191 lines
5.8 KiB
Markdown
191 lines
5.8 KiB
Markdown
# Production Quality Checklist
|
||
|
||
Standards and checks for ensuring animation output is publication-ready.
|
||
|
||
## Pre-Code Checklist
|
||
|
||
Before writing any Manim code:
|
||
|
||
- [ ] Narration script written with visual beats marked
|
||
- [ ] Scene list with purpose, duration, and layout for each
|
||
- [ ] Color palette defined with meaning assignments (`PRIMARY` = main concept, etc.)
|
||
- [ ] `MONO = "Menlo"` set as the font constant
|
||
- [ ] Target resolution and aspect ratio decided
|
||
|
||
## Text Quality
|
||
|
||
### Overlap prevention
|
||
|
||
```python
|
||
# RULE: buff >= 0.5 for edge text
|
||
label.to_edge(DOWN, buff=0.5) # GOOD
|
||
label.to_edge(DOWN, buff=0.3) # BAD — may clip
|
||
|
||
# RULE: FadeOut previous before adding new at same position
|
||
self.play(ReplacementTransform(note1, note2)) # GOOD
|
||
self.play(Write(note2)) # BAD — overlaps note1
|
||
|
||
# RULE: Reduce font size for dense scenes
|
||
# When > 4 text elements visible, use font_size=20 not 28
|
||
```
|
||
|
||
### Width enforcement
|
||
|
||
Long text strings overflow the frame:
|
||
|
||
```python
|
||
# RULE: Set max width for any text that might be long
|
||
text = Text("This is a potentially long description", font_size=22, font=MONO)
|
||
if text.width > config.frame_width - 1.0:
|
||
text.set_width(config.frame_width - 1.0)
|
||
```
|
||
|
||
### Font consistency
|
||
|
||
```python
|
||
# RULE: Define MONO once, use everywhere
|
||
MONO = "Menlo"
|
||
|
||
# WRONG: mixing fonts
|
||
Text("Title", font="Helvetica")
|
||
Text("Label", font="Arial")
|
||
Text("Code", font="Courier")
|
||
|
||
# RIGHT: one font
|
||
Text("Title", font=MONO, weight=BOLD, font_size=48)
|
||
Text("Label", font=MONO, font_size=20)
|
||
Text("Code", font=MONO, font_size=18)
|
||
```
|
||
|
||
## Spatial Layout
|
||
|
||
### The coordinate budget
|
||
|
||
The visible frame is approximately 14.2 wide × 8.0 tall (default 16:9). With mandatory margins:
|
||
|
||
```
|
||
Usable area: x ∈ [-6.5, 6.5], y ∈ [-3.5, 3.5]
|
||
Top title zone: y ∈ [2.5, 3.5]
|
||
Bottom note zone: y ∈ [-3.5, -2.5]
|
||
Main content: y ∈ [-2.5, 2.5], x ∈ [-6.0, 6.0]
|
||
```
|
||
|
||
### Fill the frame
|
||
|
||
Empty scenes look unfinished. If the main content is small, add context:
|
||
- A dimmed grid/axes behind the content
|
||
- A title/subtitle at the top
|
||
- A source citation at the bottom
|
||
- Decorative geometry at low opacity
|
||
|
||
### Maximum simultaneous elements
|
||
|
||
**Hard limit: 6 actively visible elements.** Beyond that, the viewer can't track everything. If you need more:
|
||
- Dim old elements to opacity 0.3
|
||
- Remove elements that have served their purpose
|
||
- Split into two scenes
|
||
|
||
## Animation Quality
|
||
|
||
### Variety audit
|
||
|
||
Check that no two consecutive scenes use the exact same:
|
||
- Animation type (if Scene 3 uses Write for everything, Scene 4 should use FadeIn or Create)
|
||
- Color emphasis (rotate through palette colors)
|
||
- Layout (center, left-right, grid — alternate)
|
||
- Pacing (if Scene 2 was slow and deliberate, Scene 3 can be faster)
|
||
|
||
### Tempo curve
|
||
|
||
A good video follows a tempo curve:
|
||
|
||
```
|
||
Slow ──→ Medium ──→ FAST (climax) ──→ Slow (conclusion)
|
||
|
||
Scene 1: Slow (introduction, setup)
|
||
Scene 2: Medium (building understanding)
|
||
Scene 3: Medium-Fast (core content, lots of animation)
|
||
Scene 4: FAST (montage of applications/results)
|
||
Scene 5: Slow (conclusion, key takeaway)
|
||
```
|
||
|
||
### Transition quality
|
||
|
||
Between scenes:
|
||
- **Clean exit**: `self.play(FadeOut(Group(*self.mobjects)), run_time=0.5)`
|
||
- **Brief pause**: `self.wait(0.3)` after fadeout, before next scene's first animation
|
||
- **Never hard-cut**: always animate the transition
|
||
|
||
## Color Quality
|
||
|
||
### Dimming on dark backgrounds
|
||
|
||
Colors that look vibrant on white look muddy on dark backgrounds (#0D1117, #1C1C1C). Test your palette:
|
||
|
||
```python
|
||
# Colors that work well on dark backgrounds:
|
||
# Bright and saturated: #58C4DD, #83C167, #FFFF00, #FF6B6B
|
||
# Colors that DON'T work: #666666 (invisible), #2244AA (too dark)
|
||
|
||
# RULE: Structural elements (axes, grids) at opacity 0.15
|
||
# Context elements at 0.3-0.4
|
||
# Primary elements at 1.0
|
||
```
|
||
|
||
### Color meaning consistency
|
||
|
||
Once a color is assigned a meaning, it keeps that meaning for the entire video:
|
||
|
||
```python
|
||
# If PRIMARY (#58C4DD) means "the model" in Scene 1,
|
||
# it means "the model" in every scene.
|
||
# Never reuse PRIMARY for a different concept later.
|
||
```
|
||
|
||
## Data Visualization Quality
|
||
|
||
### Minimum requirements for charts
|
||
|
||
- Axis labels on every axis
|
||
- Y-axis range starts at 0 (or has a clear break indicator)
|
||
- Bar/line colors match the legend
|
||
- Numbers on notable data points (at least the maximum and the comparison point)
|
||
|
||
### Animated counters
|
||
|
||
When showing a number changing:
|
||
```python
|
||
# GOOD: DecimalNumber with smooth animation
|
||
counter = DecimalNumber(0, font_size=48, num_decimal_places=0, font="Menlo")
|
||
self.play(counter.animate.set_value(1000), run_time=3, rate_func=rush_from)
|
||
|
||
# BAD: Text that jumps between values
|
||
```
|
||
|
||
## Pre-Render Checklist
|
||
|
||
Before running `manim -qh`:
|
||
|
||
- [ ] All scenes render without errors at `-ql`
|
||
- [ ] Preview stills at `-qm` for text-heavy scenes (check kerning)
|
||
- [ ] Background color set in every scene (`self.camera.background_color = BG`)
|
||
- [ ] `add_subcaption()` or `subcaption=` on every significant animation
|
||
- [ ] No text smaller than font_size=18
|
||
- [ ] No text using proportional fonts (use monospace)
|
||
- [ ] buff >= 0.5 on all `.to_edge()` calls
|
||
- [ ] Clean exit (FadeOut all) at end of every scene
|
||
- [ ] `self.wait()` after every reveal
|
||
- [ ] Color constants used (no hardcoded hex strings in scene code)
|
||
- [ ] All scenes use the same quality flag (don't mix `-ql` and `-qh`)
|
||
|
||
## Post-Render Checklist
|
||
|
||
After stitching the final video:
|
||
|
||
- [ ] Watch the complete video at 1x speed — does it feel rushed anywhere?
|
||
- [ ] Is there a moment where two things animate simultaneously and it's confusing?
|
||
- [ ] Does every text label have enough time to be read?
|
||
- [ ] Are transitions between scenes smooth (no black frames, no jarring cuts)?
|
||
- [ ] Is the audio in sync with the visuals (if using voiceover)?
|
||
- [ ] Is the Gibbs-like "first impression" good? The first 5 seconds determine if someone keeps watching
|