diff options
Diffstat (limited to 'apps/web/src/timeline/controllers/playhead-controller.ts')
| -rw-r--r-- | apps/web/src/timeline/controllers/playhead-controller.ts | 30 |
1 files changed, 17 insertions, 13 deletions
diff --git a/apps/web/src/timeline/controllers/playhead-controller.ts b/apps/web/src/timeline/controllers/playhead-controller.ts index d2b7d82f..e914ff21 100644 --- a/apps/web/src/timeline/controllers/playhead-controller.ts +++ b/apps/web/src/timeline/controllers/playhead-controller.ts @@ -1,6 +1,11 @@ import type { MouseEvent as ReactMouseEvent } from "react"; -import { snappedSeekTime, type FrameRate } from "opencut-wasm"; -import { TICKS_PER_SECOND } from "@/wasm"; +import type { FrameRate } from "opencut-wasm"; +import { + mediaTime, + snapSeekMediaTime, + TICKS_PER_SECOND, + type MediaTime, +} from "@/wasm"; import { buildTimelineSnapPoints, getTimelineSnapThresholdInTicks, @@ -26,7 +31,7 @@ interface ScrubSession { /** True once the mouse has moved during a ruler drag. */ hasMoved: boolean; /** Most recent frame-snapped time set by scrub(). */ - currentTime: number | null; + currentTime: MediaTime | null; } type Session = { kind: "idle" } | ScrubSession; @@ -35,7 +40,7 @@ type Session = { kind: "idle" } | ScrubSession; export interface PlayheadConfig { zoomLevel: number; - duration: number; + duration: MediaTime; getActiveProjectFps: () => FrameRate | null; isShiftHeld: () => boolean; getIsPlaying: () => boolean; @@ -45,12 +50,12 @@ export interface PlayheadConfig { getPlayheadEl: () => HTMLDivElement | null; getSceneTracks: () => SceneTracks; getSceneBookmarks: () => Bookmark[]; - seek: (time: number) => void; + seek: (time: MediaTime) => void; setScrubbing: (isScrubbing: boolean) => void; setTimelineViewState: (viewState: { zoomLevel: number; scrollLeft: number; - playheadTime: number; + playheadTime: MediaTime; }) => void; } @@ -69,8 +74,8 @@ function pixelToTime({ clientX: number; rulerEl: HTMLDivElement; zoomLevel: number; - duration: number; -}): number { + duration: MediaTime; +}): MediaTime { const rulerRect = rulerEl.getBoundingClientRect(); const contentWidth = timelineTimeToPixels({ time: duration, zoomLevel }); const clampedX = Math.max( @@ -84,7 +89,7 @@ function pixelToTime({ clampedX / (BASE_TIMELINE_PIXELS_PER_SECOND * zoomLevel), ), ); - return Math.round(seconds * TICKS_PER_SECOND); + return mediaTime({ ticks: Math.round(seconds * TICKS_PER_SECOND) }); } // --- Controller --- @@ -159,7 +164,7 @@ export class PlayheadController { * Called on scroll and playback events to avoid React re-renders * during animation frame updates. */ - updatePlayheadLeft(time: number): void { + updatePlayheadLeft(time: MediaTime): void { const playheadEl = this.config.getPlayheadEl(); if (!playheadEl) return; @@ -175,7 +180,7 @@ export class PlayheadController { * Updates the playhead position and auto-scrolls to keep the playhead * visible during playback. */ - handlePlaybackUpdate(time: number): void { + handlePlaybackUpdate(time: MediaTime): void { this.updatePlayheadLeft(time); // Auto-scroll only during playback, not while scrubbing. @@ -244,8 +249,7 @@ export class PlayheadController { zoomLevel, duration, }); - const frameTime = - snappedSeekTime({ time: rawTime, duration, rate: fps }) ?? rawTime; + const frameTime = snapSeekMediaTime({ time: rawTime, duration, fps }); const time = (() => { if (!isElementSnappingEnabled || this.config.isShiftHeld()) |
