---
name: "explainer_animation"
description: "Storyboard-to-render pipeline for simple explainer animations with ffmpeg: kinetic typography captions, procedural backgrounds, Ken Burns stills, and voiceover-timed scenes. Use when asked to make an explainer animation, animate text over video, or build a narrated slideshow-style video without a GUI editor."
---

# Explainer Animation

## Purpose
Turn a storyboard (scenes + beats + captions + voiceover) into a finished narrated animation video using only ffmpeg — no GUI editor, no assets required beyond stills and VO audio.

## Workflow
1. **Storyboard.** Write one scene per JSON object (see `references/scene-pipeline.md` and the template at `assets/sample-storyboard.json`). Each scene: `name`, `duration`, `bg`, optional `captions`, optional `vo`.
2. **Voiceover first.** Get VO audio and its word timestamps *before* locking durations (see `references/vo-timing.md`). Scene duration = VO segment length + 0.5–1.0s padding. Text-driven layouts follow the VO, never the reverse.
3. **Render.** Run `bin/explainer.py storyboard.json -o out.mp4`. It renders each scene (background → captions → effects), concatenates, then mixes VO + optional music bed with loudness normalization.
4. **Verify.** ffprobe the total duration against the storyboard sum; spot-check 2–3 frames per scene (text present, positioned, on time). Fix the storyboard, never hand-edit intermediates.

## Output Contract
- One MP4 per storyboard: `<name>.mp4`, 1280×720, 30fps, H.264 + AAC, yuv420p.
- Captions visible only inside their `start → start+duration` windows, entry animation complete within 0.4s.
- VO audible, music bed ducked, peaks within streaming loudness (`loudnorm` I=-16 LUFS).

## Operating Rules
1. Never hand-edit the filtergraph in `bin/` at request time — fix the storyboard JSON instead; the renderer is the single source of truth.
2. Caption text is written via `textfile=` (never inline `text=`), so colons/apostrophes in copy cannot break the filtergraph.
3. Dynamic alpha only: `:alpha='expr'`. Never `fontcolor=white@'expr'` — that form fails for runtime expressions.
4. Never use dynamic `fontsize='expr'` (drawtext scale tricks) — one build family has segfaulted on it; simulate scale with alpha flashes and position snaps (see `references/text-recipes.md`).
5. All factual claims about ffmpeg options inside this skill were verified on ffmpeg 8.1.2 (2026-09-20); if a recipe fails on another build, simplify the filtergraph and note it in the storyboard log.
