diff options
| author | Maze Winther <mazewinther@gmail.com> | 2026-04-07 04:41:27 +0200 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2026-04-07 04:41:27 +0200 |
| commit | cbd1b8212370c67b34a70dccd21bd82de72fead2 (patch) | |
| tree | d97cbee2aae22c22b59c59a50e9f8a6af0ae8ccf /apps/web/src/hooks | |
| parent | 4f7d401a974047d37673ee8e3840dceaaddc295c (diff) | |
| download | opencut-cbd1b8212370c67b34a70dccd21bd82de72fead2.tar.gz | |
refactor: structured track layout per scene
Diffstat (limited to 'apps/web/src/hooks')
| -rw-r--r-- | apps/web/src/hooks/actions/use-editor-actions.ts | 16 | ||||
| -rw-r--r-- | apps/web/src/hooks/timeline/element/use-element-interaction.ts | 24 | ||||
| -rw-r--r-- | apps/web/src/hooks/timeline/element/use-element-resize.ts | 2 | ||||
| -rw-r--r-- | apps/web/src/hooks/timeline/use-bookmark-drag.ts | 2 | ||||
| -rw-r--r-- | apps/web/src/hooks/timeline/use-timeline-drag-drop.ts | 55 | ||||
| -rw-r--r-- | apps/web/src/hooks/timeline/use-timeline-playhead.ts | 2 | ||||
| -rw-r--r-- | apps/web/src/hooks/use-element-preview.ts | 13 | ||||
| -rw-r--r-- | apps/web/src/hooks/use-mask-handles.ts | 4 | ||||
| -rw-r--r-- | apps/web/src/hooks/use-preview-interaction.ts | 4 | ||||
| -rw-r--r-- | apps/web/src/hooks/use-transform-handles.ts | 4 |
10 files changed, 85 insertions, 41 deletions
diff --git a/apps/web/src/hooks/actions/use-editor-actions.ts b/apps/web/src/hooks/actions/use-editor-actions.ts index 599b4260..be04a7d3 100644 --- a/apps/web/src/hooks/actions/use-editor-actions.ts +++ b/apps/web/src/hooks/actions/use-editor-actions.ts @@ -179,11 +179,12 @@ export function useEditorActions() { "split", () => { const currentTime = editor.playback.getCurrentTime(); + const tracks = editor.scenes.getActiveScene().tracks; const elementsToSplit = selectedElements.length > 0 ? selectedElements : getElementsAtTime({ - tracks: editor.timeline.getTracks(), + tracks, time: currentTime, }); @@ -201,11 +202,12 @@ export function useEditorActions() { "split-left", () => { const currentTime = editor.playback.getCurrentTime(); + const tracks = editor.scenes.getActiveScene().tracks; const elementsToSplit = selectedElements.length > 0 ? selectedElements : getElementsAtTime({ - tracks: editor.timeline.getTracks(), + tracks, time: currentTime, }); @@ -233,11 +235,12 @@ export function useEditorActions() { "split-right", () => { const currentTime = editor.playback.getCurrentTime(); + const tracks = editor.scenes.getActiveScene().tracks; const elementsToSplit = selectedElements.length > 0 ? selectedElements : getElementsAtTime({ - tracks: editor.timeline.getTracks(), + tracks, time: currentTime, }); @@ -310,7 +313,12 @@ export function useEditorActions() { useActionHandler( "select-all", () => { - const allElements = editor.timeline.getTracks().flatMap((track) => + const scene = editor.scenes.getActiveScene(); + const allElements = [ + ...scene.tracks.overlay, + scene.tracks.main, + ...scene.tracks.audio, + ].flatMap((track) => track.elements.map((element) => ({ trackId: track.id, elementId: element.id, diff --git a/apps/web/src/hooks/timeline/element/use-element-interaction.ts b/apps/web/src/hooks/timeline/element/use-element-interaction.ts index 6fcd4168..98918bea 100644 --- a/apps/web/src/hooks/timeline/element/use-element-interaction.ts +++ b/apps/web/src/hooks/timeline/element/use-element-interaction.ts @@ -21,6 +21,7 @@ import { registerCanceller } from "@/lib/cancel-interaction"; import type { DropTarget, ElementDragState, + SceneTracks, TimelineElement, TimelineTrack, } from "@/lib/timeline"; @@ -101,7 +102,7 @@ function getDragDropTarget({ clientY: number; elementId: string; trackId: string; - tracks: TimelineTrack[]; + tracks: SceneTracks; tracksContainerRef: RefObject<HTMLDivElement | null>; tracksScrollRef: RefObject<HTMLDivElement | null>; headerRef?: RefObject<HTMLElement | null>; @@ -113,7 +114,11 @@ function getDragDropTarget({ const scrollContainer = tracksScrollRef.current; if (!containerRect || !scrollContainer) return null; - const sourceTrack = tracks.find(({ id }) => id === trackId); + const sourceTrack = [ + ...tracks.overlay, + tracks.main, + ...tracks.audio, + ].find(({ id }) => id === trackId); const movingElement = sourceTrack?.elements.find( ({ id }) => id === elementId, ); @@ -163,7 +168,12 @@ export function useElementInteraction({ }: UseElementInteractionProps) { const editor = useEditor(); const isShiftHeldRef = useShiftKey(); - const tracks = editor.timeline.getTracks(); + const sceneTracks = editor.scenes.getActiveScene().tracks; + const tracks = [ + ...sceneTracks.overlay, + sceneTracks.main, + ...sceneTracks.audio, + ]; const { isElementSelected, selectElement, @@ -242,7 +252,7 @@ export function useElementInteraction({ const startSnap = snapElementEdge({ targetTime: frameSnappedTime, elementDuration, - tracks, + tracks: sceneTracks, playheadTime, zoomLevel, excludeElementId: movingElement.id, @@ -252,7 +262,7 @@ export function useElementInteraction({ const endSnap = snapElementEdge({ targetTime: frameSnappedTime, elementDuration, - tracks, + tracks: sceneTracks, playheadTime, zoomLevel, excludeElementId: movingElement.id, @@ -376,7 +386,7 @@ export function useElementInteraction({ clientY, elementId: dragState.elementId, trackId: dragState.trackId, - tracks, + tracks: sceneTracks, tracksContainerRef, tracksScrollRef, headerRef, @@ -436,7 +446,7 @@ export function useElementInteraction({ clientY, elementId: dragState.elementId, trackId: dragState.trackId, - tracks, + tracks: sceneTracks, tracksContainerRef, tracksScrollRef, headerRef, 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 dec87eef..bb0d880c 100644 --- a/apps/web/src/hooks/timeline/element/use-element-resize.ts +++ b/apps/web/src/hooks/timeline/element/use-element-resize.ts @@ -196,7 +196,7 @@ export function useTimelineElementResize({ const minDuration = Math.round(TICKS_PER_SECOND * projectFps.denominator / projectFps.numerator); const shouldSnap = snappingEnabled && !isShiftHeldRef.current; if (shouldSnap) { - const tracks = editor.timeline.getTracks(); + const tracks = editor.scenes.getActiveScene().tracks; const playheadTime = editor.playback.getCurrentTime(); const snapPoints = findSnapPoints({ tracks, diff --git a/apps/web/src/hooks/timeline/use-bookmark-drag.ts b/apps/web/src/hooks/timeline/use-bookmark-drag.ts index 90edbede..3ff1cb21 100644 --- a/apps/web/src/hooks/timeline/use-bookmark-drag.ts +++ b/apps/web/src/hooks/timeline/use-bookmark-drag.ts @@ -44,7 +44,7 @@ export function useBookmarkDrag({ }: UseBookmarkDragProps) { const editor = useEditor(); const isShiftHeldRef = useShiftKey(); - const tracks = editor.timeline.getTracks(); + const tracks = editor.scenes.getActiveScene().tracks; const activeScene = editor.scenes.getActiveScene(); const bookmarks = activeScene?.bookmarks ?? []; const playheadTime = editor.playback.getCurrentTime(); diff --git a/apps/web/src/hooks/timeline/use-timeline-drag-drop.ts b/apps/web/src/hooks/timeline/use-timeline-drag-drop.ts index 7b9ee2ee..009f0ff6 100644 --- a/apps/web/src/hooks/timeline/use-timeline-drag-drop.ts +++ b/apps/web/src/hooks/timeline/use-timeline-drag-drop.ts @@ -17,7 +17,6 @@ import { AddTrackCommand, InsertElementCommand } from "@/lib/commands/timeline"; import { BatchCommand } from "@/lib/commands"; import { computeDropTarget } from "@/components/editor/panels/timeline/drop-target"; import { getDragData, hasDragData } from "@/lib/drag-data"; -import { isMainTrack } from "@/lib/timeline/placement"; import type { TrackType, DropTarget, ElementType } from "@/lib/timeline"; import type { MediaDragData, @@ -149,13 +148,13 @@ export function useTimelineDragDrop({ ? (dragData as MediaDragData).targetElementTypes : undefined; - const tracks = editor.timeline.getTracks(); + const sceneTracks = editor.scenes.getActiveScene().tracks; const currentTime = editor.playback.getCurrentTime(); const target = computeDropTarget({ elementType, mouseX, mouseY, - tracks, + tracks: sceneTracks, playheadTime: currentTime, isExternalDrop: isExternal, elementDuration: duration, @@ -230,7 +229,11 @@ export function useTimelineDragDrop({ return; } - const tracks = editor.timeline.getTracks(); + const tracks = [ + ...editor.scenes.getActiveScene().tracks.overlay, + editor.scenes.getActiveScene().tracks.main, + ...editor.scenes.getActiveScene().tracks.audio, + ]; const track = tracks[target.trackIndex]; if (!track) return; editor.timeline.insertElement({ @@ -267,7 +270,11 @@ export function useTimelineDragDrop({ return; } - const tracks = editor.timeline.getTracks(); + const tracks = [ + ...editor.scenes.getActiveScene().tracks.overlay, + editor.scenes.getActiveScene().tracks.main, + ...editor.scenes.getActiveScene().tracks.audio, + ]; const track = tracks[target.trackIndex]; if (!track) return; editor.timeline.insertElement({ @@ -305,7 +312,11 @@ export function useTimelineDragDrop({ return; } - const tracks = editor.timeline.getTracks(); + const tracks = [ + ...editor.scenes.getActiveScene().tracks.overlay, + editor.scenes.getActiveScene().tracks.main, + ...editor.scenes.getActiveScene().tracks.audio, + ]; const track = tracks[target.trackIndex]; if (!track) return; editor.timeline.insertElement({ @@ -352,7 +363,11 @@ export function useTimelineDragDrop({ return; } - const tracks = editor.timeline.getTracks(); + const tracks = [ + ...editor.scenes.getActiveScene().tracks.overlay, + editor.scenes.getActiveScene().tracks.main, + ...editor.scenes.getActiveScene().tracks.audio, + ]; const track = tracks[target.trackIndex]; if (!track) return; editor.timeline.insertElement({ @@ -380,7 +395,11 @@ export function useTimelineDragDrop({ return; } - const tracks = editor.timeline.getTracks(); + const tracks = [ + ...editor.scenes.getActiveScene().tracks.overlay, + editor.scenes.getActiveScene().tracks.main, + ...editor.scenes.getActiveScene().tracks.audio, + ]; const effectTrack = tracks.find((t) => t.type === "effect"); let trackId: string; @@ -447,16 +466,14 @@ export function useTimelineDragDrop({ const duration = createdAsset.duration ?? DEFAULT_NEW_ELEMENT_DURATION; - const currentTracks = editor.timeline.getTracks(); + const sceneTracks = editor.scenes.getActiveScene().tracks; const currentTime = editor.playback.getCurrentTime(); - const onlyTrack = currentTracks[0]; const reuseMainTrackId = createdAsset.type !== "audio" && - currentTracks.length === 1 && - !!onlyTrack && - isMainTrack(onlyTrack) && - onlyTrack.elements.length === 0 - ? onlyTrack.id + sceneTracks.overlay.length === 0 && + sceneTracks.audio.length === 0 && + sceneTracks.main.elements.length === 0 + ? sceneTracks.main.id : null; const dropTarget = reuseMainTrackId ? null @@ -464,7 +481,7 @@ export function useTimelineDragDrop({ elementType: createdAsset.type, mouseX, mouseY, - tracks: currentTracks, + tracks: sceneTracks, playheadTime: currentTime, isExternalDrop: true, elementDuration: duration, @@ -488,7 +505,11 @@ export function useTimelineDragDrop({ trackId = addTrackCmd.getTrackId(); editor.command.execute({ command: addTrackCmd }); } else { - trackId = currentTracks[dropTarget.trackIndex]?.id; + trackId = [ + ...sceneTracks.overlay, + sceneTracks.main, + ...sceneTracks.audio, + ][dropTarget.trackIndex]?.id; } } diff --git a/apps/web/src/hooks/timeline/use-timeline-playhead.ts b/apps/web/src/hooks/timeline/use-timeline-playhead.ts index 70364e90..1886222f 100644 --- a/apps/web/src/hooks/timeline/use-timeline-playhead.ts +++ b/apps/web/src/hooks/timeline/use-timeline-playhead.ts @@ -90,7 +90,7 @@ export function useTimelinePlayhead({ const shouldSnap = snappingEnabled && !isShiftHeldRef.current; const time = (() => { if (!shouldSnap) return frameTime; - const tracks = editor.timeline.getTracks(); + const tracks = editor.scenes.getActiveScene().tracks; const bookmarks = editor.scenes.getActiveScene()?.bookmarks ?? []; const snapPoints = findSnapPoints({ tracks, diff --git a/apps/web/src/hooks/use-element-preview.ts b/apps/web/src/hooks/use-element-preview.ts index d717143d..4f28be83 100644 --- a/apps/web/src/hooks/use-element-preview.ts +++ b/apps/web/src/hooks/use-element-preview.ts @@ -1,5 +1,5 @@ import { useEditor } from "@/hooks/use-editor";
-import type { TimelineElement } from "@/lib/timeline";
+import { findTrackInSceneTracks, type TimelineElement } from "@/lib/timeline";
/**
* Subscribes to render tracks and returns the live (preview-aware) version of
@@ -18,13 +18,14 @@ export function useElementPreview<T extends TimelineElement>({ fallback: T;
}) {
const editor = useEditor();
- useEditor((e) => e.timeline.getRenderTracks());
+ useEditor((e) => e.timeline.getPreviewTracks());
+ const previewTracks = editor.timeline.getPreviewTracks();
const renderElement =
- (editor.timeline
- .getRenderTracks()
- .find((t) => t.id === trackId)
- ?.elements.find((el) => el.id === elementId) as T | undefined) ??
+ (findTrackInSceneTracks({
+ tracks: previewTracks ?? editor.scenes.getActiveScene().tracks,
+ trackId,
+ })?.elements.find((element) => element.id === elementId) as T | undefined) ??
fallback;
const previewUpdates = (updates: Partial<TimelineElement>) =>
diff --git a/apps/web/src/hooks/use-mask-handles.ts b/apps/web/src/hooks/use-mask-handles.ts index 63fdd674..d2400ee0 100644 --- a/apps/web/src/hooks/use-mask-handles.ts +++ b/apps/web/src/hooks/use-mask-handles.ts @@ -45,7 +45,9 @@ export function useMaskHandles({ null,
);
- const tracks = useEditor((e) => e.timeline.getRenderTracks());
+ const tracks = useEditor(
+ (e) => e.timeline.getPreviewTracks() ?? e.scenes.getActiveScene().tracks,
+ );
const currentTime = useEditor((e) => e.playback.getCurrentTime());
const mediaAssets = useEditor((e) => e.media.getAssets());
const canvasSize = useEditor(
diff --git a/apps/web/src/hooks/use-preview-interaction.ts b/apps/web/src/hooks/use-preview-interaction.ts index 90fa0450..2a3e5c28 100644 --- a/apps/web/src/hooks/use-preview-interaction.ts +++ b/apps/web/src/hooks/use-preview-interaction.ts @@ -180,7 +180,7 @@ export function usePreviewInteraction({ ({ clientX, clientY }: React.MouseEvent) => { if (editingText || isMaskMode) return; - const tracks = editor.timeline.getTracks(); + const tracks = editor.scenes.getActiveScene().tracks; const currentTime = editor.playback.getCurrentTime(); const mediaAssets = editor.media.getAssets(); const canvasSize = editor.project.getActive().settings.canvasSize; @@ -238,7 +238,7 @@ export function usePreviewInteraction({ if (isMaskMode) return; if (button !== 0) return; - const tracks = editor.timeline.getTracks(); + const tracks = editor.scenes.getActiveScene().tracks; const currentTime = editor.playback.getCurrentTime(); const mediaAssets = editor.media.getAssets(); const canvasSize = editor.project.getActive().settings.canvasSize; diff --git a/apps/web/src/hooks/use-transform-handles.ts b/apps/web/src/hooks/use-transform-handles.ts index 659aa598..7495a387 100644 --- a/apps/web/src/hooks/use-transform-handles.ts +++ b/apps/web/src/hooks/use-transform-handles.ts @@ -132,7 +132,9 @@ export function useTransformHandles({ ); const selectedElements = useEditor((e) => e.selection.getSelectedElements()); - const tracks = useEditor((e) => e.timeline.getRenderTracks()); + const tracks = useEditor( + (e) => e.timeline.getPreviewTracks() ?? e.scenes.getActiveScene().tracks, + ); const currentTime = useEditor((e) => e.playback.getCurrentTime()); const currentTimeRef = useRef(currentTime); currentTimeRef.current = currentTime; |
