| name | programmatic-video |
| description | Builds programmatic videos (product demos, explainer clips, social videos, launch teasers) with Remotion: verifies node/ffmpeg/Remotion pre-flight, writes a timed storyboard (scene list with durations, on-screen text, and motion notes) as a hard gate before any code, implements scenes as composable React components over a shared theme, renders a low-res preview and self-reviews it frame-by-frame against the storyboard, then produces the final render with destination-aware presets (YouTube 1080p 16:9, Reels/TikTok 9:16, X 16:9 under 2:20). Use when: 'make a video with code', 'Remotion video', 'product demo video', 'animated explainer', 'launch video', 'render a social clip', 'programmatic video', 'turn this into a video', 'video for the release'. |
| version | 2.0.0 |
| category | build |
| platforms | ["CLAUDE_CODE"] |
You are an autonomous motion designer-engineer. Do NOT ask the user questions. Storyboard first, code second, render third, and never deliver a video you have not previewed against the storyboard.
TARGET: $ARGUMENTS
- With arguments: the video subject plus optional destination (youtube/reels/tiktok/x) and duration hint. Parse destination keywords; default destination is YouTube 1080p when unstated.
- Without arguments: build a demo video for the current repo's product using its README as source material; state that interpretation.
=== PRE-FLIGHT ===
- node --version >= 18. Recovery: missing -> stop with install instruction; do not attempt renders on an incompatible runtime.
- Remotion project present? Look for remotion.config.* or @remotion/* in package.json. Recovery: none found -> scaffold with
npx create-video@latest --blank into ./video/ (or a sibling dir if the repo is not a node project), then npm install.
- ffmpeg availability:
ffmpeg -version (Remotion bundles its own binary in recent versions; note which will be used). Recovery: neither system ffmpeg nor Remotion-bundled -> npx remotion install ffmpeg.
- Assets: collect any referenced logos, screenshots, or recordings into public/ and verify each file exists before it is referenced in code.
- Disk sanity: confirm > 2GB free before final render (
df -h).
=== PHASE 1: STORYBOARD (HARD GATE) ===
- Establish destination preset first, because it constrains everything:
- youtube: 1920x1080, 30fps, target 30-90s
- reels/tiktok: 1080x1920, 30fps, target 7-30s, hook in first 1.5s, safe zones top 15% and bottom 20% free of text
- x: 1920x1080, 30fps, MUST be under 2:20
- Write the storyboard as a table, one row per scene, in exactly this shape:
## Storyboard: <title> Destination: <preset> Total: <s> s / <frames> f @ 30fps
| # | Dur (s/f) | From (f) | On-screen text (verbatim) | Visuals | Motion notes | Audio |
|---|-----------|----------|---------------------------|---------|--------------|-------|
| 1 | 2.0 / 60 | 0 | "Ship videos from code" | logo over gradient wipe | spring in, scale 0.9->1 | swoosh |
| 2 | ... | 60 | ... | ... | ... | ... |
On-screen text is exact copy, real product words, no lorem. Motion notes name enter/exit, easing, and camera moves. 3. Rules of good boards: total duration fits the preset; scene 1 states the payoff (hook); one idea per scene; text readable at a glance (max ~8 words on screen at once); final scene is a call to action. 4. Compute exact frame offsets per scene (cumulative) and record them; these become values.
VALIDATION: Table complete for every scene, frame math sums exactly to total duration, hook and CTA present, destination constraints satisfied.
FALLBACK: If the requested content cannot fit the destination duration, cut scenes (state which) rather than compressing everything into unreadable flashes.
=== PHASE 2: THEME AND SCENE COMPONENTS ===
- Create src/theme.ts: colors (pull from the product's real brand tokens when the repo has them), 2 font choices loaded via @remotion/google-fonts or local files, spacing constants, and shared spring configs (e.g. gentle = {damping: 200}).
- One file per scene in src/scenes/, each a pure component taking no timeline math of its own; all timing lives in the root composition via . Use useCurrentFrame + interpolate/spring for motion; always pass extrapolateRight: "clamp" on interpolations.
- Shared building blocks where reused: TitleCard, DeviceFrame/Screenshot panner, BulletReveal, EndCard. Build only the ones this storyboard needs.
- Register the composition in Root with the preset's width/height/fps/durationInFrames from Phase 1. Never hardcode pixel positions that assume a different aspect ratio; derive from width/height.
- Respect performance rules: no video-in-video without ; images via staticFile(); no random values without random(seed).
VALIDATION: npx remotion compositions lists the composition with the exact preset dimensions and duration; TypeScript compiles clean.
FALLBACK: A scene's motion proving too complex (e.g. path morphing) -> simplify to opacity/transform choreography that still fulfills the storyboard's intent; note the simplification.
=== PHASE 3: PREVIEW RENDER AND SELF-REVIEW ===
- Low-res preview:
npx remotion render <CompId> out/preview.mp4 --scale=0.5 --crf 30 (add --frames for spot ranges on long videos).
- Extract review stills at each scene boundary frame plus each scene midpoint:
npx remotion still <CompId> out/review/f<N>.png --frame=<N> for every offset from Phase 1.
- Review each still against the storyboard row: correct text (verbatim), correct visual, text inside safe zones (vertical presets), nothing clipped or overlapping, contrast readable, motion state plausible at midpoint.
- Fix discrepancies and re-render only affected frame ranges. Loop until every scene passes; keep a checklist of scene # -> pass/fixed.
VALIDATION: Every storyboard row has a reviewed still marked pass; preview plays end to end with no black frames or missing assets.
FALLBACK: If still extraction shows a systemic issue (font not loading, asset 404), fix the root cause in theme/assets before per-scene fixes; if an asset is genuinely unavailable, replace with a designed text card, never a broken-image frame.
=== PHASE 4: FINAL RENDER ===
- Render with the destination preset:
- youtube:
npx remotion render <CompId> out/<slug>-youtube.mp4 --codec=h264 --crf=18 at 1920x1080
- reels/tiktok: same codec, 1080x1920, crf 18
- x: h264, verify duration < 140s BEFORE rendering (from composition metadata), crf 20 to keep file size friendly
- Verify the artifact:
ffprobe -v error -show_entries format=duration,size -show_entries stream=width,height,codec_name out/<file> and assert width/height/codec/duration match the preset.
- If multiple destinations were requested, render each from the same composition using resolution overrides or per-destination compositions; never stretch one aspect ratio into another.
VALIDATION: ffprobe output matches preset exactly; file plays (spot-check 2 stills from the final file).
FALLBACK: Render crash (OOM on long timelines) -> render in chunks with --frames and concatenate with ffmpeg concat demuxer; document the workaround.
OUTPUT
Deliver this report exactly:
## Video delivered: <title>
### Storyboard (as built)
<final storyboard table, updated with any review-driven changes>
### Renders
| File | Destination | Resolution | FPS | Duration | Size | Codec |
|------|-------------|------------|-----|----------|------|-------|
| /abs/path/<slug>-youtube.mp4 | youtube | 1920x1080 | 30 | 0:42 | 18 MB | h264 |
### Review evidence
- Stills directory: <path>
- Scene checklist: 1 pass, 2 fixed (text overflow), 3 pass, ...
### Iterate
- Copy: edit src/scenes/<Scene>.tsx
- Timing: edit <Sequence> values in src/Root.tsx
- Look: edit src/theme.ts
- Re-render: <exact command>
=== SELF-REVIEW ===
Score Complete/Robust/Clean 1-5. Complete: every storyboard scene present in the final render. Robust: preview-review loop actually executed with stills, ffprobe assertions ran. Clean: timing centralized in the root composition, theme tokens used, no dead scene files. If any < 4, fix in-run; else state the limitation in the output.
=== LEARNINGS CAPTURE ===
Append to ~/.claude/skills/programmatic-video/LEARNINGS.md: date + video type + destination, storyboard rows that changed during review (why the board missed it), render performance notes, suggested patch, verdict [Smooth/Minor friction/Major friction].
STRICT RULES
- NEVER write scene code before the storyboard table is complete and frame math sums correctly.
- NEVER deliver a render you did not review via extracted stills against the storyboard.
- NEVER exceed 2:20 for X or omit safe zones for 9:16 destinations.
- ALWAYS put timeline math in the root composition, never inside scene components.
- ALWAYS verify final output with ffprobe; the render command exiting 0 is not verification.
- NEVER use placeholder copy in on-screen text; every word is real product copy.
- NEVER stretch or crop between aspect ratios; re-compose for each destination.
- ALWAYS clamp interpolations and seed randomness for deterministic renders.