Skip to content

decision-tree example renders 2 unique frames, and check + render both report success #3352

Description

@miguel-heygen

Describe the bug

The shipped decision-tree example renders a 10-second video containing 2 unique
frames
, and both quality gates report success while it happens.

Two defects, and the second is the serious one:

  1. registry/examples/decision-tree/compositions/decision_tree.html:388 reads
    tl.labels["hold5"]. At render time tl.labels is undefined, so the composition
    script throws and the timeline is never built.
  2. Nothing fails. check exits 0 and prints "Check passed". render logs the
    TypeError, then logs sub_timeline_readiness_timeout after waiting 45 seconds,
    then writes the mp4 and exits 0. A user following the quickstart gets a green
    check, a green render, and a still image.

Anyone starting from this example hits it on their first render.

Steps to reproduce

npx --yes hyperframes@0.8.2 init decision-tree --non-interactive --example=decision-tree
cd decision-tree
npm run check                                              # exits 0, "Check passed"
npm run render -- --quality draft --output renders/dt.mp4  # exits 0

# count unique frames in the result
mkdir -p /tmp/dtf && ffmpeg -v error -i renders/dt.mp4 -vf fps=1 /tmp/dtf/f%03d.png
ls /tmp/dtf | wc -l          # 10 sampled
md5 -q /tmp/dtf/*.png | sort -u | wc -l   # 2 unique

Expected behavior

The example renders its intended animation. Failing that, a composition script that
throws, or a sub-composition timeline that never registers, fails the render loudly
instead of producing a near-static file with a zero exit code.

Actual behavior

check:

  0 error(s), 1 warning(s), 1 info(s)
Motion     ◇ 0 errors, 0 warnings
Contrast   ◇ 37/37 text checks pass WCAG AA
◇  Check passed

render:

[Browser:ERROR] [Compiler] Composition script failed decision-tree TypeError: Cannot read properties of undefined (reading 'hold5')
[FrameCapture] Sub-composition timelines not registered after 45000ms: decision-tree. ...
[FrameCapture:sub_timeline_readiness_timeout] Sub-composition timelines did not become ready within 45000ms { timeoutMs: 45000 }
[INFO] Calibration complete, estimated cost: 22ms/frame (p95)

The TypeError repeats during capture. The render then completes normally.

Output: 10.000000s, 193338 bytes, and sampling at 1 fps yields two distinct images —
one held for the first 8 samples, another for the last 2.

The failing code

// registry/examples/decision-tree/compositions/decision_tree.html:384
tl.addLabel("hold5", "+=0.2");

// :388
const typingStart = tl.labels["hold5"];

addLabel does not throw; the subsequent read of tl.labels does, so tl.labels is
undefined on the render path specifically. I have not determined why — that is worth
establishing before fixing, because if the timeline object exposed during render does
not carry labels, then every composition that reads a label position is affected and
this example is just the one we happen to ship.

Why the gate half matters more than the example

Fixing the example alone would close the symptom and leave the hole. Today a
composition script can throw on every frame, a sub-composition timeline can time out
after 45 seconds, and the pipeline still reports success. Both of those are already
detected and logged — they simply are not wired to an exit code.

Concretely worth deciding:

  • A [Compiler] Composition script failed error should fail the render, or at minimum
    fail it under --strict, rather than only appearing in the log.
  • sub_timeline_readiness_timeout after a full 45-second wait is not a soft condition.
    If a composition legitimately has no GSAP timelines it can declare data-no-timeline,
    which is what that opt-out exists for, so reaching the timeout means something is
    genuinely wrong.

Environment

hyperframes  0.8.2 (pinned by the scaffold; latest 0.8.3)
Node.js      v22.23.1 (darwin arm64)
Capture      drawelement -> beginframe, --quality draft, 6 workers

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions