| name | manim-020-gotchas |
| title | Manim CE 0.20.1 Common Pitfalls |
| description | Gotchas and API changes specific to Manim Community Edition 0.20.1. Includes ImageMobject, animation names, and font handling. |
| author | Hermi |
| date | 2026-04-16T00:00:00.000Z |
| tags | ["manim","animation","gotchas",0.2] |
Overview
Common pitfalls discovered when building Manim animations with CE v0.20.1.
Prevents runtime errors during render.
Pitfalls & Fixes
1. ImageMobject cannot go in VGroup
Gotchas and API changes specific to Manim Community Edition 0.20.1. Includes ImageMobject, animation names, and font handling.
VGroup(title, ImageMobject("plot.png"), caption)
Group(title, ImageMobject("plot.png"), caption)
VGroup only accepts VMobject subclasses. ImageMobject is a PixelArtMobject,
not a VMobject. Use Group (which accepts any Mobject) when mixing images with text/shapes.
2. GrowIn does not exist in 0.20.1
Available animation aliases for images:
FadeIn(mob) — fade from transparent
FadeOut(mob) — fade to transparent
GrowFromPoint(mob, point) — grow from a specific point
GrowFromCenter(mob) — grow from center
GrowIn was removed/renamed. Use FadeIn for image appearances.
3. Font name fallback
Manim 0.20.1 warns if a requested font is not installed. Common fallback:
font="DejaVu Sans Mono"
Text("Hello")
4. partial_movie_files cache corruption
If a render crashes mid-way, the next render may use corrupted cached animations.
Fix: delete the specific partial file or the whole cache:
rm -rf media/videos/*/partial_movie_files/SCENE_NAME/
5. run_time vs wait for scene pacing
Use explicit wait() between animated sections instead of inflating run_time
on the last animation — wait() is more predictable and easier to debug timing:
self.play(Write(text), run_time=2.0)
self.wait(2.0)
6. Random state in animations
If using np.random in animation loops, seed it at the scene level:
def construct(self):
np.random.seed(42)
7. ParametricFunction uses t_range, NOT t_min/t_max
ParametricFunction(
lambda t: np.array([t, np.sin(t), 0]),
t_min=-PI, t_max=PI, color=GREEN
)
ParametricFunction(
lambda t: np.array([t, np.sin(t), 0]),
t_range=(-PI, PI, 0.05),
color=GREEN
)
8. MathTex does NOT accept font or font_size parameters
MathTex(r"\frac{a}{b}", font="DejaVu Sans Mono", font_size=30)
formula = MathTex(r"\frac{a}{b}")
formula.scale(0.8)
MathTex inherits from SVG objects — it uses system LaTeX fonts. For custom fonts/size, use Text() instead.
9. MathTex.get_part_by_tex() often returns None
eq.get_part_by_tex("sin(\\theta)").set_color(GREEN)
eq.get_part_by_tex("y").set_color(GREEN)
eq.set_color_by_tex("sin", GREEN)
eq.set_color_by_tex("y", GREEN)
eq.set_color_by_tex("r", YELLOW)
get_part_by_tex() looks for exact tex string matches in submobjects, which often fail because Manim splits the equation into many individual submobjects. set_color_by_tex() is more reliable.
10. DOWN_RIGHT does NOT exist in Manim 0.20.1
Line(ORIGIN, DOWN_RIGHT * 2.5, color=DIM)
Line(ORIGIN, RIGHT * 2 - DOWN * 1.5, color=DIM)
Available direction shortcuts: UP, DOWN, LEFT, RIGHT, UP_LEFT, UP_RIGHT, DOWN_LEFT, DOWN_RIGHT — NONE of these exist in Manim CE. Always compose: RIGHT * 2 - DOWN * 1.5.
11. run_time(...) syntax error (function-call style)
self.play(Create(mob), run_time(0.3))
self.play(Create(mob), run_time=0.3)
Common typo from copying/manually editing. Always check run_time=, not run_time(...).
12. Text() does NOT accept font_weight parameter
Text("Hello", font_size=44, font_weight=8)
Text("Hello", font_size=44)
Manim 0.20.1's Text class (Pango-based) does not support font_weight. For bold text, use Text("Hello", font="DejaVu Sans Bold") or just rely on default rendering.
13. Arc does NOT accept start_position parameter
Arc(radius=0.5, start_angle=0, angle=theta, start_position=LEFT * 3)
arc = Arc(radius=0.5, start_angle=0, angle=theta)
arc.add_updater(lambda m: m.move_to(LEFT * 3))
The start_position parameter is not part of Manim CE's Arc API. Use move_to() or an updater to position.
14. Frame rate limits minimum wait() duration
self.wait(0.03)
Low-quality draft renders (-ql) use 15 FPS, so wait() under ~0.067s gets silently extended. High-quality renders (-qh) use 60 FPS where 0.03s is fine. Design animations assuming -ql pacing if you want draft renders to look correct.
15. MathTex does NOT accept color in .scale()
MathTex("+", color=RED).scale(0.6, color=RED)
MathTex("+", color=RED).scale(0.6)
MathTex("+").scale(0.6).set_color(RED)
.scale() only accepts sizing arguments. Pass color= to the constructor, or call .set_color() after scaling.
16. CYAN does NOT exist in Manim 0.20.1
Text("minus", color=CYAN)
Text("minus", color=TEAL)
Text("minus", color=PURE_CYAN)
Check available color names with: python3 -c "from manim import *; print(dir())" | tr ',' '\n' | grep -iE "cyan|teal|blue"
17. Unicode minus − (U+2212) crashes MathTex LaTeX compilation
MathTex(r"−", color=WHITE)
MathTex(r"-", color=WHITE)
Text("-", color=WHITE)
MathTex goes through LaTeX which has no Unicode minus support. Use ASCII "-" in MathTex, or use Text() (Pango-based, no LaTeX) for arbitrary Unicode characters.
18. Arrow does NOT accept tip_width_factor
Arrow(start, end, tip_width_factor=0.4)
Arrow(start, end, stroke_width=5, max_tip_length_to_length_ratio=0.3)
Check Arrow's signature: python3 -c "from manim import Arrow; import inspect; print(inspect.signature(Arrow.__init__))"
Relevant params: stroke_width, buff, max_tip_length_to_length_ratio, max_stroke_width_to_length_ratio.
Verification Checklist
Additional Pitfalls
19. Polyline does NOT exist in Manim 0.20.1
Polyline(points, color=GREEN, stroke_width=4)
segments = VGroup()
for i in range(len(points)-1):
segments.add(Line(points[i], points[i+1], color=GREEN, stroke_width=4))
For zigzag resistors or any polyline, build it from individual Line objects in a VGroup.
20. Triangle(side_length=...) is NOT supported
Triangle(side_length=0.3, color=RED)
Triangle().scale(0.15).set_color(RED)
Dot(radius=0.15, color=RED, fill_opacity=0.8)
Triangle (which is a RegularPolygram) only accepts **kwargs for styling. For triangles use .scale() after creation. For LED-like indicators, Dot is often simpler.
21. VGroup unpacking confusion
wires = VGroup(L1, L2, L3, L4)
self.play(Create(v_group(*wires)))
wires = VGroup(L1, L2, L3, L4)
self.play(Create(wires))
VGroup() takes items directly as arguments. There is no v_group() — it's VGroup. And wires is already a single Mobject, so just pass wires, not *wires.
22. Arrow stroke_width affects both line and arrowhead
If you want a thick line but proportional arrowhead, use stroke_width together with max_tip_length_to_length_ratio. The stroke_width sets both the shaft and the arrowhead bar thickness.
23. set_color_by_tex() on a copy doesn't affect original
formula_red = formula.copy()
formula_red.set_color_by_tex("V", RED)
formula.set_color_by_tex("V", RED)
When highlighting parts of a MathTex, either call set_color_by_tex() on the original or use the copy for the entire animation replacing the original.
25. tip_width_ratio does NOT exist on Arrow()
Arrow(start, end, tip_width_ratio=0.3)
Arrow(start, end, stroke_width=4, max_tip_length_to_length_ratio=0.3)
tip_width_ratio is NOT a valid Arrow parameter in Manim CE. The closest alternatives are max_tip_length_to_length_ratio and tip_length. See also pitfall 18 (tip_width_factor also invalid).
26. Degenerate Arrow (start == end) crashes deep in numpy
line = DashedLine(ORIGIN, ORIGIN, color=DIM)
line = Arrow(P, P, color=DIM)
line = Line(ORIGIN, RIGHT * 0.1, color=DIM, stroke_width=1.5)
When start and end are identical, Arrow.put_start_and_end_on() calls np.cross(zero_vector, zero_vector) which raises. Even DashedLine(ORIGIN, ORIGIN) crashes. If you need a zero-length decorative element, use Dot() or a short Line() instead.
27. FadeOut(Group(...)) can crash with assertion errors
self.play(FadeOut(Group(mob1, mob2, mob3)))
self.play(FadeOut(mob1), FadeOut(mob2), FadeOut(mob3))
self.play(AnimationGroup(FadeOut(mob1), FadeOut(mob2), FadeOut(mob3)))
FadeOut on a Group can trigger assertion errors inside Manim's updater system, especially when the group contains mobjects with conflicting states. Fade individual mobjects or use AnimationGroup instead.
24. Axes.get_tick_labels() does NOT exist
x_ticks = axes.get_tick_labels()
self.play(FadeIn(x_ticks))
Manim's Axes renders tick marks and labels automatically. If you need custom tick labels, use axes.get_axis_labels() or create them manually with MathTex/Text and axes.c2p().