SlopCamera
Browse documentationHow-to guides · Make a math explainer video with Manim

How-to guides

Make a math explainer video with Manim

Render the visuals with Manim and keep narration, music, and timing revisable in a SlopCamera project.

Produce a mathematical explainer that stays editable after delivery: Manim Community renders the visuals, while narration, music, and sound effects live in an ordinary SlopCamera project you can keep revising. When the explanation depends on detailed 3D, author a Blender scene instead; when named geometry and world-space media need an editable camera, use a spatial scene. Render Blender, CadQuery, and Manim films from source covers the other engines and shared assets.

This path uses the slopcamera studio commands, which ship in v3.10.3. You also need a selected Python environment with Manim Community and its Typst optional dependency, plus local FFmpeg and FFprobe. The qualified observation is Manim Community 0.21.0 on the CPU Cairo renderer; run slopcamera doctor --json and check capabilities for your install.

Inspect the finished example

Manim lesson

Why the long side is five

A portrait lesson tiles a 3–4–5 triangle into 25 areas.

10s · Silent

Requirements

Requires: Slopcamera 3.2.8 or later and Manim Community 0.21.0; reproduction helper needs a source checkout. Local rendering; no model account.

This actual ten-second Manim render contains 240 frames at 24 fps in a 720×1280 portrait composition. Inspect the tile transitions, the presenter and the caption rail, then open the complete lesson source to change the authored timings. It is silent: the mouth cues and visible captions do not establish speech alignment. The geometry illustrates the 3–4–5 case, not a general proof.

The showcase reproduction helper uses a source installation. To build a lesson with the verified release, follow the scaffold and rendering commands below.

Author the lesson

slopcamera studio init lesson --template manim-lesson --json

The scaffold writes scene.py, lesson.json, lesson.py, toolkit.py, source.json, and job.json under lesson/. The starter is a 10-second portrait lesson in which an original presenter points to a right triangle while nine plus sixteen unit tiles rearrange into a five-by-five square. It illustrates the 3–4–5 example; it does not establish a general proof of Pythagoras.

Edit the script, the supported mathematical parameters, and the cues in lesson.json. The tile template takes two integer legs of at most 12 each with an integer hypotenuse of at most 15, and every displayed length, square count, and tile destination derives from those values. Caption words, mouth shapes, and gestures use half-open microsecond intervals, and gaps between mouth cues select the resting mouth. The reusable layout supports portrait aspect ratios from 0.48 through 0.75, so keep room for the presenter, the diagram, and the caption rail rather than cropping a landscape composition. Declare every helper and input asset in source.json. The checked lesson example documents the supported fields and conversion helpers.

Render the silent visuals

Retain the edited source, then bind the returned bundle digest into a fresh job:

slopcamera studio bundle lesson/source.json --json > lesson-bundle.json

Save this helper as prepare-lesson.ts and run it with Bun. It copies the digest into the job and assigns a fresh job ID, because reusing an old job ID with changed inputs is a conflict.

const job = await Bun.file("lesson/job.json").json();
const bundle = await Bun.file("lesson-bundle.json").json();
job.bundleSha256 = bundle.bundleSha256;
job.jobId = `studio_lesson_${crypto.randomUUID()}`;
await Bun.write("lesson/current.job.json", JSON.stringify(job, null, 2));
bun prepare-lesson.ts
slopcamera studio plan lesson/current.job.json --json
slopcamera studio probe lesson/current.job.json --python /absolute/venv/bin/python --json
slopcamera studio run lesson/current.job.json --python /absolute/venv/bin/python --allow-trusted-code --json

Pass the virtual environment's own interpreter path, because resolving its symlink can select the wrong package environment. run executes your source as the current user under the explicit --allow-trusted-code grant; that grant is not an operating-system sandbox.

Inspect the actual frames and the run receipt, then assemble the verified output into an ordinary project:

slopcamera studio assemble <studio-id> --output-id beauty --name "Geometry lesson" --json

The Manim driver renders silent visuals and rejects source-side audio. Narration, sound-effect, and cue fields in the lesson are authoring references; they never fetch, synthesize, import, or place audio by themselves.

Add narration and sound

Use supplied audio, or generate narration through an authorized Gateway call and keep its receipt. Place each retained file on the project timeline:

slopcamera project add <project-id> narration.wav --role dialogue --at 0us --json
slopcamera project add <project-id> tile-click.wav --role other --at 7600000us --json

An --at placement expresses authored timing, not proof of word alignment or lip sync. Rhubarb output can be converted with the lesson toolkit's rhubarb_mouth_cues helper; keep the original recognizer result, and treat mouth shapes as separate from word timestamps, which need their own measured evidence. If the project's overlay layer owns the visible delivery captions, disable the lesson's caption layer instead of rendering the same words twice, and keep the same retained word timings so emphasis survives the move.

Check the final explanation

Render the project at the intended portrait dimensions. When the edit deliberately uses authored but unverified placement timing, acknowledge --allow-unverified-sync on the render; otherwise apply the relevant synchronization evidence first. Edit and deliver video covers the delivery checks.

Inspect numerical labels, units, diagram geometry, presenter and caption collisions, and each cue boundary. Listen to the assembled narration against the picture before describing it as synchronized, and when listening is unavailable, report the signal and frame checks you performed and the review you could not do. Keep the mathematical source and the native frames when only the audio changes, so a narration revision never forces a new visual render.