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,369 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Updater and ValueTracker Patterns for Manim Community
|
|
3
|
+
|
|
4
|
+
Demonstrates dynamic animations using updaters and ValueTracker.
|
|
5
|
+
Adapted from 3b1b's animation patterns for ManimCE.
|
|
6
|
+
|
|
7
|
+
Run with: manim -pql updater_patterns.py SceneName
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from manim import *
|
|
11
|
+
import numpy as np
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BasicUpdater(Scene):
|
|
15
|
+
"""Simple updater that makes an object follow another."""
|
|
16
|
+
|
|
17
|
+
def construct(self):
|
|
18
|
+
# Leader dot
|
|
19
|
+
leader = Dot(color=RED, radius=0.2)
|
|
20
|
+
leader_label = Text("Leader", font_size=24).next_to(leader, UP)
|
|
21
|
+
|
|
22
|
+
# Follower that always stays next to leader
|
|
23
|
+
follower = Dot(color=BLUE, radius=0.15)
|
|
24
|
+
follower.add_updater(lambda m: m.next_to(leader, RIGHT, buff=0.5))
|
|
25
|
+
|
|
26
|
+
follower_label = Text("Follower", font_size=24, color=BLUE)
|
|
27
|
+
follower_label.add_updater(lambda m: m.next_to(follower, DOWN))
|
|
28
|
+
|
|
29
|
+
self.add(leader, leader_label, follower, follower_label)
|
|
30
|
+
|
|
31
|
+
# Move the leader - follower automatically follows
|
|
32
|
+
self.play(leader.animate.shift(RIGHT * 3), run_time=2)
|
|
33
|
+
self.play(leader.animate.shift(UP * 2), run_time=2)
|
|
34
|
+
self.play(leader.animate.shift(LEFT * 4 + DOWN), run_time=2)
|
|
35
|
+
self.wait()
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class ValueTrackerBasics(Scene):
|
|
39
|
+
"""Demonstrates ValueTracker for animating numeric values."""
|
|
40
|
+
|
|
41
|
+
def construct(self):
|
|
42
|
+
# Create a ValueTracker
|
|
43
|
+
tracker = ValueTracker(0)
|
|
44
|
+
|
|
45
|
+
# DecimalNumber that displays the tracker value
|
|
46
|
+
number = DecimalNumber(
|
|
47
|
+
0,
|
|
48
|
+
num_decimal_places=2,
|
|
49
|
+
font_size=72,
|
|
50
|
+
include_sign=True
|
|
51
|
+
)
|
|
52
|
+
number.add_updater(lambda m: m.set_value(tracker.get_value()))
|
|
53
|
+
|
|
54
|
+
# Label
|
|
55
|
+
label = Text("Value: ", font_size=48)
|
|
56
|
+
label.next_to(number, LEFT)
|
|
57
|
+
|
|
58
|
+
self.add(label, number)
|
|
59
|
+
|
|
60
|
+
# Animate the tracker
|
|
61
|
+
self.play(tracker.animate.set_value(10), run_time=2)
|
|
62
|
+
self.wait(0.5)
|
|
63
|
+
self.play(tracker.animate.set_value(-5), run_time=2)
|
|
64
|
+
self.wait(0.5)
|
|
65
|
+
self.play(tracker.animate.set_value(0), run_time=1)
|
|
66
|
+
self.wait()
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class CircleRadiusTracker(Scene):
|
|
70
|
+
"""Circle that grows/shrinks with a ValueTracker."""
|
|
71
|
+
|
|
72
|
+
def construct(self):
|
|
73
|
+
tracker = ValueTracker(1)
|
|
74
|
+
|
|
75
|
+
# Circle with radius controlled by tracker
|
|
76
|
+
circle = always_redraw(
|
|
77
|
+
lambda: Circle(
|
|
78
|
+
radius=tracker.get_value(),
|
|
79
|
+
color=BLUE,
|
|
80
|
+
fill_opacity=0.3
|
|
81
|
+
)
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# Radius label
|
|
85
|
+
radius_text = always_redraw(
|
|
86
|
+
lambda: MathTex(
|
|
87
|
+
f"r = {tracker.get_value():.2f}"
|
|
88
|
+
).to_edge(UP)
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
self.add(circle, radius_text)
|
|
92
|
+
|
|
93
|
+
# Animate radius changes
|
|
94
|
+
self.play(tracker.animate.set_value(2.5), run_time=2)
|
|
95
|
+
self.play(tracker.animate.set_value(0.5), run_time=2)
|
|
96
|
+
self.play(tracker.animate.set_value(1.5), run_time=1)
|
|
97
|
+
self.wait()
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class RotatingUpdater(Scene):
|
|
101
|
+
"""Object that rotates continuously using dt (delta time)."""
|
|
102
|
+
|
|
103
|
+
def construct(self):
|
|
104
|
+
# Create rotating group
|
|
105
|
+
square = Square(side_length=2, color=BLUE, fill_opacity=0.5)
|
|
106
|
+
dot = Dot(color=RED).move_to(square.get_corner(UR))
|
|
107
|
+
|
|
108
|
+
group = VGroup(square, dot)
|
|
109
|
+
|
|
110
|
+
# Add rotation updater with dt for smooth rotation
|
|
111
|
+
group.add_updater(lambda m, dt: m.rotate(dt * PI / 2))
|
|
112
|
+
|
|
113
|
+
self.add(group)
|
|
114
|
+
self.wait(4) # Watch it rotate
|
|
115
|
+
|
|
116
|
+
# Remove updater
|
|
117
|
+
group.clear_updaters()
|
|
118
|
+
self.wait()
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class TracedPathExample(Scene):
|
|
122
|
+
"""Demonstrates TracedPath for drawing motion trails."""
|
|
123
|
+
|
|
124
|
+
def construct(self):
|
|
125
|
+
# Moving dot
|
|
126
|
+
dot = Dot(color=RED, radius=0.15)
|
|
127
|
+
dot.move_to(LEFT * 3)
|
|
128
|
+
|
|
129
|
+
# Traced path follows the dot
|
|
130
|
+
traced_path = TracedPath(
|
|
131
|
+
dot.get_center,
|
|
132
|
+
stroke_color=YELLOW,
|
|
133
|
+
stroke_width=3
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
self.add(traced_path, dot)
|
|
137
|
+
|
|
138
|
+
# Move dot in a pattern
|
|
139
|
+
self.play(
|
|
140
|
+
dot.animate.shift(RIGHT * 3 + UP * 2),
|
|
141
|
+
run_time=1.5
|
|
142
|
+
)
|
|
143
|
+
self.play(
|
|
144
|
+
dot.animate.shift(RIGHT * 2 + DOWN * 3),
|
|
145
|
+
run_time=1.5
|
|
146
|
+
)
|
|
147
|
+
self.play(
|
|
148
|
+
dot.animate.shift(LEFT * 2 + UP * 1),
|
|
149
|
+
run_time=1.5
|
|
150
|
+
)
|
|
151
|
+
self.wait()
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class SineWaveTracker(Scene):
|
|
155
|
+
"""Animated sine wave using ValueTracker."""
|
|
156
|
+
|
|
157
|
+
def construct(self):
|
|
158
|
+
# Phase tracker
|
|
159
|
+
phase = ValueTracker(0)
|
|
160
|
+
|
|
161
|
+
# Axes
|
|
162
|
+
axes = Axes(
|
|
163
|
+
x_range=[0, 2 * PI, PI / 2],
|
|
164
|
+
y_range=[-1.5, 1.5, 0.5],
|
|
165
|
+
x_length=10,
|
|
166
|
+
y_length=4,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
# Sine wave that updates with phase
|
|
170
|
+
sine_wave = always_redraw(
|
|
171
|
+
lambda: axes.plot(
|
|
172
|
+
lambda x: np.sin(x + phase.get_value()),
|
|
173
|
+
color=BLUE,
|
|
174
|
+
x_range=[0, 2 * PI]
|
|
175
|
+
)
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
# Dot that follows the wave
|
|
179
|
+
dot = always_redraw(
|
|
180
|
+
lambda: Dot(color=RED).move_to(
|
|
181
|
+
axes.c2p(PI, np.sin(PI + phase.get_value()))
|
|
182
|
+
)
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
self.add(axes, sine_wave, dot)
|
|
186
|
+
|
|
187
|
+
# Animate phase change (wave shifts)
|
|
188
|
+
self.play(
|
|
189
|
+
phase.animate.set_value(2 * PI),
|
|
190
|
+
run_time=4,
|
|
191
|
+
rate_func=linear
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
class ArrowUpdater(Scene):
|
|
196
|
+
"""Arrow that always points from one object to another."""
|
|
197
|
+
|
|
198
|
+
def construct(self):
|
|
199
|
+
# Two dots
|
|
200
|
+
dot1 = Dot(color=BLUE, radius=0.2).shift(LEFT * 2)
|
|
201
|
+
dot2 = Dot(color=RED, radius=0.2).shift(RIGHT * 2)
|
|
202
|
+
|
|
203
|
+
# Arrow that always connects them
|
|
204
|
+
arrow = always_redraw(
|
|
205
|
+
lambda: Arrow(
|
|
206
|
+
dot1.get_center(),
|
|
207
|
+
dot2.get_center(),
|
|
208
|
+
buff=0.3,
|
|
209
|
+
color=YELLOW
|
|
210
|
+
)
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
# Distance label
|
|
214
|
+
distance = always_redraw(
|
|
215
|
+
lambda: DecimalNumber(
|
|
216
|
+
np.linalg.norm(dot2.get_center() - dot1.get_center()),
|
|
217
|
+
num_decimal_places=2,
|
|
218
|
+
font_size=36
|
|
219
|
+
).next_to(arrow, UP)
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
self.add(dot1, dot2, arrow, distance)
|
|
223
|
+
|
|
224
|
+
# Move dots around
|
|
225
|
+
self.play(dot1.animate.shift(UP * 2), run_time=1.5)
|
|
226
|
+
self.play(dot2.animate.shift(DOWN + LEFT * 2), run_time=1.5)
|
|
227
|
+
self.play(
|
|
228
|
+
dot1.animate.shift(RIGHT * 3),
|
|
229
|
+
dot2.animate.shift(UP * 2),
|
|
230
|
+
run_time=2
|
|
231
|
+
)
|
|
232
|
+
self.wait()
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class ParametricCurveTracer(Scene):
|
|
236
|
+
"""Traces a parametric curve using ValueTracker."""
|
|
237
|
+
|
|
238
|
+
def construct(self):
|
|
239
|
+
# Parameter t
|
|
240
|
+
t_tracker = ValueTracker(0)
|
|
241
|
+
|
|
242
|
+
# Parametric curve (Lissajous)
|
|
243
|
+
def parametric_func(t):
|
|
244
|
+
return np.array([
|
|
245
|
+
2 * np.sin(2 * t),
|
|
246
|
+
2 * np.sin(3 * t),
|
|
247
|
+
0
|
|
248
|
+
])
|
|
249
|
+
|
|
250
|
+
# Dot at current position
|
|
251
|
+
dot = always_redraw(
|
|
252
|
+
lambda: Dot(color=RED, radius=0.15).move_to(
|
|
253
|
+
parametric_func(t_tracker.get_value())
|
|
254
|
+
)
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
# Traced path
|
|
258
|
+
path = TracedPath(
|
|
259
|
+
dot.get_center,
|
|
260
|
+
stroke_color=BLUE,
|
|
261
|
+
stroke_width=2
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
self.add(path, dot)
|
|
265
|
+
|
|
266
|
+
# Trace the curve
|
|
267
|
+
self.play(
|
|
268
|
+
t_tracker.animate.set_value(2 * PI),
|
|
269
|
+
run_time=6,
|
|
270
|
+
rate_func=linear
|
|
271
|
+
)
|
|
272
|
+
self.wait()
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
class MultipleTrackers(Scene):
|
|
276
|
+
"""Using multiple ValueTrackers together."""
|
|
277
|
+
|
|
278
|
+
def construct(self):
|
|
279
|
+
# Separate trackers for x and y
|
|
280
|
+
x_tracker = ValueTracker(0)
|
|
281
|
+
y_tracker = ValueTracker(0)
|
|
282
|
+
|
|
283
|
+
# Dot controlled by both trackers
|
|
284
|
+
dot = always_redraw(
|
|
285
|
+
lambda: Dot(color=RED, radius=0.2).move_to(
|
|
286
|
+
RIGHT * x_tracker.get_value() + UP * y_tracker.get_value()
|
|
287
|
+
)
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
# Coordinate display
|
|
291
|
+
coords = always_redraw(
|
|
292
|
+
lambda: MathTex(
|
|
293
|
+
f"({x_tracker.get_value():.1f}, {y_tracker.get_value():.1f})"
|
|
294
|
+
).to_corner(UL)
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
self.add(dot, coords)
|
|
298
|
+
|
|
299
|
+
# Animate both trackers
|
|
300
|
+
self.play(x_tracker.animate.set_value(3), run_time=1.5)
|
|
301
|
+
self.play(y_tracker.animate.set_value(2), run_time=1.5)
|
|
302
|
+
self.play(
|
|
303
|
+
x_tracker.animate.set_value(-2),
|
|
304
|
+
y_tracker.animate.set_value(-1),
|
|
305
|
+
run_time=2
|
|
306
|
+
)
|
|
307
|
+
self.wait()
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
class SpringMassSimulation(Scene):
|
|
311
|
+
"""Simple physics simulation with updaters."""
|
|
312
|
+
|
|
313
|
+
def construct(self):
|
|
314
|
+
# Physics parameters
|
|
315
|
+
k = 10 # Spring constant
|
|
316
|
+
mass = 1
|
|
317
|
+
damping = 0.5
|
|
318
|
+
|
|
319
|
+
# State trackers
|
|
320
|
+
position = ValueTracker(2) # Initial displacement
|
|
321
|
+
velocity = ValueTracker(0)
|
|
322
|
+
|
|
323
|
+
# Ground line
|
|
324
|
+
ground = Line(LEFT * 4, RIGHT * 4, color=WHITE).shift(DOWN * 2)
|
|
325
|
+
|
|
326
|
+
# Mass (square)
|
|
327
|
+
mass_obj = always_redraw(
|
|
328
|
+
lambda: Square(
|
|
329
|
+
side_length=0.8,
|
|
330
|
+
color=BLUE,
|
|
331
|
+
fill_opacity=0.8
|
|
332
|
+
).move_to(UP * position.get_value())
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
# Spring (simplified as line)
|
|
336
|
+
spring = always_redraw(
|
|
337
|
+
lambda: Line(
|
|
338
|
+
ground.get_center() + UP * 0.1,
|
|
339
|
+
mass_obj.get_bottom(),
|
|
340
|
+
color=GREY
|
|
341
|
+
)
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
self.add(ground, spring, mass_obj)
|
|
345
|
+
|
|
346
|
+
# Physics update function
|
|
347
|
+
def physics_update(mob, dt):
|
|
348
|
+
x = position.get_value()
|
|
349
|
+
v = velocity.get_value()
|
|
350
|
+
|
|
351
|
+
# F = -kx - damping*v
|
|
352
|
+
acceleration = (-k * x - damping * v) / mass
|
|
353
|
+
new_v = v + acceleration * dt
|
|
354
|
+
new_x = x + new_v * dt
|
|
355
|
+
|
|
356
|
+
velocity.set_value(new_v)
|
|
357
|
+
position.set_value(new_x)
|
|
358
|
+
|
|
359
|
+
# Add physics updater to a dummy mobject
|
|
360
|
+
physics_driver = Mobject()
|
|
361
|
+
physics_driver.add_updater(physics_update)
|
|
362
|
+
self.add(physics_driver)
|
|
363
|
+
|
|
364
|
+
# Let it run
|
|
365
|
+
self.wait(5)
|
|
366
|
+
|
|
367
|
+
# Clean up
|
|
368
|
+
physics_driver.clear_updaters()
|
|
369
|
+
self.wait()
|