manim 0.17.0__py3-none-any.whl → 0.19.1__py3-none-any.whl

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 (163) hide show
  1. manim/__init__.py +11 -6
  2. manim/__main__.py +62 -19
  3. manim/_config/__init__.py +10 -9
  4. manim/_config/cli_colors.py +26 -9
  5. manim/_config/default.cfg +1 -3
  6. manim/_config/logger_utils.py +23 -13
  7. manim/_config/utils.py +662 -468
  8. manim/animation/animation.py +164 -18
  9. manim/animation/changing.py +34 -23
  10. manim/animation/composition.py +265 -67
  11. manim/animation/creation.py +208 -26
  12. manim/animation/fading.py +16 -18
  13. manim/animation/growing.py +35 -15
  14. manim/animation/indication.py +150 -76
  15. manim/animation/movement.py +56 -22
  16. manim/animation/numbers.py +64 -6
  17. manim/animation/rotation.py +78 -7
  18. manim/animation/specialized.py +6 -7
  19. manim/animation/speedmodifier.py +13 -10
  20. manim/animation/transform.py +14 -11
  21. manim/animation/transform_matching_parts.py +3 -4
  22. manim/animation/updaters/mobject_update_utils.py +152 -30
  23. manim/animation/updaters/update.py +10 -7
  24. manim/camera/camera.py +182 -118
  25. manim/camera/mapping_camera.py +34 -3
  26. manim/camera/moving_camera.py +95 -74
  27. manim/camera/multi_camera.py +23 -15
  28. manim/camera/three_d_camera.py +70 -52
  29. manim/cli/__init__.py +17 -0
  30. manim/cli/cfg/group.py +76 -44
  31. manim/cli/checkhealth/checks.py +192 -0
  32. manim/cli/checkhealth/commands.py +90 -0
  33. manim/cli/default_group.py +158 -25
  34. manim/cli/init/commands.py +33 -25
  35. manim/cli/plugins/commands.py +16 -3
  36. manim/cli/render/commands.py +72 -60
  37. manim/cli/render/ease_of_access_options.py +4 -3
  38. manim/cli/render/global_options.py +59 -17
  39. manim/cli/render/output_options.py +6 -5
  40. manim/cli/render/render_options.py +98 -33
  41. manim/constants.py +109 -59
  42. manim/data_structures.py +31 -0
  43. manim/mobject/frame.py +8 -5
  44. manim/mobject/geometry/__init__.py +1 -0
  45. manim/mobject/geometry/arc.py +277 -135
  46. manim/mobject/geometry/boolean_ops.py +32 -31
  47. manim/mobject/geometry/labeled.py +376 -0
  48. manim/mobject/geometry/line.py +192 -87
  49. manim/mobject/geometry/polygram.py +224 -58
  50. manim/mobject/geometry/shape_matchers.py +61 -25
  51. manim/mobject/geometry/tips.py +122 -48
  52. manim/mobject/graph.py +1027 -419
  53. manim/mobject/graphing/coordinate_systems.py +533 -278
  54. manim/mobject/graphing/functions.py +53 -32
  55. manim/mobject/graphing/number_line.py +123 -65
  56. manim/mobject/graphing/probability.py +88 -62
  57. manim/mobject/graphing/scale.py +33 -19
  58. manim/mobject/logo.py +118 -28
  59. manim/mobject/matrix.py +87 -83
  60. manim/mobject/mobject.py +912 -442
  61. manim/mobject/opengl/dot_cloud.py +16 -5
  62. manim/mobject/opengl/opengl_compatibility.py +4 -2
  63. manim/mobject/opengl/opengl_geometry.py +254 -153
  64. manim/mobject/opengl/opengl_image_mobject.py +3 -1
  65. manim/mobject/opengl/opengl_mobject.py +779 -482
  66. manim/mobject/opengl/opengl_point_cloud_mobject.py +41 -14
  67. manim/mobject/opengl/opengl_surface.py +14 -92
  68. manim/mobject/opengl/opengl_three_dimensions.py +12 -8
  69. manim/mobject/opengl/opengl_vectorized_mobject.py +98 -100
  70. manim/mobject/svg/brace.py +173 -41
  71. manim/mobject/svg/svg_mobject.py +139 -53
  72. manim/mobject/table.py +61 -68
  73. manim/mobject/text/code_mobject.py +193 -539
  74. manim/mobject/text/numbers.py +81 -34
  75. manim/mobject/text/tex_mobject.py +130 -78
  76. manim/mobject/text/text_mobject.py +288 -164
  77. manim/mobject/three_d/polyhedra.py +111 -13
  78. manim/mobject/three_d/three_d_utils.py +17 -8
  79. manim/mobject/three_d/three_dimensions.py +239 -106
  80. manim/mobject/types/image_mobject.py +50 -30
  81. manim/mobject/types/point_cloud_mobject.py +120 -75
  82. manim/mobject/types/vectorized_mobject.py +841 -408
  83. manim/mobject/value_tracker.py +105 -38
  84. manim/mobject/vector_field.py +50 -31
  85. manim/opengl/__init__.py +3 -3
  86. manim/plugins/__init__.py +14 -1
  87. manim/plugins/plugins_flags.py +10 -14
  88. manim/renderer/cairo_renderer.py +65 -50
  89. manim/renderer/opengl_renderer.py +89 -69
  90. manim/renderer/opengl_renderer_window.py +39 -18
  91. manim/renderer/shader.py +123 -87
  92. manim/renderer/shader_wrapper.py +44 -28
  93. manim/renderer/vectorized_mobject_rendering.py +38 -10
  94. manim/scene/moving_camera_scene.py +32 -3
  95. manim/scene/scene.py +507 -242
  96. manim/scene/scene_file_writer.py +371 -220
  97. manim/scene/section.py +20 -16
  98. manim/scene/three_d_scene.py +14 -22
  99. manim/scene/vector_space_scene.py +223 -129
  100. manim/scene/zoomed_scene.py +46 -41
  101. manim/typing.py +990 -0
  102. manim/utils/bezier.py +1823 -371
  103. manim/utils/caching.py +12 -5
  104. manim/utils/color/AS2700.py +236 -0
  105. manim/utils/color/BS381.py +318 -0
  106. manim/utils/color/DVIPSNAMES.py +96 -0
  107. manim/utils/color/SVGNAMES.py +179 -0
  108. manim/utils/color/X11.py +533 -0
  109. manim/utils/color/XKCD.py +952 -0
  110. manim/utils/color/__init__.py +61 -0
  111. manim/utils/color/core.py +1667 -0
  112. manim/utils/color/manim_colors.py +218 -0
  113. manim/utils/commands.py +48 -20
  114. manim/utils/config_ops.py +39 -19
  115. manim/utils/debug.py +8 -7
  116. manim/utils/deprecation.py +86 -39
  117. manim/utils/docbuild/__init__.py +17 -0
  118. manim/utils/docbuild/autoaliasattr_directive.py +236 -0
  119. manim/utils/docbuild/autocolor_directive.py +99 -0
  120. manim/utils/docbuild/manim_directive.py +94 -41
  121. manim/utils/docbuild/module_parsing.py +245 -0
  122. manim/utils/exceptions.py +6 -0
  123. manim/utils/family.py +5 -3
  124. manim/utils/family_ops.py +17 -4
  125. manim/utils/file_ops.py +27 -17
  126. manim/utils/hashing.py +55 -45
  127. manim/utils/images.py +13 -7
  128. manim/utils/ipython_magic.py +13 -7
  129. manim/utils/iterables.py +163 -120
  130. manim/utils/module_ops.py +66 -24
  131. manim/utils/opengl.py +77 -24
  132. manim/utils/parameter_parsing.py +32 -0
  133. manim/utils/paths.py +30 -33
  134. manim/utils/polylabel.py +235 -0
  135. manim/utils/qhull.py +218 -0
  136. manim/utils/rate_functions.py +98 -32
  137. manim/utils/simple_functions.py +25 -33
  138. manim/utils/sounds.py +7 -1
  139. manim/utils/space_ops.py +188 -115
  140. manim/utils/testing/__init__.py +17 -0
  141. manim/utils/testing/_frames_testers.py +13 -8
  142. manim/utils/testing/_show_diff.py +5 -3
  143. manim/utils/testing/_test_class_makers.py +34 -18
  144. manim/utils/testing/frames_comparison.py +37 -19
  145. manim/utils/tex.py +130 -198
  146. manim/utils/tex_file_writing.py +77 -47
  147. manim/utils/tex_templates.py +2 -1
  148. manim/utils/unit.py +6 -5
  149. {manim-0.17.0.dist-info → manim-0.19.1.dist-info}/METADATA +64 -65
  150. manim-0.19.1.dist-info/RECORD +220 -0
  151. {manim-0.17.0.dist-info → manim-0.19.1.dist-info}/WHEEL +1 -1
  152. manim-0.19.1.dist-info/entry_points.txt +3 -0
  153. {manim-0.17.0.dist-info → manim-0.19.1.dist-info/licenses}/LICENSE.community +1 -1
  154. manim/cli/new/group.py +0 -189
  155. manim/communitycolors.py +0 -9
  156. manim/gui/__init__.py +0 -0
  157. manim/gui/gui.py +0 -82
  158. manim/plugins/import_plugins.py +0 -43
  159. manim/utils/color.py +0 -552
  160. manim-0.17.0.dist-info/RECORD +0 -206
  161. manim-0.17.0.dist-info/entry_points.txt +0 -4
  162. /manim/cli/{new → checkhealth}/__init__.py +0 -0
  163. {manim-0.17.0.dist-info → manim-0.19.1.dist-info/licenses}/LICENSE +0 -0
@@ -1,6 +1,5 @@
1
1
  """Animate mobjects."""
2
2
 
3
-
4
3
  from __future__ import annotations
5
4
 
6
5
  from manim.mobject.opengl.opengl_mobject import OpenGLMobject
@@ -8,15 +7,19 @@ from manim.mobject.opengl.opengl_mobject import OpenGLMobject
8
7
  from .. import config, logger
9
8
  from ..constants import RendererType
10
9
  from ..mobject import mobject
11
- from ..mobject.mobject import Mobject
10
+ from ..mobject.mobject import Group, Mobject
12
11
  from ..mobject.opengl import opengl_mobject
13
12
  from ..utils.rate_functions import linear, smooth
14
13
 
15
- __all__ = ["Animation", "Wait", "override_animation"]
14
+ __all__ = ["Animation", "Wait", "Add", "override_animation"]
16
15
 
17
16
 
17
+ from collections.abc import Callable, Iterable, Sequence
18
18
  from copy import deepcopy
19
- from typing import TYPE_CHECKING, Callable, Iterable, Sequence
19
+ from functools import partialmethod
20
+ from typing import TYPE_CHECKING, Any
21
+
22
+ from typing_extensions import Self
20
23
 
21
24
  if TYPE_CHECKING:
22
25
  from manim.scene.scene import Scene
@@ -51,7 +54,6 @@ class Animation:
51
54
  For example ``rate_func(0.5)`` is the proportion of the animation that is done
52
55
  after half of the animations run time.
53
56
 
54
-
55
57
  reverse_rate_function
56
58
  Reverses the rate function of the animation. Setting ``reverse_rate_function``
57
59
  does not have any effect on ``remover`` or ``introducer``. These need to be
@@ -112,13 +114,13 @@ class Animation:
112
114
  *args,
113
115
  use_override=True,
114
116
  **kwargs,
115
- ):
117
+ ) -> Self:
116
118
  if isinstance(mobject, Mobject) and use_override:
117
119
  func = mobject.animation_override_for(cls)
118
120
  if func is not None:
119
121
  anim = func(mobject, *args, **kwargs)
120
122
  logger.debug(
121
- f"The {cls.__name__} animation has been is overridden for "
123
+ f"The {cls.__name__} animation has been overridden for "
122
124
  f"{type(mobject).__name__} mobjects. use_override = False can "
123
125
  f" be used as keyword argument to prevent animation overriding.",
124
126
  )
@@ -127,7 +129,7 @@ class Animation:
127
129
 
128
130
  def __init__(
129
131
  self,
130
- mobject: Mobject | None,
132
+ mobject: Mobject | OpenGLMobject | None,
131
133
  lag_ratio: float = DEFAULT_ANIMATION_LAG_RATIO,
132
134
  run_time: float = DEFAULT_ANIMATION_RUN_TIME,
133
135
  rate_func: Callable[[float], float] = smooth,
@@ -138,7 +140,7 @@ class Animation:
138
140
  introducer: bool = False,
139
141
  *,
140
142
  _on_finish: Callable[[], None] = lambda _: None,
141
- **kwargs,
143
+ use_override: bool = True, # included here to avoid TypeError if passed from a subclass' constructor
142
144
  ) -> None:
143
145
  self._typecheck_input(mobject)
144
146
  self.run_time: float = run_time
@@ -158,8 +160,6 @@ class Animation:
158
160
  else:
159
161
  self.starting_mobject: Mobject = Mobject()
160
162
  self.mobject: Mobject = mobject if mobject is not None else Mobject()
161
- if kwargs:
162
- logger.debug("Animation received extra kwargs: %s", kwargs)
163
163
 
164
164
  if hasattr(self, "CONFIG"):
165
165
  logger.error(
@@ -169,6 +169,19 @@ class Animation:
169
169
  ),
170
170
  )
171
171
 
172
+ @property
173
+ def run_time(self) -> float:
174
+ return self._run_time
175
+
176
+ @run_time.setter
177
+ def run_time(self, value: float) -> None:
178
+ if value < 0:
179
+ raise ValueError(
180
+ f"The run_time of {self.__class__.__name__} cannot be "
181
+ f"negative. The given value was {value}."
182
+ )
183
+ self._run_time = value
184
+
172
185
  def _typecheck_input(self, mobject: Mobject | None) -> None:
173
186
  if mobject is None:
174
187
  logger.debug("Animation with empty mobject")
@@ -249,11 +262,11 @@ class Animation:
249
262
  ):
250
263
  scene.add(self.mobject)
251
264
 
252
- def create_starting_mobject(self) -> Mobject:
265
+ def create_starting_mobject(self) -> Mobject | OpenGLMobject:
253
266
  # Keep track of where the mobject starts
254
267
  return self.mobject.copy()
255
268
 
256
- def get_all_mobjects(self) -> Sequence[Mobject]:
269
+ def get_all_mobjects(self) -> Sequence[Mobject | OpenGLMobject]:
257
270
  """Get all mobjects involved in the animation.
258
271
 
259
272
  Ordering must match the ordering of arguments to interpolate_submobject
@@ -398,6 +411,7 @@ class Animation:
398
411
  self.run_time = run_time
399
412
  return self
400
413
 
414
+ # TODO: is this getter even necessary?
401
415
  def get_run_time(self) -> float:
402
416
  """Get the run time of the animation.
403
417
 
@@ -457,7 +471,7 @@ class Animation:
457
471
  return self
458
472
 
459
473
  def is_remover(self) -> bool:
460
- """Test if a the animation is a remover.
474
+ """Test if the animation is a remover.
461
475
 
462
476
  Returns
463
477
  -------
@@ -467,7 +481,7 @@ class Animation:
467
481
  return self.remover
468
482
 
469
483
  def is_introducer(self) -> bool:
470
- """Test if a the animation is an introducer.
484
+ """Test if the animation is an introducer.
471
485
 
472
486
  Returns
473
487
  -------
@@ -476,9 +490,57 @@ class Animation:
476
490
  """
477
491
  return self.introducer
478
492
 
493
+ @classmethod
494
+ def __init_subclass__(cls, **kwargs) -> None:
495
+ super().__init_subclass__(**kwargs)
496
+
497
+ cls._original__init__ = cls.__init__
498
+
499
+ _original__init__ = __init__ # needed if set_default() is called with no kwargs directly from Animation
500
+
501
+ @classmethod
502
+ def set_default(cls, **kwargs) -> None:
503
+ """Sets the default values of keyword arguments.
504
+
505
+ If this method is called without any additional keyword
506
+ arguments, the original default values of the initialization
507
+ method of this class are restored.
508
+
509
+ Parameters
510
+ ----------
511
+
512
+ kwargs
513
+ Passing any keyword argument will update the default
514
+ values of the keyword arguments of the initialization
515
+ function of this class.
516
+
517
+ Examples
518
+ --------
519
+
520
+ .. manim:: ChangeDefaultAnimation
521
+
522
+ class ChangeDefaultAnimation(Scene):
523
+ def construct(self):
524
+ Rotate.set_default(run_time=2, rate_func=rate_functions.linear)
525
+ Indicate.set_default(color=None)
526
+
527
+ S = Square(color=BLUE, fill_color=BLUE, fill_opacity=0.25)
528
+ self.add(S)
529
+ self.play(Rotate(S, PI))
530
+ self.play(Indicate(S))
531
+
532
+ Rotate.set_default()
533
+ Indicate.set_default()
534
+
535
+ """
536
+ if kwargs:
537
+ cls.__init__ = partialmethod(cls.__init__, **kwargs)
538
+ else:
539
+ cls.__init__ = cls._original__init__
540
+
479
541
 
480
542
  def prepare_animation(
481
- anim: Animation | mobject._AnimationBuilder,
543
+ anim: Animation | mobject._AnimationBuilder | opengl_mobject._AnimationBuilder,
482
544
  ) -> Animation:
483
545
  r"""Returns either an unchanged animation, or the animation built
484
546
  from a passed animation factory.
@@ -528,8 +590,8 @@ class Wait(Animation):
528
590
  stop_condition
529
591
  A function without positional arguments that evaluates to a boolean.
530
592
  The function is evaluated after every new frame has been rendered.
531
- Playing the animation only stops after the return value is truthy.
532
- Overrides the specified ``run_time``.
593
+ Playing the animation stops after the return value is truthy, or
594
+ after the specified ``run_time`` has passed.
533
595
  frozen_frame
534
596
  Controls whether or not the wait animation is static, i.e., corresponds
535
597
  to a frozen frame. If ``False`` is passed, the render loop still
@@ -575,6 +637,90 @@ class Wait(Animation):
575
637
  pass
576
638
 
577
639
 
640
+ class Add(Animation):
641
+ """Add Mobjects to a scene, without animating them in any other way. This
642
+ is similar to the :meth:`.Scene.add` method, but :class:`Add` is an
643
+ animation which can be grouped into other animations.
644
+
645
+ Parameters
646
+ ----------
647
+ mobjects
648
+ One :class:`~.Mobject` or more to add to a scene.
649
+ run_time
650
+ The duration of the animation after adding the ``mobjects``. Defaults
651
+ to 0, which means this is an instant animation without extra wait time
652
+ after adding them.
653
+ **kwargs
654
+ Additional arguments to pass to the parent :class:`Animation` class.
655
+
656
+ Examples
657
+ --------
658
+
659
+ .. manim:: DefaultAddScene
660
+
661
+ class DefaultAddScene(Scene):
662
+ def construct(self):
663
+ text_1 = Text("I was added with Add!")
664
+ text_2 = Text("Me too!")
665
+ text_3 = Text("And me!")
666
+ texts = VGroup(text_1, text_2, text_3).arrange(DOWN)
667
+ rect = SurroundingRectangle(texts, buff=0.5)
668
+
669
+ self.play(
670
+ Create(rect, run_time=3.0),
671
+ Succession(
672
+ Wait(1.0),
673
+ # You can Add a Mobject in the middle of an animation...
674
+ Add(text_1),
675
+ Wait(1.0),
676
+ # ...or multiple Mobjects at once!
677
+ Add(text_2, text_3),
678
+ ),
679
+ )
680
+ self.wait()
681
+
682
+ .. manim:: AddWithRunTimeScene
683
+
684
+ class AddWithRunTimeScene(Scene):
685
+ def construct(self):
686
+ # A 5x5 grid of circles
687
+ circles = VGroup(
688
+ *[Circle(radius=0.5) for _ in range(25)]
689
+ ).arrange_in_grid(5, 5)
690
+
691
+ self.play(
692
+ Succession(
693
+ # Add a run_time of 0.2 to wait for 0.2 seconds after
694
+ # adding the circle, instead of using Wait(0.2) after Add!
695
+ *[Add(circle, run_time=0.2) for circle in circles],
696
+ rate_func=smooth,
697
+ )
698
+ )
699
+ self.wait()
700
+ """
701
+
702
+ def __init__(
703
+ self, *mobjects: Mobject, run_time: float = 0.0, **kwargs: Any
704
+ ) -> None:
705
+ mobject = mobjects[0] if len(mobjects) == 1 else Group(*mobjects)
706
+ super().__init__(mobject, run_time=run_time, introducer=True, **kwargs)
707
+
708
+ def begin(self) -> None:
709
+ pass
710
+
711
+ def finish(self) -> None:
712
+ pass
713
+
714
+ def clean_up_from_scene(self, scene: Scene) -> None:
715
+ pass
716
+
717
+ def update_mobjects(self, dt: float) -> None:
718
+ pass
719
+
720
+ def interpolate(self, alpha: float) -> None:
721
+ pass
722
+
723
+
578
724
  def override_animation(
579
725
  animation_class: type[Animation],
580
726
  ) -> Callable[[Callable], Callable]:
@@ -4,15 +4,23 @@ from __future__ import annotations
4
4
 
5
5
  __all__ = ["AnimatedBoundary", "TracedPath"]
6
6
 
7
- from typing import Callable
7
+ from collections.abc import Callable, Sequence
8
+ from typing import Any
8
9
 
9
- from colour import Color
10
+ from typing_extensions import Self
10
11
 
11
- from manim._config import config
12
+ from manim.mobject.mobject import Mobject
12
13
  from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL
13
14
  from manim.mobject.types.vectorized_mobject import VGroup, VMobject
14
- from manim.utils.color import BLUE_B, BLUE_D, BLUE_E, GREY_BROWN, WHITE
15
- from manim.utils.rate_functions import smooth
15
+ from manim.utils.color import (
16
+ BLUE_B,
17
+ BLUE_D,
18
+ BLUE_E,
19
+ GREY_BROWN,
20
+ WHITE,
21
+ ParsableManimColor,
22
+ )
23
+ from manim.utils.rate_functions import RateFunction, smooth
16
24
 
17
25
 
18
26
  class AnimatedBoundary(VGroup):
@@ -34,14 +42,14 @@ class AnimatedBoundary(VGroup):
34
42
 
35
43
  def __init__(
36
44
  self,
37
- vmobject,
38
- colors=[BLUE_D, BLUE_B, BLUE_E, GREY_BROWN],
39
- max_stroke_width=3,
40
- cycle_rate=0.5,
41
- back_and_forth=True,
42
- draw_rate_func=smooth,
43
- fade_rate_func=smooth,
44
- **kwargs,
45
+ vmobject: VMobject,
46
+ colors: Sequence[ParsableManimColor] = [BLUE_D, BLUE_B, BLUE_E, GREY_BROWN],
47
+ max_stroke_width: float = 3,
48
+ cycle_rate: float = 0.5,
49
+ back_and_forth: bool = True,
50
+ draw_rate_func: RateFunction = smooth,
51
+ fade_rate_func: RateFunction = smooth,
52
+ **kwargs: Any,
45
53
  ):
46
54
  super().__init__(**kwargs)
47
55
  self.colors = colors
@@ -55,10 +63,10 @@ class AnimatedBoundary(VGroup):
55
63
  vmobject.copy().set_style(stroke_width=0, fill_opacity=0) for x in range(2)
56
64
  ]
57
65
  self.add(*self.boundary_copies)
58
- self.total_time = 0
66
+ self.total_time = 0.0
59
67
  self.add_updater(lambda m, dt: self.update_boundary_copies(dt))
60
68
 
61
- def update_boundary_copies(self, dt):
69
+ def update_boundary_copies(self, dt: float) -> None:
62
70
  # Not actual time, but something which passes at
63
71
  # an altered rate to make the implementation below
64
72
  # cleaner
@@ -74,9 +82,9 @@ class AnimatedBoundary(VGroup):
74
82
  fade_alpha = self.fade_rate_func(alpha)
75
83
 
76
84
  if self.back_and_forth and int(time) % 2 == 1:
77
- bounds = (1 - draw_alpha, 1)
85
+ bounds = (1.0 - draw_alpha, 1.0)
78
86
  else:
79
- bounds = (0, draw_alpha)
87
+ bounds = (0.0, draw_alpha)
80
88
  self.full_family_become_partial(growing, vmobject, *bounds)
81
89
  growing.set_stroke(colors[index], width=msw)
82
90
 
@@ -86,7 +94,9 @@ class AnimatedBoundary(VGroup):
86
94
 
87
95
  self.total_time += dt
88
96
 
89
- def full_family_become_partial(self, mob1, mob2, a, b):
97
+ def full_family_become_partial(
98
+ self, mob1: VMobject, mob2: VMobject, a: float, b: float
99
+ ) -> Self:
90
100
  family1 = mob1.family_members_with_points()
91
101
  family2 = mob2.family_members_with_points()
92
102
  for sm1, sm2 in zip(family1, family2):
@@ -140,22 +150,23 @@ class TracedPath(VMobject, metaclass=ConvertToOpenGL):
140
150
  self,
141
151
  traced_point_func: Callable,
142
152
  stroke_width: float = 2,
143
- stroke_color: Color = WHITE,
153
+ stroke_color: ParsableManimColor | None = WHITE,
144
154
  dissipating_time: float | None = None,
145
- **kwargs,
146
- ):
155
+ **kwargs: Any,
156
+ ) -> None:
147
157
  super().__init__(stroke_color=stroke_color, stroke_width=stroke_width, **kwargs)
148
158
  self.traced_point_func = traced_point_func
149
159
  self.dissipating_time = dissipating_time
150
- self.time = 1 if self.dissipating_time else None
160
+ self.time = 1.0 if self.dissipating_time else None
151
161
  self.add_updater(self.update_path)
152
162
 
153
- def update_path(self, mob, dt):
163
+ def update_path(self, mob: Mobject, dt: float) -> None:
154
164
  new_point = self.traced_point_func()
155
165
  if not self.has_points():
156
166
  self.start_new_path(new_point)
157
167
  self.add_line_to(new_point)
158
168
  if self.dissipating_time:
169
+ assert self.time is not None
159
170
  self.time += dt
160
171
  if self.time - 1 > self.dissipating_time:
161
172
  nppcc = self.n_points_per_curve