summaryrefslogtreecommitdiff
path: root/apps/web/src/hooks/timeline/element/use-element-resize.ts
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/src/hooks/timeline/element/use-element-resize.ts')
-rw-r--r--apps/web/src/hooks/timeline/element/use-element-resize.ts42
1 files changed, 22 insertions, 20 deletions
diff --git a/apps/web/src/hooks/timeline/element/use-element-resize.ts b/apps/web/src/hooks/timeline/element/use-element-resize.ts
index 3dd98bea..dec87eef 100644
--- a/apps/web/src/hooks/timeline/element/use-element-resize.ts
+++ b/apps/web/src/hooks/timeline/element/use-element-resize.ts
@@ -1,6 +1,7 @@
import { useState, useEffect, useRef, useCallback } from "react";
import { BASE_TIMELINE_PIXELS_PER_SECOND } from "@/lib/timeline/scale";
-import { snapTimeToFrame } from "opencut-wasm";
+import { TICKS_PER_SECOND } from "@/lib/wasm";
+import { roundToFrame } from "opencut-wasm";
import type { TimelineElement, TimelineTrack } from "@/lib/timeline";
import { useEditor } from "@/hooks/use-editor";
import { useShiftKey } from "@/hooks/use-shift-key";
@@ -185,13 +186,14 @@ export function useTimelineElementResize({
({ clientX }: { clientX: number }) => {
if (!resizing) return;
- const deltaX = clientX - resizing.startX;
- let deltaTime =
- deltaX / (BASE_TIMELINE_PIXELS_PER_SECOND * zoomLevel);
- let resizeSnapPoint: SnapPoint | null = null;
+ const deltaX = clientX - resizing.startX;
+ let deltaTime = Math.round(
+ (deltaX / (BASE_TIMELINE_PIXELS_PER_SECOND * zoomLevel)) * TICKS_PER_SECOND,
+ );
+ let resizeSnapPoint: SnapPoint | null = null;
- const projectFps = editor.project.getActive().settings.fps;
- const minDurationSeconds = 1 / projectFps;
+ const projectFps = editor.project.getActive().settings.fps;
+ const minDuration = Math.round(TICKS_PER_SECOND * projectFps.denominator / projectFps.numerator);
const shouldSnap = snappingEnabled && !isShiftHeldRef.current;
if (shouldSnap) {
const tracks = editor.timeline.getTracks();
@@ -277,19 +279,19 @@ export function useTimelineElementResize({
const maxAllowed =
sourceDuration -
resizing.initialTrimEnd -
- getVisibleSourceSpanForDuration(minDurationSeconds);
+ getVisibleSourceSpanForDuration(minDuration);
const calculated =
resizing.initialTrimStart + getSourceDeltaForClipDelta(deltaTime);
if (calculated >= 0 && calculated <= maxAllowed) {
- const newTrimStart = snapTimeToFrame({ time: Math.min(maxAllowed, Math.max(minTrimStartForNeighbor, calculated)), fps: projectFps });
+ const newTrimStart = roundToFrame({ time: Math.min(maxAllowed, Math.max(minTrimStartForNeighbor, calculated)), rate: projectFps }) ?? Math.min(maxAllowed, Math.max(minTrimStartForNeighbor, calculated));
const visibleSourceSpan = Math.max(
0,
sourceDuration - newTrimStart - resizing.initialTrimEnd,
);
- const newDuration = snapTimeToFrame({ time: getDurationForVisibleSourceSpan(visibleSourceSpan), fps: projectFps });
+ const newDuration = roundToFrame({ time: getDurationForVisibleSourceSpan(visibleSourceSpan), rate: projectFps }) ?? getDurationForVisibleSourceSpan(visibleSourceSpan);
const trimDelta = resizing.initialDuration - newDuration;
- const newStartTime = snapTimeToFrame({ time: resizing.initialStartTime + trimDelta, fps: projectFps });
+ const newStartTime = roundToFrame({ time: resizing.initialStartTime + trimDelta, rate: projectFps }) ?? resizing.initialStartTime + trimDelta;
setCurrentTrimStart(newTrimStart);
setCurrentStartTime(newStartTime);
@@ -311,8 +313,8 @@ export function useTimelineElementResize({
)
: Math.min(extensionAmount, maxExtension),
);
- const newStartTime = snapTimeToFrame({ time: resizing.initialStartTime - actualExtension, fps: projectFps });
- const newDuration = snapTimeToFrame({ time: resizing.initialDuration + actualExtension, fps: projectFps });
+ const newStartTime = roundToFrame({ time: resizing.initialStartTime - actualExtension, rate: projectFps }) ?? resizing.initialStartTime - actualExtension;
+ const newDuration = roundToFrame({ time: resizing.initialDuration + actualExtension, rate: projectFps }) ?? resizing.initialDuration + actualExtension;
setCurrentTrimStart(0);
setCurrentStartTime(newStartTime);
@@ -338,8 +340,8 @@ export function useTimelineElementResize({
0,
sourceDuration - newTrimStart - resizing.initialTrimEnd,
);
- const newDuration = snapTimeToFrame({ time: getDurationForVisibleSourceSpan(visibleSourceSpan), fps: projectFps });
- const newStartTime = snapTimeToFrame({ time: resizing.initialStartTime + (resizing.initialDuration - newDuration), fps: projectFps });
+ const newDuration = roundToFrame({ time: getDurationForVisibleSourceSpan(visibleSourceSpan), rate: projectFps }) ?? getDurationForVisibleSourceSpan(visibleSourceSpan);
+ const newStartTime = roundToFrame({ time: resizing.initialStartTime + (resizing.initialDuration - newDuration), rate: projectFps }) ?? resizing.initialStartTime + (resizing.initialDuration - newDuration);
setCurrentTrimStart(newTrimStart);
setCurrentStartTime(newStartTime);
@@ -366,7 +368,7 @@ export function useTimelineElementResize({
const extensionNeeded = Math.abs(newTrimEnd);
const baseDuration =
resizing.initialDuration + resizing.initialTrimEnd;
- const newDuration = snapTimeToFrame({ time: Math.min(baseDuration + extensionNeeded, maxAllowedDuration), fps: projectFps });
+ const newDuration = roundToFrame({ time: Math.min(baseDuration + extensionNeeded, maxAllowedDuration), rate: projectFps }) ?? Math.min(baseDuration + extensionNeeded, maxAllowedDuration);
setCurrentDuration(newDuration);
setCurrentTrimEnd(0);
@@ -376,7 +378,7 @@ export function useTimelineElementResize({
const unclampedDuration = getDurationForVisibleSourceSpan(
Math.max(0, sourceDuration - resizing.initialTrimStart),
);
- const newDuration = snapTimeToFrame({ time: Math.min(unclampedDuration, maxAllowedDuration), fps: projectFps });
+ const newDuration = roundToFrame({ time: Math.min(unclampedDuration, maxAllowedDuration), rate: projectFps }) ?? Math.min(unclampedDuration, maxAllowedDuration);
setCurrentDuration(newDuration);
setCurrentTrimEnd(0);
@@ -395,17 +397,17 @@ export function useTimelineElementResize({
const maxTrimEnd =
sourceDuration -
resizing.initialTrimStart -
- getVisibleSourceSpanForDuration(minDurationSeconds);
+ getVisibleSourceSpanForDuration(minDuration);
const clampedTrimEnd = Math.min(
maxTrimEnd,
Math.max(minTrimEndForNeighbor, newTrimEnd),
);
- const finalTrimEnd = snapTimeToFrame({ time: clampedTrimEnd, fps: projectFps });
+ const finalTrimEnd = roundToFrame({ time: clampedTrimEnd, rate: projectFps }) ?? clampedTrimEnd;
const visibleSourceSpan = Math.max(
0,
sourceDuration - resizing.initialTrimStart - finalTrimEnd,
);
- const newDuration = snapTimeToFrame({ time: getDurationForVisibleSourceSpan(visibleSourceSpan), fps: projectFps });
+ const newDuration = roundToFrame({ time: getDurationForVisibleSourceSpan(visibleSourceSpan), rate: projectFps }) ?? getDurationForVisibleSourceSpan(visibleSourceSpan);
setCurrentTrimEnd(finalTrimEnd);
setCurrentDuration(newDuration);