0
# Utilities
1
2
Essential utility functions including mathematical operations, color management, rate functions, file operations, and debugging tools for animation development. These utilities provide the foundational support functions that enable smooth animation development and mathematical precision.
3
4
## Capabilities
5
6
### Constants and Directions
7
8
Fundamental mathematical and spatial constants used throughout Manim for positioning, animation, and mathematical calculations.
9
10
```python { .api }
11
# Coordinate system constants
12
ORIGIN: np.ndarray # [0, 0, 0] - Center of coordinate system
13
14
# Direction vectors (unit vectors)
15
UP: np.ndarray # [0, 1, 0] - Positive y direction
16
DOWN: np.ndarray # [0, -1, 0] - Negative y direction
17
LEFT: np.ndarray # [-1, 0, 0] - Negative x direction
18
RIGHT: np.ndarray # [1, 0, 0] - Positive x direction
19
IN: np.ndarray # [0, 0, -1] - Negative z direction (into screen)
20
OUT: np.ndarray # [0, 0, 1] - Positive z direction (out of screen)
21
22
# Coordinate axes
23
X_AXIS: np.ndarray # [1, 0, 0] - X-axis unit vector
24
Y_AXIS: np.ndarray # [0, 1, 0] - Y-axis unit vector
25
Z_AXIS: np.ndarray # [0, 0, 1] - Z-axis unit vector
26
27
# Diagonal directions (combinations)
28
UL: np.ndarray # UP + LEFT - Upper left diagonal
29
UR: np.ndarray # UP + RIGHT - Upper right diagonal
30
DL: np.ndarray # DOWN + LEFT - Lower left diagonal
31
DR: np.ndarray # DOWN + RIGHT - Lower right diagonal
32
33
# Mathematical constants
34
PI: float # π (pi) ≈ 3.14159
35
TAU: float # 2π (tau) ≈ 6.28318 - full circle
36
DEGREES: float # π/180 - conversion factor from degrees to radians
37
38
# Size and spacing constants
39
DEFAULT_DOT_RADIUS: float = 0.08
40
DEFAULT_SMALL_DOT_RADIUS: float = 0.04
41
DEFAULT_DASH_LENGTH: float = 0.05
42
DEFAULT_ARROW_TIP_LENGTH: float = 0.35
43
DEFAULT_STROKE_WIDTH: float = 4
44
DEFAULT_FONT_SIZE: float = 48
45
46
# Buffer distances for spacing
47
SMALL_BUFF: float = 0.1 # Small buffer distance
48
MED_SMALL_BUFF: float = 0.25 # Medium-small buffer
49
MED_LARGE_BUFF: float = 0.5 # Medium-large buffer
50
LARGE_BUFF: float = 1.0 # Large buffer distance
51
52
# Default positioning buffers
53
DEFAULT_MOBJECT_TO_EDGE_BUFFER: float = 0.5
54
DEFAULT_MOBJECT_TO_MOBJECT_BUFFER: float = 0.25
55
56
# Animation timing constants
57
DEFAULT_POINTWISE_FUNCTION_RUN_TIME: float = 3.0
58
DEFAULT_WAIT_TIME: float = 1.0
59
60
# Quality settings density
61
DEFAULT_POINT_DENSITY_2D: float = 25
62
DEFAULT_POINT_DENSITY_1D: float = 250
63
64
# Font and text scaling
65
SCALE_FACTOR_PER_FONT_POINT: float = 0.001
66
67
# Rendering quality constants
68
QUALITIES: dict = {
69
"fourk_quality": "4k quality rendering",
70
"production_quality": "Production quality rendering",
71
"high_quality": "High quality rendering",
72
"medium_quality": "Medium quality rendering",
73
"low_quality": "Low quality rendering",
74
"example_quality": "Example quality rendering"
75
}
76
DEFAULT_QUALITY: str = "high_quality"
77
78
# Renderer configuration
79
class RendererType:
80
"""Enumeration of available renderer types."""
81
CAIRO: str = "cairo" # Cairo 2D renderer
82
OPENGL: str = "opengl" # OpenGL 3D renderer
83
84
# Line styling enums
85
class LineJointType:
86
"""Enumeration of line joint types for stroke rendering."""
87
AUTO: int = 0 # Automatic joint type selection
88
ROUND: int = 1 # Rounded line joints
89
BEVEL: int = 2 # Beveled line joints
90
MITER: int = 3 # Mitered line joints
91
92
class CapStyleType:
93
"""Enumeration of line cap styles for stroke ends."""
94
AUTO: int = 0 # Automatic cap style selection
95
ROUND: int = 1 # Rounded line caps
96
BUTT: int = 2 # Flat butt line caps
97
SQUARE: int = 3 # Square line caps
98
99
# Font weight constants
100
THIN: int = 100
101
ULTRALIGHT: int = 200
102
LIGHT: int = 300
103
SEMILIGHT: int = 350
104
BOOK: int = 380
105
NORMAL: int = 400
106
MEDIUM: int = 500
107
SEMIBOLD: int = 600
108
BOLD: int = 700
109
ULTRABOLD: int = 800
110
HEAVY: int = 900
111
ULTRAHEAVY: int = 1000
112
113
# Font style constants
114
ITALIC: str = "italic"
115
OBLIQUE: str = "oblique"
116
117
# Interface constants
118
SHIFT_VALUE: int = 65505 # Keyboard shift key value
119
CTRL_VALUE: int = 65507 # Keyboard control key value
120
START_X: int = 30 # Default window x position
121
START_Y: int = 20 # Default window y position
122
```
123
124
### Rate Functions
125
126
Mathematical functions that control animation timing and easing for natural, expressive motion curves.
127
128
```python { .api }
129
# Basic rate functions
130
def linear(t: float) -> float:
131
"""
132
Linear interpolation - constant speed throughout animation.
133
134
Parameters:
135
- t: Time parameter [0, 1]
136
137
Returns:
138
- float: Linear progress [0, 1]
139
"""
140
141
def smooth(t: float) -> float:
142
"""
143
Smooth S-curve interpolation using smoothstep function.
144
145
Provides smooth acceleration and deceleration with no sudden changes
146
in velocity at start or end.
147
148
Parameters:
149
- t: Time parameter [0, 1]
150
151
Returns:
152
- float: Smooth progress [0, 1]
153
"""
154
155
def rush_into(t: float) -> float:
156
"""
157
Start slow, then rapidly accelerate toward end.
158
159
Parameters:
160
- t: Time parameter [0, 1]
161
162
Returns:
163
- float: Rush-in progress [0, 1]
164
"""
165
166
def rush_from(t: float) -> float:
167
"""
168
Start fast, then decelerate toward end.
169
170
Parameters:
171
- t: Time parameter [0, 1]
172
173
Returns:
174
- float: Rush-from progress [0, 1]
175
"""
176
177
def slow_into(t: float) -> float:
178
"""
179
Gradually accelerate throughout animation.
180
181
Parameters:
182
- t: Time parameter [0, 1]
183
184
Returns:
185
- float: Slow-into progress [0, 1]
186
"""
187
188
def double_smooth(t: float) -> float:
189
"""
190
Extra smooth S-curve with more gradual acceleration/deceleration.
191
192
Parameters:
193
- t: Time parameter [0, 1]
194
195
Returns:
196
- float: Double-smooth progress [0, 1]
197
"""
198
199
def there_and_back(t: float) -> float:
200
"""
201
Go from 0 to 1 and back to 0 during animation.
202
203
Creates a motion that reaches the target at the midpoint
204
then returns to the starting position.
205
206
Parameters:
207
- t: Time parameter [0, 1]
208
209
Returns:
210
- float: There-and-back progress [0, 1, 0]
211
"""
212
213
def there_and_back_with_pause(
214
t: float,
215
pause_ratio: float = 1/3
216
) -> float:
217
"""
218
Go to target, pause, then return with customizable pause duration.
219
220
Parameters:
221
- t: Time parameter [0, 1]
222
- pause_ratio: Fraction of time to pause at target
223
224
Returns:
225
- float: Progress with pause [0, 1, pause, 0]
226
"""
227
228
def running_start(
229
t: float,
230
pull_factor: float = -0.5
231
) -> float:
232
"""
233
Start by moving backward, then accelerate forward.
234
235
Creates anticipation by initially moving in opposite direction
236
before accelerating toward target.
237
238
Parameters:
239
- t: Time parameter [0, 1]
240
- pull_factor: How far backward to go initially
241
242
Returns:
243
- float: Running start progress
244
"""
245
246
def wiggle(t: float, wiggles: float = 2) -> float:
247
"""
248
Oscillating motion that settles at target.
249
250
Parameters:
251
- t: Time parameter [0, 1]
252
- wiggles: Number of oscillations
253
254
Returns:
255
- float: Wiggling progress [0, 1]
256
"""
257
258
def exponential_decay(t: float) -> float:
259
"""
260
Exponentially approach target value.
261
262
Parameters:
263
- t: Time parameter [0, 1]
264
265
Returns:
266
- float: Exponential progress [0, 1)
267
"""
268
269
# Standard easing functions (CSS/web animation style)
270
# Sine easing
271
def ease_in_sine(t: float) -> float:
272
"""Sine-based ease-in curve."""
273
274
def ease_out_sine(t: float) -> float:
275
"""Sine-based ease-out curve."""
276
277
def ease_in_out_sine(t: float) -> float:
278
"""Sine-based ease-in-out curve."""
279
280
# Quadratic easing
281
def ease_in_quad(t: float) -> float:
282
"""Quadratic ease-in curve (t²)."""
283
284
def ease_out_quad(t: float) -> float:
285
"""Quadratic ease-out curve."""
286
287
def ease_in_out_quad(t: float) -> float:
288
"""Quadratic ease-in-out curve."""
289
290
# Cubic easing
291
def ease_in_cubic(t: float) -> float:
292
"""Cubic ease-in curve (t³)."""
293
294
def ease_out_cubic(t: float) -> float:
295
"""Cubic ease-out curve."""
296
297
def ease_in_out_cubic(t: float) -> float:
298
"""Cubic ease-in-out curve."""
299
300
# Quartic easing
301
def ease_in_quart(t: float) -> float:
302
"""Quartic ease-in curve (t⁴)."""
303
304
def ease_out_quart(t: float) -> float:
305
"""Quartic ease-out curve."""
306
307
def ease_in_out_quart(t: float) -> float:
308
"""Quartic ease-in-out curve."""
309
310
# Exponential easing
311
def ease_in_expo(t: float) -> float:
312
"""Exponential ease-in curve."""
313
314
def ease_out_expo(t: float) -> float:
315
"""Exponential ease-out curve."""
316
317
def ease_in_out_expo(t: float) -> float:
318
"""Exponential ease-in-out curve."""
319
320
# Circular easing
321
def ease_in_circ(t: float) -> float:
322
"""Circular ease-in curve."""
323
324
def ease_out_circ(t: float) -> float:
325
"""Circular ease-out curve."""
326
327
def ease_in_out_circ(t: float) -> float:
328
"""Circular ease-in-out curve."""
329
330
# Back easing (overshoots target)
331
def ease_in_back(t: float) -> float:
332
"""Back ease-in with overshoot."""
333
334
def ease_out_back(t: float) -> float:
335
"""Back ease-out with overshoot."""
336
337
def ease_in_out_back(t: float) -> float:
338
"""Back ease-in-out with overshoot."""
339
340
# Elastic easing (bouncing effect)
341
def ease_in_elastic(t: float) -> float:
342
"""Elastic ease-in with bouncing."""
343
344
def ease_out_elastic(t: float) -> float:
345
"""Elastic ease-out with bouncing."""
346
347
def ease_in_out_elastic(t: float) -> float:
348
"""Elastic ease-in-out with bouncing."""
349
350
# Bounce easing
351
def ease_in_bounce(t: float) -> float:
352
"""Bounce ease-in curve."""
353
354
def ease_out_bounce(t: float) -> float:
355
"""Bounce ease-out curve."""
356
357
def ease_in_out_bounce(t: float) -> float:
358
"""Bounce ease-in-out curve."""
359
360
# Rate function utilities
361
def squish_rate_func(
362
func: Callable[[float], float],
363
a: float = 0.4,
364
b: float = 0.6
365
) -> Callable[[float], float]:
366
"""
367
Compress rate function to operate within [a, b] interval.
368
369
Parameters:
370
- func: Rate function to compress
371
- a: Start of active interval
372
- b: End of active interval
373
374
Returns:
375
- Callable: Compressed rate function
376
"""
377
378
def lingering(t: float) -> float:
379
"""
380
Linger at start, then smoothly progress to end.
381
382
Parameters:
383
- t: Time parameter [0, 1]
384
385
Returns:
386
- float: Lingering progress [0, 1]
387
"""
388
```
389
390
### Color System
391
392
Comprehensive color management system with predefined colors, color space conversions, and gradient utilities.
393
394
```python { .api }
395
# Color class and core functions
396
class ManimColor:
397
"""
398
Manim color class supporting multiple color spaces and formats.
399
400
Handles color parsing, conversion, and manipulation with support
401
for RGB, HSV, hex, and named colors.
402
"""
403
404
def __init__(color_value: str | tuple | np.ndarray) -> None:
405
"""
406
Parameters:
407
- color_value: Color specification (hex, name, RGB tuple, etc.)
408
"""
409
410
@staticmethod
411
def parse(color: str | ManimColor) -> ManimColor:
412
"""Parse color from various input formats."""
413
414
def hex() -> str:
415
"""Get color as hex string (#RRGGBB)."""
416
417
def rgb() -> tuple[float, float, float]:
418
"""Get color as RGB tuple [0,1]."""
419
420
def rgba() -> tuple[float, float, float, float]:
421
"""Get color as RGBA tuple [0,1]."""
422
423
def hsv() -> tuple[float, float, float]:
424
"""Get color as HSV tuple."""
425
426
def invert() -> ManimColor:
427
"""Get inverted/complementary color."""
428
429
def interpolate(other: ManimColor, alpha: float) -> ManimColor:
430
"""Interpolate between this color and another."""
431
432
# Core color constants (most commonly used)
433
WHITE: ManimColor
434
BLACK: ManimColor
435
GRAY: ManimColor
436
GREY: ManimColor # Alternative spelling
437
438
RED: ManimColor
439
GREEN: ManimColor
440
BLUE: ManimColor
441
YELLOW: ManimColor
442
ORANGE: ManimColor
443
PURPLE: ManimColor
444
PINK: ManimColor
445
BROWN: ManimColor
446
447
# Extended color palette
448
RED_A: ManimColor # Light red
449
RED_B: ManimColor # Medium red
450
RED_C: ManimColor # Standard red
451
RED_D: ManimColor # Dark red
452
RED_E: ManimColor # Very dark red
453
454
BLUE_A: ManimColor # Light blue
455
BLUE_B: ManimColor # Medium blue
456
BLUE_C: ManimColor # Standard blue
457
BLUE_D: ManimColor # Dark blue
458
BLUE_E: ManimColor # Very dark blue
459
460
GREEN_A: ManimColor # Light green
461
GREEN_B: ManimColor # Medium green
462
GREEN_C: ManimColor # Standard green
463
GREEN_D: ManimColor # Dark green
464
GREEN_E: ManimColor # Very dark green
465
466
# Additional standard colors
467
MAROON_A: ManimColor
468
MAROON_B: ManimColor
469
MAROON_C: ManimColor
470
MAROON_D: ManimColor
471
MAROON_E: ManimColor
472
473
YELLOW_A: ManimColor
474
YELLOW_B: ManimColor
475
YELLOW_C: ManimColor
476
YELLOW_D: ManimColor
477
YELLOW_E: ManimColor
478
479
TEAL_A: ManimColor
480
TEAL_B: ManimColor
481
TEAL_C: ManimColor
482
TEAL_D: ManimColor
483
TEAL_E: ManimColor
484
485
GOLD_A: ManimColor
486
GOLD_B: ManimColor
487
GOLD_C: ManimColor
488
GOLD_D: ManimColor
489
GOLD_E: ManimColor
490
491
# Color manipulation functions
492
def interpolate_color(
493
color1: ManimColor | str,
494
color2: ManimColor | str,
495
alpha: float
496
) -> ManimColor:
497
"""
498
Interpolate between two colors.
499
500
Parameters:
501
- color1: Starting color
502
- color2: Ending color
503
- alpha: Interpolation factor [0, 1]
504
505
Returns:
506
- ManimColor: Interpolated color
507
"""
508
509
def color_gradient(
510
colors: Sequence[ManimColor | str],
511
length: int
512
) -> list[ManimColor]:
513
"""
514
Create smooth gradient between multiple colors.
515
516
Parameters:
517
- colors: List of colors to interpolate between
518
- length: Number of colors in resulting gradient
519
520
Returns:
521
- list[ManimColor]: Gradient color sequence
522
"""
523
524
def random_color() -> ManimColor:
525
"""Generate random color."""
526
527
def random_bright_color() -> ManimColor:
528
"""Generate random bright/saturated color."""
529
530
def invert_color(color: ManimColor | str) -> ManimColor:
531
"""
532
Get inverted/complementary color.
533
534
Parameters:
535
- color: Color to invert
536
537
Returns:
538
- ManimColor: Inverted color
539
"""
540
541
def color_to_rgb(color: ManimColor | str) -> np.ndarray:
542
"""Convert color to RGB array [0,1]."""
543
544
def color_to_rgba(
545
color: ManimColor | str,
546
alpha: float = 1.0
547
) -> np.ndarray:
548
"""Convert color to RGBA array [0,1]."""
549
550
def rgb_to_color(rgb: np.ndarray) -> ManimColor:
551
"""Convert RGB array to ManimColor."""
552
553
def hex_to_color(hex_code: str) -> ManimColor:
554
"""Convert hex string to ManimColor."""
555
556
# Extended color collections
557
# Access additional color palettes
558
XKCD: module # XKCD color names (XKCD.AVOCADO, etc.)
559
X11: module # X11 color names
560
DVIPSNAMES: module # LaTeX DVIPS color names
561
BS381: module # British Standard colors
562
AS2700: module # Australian Standard colors
563
SVGNAMES: module # SVG/HTML color names
564
```
565
566
### Space Operations
567
568
Mathematical utilities for 3D space calculations, coordinate transformations, and geometric operations.
569
570
```python { .api }
571
# Vector operations
572
def normalize(vect: np.ndarray) -> np.ndarray:
573
"""
574
Normalize vector to unit length.
575
576
Parameters:
577
- vect: Vector to normalize
578
579
Returns:
580
- np.ndarray: Unit vector in same direction
581
"""
582
583
def get_norm(vect: np.ndarray) -> float:
584
"""
585
Get length/magnitude of vector.
586
587
Parameters:
588
- vect: Input vector
589
590
Returns:
591
- float: Vector magnitude
592
"""
593
594
def cross(v1: np.ndarray, v2: np.ndarray) -> np.ndarray:
595
"""
596
Cross product of two 3D vectors.
597
598
Parameters:
599
- v1: First vector
600
- v2: Second vector
601
602
Returns:
603
- np.ndarray: Cross product vector
604
"""
605
606
def dot(v1: np.ndarray, v2: np.ndarray) -> float:
607
"""
608
Dot product of two vectors.
609
610
Parameters:
611
- v1: First vector
612
- v2: Second vector
613
614
Returns:
615
- float: Dot product scalar
616
"""
617
618
def angle_between_vectors(v1: np.ndarray, v2: np.ndarray) -> float:
619
"""
620
Calculate angle between two vectors in radians.
621
622
Parameters:
623
- v1: First vector
624
- v2: Second vector
625
626
Returns:
627
- float: Angle in radians [0, π]
628
"""
629
630
def angle_of_vector(vector: np.ndarray) -> float:
631
"""
632
Get angle of 2D vector from positive x-axis.
633
634
Parameters:
635
- vector: 2D or 3D vector (z-component ignored)
636
637
Returns:
638
- float: Angle in radians [-π, π]
639
"""
640
641
# Coordinate transformations
642
def spherical_to_cartesian(
643
radius: float,
644
theta: float,
645
phi: float
646
) -> np.ndarray:
647
"""
648
Convert spherical coordinates to Cartesian.
649
650
Parameters:
651
- radius: Radial distance
652
- theta: Azimuthal angle (from x-axis)
653
- phi: Polar angle (from z-axis)
654
655
Returns:
656
- np.ndarray: Cartesian coordinates [x, y, z]
657
"""
658
659
def cartesian_to_spherical(point: np.ndarray) -> tuple[float, float, float]:
660
"""
661
Convert Cartesian coordinates to spherical.
662
663
Parameters:
664
- point: Cartesian point [x, y, z]
665
666
Returns:
667
- tuple: (radius, theta, phi) in spherical coordinates
668
"""
669
670
def cylindrical_to_cartesian(
671
radius: float,
672
theta: float,
673
z: float
674
) -> np.ndarray:
675
"""
676
Convert cylindrical coordinates to Cartesian.
677
678
Parameters:
679
- radius: Radial distance from z-axis
680
- theta: Angle around z-axis
681
- z: Height along z-axis
682
683
Returns:
684
- np.ndarray: Cartesian coordinates [x, y, z]
685
"""
686
687
# Rotation and transformation matrices
688
def rotation_matrix(
689
angle: float,
690
axis: np.ndarray = OUT
691
) -> np.ndarray:
692
"""
693
Create rotation matrix for rotating around specified axis.
694
695
Parameters:
696
- angle: Rotation angle in radians
697
- axis: Rotation axis vector
698
699
Returns:
700
- np.ndarray: 3x3 rotation matrix
701
"""
702
703
def rotation_about_z(angle: float) -> np.ndarray:
704
"""Rotation matrix for rotation about z-axis."""
705
706
def z_to_vector(z: complex) -> np.ndarray:
707
"""Convert complex number to 2D vector."""
708
709
def complex_to_R3(z: complex) -> np.ndarray:
710
"""Convert complex number to 3D point [Re(z), Im(z), 0]."""
711
712
def R3_to_complex(point: np.ndarray) -> complex:
713
"""Convert 3D point to complex number."""
714
715
def rotate_vector(
716
vector: np.ndarray,
717
angle: float,
718
axis: np.ndarray = OUT
719
) -> np.ndarray:
720
"""
721
Rotate vector around specified axis.
722
723
Parameters:
724
- vector: Vector to rotate
725
- angle: Rotation angle in radians
726
- axis: Rotation axis
727
728
Returns:
729
- np.ndarray: Rotated vector
730
"""
731
732
# Geometric utilities
733
def line_intersection(
734
line1: tuple[np.ndarray, np.ndarray],
735
line2: tuple[np.ndarray, np.ndarray]
736
) -> np.ndarray:
737
"""
738
Find intersection point of two 2D lines.
739
740
Parameters:
741
- line1: (point1, point2) defining first line
742
- line2: (point1, point2) defining second line
743
744
Returns:
745
- np.ndarray: Intersection point
746
"""
747
748
def get_closest_point_on_line(
749
a: np.ndarray,
750
b: np.ndarray,
751
p: np.ndarray
752
) -> np.ndarray:
753
"""
754
Find closest point on line segment to given point.
755
756
Parameters:
757
- a: Line start point
758
- b: Line end point
759
- p: Reference point
760
761
Returns:
762
- np.ndarray: Closest point on line to p
763
"""
764
765
def perpendicular_bisector(
766
line: tuple[np.ndarray, np.ndarray]
767
) -> tuple[np.ndarray, np.ndarray]:
768
"""
769
Get perpendicular bisector of line segment.
770
771
Parameters:
772
- line: (start_point, end_point) of line segment
773
774
Returns:
775
- tuple: (point, direction) defining perpendicular bisector
776
"""
777
778
def compass_directions(n: int = 4, start_vect: np.ndarray = RIGHT) -> list[np.ndarray]:
779
"""
780
Generate n evenly spaced unit vectors around circle.
781
782
Parameters:
783
- n: Number of directions
784
- start_vect: Starting direction
785
786
Returns:
787
- list[np.ndarray]: List of direction vectors
788
"""
789
```
790
791
### File and Path Operations
792
793
File system utilities for handling assets, output files, and resource management.
794
795
```python { .api }
796
# File operations
797
def guarantee_existence(path: str) -> str:
798
"""
799
Ensure directory exists, creating it if necessary.
800
801
Parameters:
802
- path: Directory path
803
804
Returns:
805
- str: Verified directory path
806
"""
807
808
def add_extension_if_not_present(
809
file_name: str,
810
extension: str
811
) -> str:
812
"""
813
Add file extension if not already present.
814
815
Parameters:
816
- file_name: Base filename
817
- extension: Extension to add (with or without dot)
818
819
Returns:
820
- str: Filename with extension
821
"""
822
823
def get_sorted_integer_files(directory: str) -> list[str]:
824
"""
825
Get list of files with integer names, sorted numerically.
826
827
Parameters:
828
- directory: Directory to search
829
830
Returns:
831
- list[str]: Sorted list of integer-named files
832
"""
833
834
def seek_full_path_from_defaults(
835
file_name: str,
836
default_dir: str,
837
extensions: list[str] = None
838
) -> str:
839
"""
840
Find file in default directory with optional extension matching.
841
842
Parameters:
843
- file_name: Base filename to search for
844
- default_dir: Directory to search in
845
- extensions: List of extensions to try
846
847
Returns:
848
- str: Full path to found file
849
"""
850
851
def open_media_file(file_path: str) -> None:
852
"""
853
Open media file with system default application.
854
855
Parameters:
856
- file_path: Path to media file
857
"""
858
859
# Path utilities
860
def get_manim_dir() -> str:
861
"""Get Manim installation directory."""
862
863
def get_downloads_dir() -> str:
864
"""Get user downloads directory."""
865
866
def get_output_dir() -> str:
867
"""Get configured output directory."""
868
869
def get_tex_dir() -> str:
870
"""Get directory for LaTeX files."""
871
872
def get_raster_image_dir() -> str:
873
"""Get directory for raster images."""
874
875
def get_vector_image_dir() -> str:
876
"""Get directory for vector images."""
877
878
# Asset management
879
def find_file(
880
file_name: str,
881
directories: list[str] = None
882
) -> str:
883
"""
884
Search for file in multiple directories.
885
886
Parameters:
887
- file_name: Name of file to find
888
- directories: List of directories to search
889
890
Returns:
891
- str: Full path to found file
892
"""
893
```
894
895
### Mathematical Utilities
896
897
Essential mathematical functions and utilities for calculations, interpolation, and numerical operations.
898
899
```python { .api }
900
# Interpolation functions
901
def interpolate(start: float, end: float, alpha: float) -> float:
902
"""
903
Linear interpolation between two values.
904
905
Parameters:
906
- start: Starting value
907
- end: Ending value
908
- alpha: Interpolation factor [0, 1]
909
910
Returns:
911
- float: Interpolated value
912
"""
913
914
def inverse_interpolate(
915
start: float,
916
end: float,
917
value: float
918
) -> float:
919
"""
920
Find interpolation factor for given value between start and end.
921
922
Parameters:
923
- start: Starting value
924
- end: Ending value
925
- value: Value to find factor for
926
927
Returns:
928
- float: Interpolation factor
929
"""
930
931
def clip(value: float, min_val: float, max_val: float) -> float:
932
"""
933
Clamp value to specified range.
934
935
Parameters:
936
- value: Value to clamp
937
- min_val: Minimum allowed value
938
- max_val: Maximum allowed value
939
940
Returns:
941
- float: Clamped value
942
"""
943
944
def binary_search(
945
function: Callable[[float], float],
946
target: float,
947
lower_bound: float,
948
upper_bound: float,
949
tolerance: float = 1e-6
950
) -> float:
951
"""
952
Binary search for input that produces target output.
953
954
Parameters:
955
- function: Function to search
956
- target: Target output value
957
- lower_bound: Lower bound for search
958
- upper_bound: Upper bound for search
959
- tolerance: Accuracy tolerance
960
961
Returns:
962
- float: Input value producing target output
963
"""
964
965
# Numerical utilities
966
def choose(n: int, k: int) -> int:
967
"""
968
Binomial coefficient "n choose k".
969
970
Parameters:
971
- n: Total number of items
972
- k: Number to choose
973
974
Returns:
975
- int: Binomial coefficient
976
"""
977
978
def bezier(points: np.ndarray) -> Callable[[float], np.ndarray]:
979
"""
980
Create Bézier curve function from control points.
981
982
Parameters:
983
- points: Array of control points
984
985
Returns:
986
- Callable: Function mapping t∈[0,1] to curve points
987
"""
988
989
def partial_bezier_points(
990
points: np.ndarray,
991
a: float,
992
b: float
993
) -> np.ndarray:
994
"""
995
Get control points for partial Bézier curve.
996
997
Parameters:
998
- points: Original control points
999
- a: Start parameter [0, 1]
1000
- b: End parameter [0, 1]
1001
1002
Returns:
1003
- np.ndarray: Control points for partial curve
1004
"""
1005
1006
# Array and sequence utilities
1007
def make_smooth_bezier_curve_connections(
1008
bezier_point_sets: list[np.ndarray]
1009
) -> list[np.ndarray]:
1010
"""
1011
Connect Bézier curves smoothly by adjusting control points.
1012
1013
Parameters:
1014
- bezier_point_sets: List of Bézier control point sets
1015
1016
Returns:
1017
- list[np.ndarray]: Smoothly connected control point sets
1018
"""
1019
1020
def get_smooth_handle_points(
1021
points: np.ndarray
1022
) -> tuple[np.ndarray, np.ndarray]:
1023
"""
1024
Generate smooth Bézier handles for curve through points.
1025
1026
Parameters:
1027
- points: Points to create smooth curve through
1028
1029
Returns:
1030
- tuple: (left_handles, right_handles) for smooth curve
1031
"""
1032
```
1033
1034
### Debugging and Development
1035
1036
Tools and utilities for debugging animations, performance monitoring, and development workflow enhancement.
1037
1038
```python { .api }
1039
# Logging and debugging
1040
from manim import logger
1041
1042
logger.debug(message: str) -> None:
1043
"""Log debug-level message."""
1044
1045
logger.info(message: str) -> None:
1046
"""Log info-level message."""
1047
1048
logger.warning(message: str) -> None:
1049
"""Log warning-level message."""
1050
1051
logger.error(message: str) -> None:
1052
"""Log error-level message."""
1053
1054
# Console output (use instead of print)
1055
from manim import console
1056
1057
console.print(*args, **kwargs) -> None:
1058
"""Rich console print with formatting support."""
1059
1060
console.log(*args, **kwargs) -> None:
1061
"""Rich console log with timestamp."""
1062
1063
# Development utilities
1064
def get_parameters_from_function(func: Callable) -> dict:
1065
"""Extract parameter information from function signature."""
1066
1067
def get_all_descendent_classes(Class: type) -> list[type]:
1068
"""Get all classes that inherit from given class."""
1069
1070
def get_mobject_family_members(
1071
mobjects: list[Mobject],
1072
only_those_with_points: bool = False
1073
) -> list[Mobject]:
1074
"""
1075
Get all mobjects including submobjects in flattened list.
1076
1077
Parameters:
1078
- mobjects: List of mobjects to expand
1079
- only_those_with_points: Whether to include only mobjects with points
1080
1081
Returns:
1082
- list[Mobject]: Flattened list including all submobjects
1083
"""
1084
1085
# Performance monitoring
1086
import time
1087
1088
def time_function(func: Callable) -> Callable:
1089
"""Decorator to measure function execution time."""
1090
1091
def profile_memory_usage(func: Callable) -> Callable:
1092
"""Decorator to profile memory usage of function."""
1093
1094
# Interactive development
1095
def interactive_embed() -> None:
1096
"""Start interactive Python session with current scene state."""
1097
1098
def pause_for_interaction() -> None:
1099
"""Pause animation for user interaction."""
1100
```
1101
1102
## Usage Examples
1103
1104
### Rate Functions
1105
1106
```python
1107
from manim import *
1108
1109
class RateFunctionExample(Scene):
1110
def construct(self):
1111
dot = Dot()
1112
1113
# Different easing styles
1114
animations = [
1115
dot.animate.shift(RIGHT * 2).set_rate_func(linear),
1116
dot.animate.shift(UP * 2).set_rate_func(smooth),
1117
dot.animate.shift(LEFT * 2).set_rate_func(there_and_back),
1118
dot.animate.shift(DOWN * 2).set_rate_func(ease_out_bounce)
1119
]
1120
1121
for anim in animations:
1122
self.play(anim)
1123
self.wait(0.5)
1124
```
1125
1126
### Color Operations
1127
1128
```python
1129
class ColorExample(Scene):
1130
def construct(self):
1131
# Using predefined colors
1132
circle1 = Circle(color=RED)
1133
circle2 = Circle(color=BLUE_D)
1134
circle3 = Circle(color=XKCD.AVOCADO)
1135
1136
# Color interpolation
1137
interpolated_color = interpolate_color(RED, BLUE, 0.5)
1138
circle4 = Circle(color=interpolated_color)
1139
1140
# Color gradients
1141
gradient_colors = color_gradient([RED, GREEN, BLUE], 10)
1142
circles = VGroup(*[
1143
Circle(color=color, radius=0.3)
1144
for color in gradient_colors
1145
])
1146
circles.arrange(RIGHT)
1147
1148
self.add(circles)
1149
```
1150
1151
### Space Operations
1152
1153
```python
1154
class SpaceOpsExample(Scene):
1155
def construct(self):
1156
# Vector operations
1157
v1 = np.array([1, 0, 0])
1158
v2 = np.array([0, 1, 0])
1159
1160
# Cross product
1161
cross_product = cross(v1, v2)
1162
arrow = Arrow(ORIGIN, cross_product, color=RED)
1163
1164
# Angle between vectors
1165
angle = angle_between_vectors(UP, RIGHT)
1166
arc = Arc(angle=angle, color=YELLOW)
1167
1168
# Rotation
1169
rotated_vector = rotate_vector(RIGHT, PI/4)
1170
rotated_arrow = Arrow(ORIGIN, rotated_vector, color=GREEN)
1171
1172
self.add(arrow, arc, rotated_arrow)
1173
```
1174
1175
### Mathematical Utilities
1176
1177
```python
1178
class MathUtilsExample(Scene):
1179
def construct(self):
1180
# Create smooth curve through points
1181
points = np.array([
1182
[-3, -1, 0],
1183
[-1, 1, 0],
1184
[1, -1, 0],
1185
[3, 1, 0]
1186
])
1187
1188
# Generate smooth Bézier curve
1189
curve = VMobject()
1190
curve.set_points_smoothly(points)
1191
curve.set_stroke(YELLOW, 3)
1192
1193
# Mark the control points
1194
dots = VGroup(*[Dot(p, color=RED) for p in points])
1195
1196
self.add(curve, dots)
1197
```
1198
1199
### Development and Debugging
1200
1201
```python
1202
class DebugExample(Scene):
1203
def construct(self):
1204
# Enable debug logging
1205
logger.setLevel("DEBUG")
1206
1207
# Time animation performance
1208
start_time = time.time()
1209
1210
circle = Circle()
1211
logger.info("Created circle")
1212
1213
self.play(Create(circle))
1214
1215
end_time = time.time()
1216
logger.info(f"Animation took {end_time - start_time:.2f} seconds")
1217
1218
# Interactive debugging (uncomment for interactive use)
1219
# self.interactive_embed()
1220
```
1221
1222
### File Operations
1223
1224
```python
1225
class FileOpsExample(Scene):
1226
def construct(self):
1227
# Ensure output directory exists
1228
output_dir = guarantee_existence("custom_output")
1229
1230
# Find asset file
1231
try:
1232
asset_path = find_file("my_image.png", [
1233
"assets/images",
1234
"resources",
1235
get_downloads_dir()
1236
])
1237
1238
# Use found image
1239
image = ImageMobject(asset_path)
1240
self.add(image)
1241
1242
except FileNotFoundError:
1243
# Fallback if image not found
1244
text = Text("Image not found")
1245
self.add(text)
1246
```
1247
1248
### Configuration and Constants
1249
1250
```python
1251
class ConstantsExample(Scene):
1252
def construct(self):
1253
# Use directional constants for positioning
1254
center_dot = Dot(ORIGIN, color=WHITE)
1255
1256
direction_dots = VGroup(
1257
Dot(UP, color=RED),
1258
Dot(DOWN, color=GREEN),
1259
Dot(LEFT, color=BLUE),
1260
Dot(RIGHT, color=YELLOW),
1261
Dot(UL, color=PURPLE),
1262
Dot(UR, color=ORANGE),
1263
Dot(DL, color=PINK),
1264
Dot(DR, color=TEAL)
1265
)
1266
1267
# Use buffer constants for spacing
1268
text = Text("Directions").next_to(
1269
center_dot,
1270
UP,
1271
buff=LARGE_BUFF
1272
)
1273
1274
self.add(center_dot, direction_dots, text)
1275
```