test(producer): add variables-prod regression test for the variables stack

End-to-end Docker regression test that exercises the full variables
chain: meta.json renderConfig.variables → harness → createRenderJob →
RenderConfig → CaptureOptions → engine evaluateOnNewDocument →
window.__hfVariables → getVariables() → DOM text → rendered pixels.

Fixture (packages/producer/tests/variables-prod/):
- src/index.html: composition with three declared variables (title,
  subtitle, bgColor) read via window.__hyperframes.getVariables() and
  rendered as positioned text on a colored background. No animation —
  keeps the regression frame-stable so it isolates "did the variables
  flow through?" from motion concerns.
- meta.json: tags ["variables", "composition"] (runs in the existing
  fast shard's tag filter), renderConfig.variables provides override
  values the baseline reflects ("Override Title", "Override subtitle",
  #0a3d62). Defaults would produce a visibly different frame, so a
  failing baseline that reflects defaults means the variables didn't
  propagate.
- output/output.mp4: Docker-generated baseline per the project's
  CLAUDE.md golden-baseline rule.

Harness change (packages/producer/src/regression-harness.ts):
- TestMetadata.renderConfig gains an optional variables field,
  validated as a JSON object in the meta.json validator.
- The createRenderJob call site forwards renderConfig.variables to
  RenderConfig.variables, which the engine already consumes via
  evaluateOnNewDocument (PR #600).

Verified: docker:test variables-prod passes 100/100 visual checkpoints
and audio correlation 1.000 against the committed baseline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
James
2026-05-04 20:33:43 +00:00
committed by James Russo
co-authored by Claude Opus 4.7
parent 62c2589839
commit 58b4234809
6 changed files with 268 additions and 0 deletions
@@ -0,0 +1,96 @@
<!doctype html>
<html
lang="en"
data-composition-variables='[
{"id":"title","type":"string","label":"Title","default":"Default Title"},
{"id":"subtitle","type":"string","label":"Subtitle","default":"Default subtitle"},
{"id":"bgColor","type":"color","label":"Background","default":"#0b0b0d"}
]'
>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
margin: 0;
width: 1920px;
height: 1080px;
overflow: hidden;
}
body {
background: #0b0b0d;
font-family: -apple-system, "Helvetica Neue", Arial, sans-serif;
}
[data-composition-id="main"] {
width: 100%;
height: 100%;
position: relative;
}
.title {
position: absolute;
top: 380px;
left: 0;
right: 0;
font-size: 140px;
font-weight: 700;
color: #ffffff;
text-align: center;
line-height: 1;
}
.subtitle {
position: absolute;
top: 600px;
left: 0;
right: 0;
font-size: 56px;
color: #9aa0a6;
text-align: center;
line-height: 1;
}
</style>
</head>
<body>
<div
id="root"
data-composition-id="main"
data-start="0"
data-duration="3"
data-width="1920"
data-height="1080"
>
<audio
id="silence-track"
src="silence.wav"
data-start="0"
data-duration="3"
data-track-index="0"
></audio>
<h1 id="title-el" class="title clip" data-start="0" data-duration="3"></h1>
<p id="subtitle-el" class="subtitle clip" data-start="0" data-duration="3"></p>
</div>
<script>
// Render-time values: declared defaults from data-composition-variables
// merged with overrides from meta.json's renderConfig.variables (which
// arrive via window.__hfVariables, injected by the engine).
const vars = window.__hyperframes.getVariables();
document.body.style.background = vars.bgColor;
document.getElementById("title-el").textContent = vars.title;
document.getElementById("subtitle-el").textContent = vars.subtitle;
window.__timelines = window.__timelines || {};
const tl = gsap.timeline({ paused: true });
// Static placement — no animation. Keeps the regression frame-stable
// and isolates "did the variables flow through?" from motion concerns.
tl.to({}, { duration: 2 });
window.__timelines["main"] = tl;
</script>
</body>
</html>