Turns a folder of LaTeX notes into short, narrated, linked Manim videos through a file-based, stage-gated pipeline. The goal is the workflow: a robust, repeatable system where each stage reads files and writes files.
upstream *.tex (read-only: the host repo's own files, or input/)
(+ sibling *.md optional pandoc high-level characterization,
leveraged alongside the .tex when present)
→ sources/{slug}.tex editable working copy (vendored, normalizable)
→ content/{slug}.md concept scaffold (what/why/how)
→ content/{slug}-script.md narration + beats
→ scenes/{slug}.py Manim code (manim-voiceover)
→ media/videos/.../<SceneClass>.mp4 per-beat renders + .srt (gitignored)
→ media/videos/.../_assembled/{slug}.mp4 one assembled video per chapter
(the reviewable deliverable)
brew bundle # system deps: uv, ffmpeg, MacTeX, cairo
uv sync # Python deps
# point the bootstrap at your notes (numbered .tex chapters):
uv run python tools/init_project.py input/<Subject> --scaffold-concepts
# review project.yaml (order, prereqs, title, notation rules) and flesh out
# the concept stubs, then work through the pipeline stages (see PIPELINE.md)
make check # provenance + notation + review-status gates
make video-draft # 480p draft: render + assemble → one .mp4 per chapter
make video # 1080p60 final: render + assemble (reviewable deliverable)
Rendering requires a real machine (Mac), not a cloud sandbox — see HISTORY.md.
This repo is the engine; each video project is the content and lives
outside it. The project holds only what is specific to it — project.yaml,
sources/, content/, scenes/, media/ — while the engine holds the
tools, the Python environment, and the docs. The engine evolves in one place
without being copied into every project. Two postures:
Embedded (preferred for base repos — articles, books, software). The
project is a single reserved subdirectory, ageation/, inside the repo the
videos are about, and upstream_dir points back into the host — no input/
folder at all:
my-article/ # the base repo (e.g. the article template)
main.tex sections/ figures/ templates/ ...
ageation/ # everything video, one reserved name
project.yaml sources/ content/ scenes/ media/
uv run python tools/init_project.py ../sections --project ../my-article/ageation
bootstraps it; the host's .gitignore gains ageation/media/ and
ageation/.env, and deleting the videos is rm -rf ageation/.
Standalone. When the upstream notes live elsewhere (a co-author's synced
folder, an external download), the project is its own directory and the
read-only upstream is dropped under input/ — this is the only posture that
uses input/.
The rules of the split, in either posture:
- The venv lives here. Run
uv sync(anduv run …) in this repo, never in the project — a project has nopyproject.tomlby design. - Tools are pointed at the project: every tool takes
--project DIR(e.g.uv run python tools/render.py --project ../my-article/ageation -q h), andmake check PROJECT=…runs the gates against it. - A hand-written
project.yamlis first-class.init_project.pyis a convenience for inputs shaped like numbered chapter notes; repo- or article-shaped inputs (ordering in amain.tex, multi-file chapters) are expected to start from a hand-authoredproject.yamlinstead. - Projects version their own content (the host repo, or the standalone
dir as its own git repo); gitignore
.env(TTS keys),media/(regenerable),__pycache__/. - Provenance records the engine version:
stamp_provenance.pywritesframework_commit(this repo's git description, with a-dirtymarker) into each concept, so a project can always tell which engine built it.
project.yaml— the per-project config + ordering spine: title, upstream dir, notation rules, chapters with status and prereqs. Generated bytools/init_project.py, then human-curated.content/— concept + script markdown (the reviewable prose layers).sources/— editable working copies of each source, with provenance headers.scenes/— Manim scenes +_style.py(shared house style, overflow guard).tools/—init_project(bootstrap + concept stubs),vendor_sources,stamp_provenance,check_sync(4-link drift gate, scene layer included),check_notation,check_status(human-review gate),normalize_notation,render(refuses un-approved scripts),assemble(stitches each chapter's per-beat clips into the single reviewable_assembled/<slug>.mp4). All take--project DIR(default.), so they drive any project directory.render_all.sh/Makefile— render + assemble + gate commands.make video/video-draft/video-4kchain render and assemble to produce one.mp4per chapter;./render_all.shdoes the same from the shell.PROJECT=retargets.examples/probability/— the original 12-chapter probability course, kept as a complete worked example; Chapter 5 there is the reference scene implementation.
- HISTORY.md — the full story: goal, every design decision with rationale, and a step-by-step roadmap to reproduce the workflow from scratch.
- PIPELINE.md — the detailed pipeline spec and conventions.
- CLAUDE.md — instructions for an AI agent working in this repo.
- NOTATION.md — how per-project notation rules work.
Git keeps the generators (scripts, scenes, tools, manifest, vendored sources),
not the outputs. media/ (videos/audio) and input/ (external notes) are
gitignored — a thin history that can always regenerate the videos, which may
differ slightly as the tooling evolves.