{ "tier": 3, "name": "stargazed-data-driven", "composition_id": "Stargazed", "description": "Data-driven 10-second composition with three scenes, custom React subcomponents reused across scenes, a Zod schema with defaultProps, and a count-up number animation. Translates the realistic shape of a production Remotion composition into HF — without using the runtime adapter from PR #214.", "duration_seconds": 10, "fps": 30, "width": 1280, "height": 720, "ssim_threshold": 0.9, "validation": { "measured_mean_ssim": 0.953, "measured_min_ssim": 0.927, "measured_p05_ssim": 0.938, "measured_p95_ssim": 0.977, "measured_at": "2026-04-27", "measured_against": "remotion@4.0 (PNG output, BT.709) vs hyperframes@0.4.15-alpha.1", "notes": "Count-up timing in StatsScene shows a few-frame offset between Remotion's manual 1-(1-t)^3 and GSAP's power3.out — both formulas are identical, so the offset comes from sub-frame timing of when the seek + onUpdate fire. Final values converge correctly. Visible only as transient digit mismatches mid-animation; no SSIM impact above the noise floor." }, "remotion_apis_exercised": [ "Composition with z.object schema and typed defaultProps", "Sequence (3 nested with computed offsets)", "AbsoluteFill", "useCurrentFrame, useVideoConfig", "interpolate (single-segment, multi-segment, with extrapolation)", "spring (two configs: damping:12 and damping:14)", "Custom React subcomponents reused with different props (StatCard ×3)", "Custom React utility component (AnimatedNumber for count-up)", "Custom React utility component (UnderlinedText)", "Per-instance delay via prop (delayInFrames)" ], "translation_notes": [ "Zod schema + defaultProps → data-* attributes on the root #stage div. The skill emits one data attribute per scalar prop; nested arrays (stats[]) get materialized as repeated HTML markup with per-instance data attributes (data-stat-index, data-stat-value, --card-color).", "Custom React subcomponents inline as repeated HTML divs. The component prop interface becomes the repeated markup template. This is lossy for components with internal state — fine here because StatCard, AnimatedNumber, UnderlinedText all derive from props alone.", "AnimatedNumber's frame-driven count-up → a GSAP tween on a { v: 0 } counter object with onUpdate rewriting textContent. GSAP's power3.out is cubic easeOut, matching the Remotion 1-(1-t)^3 manual ease.", "Two different springs in this composition: damping:12 → back.out(1.4) (snappy), damping:14 → back.out(1.2) (calmer). The 1.4 vs 1.2 overshoot ratio approximates the damping difference.", "Per-instance stagger via delayInFrames prop translates to a GSAP timeline offset of (i * 0.4)s.", "Threshold 0.90 reflects: spring → back.out approximation (×2 different configs), the count-up easing curve match (very close but not identical due to sub-frame seek timing), font/AA differences on body text. SSIM well below 0.90 indicates a structural mismatch, not approximation drift." ], "rationale": "Threshold 0.90 sits ~0.04 below measured p05 (0.938). The wider gap vs T1/T2 reflects T3's bigger approximation budget (2 spring instances + count-up timing + font fallback on multiple text sizes). Mean SSIM below 0.90 = structural mismatch (wrong durations, wrong stagger, missing prop wiring), not approximation drift." }