Skip to content

fix(producer): a clip bound by its mount's variable values plays the bound file - #6501

Merged
miguel-heygen merged 5 commits into
mainfrom
fix/variable-bound-media-src
Oct 27, 2026
Merged

miguel-heygen merged 5 commits into
mainfrom
fix/variable-bound-media-src

Conversation

@miguel-heygen

@miguel-heygen miguel-heygen commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

What was wrong

A clip bound with data-var-src inside a sub-composition rendered frozen at its authored placeholder's length when the mount set the real file through data-variable-values. Reported on 0.8.206 (rated 4/10): a <video data-start="0" data-duration="60" data-var-src="src"> over a 3 s placeholder, mount value a 13 s clip; the render played the first 3.1 s and held the last frame. No error anywhere.

The compiler can only read the authored src, so media bound to a variable is sent through a browser probe that reads what the runtime resolved. hasVariableBoundMedia, the gate for that probe, only asked whether the render's own --variables named the element's variable. A value from the mount's data-variable-values, or a default the composition declares, never opened it, so frame extraction and the audio mix used the placeholder.

Fix

hasVariableBoundMedia asks the question the runtime answers: does the element's variable have a value anywhere it looks: the render's variables, the data-variable-values of a mount above the element, or a declared default (data-composition-variables)? It reads them with parseHostVariableValues and readDeclaredDefaults, the readers the bundler and runtime already use. A variable with no value anywhere still skips the browser, as before.

Design calls:

  • Fixed at the gate, not by resolving the source in the compiler: the browser probe already reconciles source, duration and audio for the render-variable case, so the mount and default cases go through the same path.
  • A declared default counts even when it equals the placeholder: a few more renders launch the probe, and none can be wrong.

What I measured

fails without the fix: against main's gate, the new real-render test fails (expected 0 to be greater than 200: the frame at 6 s is the black placeholder, not the white part of the bound clip), and the three new gate and compile cases fail (70 pass, 3 fail); with the fix all pass (73 pass in probeStage plus the compile fixture, miga, Linux).

The real render (variableMountMedia.integration.test.ts): a 3 s black placeholder, a 13 s clip that is black for 5 s then white, a mount binding the 13 s clip, rendered for 8 s; the frame at 1 s is black and the frame at 6 s is white. The compile fixture (htmlCompiler.variableMedia.test.ts) uses the same 3 s and 13 s files. Both are added to the integration lane list. Fallow audit, oxfmt, oxlint and the reachability check pass locally.

What I did NOT exercise

A default a sub-composition declares on its own file's <html data-composition-variables>: inlining drops that attribute, so the gate cannot see it and a clip bound to such a default (with no mount value and no render variable) still uses its authored src. Only a default declared on the root <html> or a composition element is read. The mount-value case that was reported is covered.

The Studio preview: it resolves bindings in the browser runtime (applyVariableBindings), which this does not touch, and I did not open it. The audio side of the same bound clip: the probe reconciles audio entries by the same path, but the test measures picture only. A variable bound on an <img> or <source>, and a declared default that differs from the placeholder, are covered by the gate's unit cases, not by a render.

@miguel-heygen
miguel-heygen force-pushed the fix/variable-bound-media-src branch from 62c534f to 386b401 Compare October 27, 2026 01:23
@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Edit accuracy: accurate 271 (base branch 271), smooth 126 of those

The gate passes.
Smoothness is reported in the artifact, not gated. A case fails only if it fails 2 of 3 runs.

Quarantined, measured but not gated (0)

Unstable (1)

  • seqplainkeys-none-px-r0-root-z100: tracking 0.06, pressJump 0, drop 0, reload 0, render 0.03, renderKey -, undo false, teleport true / tracking 0.06, pressJump 0, drop 0, reload 0, render 0.03, renderKey -, undo true, teleport true / tracking 0.06, pressJump 0, drop 0, reload 0, render 0.03, renderKey -, undo true, teleport true

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: REQUEST CHANGES · 1 blocker · 0 important · 0 nits

The fix itself looks right. The blocker is the required Comments check, which fails on this head (inline).

Scope

Read probeStage.ts, its tests, the compile fixture, the real-render test and the integration lane list at 386b4016, plus parseHostVariableValues/readDeclaredDefaults (both tolerate malformed JSON) and the loader's mount scope (stashInstanceVariables: declared defaults plus host values). Locally: bun test on htmlCompiler.variableMedia and probeStage passes 73/73. CI is green except Comments; Windows render was still running.

Not a finding, unverified: a sub-composition that declares its default on its file's <html data-composition-variables> (the loader reads doc.documentElement) loses that attribute in the compiled HTML. A scratch compile shows hasVariableBoundMedia returning false there, while the template-root form returns true. I did not check whether the render runtime still resolves that default.

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE — 1 resolved, 0 open, 0 new · 386b401 → c48378e. The change is comment-only, and CI is green including Comments. The PR body now names the <html>-declared default as not covered.

@miguel-heygen
miguel-heygen added this pull request to the merge queue Oct 27, 2026
Merged via the queue into main with commit c618724 Oct 27, 2026
121 of 122 checks passed
@miguel-heygen
miguel-heygen deleted the fix/variable-bound-media-src branch October 27, 2026 03:25
valeriangalliat added a commit to ArcadeHQ/hyperframes-next that referenced this pull request Nov 10, 2026
Drops patch/probe-var-src-media (heygen-com#6501 probes data-var-src media bound by
a mount's values or a root default) and patch/distributed-page-motion-blur
(heygen-com#7311 lets distributed renders honour page motion blur). Records the
upstream issue for patch/probe-untraced-media-src.
valeriangalliat added a commit to ArcadeHQ/hyperframes-next that referenced this pull request Nov 10, 2026
Drops patch/probe-var-src-media (heygen-com#6501 probes data-var-src media bound by
a mount's values or a root default) and patch/distributed-page-motion-blur
(heygen-com#7311 lets distributed renders honour page motion blur). Records the
upstream issue for patch/probe-untraced-media-src.
valeriangalliat added a commit to ArcadeHQ/hyperframes-next that referenced this pull request Nov 10, 2026
Drops patch/probe-var-src-media (heygen-com#6501 probes data-var-src media bound by
a mount's values or a root default) and patch/distributed-page-motion-blur
(heygen-com#7311 lets distributed renders honour page motion blur). Records the
upstream issue for patch/probe-untraced-media-src.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant