Tier 2 — title-image-outro
What it tests
Three-scene composition. Each scene exercises a different Remotion idiom:
- Scene 1 (0–2 s) — TitleScene with
spring({damping:12, stiffness:100, mass:1})driving atransform: scale()on text. Tests the lossyspring → GSAP easetranslation. - Scene 2 (2–4 s) — ImageScene that fades in a
staticFile-loaded image and linearly scales it from 0.8 → 1.0. Tests asset paths + linearinterpolate. - Scene 3 (4–6 s) — OutroScene with a 1-s linear fade-in. Sanity check after the harder scenes.
A silent 6-second WAV plays throughout at volume={0.5}. Tests <Audio> translation.
If a translation passes T2, the skill correctly handles <Sequence> boundaries,
<Audio> / <Img> / staticFile, and the Remotion spring → GSAP ease heuristic.
Translation walk-through
| Remotion | HyperFrames |
|---|---|
<Sequence from={0} durationInFrames={60}> |
<div data-start="0" data-duration="2" data-track-index="0"> |
spring({frame, fps, config: {damping:12, stiffness:100, mass:1}}) |
gsap.to(target, { scale: 1, duration: 0.7, ease: "back.out(1.4)" }) |
<Audio src={staticFile("music.wav")} volume={0.5} /> |
<audio src="assets/music.wav" data-start="0" data-duration="6" data-volume="0.5" data-track-index="1"> |
<Img src={staticFile("square.png")} /> |
<img src="assets/square.png"> (with setup.sh copying into both trees) |
interpolate(frame, [0, 15], [0, 1]) at 30 fps |
gsap.to(target, { opacity: 1, duration: 0.5, ease: "none" }) |
The scene crossfading is a HyperFrames idiom, not a Remotion one: at scene boundaries
we gsap.set(scene, { opacity: 0 }) so the previous scene disappears at the
right time. Remotion does this implicitly by virtue of <Sequence>'s durationInFrames.
How to render and evaluate
# 1. Generate the binary assets (PNG + WAV) via ffmpeg
./setup.sh
# 2. Render Remotion baseline
cd remotion-src && npm install && npm run render
# 3. Render HyperFrames translation
cd ../hf-src && npx hyperframes render --output ../hf.mp4
# 4. Compare
../../../scripts/render_diff.sh ./remotion-src/out/baseline.mp4 ./hf.mp4 ./diff
Why threshold 0.95?
Same threshold as T1 (expected.json codifies it for the orchestrator). Spring → back.out(1.4)
came in cleaner than predicted during calibration — the validated mean is 0.985 against the
0.95 gate. If the translation breaks anything else (spring overshoot wrong, stagger off,
asset path drift), mean SSIM will fall well below 0.95 — that's the failure signal.