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,444 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: color-conventions
|
|
3
|
+
description: The comprehensive 3Blue1Brown color system for mathematical visualization in ManimCE
|
|
4
|
+
metadata:
|
|
5
|
+
tags: colors, color-system, 3b1b, conventions, heatmap, gradient, backstroke, value-to-color
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# 3Blue1Brown Color Conventions
|
|
9
|
+
|
|
10
|
+
The 3b1b videos use a remarkably consistent color system across all 407+ files. Colors carry semantic meaning -- they tell the viewer what role each element plays.
|
|
11
|
+
|
|
12
|
+
## Domain Color Conventions
|
|
13
|
+
|
|
14
|
+
### Linear Algebra (from `_2016/eola/`)
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
from manim import *
|
|
18
|
+
|
|
19
|
+
# Basis vectors -- THE most iconic 3b1b color choice
|
|
20
|
+
X_COLOR = GREEN # i-hat, x-component, first basis vector
|
|
21
|
+
Y_COLOR = RED # j-hat, y-component, second basis vector
|
|
22
|
+
Z_COLOR = BLUE # k-hat, z-component, third basis vector
|
|
23
|
+
|
|
24
|
+
# These are used in EVERY EoLA chapter
|
|
25
|
+
i_hat = Vector([1, 0], color=X_COLOR)
|
|
26
|
+
j_hat = Vector([0, 1], color=Y_COLOR)
|
|
27
|
+
|
|
28
|
+
# Eigenvalues
|
|
29
|
+
EIGEN_COLOR_1 = TEAL # First eigenvalue/eigenvector
|
|
30
|
+
EIGEN_COLOR_2 = YELLOW # Second eigenvalue/eigenvector
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Calculus / Differential Equations (from `_2017/`, `_2019/diffyq/`)
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
# Physical quantities
|
|
37
|
+
DISTANCE_COLOR = BLUE
|
|
38
|
+
TIME_COLOR = YELLOW
|
|
39
|
+
VELOCITY_COLOR = GREEN
|
|
40
|
+
ACCELERATION_COLOR = RED
|
|
41
|
+
|
|
42
|
+
# Derivative visualization
|
|
43
|
+
FUNCTION_COLOR = YELLOW # f(x)
|
|
44
|
+
DERIVATIVE_COLOR = GREEN # f'(x)
|
|
45
|
+
TANGENT_COLOR = BLUE # tangent line
|
|
46
|
+
|
|
47
|
+
# Area under curve
|
|
48
|
+
AREA_COLOR = BLUE_D # Riemann rectangles (with gradient to GREEN)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Optics / Waves (from `_2023/optics_puzzles/`)
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
# Wave colors
|
|
55
|
+
WAVE_COLOR = YELLOW # Default wave
|
|
56
|
+
MEDIUM_COLOR = BLUE # Glass/water medium
|
|
57
|
+
MEDIUM_OPACITY = 0.35 # Standard medium opacity
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Physics / Differential Equations (from `_2019/diffyq/`)
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
# Phase space
|
|
64
|
+
THETA_COLOR = WHITE # angle variable
|
|
65
|
+
OMEGA_COLOR = RED # angular velocity (also used for velocity vectors)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Probability / Statistics (from `_2023/clt/`, `_2019/bayes/`)
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
# Distribution colors
|
|
72
|
+
BAR_COLORS = (BLUE_D, GREEN_D) # Gradient for bar charts
|
|
73
|
+
BAR_COLORS_ALT = (BLUE, TEAL) # Alternative gradient
|
|
74
|
+
SAMPLE_COLOR = YELLOW # Sample markers / indicators
|
|
75
|
+
GAUSSIAN_COLOR = YELLOW # Normal curve overlay
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### SIR Epidemic Model (from `_2020/sir.py`)
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
# Epidemic states -- standard epidemiology convention
|
|
82
|
+
SIR_COLORS = {
|
|
83
|
+
"S": BLUE, # Susceptible
|
|
84
|
+
"I": RED, # Infected
|
|
85
|
+
"R": GREY_D, # Recovered
|
|
86
|
+
}
|
|
87
|
+
ASYMPTOMATIC_COLOR = YELLOW
|
|
88
|
+
SOCIAL_DISTANCE_COLOR = YELLOW
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Transformers / Neural Networks (from `_2024/transformers/`)
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
# Attention and embedding colors
|
|
95
|
+
S_COLOR = YELLOW # Used for variable 's' in Laplace/zeta
|
|
96
|
+
T_COLOR = BLUE # Used for time variable 't'
|
|
97
|
+
|
|
98
|
+
# Matrix heatmap colors
|
|
99
|
+
POSITIVE_LOW = BLUE_E # Low positive values
|
|
100
|
+
POSITIVE_HIGH = BLUE_B # High positive values
|
|
101
|
+
NEGATIVE_LOW = RED_E # Low negative values (near zero)
|
|
102
|
+
NEGATIVE_HIGH = RED_B # High negative values
|
|
103
|
+
|
|
104
|
+
# Pi creature conventional coloring
|
|
105
|
+
PI_CREATURE_COLOR = BLUE # Randolph (default pi creature)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Complex Analysis (from `_2025/laplace/`, `_2025/zeta/`)
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
S_COLOR = YELLOW # Complex variable s
|
|
112
|
+
T_COLOR = BLUE # Time variable t
|
|
113
|
+
PI_COLOR = RED # Used for pi in e^(i*pi)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## The value_to_color() Pattern
|
|
117
|
+
|
|
118
|
+
From `_2024/transformers/helpers.py` -- the key function for matrix heatmaps and data visualization.
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from manim import *
|
|
122
|
+
|
|
123
|
+
def value_to_color(
|
|
124
|
+
value,
|
|
125
|
+
low_positive_color=BLUE_E,
|
|
126
|
+
high_positive_color=BLUE_B,
|
|
127
|
+
low_negative_color=RED_E,
|
|
128
|
+
high_negative_color=RED_B,
|
|
129
|
+
min_value=0.0,
|
|
130
|
+
max_value=10.0,
|
|
131
|
+
):
|
|
132
|
+
"""Map a numerical value to a color using HSL interpolation.
|
|
133
|
+
|
|
134
|
+
Positive values: blue gradient (BLUE_E to BLUE_B)
|
|
135
|
+
Negative values: red gradient (RED_E to RED_B)
|
|
136
|
+
"""
|
|
137
|
+
alpha = min(max(abs(value) / max_value, 0), 1)
|
|
138
|
+
if value >= 0:
|
|
139
|
+
return interpolate_color(low_positive_color, high_positive_color, alpha)
|
|
140
|
+
else:
|
|
141
|
+
return interpolate_color(low_negative_color, high_negative_color, alpha)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class MatrixHeatmap(Scene):
|
|
145
|
+
"""Visualize a matrix with value_to_color encoding."""
|
|
146
|
+
|
|
147
|
+
def construct(self):
|
|
148
|
+
n_rows, n_cols = 5, 5
|
|
149
|
+
values = np.random.randn(n_rows, n_cols) * 3
|
|
150
|
+
|
|
151
|
+
cells = VGroup()
|
|
152
|
+
cell_size = 0.7
|
|
153
|
+
for i in range(n_rows):
|
|
154
|
+
for j in range(n_cols):
|
|
155
|
+
cell = Square(side_length=cell_size)
|
|
156
|
+
color = value_to_color(values[i, j], max_value=5)
|
|
157
|
+
cell.set_fill(color, opacity=0.9)
|
|
158
|
+
cell.set_stroke(WHITE, 0.5)
|
|
159
|
+
cell.move_to(np.array([
|
|
160
|
+
j * cell_size - (n_cols - 1) * cell_size / 2,
|
|
161
|
+
-i * cell_size + (n_rows - 1) * cell_size / 2,
|
|
162
|
+
0
|
|
163
|
+
]))
|
|
164
|
+
cells.add(cell)
|
|
165
|
+
|
|
166
|
+
self.play(FadeIn(cells, lag_ratio=0.01), run_time=2)
|
|
167
|
+
self.wait(2)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Temperature-to-Color (Heat Equation)
|
|
171
|
+
|
|
172
|
+
For heat equation and thermal simulations, map temperature to a blue-red gradient.
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
def temperature_to_color(temp, t_min=-1, t_max=1):
|
|
176
|
+
"""Map temperature to a blue (cold) to red (hot) gradient."""
|
|
177
|
+
alpha = (temp - t_min) / (t_max - t_min)
|
|
178
|
+
alpha = max(0, min(1, alpha)) # Clamp
|
|
179
|
+
|
|
180
|
+
if alpha < 0.5:
|
|
181
|
+
return interpolate_color(BLUE, WHITE, 2 * alpha)
|
|
182
|
+
else:
|
|
183
|
+
return interpolate_color(WHITE, RED, 2 * (alpha - 0.5))
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class HeatEquationViz(Scene):
|
|
187
|
+
"""Heat distribution visualization."""
|
|
188
|
+
|
|
189
|
+
def construct(self):
|
|
190
|
+
n_bars = 50
|
|
191
|
+
bars = VGroup()
|
|
192
|
+
temps = np.sin(np.linspace(0, 2 * PI, n_bars))
|
|
193
|
+
|
|
194
|
+
for i, t in enumerate(temps):
|
|
195
|
+
bar = Rectangle(
|
|
196
|
+
width=FRAME_WIDTH / n_bars,
|
|
197
|
+
height=3,
|
|
198
|
+
fill_opacity=1,
|
|
199
|
+
stroke_width=0,
|
|
200
|
+
)
|
|
201
|
+
bar.set_fill(temperature_to_color(t))
|
|
202
|
+
bar.move_to([(i - n_bars / 2) * FRAME_WIDTH / n_bars, 0, 0])
|
|
203
|
+
bars.add(bar)
|
|
204
|
+
|
|
205
|
+
self.play(FadeIn(bars, lag_ratio=0.01))
|
|
206
|
+
self.wait(2)
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## HSL Interpolation for Smooth Gradients
|
|
210
|
+
|
|
211
|
+
ManimCE's `interpolate_color` works in RGB space. For smoother gradients (especially around the color wheel), HSL interpolation is preferred. 3b1b's ManimGL has `interpolate_color_by_hsl`.
|
|
212
|
+
|
|
213
|
+
```python
|
|
214
|
+
import colorsys
|
|
215
|
+
|
|
216
|
+
def interpolate_color_hsl(color1, color2, alpha):
|
|
217
|
+
"""Interpolate between two colors in HSL space for smoother results."""
|
|
218
|
+
rgb1 = color_to_rgb(color1)
|
|
219
|
+
rgb2 = color_to_rgb(color2)
|
|
220
|
+
|
|
221
|
+
h1, l1, s1 = colorsys.rgb_to_hls(*rgb1)
|
|
222
|
+
h2, l2, s2 = colorsys.rgb_to_hls(*rgb2)
|
|
223
|
+
|
|
224
|
+
# Handle hue wraparound
|
|
225
|
+
if abs(h2 - h1) > 0.5:
|
|
226
|
+
if h1 < h2:
|
|
227
|
+
h1 += 1
|
|
228
|
+
else:
|
|
229
|
+
h2 += 1
|
|
230
|
+
|
|
231
|
+
h = (1 - alpha) * h1 + alpha * h2
|
|
232
|
+
l = (1 - alpha) * l1 + alpha * l2
|
|
233
|
+
s = (1 - alpha) * s1 + alpha * s2
|
|
234
|
+
|
|
235
|
+
h = h % 1.0
|
|
236
|
+
r, g, b = colorsys.hls_to_rgb(h, l, s)
|
|
237
|
+
return rgb_to_color([r, g, b])
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
class HSLGradient(Scene):
|
|
241
|
+
"""Smooth HSL gradient compared to RGB."""
|
|
242
|
+
|
|
243
|
+
def construct(self):
|
|
244
|
+
n = 50
|
|
245
|
+
# RGB interpolation (can look muddy)
|
|
246
|
+
rgb_bars = VGroup()
|
|
247
|
+
for i in range(n):
|
|
248
|
+
alpha = i / (n - 1)
|
|
249
|
+
bar = Rectangle(width=FRAME_WIDTH / n, height=1)
|
|
250
|
+
bar.set_fill(interpolate_color(RED, BLUE, alpha), opacity=1)
|
|
251
|
+
bar.set_stroke(width=0)
|
|
252
|
+
bar.move_to([(i - n / 2) * FRAME_WIDTH / n, 1, 0])
|
|
253
|
+
rgb_bars.add(bar)
|
|
254
|
+
|
|
255
|
+
# HSL interpolation (stays vivid)
|
|
256
|
+
hsl_bars = VGroup()
|
|
257
|
+
for i in range(n):
|
|
258
|
+
alpha = i / (n - 1)
|
|
259
|
+
bar = Rectangle(width=FRAME_WIDTH / n, height=1)
|
|
260
|
+
bar.set_fill(interpolate_color_hsl(RED, BLUE, alpha), opacity=1)
|
|
261
|
+
bar.set_stroke(width=0)
|
|
262
|
+
bar.move_to([(i - n / 2) * FRAME_WIDTH / n, -1, 0])
|
|
263
|
+
hsl_bars.add(bar)
|
|
264
|
+
|
|
265
|
+
rgb_label = Text("RGB interpolation", font_size=24).next_to(rgb_bars, LEFT)
|
|
266
|
+
hsl_label = Text("HSL interpolation", font_size=24).next_to(hsl_bars, LEFT)
|
|
267
|
+
|
|
268
|
+
self.add(rgb_bars, hsl_bars, rgb_label, hsl_label)
|
|
269
|
+
self.wait(2)
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## set_backstroke() for Readability
|
|
273
|
+
|
|
274
|
+
3b1b frequently uses `set_backstroke()` to add a dark outline behind text/equations that overlap with colorful backgrounds. In ManimCE, this needs a manual approach since `set_backstroke` is a ManimGL feature.
|
|
275
|
+
|
|
276
|
+
```python
|
|
277
|
+
def set_backstroke(mob, color=BLACK, width=5):
|
|
278
|
+
"""ManimCE equivalent of ManimGL's set_backstroke.
|
|
279
|
+
Adds a background stroke for readability over colored backgrounds."""
|
|
280
|
+
mob.set_stroke(color, width, background=True)
|
|
281
|
+
return mob
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
class BackstrokeDemo(Scene):
|
|
285
|
+
"""Text readability over colored backgrounds."""
|
|
286
|
+
|
|
287
|
+
def construct(self):
|
|
288
|
+
# Colorful background
|
|
289
|
+
gradient_rect = Rectangle(
|
|
290
|
+
width=FRAME_WIDTH, height=FRAME_HEIGHT,
|
|
291
|
+
fill_opacity=1,
|
|
292
|
+
)
|
|
293
|
+
gradient_rect.set_color_by_gradient(BLUE, GREEN, YELLOW)
|
|
294
|
+
self.add(gradient_rect)
|
|
295
|
+
|
|
296
|
+
# Text without backstroke (hard to read)
|
|
297
|
+
text_bad = MathTex(r"e^{i\pi} + 1 = 0", font_size=60)
|
|
298
|
+
text_bad.shift(UP)
|
|
299
|
+
|
|
300
|
+
# Text with backstroke (readable)
|
|
301
|
+
text_good = MathTex(r"e^{i\pi} + 1 = 0", font_size=60)
|
|
302
|
+
text_good.shift(DOWN)
|
|
303
|
+
set_backstroke(text_good, BLACK, 8)
|
|
304
|
+
|
|
305
|
+
label_bad = Text("Without backstroke", font_size=20).next_to(text_bad, UP)
|
|
306
|
+
label_good = Text("With backstroke", font_size=20).next_to(text_good, UP)
|
|
307
|
+
set_backstroke(label_bad, BLACK, 5)
|
|
308
|
+
set_backstroke(label_good, BLACK, 5)
|
|
309
|
+
|
|
310
|
+
self.add(text_bad, text_good, label_bad, label_good)
|
|
311
|
+
self.wait(2)
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Color-Coded Equation Pattern (tex_to_color_map / t2c)
|
|
315
|
+
|
|
316
|
+
The most pervasive pattern in all 3b1b code: color individual LaTeX symbols by their semantic role.
|
|
317
|
+
|
|
318
|
+
```python
|
|
319
|
+
class ColorCodedEquation(Scene):
|
|
320
|
+
"""Using tex_to_color_map for semantic coloring."""
|
|
321
|
+
|
|
322
|
+
def construct(self):
|
|
323
|
+
# Linear algebra style
|
|
324
|
+
eigen_eq = MathTex(
|
|
325
|
+
r"A \vec{v} = \lambda \vec{v}",
|
|
326
|
+
tex_to_color_map={
|
|
327
|
+
r"\vec{v}": YELLOW,
|
|
328
|
+
r"\lambda": TEAL,
|
|
329
|
+
},
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
# Calculus style
|
|
333
|
+
deriv_eq = MathTex(
|
|
334
|
+
r"\frac{d}{dt} f(t) = \lim_{\Delta t \to 0}"
|
|
335
|
+
r"\frac{f(t + \Delta t) - f(t)}{\Delta t}",
|
|
336
|
+
tex_to_color_map={
|
|
337
|
+
r"t": BLUE,
|
|
338
|
+
r"\Delta t": GREEN,
|
|
339
|
+
},
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
# Complex analysis style
|
|
343
|
+
euler = MathTex(
|
|
344
|
+
r"e^{i \theta} = \cos(\theta) + i \sin(\theta)",
|
|
345
|
+
tex_to_color_map={
|
|
346
|
+
r"\theta": YELLOW,
|
|
347
|
+
r"i": BLUE,
|
|
348
|
+
},
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
equations = VGroup(eigen_eq, deriv_eq, euler)
|
|
352
|
+
equations.arrange(DOWN, buff=0.8)
|
|
353
|
+
|
|
354
|
+
for eq in equations:
|
|
355
|
+
self.play(Write(eq), run_time=1.5)
|
|
356
|
+
self.wait(0.5)
|
|
357
|
+
|
|
358
|
+
self.wait(2)
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
## Submobject Color Gradients
|
|
362
|
+
|
|
363
|
+
3b1b frequently colors groups of submobjects with a gradient using `set_submobject_colors_by_gradient` or `set_color_by_gradient`:
|
|
364
|
+
|
|
365
|
+
```python
|
|
366
|
+
class GradientPatterns(Scene):
|
|
367
|
+
"""Color gradient patterns from the codebase."""
|
|
368
|
+
|
|
369
|
+
def construct(self):
|
|
370
|
+
# Bars with gradient
|
|
371
|
+
bars = VGroup(*[
|
|
372
|
+
Rectangle(width=0.5, height=h, fill_opacity=0.8, stroke_width=1)
|
|
373
|
+
for h in np.random.uniform(0.5, 3, 10)
|
|
374
|
+
])
|
|
375
|
+
bars.arrange(RIGHT, buff=0.1, aligned_edge=DOWN)
|
|
376
|
+
bars.set_color_by_gradient(BLUE_D, GREEN_D) # Standard 3b1b bar colors
|
|
377
|
+
|
|
378
|
+
# Dots along a path with gradient
|
|
379
|
+
dots = VGroup(*[
|
|
380
|
+
Dot(radius=0.08)
|
|
381
|
+
for _ in range(20)
|
|
382
|
+
])
|
|
383
|
+
dots.arrange_in_grid(rows=1, buff=0.3)
|
|
384
|
+
dots.set_color_by_gradient(RED, YELLOW, GREEN, BLUE)
|
|
385
|
+
|
|
386
|
+
group = VGroup(bars, dots).arrange(DOWN, buff=1)
|
|
387
|
+
self.add(group)
|
|
388
|
+
self.wait(2)
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
## Opacity Conventions
|
|
392
|
+
|
|
393
|
+
```python
|
|
394
|
+
# Background planes/grids
|
|
395
|
+
BACKGROUND_OPACITY = 0.3 # NumberPlane typically at 30-40% opacity
|
|
396
|
+
|
|
397
|
+
# Faded elements (de-emphasized)
|
|
398
|
+
FADED_OPACITY = 0.25 # Elements pushed to background
|
|
399
|
+
|
|
400
|
+
# Fill opacity for shapes
|
|
401
|
+
SHAPE_FILL_OPACITY = 0.5 # Standard fill for rectangles, polygons
|
|
402
|
+
|
|
403
|
+
# Medium (glass, water) opacity
|
|
404
|
+
MEDIUM_OPACITY = 0.35 # From optics videos
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
## Complete Color Reference Table
|
|
408
|
+
|
|
409
|
+
| Domain | Element | Color | Source |
|
|
410
|
+
|--------|---------|-------|--------|
|
|
411
|
+
| Linear Algebra | i-hat / x-axis | `GREEN` | `_2016/eola/` |
|
|
412
|
+
| Linear Algebra | j-hat / y-axis | `RED` | `_2016/eola/` |
|
|
413
|
+
| Linear Algebra | k-hat / z-axis | `BLUE` | `_2016/eola/` |
|
|
414
|
+
| Linear Algebra | Eigenvalue 1 | `TEAL` | `_2024/linalg/` |
|
|
415
|
+
| Linear Algebra | Eigenvalue 2 | `YELLOW` | `_2024/linalg/` |
|
|
416
|
+
| Calculus | Function graph | `YELLOW` | `_2017/` |
|
|
417
|
+
| Calculus | Derivative | `GREEN` | `_2017/` |
|
|
418
|
+
| Calculus | Area / integral | `BLUE_D` to `GREEN` | `_2017/` |
|
|
419
|
+
| Physics | Time variable | `BLUE` / `YELLOW` | `_2019/diffyq/` |
|
|
420
|
+
| Physics | Velocity | `RED` | `_2019/diffyq/` |
|
|
421
|
+
| Probability | Bar chart | `BLUE_D` to `GREEN_D` | `_2023/clt/` |
|
|
422
|
+
| Probability | Samples | `YELLOW` | `_2023/clt/` |
|
|
423
|
+
| Probability | Gaussian curve | `YELLOW` | `_2023/clt/` |
|
|
424
|
+
| SIR | Susceptible | `BLUE` | `_2020/sir.py` |
|
|
425
|
+
| SIR | Infected | `RED` | `_2020/sir.py` |
|
|
426
|
+
| SIR | Recovered | `GREY_D` | `_2020/sir.py` |
|
|
427
|
+
| Complex | Variable s | `YELLOW` | `_2025/` |
|
|
428
|
+
| Complex | Pi | `RED` | `_2025/laplace/` |
|
|
429
|
+
| Neural Networks | Positive weights | `BLUE_E` to `BLUE_B` | `_2024/transformers/` |
|
|
430
|
+
| Neural Networks | Negative weights | `RED_E` to `RED_B` | `_2024/transformers/` |
|
|
431
|
+
| General | Highlighted text | `YELLOW` | everywhere |
|
|
432
|
+
| General | Author name | `YELLOW` | `custom/opening_quote.py` |
|
|
433
|
+
| General | Background | `BLACK` (default) | everywhere |
|
|
434
|
+
| General | Backstroke | `BLACK`, width 3-8 | `_2025/` |
|
|
435
|
+
|
|
436
|
+
## Best Practices
|
|
437
|
+
|
|
438
|
+
1. **Maintain consistency** -- once a variable gets a color, keep it throughout the video
|
|
439
|
+
2. **Use `tex_to_color_map`** for every equation with multiple meaningful symbols
|
|
440
|
+
3. **Positive = blue, negative = red** for value-encoded colors (matrix heatmaps)
|
|
441
|
+
4. **Use backstroke** (`background_stroke`) when text overlaps colored backgrounds
|
|
442
|
+
5. **Gradients for bar charts** -- typically `BLUE_D` to `GREEN_D` or `BLUE` to `TEAL`
|
|
443
|
+
6. **Dim to 25% opacity** to de-emphasize elements rather than removing them
|
|
444
|
+
7. **HSL interpolation** for smooth gradients that stay vivid through the middle
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: colors
|
|
3
|
+
description: Color constants, gradients, and color manipulation in Manim
|
|
4
|
+
metadata:
|
|
5
|
+
tags: color, colors, gradient, rgb, hex, palette
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Colors in Manim
|
|
9
|
+
|
|
10
|
+
Manim provides predefined color constants and supports custom colors.
|
|
11
|
+
|
|
12
|
+
## IMPORTANT: Only Use Named Color Constants
|
|
13
|
+
|
|
14
|
+
**NEVER use hex color strings like `"#FF5733"` or `"#2ECC71"`.** Hex strings frequently cause `ManimColor._internal_from_hex_string` errors and crash the render. Always use the named constants below.
|
|
15
|
+
|
|
16
|
+
**NEVER use `CYAN`** — it does not exist in ManimCE. Use `TEAL` instead.
|
|
17
|
+
|
|
18
|
+
### Complete List of Valid Color Constants
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
# Primary colors
|
|
22
|
+
RED, GREEN, BLUE, YELLOW, ORANGE, PINK, PURPLE, WHITE, BLACK
|
|
23
|
+
|
|
24
|
+
# Grey/Gray (both spellings work)
|
|
25
|
+
GREY, GRAY
|
|
26
|
+
GREY_A, GREY_B, GREY_C, GREY_D, GREY_E
|
|
27
|
+
GRAY_A, GRAY_B, GRAY_C, GRAY_D, GRAY_E
|
|
28
|
+
LIGHT_GREY, LIGHT_GRAY, DARK_GREY, DARK_GRAY
|
|
29
|
+
LIGHTER_GREY, LIGHTER_GRAY, DARKER_GREY, DARKER_GRAY
|
|
30
|
+
|
|
31
|
+
# Color variants (_A = lightest, _E = darkest)
|
|
32
|
+
BLUE_A, BLUE_B, BLUE_C, BLUE_D, BLUE_E
|
|
33
|
+
RED_A, RED_B, RED_C, RED_D, RED_E
|
|
34
|
+
GREEN_A, GREEN_B, GREEN_C, GREEN_D, GREEN_E
|
|
35
|
+
TEAL, TEAL_A, TEAL_B, TEAL_C, TEAL_D, TEAL_E
|
|
36
|
+
GOLD, GOLD_A, GOLD_B, GOLD_C, GOLD_D, GOLD_E
|
|
37
|
+
YELLOW_A, YELLOW_B, YELLOW_C, YELLOW_D, YELLOW_E
|
|
38
|
+
MAROON, MAROON_A, MAROON_B, MAROON_C, MAROON_D, MAROON_E
|
|
39
|
+
PURPLE_A, PURPLE_B, PURPLE_C, PURPLE_D, PURPLE_E
|
|
40
|
+
ORANGE_A, ORANGE_B, ORANGE_C, ORANGE_D, ORANGE_E
|
|
41
|
+
PINK_A, PINK_B, PINK_C, PINK_D, PINK_E
|
|
42
|
+
|
|
43
|
+
# Pure RGB primaries
|
|
44
|
+
PURE_RED, PURE_GREEN, PURE_BLUE
|
|
45
|
+
|
|
46
|
+
# Browns
|
|
47
|
+
LIGHT_BROWN, DARK_BROWN
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
These 80+ named colors provide more than enough variety. If you need a specific shade, use `interpolate_color(COLOR1, COLOR2, alpha)` with named colors — never raw hex strings.
|
|
51
|
+
|
|
52
|
+
## Using Colors
|
|
53
|
+
|
|
54
|
+
### Setting Color on Creation
|
|
55
|
+
```python
|
|
56
|
+
circle = Circle(color=RED)
|
|
57
|
+
square = Square(color=BLUE, fill_color=GREEN, fill_opacity=0.5)
|
|
58
|
+
text = Text("Hello", color=YELLOW)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Setting Color After Creation
|
|
62
|
+
```python
|
|
63
|
+
circle = Circle()
|
|
64
|
+
circle.set_color(RED)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Custom Colors (Advanced — Prefer Named Constants)
|
|
68
|
+
|
|
69
|
+
If you absolutely need a custom color, use `ManimColor` or `interpolate_color` with named constants:
|
|
70
|
+
```python
|
|
71
|
+
# Blend two named colors — PREFERRED approach
|
|
72
|
+
custom = interpolate_color(BLUE, GREEN, 0.5)
|
|
73
|
+
|
|
74
|
+
# RGB values (0-1 range) — use only when no named color works
|
|
75
|
+
from manim import rgb_to_color
|
|
76
|
+
custom = rgb_to_color([0.5, 0.2, 0.8])
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Fill vs Stroke Color
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
square = Square()
|
|
83
|
+
square.set_fill(RED, opacity=0.8) # Interior color
|
|
84
|
+
square.set_stroke(BLUE, width=4) # Border color
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Combined Styling
|
|
88
|
+
```python
|
|
89
|
+
square = Square(
|
|
90
|
+
color=BLUE, # Sets both fill and stroke
|
|
91
|
+
fill_opacity=0.5, # Fill transparency
|
|
92
|
+
stroke_width=4 # Border thickness
|
|
93
|
+
)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Gradients
|
|
97
|
+
|
|
98
|
+
### Color Gradient on Mobject
|
|
99
|
+
```python
|
|
100
|
+
text = Text("GRADIENT")
|
|
101
|
+
text.set_color_by_gradient(RED, YELLOW, GREEN)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Gradient Along Path
|
|
105
|
+
```python
|
|
106
|
+
line = Line(LEFT * 3, RIGHT * 3)
|
|
107
|
+
line.set_color_by_gradient(BLUE, GREEN, YELLOW)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Color Interpolation
|
|
111
|
+
|
|
112
|
+
Create colors between two colors:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from manim import interpolate_color
|
|
116
|
+
|
|
117
|
+
# Get color halfway between RED and BLUE
|
|
118
|
+
mid_color = interpolate_color(RED, BLUE, 0.5)
|
|
119
|
+
|
|
120
|
+
# Create a range of colors
|
|
121
|
+
colors = [interpolate_color(RED, BLUE, alpha) for alpha in np.linspace(0, 1, 10)]
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## ManimColor Class
|
|
125
|
+
|
|
126
|
+
For advanced color manipulation:
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from manim import ManimColor
|
|
130
|
+
|
|
131
|
+
# Start from named constants — NOT hex strings
|
|
132
|
+
color1 = ManimColor(RED)
|
|
133
|
+
color2 = ManimColor(BLUE)
|
|
134
|
+
|
|
135
|
+
# Color manipulation methods
|
|
136
|
+
lighter = color1.lighter() # Lighter version
|
|
137
|
+
darker = color1.darker() # Darker version
|
|
138
|
+
|
|
139
|
+
# Interpolation
|
|
140
|
+
mixed = color1.interpolate(color2, 0.5) # Blend two colors
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Opacity
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
# Set opacity (0 = transparent, 1 = opaque)
|
|
147
|
+
circle = Circle(fill_opacity=0.5, stroke_opacity=0.8)
|
|
148
|
+
|
|
149
|
+
# Modify opacity
|
|
150
|
+
circle.set_opacity(0.5) # Both fill and stroke
|
|
151
|
+
circle.set_fill_opacity(0.7) # Fill only
|
|
152
|
+
circle.set_stroke_opacity(0.3) # Stroke only
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Color by Value
|
|
156
|
+
|
|
157
|
+
Color mobjects based on a value (useful for data visualization):
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
class ColorByValue(Scene):
|
|
161
|
+
def construct(self):
|
|
162
|
+
dots = VGroup(*[Dot() for _ in range(10)]).arrange(RIGHT)
|
|
163
|
+
|
|
164
|
+
for i, dot in enumerate(dots):
|
|
165
|
+
# Color from blue (cold) to red (hot)
|
|
166
|
+
dot.set_color(interpolate_color(BLUE, RED, i / 9))
|
|
167
|
+
|
|
168
|
+
self.add(dots)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Random Colors
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
from manim import random_color, random_bright_color
|
|
175
|
+
|
|
176
|
+
circle = Circle(color=random_color())
|
|
177
|
+
square = Square(color=random_bright_color())
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Color Lists for Animations
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
class ColorCycle(Scene):
|
|
184
|
+
def construct(self):
|
|
185
|
+
circle = Circle()
|
|
186
|
+
self.add(circle)
|
|
187
|
+
|
|
188
|
+
colors = [RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE]
|
|
189
|
+
for color in colors:
|
|
190
|
+
self.play(circle.animate.set_color(color), run_time=0.5)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Best Practices
|
|
194
|
+
|
|
195
|
+
1. **Use color variants for depth** - `BLUE_E` for shadows, `BLUE_A` for highlights
|
|
196
|
+
2. **Maintain color consistency** - Use the same colors for related concepts
|
|
197
|
+
3. **Use opacity for layering** - Semi-transparent fills show overlapping
|
|
198
|
+
4. **Consider colorblind accessibility** - Avoid red-green only distinctions
|
|
199
|
+
5. **Use gradients sparingly** - They can be distracting
|