Skip to content

Commit af48434

Browse files
committed
feat: Add initial Manim animation scenes for the docproc demo, including a README and a rendering script.
1 parent 2ef1550 commit af48434

File tree

7 files changed

+632
-0
lines changed

7 files changed

+632
-0
lines changed

demo/video-assets/README.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# docproc Demo – Manim Animation Scenes
2+
3+
Animated scenes built with **Manim Community Edition** for the `docproc` developer tool demo.
4+
5+
## Scenes
6+
7+
| File | Class | Description |
8+
|------|-------|-------------|
9+
| `scene1_problem.py` | `ProblemScene` | Broken parser pipeline with red error highlights |
10+
| `scene2_intro.py` | `IntroScene` | PDF/DOCX/PPTX/XLSX → docproc → clean.md |
11+
| `scene3_vision.py` | `VisionScene` | Image & equation → Vision Model → LaTeX/caption |
12+
| `scene4_pipeline.py`| `PipelineScene`| Full AI pipeline with Chat/Notes/Flashcards output |
13+
| `scene5_architecture.py` | `ArchitectureScene` | Two-column system architecture diagram |
14+
15+
## Requirements
16+
17+
```bash
18+
pip install manim
19+
```
20+
21+
## Render a single scene
22+
23+
```bash
24+
# High quality (1080p, 60 fps)
25+
manim -qh scene1_problem.py ProblemScene
26+
27+
# Low quality preview
28+
manim -ql scene1_problem.py ProblemScene
29+
```
30+
31+
## Render all scenes at once
32+
33+
```bash
34+
bash render_all.sh # high quality (default)
35+
bash render_all.sh -ql # low quality (fast preview)
36+
bash render_all.sh -qk # 4K
37+
```
38+
39+
Output MP4 files are written to `./media/videos/`.
40+
41+
## Visual Style
42+
43+
- **Background**: `#0b0b0b`
44+
- **Accent**: `#6366F1` (indigo)
45+
- **Error**: `#ef4444` (red)
46+
- **Text**: white
47+
- **Fonts**: Helvetica (labels), Courier New (code/filenames)

demo/video-assets/render_all.sh

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/usr/bin/env bash
2+
# render_all.sh – Render all five docproc demo scenes with Manim CE
3+
# Usage: bash render_all.sh [quality_flag]
4+
# Quality flags: -ql (low), -qm (medium), -qh (high, default), -qk (4K)
5+
6+
set -e
7+
Q=${1:--qh}
8+
DIR="$(cd "$(dirname "$0")" && pwd)"
9+
10+
SCENES=(
11+
"scene1_problem.py:ProblemScene"
12+
"scene2_intro.py:IntroScene"
13+
"scene3_vision.py:VisionScene"
14+
"scene4_pipeline.py:PipelineScene"
15+
"scene5_architecture.py:ArchitectureScene"
16+
)
17+
18+
echo "▶ Rendering docproc demo scenes (quality: $Q) …"
19+
for entry in "${SCENES[@]}"; do
20+
FILE="${entry%%:*}"
21+
CLASS="${entry##*:}"
22+
echo "$CLASS"
23+
manim "$Q" "$DIR/$FILE" "$CLASS"
24+
done
25+
26+
echo ""
27+
echo "✅ All scenes rendered. Output in: $DIR/media/"
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
"""
2+
Scene 1: ProblemScene
3+
Shows a typical broken document-parsing pipeline with red error highlights.
4+
Gruvbox dark theme.
5+
"""
6+
7+
from manim import *
8+
9+
# ── Gruvbox Dark Palette ─────────────────────────────────────────────────────
10+
BG_COLOR = "#282828" # gruvbox bg
11+
FG = "#ebdbb2" # gruvbox fg (warm cream)
12+
ACCENT = "#83a598" # gruvbox bright-blue
13+
ERROR = "#fb4934" # gruvbox bright-red
14+
GRAY = "#928374" # gruvbox gray
15+
DARK_BG = "#1d2021" # gruvbox bg-hard (inner fills)
16+
17+
18+
class ProblemScene(Scene):
19+
def construct(self):
20+
self.camera.background_color = BG_COLOR
21+
22+
# ── Pipeline nodes ──────────────────────────────────────────────────
23+
pdf_box = self._node("PDF", color=ACCENT)
24+
parser_box = self._node("Typical\nParser", color=GRAY)
25+
output_box = self._node("Broken\nMarkdown",color=ERROR)
26+
27+
pdf_box.to_edge(LEFT, buff=1.2)
28+
parser_box.move_to(ORIGIN)
29+
output_box.to_edge(RIGHT, buff=1.2)
30+
31+
arrow1 = Arrow(
32+
pdf_box.get_right(), parser_box.get_left(),
33+
buff=0.15, color=GRAY, stroke_width=2.5
34+
)
35+
arrow2 = Arrow(
36+
parser_box.get_right(), output_box.get_left(),
37+
buff=0.15, color=ERROR, stroke_width=2.5
38+
)
39+
40+
pipeline = VGroup(pdf_box, parser_box, output_box, arrow1, arrow2)
41+
pipeline.shift(UP * 0.8)
42+
43+
# ── Broken output lines ──────────────────────────────────────────────
44+
broken_lines = VGroup(
45+
Text("Equation: ???", font="Courier New", font_size=22, color=ERROR),
46+
Text("Figure: image_42.png", font="Courier New", font_size=22, color=ERROR),
47+
Text("Table: [missing]", font="Courier New", font_size=22, color=ERROR),
48+
).arrange(DOWN, aligned_edge=LEFT, buff=0.25)
49+
broken_lines.to_edge(DOWN, buff=1.8)
50+
51+
# Dashed border around broken block (DashedVMobject is the CE 0.20 API)
52+
border_solid = SurroundingRectangle(
53+
broken_lines, color=ERROR, stroke_width=1.5,
54+
corner_radius=0.1, buff=0.2
55+
)
56+
border = DashedVMobject(border_solid, num_dashes=28, dashed_ratio=0.55)
57+
58+
# ── Caption ─────────────────────────────────────────────────────────
59+
caption = Text(
60+
"Structure is lost", font="Helvetica", font_size=28,
61+
color=FG, weight=BOLD
62+
).to_edge(DOWN, buff=0.5)
63+
64+
# ── Cross icon on output box ─────────────────────────────────────────
65+
cross = Cross(output_box, stroke_color=ERROR, stroke_width=3, scale_factor=0.35)
66+
cross.move_to(output_box.get_center())
67+
68+
# ── Animations ──────────────────────────────────────────────────────
69+
self.play(FadeIn(pdf_box, shift=RIGHT * 0.3), run_time=0.5)
70+
self.play(GrowArrow(arrow1), FadeIn(parser_box, shift=RIGHT * 0.3), run_time=0.6)
71+
self.play(GrowArrow(arrow2), FadeIn(output_box, shift=RIGHT * 0.3), run_time=0.6)
72+
self.play(Create(cross), run_time=0.4)
73+
self.wait(0.3)
74+
75+
self.play(
76+
LaggedStart(
77+
*[FadeIn(line, shift=LEFT * 0.2) for line in broken_lines],
78+
lag_ratio=0.25,
79+
),
80+
run_time=1.0,
81+
)
82+
self.play(Create(border), run_time=0.5)
83+
self.play(Write(caption), run_time=0.8)
84+
self.wait(1.2)
85+
86+
# ── helpers ─────────────────────────────────────────────────────────────
87+
@staticmethod
88+
def _node(label: str, color: str = FG) -> VGroup:
89+
rect = RoundedRectangle(
90+
corner_radius=0.12, width=2.2, height=0.9,
91+
fill_color=DARK_BG, fill_opacity=1,
92+
stroke_color=color, stroke_width=2,
93+
)
94+
text = Text(label, font="Helvetica", font_size=22, color=color, weight=BOLD)
95+
text.move_to(rect.get_center())
96+
return VGroup(rect, text)

demo/video-assets/scene2_intro.py

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
"""
2+
Scene 2: IntroScene
3+
Documents (PDF, DOCX, PPTX, XLSX) flow into docproc and produce clean.md.
4+
Gruvbox dark theme.
5+
"""
6+
7+
from manim import *
8+
9+
# ── Gruvbox Dark Palette ─────────────────────────────────────────────────────
10+
BG_COLOR = "#282828" # gruvbox bg
11+
FG = "#ebdbb2" # gruvbox fg
12+
ACCENT = "#83a598" # gruvbox bright-blue (docproc / engine)
13+
GRAY = "#928374" # gruvbox gray
14+
GREEN = "#b8bb26" # gruvbox bright-green (output)
15+
ORANGE = "#fe8019" # gruvbox bright-orange
16+
YELLOW = "#fabd2f" # gruvbox bright-yellow
17+
RED_G = "#fb4934" # gruvbox bright-red
18+
BLUE_G = "#83a598" # gruvbox bright-blue
19+
DARK_BG = "#1d2021" # gruvbox bg-hard
20+
21+
22+
# Per-format chip colors (all Gruvbox hues)
23+
DOC_COLORS = {
24+
"PDF": "#fb4934", # bright-red
25+
"DOCX": "#83a598", # bright-blue
26+
"PPTX": "#fe8019", # bright-orange
27+
"XLSX": "#b8bb26", # bright-green
28+
}
29+
30+
31+
class IntroScene(Scene):
32+
def construct(self):
33+
self.camera.background_color = BG_COLOR
34+
35+
# ── Document chips (left column) ─────────────────────────────────────
36+
doc_nodes = VGroup(
37+
*[self._doc_chip(lbl, col) for lbl, col in DOC_COLORS.items()]
38+
).arrange(DOWN, buff=0.35)
39+
doc_nodes.to_edge(LEFT, buff=1.5)
40+
41+
# ── docproc engine box (centre) ──────────────────────────────────────
42+
engine_rect = RoundedRectangle(
43+
corner_radius=0.15, width=2.6, height=1.1,
44+
fill_color=DARK_BG, fill_opacity=1,
45+
stroke_color=ACCENT, stroke_width=2.5,
46+
)
47+
engine_label = Text("docproc", font="Courier New", font_size=26,
48+
color=ACCENT, weight=BOLD)
49+
engine_label.move_to(engine_rect.get_center())
50+
engine = VGroup(engine_rect, engine_label).move_to(ORIGIN)
51+
52+
# ── clean.md output box (right) ──────────────────────────────────────
53+
out_rect = RoundedRectangle(
54+
corner_radius=0.15, width=2.6, height=1.1,
55+
fill_color=DARK_BG, fill_opacity=1,
56+
stroke_color=GREEN, stroke_width=2.5,
57+
)
58+
out_label = Text("clean.md", font="Courier New", font_size=24,
59+
color=GREEN, weight=BOLD)
60+
out_label.move_to(out_rect.get_center())
61+
output = VGroup(out_rect, out_label).to_edge(RIGHT, buff=1.5)
62+
63+
# ── Subtitle ─────────────────────────────────────────────────────────
64+
subtitle = Text(
65+
"Document → Markdown → AI",
66+
font="Helvetica", font_size=26, color=GRAY
67+
).to_edge(DOWN, buff=0.55)
68+
69+
# Subtle glow behind engine
70+
pulse = Circle(radius=1.4, stroke_width=0)
71+
pulse.set_fill(ACCENT, opacity=0.07)
72+
pulse.move_to(engine.get_center())
73+
74+
# ── Animations ──────────────────────────────────────────────────────
75+
self.play(FadeIn(pulse, scale=0.6), FadeIn(engine, scale=0.85), run_time=0.7)
76+
77+
self.play(
78+
LaggedStart(
79+
*[FadeIn(d, shift=RIGHT * 0.25) for d in doc_nodes],
80+
lag_ratio=0.2,
81+
),
82+
run_time=0.8,
83+
)
84+
85+
arrows_in = [
86+
Arrow(d.get_right(), engine_rect.get_left(), buff=0.12,
87+
color=d[1].color, stroke_width=2,
88+
max_tip_length_to_length_ratio=0.15)
89+
for d in doc_nodes
90+
]
91+
self.play(
92+
LaggedStart(*[GrowArrow(a) for a in arrows_in], lag_ratio=0.15),
93+
run_time=1.0,
94+
)
95+
96+
# Pulse engine
97+
self.play(
98+
pulse.animate.scale(1.15).set_fill(opacity=0.14),
99+
engine_label.animate.set_color(FG),
100+
run_time=0.4,
101+
)
102+
self.play(
103+
pulse.animate.scale(1 / 1.15).set_fill(opacity=0.07),
104+
engine_label.animate.set_color(ACCENT),
105+
run_time=0.4,
106+
)
107+
108+
arrow_out = Arrow(
109+
engine_rect.get_right(), out_rect.get_left(),
110+
buff=0.12, color=GREEN, stroke_width=2.5,
111+
max_tip_length_to_length_ratio=0.15
112+
)
113+
self.play(GrowArrow(arrow_out), FadeIn(output, shift=RIGHT * 0.3), run_time=0.8)
114+
self.play(Write(subtitle), run_time=0.7)
115+
self.wait(1.2)
116+
117+
@staticmethod
118+
def _doc_chip(label: str, color: str) -> VGroup:
119+
rect = RoundedRectangle(
120+
corner_radius=0.1, width=1.5, height=0.52,
121+
fill_color=DARK_BG, fill_opacity=1,
122+
stroke_color=color, stroke_width=1.8,
123+
)
124+
text = Text(label, font="Courier New", font_size=20, color=color, weight=BOLD)
125+
text.move_to(rect.get_center())
126+
return VGroup(rect, text)

0 commit comments

Comments
 (0)