
Math Visualizer
- 42 installs
- 292 repo stars
- Updated January 29, 2026
- rohitg00/manim-video-generator
Helps with ai & agent building tasks during AI-assisted development.
About
math-visualizer is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- math-visualizer
- AI & Agent Building
- AI-coding skill
Math Visualizer by the numbers
- 42 all-time installs (skills.sh)
- Ranked #8,070 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/rohitg00/manim-video-generator --skill math-visualizerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 42 |
|---|---|
| repo stars | ★ 292 |
| Last updated | January 29, 2026 |
| Repository | rohitg00/manim-video-generator ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
Math Visualizer Skill
The Math Visualizer brings mathematical concepts to life through precise, beautiful animations that reveal the structure and relationships within mathematics.
Mathematical Domains
Supported Areas
- Algebra: Equations, inequalities, polynomials
- Calculus: Derivatives, integrals, limits, series
- Geometry: Shapes, transformations, proofs
- Trigonometry: Functions, identities, unit circle
- Linear Algebra: Vectors, matrices, transformations
- Complex Analysis: Complex numbers, transformations
- Number Theory: Primes, sequences, patterns
Rules
rules/equation-presentation.md
How to present equations with proper pacing and emphasis.
rules/color-coding-math.md
Consistent color schemes for mathematical elements.
rules/graphing-best-practices.md
Creating clear, informative function graphs.
rules/proof-visualization.md
Step-by-step proof animations that build understanding.
Color Coding Standard
| Element | Color | Hex |
|---|---|---|
| Variables (x, y) | BLUE | #58C4DD |
| Constants | YELLOW | #FFFF00 |
| Operators | WHITE | #FFFFFF |
| Key Terms | GREEN | #83C167 |
| Equals/Results | GOLD | #FFD700 |
| Negative/Subtract | RED | #FC6255 |
Templates
Equation Derivation
from manim import *
class EquationDerivation(Scene):
def construct(self):
# Initial equation
eq1 = MathTex(r"x^2 + 2x + 1 = 0")
self.play(Write(eq1))
self.wait()
# Transform step by step
eq2 = MathTex(r"(x + 1)^2 = 0")
eq3 = MathTex(r"x + 1 = 0")
eq4 = MathTex(r"x = -1")
# Show each transformation
for new_eq in [eq2, eq3, eq4]:
self.play(TransformMatchingTex(eq1, new_eq))
self.wait()
eq1 = new_eq
# Highlight final answer
box = SurroundingRectangle(eq4, color=GREEN, buff=0.2)
self.play(Create(box))Color-Coded Equation
from manim import *
class ColorCodedEquation(Scene):
def construct(self):
# Equation with color-coded parts
equation = MathTex(
r"f(", r"x", r") = ", r"a", r"x^2", r" + ", r"b", r"x", r" + ", r"c"
)
# Color code
equation[1].set_color(BLUE) # x
equation[3].set_color(YELLOW) # a
equation[4].set_color(BLUE) # x^2
equation[6].set_color(YELLOW) # b
equation[7].set_color(BLUE) # x
equation[9].set_color(YELLOW) # c
self.play(Write(equation))
# Explain each part
labels = [
(equation[3], "coefficient"),
(equation[1], "variable"),
(equation[9], "constant")
]
for part, label_text in labels:
self.play(Indicate(part))
label = Text(label_text, font_size=24).next_to(part, DOWN)
self.play(Write(label))
self.wait()
self.play(FadeOut(label))Function Graph with Animation
from manim import *
class FunctionGraph(Scene):
def construct(self):
# Create axes
axes = Axes(
x_range=[-4, 4, 1],
y_range=[-2, 8, 1],
x_length=8,
y_length=5,
axis_config={"include_tip": True}
)
labels = axes.get_axis_labels(x_label="x", y_label="y")
self.play(Create(axes), Write(labels))
# Function
func = axes.plot(lambda x: x**2, color=BLUE)
func_label = MathTex(r"f(x) = x^2", color=BLUE).to_corner(UR)
self.play(Create(func), Write(func_label))
# Show derivative
deriv = axes.plot(lambda x: 2*x, color=GREEN)
deriv_label = MathTex(r"f'(x) = 2x", color=GREEN).next_to(func_label, DOWN)
self.play(Create(deriv), Write(deriv_label))
# Tangent line demonstration
x_tracker = ValueTracker(-2)
tangent = always_redraw(lambda: axes.get_secant_slope_group(
x=x_tracker.get_value(),
graph=func,
dx=0.01,
secant_line_color=YELLOW,
secant_line_length=4
))
dot = always_redraw(lambda: Dot(
axes.c2p(x_tracker.get_value(), x_tracker.get_value()**2),
color=RED
))
self.play(Create(tangent), Create(dot))
self.play(x_tracker.animate.set_value(2), run_time=4)3D Mathematical Surface
from manim import *
class Surface3D(ThreeDScene):
def construct(self):
# Set up camera
self.set_camera_orientation(phi=75 * DEGREES, theta=-45 * DEGREES)
# Create axes
axes = ThreeDAxes(
x_range=[-3, 3, 1],
y_range=[-3, 3, 1],
z_range=[-2, 2, 1]
)
# Create surface
surface = Surface(
lambda u, v: axes.c2p(u, v, np.sin(u) * np.cos(v)),
u_range=[-PI, PI],
v_range=[-PI, PI],
resolution=(30, 30),
fill_opacity=0.7
)
surface.set_fill_by_value(
axes=axes,
colorscale=[(RED, -1), (YELLOW, 0), (GREEN, 1)]
)
# Animate
self.play(Create(axes))
self.play(Create(surface), run_time=3)
self.begin_ambient_camera_rotation(rate=0.2)
self.wait(5)Geometric Proof
from manim import *
class PythagoreanProof(Scene):
def construct(self):
# Create right triangle
triangle = Polygon(
ORIGIN, RIGHT * 3, RIGHT * 3 + UP * 4,
color=WHITE, fill_opacity=0.3
)
# Labels
a_label = MathTex("a").next_to(triangle, DOWN)
b_label = MathTex("b").next_to(triangle, RIGHT)
c_label = MathTex("c").move_to(
(ORIGIN + RIGHT * 3 + UP * 4) / 2 + LEFT * 0.5 + UP * 0.3
)
self.play(Create(triangle))
self.play(Write(a_label), Write(b_label), Write(c_label))
# Show squares on each side
sq_a = Square(side_length=3, color=BLUE, fill_opacity=0.5)
sq_a.next_to(triangle, DOWN, buff=0)
sq_b = Square(side_length=4, color=GREEN, fill_opacity=0.5)
sq_b.next_to(triangle, RIGHT, buff=0)
self.play(Create(sq_a), Create(sq_b))
# Area labels
area_a = MathTex(r"a^2", color=BLUE).move_to(sq_a)
area_b = MathTex(r"b^2", color=GREEN).move_to(sq_b)
self.play(Write(area_a), Write(area_b))
# Conclusion
theorem = MathTex(r"a^2 + b^2 = c^2").to_edge(UP)
box = SurroundingRectangle(theorem, color=GOLD)
self.play(Write(theorem), Create(box))LaTeX Quick Reference
Common Expressions
% Fractions
\frac{a}{b}
% Square root
\sqrt{x} \sqrt[n]{x}
% Summation
\sum_{i=1}^{n} x_i
% Integral
\int_{a}^{b} f(x) \, dx
% Limit
\lim_{x \to \infty} f(x)
% Matrix
\begin{pmatrix} a & b \\ c & d \end{pmatrix}
% Partial derivative
\frac{\partial f}{\partial x}Greek Letters
\alpha \beta \gamma \delta \epsilon
\theta \lambda \mu \pi \sigma \omega
\Gamma \Delta \Theta \Lambda \Sigma \OmegaBest Practices
1. Reveal equations gradually - Build up complex equations piece by piece 2. Use consistent notation - Same symbol = same meaning throughout 3. Annotate meaningfully - Labels should clarify, not clutter 4. Show, don't just state - Animate the mathematical relationships 5. Connect to intuition - Bridge abstract math to visual understanding
"""
Example: Derivative as Slope of Tangent Line
Shows the geometric interpretation of derivatives
"""
from manim import *
class DerivativeVisualization(Scene):
def construct(self):
# Setup axes
axes = Axes(
x_range=[-1, 5, 1],
y_range=[-1, 10, 2],
axis_config={"include_tip": True}
)
labels = axes.get_axis_labels(x_label="x", y_label="y")
# Function
func = lambda x: 0.5 * x**2
graph = axes.plot(func, color=BLUE)
graph_label = MathTex("f(x) = \\frac{1}{2}x^2").to_corner(UR)
self.play(Create(axes), Write(labels))
self.play(Create(graph), Write(graph_label))
self.wait()
# Tangent line at x=2
x_val = 2
slope = x_val # derivative of 0.5x^2 is x
dot = Dot(axes.c2p(x_val, func(x_val)), color=YELLOW)
tangent = axes.plot(
lambda x: slope * (x - x_val) + func(x_val),
x_range=[0, 4],
color=RED
)
slope_label = MathTex(f"f'({x_val}) = {slope}").next_to(dot, UR)
self.play(Create(dot))
self.play(Create(tangent), Write(slope_label))
self.wait()
# Show derivative formula
formula = MathTex(
"f'(x) = \\lim_{h \\to 0} \\frac{f(x+h) - f(x)}{h}"
).to_edge(DOWN)
self.play(Write(formula))
self.wait(2)
"""
Example: Pythagorean Theorem Visualization
Demonstrates geometric proof with animated squares
"""
from manim import *
class PythagoreanTheorem(Scene):
def construct(self):
# Create right triangle
triangle = Polygon(
ORIGIN, 3*RIGHT, 3*RIGHT + 4*UP,
color=WHITE, fill_opacity=0.3
)
# Labels for sides
a_label = MathTex("a").next_to(triangle, DOWN)
b_label = MathTex("b").next_to(triangle, RIGHT)
c_label = MathTex("c").move_to(triangle.get_center() + LEFT + UP)
# Squares on each side
sq_a = Square(side_length=3, color=BLUE, fill_opacity=0.5)
sq_a.next_to(triangle, DOWN, buff=0)
sq_b = Square(side_length=4, color=GREEN, fill_opacity=0.5)
sq_b.next_to(triangle, RIGHT, buff=0)
sq_c = Square(side_length=5, color=RED, fill_opacity=0.5)
sq_c.rotate(np.arctan(4/3))
sq_c.move_to(triangle.get_center() + 2*LEFT + 2*UP)
# Equation
equation = MathTex("a^2", "+", "b^2", "=", "c^2")
equation.to_edge(UP)
equation[0].set_color(BLUE)
equation[2].set_color(GREEN)
equation[4].set_color(RED)
# Animate
self.play(Create(triangle))
self.play(Write(a_label), Write(b_label), Write(c_label))
self.wait()
self.play(GrowFromCenter(sq_a))
self.play(GrowFromCenter(sq_b))
self.play(GrowFromCenter(sq_c))
self.wait()
self.play(Write(equation))
self.wait(2)
Math Visualizer Best Practices
LaTeX Rendering
- Always use
MathTexfor mathematical expressions - Use
Texfor plain text labels - Prefer
\displaystylefor fractions and integrals - Use
\text{}for words within equations
Color Coding
- Use consistent colors for variables (e.g., x=BLUE, y=GREEN)
- Highlight important terms with
set_color() - Use
indicate()animation for emphasis
Animation Timing
- Give viewers 1-2 seconds to read new equations
- Use
TransformMatchingTexfor equation transformations - Fade out intermediate steps, don't delete abruptly
Common Patterns
Equation Transformation
eq1 = MathTex("x^2 + 2x + 1")
eq2 = MathTex("(x + 1)^2")
self.play(TransformMatchingTex(eq1, eq2))Step-by-Step Derivation
steps = VGroup(
MathTex("f(x) = x^2"),
MathTex("f'(x) = 2x"),
MathTex("f''(x) = 2")
).arrange(DOWN)
for step in steps:
self.play(Write(step))
self.wait(0.5)Graph with Function
axes = Axes(x_range=[-3, 3], y_range=[-1, 9])
graph = axes.plot(lambda x: x**2, color=BLUE)
label = axes.get_graph_label(graph, "f(x) = x^2")Avoid
- Don't crowd too many equations on screen
- Don't use tiny font sizes
- Don't skip steps in derivations
- Don't use inconsistent notation
Color Coding for Mathematics
Standard Color Palette
| Element Type | Color Name | Hex Code | Manim Constant |
|---|---|---|---|
| Variables (x, y, z) | Blue | #58C4DD | BLUE |
| Constants (a, b, c) | Yellow | #FFFF00 | YELLOW |
| Functions (f, g, h) | Green | #83C167 | GREEN |
| Operators (+, −, ×) | White | #FFFFFF | WHITE |
| Results/Answers | Gold | #FFD700 | GOLD |
| Errors/Negatives | Red | #FC6255 | RED |
| Secondary emphasis | Purple | #9A72AC | PURPLE |
| Neutral/Background | Gray | #888888 | GRAY |
Application Examples
Quadratic Formula
formula = MathTex(
"x", "=",
"\\frac{-", "b", "\\pm\\sqrt{", "b", "^2 - 4", "a", "c", "}}{2", "a", "}"
)
# Color variables
formula[0].set_color(BLUE) # x
formula[3].set_color(YELLOW) # b
formula[5].set_color(YELLOW) # b
formula[7].set_color(YELLOW) # a
formula[8].set_color(YELLOW) # c
formula[10].set_color(YELLOW) # aFunction Notation
func = MathTex("f", "(", "x", ")", "=", "x", "^2")
func[0].set_color(GREEN) # f
func[2].set_color(BLUE) # x (input)
func[5].set_color(BLUE) # x (in expression)Consistency Rules
Rule 1: Same Variable = Same Color
If x is blue in the first equation, it must be blue in ALL equations.
Rule 2: Color Changes Signal Transformation
# x is blue, transforms to red when squared
x_var = MathTex("x").set_color(BLUE)
x_squared = MathTex("x^2").set_color(BLUE)
# After transformation, result is different color
result = MathTex("4").set_color(GOLD)Rule 3: Use Color Groups for Related Terms
# Terms being combined should share color family
term1 = MathTex("2x").set_color(BLUE)
term2 = MathTex("3x").set_color(BLUE_C) # Lighter blue
sum_term = MathTex("5x").set_color(BLUE_A) # CombinedWhen NOT to Use Color
- Don't color every single element (visual overload)
- Don't use more than 4-5 colors in one scene
- Don't use similar colors for different concepts (e.g., light blue vs cyan)
- Don't color generic operators unless emphasizing them
Accessibility Considerations
- Ensure sufficient contrast against background
- Don't rely solely on color to convey meaning
- Consider color-blind viewers (avoid red-green only distinctions)
- Use shapes/labels in addition to colors when critical
Community Edition Implementation Patterns
Best practices for implementing animations with the Manim Community Edition renderer.
Import Patterns
# Standard import (recommended)
from manim import *
# Selective imports for clarity
from manim import Scene, Circle, Square, Write, FadeIn, MathTexScene Types
Standard Scene
class MyAnimation(Scene):
def construct(self):
circle = Circle()
self.play(Create(circle))
self.wait()3D Scene
class My3DAnimation(ThreeDScene):
def construct(self):
self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)
sphere = Sphere()
self.play(Create(sphere))Moving Camera Scene
class CameraAnimation(MovingCameraScene):
def construct(self):
circle = Circle()
self.play(Create(circle))
self.play(self.camera.frame.animate.scale(0.5).move_to(circle))Core Animations
Creation Animations
| Animation | Use Case |
|---|---|
Create(mobject) | Draw shapes stroke-first |
Write(text) | Write text/equations |
FadeIn(mobject) | Gentle appearance |
GrowFromCenter(mobject) | Expand from center |
DrawBorderThenFill(mobject) | Outline then fill |
Transformation Animations
| Animation | Use Case |
|---|---|
Transform(a, b) | Morph a into b |
ReplacementTransform(a, b) | Replace a with b |
TransformMatchingTex(a, b) | Match LaTeX parts |
TransformMatchingShapes(a, b) | Match shape components |
Exit Animations
| Animation | Use Case |
|---|---|
FadeOut(mobject) | Gentle disappearance |
Uncreate(mobject) | Reverse of Create |
ShrinkToCenter(mobject) | Collapse to center |
LaTeX Rendering
Basic Math
# Simple equation
eq = MathTex("E = mc^2")
# With color isolation
eq = MathTex("E", "=", "m", "c^2")
eq[0].set_color(YELLOW) # E
eq[3].set_color(BLUE) # c^2Using substrings_to_isolate
eq = MathTex(
"x^2 + 2x + 1 = 0",
substrings_to_isolate=["x", "1", "0"]
)
eq.set_color_by_tex("x", BLUE)
eq.set_color_by_tex("1", GREEN)Text with Math
text = Tex("The area is ", "$A = \\pi r^2$")CLI Usage
# Preview with low quality (fast)
manim -pql script.py SceneName
# Preview with medium quality
manim -pqm script.py SceneName
# High quality render
manim -pqh script.py SceneName
# 4K render
manim -pqk script.py SceneName
# Save last frame as image
manim -pql -s script.py SceneName
# Transparent background
manim -pql -t script.py SceneNameQuality Presets
| Flag | Resolution | FPS | Use Case |
|---|---|---|---|
-ql | 480p | 15 | Quick preview |
-qm | 720p | 30 | Development |
-qh | 1080p | 60 | Production |
-qk | 4K | 60 | High-end production |
Debugging Techniques
Visual Debugging
# Add without animation (instant)
self.add(circle)
# Show bounding box
circle.add(SurroundingRectangle(circle))
# Add coordinate labels
self.add(NumberPlane())Print Debugging
def construct(self):
circle = Circle()
print(f"Circle center: {circle.get_center()}")
print(f"Circle radius: {circle.radius}")
print(f"Circle color: {circle.get_color()}")Interactive Mode
# Pause and inspect
self.wait()
self.interactive_embed() # Opens interactive shellAnimation Timing
Run Time Control
self.play(Create(circle), run_time=2) # 2 seconds
self.play(FadeIn(square), run_time=0.5) # FastSimultaneous Animations
# All at once
self.play(Create(circle), Write(text), FadeIn(square))
# With AnimationGroup
self.play(AnimationGroup(
Create(circle),
Write(text),
lag_ratio=0.5 # Stagger start times
))Sequential with Succession
self.play(Succession(
Create(circle),
circle.animate.shift(RIGHT),
FadeOut(circle)
))Common Patterns
Animate Method
# Fluent animation syntax
self.play(circle.animate.shift(RIGHT).scale(2).set_color(RED))Value Tracking
tracker = ValueTracker(0)
number = always_redraw(lambda: DecimalNumber(tracker.get_value()))
self.play(tracker.animate.set_value(100), run_time=3)Updaters
dot = Dot()
label = always_redraw(lambda: Text(f"({dot.get_x():.1f}, {dot.get_y():.1f})").next_to(dot, UP))
self.add(dot, label)
self.play(dot.animate.shift(RIGHT * 3))Anti-Patterns
Avoid
# Don't modify mobjects during play
self.play(Create(circle))
circle.shift(RIGHT) # Wrong - not animated
# Don't forget to add mobjects
text = Text("Hello")
self.play(text.animate.shift(UP)) # Error - text not addedPrefer
# Animate changes
self.play(Create(circle))
self.play(circle.animate.shift(RIGHT)) # Correct
# Add before animating
text = Text("Hello")
self.add(text)
self.play(text.animate.shift(UP)) # Or use FadeInConcept Decomposition System
A systematic approach to breaking down complex mathematical concepts into teachable prerequisite chains.
Overview
Before visualizing any mathematical concept, decompose it into its fundamental prerequisites. This ensures viewers can follow the explanation without knowledge gaps.
The Prerequisite Discovery Algorithm
Core Question
For any concept X, recursively ask:
"What must I understand BEFORE I can understand X?"
Process Flow
Target Concept
│
▼
┌─────────────────┐
│ Identify Direct │
│ Prerequisites │
└────────┬────────┘
│
▼
┌─────────────────┐
│ For Each Prereq │◄──────┐
│ Recurse │ │
└────────┬────────┘ │
│ │
▼ │
┌─────────────────┐ │
│ Is Foundation? │──No───┘
└────────┬────────┘
│ Yes
▼
┌─────────────────┐
│ Stop Recursion │
└─────────────────┘Foundation Detection
What Counts as Foundation?
Stop recursion when you reach concepts that:
- Are taught in basic education (algebra, basic geometry)
- Require no special mathematical background
- Can be assumed as common knowledge for target audience
Foundation Examples by Domain
| Domain | Foundation Concepts |
|---|---|
| Calculus | Algebra, Functions, Graphs |
| Linear Algebra | Vectors, Basic Arithmetic, Equations |
| Probability | Fractions, Counting, Basic Statistics |
| Number Theory | Integers, Division, Prime Numbers |
Knowledge Dependency Graph
Structure
Build a Directed Acyclic Graph (DAG) where:
- Nodes = Concepts
- Edges = "requires understanding of"
- Leaves = Foundation concepts
- Root = Target concept
Example: Eigenvalues
Eigenvalues
│
┌─────────────┼─────────────┐
│ │ │
▼ ▼ ▼
Linear Determinants Characteristic
Transformations Polynomial
│ │ │
▼ ▼ ▼
Matrix 2x2/3x3 Polynomial
Multiplication Matrices Equations
│ │ │
└──────┬──────┴──────┬──────┘
│ │
▼ ▼
Vectors Algebra
(Foundation) (Foundation)JSON Representation
{
"concept": "Eigenvalues",
"prerequisites": [
{
"concept": "Linear Transformations",
"prerequisites": [
{
"concept": "Matrix Multiplication",
"prerequisites": [
{"concept": "Vectors", "foundation": true},
{"concept": "Algebra", "foundation": true}
]
}
]
},
{
"concept": "Determinants",
"prerequisites": [
{"concept": "2x2/3x3 Matrices", "foundation": true}
]
},
{
"concept": "Characteristic Polynomial",
"prerequisites": [
{"concept": "Polynomial Equations", "foundation": true}
]
}
]
}Scene Ordering from DAG
Topological Sort
Order scenes by dependency depth: 1. Foundation scenes first (deepest leaves) 2. Build up through prerequisites 3. Target concept last (root)
Algorithm
def get_scene_order(concept_dag):
"""Return concepts in teaching order (foundations first)."""
order = []
visited = set()
def visit(node):
if node["concept"] in visited:
return
visited.add(node["concept"])
# Visit prerequisites first
for prereq in node.get("prerequisites", []):
visit(prereq)
order.append(node["concept"])
visit(concept_dag)
return orderExample Output
For Eigenvalues: 1. Vectors (foundation) 2. Algebra (foundation) 3. Matrix Multiplication 4. 2x2/3x3 Matrices 5. Linear Transformations 6. Determinants 7. Polynomial Equations 8. Characteristic Polynomial 9. Eigenvalues (target)
Implementation in Scenes
Scene Specification Format
## Knowledge Tree
Target: Eigenvalues
### Prerequisites (in order)
1. Vectors (30s) - Quick review
2. Matrix Multiplication (60s) - Core mechanic
3. Linear Transformations (90s) - Conceptual understanding
4. Determinants (60s) - Calculation method
5. Characteristic Polynomial (45s) - Setup
6. Eigenvalues (120s) - Main contentDuration Allocation
| Concept Type | Suggested Duration |
|---|---|
| Foundation (review) | 15-30s |
| Prerequisite | 30-60s |
| Supporting concept | 60-90s |
| Target concept | 90-180s |
Practical Guidelines
Depth Control
- Quick explanation: 1-2 prerequisite levels
- Standard video: 2-3 levels
- Deep dive: 3-4 levels
- Course content: Full tree
Audience Calibration
Adjust foundation level based on audience:
| Audience | Foundation Level |
|---|---|
| General public | Arithmetic, basic shapes |
| High school | Algebra, trigonometry |
| Undergrad | Calculus, linear algebra basics |
| Graduate | Advanced topics as foundations |
Skip Conditions
Omit a prerequisite when:
- Audience definitely knows it
- It's tangential to main point
- Time constraints require it
- You can reference "recall that..."
Visual Indicators
Show the Tree
Consider visualizing the knowledge tree itself:
# Show what we'll cover
tree_visual = create_knowledge_tree_diagram(concept_dag)
self.play(Create(tree_visual))
self.wait(2)
# Highlight current position as we progress
for concept in scene_order:
highlight_node(tree_visual, concept)
# ... teach concept ...Progress Indicators
# Show progress through prerequisites
progress = ProgressBar(len(concepts))
for i, concept in enumerate(concepts):
progress.update(i)
# ... teach concept ...Anti-Patterns
Avoid
- Assuming knowledge: Jumping to advanced concepts
- Over-decomposition: Breaking down obvious things
- Circular dependencies: A requires B requires A
- Missing foundations: Leaving gaps in the tree
Prefer
- Explicit prerequisites: State what's assumed
- Just-in-time review: Brief refreshers
- Clear progression: Visible path through concepts
- Appropriate depth: Match audience level
Equation Presentation Rules
Progressive Revelation
Build Equations Step by Step
Never show a complex equation all at once. Build it piece by piece:
# GOOD: Progressive reveal
eq_part1 = MathTex("E")
self.play(Write(eq_part1))
eq_part2 = MathTex("E = mc")
self.play(TransformMatchingTex(eq_part1, eq_part2))
eq_final = MathTex("E = mc^2")
self.play(TransformMatchingTex(eq_part2, eq_final))
# BAD: All at once
eq = MathTex("E = mc^2")
self.play(Write(eq)) # Viewer has no time to processTiming Guidelines
| Equation Complexity | Write Time | Wait After |
|---|---|---|
| Simple (x = 1) | 0.5s | 1s |
| Medium (ax² + bx + c) | 1s | 1.5s |
| Complex (∫∫ f(x,y) dx dy) | 1.5s | 2-3s |
| Multi-line derivations | 2s per line | 1s between lines |
Positioning
Center Important Equations
equation.move_to(ORIGIN) # Main focusUse Consistent Margins
equation.to_edge(UP, buff=1) # Standard top margin
supporting_text.to_edge(DOWN, buff=0.5)Group Related Equations
equations = VGroup(eq1, eq2, eq3)
equations.arrange(DOWN, buff=0.5, aligned_edge=LEFT)Transitions Between Equations
Transform for Related Equations
# When equations are related
self.play(TransformMatchingTex(eq1, eq2))Fade for Unrelated Equations
# When switching topics
self.play(FadeOut(eq1), FadeIn(eq2))Replacement for Substitution
# When one equation replaces another
self.play(ReplacementTransform(eq1, eq2))Emphasis Techniques
Boxing Important Results
box = SurroundingRectangle(equation, color=YELLOW, buff=0.2)
self.play(Create(box))Underlining Key Terms
underline = Underline(equation[0], color=RED)
self.play(Create(underline))Scaling for Focus
self.play(equation.animate.scale(1.3))Graphing Best Practices
Axis Configuration
Standard Setup
axes = Axes(
x_range=[-5, 5, 1], # [min, max, step]
y_range=[-3, 3, 1],
x_length=10, # Screen units
y_length=6,
axis_config={
"include_numbers": True,
"include_tip": True,
"numbers_to_exclude": [0], # Avoid clutter at origin
}
)Always Include Labels
labels = axes.get_axis_labels(x_label="x", y_label="y")
# Or custom labels
x_label = MathTex("t").next_to(axes.x_axis, RIGHT)
y_label = MathTex("f(t)").next_to(axes.y_axis, UP)Function Plotting
Smooth Curves
# Default resolution is good for most functions
graph = axes.plot(lambda x: x**2, color=BLUE)
# Increase resolution for wiggly functions
graph = axes.plot(
lambda x: np.sin(10*x),
color=BLUE,
use_smoothing=True
)Discontinuities
# Handle discontinuities with multiple plots
left_part = axes.plot(lambda x: 1/x, x_range=[-5, -0.1], color=BLUE)
right_part = axes.plot(lambda x: 1/x, x_range=[0.1, 5], color=BLUE)Domain Restrictions
# Explicitly set domain
graph = axes.plot(
lambda x: np.sqrt(x),
x_range=[0, 5], # Only plot where defined
color=GREEN
)Labeling Functions
Graph Labels
label = axes.get_graph_label(
graph,
label="f(x) = x^2",
x_val=3, # Position along x-axis
direction=UR, # Label direction from point
buff=0.2
)Point Labels
point = axes.coords_to_point(2, 4)
dot = Dot(point, color=YELLOW)
label = MathTex("(2, 4)").next_to(dot, UR, buff=0.1)Animation Sequences
Recommended Order
1. Create axes 2. Add axis labels 3. Plot function 4. Add function label 5. Animate special features (tangents, areas, etc.)
def construct(self):
# 1. Axes
self.play(Create(axes))
# 2. Labels
self.play(Write(labels))
# 3. Function (trace animation)
self.play(Create(graph), run_time=2)
# 4. Label
self.play(Write(func_label))
# 5. Special features
self.animate_tangent_line()Special Features
Tangent Lines
tangent = axes.get_secant_slope_group(
x=2,
graph=graph,
dx=0.01,
secant_line_color=YELLOW,
secant_line_length=4
)Areas Under Curves
area = axes.get_area(
graph,
x_range=[0, 2],
color=BLUE,
opacity=0.5
)Vertical/Horizontal Lines
# Vertical line at x=2
v_line = axes.get_vertical_line(
axes.input_to_graph_point(2, graph),
color=YELLOW
)
# Horizontal line at y=3
h_line = DashedLine(
axes.c2p(-5, 3),
axes.c2p(5, 3),
color=RED
)Common Mistakes to Avoid
1. Unlabeled axes - Always include labels 2. Poor domain choice - Show relevant portion of function 3. Cluttered numbers - Use numbers_to_exclude to remove 0 4. Wrong aspect ratio - Match x_length/y_length to range ratio 5. Too fast plotting - Use run_time=2 or more for complex graphs
OpenGL Renderer Implementation Patterns
Best practices for implementing animations with the OpenGL-based renderer (alternative to Cairo).
Key Differences from Community Edition
| Feature | Community Edition | OpenGL Renderer |
|---|---|---|
| Creation animation | Create() | ShowCreation() |
| Color in LaTeX | set_color_by_tex() | t2c parameter |
| Camera control | self.camera.frame | self.frame |
| 3D Scene class | ThreeDScene | Standard Scene |
| Interactive mode | Limited | Full with -se flag |
Import Patterns
# Standard import for OpenGL renderer
from manimlib import *
# Note: Different package nameInteractive Development
Starting Interactive Mode
# Run with interactive embed
manimgl script.py SceneName -se
# The -se flag enables:
# - Pausing at self.embed() calls
# - Live code execution
# - Real-time mobject inspectionUsing embed()
class InteractiveScene(Scene):
def construct(self):
circle = Circle()
self.play(ShowCreation(circle))
# Pause here for interactive exploration
self.embed()
# Continue after exiting embed
self.play(circle.animate.shift(RIGHT))Checkpoint Workflow
def construct(self):
# Create initial state
circle = Circle()
self.play(ShowCreation(circle))
# Save checkpoint
self.checkpoint_paste() # Copy current state
# Experiment from here
self.play(circle.animate.scale(2))LaTeX with Color Coding
Using t2c Parameter
# t2c = "tex to color" dictionary
equation = Tex(
"E = mc^2",
t2c={
"E": YELLOW,
"m": GREEN,
"c": BLUE
}
)Complex Color Mapping
# Multiple characters with same color
formula = Tex(
"\\frac{d}{dx}[x^n] = nx^{n-1}",
t2c={
"x": BLUE,
"n": RED,
"d": GREEN,
"dx": GREEN
}
)Isolating Substrings
# For transformation matching
eq1 = Tex("x^2", " + ", "2x", " + ", "1")
eq2 = Tex("(x + 1)^2")
# Color individual parts
eq1[0].set_color(BLUE) # x^2
eq1[2].set_color(GREEN) # 2xCamera Control
Frame-Based Control
class CameraScene(Scene):
def construct(self):
circle = Circle()
self.play(ShowCreation(circle))
# Access frame directly (not self.camera.frame)
self.play(self.frame.animate.scale(0.5))
self.play(self.frame.animate.move_to(circle))3D Camera Orientation
class My3DScene(Scene):
def construct(self):
# No special 3D scene class needed
surface = Surface(lambda u, v: [u, v, u*v])
self.play(ShowCreation(surface))
# Reorient camera
self.play(self.frame.animate.reorient(45, 60))
# Camera parameters: theta (rotation), phi (elevation)Camera Movements
# Pan
self.play(self.frame.animate.shift(RIGHT * 2))
# Zoom
self.play(self.frame.animate.scale(0.5)) # Zoom in
self.play(self.frame.animate.scale(2)) # Zoom out
# Combined
self.play(
self.frame.animate
.move_to(target)
.scale(0.3)
.reorient(30, 45)
)Animation Syntax
ShowCreation (not Create)
# Correct for OpenGL renderer
self.play(ShowCreation(circle))
# NOT Create(circle) - that's Community EditionOther Animation Differences
# These work the same
self.play(Write(text))
self.play(FadeIn(mobject))
self.play(Transform(a, b))
# Animate method works the same
self.play(circle.animate.shift(RIGHT).scale(2))3D Without Special Classes
class Simple3D(Scene):
def construct(self):
# 3D objects work in regular Scene
axes = ThreeDAxes()
sphere = Sphere(radius=1)
self.play(ShowCreation(axes))
self.play(ShowCreation(sphere))
# Camera reorientation
self.play(self.frame.animate.reorient(60, 70))
# Continuous rotation
self.frame.add_updater(lambda m, dt: m.increment_theta(0.1 * dt))
self.wait(5)Debugging in Interactive Mode
Inspecting Mobjects
def construct(self):
circle = Circle()
self.add(circle)
self.embed()
# In interactive mode, you can:
# >>> circle.get_center()
# >>> circle.set_color(RED)
# >>> self.play(circle.animate.scale(2))Real-Time Modifications
# While in embed(), you can:
# - Create new mobjects
# - Run animations
# - Test transformations
# - Adjust colors and positionsPerformance Optimizations
GPU Acceleration
# OpenGL renderer leverages GPU for:
# - Shader-based rendering
# - Real-time preview
# - Smooth 3D rotationsEfficient Updates
# Use always_redraw for dynamic content
graph = always_redraw(lambda: FunctionGraph(
lambda x: np.sin(x + tracker.get_value()),
x_range=[-PI, PI]
))Common Patterns
Interactive Workflow
# 1. Start with interactive flag
manimgl script.py MyScene -se
# 2. Scene runs until embed()
# 3. Test changes in Python shell
# 4. Type 'exit()' to continue
# 5. Iterate on codeRapid Prototyping
class Prototype(Scene):
def construct(self):
# Quick setup
self.play(ShowCreation(Circle()))
# Pause to experiment
self.embed()
# Continue with refined versionAnti-Patterns
Avoid
# Don't use Create() - use ShowCreation()
self.play(Create(circle)) # Wrong for OpenGL
# Don't use self.camera.frame
self.play(self.camera.frame.animate.scale(0.5)) # WrongPrefer
# Use ShowCreation()
self.play(ShowCreation(circle)) # Correct
# Use self.frame directly
self.play(self.frame.animate.scale(0.5)) # CorrectProof Visualization Rules
Structure of a Visual Proof
1. State the Theorem
theorem = MathTex(r"\text{Theorem: } a^2 + b^2 = c^2")
theorem.to_edge(UP)
self.play(Write(theorem))2. Establish Given Information
given = VGroup(
MathTex(r"\text{Given: Right triangle with legs } a, b"),
MathTex(r"\text{and hypotenuse } c")
).arrange(DOWN, aligned_edge=LEFT)
self.play(FadeIn(given))3. Build the Proof Step by Step
Each step should:
- Be visually motivated
- Connect to the previous step
- Pause for comprehension
4. Conclude with QED
qed = MathTex(r"\blacksquare").to_corner(DR)
self.play(FadeIn(qed))Visual Proof Techniques
Proof by Construction
Show that something can be built:
# Build a square from four triangles
triangles = [self.create_triangle() for _ in range(4)]
square = VGroup(*triangles)
for i, t in enumerate(triangles):
t.rotate(i * PI/2)
self.play(LaggedStart(*[Create(t) for t in triangles]))Proof by Transformation
Show equivalence through morphing:
# Show two expressions are equal by transforming one into the other
expr1 = MathTex(r"(a+b)^2")
expr2 = MathTex(r"a^2 + 2ab + b^2")
self.play(TransformMatchingTex(expr1, expr2))Proof by Dissection
Break apart and rearrange:
# Cut shape into pieces, rearrange to show equality
pieces = self.cut_shape(original)
self.play(*[p.animate.move_to(new_positions[i]) for i, p in enumerate(pieces)])Annotation Patterns
Step Numbers
for i, step in enumerate(proof_steps):
number = Text(f"({i+1})", font_size=20).next_to(step, LEFT)
self.play(Write(number), Write(step))Justifications
step = MathTex(r"x + x = 2x")
reason = Text("(combining like terms)", font_size=18, color=GRAY)
reason.next_to(step, RIGHT, buff=1)
self.play(Write(step), FadeIn(reason))Highlighting Key Transitions
# Before transformation
self.play(Indicate(term_to_change, color=YELLOW))
# Transform
self.play(Transform(old_term, new_term))
# After transformation
self.play(Indicate(new_term, color=GREEN))Timing for Proof Steps
| Proof Element | Duration | Wait |
|---|---|---|
| Theorem statement | 1.5s | 2s |
| Given information | 1s | 1s |
| Simple step | 1s | 1s |
| Complex step | 2s | 2s |
| Key insight | 1.5s | 3s |
| Conclusion | 1s | 2s |
Common Proof Animations
Equality Demonstration
# Show A = B by animating A to position of B
self.play(
left_side.animate.move_to(right_side),
right_side.animate.set_opacity(0.3)
)Contradiction Highlight
# Show contradiction with X mark or color
contradiction = Cross(statement, stroke_color=RED, stroke_width=8)
self.play(Create(contradiction))Induction Step
# Show n → n+1 transition
base = MathTex("P(n)")
inductive = MathTex("P(n+1)")
arrow = Arrow(base.get_right(), inductive.get_left())
self.play(Create(arrow), FadeIn(inductive))Best Practices
1. Don't skip steps - Show every logical connection 2. Use visual metaphors - Geometric proofs are often clearest 3. Color-code consistently - Same element = same color 4. Pause at key moments - Give viewer time to understand 5. Summarize at end - Briefly replay the key insight
"""
Template: Concept Flow Scene
Use for multi-concept explanations with prerequisite ordering
"""
from manim import *
class ConceptFlowScene(Scene):
"""
Base template for knowledge-tree-based animations.
Concepts are presented in prerequisite order.
"""
# Define your knowledge tree structure
KNOWLEDGE_TREE = {
"target": "Your Target Concept",
"concepts": [
# Listed in teaching order (foundations first)
{
"name": "Foundation 1",
"duration": 30, # seconds
"type": "foundation"
},
{
"name": "Prerequisite 1",
"duration": 45,
"type": "prerequisite"
},
{
"name": "Prerequisite 2",
"duration": 60,
"type": "prerequisite"
},
{
"name": "Target Concept",
"duration": 120,
"type": "target"
}
]
}
def construct(self):
# Show overview first
self.show_concept_roadmap()
# Teach each concept in order
for i, concept in enumerate(self.KNOWLEDGE_TREE["concepts"]):
self.show_progress(i)
self.teach_concept(concept)
# Conclusion
self.show_summary()
def show_concept_roadmap(self):
"""Display the learning path overview."""
title = Text("Today's Journey", font_size=48)
title.to_edge(UP)
# Create concept list
concepts = VGroup()
for i, concept in enumerate(self.KNOWLEDGE_TREE["concepts"]):
icon = self._get_concept_icon(concept["type"])
label = Text(concept["name"], font_size=32)
row = VGroup(icon, label).arrange(RIGHT, buff=0.3)
concepts.add(row)
concepts.arrange(DOWN, aligned_edge=LEFT, buff=0.4)
concepts.next_to(title, DOWN, buff=0.8)
# Animate
self.play(Write(title))
for row in concepts:
self.play(FadeIn(row, shift=RIGHT * 0.3), run_time=0.4)
self.wait(2)
self.play(FadeOut(VGroup(title, concepts)))
def _get_concept_icon(self, concept_type):
"""Return appropriate icon for concept type."""
if concept_type == "foundation":
icon = Square(side_length=0.3, fill_opacity=1, color=BLUE)
elif concept_type == "prerequisite":
icon = Circle(radius=0.15, fill_opacity=1, color=GREEN)
else: # target
icon = Star(n=5, outer_radius=0.2, fill_opacity=1, color=GOLD)
return icon
def show_progress(self, current_index):
"""Show progress through the concept tree."""
total = len(self.KNOWLEDGE_TREE["concepts"])
current = self.KNOWLEDGE_TREE["concepts"][current_index]
# Progress bar
progress_bg = Rectangle(
width=10, height=0.3,
fill_opacity=0.3, fill_color=GREY,
stroke_width=0
)
progress_fill = Rectangle(
width=10 * (current_index + 1) / total,
height=0.3,
fill_opacity=1, fill_color=BLUE,
stroke_width=0
)
progress_fill.align_to(progress_bg, LEFT)
progress_bar = VGroup(progress_bg, progress_fill)
progress_bar.to_edge(UP, buff=0.2)
# Current concept label
label = Text(
f"Step {current_index + 1}/{total}: {current['name']}",
font_size=24
)
label.next_to(progress_bar, DOWN, buff=0.2)
self.play(
FadeIn(progress_bar),
FadeIn(label),
run_time=0.5
)
self.wait(0.5)
self.play(
FadeOut(progress_bar),
FadeOut(label),
run_time=0.3
)
def teach_concept(self, concept):
"""
Override this method for each concept.
This is a placeholder showing the structure.
"""
# Show concept title
title = Text(concept["name"], font_size=48)
self.play(Write(title))
self.wait(1)
# Placeholder content - replace with actual teaching
content = Text(
f"[Content for {concept['name']}]",
font_size=32,
color=GREY
)
content.next_to(title, DOWN, buff=1)
self.play(FadeIn(content))
self.wait(concept["duration"] / 10) # Scaled for demo
self.play(FadeOut(VGroup(title, content)))
def show_summary(self):
"""Show what was covered."""
title = Text("Summary", font_size=48)
title.to_edge(UP)
# Recap all concepts
recap = VGroup()
for concept in self.KNOWLEDGE_TREE["concepts"]:
check = Text("✓", font_size=32, color=GREEN)
label = Text(concept["name"], font_size=28)
row = VGroup(check, label).arrange(RIGHT, buff=0.3)
recap.add(row)
recap.arrange(DOWN, aligned_edge=LEFT, buff=0.3)
recap.next_to(title, DOWN, buff=0.8)
self.play(Write(title))
self.play(LaggedStart(
*[FadeIn(row, shift=UP * 0.2) for row in recap],
lag_ratio=0.2
))
self.wait(2)
# =============================================================================
# EXAMPLE: Derivative Concept Flow
# =============================================================================
class DerivativeConceptFlow(ConceptFlowScene):
"""Example: Teaching derivatives with prerequisites."""
KNOWLEDGE_TREE = {
"target": "Derivatives",
"concepts": [
{
"name": "Functions",
"duration": 30,
"type": "foundation"
},
{
"name": "Slope of a Line",
"duration": 45,
"type": "prerequisite"
},
{
"name": "Limits",
"duration": 60,
"type": "prerequisite"
},
{
"name": "Derivatives",
"duration": 120,
"type": "target"
}
]
}
def teach_concept(self, concept):
"""Custom teaching for each concept."""
name = concept["name"]
if name == "Functions":
self._teach_functions()
elif name == "Slope of a Line":
self._teach_slope()
elif name == "Limits":
self._teach_limits()
elif name == "Derivatives":
self._teach_derivatives()
def _teach_functions(self):
"""Quick function review."""
title = Text("Functions: Input → Output", font_size=36)
title.to_edge(UP, buff=1)
# f(x) = x²
axes = Axes(x_range=[-3, 3], y_range=[-1, 9], x_length=6, y_length=4)
graph = axes.plot(lambda x: x**2, color=BLUE)
label = MathTex("f(x) = x^2").next_to(axes, UP)
self.play(Write(title))
self.play(Create(axes), Write(label))
self.play(Create(graph))
self.wait(1)
self.play(FadeOut(VGroup(title, axes, graph, label)))
def _teach_slope(self):
"""Teach slope concept."""
title = Text("Slope = Rise / Run", font_size=36)
title.to_edge(UP, buff=1)
axes = Axes(x_range=[0, 5], y_range=[0, 5], x_length=5, y_length=5)
line = axes.plot(lambda x: 0.5 * x + 1, color=GREEN)
# Show rise and run
p1 = axes.c2p(1, 1.5)
p2 = axes.c2p(3, 2.5)
rise = Line(
start=[p2[0], p1[1], 0],
end=p2,
color=RED
)
run = Line(
start=p1,
end=[p2[0], p1[1], 0],
color=BLUE
)
rise_label = Text("rise", font_size=24, color=RED).next_to(rise, RIGHT)
run_label = Text("run", font_size=24, color=BLUE).next_to(run, DOWN)
self.play(Write(title))
self.play(Create(axes), Create(line))
self.play(Create(run), Write(run_label))
self.play(Create(rise), Write(rise_label))
formula = MathTex(r"m = \frac{\text{rise}}{\text{run}}").to_edge(DOWN)
self.play(Write(formula))
self.wait(1)
self.play(FadeOut(VGroup(title, axes, line, rise, run, rise_label, run_label, formula)))
def _teach_limits(self):
"""Teach limit concept."""
title = Text("Limits: Approaching a Value", font_size=36)
title.to_edge(UP, buff=1)
limit_eq = MathTex(
r"\lim_{x \to a} f(x) = L"
).scale(1.2)
explanation = Text(
"As x gets closer to a, f(x) gets closer to L",
font_size=28
).next_to(limit_eq, DOWN, buff=0.5)
self.play(Write(title))
self.play(Write(limit_eq))
self.play(FadeIn(explanation))
self.wait(1)
self.play(FadeOut(VGroup(title, limit_eq, explanation)))
def _teach_derivatives(self):
"""Main derivative content."""
title = Text("The Derivative", font_size=48)
title.to_edge(UP, buff=0.5)
# Definition
definition = MathTex(
r"f'(x) = \lim_{h \to 0} \frac{f(x+h) - f(x)}{h}"
).scale(1.1)
# Meaning
meaning = Text(
"= Instantaneous rate of change",
font_size=32
).next_to(definition, DOWN, buff=0.5)
# Visual
axes = Axes(
x_range=[-1, 4], y_range=[-1, 10],
x_length=8, y_length=5
).shift(DOWN * 0.5)
curve = axes.plot(lambda x: x**2, color=BLUE)
# Tangent line at x=2
x_val = 2
slope = 2 * x_val # derivative of x²
tangent = axes.plot(
lambda x: slope * (x - x_val) + x_val**2,
x_range=[0.5, 3.5],
color=YELLOW
)
dot = Dot(axes.c2p(x_val, x_val**2), color=RED)
self.play(Write(title))
self.play(Write(definition))
self.play(FadeIn(meaning))
self.wait(1)
self.play(
VGroup(definition, meaning).animate.scale(0.7).to_corner(UR),
run_time=0.5
)
self.play(Create(axes), Create(curve))
self.play(Create(dot), Create(tangent))
tangent_label = Text("Tangent line", font_size=24, color=YELLOW)
tangent_label.next_to(tangent, UP)
slope_label = MathTex(f"\\text{{slope}} = {slope}", font_size=32)
slope_label.next_to(tangent_label, RIGHT, buff=1)
self.play(Write(tangent_label), Write(slope_label))
self.wait(2)
self.play(FadeOut(VGroup(
title, definition, meaning, axes, curve, tangent, dot,
tangent_label, slope_label
)))
"""
Template: Equation Transformation
Use for step-by-step algebraic manipulations
"""
from manim import *
class EquationTransform(Scene):
def construct(self):
# Define your equations
equations = [
MathTex("{{x^2}} + {{2x}} + {{1}} = 0"),
MathTex("{{x^2}} + {{2x}} = {{-1}}"),
MathTex("{{x^2}} + {{2x}} + {{1}} = {{-1}} + {{1}}"),
MathTex("{{(x + 1)^2}} = {{0}}"),
MathTex("{{x}} = {{-1}}"),
]
# Position first equation
equations[0].to_edge(UP, buff=1)
self.play(Write(equations[0]))
self.wait()
# Transform through each step
for i in range(1, len(equations)):
equations[i].move_to(equations[i-1])
self.play(TransformMatchingTex(
equations[i-1], equations[i],
key_map={
# Map parts that should transform into each other
}
))
self.wait(0.5)
# Highlight final answer
self.play(equations[-1].animate.set_color(YELLOW))
self.wait(2)
"""
Template: Function Graph with Annotations
Use for visualizing mathematical functions
"""
from manim import *
class GraphFunction(Scene):
def construct(self):
# Configuration
FUNC = lambda x: x**2 - 2*x - 3
X_RANGE = [-2, 5]
Y_RANGE = [-5, 10]
FUNC_LABEL = "f(x) = x^2 - 2x - 3"
# Create axes
axes = Axes(
x_range=[X_RANGE[0], X_RANGE[1], 1],
y_range=[Y_RANGE[0], Y_RANGE[1], 2],
axis_config={"include_numbers": True}
)
# Plot function
graph = axes.plot(FUNC, color=BLUE)
label = MathTex(FUNC_LABEL).to_corner(UR)
self.play(Create(axes))
self.play(Create(graph), Write(label))
self.wait()
# Mark special points (roots, vertex, etc.)
roots = [(-1, 0), (3, 0)]
vertex = (1, -4)
root_dots = VGroup(*[
Dot(axes.c2p(x, y), color=RED)
for x, y in roots
])
vertex_dot = Dot(axes.c2p(*vertex), color=GREEN)
vertex_label = MathTex("\\text{vertex}").next_to(vertex_dot, DOWN)
self.play(Create(root_dots))
self.play(Create(vertex_dot), Write(vertex_label))
self.wait(2)