YouTube video creator — narration → Manim → DrawCMS
Turn a folder of narration scripts (one markdown + one mp3 per chapter) into a chapter-per-video series plus one combined video, perfectly synchronised to the narration:
my-series/
├── narration/ # one .md + one .mp3 per chapter
├── .drawcms/ # DrawCMS diagram specs + build receipts
├── video/ # the pipeline (from templates/video/)
│ ├── segments.py # content spec: which beats cover which paragraphs
│ ├── timing.py # paragraph → seconds allocation from real audio
│ ├── beats.py # SegmentScene: renderers, animations, diagrams
│ ├── scenes.py # one Manim scene class per segment
│ ├── theme.py # palette + layout bands (rebrand this)
│ └── build.py # diagram | schedule | render | mux | concat
├── schedule.json # validated timeline (generated)
├── manim_build/ # rendered scenes (generated)
└── final/ # 01-*.mp4 … + full.mp4 (generated)
When to use
- The user has (or wants to write) narration markdown + mp3 files and wants videos built from them.
- Rebuilding an existing series after narration fixes, content edits, or style changes.
- Adding chapters, re-timing beats, or adding DrawCMS diagrams to a series.
Do not use this for: live-action editing, screen recordings, or audio-less videos — this pipeline is specifically script+narration → motion graphics.
Prerequisites
| Tool | Needed for | Notes |
|---|---|---|
| Python ≥3.10 + venv/uv | everything | uv venv .venv && uv pip install --python .venv/bin/python manim |
| Manim Community (0.22.x) | rendering | manim binary inside .venv/bin/ |
| ffmpeg + ffprobe | durations, mux, concat | on PATH |
| Node + DrawCMS CLI | diagrams (optional) | ~/.agents/skills/drawcms/bin/drawcms.mjs; override with DRAWCMS_CLI |
| faster-whisper | narration verification (optional but recommended) | uv pip install faster-whisper |
Fast path
Run everything from the project root (the folder holding video/).
- Scaffold. Copy
templates/video/→video/,templates/fixtures/contents →narration/,templates/.drawcms/→.drawcms/. Create the venv and install manim. Prove it works before touching content:python templates/smoke_test.py(from this skill's folder). - Verify narration. Transcribe every mp3 with faster-whisper and diff it
against the markdown word-for-word; fix mismatches before building
visuals. →
references/narration-sync.md - Author the content spec. For each segment, split the script into
paragraphs and give every beat a
paras: [start, end)range. The ranges must tile the script exactly —build.py scheduleenforces it. Beat text must be shorter than the narration it covers. →references/manim-beats.md - Validate timing.
.venv/bin/python video/build.py schedule→ all segmentsOK, total duration = sum of mp3s. Fix any tiling error now. - DrawCMS diagrams (optional). Author typed JSON specs in
.drawcms/, build receipts, drive them witharchitecturebeats that highlight subsets per beat. →references/drawcms-diagrams.md - Render one scene first (
build.py render intro --force), inspect frames, then render the rest. →references/verification.md - Verify. Beats probe, frame grid, full-res crops of every diagram
beat, bounds checks. →
references/verification.md - Mux + concat.
build.py mux --forcethenbuild.py concat(concatalways rebuilds). Check final durations with ffprobe. - Iterate. After any code/content change:
render <ids> --force→mux --force→concat. Renders are skipped when outputs are current, so a restart is always safe — but mux must be forced after a re-render or you ship stale video with new audio.
Detailed command reference and layout rationale → references/workflow.md.
Invariants (never violate these)
- Paragraph ranges tile the script.
[0,a), [a,b), … [z,n)with no gaps or overlaps. Timing derives from this; a gap = a silent stretch with no visuals, an overlap = double-counted seconds. - Beat text ≤ narration. The narrator says more than the card shows. Cards that read longer than the audio feel wrong even when sync is exact.
- No progress bar. The narration audio is the timeline; a bar adds noise and dates the video.
- Centered, sized text. Multi-line text is centered per line (Manim
left-aligns lines by default —
_text/_center_lineshandle this). Keep the type scale inreferences/text-animation.md. - Animations stagger; they never pop. Entrances are progressive (LaggedStart / scaled FadeIn), fit inside ~34% of the beat, and the rest of the beat is a hold. The final beat fades out with a ~0.6s tail.
- Diagrams stay in their band. Heading + diagram fit below the header
rule (
_r_architecturescales them in). Node labels must fit inside their boxes (auto-fit in_node_label); no mid-word breaks. - Edge labels only when ≤4 edges are highlighted (built into
_arch_style); more than that and the diagram becomes unreadable. - DrawCMS receipts are the source of truth for diagram topology and
layout — never hand-edit
.built.json; edit the spec and rebuild. - Force mux after re-render.
render --forcealone leavesfinal/stale.
Skill layout
| Path | Purpose |
|---|---|
references/workflow.md | End-to-end pipeline, commands, iteration loops |
references/narration-sync.md | ASR verification, paragraph rules, timing math |
references/manim-beats.md | Beat vocabulary, scene architecture, adding beat types |
references/text-animation.md | Type scale, centering, entrance-animation rules |
references/drawcms-diagrams.md | Spec authoring, integration, layout rules |
references/verification.md | Probes, frame grids, bbox checks, failure table |
templates/ | Drop-in pipeline code + fixture narration + smoke test |
agents/ | Adapters for OpenCode, Claude Code, Cursor, AGENTS.md |
install.sh | Symlink this skill into ~/.agents/skills and ~/.claude/skills |