Manimator turns a text idea or a PDF (arxiv papers work well) into a narrated Manim video with synchronized subtitles.
- An LLM writes a 60-second Manim scene and a matching narration script.
- A TTS engine reads the narration. The default engine is
OmniVoice, a zero-shot voice
cloning model: drop a 3-10 second reference clip into
assets/voices/and the narration comes out in that voice. - Manim renders the scene, ffmpeg merges video, audio, and an ASS subtitle track. If the generated code fails to render, the same LLM gets the error message and fixes its own code (up to 2 retries).
Both input types offer a Manim animation style and a narrated slide-show style.
A text idea offers:
Manim animation (default): the LLM writes an animated scene about the idea, as above.
Picture walkthrough: a narrated slide show of real images. The LLM plans the video as a list of segments, each naming a subject to illustrate, and the app looks each one up and downloads it. No image bytes come from the model, so this works with every provider. Four open, key-free sources are tried in order until one returns a usable image: a Wikipedia article's lead image, an Openverse search (public domain and CC0 only), a Wikimedia Commons image search, and the NASA image library. Concrete subjects (people, places, organisms, landmarks, standard scientific diagrams) resolve well; very niche or very recent specifics may have no image and get skipped.
A PDF offers:
Manim animation (default): the LLM picks one core concept from the paper and writes an animated scene about it, as above.
Figure walkthrough: a narrated slide show of the paper's own figures, in the style of NotebookLM video overviews and the Paper2Video line of work. The pipeline extracts each figure as a whole region by clustering the page's images and vector drawings (pymupdf), so multi-part figures and vector-drawn plots come out intact rather than split into pieces; it falls back to full-page renders only for unusual layouts. It then shows the LLM the paper plus every figure and gets back a script: which figures to show, in what order, with a heading and narration for each. The slide code is generated from a fixed template, with each slide timed to its narration audio, so this mode has no LLM-written Manim code and cannot fail on generated syntax. Works with all four providers; Codex gets the extracted paper text and the figure images instead of the PDF file.
Both walkthrough styles share an explainer style and an optional focus box:
| Style | Shape | Rough length |
|---|---|---|
| Summary | Motivation, method, results | 150-350 words |
| Deep explainer | Problem, prior work, the idea, why it works, limitations | 300-550 words |
| Long explainer | The deep spine at maximum depth | 500-900 words |
Since each slide waits for its own narration audio, a longer style makes a longer video. The focus box is free text ("spend most of the time on the architecture") and takes priority over the style's default emphasis.
The app supports four providers. The provider dropdown in the sidebar only shows providers that are usable: key-based providers appear when their key is set, and Codex appears when the codex CLI is installed.
| Provider | Needs | Default model | Override with |
|---|---|---|---|
| Gemini | GEMINI_API_KEY |
gemini-2.5-pro |
GEMINI_MODEL |
| Claude | ANTHROPIC_API_KEY |
claude-opus-4-8 |
CLAUDE_MODEL |
| OpenAI | OPENAI_API_KEY |
gpt-5.5 |
OPENAI_MODEL |
| Codex | codex CLI + codex login |
account default | CODEX_MODEL |
Copy .env.example to .env and fill in your keys, or export them in your
shell. The Gemini fallback path additionally uses Google Search grounding to
look up Manim API errors; the other providers fix code from the error
message alone.
The Codex provider runs codex exec with a JSON output schema, so it works
with a ChatGPT subscription instead of an API key. The codex CLI cannot
ingest a PDF file directly, so for PDFs the app feeds it the extracted text
(pymupdf) and attaches the figures as images via --image; it sees content
rather than layout. Generation also goes through a local CLI process, so it
is slower to start than the API providers.
Voices for OmniVoice live in assets/voices/, one directory per voice:
assets/voices/
karpathy/
reference.wav # 3-10 seconds of clean speech
reference.txt # optional transcript; auto-transcribed if absent
See assets/voices/README.md for details on adding voices. The Kokoro
engine is still available in the sidebar; it has a fixed voice but produces
word-level subtitle timing, while OmniVoice subtitles are sentence-level.
Subtitles are off by default. Enable "Burn subtitles into the video" in the sidebar to render the narration at the bottom of the frame.
The repo ships a flake that provides every system dependency (ffmpeg, texlive, cairo, pango, espeak-ng) and a Python virtualenv:
nix develop # first entry creates .venv
pip install -r requirements.txt
streamlit run src/app.pyThe texlive closure is several gigabytes; the first nix develop takes a
while. Subsequent entries are instant.
docker pull mostlyk/manimator
docker run -p 8501:8501 -e GEMINI_API_KEY='your_api_key' mostlyk/manimatorOr build locally:
docker build -t manimator .
docker run -p 8501:8501 -e ANTHROPIC_API_KEY='your_api_key' manimatorThen open http://localhost:8501. Pass whichever provider keys you have as
-e flags.
System requirements: Python 3.12, ffmpeg, a texlive installation (Manim
needs latex for MathTex), cairo, pango, and espeak-ng (for Kokoro).
With conda:
conda env create -f environment.yml
conda activate manimator
streamlit run src/app.pyWith a plain virtualenv:
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
streamlit run src/app.pyFor GPU inference install the torch build matching your hardware first:
https://pytorch.org/get-started/locally/. OmniVoice runs on CPU as well,
just slower. On GPUs with little memory (4 GB and below), the app clears
the CUDA cache between sentences and retries once on out-of-memory; if it
still cannot fit, set TTS_DEVICE=cpu to force CPU synthesis. The nix dev
shell also sets PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True, which
reduces fragmentation on small cards.
Prompts that produce good videos:
- "Explain the Fourier transform by decomposing a square wave into sine waves"
- "Show how gradient descent finds the minimum of a parabola, with the learning rate visualized"
- "Visualize matrix multiplication as a linear transformation of the plane"
- Paste an arxiv PDF and the app summarizes one core concept from it
Prompts that work poorly: anything needing 3D scenes or images (both are excluded from the generated code on purpose), and topics that need more than 60 seconds.
pytest # fast unit tests only
pytest -m integration # loads TTS models, renders video, calls live APIsThe app is hosted on Hugging Face Spaces: https://huggingface.co/spaces/mostlyk/Manimator
- The model is primed with the examples in
src/api/guide.md. PRs adding good Manim examples there directly improve generation quality. - If a prompt fails to produce a video, open an issue with the prompt so an example covering that failure can be added.
- New reference voices are welcome; see
assets/voices/README.md. - Code and prose in this repo follow
.rules.