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.
Files changed (64) hide show
  1. package/README.md +104 -0
  2. package/dist/demo.mp4 +0 -0
  3. package/dist/index.js +65 -0
  4. package/dist/mcp-app.html +142 -0
  5. package/dist/server.js +1492 -0
  6. package/package.json +67 -0
  7. package/references/composer/SKILL.md +154 -0
  8. package/references/composer/references/3b1b-series-patterns.md +217 -0
  9. package/references/composer/references/domain-planning-guides/calculus-planning.md +188 -0
  10. package/references/composer/references/domain-planning-guides/linear-algebra-planning.md +169 -0
  11. package/references/composer/references/domain-planning-guides/ml-planning.md +286 -0
  12. package/references/composer/references/domain-planning-guides/number-theory-planning.md +187 -0
  13. package/references/composer/references/domain-planning-guides/physics-planning.md +249 -0
  14. package/references/composer/references/domain-planning-guides/probability-planning.md +200 -0
  15. package/references/composer/references/mathematical-storytelling.md +359 -0
  16. package/references/composer/references/narrative-patterns.md +221 -0
  17. package/references/composer/references/opening-patterns.md +284 -0
  18. package/references/composer/references/pacing-guide.md +289 -0
  19. package/references/composer/references/scene-archetypes.md +534 -0
  20. package/references/composer/references/scene-examples.md +379 -0
  21. package/references/composer/references/visual-techniques.md +480 -0
  22. package/references/composer/templates/scenes-template.md +147 -0
  23. package/references/manimce/SKILL.md +166 -0
  24. package/references/manimce/examples/3d_visualization.py +373 -0
  25. package/references/manimce/examples/basic_animations.py +212 -0
  26. package/references/manimce/examples/graph_plotting.py +401 -0
  27. package/references/manimce/examples/lorenz_attractor.py +172 -0
  28. package/references/manimce/examples/math_visualization.py +315 -0
  29. package/references/manimce/examples/updater_patterns.py +369 -0
  30. package/references/manimce/rules/3b1b-translation.md +594 -0
  31. package/references/manimce/rules/3d.md +254 -0
  32. package/references/manimce/rules/advanced-animations.md +594 -0
  33. package/references/manimce/rules/animation-groups.md +212 -0
  34. package/references/manimce/rules/animations.md +128 -0
  35. package/references/manimce/rules/api-pitfalls.md +89 -0
  36. package/references/manimce/rules/axes.md +214 -0
  37. package/references/manimce/rules/camera.md +208 -0
  38. package/references/manimce/rules/cli.md +232 -0
  39. package/references/manimce/rules/color-conventions.md +444 -0
  40. package/references/manimce/rules/colors.md +199 -0
  41. package/references/manimce/rules/config.md +264 -0
  42. package/references/manimce/rules/creation-animations.md +158 -0
  43. package/references/manimce/rules/graphing.md +233 -0
  44. package/references/manimce/rules/grouping.md +220 -0
  45. package/references/manimce/rules/latex.md +202 -0
  46. package/references/manimce/rules/lines.md +241 -0
  47. package/references/manimce/rules/long-form-video.md +552 -0
  48. package/references/manimce/rules/mathematical-domains.md +689 -0
  49. package/references/manimce/rules/mobjects.md +116 -0
  50. package/references/manimce/rules/multi-scene-composition.md +112 -0
  51. package/references/manimce/rules/pedagogy.md +532 -0
  52. package/references/manimce/rules/physics-simulations.md +610 -0
  53. package/references/manimce/rules/positioning.md +211 -0
  54. package/references/manimce/rules/scenes.md +121 -0
  55. package/references/manimce/rules/shapes.md +300 -0
  56. package/references/manimce/rules/styling.md +177 -0
  57. package/references/manimce/rules/text-animations.md +222 -0
  58. package/references/manimce/rules/text.md +189 -0
  59. package/references/manimce/rules/timing.md +227 -0
  60. package/references/manimce/rules/transform-animations.md +157 -0
  61. package/references/manimce/rules/updaters.md +226 -0
  62. package/references/manimce/templates/basic_scene.py +64 -0
  63. package/references/manimce/templates/camera_scene.py +100 -0
  64. package/references/manimce/templates/threed_scene.py +138 -0
@@ -0,0 +1,552 @@
1
+ ---
2
+ name: long-form-video
3
+ description: Comprehensive guide to structuring long-form math videos (15-30+ min) in the 3Blue1Brown style using ManimCE
4
+ metadata:
5
+ tags: video-structure, narrative, pacing, transitions, scenes, long-form, 3b1b
6
+ ---
7
+
8
+ # Long-Form Video Structure in ManimCE
9
+
10
+ This guide captures the architectural patterns from 407 3Blue1Brown video files (2015-2026) for building coherent, long-form mathematical explainer videos.
11
+
12
+ ## Scene-Per-Section Architecture
13
+
14
+ 3b1b videos decompose into 10-40 individual Scene classes per video file. Each Scene class corresponds to one conceptual section of the video. Within each Scene, the `construct()` method is organized into commented sections that follow a clear narrative arc.
15
+
16
+ ### Method-Per-Section Pattern
17
+
18
+ ```python
19
+ from manim import *
20
+
21
+ class ExplainEigenvalues(MovingCameraScene):
22
+ """One section of a larger linear algebra video."""
23
+
24
+ def construct(self):
25
+ # Setup: establish the visual environment
26
+ self.setup_coordinate_plane()
27
+
28
+ # Introduce: present the concept with simple example
29
+ self.introduce_matrix_action()
30
+
31
+ # Demonstrate: show the key behavior
32
+ self.show_eigenvector_behavior()
33
+
34
+ # Deepen: build complexity
35
+ self.show_eigenvalue_equation()
36
+
37
+ # Conclude: transition to next topic
38
+ self.conclude_with_question()
39
+
40
+ def setup_coordinate_plane(self):
41
+ plane = NumberPlane()
42
+ plane.set_stroke(BLUE, 1, opacity=0.4)
43
+ basis_i = Vector([1, 0], color=GREEN)
44
+ basis_j = Vector([0, 1], color=RED)
45
+ i_label = MathTex(r"\hat{\imath}").next_to(basis_i, DOWN)
46
+ j_label = MathTex(r"\hat{\jmath}").next_to(basis_j, LEFT)
47
+ i_label.set_color(GREEN)
48
+ j_label.set_color(RED)
49
+
50
+ self.play(Create(plane), run_time=2)
51
+ self.play(
52
+ GrowArrow(basis_i), GrowArrow(basis_j),
53
+ Write(i_label), Write(j_label),
54
+ )
55
+ self.wait()
56
+
57
+ self.plane = plane
58
+ self.basis_vectors = VGroup(basis_i, basis_j)
59
+
60
+ def introduce_matrix_action(self):
61
+ matrix = Matrix([[3, 1], [0, 2]])
62
+ matrix.to_corner(UL)
63
+ self.play(Write(matrix))
64
+ self.wait()
65
+ self.matrix_mob = matrix
66
+
67
+ def show_eigenvector_behavior(self):
68
+ # Eigenvector stays on its span
69
+ eigen_vec = Vector([1, 0], color=YELLOW)
70
+ label = MathTex(r"\vec{v}", color=YELLOW)
71
+ label.next_to(eigen_vec, UP)
72
+ self.play(GrowArrow(eigen_vec), Write(label))
73
+ self.wait()
74
+
75
+ # After transformation, still on span but scaled
76
+ scaled_vec = Vector([3, 0], color=YELLOW)
77
+ self.play(
78
+ Transform(eigen_vec, scaled_vec),
79
+ run_time=2,
80
+ )
81
+ self.wait()
82
+
83
+ def show_eigenvalue_equation(self):
84
+ equation = MathTex(
85
+ r"A", r"\vec{v}", r"=", r"\lambda", r"\vec{v}",
86
+ tex_to_color_map={
87
+ r"\vec{v}": YELLOW,
88
+ r"\lambda": TEAL,
89
+ r"A": WHITE,
90
+ }
91
+ )
92
+ equation.to_edge(UP)
93
+ self.play(Write(equation))
94
+ self.wait(2)
95
+
96
+ def conclude_with_question(self):
97
+ question = Text("But how do we find these special vectors?")
98
+ question.scale(0.8)
99
+ question.to_edge(DOWN)
100
+ self.play(Write(question))
101
+ self.wait(2)
102
+ self.play(FadeOut(question))
103
+ ```
104
+
105
+ ## Composing 20+ Scenes Into a Video
106
+
107
+ In 3b1b's workflow, a single Python file contains many Scene classes that together form one video. Scenes are rendered individually and concatenated. Here is the typical organization pattern:
108
+
109
+ ```python
110
+ from manim import *
111
+
112
+ # --- Constants used across all scenes ---
113
+ FORMULA_COLOR = YELLOW
114
+ GRAPH_COLOR = BLUE
115
+ HIGHLIGHT_COLOR = GREEN
116
+
117
+ # --- Section 1: Opening ---
118
+ class OpeningQuote(Scene):
119
+ """Every EoLA/EoC chapter opens with a quote."""
120
+ def construct(self):
121
+ quote = Tex(
122
+ r"``There is hardly any theory which is more elementary \\"
123
+ r"than linear algebra, in spite of the fact that generations \\"
124
+ r"of professors and textbook writers have obscured its \\"
125
+ r"simplicity by preposterous calculations with matrices.''",
126
+ font_size=36,
127
+ )
128
+ quote.to_edge(UP, buff=1.0)
129
+ author = Text("-- Jean Dieudonne", color=YELLOW)
130
+ author.next_to(quote, DOWN, buff=1.0)
131
+
132
+ self.play(FadeIn(quote, lag_ratio=0.5, rate_func=linear, run_time=5))
133
+ self.wait(2)
134
+ self.play(Write(author, run_time=3))
135
+ self.wait()
136
+
137
+ # --- Section 2: Introduce the Problem ---
138
+ class IntroduceProblem(Scene):
139
+ def construct(self):
140
+ # Present the mystery first (see "Mystery First" pattern below)
141
+ ...
142
+
143
+ # --- Section 3: Build Intuition ---
144
+ class BuildIntuition(Scene):
145
+ def construct(self):
146
+ ...
147
+
148
+ # --- Section 4: Formal Proof ---
149
+ class FormalProof(Scene):
150
+ def construct(self):
151
+ ...
152
+
153
+ # --- Section 5: End Screen ---
154
+ class EndScreen(Scene):
155
+ def construct(self):
156
+ # Standard 3b1b end screen with two video recommendations
157
+ ...
158
+ ```
159
+
160
+ ### Scene Naming Conventions (from the codebase)
161
+
162
+ - **Descriptive names**: `AttentionPatterns`, `IntroduceEulersFormula`, `ShowPattern`
163
+ - **Teacher-student scenes**: `AskAboutPosition`, `ProblemSolvingRule1` (using `TeacherStudentsScene`)
164
+ - **Simple utility scenes**: `SimpleRect`, `SimpleFEq` (small annotation clips)
165
+ - **Supplement scenes**: placed in `supplements.py` for tangential content
166
+
167
+ ## Progressive Complexity Pattern
168
+
169
+ Every 3b1b video follows: simple cases first, complex cases later. Concrete examples before abstract formulas.
170
+
171
+ ```python
172
+ class ProgressiveComplexity(Scene):
173
+ def construct(self):
174
+ # Phase 1: Simplest possible case
175
+ simple_eq = MathTex(r"2 \times 3 = 6")
176
+ self.play(Write(simple_eq))
177
+ self.wait()
178
+
179
+ # Phase 2: Slightly more complex
180
+ medium_eq = MathTex(r"x^2 + y^2 = r^2")
181
+ self.play(
182
+ simple_eq.animate.shift(UP * 1.5).scale(0.7).set_opacity(0.5),
183
+ Write(medium_eq),
184
+ )
185
+ self.wait()
186
+
187
+ # Phase 3: The general case
188
+ general_eq = MathTex(
189
+ r"\sum_{n=0}^{\infty} \frac{f^{(n)}(a)}{n!}(x-a)^n"
190
+ )
191
+ self.play(
192
+ medium_eq.animate.shift(UP * 1.5).scale(0.7).set_opacity(0.5),
193
+ Write(general_eq),
194
+ )
195
+ self.wait(2)
196
+ ```
197
+
198
+ ## Pacing: wait(), run_time, and lag_ratio
199
+
200
+ ### self.wait() usage
201
+
202
+ 3b1b uses `self.wait()` generously, typically 1-2 seconds between concepts and up to `self.wait(2)` or `self.wait(3)` for important pauses where voiceover explains.
203
+
204
+ ```python
205
+ # After revealing a key result, pause for the viewer
206
+ self.play(Write(result))
207
+ self.wait(2) # Let it sink in
208
+
209
+ # Quick pause between steps
210
+ self.play(Create(arrow))
211
+ self.wait() # Default 1 second
212
+
213
+ # Long pause for complex diagrams
214
+ self.play(FadeIn(full_diagram))
215
+ self.wait(3) # Give viewer time to read everything
216
+ ```
217
+
218
+ ### run_time Control
219
+
220
+ ```python
221
+ # Fast animations for simple transitions (0.5s)
222
+ self.play(FadeOut(old_stuff), run_time=0.5)
223
+
224
+ # Standard animations (1s default)
225
+ self.play(Create(circle))
226
+
227
+ # Slow, dramatic reveals (2-3s)
228
+ self.play(Write(important_equation), run_time=2)
229
+
230
+ # Very slow for complex transformations (3-5s)
231
+ self.play(
232
+ Transform(plane, transformed_plane),
233
+ run_time=3,
234
+ rate_func=smooth,
235
+ )
236
+ ```
237
+
238
+ ### lag_ratio for Staggered Effects
239
+
240
+ The `lag_ratio` parameter is used extensively throughout the codebase for wave-like, cascading animations:
241
+
242
+ ```python
243
+ # Staggered fade-in of word-by-word text
244
+ words = VGroup(*[Text(w) for w in ["Hello", "beautiful", "world"]])
245
+ words.arrange(RIGHT, buff=0.3)
246
+ self.play(
247
+ LaggedStartMap(FadeIn, words, shift=0.5 * UP, lag_ratio=0.25)
248
+ )
249
+
250
+ # Cascading creation of bars in a chart
251
+ bars = VGroup(*[Rectangle(height=h, width=0.3) for h in [1, 2, 3, 2, 1]])
252
+ bars.arrange(RIGHT, buff=0.1, aligned_edge=DOWN)
253
+ self.play(
254
+ LaggedStartMap(GrowFromEdge, bars, edge=DOWN, lag_ratio=0.15),
255
+ run_time=2,
256
+ )
257
+
258
+ # Lagged arrow growth
259
+ arrows = VGroup(*[Arrow(ORIGIN, RIGHT) for _ in range(5)])
260
+ self.play(
261
+ LaggedStartMap(GrowArrow, arrows, lag_ratio=0.2, run_time=1.5)
262
+ )
263
+ ```
264
+
265
+ ## Transition Patterns Between Topics
266
+
267
+ ### FadeOut/FadeIn Group Transitions
268
+
269
+ The most common pattern: fade out everything from the previous section, fade in the new section.
270
+
271
+ ```python
272
+ class TransitionPatterns(Scene):
273
+ def construct(self):
274
+ # --- Section A content ---
275
+ title_a = Text("Linear Transformations")
276
+ diagram_a = NumberPlane()
277
+ section_a = VGroup(title_a, diagram_a)
278
+
279
+ self.play(Write(title_a), Create(diagram_a))
280
+ self.wait(2)
281
+
282
+ # --- Transition: clear and introduce next section ---
283
+ title_b = Text("Matrix Multiplication")
284
+ self.play(
285
+ FadeOut(section_a, shift=LEFT),
286
+ FadeIn(title_b, shift=RIGHT),
287
+ )
288
+
289
+ # --- Section B content ---
290
+ ...
291
+ ```
292
+
293
+ ### Zooming Transition (MovingCameraScene)
294
+
295
+ ```python
296
+ class ZoomTransition(MovingCameraScene):
297
+ def construct(self):
298
+ overview = VGroup(
299
+ *[Circle(radius=0.5).shift(2 * d) for d in [LEFT, RIGHT, UP, DOWN]]
300
+ )
301
+ self.add(overview)
302
+
303
+ # Zoom into one element
304
+ target = overview[0]
305
+ self.play(
306
+ self.camera.frame.animate.set_width(3).move_to(target),
307
+ run_time=2,
308
+ )
309
+ self.wait()
310
+
311
+ # Zoom back out
312
+ self.play(
313
+ self.camera.frame.animate.set_width(14).move_to(ORIGIN),
314
+ run_time=2,
315
+ )
316
+ ```
317
+
318
+ ### Rearrangement Transition
319
+
320
+ A 3b1b hallmark: instead of cutting, rearrange existing elements into a new configuration.
321
+
322
+ ```python
323
+ # Move equation to corner, make room for diagram
324
+ equation.generate_target()
325
+ equation.target.scale(0.6).to_corner(UL)
326
+ self.play(MoveToTarget(equation))
327
+
328
+ # Or with .animate
329
+ self.play(
330
+ equation.animate.scale(0.6).to_corner(UL),
331
+ FadeIn(new_diagram),
332
+ )
333
+ ```
334
+
335
+ ## The "Mystery First" Pattern
336
+
337
+ 3b1b videos almost always open with a surprising or mysterious result, then spend the video explaining it. This is the signature pedagogical hook.
338
+
339
+ ```python
340
+ class MysteryFirst(Scene):
341
+ """Pattern: Show the surprising result, THEN explain."""
342
+
343
+ def construct(self):
344
+ # Step 1: Show the surprising claim
345
+ claim = MathTex(r"1 + 2 + 4 + 8 + \cdots = -1")
346
+ claim.scale(1.5)
347
+ question_mark = Text("???", color=RED, font_size=72)
348
+ question_mark.next_to(claim, RIGHT)
349
+
350
+ self.play(Write(claim))
351
+ self.play(FadeIn(question_mark, scale=1.5))
352
+ self.wait(2)
353
+
354
+ # Step 2: "Let me show you what I mean..."
355
+ self.play(FadeOut(question_mark))
356
+ explanation_title = Text("Here's what's going on...")
357
+ explanation_title.to_edge(UP)
358
+ self.play(
359
+ claim.animate.scale(0.6).to_corner(UL),
360
+ Write(explanation_title),
361
+ )
362
+ self.wait()
363
+
364
+ # Step 3: Build up the explanation from scratch
365
+ # ... rest of the scene
366
+ ```
367
+
368
+ ### Moser's Circle Problem Pattern (Build false confidence, then reveal truth)
369
+
370
+ From `_2023/moser_reboot/main.py` and `_2015/moser_main.py`:
371
+
372
+ ```python
373
+ class BuildFalseConfidence(Scene):
374
+ """Show a pattern that LOOKS like powers of 2, then reveal it breaks."""
375
+
376
+ def construct(self):
377
+ # Reveal values one by one
378
+ values = [1, 2, 4, 8, 16, 31] # NOT 32!
379
+ labels = VGroup()
380
+ for i, v in enumerate(values):
381
+ label = MathTex(str(v))
382
+ labels.add(label)
383
+ self.play(FadeIn(label, shift=0.25 * UP), run_time=0.5)
384
+ self.wait(0.5)
385
+
386
+ # Highlight the "pattern"
387
+ brace = Brace(labels[:5], DOWN)
388
+ pattern_text = brace.get_text("Powers of 2?")
389
+ self.play(GrowFromCenter(brace), Write(pattern_text))
390
+ self.wait(2)
391
+
392
+ # The reveal: it BREAKS
393
+ highlight = SurroundingRectangle(labels[-1], color=RED)
394
+ not_32 = MathTex(r"\neq 32", color=RED)
395
+ not_32.next_to(labels[-1], RIGHT)
396
+ self.play(Create(highlight), Write(not_32))
397
+ self.wait(2)
398
+ ```
399
+
400
+ ## Opening Quote Pattern
401
+
402
+ Every Essence of Linear Algebra and Essence of Calculus chapter opens with a literary or mathematical quote. The ManimCE equivalent:
403
+
404
+ ```python
405
+ class OpeningQuoteScene(Scene):
406
+ """Standard 3b1b opening quote."""
407
+
408
+ def construct(self):
409
+ quote_text = (
410
+ r"``The introduction of numbers as coordinates is an act of "
411
+ r"violence.'' "
412
+ )
413
+ quote = Tex(quote_text, font_size=40)
414
+ quote.set_width(FRAME_WIDTH - 2)
415
+ quote.to_edge(UP, buff=1.0)
416
+
417
+ author = Text("-- Hermann Weyl", color=YELLOW)
418
+ author.next_to(quote, DOWN, buff=1.0)
419
+
420
+ self.play(
421
+ FadeIn(quote, lag_ratio=0.5, rate_func=linear, run_time=5)
422
+ )
423
+ self.wait(2)
424
+ self.play(Write(author, run_time=3))
425
+ self.wait()
426
+ ```
427
+
428
+ ## End Screen Pattern
429
+
430
+ 3b1b videos end with a standard screen showing clickable video thumbnails and patron credits.
431
+
432
+ ```python
433
+ class SimpleEndScreen(Scene):
434
+ """Simplified ManimCE end screen pattern."""
435
+
436
+ def construct(self):
437
+ # Black background with divider
438
+ divider = DashedLine(
439
+ FRAME_WIDTH / 2 * LEFT, FRAME_WIDTH / 2 * RIGHT
440
+ )
441
+ self.add(divider)
442
+
443
+ # Title
444
+ title = Text("Clicky Stuffs", font_size=54)
445
+ title.to_edge(UP, buff=0.3)
446
+ self.add(title)
447
+
448
+ # Video recommendation placeholders
449
+ screen1 = ScreenRectangle(height=2.5)
450
+ screen2 = ScreenRectangle(height=2.5)
451
+ screens = VGroup(screen1, screen2).arrange(RIGHT, buff=0.5)
452
+ screens.next_to(divider, UP, buff=0.5)
453
+
454
+ self.play(
455
+ FadeIn(screens, lag_ratio=0.3),
456
+ Write(title),
457
+ )
458
+
459
+ # Patron credits scroll
460
+ thanks = Text(
461
+ "These videos are funded by viewers.\n"
462
+ "Special thanks to channel supporters.",
463
+ font_size=24,
464
+ color=GREY_A,
465
+ )
466
+ thanks.next_to(divider, DOWN, buff=0.3)
467
+ self.play(Write(thanks))
468
+ self.wait(5)
469
+ ```
470
+
471
+ ## Comment-Driven Section Structure
472
+
473
+ Inside every 3b1b `construct()` method, sections are separated by descriptive comments. This is the universal organizational pattern across all 407 files:
474
+
475
+ ```python
476
+ def construct(self):
477
+ # Setup
478
+ axes = Axes(...)
479
+ self.add(axes)
480
+
481
+ # Show the function
482
+ graph = axes.plot(lambda x: x**2)
483
+ self.play(Create(graph))
484
+ self.wait()
485
+
486
+ # Highlight the derivative
487
+ tangent = ...
488
+ self.play(Create(tangent))
489
+ self.wait()
490
+
491
+ # Show the formula
492
+ formula = MathTex(...)
493
+ self.play(Write(formula))
494
+ self.wait(2)
495
+
496
+ # Transition to next concept
497
+ self.play(FadeOut(VGroup(graph, tangent, formula)))
498
+ ```
499
+
500
+ ## Scene Class Attributes for Configuration
501
+
502
+ Instead of ManimGL's `CONFIG` dict pattern, ManimCE uses class attributes or `__init__` parameters:
503
+
504
+ ```python
505
+ class ConfigurableScene(Scene):
506
+ """ManimCE pattern: use class attributes for configuration."""
507
+ wave_color = BLUE
508
+ wave_amplitude = 1.0
509
+ n_waves = 5
510
+ run_time = 30
511
+
512
+ def construct(self):
513
+ axes = Axes((-12, 12), (-4, 4))
514
+ for i in range(self.n_waves):
515
+ wave = axes.plot(
516
+ lambda x: self.wave_amplitude * np.sin(x + i),
517
+ color=self.wave_color,
518
+ )
519
+ self.play(Create(wave), run_time=0.5)
520
+ self.wait()
521
+ ```
522
+
523
+ ## Reusable Helper Functions
524
+
525
+ Complex scenes extract helper functions (the `get_*` naming pattern):
526
+
527
+ ```python
528
+ def get_labeled_vector(direction, label_text, color):
529
+ """Helper to create a consistently styled labeled vector."""
530
+ vec = Vector(direction, color=color)
531
+ label = MathTex(label_text, color=color, font_size=30)
532
+ label.next_to(vec.get_end(), normalize(direction), buff=0.1)
533
+ return VGroup(vec, label)
534
+
535
+ def get_matrix_mob(entries, bracket_color=WHITE):
536
+ """Create a styled matrix mobject."""
537
+ m = Matrix(entries)
538
+ m.get_brackets().set_color(bracket_color)
539
+ return m
540
+ ```
541
+
542
+ ## Best Practices Summary
543
+
544
+ 1. **One Scene class per conceptual section** -- 10-40 scenes per video
545
+ 2. **Comment every section** inside `construct()` with `# Description`
546
+ 3. **Mystery first** -- open with the surprising result
547
+ 4. **Progressive complexity** -- simple to complex, concrete to abstract
548
+ 5. **Generous pauses** -- `self.wait(2)` after key reveals
549
+ 6. **Rearrange, don't cut** -- move existing elements rather than fade-out/fade-in when possible
550
+ 7. **Extract helpers** -- `get_*` functions for reusable mobject creation
551
+ 8. **Class attributes** for configuration, not `CONFIG` dicts
552
+ 9. **End with a question** -- each section should leave the viewer wanting the next one