Skill Tracer
Skills › HyperFrames › remotion-to-hyperframes › README.md

README.md

86 lines · skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/README.md at a595755

Open on GitHub
1# Tier 3 — stargazed-data-driven
2

Tier 3 — stargazed-data-driven

Raw lines 1 to 2
3## What it tests
4
5A purpose-built data-driven fixture that exercises the realistic shape of a
6production Remotion composition without using the runtime adapter from
7PR #214. If a translation passes T3, the skill correctly handles:
8
9- A `<Composition>` with a `z.object` schema and typed `defaultProps`
10- Custom React subcomponents reused with different props across scenes
11- A nested data structure (`stats[]`) materialized as repeated HTML with
12 per-instance attributes
13- A frame-driven count-up animation (`AnimatedNumber` → GSAP `onUpdate`)
14- Two different `spring` configs translated to two different `back.out` overshoots
15- Per-instance delays via component props (`delayInFrames` → GSAP timeline offsets)

What it tests

A purpose-built data-driven fixture that exercises the realistic shape of a production Remotion composition without using the runtime adapter from PR #214. If a translation passes T3, the skill correctly handles:

  • A <Composition> with a z.object schema and typed defaultProps
  • Custom React subcomponents reused with different props across scenes
  • A nested data structure (stats[]) materialized as repeated HTML with per-instance attributes
  • A frame-driven count-up animation (AnimatedNumber → GSAP onUpdate)
  • Two different spring configs translated to two different back.out overshoots
  • Per-instance delays via component props (delayInFrames → GSAP timeline offsets)
Raw lines 3 to 16
17## Composition shape
19```
20Stargazed (10 s @ 30 fps, 1280×720)
21├── Sequence 0–3 s TitleScene
22│ ├── title ← spring scale
23│ └── subtitle ← linear fade
24├── Sequence 3–7 s StatsScene
25│ ├── StatCard "Stars" 1247 #fbbf24 (delay 0 frames)
26│ ├── StatCard "Forks" 312 #60a5fa (delay 12 frames)
27│ └── StatCard "Issues" 48 #f87171 (delay 24 frames)
28└── Sequence 7–10 s OutroScene
29 └── UnderlinedText "thanks for watching" ← scale-in underline
30```
32Each `StatCard` is a custom subcomponent that internally uses `AnimatedNumber`
33to count from 0 to the target. `AnimatedNumber` itself derives the displayed
34value from `useCurrentFrame()` + a manual `1 - (1 - t)^3` ease.

Composition shape

Stargazed (10 s @ 30 fps, 1280×720)
├── Sequence 0–3 s   TitleScene
│                    ├── title  ← spring scale
│                    └── subtitle ← linear fade
├── Sequence 3–7 s   StatsScene
│                    ├── StatCard "Stars" 1247 #fbbf24 (delay 0 frames)
│                    ├── StatCard "Forks" 312 #60a5fa  (delay 12 frames)
│                    └── StatCard "Issues" 48 #f87171  (delay 24 frames)
└── Sequence 7–10 s  OutroScene
                     └── UnderlinedText "thanks for watching" ← scale-in underline

Each StatCard is a custom subcomponent that internally uses AnimatedNumber to count from 0 to the target. AnimatedNumber itself derives the displayed value from useCurrentFrame() + a manual 1 - (1 - t)^3 ease.

Raw lines 17 to 35
36## The lossy parts (and why threshold = 0.90)
381. **`spring → back.out(N)`**: two different spring configs in this composition.
39 - `{ damping: 12, stiffness: 100, mass: 1 }` (title) → `back.out(1.4)`
40 - `{ damping: 14, stiffness: 90, mass: 1 }` (stat card) → `back.out(1.2)`
42 Overshoot ratio (1.4 vs 1.2) approximates the damping difference. The
43 late-tail curve of GSAP's back ease and Remotion's spring don't match
44 exactly — costs ~0.03 mean SSIM per spring instance.
462. **Count-up easing**: `AnimatedNumber` uses `1 - (1 - t)^3` (cubic ease-out)
47 manually computed in the component. GSAP's `power2.out` matches that cubic curve
48 exactly (`power3.out` is quartic). Compare the rounded integers at matching
49 frame times in both renderers; matching final values alone does not validate
50 the easing curve.
523. **Font rendering**: same caveat as T1/T2. System Helvetica/Arial fallback
53 produces minor anti-aliasing differences between renderers. Affects the
54 stat card numbers (large weight 800) most.
56A mean SSIM below 0.90 in T3 indicates a _structural_ mismatch (wrong scene
57durations, wrong stagger timing, missing prop wiring), not approximation
58drift. That's the failure signal we care about. The September 18 measurement
59against Remotion @ 4.0 with PNG/BT.709 output was 0.953 for the quartic
60translation; it does not measure the corrected cubic count-up.

The lossy parts (and why threshold = 0.90)

  1. **spring → back.out(N)**: two different spring configs in this composition.
  2. { damping: 12, stiffness: 100, mass: 1 } (title) → back.out(1.4)
  3. { damping: 14, stiffness: 90, mass: 1 } (stat card) → back.out(1.2)

Overshoot ratio (1.4 vs 1.2) approximates the damping difference. The late-tail curve of GSAP's back ease and Remotion's spring don't match exactly — costs ~0.03 mean SSIM per spring instance.

  1. Count-up easing: AnimatedNumber uses 1 - (1 - t)^3 (cubic ease-out) manually computed in the component. GSAP's power2.out matches that cubic curve exactly (power3.out is quartic). Compare the rounded integers at matching frame times in both renderers; matching final values alone does not validate the easing curve.
  1. Font rendering: same caveat as T1/T2. System Helvetica/Arial fallback produces minor anti-aliasing differences between renderers. Affects the stat card numbers (large weight 800) most.

A mean SSIM below 0.90 in T3 indicates a structural mismatch (wrong scene durations, wrong stagger timing, missing prop wiring), not approximation drift. That's the failure signal we care about. The September 18 measurement against Remotion @ 4.0 with PNG/BT.709 output was 0.953 for the quartic translation; it does not measure the corrected cubic count-up.

Raw lines 36 to 61
62## Translation walk-through (skill cheat sheet)
64| Remotion | HyperFrames |
65| --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
66| `<Composition schema={z.object({...})} defaultProps={...} />` | data-\* attributes on root `#stage` div |
67| nested array prop (`stats[]`) | repeated HTML markup with per-instance `data-*` attrs |
68| custom React subcomponent | inline repeated HTML using the component's prop interface as the template |
69| `<AnimatedNumber from={0} to={value} dur={45} />` (cubic ease-out count-up) | tween on `{ v: 0 }` object with `onUpdate` rewriting `textContent`, ease `power2.out` |
70| `spring({damping:12, stiffness:100})` | `back.out(1.4)` over ~0.7 s |
71| `spring({damping:14, stiffness:90})` | `back.out(1.2)` over ~0.7 s |
72| `delayInFrames={i * 12}` (per-instance) | GSAP timeline offset `(i * 0.4)` s |
73| `useVideoConfig()` to get `fps` | dropped — composition fps is in `data-fps` on `#stage` |

Translation walk-through (skill cheat sheet)

RemotionHyperFrames
<Composition schema={z.object({...})} defaultProps={...} />data-\* attributes on root #stage div
nested array prop (stats[])repeated HTML markup with per-instance data-* attrs
custom React subcomponentinline repeated HTML using the component's prop interface as the template
<AnimatedNumber from={0} to={value} dur={45} /> (cubic ease-out count-up)tween on { v: 0 } object with onUpdate rewriting textContent, ease power2.out
spring({damping:12, stiffness:100})back.out(1.4) over ~0.7 s
spring({damping:14, stiffness:90})back.out(1.2) over ~0.7 s
delayInFrames={i * 12} (per-instance)GSAP timeline offset (i * 0.4) s
useVideoConfig() to get fpsdropped — composition fps is in data-fps on #stage
Raw lines 62 to 74
75## How to render and evaluate
77```bash
78# Render Remotion baseline (no setup.sh — no binary assets in this fixture)
79cd remotion-src && npm install && npm run render
81# Render HyperFrames translation
82cd ../hf-src && npx hyperframes render --output ../hf.mp4
84# Compare
85npx hyperframes diff ../remotion-src/out/baseline.mp4 ../hf.mp4 --out ../diff
86```

How to render and evaluate

# Render Remotion baseline (no setup.sh — no binary assets in this fixture)
cd remotion-src && npm install && npm run render

# Render HyperFrames translation
cd ../hf-src && npx hyperframes render --output ../hf.mp4

# Compare
npx hyperframes diff ../remotion-src/out/baseline.mp4 ../hf.mp4 --out ../diff
Raw lines 75 to 86