Skip to content

Sub-composition slot still blanks at child data-duration when host continues (after #911 fix in 0.6.110) #1540

Closed

Description

@tosin2013

Describe the bug

When a sub-composition's data-duration ends before its host composition's data-duration ends, the sub-composition's slot blanks for the remaining time — even though
data-composition-src is present on the child div.

This is adjacent to but distinct from #911. #911's symptom was the same (slot goes black), but the root cause was the producer's htmlCompiler stripping
data-composition-src during inlining. Commit 2b46565c fixed that by making the runtime accept both data-composition-src and data-composition-file, and by having the
producer set data-composition-file. That fix is shipped in 0.6.110 — I verified the runtime bundle (dist/hyperframe.runtime.iife.js) contains
d.hasAttribute("data-composition-src")||d.hasAttribute("data-composition-file").

In my reproducer the producer is not involved — I edit index.html by hand, data-composition-src is present on the child throughout, and the slot still blanks. The trigger
is the duration mismatch itself, not a missing attribute.

Link to reproduction

Self-contained minimal reproducer below. Built on top of the unmodified npx hyperframes init decision-tree scaffold; the only edits are to index.html.

Steps to reproduce

  1. npx [email protected] init (pick decision-tree).
  2. Edit index.html — extend the root's data-duration from 15 to 331.224, but leave the child at 15.
<div id="root" data-composition-id="main" data-start="0"
     data-duration="331.224" data-width="1920" data-height="1080">
  <div id="decision-tree-comp"
       data-composition-id="decision-tree"
       data-composition-src="compositions/decision_tree.html"
       data-start="0"
       data-duration="15"
       data-track-index="0"
       data-width="1920" data-height="1080"></div>
</div>
  1. npx hyperframes render --fps 8 --quality draft --output broken.mp4
  2. Sample frames:
for t in 7 14 20 100 200 300; do
  ffmpeg -y -loglevel quiet -ss $t -i broken.mp4 -frames:v 1 -update 1 f_${t}.png
done
md5sum f_*.png

Observed (0.6.110)

Frame at md5 size content
t=7s, 14s fc3407717aa9c33b4ded9dcbcd97a561 20,302 B dotted grid (child rendering)
t=20s, 100s, 200s, 300s 9c95fca010bc4b6747f415d2c1efad74 8,680 B pure blank

All four "blank" frames are byte-identical for 316 seconds. The slot goes black the instant the child's data-duration elapses and stays black until the host's ends.

Expected

Per the framing in #911 ("regardless of host data-duration"), the slot should hold its last frame for as long as the host is still alive. That's what happens when I rewrite the
child's data-duration to also be 331.224 — t=20s/100s/300s become identical to t=14s (the dotted grid stays visible), matching what I'd expect for an external sub-composition
whose timeline has settled.

Environment

  • [email protected] (npm; tarball verified against the v0.6.110 GitHub tag)
  • Node 22.x
  • Linux (Debian-based container, headless Chromium bundled by hyperframes)
  • Render mode (not preview)

Context

I caught this while empirically validating an npm pin bump in helmdeck — we wrap hyperframes in a render pack and were investigating
a related operator-visible bug where LLM-generated compositions had mismatched root/child durations. Our workaround on our side (PR
#546
) rewrites the child's data-duration to match the root's whenever they started equal, which sidesteps this entirely — but I
wanted to surface the upstream behavior because it's a clean repro and the symptom matches #911's framing.

Happy to test a candidate fix against the same reproducer.

Two heads-ups when pasting:

  • The triple-backticks for the inner html and bash blocks I escaped with a zero-width space (you'll see them as instead of). Strip those zero-width chars before
    pasting, OR retype the inner fences. (Or grab it from /tmp/upstream-issue-body.md` directly — that one has no escaping.)
  • Title: Sub-composition slot still blanks at child data-duration when host continues (after Sub-composition slot goes black after GSAP timeline ends, regardless of host data-duration #911 fix in 0.6.110)

Activity

  1. miguel-heygen commented on Jun 17, 2026

    @miguel-heygen
    Collaborator

    Thanks for the unusually thorough writeup — the repro and frame table made this quick to confirm.

    I reproduced the behavior (visible at t=14s, blank at t=20s+ with a child data-duration="15" under a 331s host), but after tracing it I don't think this is a runtime bug — it's working as designed, and it's a different case from #911.

    The distinction from #911:

    The rule you quoted — "data-duration takes precedence" — is exactly what's producing this: a clip with data-duration="15" is a 15-second window on the timeline and ends at 15s. Holding it to the host's 331s would require ignoring data-duration, i.e. the opposite of that rule, and would re-break the #917 contract (a correctly-sized slot must end on time even when its GSAP timeline is shorter). Your helmdeck workaround — rewriting the child data-duration to match the root — is actually the correct authoring fix: if you want a sub-composition to fill the whole host, its data-duration should span the host window.

    That said, you're right that it fails silently, and a single full-bleed sub-composition shorter than its host is almost always a mistake. So rather than change the runtime, #1542 surfaces it at author time:

    PR: #1542. Closing this as working-as-designed once that lands, but happy to keep iterating if the lint heuristic misses your real-world cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions