Help us improve
Share bugs, ideas, or general feedback.
From 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.
npx claudepluginhub rubenbranco/manim-slides-skill --plugin manim-slidesHow this skill is triggered — by the user, by Claude, or both
Slash command
/manim-slides:manim-slidesThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Author animated presentations with [manim-slides](https://manim-slides.eertmans.be/latest/) 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`.
pyproject.tomlreferences/manimgl.mdreferences/performance.mdreferences/pptx-pdf-zip.mdreferences/revealjs-customization.mdreferences/sphinx-jupyter.mdrequirements-dev.txtrequirements.txtscripts/__init__.pyscripts/build.pyscripts/scaffold.pytemplates/Makefile.tmpltemplates/README.md.tmpltemplates/gitignore.tmpltemplates/manim-slides.toml.tmpltemplates/pyproject.toml.tmpltemplates/starter_slides_3d.pytemplates/starter_slides_ce.pytemplates/starter_slides_manimgl.pytests/__init__.pyMeasures whether skills, rules, and agent definitions are actually followed by auto-generating test scenarios at 3 strictness levels and reporting compliance rates with full tool call timelines.
Share bugs, ideas, or general feedback.
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.
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.
System tools:
brew install ffmpeg (macOS), apt install ffmpeg (Debian/Ubuntu), or choco install ffmpeg (Windows).Tex / MathTex mobjects. Skip if you only use Text.manim-slides present (the live Qt presenter). Headless RevealJS HTML export does not need Qt. Install via pip 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.
# 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).
Slide classSubclass 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). |
loop=True segment cannot be the first or last slide of the deck when targeting RevealJS. Place at least one regular slide before and after it.next_slide() between two play() calls collapses them into one segment. Always call next_slide() between slides.src=from pathlib import Path
self.next_slide(src=Path("./figure.png")) # static image becomes the next slide
self.next_slide(notes="""
# Section 2: Results
- Key finding 1
- Key finding 2
""")
In the browser, press S to open speaker view.
self.next_slide(direction="vertical")
ThreeDSlidefrom manim import *
from manim_slides import ThreeDSlide
class My3D(ThreeDSlide):
def construct(self):
...
| 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). |
| 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. |
play() calls collapse without next_slide(). Forgetting the call between segments produces one mega-segment. Always end each conceptual slide with next_slide().loop=True on the first or last slide is rejected by RevealJS. Put loop=True only on middle segments.max_duration_before_split_reverse = None on the class. If you only export to HTML/PPTX, also set skip_reversing = True to skip the reverse render entirely.self.wait() does not split slides. Always end a segment with self.play(...) before self.next_slide().--one-file requires 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).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).
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). |
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.
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.
manim-slides convert --to=html --show-config # all -c options + defaults
manim-slides convert --to=html --show-template # default template content
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
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 with self.play(...) before self.next_slide().next_section is unavailable.ConvertExample only work on Manim CE.<1.7.1 requires an outdated NumPy. The [manimgl] extra pins setuptools<81.For full details see references/manimgl.md.
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.
In-skill references (under references/):
revealjs-customization.md — full -c option 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: