diff options
| author | Maze Winther <mazewinther@gmail.com> | 2025-07-31 23:47:10 +0200 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2025-07-31 23:47:10 +0200 |
| commit | b00d6d5fb61229fcc035cc9680731f042d03b919 (patch) | |
| tree | 10efe1dc63dc33f70f78359c93ed2026fa74e52a /apps/web | |
| parent | 60d4b0c3d6a0cc69f165f7db8ad5099b3d1589ca (diff) | |
| download | opencut-b00d6d5fb61229fcc035cc9680731f042d03b919.tar.gz | |
fix: make timeline element resizing frame based instead of pixel based
Diffstat (limited to 'apps/web')
| -rw-r--r-- | apps/web/src/hooks/use-timeline-element-resize.ts | 41 |
1 files changed, 34 insertions, 7 deletions
diff --git a/apps/web/src/hooks/use-timeline-element-resize.ts b/apps/web/src/hooks/use-timeline-element-resize.ts index e7d46dff..d57533e0 100644 --- a/apps/web/src/hooks/use-timeline-element-resize.ts +++ b/apps/web/src/hooks/use-timeline-element-resize.ts @@ -2,6 +2,8 @@ import { useState, useEffect } from "react"; import { ResizeState, TimelineElement, TimelineTrack } from "@/types/timeline"; import { useMediaStore } from "@/stores/media-store"; import { useTimelineStore } from "@/stores/timeline-store"; +import { useProjectStore } from "@/stores/project-store"; +import { snapTimeToFrame } from "@/constants/timeline-constants"; interface UseTimelineElementResizeProps { element: TimelineElement; @@ -109,6 +111,10 @@ export function useTimelineElementResize({ // Reasonable sensitivity for resize operations - similar to timeline scale const deltaTime = deltaX / (50 * zoomLevel); + // Get project FPS for frame snapping + const projectStore = useProjectStore.getState(); + const projectFps = projectStore.activeProject?.fps || 30; + if (resizing.side === "left") { // Left resize - different behavior for media vs text/image elements const maxAllowed = element.duration - resizing.initialTrimEnd - 0.1; @@ -116,9 +122,15 @@ export function useTimelineElementResize({ if (calculated >= 0) { // Normal trimming within available content - const newTrimStart = Math.min(maxAllowed, calculated); + const newTrimStart = snapTimeToFrame( + Math.min(maxAllowed, calculated), + projectFps + ); const trimDelta = newTrimStart - resizing.initialTrimStart; - const newStartTime = element.startTime + trimDelta; + const newStartTime = snapTimeToFrame( + element.startTime + trimDelta, + projectFps + ); updateElementTrim( track.id, @@ -135,8 +147,14 @@ export function useTimelineElementResize({ const extensionAmount = Math.abs(calculated); const maxExtension = element.startTime; const actualExtension = Math.min(extensionAmount, maxExtension); - const newStartTime = element.startTime - actualExtension; - const newDuration = element.duration + actualExtension; + const newStartTime = snapTimeToFrame( + element.startTime - actualExtension, + projectFps + ); + const newDuration = snapTimeToFrame( + element.duration + actualExtension, + projectFps + ); // Keep trimStart at 0 and extend the element updateElementTrim( @@ -152,7 +170,10 @@ export function useTimelineElementResize({ // Video/Audio: can't extend beyond original content - limit to trimStart = 0 const newTrimStart = 0; const trimDelta = newTrimStart - resizing.initialTrimStart; - const newStartTime = element.startTime + trimDelta; + const newStartTime = snapTimeToFrame( + element.startTime + trimDelta, + projectFps + ); updateElementTrim( track.id, @@ -173,7 +194,10 @@ export function useTimelineElementResize({ if (canExtendElementDuration()) { // Extend the duration instead of reducing trimEnd further const extensionNeeded = Math.abs(calculated); - const newDuration = element.duration + extensionNeeded; + const newDuration = snapTimeToFrame( + element.duration + extensionNeeded, + projectFps + ); const newTrimEnd = 0; // Reset trimEnd to 0 since we're extending // Update duration first, then trim @@ -198,7 +222,10 @@ export function useTimelineElementResize({ } else { // Normal trimming within original duration const maxTrimEnd = element.duration - resizing.initialTrimStart - 0.1; // Leave at least 0.1s visible - const newTrimEnd = Math.max(0, Math.min(maxTrimEnd, calculated)); + const newTrimEnd = snapTimeToFrame( + Math.max(0, Math.min(maxTrimEnd, calculated)), + projectFps + ); updateElementTrim( track.id, |
