| name | csv-landscape-video-pipeline |
| description | Create landscape 16:9 Manim videos from CSV question banks with NVIDIA branding and TTS voiceover |
| version | 1.0.0 |
| platforms | ["linux","macos","windows"] |
CSV Landscape Video Pipeline (16:9)
When to Use
Use when users want to convert a CSV file of practice/exam questions (typically 50-100 questions) into a single landscape 16:9 educational video with:
- NVIDIA green/black branding (#76B900 on #050805)
- Professional question presentation (question card → options → answer reveal → explanation)
- TTS voiceover (Sarvam AI English voice or fallback TTS)
- Single long-form video (~10-20 minutes for 60 questions)
- Production-quality output ready for YouTube/education platforms
Prerequisites
- Python 3.10+
- Manim Community Edition v0.19+
- LaTeX (TeX Live / MiKTeX / MacTeX)
- ffmpeg
- Python packages:
pandas, edge-tts (fallback), requests, tqdm
- Optional: Sarvam AI API key for premium TTS
NVIDIA Brand Colors (Official)
| Role | Hex | Usage |
|---|
| Background | #050805 | Scene background (near-black) |
| Primary Green | #76B900 | NVIDIA brand green - accents, highlights, correct answers |
| Panel Background | #101510 | Question/option panel backgrounds |
| Text Primary | #F5F7F5 | Primary text (questions, options) |
| Text Muted | #B8C2B8 | Secondary text (explanations, metadata) |
| Correct Green | #76B900 | Correct answer highlight |
| Incorrect Red | #E84D3D | Incorrect answer highlight |
| Accent Blue | #76B900 | Progress bars, accents |
Video Specifications (Landscape 16:9)
| Parameter | Value |
|---|
| Resolution | 1920×1080 (Full HD) |
| Aspect Ratio | 16:9 |
| Frame Rate | 30 FPS (production), 15 FPS (draft) |
| Quality | -qh (1080p60) production, -ql (480p15) draft |
| Duration | ~10-15 seconds per question → ~10-15 min for 60 Q |
| Audio | 48kHz stereo, TTS voiceover |
CSV Expected Format
| Column | Required | Description |
|---|
Question | Yes | Question text |
Question Type | Yes | multiple-choice or multi-select |
Answer Option 1..6 | Yes | Option text (up to 6) |
Explanation 1..6 | Optional | Per-option explanation |
Correct Answers | Yes | Comma-separated indices (1-based) |
Overall Explanation | Optional | Full explanation |
Domain | Optional | Category/domain tag |
Pipeline Stages
CSV INPUT → PARSE → PLAN → RENDER SCENES → STITCH → ADD AUDIO → FINAL MP4
Stage 1: Parse CSV (parse_csv.py)
- Read CSV with pandas
- Validate required columns
- Clean text (escape LaTeX special chars)
- Output:
questions.json + plan.md
Stage 2: Plan Scenes (plan.md)
Generate a scene plan with:
- Scene sequence: Intro → Q1 → Q2 → ... → Q60 → Outro
- Per-question timing: ~10-15s each
- Color palette, typography, layout specs
- TTS script per question
Stage 3: Generate Manim Scenes (generate_scenes.py)
One scene class per question + intro/outro:
IntroScene - Title card with exam name, question count
QuestionScene_N - Question card → Options → Reveal → Explanation
OutroScene - Summary, score, call-to-action
Stage 4: Render (render.sh)
manim -qh --format=mp4 script.py IntroScene QuestionScene_1 QuestionScene_2 ... OutroScene
Stage 5: Stitch (stitch.sh)
ffmpeg -f concat -safe 0 -i concat.txt -c copy stitched.mp4
Stage 6: Add TTS Audio (add_audio.py)
- Generate TTS for each question's narration script
- Concatenate audio files
- Mix with video via ffmpeg
Stage 7: Final Output
final_output.mp4 - Ready for upload
Scene Design (Landscape 16:9)
Layout (1920×1080)
┌─────────────────────────────────────────────────────────────┐
│ [NVIDIA Logo] NCP-AAI Practice Test 1 Q 1/60 │ ← Top bar (100px)
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Question text (wrapped, centered, large font) │ │ ← Question card (center)
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ ← Options grid (2x2 or 3x2)
│ │ A. Opt 1 │ │ B. Opt 2 │ │ C. Opt 3 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ D. Opt 4 │ │ E. Opt 5 │ │ F. Opt 6 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │ ← Answer reveal panel (bottom)
│ │ ✓ Correct Answer: B │ │
│ │ Explanation: [Overall Explanation text...] │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ [Progress: ████████░░ 1/60] │ ← Progress bar
└─────────────────────────────────────────────────────────────┘
Animation Sequence Per Question (~12-15s)
| Time | Animation | Duration |
|---|
| 0.0-1.5s | Fade in question card + top bar | 1.5s |
| 1.5-3.0s | Stagger fade-in option cards (A→B→C→D...) | 1.5s |
| 3.0-3.5s | Pause for reading | 0.5s |
| 3.5-5.0s | Highlight correct answer (green glow), dim others | 1.5s |
| 5.0-6.5s | Slide up answer panel with explanation | 1.5s |
| 6.5-12s | Hold for TTS narration (explanation) | ~5-6s |
| 12-13s | Fade out all, progress bar advance | 1s |
TTS Integration
Primary: Sarvam AI English Voice
- API:
https://api.sarvam.ai/text-to-speech
- Voice:
en-IN-neel (English male) or en-IN-ananya (English female)
- Requires:
SARVAM_API_KEY environment variable
Fallback: edge-tts (Microsoft Edge TTS)
- Voice:
en-US-GuyNeural (male) or en-US-AriaNeural (female)
- No API key needed, works offline
TTS Script Per Question
"Question {n}: {question_text}.
Option A: {opt_a}. Option B: {opt_b}. Option C: {opt_c}. Option D: {opt_d}.
The correct answer is {correct_letter}. {overall_explanation}."
Usage
python parse_csv.py "NCP-AAI_Practice_Test_1.csv"
python generate_scenes.py
manim -ql script.py IntroScene QuestionScene_1 QuestionScene_2 ... OutroScene
manim -qh script.py IntroScene QuestionScene_1 QuestionScene_2 ... OutroScene
bash stitch.sh
python add_audio.py --tts sarvam
Project Structure
csv-video-pipeline/
├── input/
│ └── NCP-AAI_Practice_Test_1.csv
├── parse_csv.py
├── generate_scenes.py
├── add_audio.py
├── script.py # Generated Manim script
├── plan.md # Generated scene plan
├── questions.json # Parsed questions
├── concat.txt # ffmpeg concat list
├── render_draft.sh
├── render_prod.sh
├── stitch.sh
├── tts_scripts/ # Generated TTS text files
├── audio/ # Generated WAV/MP3 files
├── media/ # Manim output
│ └── videos/script/1080p60/
└── final_output.mp4 # Final deliverable
Configuration (config.yaml)
video:
resolution: "1920x1080"
fps: 30
quality: "high"
question_duration: 14
branding:
background: "#050805"
primary: "#76B900"
panel_bg: "#101510"
text_primary: "#F5F7F5"
text_muted: "#B8C2B8"
correct: "#76B900"
incorrect: "#E84D3D"
tts:
provider: "sarvam"
sarvam_voice: "en-IN-neel"
edge_voice: "en-US-GuyNeural"
sample_rate: 48000
intro:
title: "NCP-AAI Practice Test 1"
subtitle: "60 Questions • Agent Architecture & Development"
duration: 5
outro:
title: "Practice Test Complete"
subtitle: "Review your answers and improve!"
duration: 5
Verification Checklist
Before final delivery, verify:
Troubleshooting
\n\n| Issue | Fix |\n|-------|-----|\n| LaTeX errors in text | Escape _, %, $, #, &, {, }, ~, ^, \\ in parse_csv.py |\n| Text overflow | Reduce font size, increase panel height, or split long questions |\n| TTS too fast/slow | Adjust question_duration in config, or add SSML <break> tags |\n| Render too slow | Use -ql for draft, -qm for medium, only -qh for final |\n| Audio sync drift | Ensure TTS sample rate matches video (48kHz), use ffmpeg -af aresample=48000 |\n| IndentationError: unexpected indent in generate_scenes.py | The skill file's helper functions section (lines 100-175) must use 4-space indentation, not 8. Lines 101-174 inside generate_script() should be indented by 4 spaces relative to the function. |\n| SyntaxError in generated script.py (unterminated string) | The escape_latex function in generate_scenes.py writes LaTeX escape dict to the generated script. Use exactly 4 backslashes in the skill source: \"'\\\\\\\\\\\\\\\\': r'\\\\\\\\textbackslash{}'\" (produces '\\\\\\\\': r'\\\\textbackslash{}' in script.py). 8 backslashes in source = double-escaped output = broken syntax. |\n| CRLF line endings causing parse errors | Normalize to LF: dos2unix generate_scenes.py or sed -i 's/\\r//g' generate_scenes.py before running. |\n\n## References
| Issue | Fix |
|---|
| LaTeX errors in text | Escape _, %, $, #, &, {, }, ~, ^, \ in parse_csv.py |
| Text overflow | Reduce font size, increase panel height, or split long questions |
| TTS too fast/slow | Adjust question_duration in config, or add SSML <break> tags |
| Render too slow | Use -ql for draft, -qm for medium, only -qh for final |
| Audio sync drift | Ensure TTS sample rate matches video (48kHz), use ffmpeg -af aresample=48000 |
Related Skills
csv-quiz-video — Alternative approach: renders one clip per question (resumable), beat-driven audio sync via add_sound, preview mode, per-domain voiceover. Better for long-form quiz videos where resumability and voice variety matter.
manim-video — Core Manim animation patterns for educational content.
manim-reels — Vertical 9:16 reel patterns (adaptable to landscape).
Architecture Comparison
| Aspect | csv-quiz-video | csv-landscape-video-pipeline (this skill) |
|---|
| Scene structure | One clip per question (resumable) | One giant script with all scenes |
| Audio sync | Beat-driven per clip (add_sound + wait) | Post-render TTS concat + ffmpeg mix |
| Resumability | ✅ Skip existing clips | ❌ Full re-render on change |
| Preview mode | ✅ --preview (first N questions) | Manual scene selection |
| Parallelization | Possible (independent clips) | Sequential |
| Complexity | Higher (orchestrator + env vars) | Lower (single script) |