summaryrefslogtreecommitdiff
path: root/apps/web/src/timeline/components
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/src/timeline/components')
-rw-r--r--apps/web/src/timeline/components/drop-target.ts33
-rw-r--r--apps/web/src/timeline/components/index.tsx3
-rw-r--r--apps/web/src/timeline/components/timeline-element.tsx7
-rw-r--r--apps/web/src/timeline/components/timeline-playhead.tsx32
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 (