Manim plugin and lecture-site CLI for Simplex presentations.
Project description
Simplex
Simplex is a toolkit for Manim lecture projects. The repository is named
simplex, and the PyPI distribution is named manim-simplex because the bare
simplex package name is already taken on PyPI. It ships one Python package
namespace, simplex, with:
- a Manim plugin (
plugins = simplex); - theme tokens, mobjects, layout regions, slide bases, and animation helpers;
- a timeline manifest schema and render/package pipeline;
- the
simplexCLI for deck scaffolding, rendering, site building, serving, local deck management, testing, and diagnostics; - a static lecture portal with notes, citations, math rendering, thumbnails, Shaka-backed HLS playback, MP4 fallback, and GitHub Pages-friendly output.
The CLI and plugin intentionally live in one distribution so consumers only
depend on manim-simplex.
Playback Architecture
Simplex uses a continuous timeline player: render scene units independently, compose one lecture timeline per theme, package HLS/CMAF plus MP4 fallback, and navigate by seeking to cue timestamps instead of swapping per-slide videos.
Requirements
- Python 3.13+
- Manim Community 0.20.1+
- Cairo, Pango, and a TeX distribution when rendering TeX. FFmpeg is optional as a packaging fallback. See the Manim installation guide: https://docs.manim.community/en/stable/installation.html
Typical system packages:
sudo apt-get install texlive-latex-extra texlive-fonts-recommended texlive-science \
libcairo2-dev libpango1.0-dev
winget install MiKTeX.MiKTeX
winget install Gyan.FFmpeg
Install
pip install manim-simplex
With uv:
uv add manim-simplex
Verify that Manim can discover the plugin:
python -m manim plugins -l
The output should include simplex.
Configure Manim
Enable the plugin in a project-level manim.cfg:
[CLI]
plugins = simplex
quality = high_quality
Manim imports simplex.plugin through the manim.plugins entry point. The
plugin applies the active Simplex theme to Manim defaults, registers Pygments
styles, sets the TeX template, and sets the background color. Simplex records
cue timing directly from Scene.time; Manim section output remains at Manim's
default unless you explicitly enable it for debugging.
When rendering a Simplex deck, the runner looks for manim.cfg in the lecture
project root and also in the deck directory. If both exist, Simplex passes
Manim a temporary merged config: deck-local fields override matching global
fields, and unrelated fields are preserved. Command-line Manim flags still win
for one-off renders.
Quick Start
from manim import ORIGIN, MathTex, Write
from simplex import SimplexScene
class HelloSlide(SimplexScene):
def setup(self) -> None:
super().setup()
self.setup_chrome(header="Hello, Simplex")
def construct(self) -> None:
self.slide(title="Hello, Simplex")
eq = MathTex(r"e^{i\pi} + 1 = 0")
self.region.place(eq, ORIGIN)
self.play(Write(eq))
Render a standalone scene:
uv run manim -pql path/to/scene.py HelloSlide
Or create a lecture-site deck and build the portal:
uv run simplex new algorithms/hash-tables
uv run simplex render hash-tables
uv run simplex build
uv run simplex serve
Public Surface
| Module | Public surface |
|---|---|
simplex.plugin |
activate() entry point used by Manim. |
simplex.slides |
SimplexScene, SimplexThreeDScene, Slide, ThreeDSlide, OutlineScene, OutlinePart, Chrome, make_chrome. |
simplex.engine |
Region, ExitAnim, clear_scene, exit_for, register_exit, set_exit_animation, HighlightResult, apply_theme_defaults. |
simplex.mobjects |
Node, Edge, ArrayMob, ArrayEntry, ArrayPointer, OutlineProgressBar, Paper, ShowPaper, DismissPaper, PickPage, Sphere, OpenGLSphere, ScalarFieldSurface, ColorBar. |
simplex.theme |
Theme, Palette, Typography, Spacing, Motion, LatexProfile, WebPalette, active_theme, get_active_theme, presets, resolve_palette, available_palette_names, render_web_css. |
simplex.manifest |
DeckManifest, Cue, ThemeTimeline, and the schema v2 playback contract. |
simplex.deck |
DeckConfig, discover, scaffold, section metadata, bundled deck template. |
simplex.render |
Manim runner, timeline composition, HLS/MP4 packaging, cue images, slide PDFs, notes PDF, filenames. |
simplex.web |
Portal builder, notes renderer, citations, refs, templates, static assets, live reload. |
simplex.manager |
Local browser UI for deck discovery, entrypoint editing, rendering, building, and job logs. |
simplex.cli |
Typer application installed as the simplex command. |
CLI
| Command | Purpose |
|---|---|
simplex new <slug> |
Create decks/<slug>/ from the bundled template. |
simplex new <section>/<slug> |
Create a deck inside a named section. |
simplex init [dir] [--public|--private] |
Create a lectures repo from the GitHub template. |
simplex manager |
Open the local deck manager web UI. |
simplex render <slug> |
Render one deck into site/decks/<slug>/. |
simplex render <slug>::<Scene> |
Render one scene from a deck. |
simplex render <slug> --slide-theme light |
Render only one true slide theme for a deck. |
simplex render <slug> --disable_caching |
Forward Manim render flags to Manim. |
simplex build |
Render decks and build the static portal under site/. |
simplex build --disable_caching |
Forward Manim render flags to every deck render. |
simplex build --no-render |
Rebuild portal HTML from existing render output. |
simplex build --slide-theme dark |
Build only one true slide theme (dark or light) for faster tests. |
simplex serve [--watch] |
Serve site/ locally, auto-picking the next free port if 8000 is busy. |
simplex test --slide-theme dark |
Smoke-render decks by rendering only the first animation. |
simplex theme-studio |
Generate and open the palette/code-style editor. |
simplex clean |
Remove generated site/ and media/ output. |
simplex doctor |
Check required binaries, PyAV packaging, and optional fallbacks. |
Manager
simplex manager starts a local browser UI for lecture repos. It scans
decks/*/deck.toml, shows configured entrypoints and available scene classes,
and edits the existing TOML shape:
entrypoints = ["slides.intro:Intro", "slides.surface:SurfaceColoring@opengl"]
Reordering slides rewrites that string list in order. Removing an entrypoint
removes the string from entrypoints; scanned scenes can be added back with
one click. OpenGL remains the @opengl suffix convention, and renderer badges
come from the same deck parsing and source detection used by the CLI.
The manager can render the selected slide, render a full deck, or build
selected decks with or without rendering. Quality choices come from
manim.constants.QUALITIES, "project default" passes no quality flag, cache on
passes no cache flag, cache off passes --disable_caching, and flush cache
passes --flush_cache. Open-after-render opens the specific rendered scene
output for scene jobs and the generated deck/site page for deck and build jobs.
The job drawer keeps command previews, live ANSI-colored logs, elapsed time, status, stop/open controls, and output links for the current manager process. The browser remembers the last render controls locally so reopening the manager does not reset normal workflow settings.
Deck Layout
simplex new hash-tables creates:
decks/hash-tables/
|-- deck.toml
|-- notes.md
|-- refs.bib
|-- assets/
`-- slides/
|-- __init__.py
`-- intro.py
The important fields in deck.toml are:
slug = "hash-tables"
title = "Hash Tables"
summary = "A one-line deck summary."
date = "2026-05-19"
entrypoints = ["slides.intro:Intro", "slides.intro:KeyIdea"]
[slide_themes]
enabled = true
dark = "simplex_dark"
light = "simplex_light"
default = "dark"
[web]
show_notes_date = true
Default Manim render settings live in the project-level manim.cfg.
Deck-local manim.cfg files are optional overrides; matching deck-local
fields override the global value for that deck, and unrelated fields are
merged. One-off render overrides can be passed through simplex render or
simplex build.
simplex build --no-render rejects Manim render flags because there is no
render subprocess to receive them.
The date field is optional. When omitted, Simplex tries to show the first
Git commit that added the deck. If that is unavailable, it falls back to the
last time the deck's slide structure changed, then the last changed Python
scene file. Set [web] show_notes_date = true to display the same resolved
date under the first notes heading and in the generated notes PDF.
Slide refs in notes.md are generated from the visible slide title. A slide
titled Key Idea is referenced as [slide:key-idea]; no deck.toml anchor
field is needed.
voiceover is not a Simplex deck setting or a Manim core manim.cfg field.
Use the separate manim-voiceover plugin from scene code when a deck needs
narration.
[slide_themes] enabled = true renders real dark and light slide videos,
thumbnail images, and slide HTML into isolated themes/dark/ and
themes/light/ folders. The deck player swaps between those compiled
artifacts when the slide-theme toggle changes, so light mode is not a CSS
filter over dark pixels. The package defaults are simplex_dark and
simplex_light; set [slide_themes] enabled = false in site.toml or a
deck's deck.toml to keep the legacy single render plus filter toggle. Deck
settings override site settings.
The top-level theme = "..." field is intentionally omitted from new decks.
It is only a single-render fallback for projects that disable true slide
themes. With [slide_themes] enabled = true, rendered slide pixels come from
the dark and light theme names below.
During local iteration or CI smoke tests, render one true variant:
uv run simplex build --slide-theme dark
uv run simplex render hash-tables --slide-theme light
uv run simplex test --slide-theme dark
Code And Pseudocode
Simplex keeps Manim's native Code object as the authoring surface and adds a
few factories in simplex.engine.code:
from simplex import code_block, code_with_math, highlight_code_lines, pseudocode_block
code = code_block("def f(x):\n return x + 1")
algorithm = pseudocode_block(
r"""
\SetKwInput{Input}{Input}
\Input{Value $n$}
Initialize $s\leftarrow 0$\;
Return $s$\;
""",
caption=r"\textbf{Running Sum}",
)
pseudocode_block(...) compiles an algorithm2e algorithm with the shared
Simplex TeX template and returns a Code instance. Its code_lines are the
rendered, algorithm2e-numbered rows, so highlight_code_lines(algorithm, [2])
and code_explain(...) target the visible algorithm line numbers. Use
code_block(..., pseudocode=True) for the same renderer when you prefer one
factory. On TeX Live systems, install texlive-science for algorithm2e.sty.
Themes And Palettes
Theme names come from built-ins (simplex_dark, simplex_light) or JSON files
in simplex_themes/themes/. Configure them globally in site.toml:
[slide_themes]
enabled = true
dark = "simplex_dark"
light = "my_light"
default = "dark"
Deck deck.toml files may include their own [slide_themes] block when one
deck needs different themes. Deck settings override site.toml.
Theme JSON files can declare manim_palette = "...". Simplex resolves that
palette before scene imports, patches Manim color constants such as BLUE,
BLUE_A, WHITE, and GRAY, then derives any missing Simplex semantic colors
from it. Explicit theme palette fields still win. simplex_dark keeps
Manim's default palette, while simplex_light uses the built-in
simplex_light palette.
Example simplex_themes/themes/my_light.json:
{
"manim_palette": "simplex_light",
"code_style": "simplex_solarized_light",
"palette": {
"background": "#EEEAD8",
"font": "#3C313F",
"vertex": "#355561",
"vertex_stroke": "#426A79"
},
"web_palette": {
"surface": "#F8F2DD",
"text_muted": "#756E63"
}
}
palette controls rendered Manim slide pixels: background, font,
accent, vertex, vertex_stroke, edge, weight, visited, label, and
distance. Missing fields are derived from manim_palette; if
manim_palette is omitted, missing fields derive from Manim defaults.
Custom palette fields are preserved on get_active_theme().palette, so
scene code can use project-specific semantic colors:
{
"palette": {
"warning": "#FFD166",
"success": "#2A9D8F"
}
}
Fields can also hold both true-theme values in one place:
{
"palette": {
"warning": { "light": "#775500", "dark": "#FFD166" },
"background": { "light": "#F7F1DF", "dark": "#111827" }
}
}
Simplex resolves those objects from the actual render role (dark or
light), not from the theme file name. This allows dark = "lecture" and
light = "lecture" to share one JSON file when that is clearer.
code_style controls Manim slide Code objects for that theme. It accepts a
Simplex style, a Pygments style name, or a custom style exported into
simplex_themes/code_styles/.
web_palette controls generated HTML/player shell colors. Decks can still
override those shell colors with [web] background, [web] text_primary,
[web] accent, etc. Markdown notes code blocks are separate and default to
SimplexSolarizedLight; override them per deck with:
[web]
notes_code_style = "simplex_pycharm"
Create or compare palettes and code styles with:
uv run simplex theme-studio
In lecture repos, put Theme Studio code-style exports in
simplex_themes/code_styles/, palette .json or .itermcolors exports in
simplex_themes/palette_styles/, and complete theme JSON files in
simplex_themes/themes/.
Append @opengl to one entrypoint when a scene should render with ManimCE's
OpenGL renderer:
entrypoints = ["slides.intro:Intro", "slides.surface:SurfaceColoring@opengl"]
Development
git clone https://github.com/shlomi-perles/simplex.git
cd simplex
uv sync --all-extras
uv run playwright install chromium
uv run pre-commit install
Useful checks:
python tools/check_readmes.py
uv run ruff check .
uv run ruff format --check .
uv run basedpyright
uv run pytest -q
uv run pytest tests/web/test_player_browser.py -q
uv run python tools/vendor_web_assets.py
uv build --no-sources
uvx twine check dist/*
Run smoke tests locally:
uv run python -c "import simplex.plugin; simplex.plugin.activate(); print('ok')"
uv run manim plugins -l
uv run simplex --help
uv run simplex new smoke-render
uv run simplex test --only smoke-render --slide-theme dark
Release
Releases are automated through Release Please and PyPI Trusted Publishing.
Commit changes using Conventional Commits (feat:, fix:, chore:). When
changes land on main, Release Please opens or updates a release PR. Merging
that PR creates the GitHub release, builds the package with uv, publishes
manim-simplex to PyPI via OIDC, and dispatches a template update workflow.
Manual version bumps and chained simplex-web releases are no longer part of
the release process.
License
MIT. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file manim_simplex-0.17.0.tar.gz.
File metadata
- Download URL: manim_simplex-0.17.0.tar.gz
- Upload date:
- Size: 1.2 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
779369605b2c9ad6896fb2e026e83a38238225f844a80e378d554c1628282622
|
|
| MD5 |
bc44e8ba4f7a67431f525c445151f2bb
|
|
| BLAKE2b-256 |
a86078748ebe7f46e1ca4bad70232b94c8bf12b1945fad9fcb30d5e83cc6f186
|
File details
Details for the file manim_simplex-0.17.0-py3-none-any.whl.
File metadata
- Download URL: manim_simplex-0.17.0-py3-none-any.whl
- Upload date:
- Size: 1.1 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.21 {"installer":{"name":"uv","version":"0.11.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8b2b98ec7d9025696a5556c3517d73c129bc325067371c2bb9d5a4e27e7ae41f
|
|
| MD5 |
55ad090021209eb11f3e0e590b985125
|
|
| BLAKE2b-256 |
3e36c491937dd4e1ab45994272850a35914af7ff5326f65955a4235b9ef1b760
|