fix(runtime): respect hidden ancestor clips in Studio preview (#1387)#1395
Conversation
dd4498b to
c927be5
Compare
…-com#1387) Studio-stamped GSAP tween targets inside timed clips were getting visibility:visible for the full composition, overriding hidden parent panels. Skip stamping descendants of authored clips and suppress visibility on children when an ancestor timed clip is hidden. Co-authored-by: Cursor <cursoragent@cursor.com>
c927be5 to
23da438
Compare
There was a problem hiding this comment.
Strengths
findTimedClipAncestor(init.ts:400–411) correctly identifies the stamping root cause: Studio was iterating GSAP tween targets and stamping any element lackingdata-startwith a full-composition-duration pseudo-clip, regardless of position in the authored hierarchy. The guard atinit.ts:1070andinit.ts:1090eliminates that injection entirely for tween targets inside authored timed clips.- Extracting the old inline visibility-window logic into
isTimedElementVisibleAtis a clean refactor with zero behavior risk — it's a direct extraction and re-use. - Three regression tests cover the exact failure modes: per-caption stacking (
#1387), no-stamp-in-Studio, and the niemmo multi-panel beat pattern. Fixtures are minimal and readable.
Important
Fix 2 (ancestor visibility walk) changes render-mode behavior, not just Studio preview. The seek handler that now walks ancestor data-start elements runs in both Studio and render contexts. If any existing composition intentionally has a child element with a longer time window than its parent timed clip — e.g. a headline that bleeds out slightly past the parent panel's official data-duration — it would now be suppressed when the parent goes hidden. The new tests only cover the caption/panel-stack pattern. Were any existing compositions checked for this pattern before landing?
This isn't a blocker given the bug's severity, but the behavioral scope is wider than the PR description implies.
Nit
findTimedClipAncestor is called with rootComp potentially null (resolveRootCompositionElement() can return null). When null, the guard if (node === rootComp) break becomes if (node === null) break, which the while (node) loop already handles — so it's safe, but a comment acknowledging the null case would reduce reader confusion.
Verdict: APPROVE
Reasoning: Fix 1 eliminates the root cause (spurious Studio stamps on tween targets inside authored clips); Fix 2 enforces correct hierarchical visibility semantics as defense-in-depth. Together they're complete. The important note above is worth the author confirming, but it doesn't gate merge.
— Magi
Address review feedback: the hierarchical visibility guard now runs only when window.parent !== window, matching the Studio-only stamping fix. Render mode keeps prior per-element visibility semantics. Adds a render-mode regression test and documents the null rootComp case in findTimedClipAncestor. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Good catch on render scope — pushed a follow-up that gates the ancestor visibility walk to window.parent !== window, matching the stamping fix. Render mode keeps legacy per-element semantics; added a regression test for a child with a longer authored window than its parent. Also added the null rootComp comment. Fix 1 alone eliminates the root cause; Fix 2 is now Studio-only defense-in-depth. |
miguel-heygen
left a comment
There was a problem hiding this comment.
Follow-up on the new commit (a3cecdb).
My "important" flag is fully resolved. The ancestor visibility walk is now gated by window.parent !== window (init.ts:1505) — it only fires in the Studio iframe, leaving render mode's per-element visibility semantics untouched. The new render-mode regression test confirms exactly the case I was asking about: a child with a wider data-duration than its parent is not suppressed in render mode.
Null-rootComp comment added — nit cleared.
withStudioIframe helper is a nice cleanup over the inline Object.defineProperty pattern in the original tests.
Approval stands.
— Magi
Merge activity
|
Summary
Fixes #1387 — Studio preview showed all caption/telop content stacked simultaneously when GSAP tweens target children of timed clips (the standard caption pattern).
Two changes in
packages/core/src/runtime/init.ts:[id]elements that live inside an authored timed clip ancestor (prevents full-duration pseudo-clips)visibility: visiblewhen a parent timed clip is hiddenTest plan
bun run --filter @hyperframes/core test src/runtime/init.test.ts(23 tests)hyperframes previewon a composition with caption children — only one caption visible at a time in Studio