From 43f0a2b2bb1e430b96090591fedb7c17ea30dde2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel?= Date: Mon, 18 May 2026 16:32:03 -0400 Subject: [PATCH] fix(studio): seek slider respects effective timeline duration with appended blocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The seek slider read duration from the player store, which was set from the iframe adapter's getDuration() — only aware of the root composition's authored data-duration. Appended sub-compositions (via Blocks panel) extend the timeline but the slider stayed capped at the original duration. Sync effectiveTimelineDuration (which accounts for all timeline elements) into the player store, and prevent adapter callbacks from overwriting a larger effective duration back down to the authored value. --- packages/studio/src/App.tsx | 8 ++++---- packages/studio/src/player/hooks/useTimelinePlayer.ts | 2 +- .../studio/src/player/hooks/useTimelineSyncCallbacks.ts | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/studio/src/App.tsx b/packages/studio/src/App.tsx index 1cf24b2c5..ced474638 100644 --- a/packages/studio/src/App.tsx +++ b/packages/studio/src/App.tsx @@ -84,6 +84,10 @@ export function StudioApp() { : 0; return Math.max(timelineDuration, maxEnd); }, [timelineDuration, timelineElements]); + useEffect(() => { + if (effectiveTimelineDuration !== usePlayerStore.getState().duration) + usePlayerStore.getState().setDuration(effectiveTimelineDuration); + }, [effectiveTimelineDuration]); const refreshPreviewDocumentVersion = useCallback(() => { setPreviewDocumentVersion((v) => v + 1); window.setTimeout(() => setPreviewDocumentVersion((v) => v + 1), 80); @@ -235,11 +239,9 @@ export function StudioApp() { openSourceForSelection: fileManager.openSourceForSelection, selectSidebarTab: (tab: SidebarTab) => leftSidebarRef.current?.selectTab(tab), }); - domEditSelectionBridgeRef.current = domEditSession.domEditSelection; clearDomSelectionRef.current = domEditSession.clearDomSelection; handleDomEditElementDeleteRef.current = domEditSession.handleDomEditElementDelete; - useCaptionDetection({ projectId, activeCompPath, @@ -271,10 +273,8 @@ export function StudioApp() { setConsoleErrors, resetErrors: resetConsoleErrors, } = useConsoleErrorCapture(previewIframe); - const [globalDragOver, setGlobalDragOver] = useState(false); const dragCounterRef = useRef(0); - const { syncPreviewTimelineHotkey, syncPreviewHistoryHotkey } = appHotkeys; const handlePreviewIframeRef = useCallback( (iframe: HTMLIFrameElement | null) => { diff --git a/packages/studio/src/player/hooks/useTimelinePlayer.ts b/packages/studio/src/player/hooks/useTimelinePlayer.ts index cbd6a164a..7b6579afe 100644 --- a/packages/studio/src/player/hooks/useTimelinePlayer.ts +++ b/packages/studio/src/player/hooks/useTimelinePlayer.ts @@ -99,7 +99,7 @@ export function useTimelinePlayer() { if ( Number.isFinite(nextDuration) && (nextDuration ?? 0) > 0 && - nextDuration !== state.duration + (nextDuration ?? 0) > state.duration ) { setDuration(nextDuration ?? 0); } diff --git a/packages/studio/src/player/hooks/useTimelineSyncCallbacks.ts b/packages/studio/src/player/hooks/useTimelineSyncCallbacks.ts index 54c28732f..7a55ec01d 100644 --- a/packages/studio/src/player/hooks/useTimelineSyncCallbacks.ts +++ b/packages/studio/src/player/hooks/useTimelineSyncCallbacks.ts @@ -163,11 +163,12 @@ export function useTimelineSyncCallbacks({ // with the initial adapter seek on iframe load. liveTime.notify(startTime); const adapterDur = adapter.getDuration(); + const storeDur = usePlayerStore.getState().duration; if ( Number.isFinite(adapterDur) && adapterDur > 0 && adapterDur < 7200 && - adapterDur !== usePlayerStore.getState().duration + adapterDur > storeDur ) { setDuration(adapterDur); }