From ca6069763da088995d58f60916e02d37dd913680 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel?= Date: Mon, 18 May 2026 18:10:43 -0400 Subject: [PATCH] fix(studio): patch runtime clock when document duration exceeds player duration When the runtime player's clock duration is smaller than the effective timeline (computed from data-start + data-hf-authored-duration on sub-composition elements), the seek is clamped too early and sub-compositions beyond the clock duration are invisible. Detect this mismatch in getAdapter() and pad the root GSAP timeline to the document duration, then force a timeline rebind so the clock updates. --- .../src/player/hooks/useTimelinePlayer.ts | 25 +++++++++++++++++++ .../studio/src/player/lib/playbackTypes.ts | 1 + 2 files changed, 26 insertions(+) diff --git a/packages/studio/src/player/hooks/useTimelinePlayer.ts b/packages/studio/src/player/hooks/useTimelinePlayer.ts index cecd98458..ecd923389 100644 --- a/packages/studio/src/player/hooks/useTimelinePlayer.ts +++ b/packages/studio/src/player/hooks/useTimelinePlayer.ts @@ -43,6 +43,27 @@ import { shouldMutePreviewAudio, } from "../lib/timelineIframeHelpers"; +function patchRuntimeClockDuration(win: IframeWindow, targetDuration: number): void { + try { + const rootEl = win.document?.querySelector("[data-composition-id]"); + const rootId = rootEl?.getAttribute("data-composition-id"); + const tl = rootId && win.__timelines?.[rootId]; + if (tl && typeof tl.duration === "function" && tl.duration() < targetDuration) { + const tlWithTo = tl as typeof tl & { + to?: (t: object, v: { duration: number }, p: number) => void; + }; + if (typeof tlWithTo.to === "function") { + tlWithTo.to({}, { duration: 0 }, targetDuration); + } + } + if (typeof win.__hfForceTimelineRebind === "function") { + win.__hfForceTimelineRebind(); + } + } catch { + // cross-origin or missing runtime — non-fatal + } +} + // --------------------------------------------------------------------------- // Hook // --------------------------------------------------------------------------- @@ -119,6 +140,10 @@ export function useTimelinePlayer() { const playerAdapter = win.__player && typeof win.__player.play === "function" ? win.__player : null; if (getAdapterDuration(playerAdapter) > 0) { + const docDur = readTimelineDurationFromDocument(iframe?.contentDocument); + if (docDur > 0 && docDur > playerAdapter!.getDuration()) { + patchRuntimeClockDuration(win, docDur); + } return playerAdapter; } diff --git a/packages/studio/src/player/lib/playbackTypes.ts b/packages/studio/src/player/lib/playbackTypes.ts index e86b67667..540933465 100644 --- a/packages/studio/src/player/lib/playbackTypes.ts +++ b/packages/studio/src/player/lib/playbackTypes.ts @@ -57,4 +57,5 @@ export type IframeWindow = Window & { __timeline?: TimelineLike; __timelines?: Record; __clipManifest?: ClipManifest; + __hfForceTimelineRebind?: () => void; };