diff options
| author | Maze Winther <mazewinther@gmail.com> | 2026-04-26 02:50:04 +0200 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2026-04-26 02:50:04 +0200 |
| commit | eea6d43c82e1fd09d94d73001090dad205b1f1d2 (patch) | |
| tree | 384c92e467effb708bcc96e25117c064b18464b8 /apps/web/src/timeline/components | |
| parent | f1b45b4328cff6a016720ce7b38b87ac2992dc2d (diff) | |
| download | opencut-eea6d43c82e1fd09d94d73001090dad205b1f1d2.tar.gz | |
fix: model editor time as wasm MediaTime ticks end-to-end
Diffstat (limited to 'apps/web/src/timeline/components')
| -rw-r--r-- | apps/web/src/timeline/components/drop-target.ts | 33 | ||||
| -rw-r--r-- | apps/web/src/timeline/components/index.tsx | 3 | ||||
| -rw-r--r-- | apps/web/src/timeline/components/timeline-element.tsx | 7 | ||||
| -rw-r--r-- | apps/web/src/timeline/components/timeline-playhead.tsx | 32 |
4 files changed, 52 insertions, 23 deletions
diff --git a/apps/web/src/timeline/components/drop-target.ts b/apps/web/src/timeline/components/drop-target.ts index be2495e4..f68a4b72 100644 --- a/apps/web/src/timeline/components/drop-target.ts +++ b/apps/web/src/timeline/components/drop-target.ts @@ -3,7 +3,12 @@ import type { ComputeDropTargetParams, DropTarget } from "@/timeline"; import { resolveTrackPlacement } from "@/timeline/placement"; import { TIMELINE_TRACK_GAP_PX } from "./layout"; import { getTrackHeight } from "./track-layout"; -import { TICKS_PER_SECOND } from "@/wasm"; +import { + mediaTime, + type MediaTime, + roundMediaTime, + TICKS_PER_SECOND, +} from "@/wasm"; function findElementAtPosition({ mouseX, @@ -20,9 +25,11 @@ function findElementAtPosition({ pixelsPerSecond: number; zoomLevel: number; }): { elementId: string; trackId: string } | null { - const time = Math.round( - (mouseX / (pixelsPerSecond * zoomLevel)) * TICKS_PER_SECOND, - ); + const time = mediaTime({ + ticks: Math.round( + (mouseX / (pixelsPerSecond * zoomLevel)) * TICKS_PER_SECOND, + ), + }); const track = tracks[trackIndex]; if (!track || !("elements" in track)) return null; @@ -82,7 +89,7 @@ const EMPTY_TARGET_ELEMENT = null; function fallbackNewTrackDropTarget({ xPosition, }: { - xPosition: number; + xPosition: MediaTime; }): DropTarget { return { trackIndex: 0, @@ -111,13 +118,16 @@ export function computeDropTarget({ const orderedTracks = [...tracks.overlay, tracks.main, ...tracks.audio]; const mainTrackIndex = tracks.overlay.length; const xPosition = - typeof startTimeOverride === "number" + startTimeOverride !== undefined ? startTimeOverride : isExternalDrop ? playheadTime - : Math.round( - Math.max(0, mouseX / (pixelsPerSecond * zoomLevel)) * TICKS_PER_SECOND, - ); + : mediaTime({ + ticks: Math.round( + Math.max(0, mouseX / (pixelsPerSecond * zoomLevel)) * + TICKS_PER_SECOND, + ), + }); if (orderedTracks.length === 0) { const placementResult = resolveTrackPlacement({ @@ -221,7 +231,10 @@ export function computeDropTarget({ } if (placementResult.kind === "existingTrack") { - const adjustedXPosition = placementResult.adjustedStartTime ?? xPosition; + const adjustedXPosition = + placementResult.adjustedStartTime !== undefined + ? roundMediaTime({ time: placementResult.adjustedStartTime }) + : xPosition; return { trackIndex: placementResult.trackIndex, diff --git a/apps/web/src/timeline/components/index.tsx b/apps/web/src/timeline/components/index.tsx index e6a9df49..5d61a0a9 100644 --- a/apps/web/src/timeline/components/index.tsx +++ b/apps/web/src/timeline/components/index.tsx @@ -29,6 +29,7 @@ import { useState, type ReactNode, } from "react"; +import type { MediaTime } from "@/wasm"; import type { ElementDragState, DropTarget } from "@/timeline"; import { TimelineTrackContent } from "./timeline-track"; import { TimelinePlayhead } from "./timeline-playhead"; @@ -132,7 +133,7 @@ export function Timeline() { [scene], ); const mainTrackId = scene?.tracks.main.id ?? null; - const seek = (time: number) => editor.playback.seek({ time }); + const seek = (time: MediaTime) => editor.playback.seek({ time }); const timelineRef = useRef<HTMLDivElement>(null); const timelineHeaderRef = useRef<HTMLDivElement>(null); diff --git a/apps/web/src/timeline/components/timeline-element.tsx b/apps/web/src/timeline/components/timeline-element.tsx index 74c34607..e0eeb378 100644 --- a/apps/web/src/timeline/components/timeline-element.tsx +++ b/apps/web/src/timeline/components/timeline-element.tsx @@ -49,7 +49,7 @@ import { import { buildWaveformGainSamples } from "@/timeline/audio-state"; import { getTimelinePixelsPerSecond } from "@/timeline"; import { buildWaveformSourceKey } from "@/media/waveform-summary"; -import { TICKS_PER_SECOND } from "@/wasm/ticks"; +import { addMediaTime, TICKS_PER_SECOND, ZERO_MEDIA_TIME } from "@/wasm"; import { getActionDefinition, type TAction, @@ -257,10 +257,11 @@ export function TimelineElement({ isBeingDragged && dragState.isDragging ? dragState.currentMouseY - dragState.startMouseY : 0; - const dragTimeOffset = dragState.dragTimeOffsets[element.id] ?? 0; + const dragTimeOffset = + dragState.dragTimeOffsets[element.id] ?? ZERO_MEDIA_TIME; const elementStartTime = isBeingDragged && dragState.isDragging - ? dragState.currentTime + dragTimeOffset + ? addMediaTime({ a: dragState.currentTime, b: dragTimeOffset }) : renderElement.startTime; const displayedStartTime = elementStartTime; const displayedDuration = renderElement.duration; diff --git a/apps/web/src/timeline/components/timeline-playhead.tsx b/apps/web/src/timeline/components/timeline-playhead.tsx index 4dd3329f..5b1e45ab 100644 --- a/apps/web/src/timeline/components/timeline-playhead.tsx +++ b/apps/web/src/timeline/components/timeline-playhead.tsx @@ -7,7 +7,14 @@ import { timelineTimeToSnappedPixels, } from "@/timeline"; import { useTimelinePlayhead } from "@/timeline/hooks/use-timeline-playhead"; -import { TICKS_PER_SECOND } from "@/wasm"; +import { + addMediaTime, + maxMediaTime, + mediaTime, + subMediaTime, + TICKS_PER_SECOND, + ZERO_MEDIA_TIME, +} from "@/wasm"; import { useEditor } from "@/editor/use-editor"; import { TIMELINE_SCROLLBAR_SIZE_PX } from "./layout"; import { TIMELINE_LAYERS } from "./layers"; @@ -72,17 +79,24 @@ export function TimelinePlayhead({ event.preventDefault(); const fps = editor.project.getActive().settings.fps; - const ticksPerFrame = Math.round( - (TICKS_PER_SECOND * fps.denominator) / fps.numerator, - ); + const ticksPerFrame = mediaTime({ + ticks: Math.round( + (TICKS_PER_SECOND * fps.denominator) / fps.numerator, + ), + }); const direction = event.key === "ArrowRight" ? 1 : -1; const now = editor.playback.getCurrentTime(); - const nextTime = Math.max( - 0, - Math.min(duration, now + direction * ticksPerFrame), - ); + const nextTime = + direction > 0 + ? addMediaTime({ a: now, b: ticksPerFrame }) + : subMediaTime({ a: now, b: ticksPerFrame }); - editor.playback.seek({ time: nextTime }); + editor.playback.seek({ + time: maxMediaTime({ + a: ZERO_MEDIA_TIME, + b: duration < nextTime ? duration : nextTime, + }), + }); }; return ( |
