| name | csv-quiz-video |
| description | Create a long landscape 16:9 quiz/practice-test video from a CSV of multiple-choice / multi-select questions using Manim and Sarvam AI English voiceover. Brand theme is USER-SELECTED (never assume). Use when the user asks to "make a quiz video from a CSV", "practice test video", "manim quiz video", "MCQ video", "certification quiz video", or "turn questions CSV into a narrated video". |
csv-quiz-video
Turns a quiz CSV into one long 1920x1080 MP4: Manim visuals, user-chosen brand theme, per-domain Sarvam English voiceover, quiz-style countdown + answer reveal.
MANDATORY: Ask for theme first
Do NOT hardcode Databricks, NVIDIA, or any brand. Before writing generators or starting a full render, ask the user which theme to follow, for example:
- Brand name (NVIDIA, Databricks, AWS, custom, …)
- Accent color (hex)
- Background / panel colors (hex)
- Optional brand line for intro (e.g. "Databricks ML Professional")
- Optional cert name for outro narration
Only proceed after the user picks a theme (or says “same as last batch”).
Suggested prompt to user:
Which brand theme should this landscape quiz video use?
1) NVIDIA — green #76B900 on near-black
2) Databricks — lava #FF3621 on navy #0A1216
3) Custom — paste accent + background hex codes
CLI already supports:
python build_video.py "<csv>" --out <workdir> --theme nvidia|databricks ...
For custom brands: set colors in theme.py (or extend THEME map) using the user’s hex values — still confirm with them first.
Requirements
- Python 3.11+, Manim Community 0.20+, ffmpeg/ffprobe on PATH.
pip install -r requirements.txt
SARVAM_API_KEY in the environment or an .env in the output dir.
- Use the same Python that has Manim (
sys.executable in build_video.py) — do not call bare python if Manim is only in a venv.
CSV Schema
See references/csv-schema.md. Columns: Question, Question Type (multiple-choice | multi-select), Answer Option 1..6, Explanation 1..6, Correct Answers (1-indexed, comma-separated), Overall Explanation, Domain.
Usage
python build_video.py "<path/to.csv>" --out <workdir> --preview --theme nvidia
python build_video.py "<path/to.csv>" --out <workdir> --full --theme databricks \
--title "Practice Test 1" \
--cert-name "Databricks ML Professional"
Outputs <workdir>/<title>.mp4. Audio is cached in <workdir>/audio/; per-clip MP4s in <workdir>/clips/ (delete a clip to force its re-render). Final MP4 is written only after all clips finish — do not tell the user the final path exists until concat completes.
Architecture
Pure-logic Python modules feed a data-driven set of Manim scenes rendered one clip per question/section; an orchestrator synthesizes audio per beat, times each animation to its audio duration, renders clips (resumable), and ffmpeg-concats intro + dividers + questions + outro into the final video.
Modules
theme.py — Theme-aware colors (QUIZ_THEME / --theme), text wrapping, fit-to-box helpers.
parse_csv.py — CSV → normalized question dicts.
voices.py — Per-domain Sarvam bulbul:v2 voice map (English en-IN).
narration.py — Question → ordered narration beats; dynamic domain list in intro.
sarvam_tts.py — Chunked TTS with caching, duration measurement via ffprobe.
quiz_scene.py — Manim Scene subclasses: IntroScene, DividerScene, QuestionScene, OutroScene.
build_video.py — CLI orchestrator: parse → synthesize audio → render clips → concat.
Key Implementation Details
Themes (built-in presets only — still ask user)
| Theme | BG | Accent | Notes |
|---|
nvidia (default CLI) | #0D0D0D | #76B900 | Green on black |
databricks | #0A1216 | #FF3621 | Lava on navy |
Custom brands: extend theme.py with user-provided hex; do not invent a brand without asking.
Sarvam AI TTS
- Model:
bulbul:v2, endpoint POST https://api.sarvam.ai/text-to-speech
- Header:
api-subscription-key, body field text (max 1500 chars)
- Response:
{"audios": [base64...]} → WAV
- Speakers (lowercase): female
anushka, manisha, vidya, arya; male abhilash, karun, hitesh
- Caching: SHA256 of
model|lang|speaker|pitch|pace|text → 24-char hex
Manim Scenes
- Frame: 14.222 × 8.0 (1920×1080 @ 30fps → manim units)
- Font:
DejaVu Sans
QuestionScene flow: top bar → question → options → 3-2-1 countdown → correct highlight + badge → explanation
- Audio: each beat via
scene.add_sound(wav_path) timed to duration
Resumable Rendering
- Writes
clips/_render.json, sets QUIZ_CLIP_JSON, invokes sys.executable -m manim render ...
- Existing clip MP4s > 50KB are skipped
- Final concat: ffmpeg re-encode to 30fps, yuv420p, AAC 192k / 48kHz
Pitfalls & Fixes
- Never assume theme — always ask (or reuse explicit prior user choice for this batch).
- Final file missing mid-run — expected; only exists after concat. Report clip progress instead.
- Wrong Python / no manim — use Hermes venv or the interpreter that has Manim;
build_video.py uses sys.executable.
- Sarvam API field names:
target_language_code, speech_sample_rate, enable_preprocessing: true.
- Empty Text() — filter empty narration beats.
- QUIZ_CLIP_JSON must be set before Manim loads
quiz_scene.py.
- Windows concat paths — write absolute paths with forward slashes in the concat list.
Production Notes
- ~2–3 hours for ~60 questions at 1080p30; per-question clip ~2–3 MB.
- Background:
terminal(background=true, notify_on_complete=true).
- Re-run same command to resume.
- Smoke:
--limit 1 --quality l then --preview then --full --quality h in a separate out dir so low-res clips are not reused.
Related Skills
manim-reels — vertical 9:16 one-video-per-question reels (also ask for theme).
csv-landscape-video-pipeline — monolithic single-script landscape path.
References
references/sarvam-api.md
references/csv-schema.md
references/manim-patterns.md