manim-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +104 -0
- package/dist/demo.mp4 +0 -0
- package/dist/index.js +65 -0
- package/dist/mcp-app.html +142 -0
- package/dist/server.js +1492 -0
- package/package.json +67 -0
- package/references/composer/SKILL.md +154 -0
- package/references/composer/references/3b1b-series-patterns.md +217 -0
- package/references/composer/references/domain-planning-guides/calculus-planning.md +188 -0
- package/references/composer/references/domain-planning-guides/linear-algebra-planning.md +169 -0
- package/references/composer/references/domain-planning-guides/ml-planning.md +286 -0
- package/references/composer/references/domain-planning-guides/number-theory-planning.md +187 -0
- package/references/composer/references/domain-planning-guides/physics-planning.md +249 -0
- package/references/composer/references/domain-planning-guides/probability-planning.md +200 -0
- package/references/composer/references/mathematical-storytelling.md +359 -0
- package/references/composer/references/narrative-patterns.md +221 -0
- package/references/composer/references/opening-patterns.md +284 -0
- package/references/composer/references/pacing-guide.md +289 -0
- package/references/composer/references/scene-archetypes.md +534 -0
- package/references/composer/references/scene-examples.md +379 -0
- package/references/composer/references/visual-techniques.md +480 -0
- package/references/composer/templates/scenes-template.md +147 -0
- package/references/manimce/SKILL.md +166 -0
- package/references/manimce/examples/3d_visualization.py +373 -0
- package/references/manimce/examples/basic_animations.py +212 -0
- package/references/manimce/examples/graph_plotting.py +401 -0
- package/references/manimce/examples/lorenz_attractor.py +172 -0
- package/references/manimce/examples/math_visualization.py +315 -0
- package/references/manimce/examples/updater_patterns.py +369 -0
- package/references/manimce/rules/3b1b-translation.md +594 -0
- package/references/manimce/rules/3d.md +254 -0
- package/references/manimce/rules/advanced-animations.md +594 -0
- package/references/manimce/rules/animation-groups.md +212 -0
- package/references/manimce/rules/animations.md +128 -0
- package/references/manimce/rules/api-pitfalls.md +89 -0
- package/references/manimce/rules/axes.md +214 -0
- package/references/manimce/rules/camera.md +208 -0
- package/references/manimce/rules/cli.md +232 -0
- package/references/manimce/rules/color-conventions.md +444 -0
- package/references/manimce/rules/colors.md +199 -0
- package/references/manimce/rules/config.md +264 -0
- package/references/manimce/rules/creation-animations.md +158 -0
- package/references/manimce/rules/graphing.md +233 -0
- package/references/manimce/rules/grouping.md +220 -0
- package/references/manimce/rules/latex.md +202 -0
- package/references/manimce/rules/lines.md +241 -0
- package/references/manimce/rules/long-form-video.md +552 -0
- package/references/manimce/rules/mathematical-domains.md +689 -0
- package/references/manimce/rules/mobjects.md +116 -0
- package/references/manimce/rules/multi-scene-composition.md +112 -0
- package/references/manimce/rules/pedagogy.md +532 -0
- package/references/manimce/rules/physics-simulations.md +610 -0
- package/references/manimce/rules/positioning.md +211 -0
- package/references/manimce/rules/scenes.md +121 -0
- package/references/manimce/rules/shapes.md +300 -0
- package/references/manimce/rules/styling.md +177 -0
- package/references/manimce/rules/text-animations.md +222 -0
- package/references/manimce/rules/text.md +189 -0
- package/references/manimce/rules/timing.md +227 -0
- package/references/manimce/rules/transform-animations.md +157 -0
- package/references/manimce/rules/updaters.md +226 -0
- package/references/manimce/templates/basic_scene.py +64 -0
- package/references/manimce/templates/camera_scene.py +100 -0
- package/references/manimce/templates/threed_scene.py +138 -0
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pedagogy
|
|
3
|
+
description: Pedagogical patterns from 3Blue1Brown for creating effective mathematical explanations in ManimCE
|
|
4
|
+
metadata:
|
|
5
|
+
tags: pedagogy, teaching, 3b1b, pi-creature, intuition, visualization, revelation
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Pedagogical Patterns from 3Blue1Brown
|
|
9
|
+
|
|
10
|
+
These patterns are distilled from the full 3Blue1Brown video corpus (2015-2026). They represent the core teaching philosophy that makes 3b1b videos effective.
|
|
11
|
+
|
|
12
|
+
## "Never Forget What This Represents"
|
|
13
|
+
|
|
14
|
+
The central 3b1b principle: every algebraic manipulation must be tied back to its geometric or visual meaning. Never let the viewer lose sight of the connection between symbols and pictures.
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
from manim import *
|
|
18
|
+
|
|
19
|
+
class TieComputationToGeometry(Scene):
|
|
20
|
+
"""Always show both the formula AND what it means visually."""
|
|
21
|
+
|
|
22
|
+
def construct(self):
|
|
23
|
+
# Show the equation
|
|
24
|
+
equation = MathTex(
|
|
25
|
+
r"|\vec{v}|^2 = x^2 + y^2",
|
|
26
|
+
tex_to_color_map={"x": GREEN, "y": RED},
|
|
27
|
+
)
|
|
28
|
+
equation.to_edge(UP)
|
|
29
|
+
|
|
30
|
+
# Show the geometry simultaneously
|
|
31
|
+
plane = NumberPlane().set_opacity(0.3)
|
|
32
|
+
vec = Vector([3, 2], color=YELLOW)
|
|
33
|
+
x_comp = Line(ORIGIN, [3, 0, 0], color=GREEN, stroke_width=4)
|
|
34
|
+
y_comp = Line([3, 0, 0], [3, 2, 0], color=RED, stroke_width=4)
|
|
35
|
+
|
|
36
|
+
x_label = MathTex("x", color=GREEN).next_to(x_comp, DOWN)
|
|
37
|
+
y_label = MathTex("y", color=RED).next_to(y_comp, RIGHT)
|
|
38
|
+
|
|
39
|
+
# Introduce both together
|
|
40
|
+
self.add(plane)
|
|
41
|
+
self.play(
|
|
42
|
+
GrowArrow(vec),
|
|
43
|
+
Write(equation),
|
|
44
|
+
)
|
|
45
|
+
self.wait()
|
|
46
|
+
|
|
47
|
+
# Show the components connecting to the formula
|
|
48
|
+
self.play(Create(x_comp), Write(x_label))
|
|
49
|
+
self.play(Create(y_comp), Write(y_label))
|
|
50
|
+
self.wait()
|
|
51
|
+
|
|
52
|
+
# Highlight the connection: square each component visually
|
|
53
|
+
x_square = Square(side_length=1.5, color=GREEN, fill_opacity=0.3)
|
|
54
|
+
x_square.next_to(x_comp, DOWN, buff=0.5, aligned_edge=LEFT)
|
|
55
|
+
x_sq_label = MathTex("x^2", color=GREEN).move_to(x_square)
|
|
56
|
+
|
|
57
|
+
y_square = Square(side_length=1.0, color=RED, fill_opacity=0.3)
|
|
58
|
+
y_square.next_to(y_comp, RIGHT, buff=0.5, aligned_edge=DOWN)
|
|
59
|
+
y_sq_label = MathTex("y^2", color=RED).move_to(y_square)
|
|
60
|
+
|
|
61
|
+
self.play(
|
|
62
|
+
DrawBorderThenFill(x_square), Write(x_sq_label),
|
|
63
|
+
DrawBorderThenFill(y_square), Write(y_sq_label),
|
|
64
|
+
)
|
|
65
|
+
self.wait(2)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Physical Intuition First, Formalization Second
|
|
69
|
+
|
|
70
|
+
Always start with a physical, tangible example before introducing abstract notation. The viewer should already "feel" the answer before seeing the formula.
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
class IntuitionFirst(Scene):
|
|
74
|
+
"""Show the physical behavior, THEN the equation."""
|
|
75
|
+
|
|
76
|
+
def construct(self):
|
|
77
|
+
# Phase 1: Show the physical behavior (no formulas yet)
|
|
78
|
+
title = Text("What happens when you spin a wheel?", font_size=36)
|
|
79
|
+
title.to_edge(UP)
|
|
80
|
+
self.play(Write(title))
|
|
81
|
+
|
|
82
|
+
wheel = Circle(radius=1.5, color=WHITE)
|
|
83
|
+
dot = Dot(point=wheel.point_from_proportion(0), color=YELLOW)
|
|
84
|
+
dot.add_updater(
|
|
85
|
+
lambda m, dt: m.move_to(
|
|
86
|
+
wheel.point_from_proportion(
|
|
87
|
+
(m.get_center()[0] / (2 * PI * 1.5)) % 1
|
|
88
|
+
)
|
|
89
|
+
)
|
|
90
|
+
)
|
|
91
|
+
self.play(Create(wheel), FadeIn(dot))
|
|
92
|
+
|
|
93
|
+
# Trace the path as the wheel rolls
|
|
94
|
+
traced_path = TracedPath(dot.get_center, stroke_color=YELLOW, stroke_width=2)
|
|
95
|
+
self.add(traced_path)
|
|
96
|
+
self.play(Rotate(wheel, 2 * TAU, about_point=ORIGIN), run_time=4)
|
|
97
|
+
self.wait()
|
|
98
|
+
|
|
99
|
+
# Phase 2: NOW introduce the formula
|
|
100
|
+
self.play(FadeOut(title))
|
|
101
|
+
formula_title = Text("The math behind this:", font_size=36)
|
|
102
|
+
formula_title.to_edge(UP)
|
|
103
|
+
formula = MathTex(
|
|
104
|
+
r"\vec{r}(t) = \begin{bmatrix} t - \sin(t) \\ 1 - \cos(t) \end{bmatrix}"
|
|
105
|
+
)
|
|
106
|
+
formula.next_to(formula_title, DOWN, buff=0.5)
|
|
107
|
+
|
|
108
|
+
self.play(Write(formula_title), Write(formula))
|
|
109
|
+
self.wait(2)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Multiple Perspectives on the Same Concept
|
|
113
|
+
|
|
114
|
+
3b1b regularly shows 2-3 different ways to think about the same idea (algebraic, geometric, physical). This is central to the Essence of Linear Algebra series.
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
class MultiplePerspectives(Scene):
|
|
118
|
+
"""Show the same concept from different angles."""
|
|
119
|
+
|
|
120
|
+
def construct(self):
|
|
121
|
+
# Perspective 1: Geometric (visual)
|
|
122
|
+
p1_title = Text("Geometric View", font_size=30, color=BLUE)
|
|
123
|
+
p1_title.to_corner(UL)
|
|
124
|
+
det_visual = VGroup(
|
|
125
|
+
Vector([2, 0], color=GREEN),
|
|
126
|
+
Vector([1, 1.5], color=RED),
|
|
127
|
+
)
|
|
128
|
+
parallelogram = Polygon(
|
|
129
|
+
ORIGIN, [2, 0, 0], [3, 1.5, 0], [1, 1.5, 0],
|
|
130
|
+
fill_color=YELLOW, fill_opacity=0.3, stroke_color=YELLOW,
|
|
131
|
+
)
|
|
132
|
+
area_label = MathTex(r"\text{Area}", color=YELLOW)
|
|
133
|
+
area_label.move_to(parallelogram)
|
|
134
|
+
|
|
135
|
+
geo_group = VGroup(det_visual, parallelogram, area_label, p1_title)
|
|
136
|
+
geo_group.shift(3 * LEFT)
|
|
137
|
+
|
|
138
|
+
# Perspective 2: Algebraic (formula)
|
|
139
|
+
p2_title = Text("Algebraic View", font_size=30, color=GREEN)
|
|
140
|
+
p2_title.to_edge(UP).shift(3 * RIGHT)
|
|
141
|
+
formula = MathTex(
|
|
142
|
+
r"\det \begin{bmatrix} a & b \\ c & d \end{bmatrix} = ad - bc"
|
|
143
|
+
)
|
|
144
|
+
formula.next_to(p2_title, DOWN, buff=0.5)
|
|
145
|
+
|
|
146
|
+
alg_group = VGroup(p2_title, formula)
|
|
147
|
+
|
|
148
|
+
# Show them side by side
|
|
149
|
+
self.play(
|
|
150
|
+
Write(p1_title),
|
|
151
|
+
GrowArrow(det_visual[0]), GrowArrow(det_visual[1]),
|
|
152
|
+
)
|
|
153
|
+
self.play(DrawBorderThenFill(parallelogram), Write(area_label))
|
|
154
|
+
self.wait()
|
|
155
|
+
|
|
156
|
+
self.play(Write(p2_title), Write(formula))
|
|
157
|
+
self.wait()
|
|
158
|
+
|
|
159
|
+
# Draw the connection
|
|
160
|
+
arrow = Arrow(
|
|
161
|
+
parallelogram.get_right(), formula.get_left(),
|
|
162
|
+
color=WHITE, buff=0.5,
|
|
163
|
+
)
|
|
164
|
+
same_thing = Text("Same thing!", font_size=24, color=YELLOW)
|
|
165
|
+
same_thing.next_to(arrow, UP)
|
|
166
|
+
self.play(GrowArrow(arrow), Write(same_thing))
|
|
167
|
+
self.wait(2)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Pi Creature Reactions for Emotional Engagement
|
|
171
|
+
|
|
172
|
+
In ManimGL, 3b1b uses `PiCreatureScene` and `TeacherStudentsScene` for character reactions. In ManimCE, you can create similar emotional signposting with simpler means, or use the community pi creature plugin.
|
|
173
|
+
|
|
174
|
+
### Emotional Markers Without Pi Creatures
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
class EmotionalMarkers(Scene):
|
|
178
|
+
"""Use visual cues to signal emotional beats."""
|
|
179
|
+
|
|
180
|
+
def construct(self):
|
|
181
|
+
# Confusion marker
|
|
182
|
+
equation = MathTex(r"e^{i\pi} + 1 = 0")
|
|
183
|
+
equation.scale(1.5)
|
|
184
|
+
self.play(Write(equation))
|
|
185
|
+
|
|
186
|
+
# "Wait, what?" moment
|
|
187
|
+
question_marks = VGroup(
|
|
188
|
+
*[Text("?", font_size=48, color=YELLOW) for _ in range(3)]
|
|
189
|
+
)
|
|
190
|
+
question_marks.arrange(RIGHT, buff=0.3)
|
|
191
|
+
question_marks.next_to(equation, DOWN, buff=0.5)
|
|
192
|
+
self.play(
|
|
193
|
+
LaggedStartMap(FadeIn, question_marks, scale=2, lag_ratio=0.2)
|
|
194
|
+
)
|
|
195
|
+
self.wait()
|
|
196
|
+
|
|
197
|
+
# "Aha!" moment
|
|
198
|
+
self.play(FadeOut(question_marks))
|
|
199
|
+
checkmark = Text("Ah, that makes sense!", color=GREEN, font_size=36)
|
|
200
|
+
checkmark.next_to(equation, DOWN, buff=0.5)
|
|
201
|
+
self.play(Write(checkmark))
|
|
202
|
+
self.wait()
|
|
203
|
+
|
|
204
|
+
# Surprise/delight
|
|
205
|
+
highlight = SurroundingRectangle(equation, color=YELLOW, buff=0.3)
|
|
206
|
+
self.play(Create(highlight))
|
|
207
|
+
self.play(
|
|
208
|
+
highlight.animate.set_stroke(width=6),
|
|
209
|
+
rate_func=there_and_back,
|
|
210
|
+
run_time=0.8,
|
|
211
|
+
)
|
|
212
|
+
self.wait()
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Teacher-Student Pattern (from 3b1b's TeacherStudentsScene)
|
|
216
|
+
|
|
217
|
+
```python
|
|
218
|
+
class TeacherStudentMoment(Scene):
|
|
219
|
+
"""Recreate the teacher-student dynamic without pi creatures."""
|
|
220
|
+
|
|
221
|
+
def construct(self):
|
|
222
|
+
# Teacher's statement
|
|
223
|
+
teacher_bubble = RoundedRectangle(
|
|
224
|
+
corner_radius=0.3, width=5, height=1.5,
|
|
225
|
+
color=BLUE, fill_opacity=0.15,
|
|
226
|
+
).to_edge(LEFT).shift(UP)
|
|
227
|
+
teacher_text = Text(
|
|
228
|
+
"Think about what the\ndeterminant represents",
|
|
229
|
+
font_size=28,
|
|
230
|
+
).move_to(teacher_bubble)
|
|
231
|
+
|
|
232
|
+
# Student's response
|
|
233
|
+
student_bubble = RoundedRectangle(
|
|
234
|
+
corner_radius=0.3, width=4, height=1.2,
|
|
235
|
+
color=GREEN, fill_opacity=0.15,
|
|
236
|
+
).to_edge(RIGHT).shift(DOWN)
|
|
237
|
+
student_text = Text(
|
|
238
|
+
"Scaling factor\nfor areas!",
|
|
239
|
+
font_size=28,
|
|
240
|
+
).move_to(student_bubble)
|
|
241
|
+
|
|
242
|
+
self.play(FadeIn(teacher_bubble), Write(teacher_text))
|
|
243
|
+
self.wait(2)
|
|
244
|
+
self.play(FadeIn(student_bubble), Write(student_text))
|
|
245
|
+
self.wait(2)
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Building on Prior Knowledge (Explicit Recap Scenes)
|
|
249
|
+
|
|
250
|
+
Many 3b1b series videos open by briefly recapping the previous video's key idea.
|
|
251
|
+
|
|
252
|
+
```python
|
|
253
|
+
class RecapPreviousVideo(Scene):
|
|
254
|
+
"""Brief recap before diving into new content."""
|
|
255
|
+
|
|
256
|
+
def construct(self):
|
|
257
|
+
# Mini header
|
|
258
|
+
recap_label = Text("Quick recap from last time:", font_size=28, color=GREY_A)
|
|
259
|
+
recap_label.to_corner(UL)
|
|
260
|
+
self.play(Write(recap_label))
|
|
261
|
+
|
|
262
|
+
# Show the key takeaway from previous video (dimmed)
|
|
263
|
+
prev_result = MathTex(
|
|
264
|
+
r"A\vec{v} = \lambda \vec{v}",
|
|
265
|
+
font_size=48,
|
|
266
|
+
)
|
|
267
|
+
prev_result.set_opacity(0.7)
|
|
268
|
+
prev_context = Text(
|
|
269
|
+
"An eigenvector stays on its own span",
|
|
270
|
+
font_size=24, color=GREY_B,
|
|
271
|
+
)
|
|
272
|
+
prev_context.next_to(prev_result, DOWN)
|
|
273
|
+
|
|
274
|
+
self.play(FadeIn(VGroup(prev_result, prev_context), shift=0.5 * UP))
|
|
275
|
+
self.wait(2)
|
|
276
|
+
|
|
277
|
+
# Transition to new content
|
|
278
|
+
new_title = Text("Today: How to compute eigenvalues", font_size=40)
|
|
279
|
+
new_title.to_edge(UP)
|
|
280
|
+
self.play(
|
|
281
|
+
FadeOut(VGroup(recap_label, prev_result, prev_context), shift=UP),
|
|
282
|
+
Write(new_title),
|
|
283
|
+
)
|
|
284
|
+
self.wait()
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## Controlled Revelation Pattern
|
|
288
|
+
|
|
289
|
+
Information is revealed progressively. Question marks become answers. Blank spaces get filled in. This creates a sense of discovery.
|
|
290
|
+
|
|
291
|
+
```python
|
|
292
|
+
class ControlledRevelation(Scene):
|
|
293
|
+
"""Reveal information progressively -- question marks become answers."""
|
|
294
|
+
|
|
295
|
+
def construct(self):
|
|
296
|
+
# Start with unknowns
|
|
297
|
+
equation = MathTex(
|
|
298
|
+
r"\det(A - ", r"\lambda", r"I) = ", r"?"
|
|
299
|
+
)
|
|
300
|
+
equation.set_color_by_tex(r"\lambda", TEAL)
|
|
301
|
+
equation[-1].set_color(RED)
|
|
302
|
+
equation.scale(1.3)
|
|
303
|
+
self.play(Write(equation))
|
|
304
|
+
self.wait(2)
|
|
305
|
+
|
|
306
|
+
# Replace the question mark with the actual answer
|
|
307
|
+
answer = MathTex(r"0", color=GREEN)
|
|
308
|
+
answer.scale(1.3)
|
|
309
|
+
answer.move_to(equation[-1])
|
|
310
|
+
self.play(
|
|
311
|
+
FadeOut(equation[-1], shift=UP),
|
|
312
|
+
FadeIn(answer, shift=UP),
|
|
313
|
+
)
|
|
314
|
+
self.wait()
|
|
315
|
+
|
|
316
|
+
# Expand progressively
|
|
317
|
+
expanded = MathTex(
|
|
318
|
+
r"(3-\lambda)(1-\lambda) - 2 = 0",
|
|
319
|
+
tex_to_color_map={r"\lambda": TEAL},
|
|
320
|
+
)
|
|
321
|
+
expanded.next_to(equation, DOWN, buff=0.8)
|
|
322
|
+
self.play(Write(expanded, run_time=2))
|
|
323
|
+
self.wait()
|
|
324
|
+
|
|
325
|
+
# Factor
|
|
326
|
+
factored = MathTex(
|
|
327
|
+
r"\lambda^2 - 4\lambda + 1 = 0",
|
|
328
|
+
tex_to_color_map={r"\lambda": TEAL},
|
|
329
|
+
)
|
|
330
|
+
factored.next_to(expanded, DOWN, buff=0.5)
|
|
331
|
+
self.play(Write(factored))
|
|
332
|
+
self.wait(2)
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Progressive Detail on Diagrams
|
|
336
|
+
|
|
337
|
+
```python
|
|
338
|
+
class ProgressiveDetail(Scene):
|
|
339
|
+
"""Add detail to a diagram in stages."""
|
|
340
|
+
|
|
341
|
+
def construct(self):
|
|
342
|
+
# Stage 1: Simple shape
|
|
343
|
+
circle = Circle(radius=2, color=WHITE)
|
|
344
|
+
self.play(Create(circle))
|
|
345
|
+
self.wait()
|
|
346
|
+
|
|
347
|
+
# Stage 2: Add points
|
|
348
|
+
points = VGroup(*[
|
|
349
|
+
Dot(circle.point_from_proportion(i / 5), color=YELLOW)
|
|
350
|
+
for i in range(5)
|
|
351
|
+
])
|
|
352
|
+
self.play(LaggedStartMap(FadeIn, points, scale=2, lag_ratio=0.15))
|
|
353
|
+
self.wait()
|
|
354
|
+
|
|
355
|
+
# Stage 3: Add chords
|
|
356
|
+
lines = VGroup()
|
|
357
|
+
for i in range(5):
|
|
358
|
+
for j in range(i + 1, 5):
|
|
359
|
+
line = Line(
|
|
360
|
+
points[i].get_center(), points[j].get_center(),
|
|
361
|
+
stroke_width=1, color=BLUE,
|
|
362
|
+
)
|
|
363
|
+
lines.add(line)
|
|
364
|
+
self.play(LaggedStartMap(Create, lines, lag_ratio=0.05))
|
|
365
|
+
self.wait()
|
|
366
|
+
|
|
367
|
+
# Stage 4: Add intersection dots
|
|
368
|
+
intersections = VGroup(*[
|
|
369
|
+
Dot(radius=0.05, color=RED)
|
|
370
|
+
for _ in range(3) # Simplified
|
|
371
|
+
])
|
|
372
|
+
# ... position at actual intersections
|
|
373
|
+
self.play(LaggedStartMap(FadeIn, intersections, scale=3, lag_ratio=0.1))
|
|
374
|
+
self.wait()
|
|
375
|
+
|
|
376
|
+
# Stage 5: Count regions with labels
|
|
377
|
+
counts = VGroup(*[
|
|
378
|
+
Integer(n, font_size=24, color=GREEN)
|
|
379
|
+
for n in [1, 2, 4, 8, 16]
|
|
380
|
+
])
|
|
381
|
+
# ... position in each configuration
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
## The "Build False Confidence, Then Reveal Truth" Pattern
|
|
385
|
+
|
|
386
|
+
From Moser's Circle Problem: present a pattern that looks obvious, then show it breaks. This is a powerful teaching tool for mathematical rigor.
|
|
387
|
+
|
|
388
|
+
```python
|
|
389
|
+
class FalseConfidence(Scene):
|
|
390
|
+
"""Moser pattern: build expectation, then subvert it."""
|
|
391
|
+
|
|
392
|
+
def construct(self):
|
|
393
|
+
# Phase 1: Accumulate evidence for the "obvious" pattern
|
|
394
|
+
title = Text("Powers of 2?", font_size=48)
|
|
395
|
+
title.to_edge(UP)
|
|
396
|
+
self.play(Write(title))
|
|
397
|
+
|
|
398
|
+
values = [1, 2, 4, 8, 16]
|
|
399
|
+
value_mobs = VGroup()
|
|
400
|
+
for v in values:
|
|
401
|
+
mob = Integer(v, font_size=42)
|
|
402
|
+
value_mobs.add(mob)
|
|
403
|
+
value_mobs.arrange(RIGHT, buff=1.0)
|
|
404
|
+
value_mobs.next_to(title, DOWN, buff=1.0)
|
|
405
|
+
|
|
406
|
+
for mob in value_mobs:
|
|
407
|
+
self.play(FadeIn(mob, shift=0.25 * UP), run_time=0.5)
|
|
408
|
+
self.wait(0.5)
|
|
409
|
+
|
|
410
|
+
# Viewer expects 32 next
|
|
411
|
+
dots = MathTex(r"\ldots")
|
|
412
|
+
dots.next_to(value_mobs, RIGHT)
|
|
413
|
+
next_val = Integer(32, font_size=42, color=GREEN)
|
|
414
|
+
next_val.next_to(dots, RIGHT)
|
|
415
|
+
question = Text("32?", font_size=42, color=GREEN)
|
|
416
|
+
question.next_to(dots, RIGHT)
|
|
417
|
+
self.play(Write(dots), FadeIn(question))
|
|
418
|
+
self.wait(2)
|
|
419
|
+
|
|
420
|
+
# Phase 2: The REVEAL -- it's actually 31!
|
|
421
|
+
actual = Integer(31, font_size=42, color=RED)
|
|
422
|
+
actual.move_to(question)
|
|
423
|
+
cross = Cross(question, stroke_color=RED, stroke_width=6)
|
|
424
|
+
|
|
425
|
+
self.play(Create(cross))
|
|
426
|
+
self.wait()
|
|
427
|
+
self.play(
|
|
428
|
+
FadeOut(question), FadeOut(cross),
|
|
429
|
+
FadeIn(actual, scale=1.5),
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
# Update title
|
|
433
|
+
new_title = Text("NOT powers of 2!", font_size=48, color=RED)
|
|
434
|
+
new_title.to_edge(UP)
|
|
435
|
+
self.play(
|
|
436
|
+
FadeOut(title),
|
|
437
|
+
FadeIn(new_title),
|
|
438
|
+
)
|
|
439
|
+
self.wait(2)
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
## Signposting and Navigation
|
|
443
|
+
|
|
444
|
+
3b1b frequently tells the viewer where they are in the explanation:
|
|
445
|
+
|
|
446
|
+
```python
|
|
447
|
+
class Signposting(Scene):
|
|
448
|
+
"""Visual navigation through a multi-step argument."""
|
|
449
|
+
|
|
450
|
+
def construct(self):
|
|
451
|
+
# Step tracker
|
|
452
|
+
steps = VGroup(
|
|
453
|
+
Text("1. Setup", font_size=24),
|
|
454
|
+
Text("2. Key insight", font_size=24),
|
|
455
|
+
Text("3. Proof", font_size=24),
|
|
456
|
+
Text("4. Implications", font_size=24),
|
|
457
|
+
)
|
|
458
|
+
steps.arrange(DOWN, aligned_edge=LEFT, buff=0.3)
|
|
459
|
+
steps.to_corner(UL)
|
|
460
|
+
steps.set_opacity(0.3)
|
|
461
|
+
|
|
462
|
+
self.add(steps)
|
|
463
|
+
|
|
464
|
+
# Highlight current step
|
|
465
|
+
for i, step in enumerate(steps):
|
|
466
|
+
if i > 0:
|
|
467
|
+
steps[i - 1].animate.set_opacity(0.3)
|
|
468
|
+
self.play(step.animate.set_opacity(1.0).set_color(YELLOW))
|
|
469
|
+
self.wait()
|
|
470
|
+
# ... do the content for this step ...
|
|
471
|
+
self.wait(2)
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
## Analogy Pattern
|
|
475
|
+
|
|
476
|
+
3b1b often introduces a concept through analogy to a familiar domain:
|
|
477
|
+
|
|
478
|
+
```python
|
|
479
|
+
class AnalogyPattern(Scene):
|
|
480
|
+
"""Introduce abstract concept through familiar analogy."""
|
|
481
|
+
|
|
482
|
+
def construct(self):
|
|
483
|
+
# The familiar thing
|
|
484
|
+
familiar_title = Text("A recipe", font_size=36)
|
|
485
|
+
familiar_title.to_edge(UP).shift(3 * LEFT)
|
|
486
|
+
recipe_items = VGroup(
|
|
487
|
+
Text("Ingredients:", font_size=24),
|
|
488
|
+
Text(" 2 cups flour", font_size=20),
|
|
489
|
+
Text(" 1 cup sugar", font_size=20),
|
|
490
|
+
Text(" 3 eggs", font_size=20),
|
|
491
|
+
).arrange(DOWN, aligned_edge=LEFT)
|
|
492
|
+
recipe_items.next_to(familiar_title, DOWN)
|
|
493
|
+
|
|
494
|
+
# The abstract thing
|
|
495
|
+
abstract_title = Text("A linear combination", font_size=36)
|
|
496
|
+
abstract_title.to_edge(UP).shift(3 * RIGHT)
|
|
497
|
+
math_items = VGroup(
|
|
498
|
+
MathTex(r"\text{Components:}", font_size=24),
|
|
499
|
+
MathTex(r"2\hat{\imath}", font_size=24, color=GREEN),
|
|
500
|
+
MathTex(r"1\hat{\jmath}", font_size=24, color=RED),
|
|
501
|
+
MathTex(r"3\hat{k}", font_size=24, color=BLUE),
|
|
502
|
+
).arrange(DOWN, aligned_edge=LEFT)
|
|
503
|
+
math_items.next_to(abstract_title, DOWN)
|
|
504
|
+
|
|
505
|
+
# Show familiar first
|
|
506
|
+
self.play(Write(familiar_title), FadeIn(recipe_items, lag_ratio=0.2))
|
|
507
|
+
self.wait(2)
|
|
508
|
+
|
|
509
|
+
# Then the abstract, drawing parallels
|
|
510
|
+
self.play(Write(abstract_title), FadeIn(math_items, lag_ratio=0.2))
|
|
511
|
+
|
|
512
|
+
# Draw arrows showing the analogy
|
|
513
|
+
arrows = VGroup(*[
|
|
514
|
+
Arrow(recipe_items[i + 1].get_right(), math_items[i + 1].get_left(), buff=0.3)
|
|
515
|
+
for i in range(3)
|
|
516
|
+
])
|
|
517
|
+
self.play(LaggedStartMap(GrowArrow, arrows, lag_ratio=0.2))
|
|
518
|
+
self.wait(2)
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
## Best Practices Summary
|
|
522
|
+
|
|
523
|
+
1. **Always tie algebra to geometry** -- if you write a formula, show what it means visually
|
|
524
|
+
2. **Physical intuition first** -- let the viewer "feel" the concept before formalizing
|
|
525
|
+
3. **Show multiple perspectives** -- algebraic, geometric, and physical views of the same idea
|
|
526
|
+
4. **Progressive revelation** -- question marks become answers, details accumulate
|
|
527
|
+
5. **Build false confidence** (when appropriate) -- show a pattern, then break it
|
|
528
|
+
6. **Signpost your progress** -- tell the viewer where they are in the argument
|
|
529
|
+
7. **Use emotional markers** -- surprise, confusion, and satisfaction moments
|
|
530
|
+
8. **Recap before extending** -- briefly review before building on prior concepts
|
|
531
|
+
9. **Analogy first** -- connect new concepts to familiar ones
|
|
532
|
+
10. **Never let notation become opaque** -- if a symbol appears, the viewer should know what it means
|