| name | educational-animations-tts |
| description | Build narrated educational animations with Manim Community Edition and TTS. Use when the user wants 3Blue1Brown-style explanatory videos where visuals are timed from generated narration durations. |
Educational animations with TTS
Use Manim Community Edition for visuals and generate TTS first so animation timing follows the real narration, not guessed seconds.
Workflow
- Draft narration as short visual beats, usually one paragraph per beat.
- Run
scripts/tts_segments.py to synthesize each beat and write a duration manifest.
- Build the Manim scene from that manifest:
self.add_sound(...), animate for the segment duration, then wait any leftover time.
- Render low quality first, check pacing, then render high quality.
See timing workflow for the exact command pattern.
Setup for sharing
Everything skill-specific lives in this folder: scripts/tts_segments.py, scripts/check_setup.py, requirements.txt, examples, and references. No Jarvis repo scripts are required.
cd educational-animations-tts
python -m venv .venv
source .venv/bin/activate
brew install ffmpeg espeak-ng
python -m pip install -r requirements.txt
python scripts/check_setup.py
Use the active venv's python in the commands below.
TTS
The local .env is intentionally gitignored. Do not print it. The script loads it only at runtime.
python scripts/tts_segments.py \
--input examples/lejepa_projection_narration.txt \
--out /tmp/wiki-animation-tts/lejepa-demo \
--mode paragraph \
--title "LEJEPA random projection diagnostic"
Default TTS tries Jarvis-compatible OpenRouter Grok voice first: x-ai/grok-voice-tts-1.0, voice Eve, mp3 output. If the OpenRouter key is missing or inactive, the script falls back to local Kokoro: hexgrad/Kokoro-82M, voice af_heart.
Use Kokoro directly when desired:
python scripts/tts_segments.py \
--provider kokoro \
--input examples/lejepa_projection_narration.txt \
--out /tmp/wiki-animation-tts/lejepa-demo \
--mode paragraph
Kokoro prerequisites are in requirements.txt; espeak-ng is the usual system dependency.
Manim timing pattern
segment = manifest["segments"][i]
self.add_sound(segment["audio_path"])
self.play(Create(diagram), run_time=segment["duration"] * 0.7)
self.wait(segment["duration"] * 0.3)
Do not hard-code narration durations unless doing a silent draft. Use --disable_caching for audio-timed renders so Manim does not reuse stale partials with an incomplete sound timeline.
Demo
TTS_MANIFEST=/tmp/wiki-animation-tts/lejepa-demo/manifest.json \
python -m manim -ql --disable_caching \
--media_dir /tmp/wiki-animation-tts/lejepa-demo/media \
examples/lejepa_projection_demo.py LejepaProjectionDemo
The demo shows a LEJEPA batch projected through a fixed random matrix, compares a second batch in the same view, then overlays prediction alignment and a falling loss curve.
Appendix clip for the Gaussian-shape distribution loss:
python scripts/tts_segments.py \
--input examples/lejepa_gaussian_loss_appendix_narration.txt \
--out /tmp/wiki-animation-tts/lejepa-loss-appendix \
--mode paragraph \
--title "LEJEPA Gaussian distribution loss appendix"
TTS_MANIFEST=/tmp/wiki-animation-tts/lejepa-loss-appendix/manifest.json \
python -m manim -ql --disable_caching \
--media_dir /tmp/wiki-animation-tts/lejepa-loss-appendix/media \
examples/lejepa_gaussian_loss_appendix.py LejepaGaussianLossAppendix