Manim slides
Build animated presentations with manim-slides 5.6.0 (Manim CE + RevealJS). Use when the user wants to author slides with Python animations, render them, or convert to HTML/RevealJS, PPTX, or PDF. Includes scaffolder for new presentations and a one-shot render-and-build pipeline.From its SKILL.md
npx -y skills add RubenBranco/Manim-Slides-Skill --skill manim-slidesAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
21.2 KB, as published. Nobody here has run it
Manim Slides Skill
Author animated presentations with manim-slides 5.6.0. Manim CE primary; ManimGL covered in references/manimgl.md. RevealJS HTML is the primary export target; PPTX/PDF/ZIP covered in references/pptx-pdf-zip.md.
Locate the skill directory
Before running any script, resolve $SKILL_DIR and cd into it:
if [ -n "${CLAUDE_PLUGIN_ROOT}" ]; then
SKILL_DIR="${CLAUDE_PLUGIN_ROOT}/skills/manim-slides"
elif [ -d "${HOME}/.codex/manim-slides-skill/skills/manim-slides" ]; then
SKILL_DIR="${HOME}/.codex/manim-slides-skill/skills/manim-slides"
else
SKILL_DIR="$(pwd)"
fi
cd "$SKILL_DIR"
The skill itself does not install dependencies. The user is responsible for environment setup. If a script fails with ModuleNotFoundError: manim or manim-slides: command not found, install the prerequisites below.
Prerequisites
System tools:
- ffmpeg — required for all rendering. Install with
brew install ffmpeg(macOS),apt install ffmpeg(Debian/Ubuntu), orchoco install ffmpeg(Windows). - LaTeX distribution (TeX Live, MacTeX, or MiKTeX) — only required if you use
Tex/MathTexmobjects. Skip if you only useText. - Python ≥ 3.9.
- Qt (PySide6 or PyQt6) — only required for
manim-slides present(the live Qt presenter). Headless RevealJS HTML export does not need Qt. Install viapip install "manim-slides[pyside6-full]"if needed.
Python packages (run once, from $SKILL_DIR):
# Runtime only (manim-slides + manim CE)
pip install -r requirements.txt
# or with uv:
uv pip install -r requirements.txt
# For development (adds pytest + pytest-mock)
pip install -e ".[dev]"
scripts/scaffold.py only uses Python's standard library and runs without any of these installed. scripts/build.py shells out to the manim-slides CLI, so manim-slides must be on $PATH (i.e. installed via the commands above) before invoking it.
Quick Start
# 1. Scaffold a new presentation directory
python3 scripts/scaffold.py ~/my-talk
# 2. Edit the generated slides.py
$EDITOR ~/my-talk/slides.py
# 3. Render and convert to RevealJS HTML in one step
python3 scripts/build.py ~/my-talk/slides.py MyTalk
This produces ~/my-talk/presentation.html (a single-file RevealJS deck).
Authoring slides — the Slide class
Subclass Slide (or ThreeDSlide for 3D scenes) instead of Manim's regular Scene:
from manim import *
from manim_slides import Slide
class MyPresentation(Slide):
def construct(self):
title = Text("Hello", font_size=72)
self.play(Write(title))
self.next_slide() # ends slide 1, opens slide 2
self.play(FadeOut(title))
self.next_slide(...) — keyword arguments
| Kwarg | Default | Honored by | Description |
|---|---|---|---|
loop | False | present, html | Loop this segment until the user advances. Cannot be the first or last slide for RevealJS. |
auto_next | False | present, html | Auto-advance once the segment ends. In RevealJS, sets data-autoslide to the segment duration in ms. |
playback_rate | 1.0 | present only | Playback speed (forward). |
reversed_playback_rate | 1.0 | present only | Playback speed when reversing. |
notes | "" | present, html, pptx | Speaker notes. Markdown for HTML; plaintext for PPTX. Press S in the browser to open speaker view. |
dedent_notes | True | same as notes | textwrap.dedent notes before rendering. |
skip_animations | False | all | Don't render this segment at all (useful while iterating). |
src | None | all | Use an external image/GIF/video as the slide content instead of the Manim animation. Type auto-detected from MIME. |
direction | "horizontal" | html only | "vertical" creates a RevealJS sub-slide (up/down arrows). |
Hard rules
- A
loop=Truesegment cannot be the first or last slide of the deck when targeting RevealJS. Place at least one regular slide before and after it. - Forgetting
next_slide()between twoplay()calls collapses them into one segment. Always callnext_slide()between slides.
Static-media slide via src=
from pathlib import Path
self.next_slide(src=Path("./figure.png")) # static image becomes the next slide
Speaker notes example
self.next_slide(notes="""
# Section 2: Results
- Key finding 1
- Key finding 2
""")
In the browser, press S to open speaker view.
Vertical RevealJS stack
self.next_slide(direction="vertical")
ThreeDSlide
from manim import *
from manim_slides import ThreeDSlide
class My3D(ThreeDSlide):
def construct(self):
...
Slide-class helpers
| API | Purpose |
|---|---|
self.canvas | Dict of "persistent" mobjects that survive across slides. |
self.add_to_canvas(name=mob) | Register a mobject in the canvas under name. |
self.remove_from_canvas("name", ...) | Remove from canvas. |
self.canvas_mobjects | Convenience: the canvas as a tuple. |
self.mobjects_without_canvas | All current mobjects except canvas members. |
self.wipe(current, future, direction=LEFT, ...) | Convenience wipe transition. |
self.zoom(current, future, scale=4.0, out=False, ...) | Convenience zoom transition. |
self.wait_time_between_slides | Property setter (default 0.0). Set to e.g. 0.1 to insert a small wait at every cut so animations finish. |
self.start_skip_animations() / self.stop_skip_animations() | Bracket regions whose animations should be skipped (useful while iterating). |
Class attributes
| Attribute | Default | Use |
|---|---|---|
disable_caching | False | Bypass Manim's cache. |
flush_cache | False | Flush Manim's cache on each render. |
skip_reversing | False | Skip generation of reversed videos. Set True if exporting only HTML/PPTX (those never play in reverse). |
max_duration_before_split_reverse | 4.0 | Set to None to avoid the parallel-reverse-render deadlock that affects long videos. |
num_processes | None | Override CPU parallelism for rendering. |
Common pitfalls
- Multiple
play()calls collapse withoutnext_slide(). Forgetting the call between segments produces one mega-segment. Always end each conceptual slide withnext_slide(). loop=Trueon the first or last slide is rejected by RevealJS. Putloop=Trueonly on middle segments.- Reverse-rendering can deadlock on long videos. If a render hangs at the reverse step, set
max_duration_before_split_reverse = Noneon the class. If you only export to HTML/PPTX, also setskip_reversing = Trueto skip the reverse render entirely. - ManimGL:
self.wait()does not split slides. Always end a segment withself.play(...)beforeself.next_slide(). - HTML without
--one-filerequires the assets folder. Without--one-file, the converter writes<output>_assets/next to the HTML; the assets directory must travel with the HTML when shared (relative paths).
Rendering
manim-slides render [--CE | --GL] FILE.py SceneName [SceneName ...]
Quality flags (passed through to Manim):
| Flag | Resolution / FPS |
|---|---|
-ql | 854×480 @ 15 fps |
-qm | 1280×720 @ 30 fps |
-qh | 1920×1080 @ 60 fps |
-qk | 4K |
Other useful flags: --fps=N, --media_dir=DIR, --disable_caching, -n a,b (render only animation indices a..b).
Output paths:
./slides/<SceneName>.json— the per-scene presentation manifest../slides/files/<SceneName>/— the assembled animation chunks.
Override the output dir with --folder (must be passed to subsequent commands too).
Converting to RevealJS HTML
manim-slides convert SceneName out.html [-c key=value ...]
The format is auto-detected from the extension; pass --to=html to be explicit. Most-used -c options:
| Option | Default | Effect |
|---|---|---|
controls | false | Show on-screen navigation arrows. |
slide_number | false | Show slide numbers (true / h.v / c/t / etc). |
progress | false | Progress bar. |
transition | none | none / fade / slide / convex / concave / zoom. |
transition_speed | default | default / fast / slow. |
reveal_theme | black | Built-in RevealJS theme. |
background_color | black | CSS color. |
auto_animate | true | Enable RevealJS auto-animate between segments. |
loop | false | Whole-deck loop. |
embedded | false | Render the deck as embeddable (no full-page styling). |
show_notes | false | Show notes in the deck (vs. only in speaker view). |
Single-file portable HTML
manim-slides convert MyScene out.html --one-file
manim-slides convert MyScene out.html --one-file --offline # also inline JS/CSS
--one-file embeds videos as base64 data URIs. --offline downloads RevealJS itself (otherwise loaded from the CDN). Combine both for a fully offline, single-file deck.
Custom Jinja2 template
manim-slides convert MyScene out.html --use-template ./my-template.html
The default template lives at manim_slides/templates/revealjs.html (in the installed package). To add RevealJS plugins beyond notes and markdown (e.g. highlight, math), supply a custom template — see references/revealjs-customization.md.
Discover all options
manim-slides convert --to=html --show-config # all -c options + defaults
manim-slides convert --to=html --show-template # default template content
Live Qt presenter (brief)
manim-slides present SceneName # 'present' is the default subcommand
manim-slides SceneName # equivalent
Default keys (configured in .manim-slides.toml):
| Key | Action |
|---|---|
Q | Quit |
Space | Play / pause |
→ | Next |
← | Previous |
V | Reverse |
R | Replay |
F | Toggle full screen |
H | Hide / show mouse |
Initialize / customize:
manim-slides init # write default .manim-slides.toml non-interactively
manim-slides wizard # Qt key-rebinding GUI
Useful flags: --start-paused, -F/--full-screen, -S/--screen N, --start-at SCENE,SLIDE, --exit-after-last-slide, --playback-rate.
Diagnostics:
manim-slides checkhealth
Using the ManimGL backend (sidebar)
Manim Slides supports both Manim CE (default) and 3blue1brown's ManimGL.
pip install "manim-slides[manimgl]"
Imports change:
from manimlib import * # was: from manim import *
from manim_slides import Slide # unchanged
Render with:
manim-slides render --GL slides.py SceneName
Override auto-detection:
MANIM_API=manimlib FORCE_MANIM_API=1 manim-slides render slides.py SceneName
ManimGL caveats:
self.wait()does NOT split slides — always end a segment withself.play(...)beforeself.next_slide().next_sectionis unavailable.- Sphinx directive, IPython magic, and the upstream
ConvertExampleonly work on Manim CE. - ManimGL
<1.7.1requires an outdated NumPy. The[manimgl]extra pinssetuptools<81.
For full details see references/manimgl.md.
Helper scripts
scripts/scaffold.py <target_dir>
Bootstraps a new presentation directory.
| Flag | Default | Description |
|---|---|---|
target_dir | required | Destination directory (must be empty unless --force). |
--name NAME | basename of target_dir | Project / class name. Sanitized to a valid Python identifier (CamelCase). |
--3d | false | Use ThreeDSlide starter. Mutually exclusive with --manimgl. |
--manimgl | false | Use ManimGL backend starter. |
--force | false | Allow writing into a non-empty directory (overwrites colliding files). |
Files created: slides.py, pyproject.toml, .manim-slides.toml, Makefile, .gitignore, README.md.
# Default Manim CE scaffold
python3 scripts/scaffold.py ~/my-talk
# Custom class name
python3 scripts/scaffold.py ~/my-talk --name ThesisDefense
# 3D starter
python3 scripts/scaffold.py ~/3d-demo --3d
# ManimGL starter
python3 scripts/scaffold.py ~/gl-demo --manimgl
scripts/build.py <slides_file> <SceneName...>
Renders and converts to RevealJS HTML in one shot.
| Flag | Default | Description |
|---|---|---|
slides_file | required | The .py file containing Slide subclasses. |
scene_name (1+) | required | One or more class names to render and concatenate. |
--output OUT | presentation.html | Output HTML path. |
--quality {l,m,h,k} | h | Maps to -ql/-qm/-qh/-qk. |
--one-file/--no-one-file | --one-file | Embed assets as data URIs vs separate <output>_assets/. |
--offline | false | Inline JS/CSS from the CDN (combine with --one-file). |
--theme THEME | black | RevealJS theme (validated against the v5.6.0 allowlist). |
--transition T | fade | RevealJS transition. |
--template T | none | Custom Jinja2 template (passes --use-template). |
-c KEY=VALUE | none, repeatable | Pass-through -c option to manim-slides convert. |
--skip-render | false | Skip render; use existing ./slides/*.json. |
--dry-run | false | Print commands without executing. |
--folder FOLDER | ./slides | Slides folder for both render and convert. |
--backend {CE,GL} | CE | Adds --CE/--GL to the render step. |
# Default build
python3 scripts/build.py slides.py MyTalk
# Light-theme deck with slide numbers and controls
python3 scripts/build.py slides.py MyTalk --theme white -c slide_number=true -c controls=true
# ManimGL backend, low quality (fast iteration)
python3 scripts/build.py slides.py MyTalk --backend GL --quality l
# Just the convert step (skip render if .json files already exist)
python3 scripts/build.py slides.py MyTalk --skip-render
# Print the commands without running
python3 scripts/build.py slides.py MyTalk --dry-run
Both scripts shell out to the upstream manim-slides CLI; they do not import from manim_slides internals. Use --dry-run to inspect the exact manim-slides ... invocations.
Going deeper
In-skill references (under references/):
revealjs-customization.md— full-coption table, custom Jinja2 templates, adding RevealJS plugins.performance.md— large-presentation tips: split classes, parallel render,skip_reversing.manimgl.md— full ManimGL backend reference.pptx-pdf-zip.md— non-HTML export targets.sphinx-jupyter.md— Sphinx directive + Jupyter magic.
Official upstream docs: