manim 0.17.3__py3-none-any.whl → 0.18.0.post0__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.

Potentially problematic release.


This version of manim might be problematic. Click here for more details.

Files changed (84) hide show
  1. manim/__init__.py +1 -0
  2. manim/__main__.py +2 -0
  3. manim/_config/__init__.py +0 -1
  4. manim/_config/logger_utils.py +1 -0
  5. manim/_config/utils.py +14 -5
  6. manim/animation/changing.py +9 -5
  7. manim/animation/creation.py +8 -3
  8. manim/animation/indication.py +4 -4
  9. manim/animation/speedmodifier.py +2 -4
  10. manim/animation/updaters/mobject_update_utils.py +134 -16
  11. manim/camera/camera.py +31 -17
  12. manim/cli/checkhealth/__init__.py +0 -0
  13. manim/cli/checkhealth/checks.py +173 -0
  14. manim/cli/checkhealth/commands.py +81 -0
  15. manim/cli/render/global_options.py +6 -0
  16. manim/constants.py +58 -54
  17. manim/mobject/geometry/__init__.py +1 -0
  18. manim/mobject/geometry/arc.py +126 -91
  19. manim/mobject/geometry/boolean_ops.py +6 -10
  20. manim/mobject/geometry/labeled.py +155 -0
  21. manim/mobject/geometry/line.py +66 -50
  22. manim/mobject/geometry/polygram.py +23 -15
  23. manim/mobject/geometry/shape_matchers.py +24 -15
  24. manim/mobject/geometry/tips.py +62 -40
  25. manim/mobject/graph.py +3 -4
  26. manim/mobject/graphing/coordinate_systems.py +190 -139
  27. manim/mobject/graphing/number_line.py +5 -2
  28. manim/mobject/graphing/probability.py +4 -3
  29. manim/mobject/graphing/scale.py +7 -7
  30. manim/mobject/logo.py +108 -22
  31. manim/mobject/matrix.py +33 -37
  32. manim/mobject/mobject.py +327 -260
  33. manim/mobject/opengl/opengl_image_mobject.py +1 -1
  34. manim/mobject/opengl/opengl_mobject.py +18 -12
  35. manim/mobject/opengl/opengl_point_cloud_mobject.py +1 -1
  36. manim/mobject/opengl/opengl_surface.py +1 -1
  37. manim/mobject/opengl/opengl_vectorized_mobject.py +21 -17
  38. manim/mobject/svg/brace.py +3 -1
  39. manim/mobject/svg/svg_mobject.py +9 -11
  40. manim/mobject/table.py +50 -54
  41. manim/mobject/text/numbers.py +48 -6
  42. manim/mobject/text/tex_mobject.py +8 -12
  43. manim/mobject/text/text_mobject.py +32 -24
  44. manim/mobject/three_d/three_d_utils.py +13 -8
  45. manim/mobject/three_d/three_dimensions.py +61 -43
  46. manim/mobject/types/image_mobject.py +5 -4
  47. manim/mobject/types/point_cloud_mobject.py +8 -6
  48. manim/mobject/types/vectorized_mobject.py +385 -258
  49. manim/mobject/vector_field.py +19 -11
  50. manim/plugins/import_plugins.py +1 -1
  51. manim/plugins/plugins_flags.py +1 -6
  52. manim/renderer/shader.py +2 -2
  53. manim/scene/scene.py +15 -7
  54. manim/scene/scene_file_writer.py +1 -2
  55. manim/scene/three_d_scene.py +1 -1
  56. manim/scene/vector_space_scene.py +17 -7
  57. manim/typing.py +133 -0
  58. manim/utils/bezier.py +267 -83
  59. manim/utils/color/AS2700.py +234 -0
  60. manim/utils/color/BS381.py +315 -0
  61. manim/utils/color/X11.py +530 -0
  62. manim/utils/color/XKCD.py +949 -0
  63. manim/utils/color/__init__.py +58 -0
  64. manim/utils/color/core.py +1036 -0
  65. manim/utils/color/manim_colors.py +220 -0
  66. manim/utils/docbuild/autocolor_directive.py +92 -0
  67. manim/utils/docbuild/manim_directive.py +40 -6
  68. manim/utils/file_ops.py +1 -1
  69. manim/utils/hashing.py +1 -1
  70. manim/utils/iterables.py +1 -1
  71. manim/utils/rate_functions.py +33 -0
  72. manim/utils/simple_functions.py +0 -18
  73. manim/utils/space_ops.py +55 -42
  74. manim/utils/testing/frames_comparison.py +9 -0
  75. manim/utils/tex.py +2 -0
  76. manim/utils/tex_file_writing.py +29 -2
  77. {manim-0.17.3.dist-info → manim-0.18.0.post0.dist-info}/METADATA +14 -14
  78. {manim-0.17.3.dist-info → manim-0.18.0.post0.dist-info}/RECORD +82 -71
  79. {manim-0.17.3.dist-info → manim-0.18.0.post0.dist-info}/WHEEL +1 -1
  80. manim/communitycolors.py +0 -9
  81. manim/utils/color.py +0 -552
  82. {manim-0.17.3.dist-info → manim-0.18.0.post0.dist-info}/LICENSE +0 -0
  83. {manim-0.17.3.dist-info → manim-0.18.0.post0.dist-info}/LICENSE.community +0 -0
  84. {manim-0.17.3.dist-info → manim-0.18.0.post0.dist-info}/entry_points.txt +0 -0
manim/mobject/mobject.py CHANGED
@@ -1,35 +1,25 @@
1
1
  """Base classes for objects that can be displayed."""
2
+
2
3
  from __future__ import annotations
3
4
 
4
5
  __all__ = ["Mobject", "Group", "override_animate"]
5
6
 
6
7
 
7
8
  import copy
9
+ import inspect
8
10
  import itertools as it
11
+ import math
9
12
  import operator as op
10
13
  import random
11
14
  import sys
12
15
  import types
13
16
  import warnings
14
17
  from functools import partialmethod, reduce
15
- from math import ceil
16
18
  from pathlib import Path
17
- from typing import (
18
- TYPE_CHECKING,
19
- Callable,
20
- Dict,
21
- Iterable,
22
- List,
23
- Optional,
24
- Sequence,
25
- Tuple,
26
- Type,
27
- TypeVar,
28
- Union,
29
- )
19
+ from typing import TYPE_CHECKING, Callable, Iterable, Literal, TypeVar, Union
30
20
 
31
21
  import numpy as np
32
- from colour import Color
22
+ from typing_extensions import Self, TypeAlias
33
23
 
34
24
  from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL
35
25
 
@@ -39,22 +29,37 @@ from ..utils.color import (
39
29
  BLACK,
40
30
  WHITE,
41
31
  YELLOW_C,
42
- Colors,
32
+ ManimColor,
33
+ ParsableManimColor,
43
34
  color_gradient,
44
35
  interpolate_color,
45
36
  )
46
37
  from ..utils.exceptions import MultiAnimationOverrideException
47
38
  from ..utils.iterables import list_update, remove_list_redundancies
48
39
  from ..utils.paths import straight_path
49
- from ..utils.simple_functions import get_parameters
50
40
  from ..utils.space_ops import angle_between_vectors, normalize, rotation_matrix
51
41
 
52
42
  # TODO: Explain array_attrs
53
43
 
54
- Updater = Union[Callable[["Mobject"], None], Callable[["Mobject", float], None]]
44
+ TimeBasedUpdater: TypeAlias = Callable[["Mobject", float], None]
45
+ NonTimeBasedUpdater: TypeAlias = Callable[["Mobject"], None]
46
+ Updater: TypeAlias = Union[NonTimeBasedUpdater, TimeBasedUpdater]
55
47
  T = TypeVar("T", bound="Mobject")
56
48
 
57
49
  if TYPE_CHECKING:
50
+ from manim.typing import (
51
+ FunctionOverride,
52
+ Image,
53
+ ManimFloat,
54
+ ManimInt,
55
+ MappingFunction,
56
+ PathFuncType,
57
+ Point3D,
58
+ Point3D_Array,
59
+ Vector,
60
+ Vector3,
61
+ )
62
+
58
63
  from ..animation.animation import Animation
59
64
 
60
65
 
@@ -81,26 +86,33 @@ class Mobject:
81
86
  animation_overrides = {}
82
87
 
83
88
  @classmethod
84
- def __init_subclass__(cls, **kwargs):
89
+ def __init_subclass__(cls, **kwargs) -> None:
85
90
  super().__init_subclass__(**kwargs)
86
91
 
87
92
  cls.animation_overrides: dict[
88
93
  type[Animation],
89
- Callable[[Mobject], Animation],
94
+ FunctionOverride,
90
95
  ] = {}
91
96
  cls._add_intrinsic_animation_overrides()
92
97
  cls._original__init__ = cls.__init__
93
98
 
94
- def __init__(self, color=WHITE, name=None, dim=3, target=None, z_index=0):
99
+ def __init__(
100
+ self,
101
+ color: ParsableManimColor | list[ParsableManimColor] = WHITE,
102
+ name: str | None = None,
103
+ dim: int = 3,
104
+ target=None,
105
+ z_index: float = 0,
106
+ ) -> None:
95
107
  self.name = self.__class__.__name__ if name is None else name
96
108
  self.dim = dim
97
109
  self.target = target
98
110
  self.z_index = z_index
99
111
  self.point_hash = None
100
112
  self.submobjects = []
101
- self.updaters = []
113
+ self.updaters: list[Updater] = []
102
114
  self.updating_suspended = False
103
- self.color = Color(color) if color else None
115
+ self.color = ManimColor.parse(color)
104
116
 
105
117
  self.reset_points()
106
118
  self.generate_points()
@@ -110,7 +122,7 @@ class Mobject:
110
122
  def animation_override_for(
111
123
  cls,
112
124
  animation_class: type[Animation],
113
- ) -> Callable[[Mobject, ...], Animation] | None:
125
+ ) -> FunctionOverride | None:
114
126
  """Returns the function defining a specific animation override for this class.
115
127
 
116
128
  Parameters
@@ -130,7 +142,7 @@ class Mobject:
130
142
  return None
131
143
 
132
144
  @classmethod
133
- def _add_intrinsic_animation_overrides(cls):
145
+ def _add_intrinsic_animation_overrides(cls) -> None:
134
146
  """Initializes animation overrides marked with the :func:`~.override_animation`
135
147
  decorator.
136
148
  """
@@ -148,8 +160,8 @@ class Mobject:
148
160
  def add_animation_override(
149
161
  cls,
150
162
  animation_class: type[Animation],
151
- override_func: Callable[[Mobject, ...], Animation],
152
- ):
163
+ override_func: FunctionOverride,
164
+ ) -> None:
153
165
  """Add an animation override.
154
166
 
155
167
  This does not apply to subclasses.
@@ -160,7 +172,7 @@ class Mobject:
160
172
  The animation type to be overridden
161
173
  override_func
162
174
  The function returning an animation replacing the default animation. It gets
163
- passed the parameters given to the animnation constructor.
175
+ passed the parameters given to the animation constructor.
164
176
 
165
177
  Raises
166
178
  ------
@@ -178,7 +190,7 @@ class Mobject:
178
190
  )
179
191
 
180
192
  @classmethod
181
- def set_default(cls, **kwargs):
193
+ def set_default(cls, **kwargs) -> None:
182
194
  """Sets the default values of keyword arguments.
183
195
 
184
196
  If this method is called without any additional keyword
@@ -201,10 +213,10 @@ class Mobject:
201
213
  >>> from manim import Square, GREEN
202
214
  >>> Square.set_default(color=GREEN, fill_opacity=0.25)
203
215
  >>> s = Square(); s.color, s.fill_opacity
204
- (<Color #83c167>, 0.25)
216
+ (ManimColor('#83C167'), 0.25)
205
217
  >>> Square.set_default()
206
218
  >>> s = Square(); s.color, s.fill_opacity
207
- (<Color white>, 0.0)
219
+ (ManimColor('#FFFFFF'), 0.0)
208
220
 
209
221
  .. manim:: ChangedDefaultTextcolor
210
222
  :save_last_frame:
@@ -323,7 +335,7 @@ class Mobject:
323
335
  """
324
336
  return _AnimationBuilder(self)
325
337
 
326
- def __deepcopy__(self, clone_from_id):
338
+ def __deepcopy__(self, clone_from_id) -> Self:
327
339
  cls = self.__class__
328
340
  result = cls.__new__(cls)
329
341
  clone_from_id[id(self)] = result
@@ -332,30 +344,28 @@ class Mobject:
332
344
  result.original_id = str(id(self))
333
345
  return result
334
346
 
335
- def __repr__(self):
347
+ def __repr__(self) -> str:
336
348
  return str(self.name)
337
349
 
338
- def reset_points(self):
350
+ def reset_points(self) -> None:
339
351
  """Sets :attr:`points` to be an empty array."""
340
352
  self.points = np.zeros((0, self.dim))
341
353
 
342
- def init_colors(self):
354
+ def init_colors(self) -> None:
343
355
  """Initializes the colors.
344
356
 
345
357
  Gets called upon creation. This is an empty method that can be implemented by
346
358
  subclasses.
347
359
  """
348
- pass
349
360
 
350
- def generate_points(self):
361
+ def generate_points(self) -> None:
351
362
  """Initializes :attr:`points` and therefore the shape.
352
363
 
353
364
  Gets called upon creation. This is an empty method that can be implemented by
354
365
  subclasses.
355
366
  """
356
- pass
357
367
 
358
- def add(self, *mobjects: Mobject):
368
+ def add(self, *mobjects: Mobject) -> Self:
359
369
  """Add mobjects as submobjects.
360
370
 
361
371
  The mobjects are added to :attr:`submobjects`.
@@ -441,7 +451,7 @@ class Mobject:
441
451
  self.submobjects = list_update(self.submobjects, unique_mobjects)
442
452
  return self
443
453
 
444
- def insert(self, index: int, mobject: Mobject):
454
+ def insert(self, index: int, mobject: Mobject) -> None:
445
455
  """Inserts a mobject at a specific position into self.submobjects
446
456
 
447
457
  Effectively just calls ``self.submobjects.insert(index, mobject)``,
@@ -462,13 +472,13 @@ class Mobject:
462
472
  raise ValueError("Mobject cannot contain self")
463
473
  self.submobjects.insert(index, mobject)
464
474
 
465
- def __add__(self, mobject):
475
+ def __add__(self, mobject: Mobject):
466
476
  raise NotImplementedError
467
477
 
468
- def __iadd__(self, mobject):
478
+ def __iadd__(self, mobject: Mobject):
469
479
  raise NotImplementedError
470
480
 
471
- def add_to_back(self, *mobjects: Mobject):
481
+ def add_to_back(self, *mobjects: Mobject) -> Self:
472
482
  """Add all passed mobjects to the back of the submobjects.
473
483
 
474
484
  If :attr:`submobjects` already contains the given mobjects, they just get moved
@@ -524,7 +534,7 @@ class Mobject:
524
534
  self.submobjects = list(dict.fromkeys(mobjects)) + self.submobjects
525
535
  return self
526
536
 
527
- def remove(self, *mobjects: Mobject):
537
+ def remove(self, *mobjects: Mobject) -> Self:
528
538
  """Remove :attr:`submobjects`.
529
539
 
530
540
  The mobjects are removed from :attr:`submobjects`, if they exist.
@@ -557,7 +567,7 @@ class Mobject:
557
567
  def __isub__(self, other):
558
568
  raise NotImplementedError
559
569
 
560
- def set(self, **kwargs):
570
+ def set(self, **kwargs) -> Self:
561
571
  """Sets attributes.
562
572
 
563
573
  I.e. ``my_mobject.set(foo=1)`` applies ``my_mobject.foo = 1``.
@@ -614,7 +624,7 @@ class Mobject:
614
624
 
615
625
  return self
616
626
 
617
- def __getattr__(self, attr):
627
+ def __getattr__(self, attr: str) -> types.MethodType:
618
628
  # Add automatic compatibility layer
619
629
  # between properties and get_* and set_*
620
630
  # methods.
@@ -662,7 +672,7 @@ class Mobject:
662
672
  raise AttributeError(f"{type(self).__name__} object has no attribute '{attr}'")
663
673
 
664
674
  @property
665
- def width(self):
675
+ def width(self) -> float:
666
676
  """The width of the mobject.
667
677
 
668
678
  Returns
@@ -695,11 +705,11 @@ class Mobject:
695
705
  return self.length_over_dim(0)
696
706
 
697
707
  @width.setter
698
- def width(self, value):
708
+ def width(self, value: float):
699
709
  self.scale_to_fit_width(value)
700
710
 
701
711
  @property
702
- def height(self):
712
+ def height(self) -> float:
703
713
  """The height of the mobject.
704
714
 
705
715
  Returns
@@ -732,11 +742,11 @@ class Mobject:
732
742
  return self.length_over_dim(1)
733
743
 
734
744
  @height.setter
735
- def height(self, value):
745
+ def height(self, value: float):
736
746
  self.scale_to_fit_height(value)
737
747
 
738
748
  @property
739
- def depth(self):
749
+ def depth(self) -> float:
740
750
  """The depth of the mobject.
741
751
 
742
752
  Returns
@@ -753,20 +763,21 @@ class Mobject:
753
763
  return self.length_over_dim(2)
754
764
 
755
765
  @depth.setter
756
- def depth(self, value):
766
+ def depth(self, value: float):
757
767
  self.scale_to_fit_depth(value)
758
768
 
759
- def get_array_attrs(self):
769
+ # Can't be staticmethod because of point_cloud_mobject.py
770
+ def get_array_attrs(self) -> list[Literal["points"]]:
760
771
  return ["points"]
761
772
 
762
- def apply_over_attr_arrays(self, func):
773
+ def apply_over_attr_arrays(self, func: MappingFunction) -> Self:
763
774
  for attr in self.get_array_attrs():
764
775
  setattr(self, attr, func(getattr(self, attr)))
765
776
  return self
766
777
 
767
778
  # Displaying
768
779
 
769
- def get_image(self, camera=None):
780
+ def get_image(self, camera=None) -> Image:
770
781
  if camera is None:
771
782
  from ..camera.camera import Camera
772
783
 
@@ -774,17 +785,17 @@ class Mobject:
774
785
  camera.capture_mobject(self)
775
786
  return camera.get_image()
776
787
 
777
- def show(self, camera=None):
788
+ def show(self, camera=None) -> None:
778
789
  self.get_image(camera=camera).show()
779
790
 
780
- def save_image(self, name=None):
791
+ def save_image(self, name: str | None = None) -> None:
781
792
  """Saves an image of only this :class:`Mobject` at its position to a png
782
793
  file."""
783
794
  self.get_image().save(
784
795
  Path(config.get_dir("video_dir")).joinpath((name or str(self)) + ".png"),
785
796
  )
786
797
 
787
- def copy(self: T) -> T:
798
+ def copy(self) -> Self:
788
799
  """Create and return an identical copy of the :class:`Mobject` including all
789
800
  :attr:`submobjects`.
790
801
 
@@ -799,7 +810,7 @@ class Mobject:
799
810
  """
800
811
  return copy.deepcopy(self)
801
812
 
802
- def generate_target(self, use_deepcopy=False):
813
+ def generate_target(self, use_deepcopy: bool = False) -> Self:
803
814
  self.target = None # Prevent unbounded linear recursion
804
815
  if use_deepcopy:
805
816
  self.target = copy.deepcopy(self)
@@ -809,7 +820,7 @@ class Mobject:
809
820
 
810
821
  # Updating
811
822
 
812
- def update(self, dt: float = 0, recursive: bool = True):
823
+ def update(self, dt: float = 0, recursive: bool = True) -> Self:
813
824
  """Apply all updaters.
814
825
 
815
826
  Does nothing if updating is suspended.
@@ -836,8 +847,7 @@ class Mobject:
836
847
  if self.updating_suspended:
837
848
  return self
838
849
  for updater in self.updaters:
839
- parameters = get_parameters(updater)
840
- if "dt" in parameters:
850
+ if "dt" in inspect.signature(updater).parameters:
841
851
  updater(self, dt)
842
852
  else:
843
853
  updater(self)
@@ -846,7 +856,7 @@ class Mobject:
846
856
  submob.update(dt, recursive)
847
857
  return self
848
858
 
849
- def get_time_based_updaters(self) -> list[Updater]:
859
+ def get_time_based_updaters(self) -> list[TimeBasedUpdater]:
850
860
  """Return all updaters using the ``dt`` parameter.
851
861
 
852
862
  The updaters use this parameter as the input for difference in time.
@@ -862,7 +872,11 @@ class Mobject:
862
872
  :meth:`has_time_based_updater`
863
873
 
864
874
  """
865
- return [updater for updater in self.updaters if "dt" in get_parameters(updater)]
875
+ return [
876
+ updater
877
+ for updater in self.updaters
878
+ if "dt" in inspect.signature(updater).parameters
879
+ ]
866
880
 
867
881
  def has_time_based_updater(self) -> bool:
868
882
  """Test if ``self`` has a time based updater.
@@ -878,7 +892,9 @@ class Mobject:
878
892
  :meth:`get_time_based_updaters`
879
893
 
880
894
  """
881
- return any("dt" in get_parameters(updater) for updater in self.updaters)
895
+ return any(
896
+ "dt" in inspect.signature(updater).parameters for updater in self.updaters
897
+ )
882
898
 
883
899
  def get_updaters(self) -> list[Updater]:
884
900
  """Return all updaters.
@@ -896,7 +912,7 @@ class Mobject:
896
912
  """
897
913
  return self.updaters
898
914
 
899
- def get_family_updaters(self):
915
+ def get_family_updaters(self) -> list[Updater]:
900
916
  return list(it.chain(*(sm.get_updaters() for sm in self.get_family())))
901
917
 
902
918
  def add_updater(
@@ -904,7 +920,7 @@ class Mobject:
904
920
  update_function: Updater,
905
921
  index: int | None = None,
906
922
  call_updater: bool = False,
907
- ):
923
+ ) -> Self:
908
924
  """Add an update function to this mobject.
909
925
 
910
926
  Update functions, or updaters in short, are functions that are applied to the
@@ -971,14 +987,14 @@ class Mobject:
971
987
  else:
972
988
  self.updaters.insert(index, update_function)
973
989
  if call_updater:
974
- parameters = get_parameters(update_function)
990
+ parameters = inspect.signature(update_function).parameters
975
991
  if "dt" in parameters:
976
992
  update_function(self, 0)
977
993
  else:
978
994
  update_function(self)
979
995
  return self
980
996
 
981
- def remove_updater(self, update_function: Updater):
997
+ def remove_updater(self, update_function: Updater) -> Self:
982
998
  """Remove an updater.
983
999
 
984
1000
  If the same updater is applied multiple times, every instance gets removed.
@@ -1005,7 +1021,7 @@ class Mobject:
1005
1021
  self.updaters.remove(update_function)
1006
1022
  return self
1007
1023
 
1008
- def clear_updaters(self, recursive: bool = True):
1024
+ def clear_updaters(self, recursive: bool = True) -> Self:
1009
1025
  """Remove every updater.
1010
1026
 
1011
1027
  Parameters
@@ -1031,7 +1047,7 @@ class Mobject:
1031
1047
  submob.clear_updaters()
1032
1048
  return self
1033
1049
 
1034
- def match_updaters(self, mobject: Mobject):
1050
+ def match_updaters(self, mobject: Mobject) -> Self:
1035
1051
  """Match the updaters of the given mobject.
1036
1052
 
1037
1053
  Parameters
@@ -1061,7 +1077,7 @@ class Mobject:
1061
1077
  self.add_updater(updater)
1062
1078
  return self
1063
1079
 
1064
- def suspend_updating(self, recursive: bool = True):
1080
+ def suspend_updating(self, recursive: bool = True) -> Self:
1065
1081
  """Disable updating from updaters and animations.
1066
1082
 
1067
1083
 
@@ -1088,7 +1104,7 @@ class Mobject:
1088
1104
  submob.suspend_updating(recursive)
1089
1105
  return self
1090
1106
 
1091
- def resume_updating(self, recursive: bool = True):
1107
+ def resume_updating(self, recursive: bool = True) -> Self:
1092
1108
  """Enable updating from updaters and animations.
1093
1109
 
1094
1110
  Parameters
@@ -1116,7 +1132,7 @@ class Mobject:
1116
1132
 
1117
1133
  # Transforming operations
1118
1134
 
1119
- def apply_to_family(self, func: Callable[[Mobject], None]):
1135
+ def apply_to_family(self, func: Callable[[Mobject], None]) -> None:
1120
1136
  """Apply a function to ``self`` and every submobject with points recursively.
1121
1137
 
1122
1138
  Parameters
@@ -1138,7 +1154,7 @@ class Mobject:
1138
1154
  for mob in self.family_members_with_points():
1139
1155
  func(mob)
1140
1156
 
1141
- def shift(self, *vectors: np.ndarray):
1157
+ def shift(self, *vectors: Vector3) -> Self:
1142
1158
  """Shift by the given vectors.
1143
1159
 
1144
1160
  Parameters
@@ -1164,7 +1180,7 @@ class Mobject:
1164
1180
 
1165
1181
  return self
1166
1182
 
1167
- def scale(self, scale_factor: float, **kwargs):
1183
+ def scale(self, scale_factor: float, **kwargs) -> Self:
1168
1184
  r"""Scale the size by a factor.
1169
1185
 
1170
1186
  Default behavior is to scale about the center of the mobject.
@@ -1210,17 +1226,17 @@ class Mobject:
1210
1226
  )
1211
1227
  return self
1212
1228
 
1213
- def rotate_about_origin(self, angle, axis=OUT, axes=[]):
1229
+ def rotate_about_origin(self, angle: float, axis: Vector3 = OUT, axes=[]) -> Self:
1214
1230
  """Rotates the :class:`~.Mobject` about the ORIGIN, which is at [0,0,0]."""
1215
1231
  return self.rotate(angle, axis, about_point=ORIGIN)
1216
1232
 
1217
1233
  def rotate(
1218
1234
  self,
1219
- angle,
1220
- axis=OUT,
1221
- about_point: Sequence[float] | None = None,
1235
+ angle: float,
1236
+ axis: Vector3 = OUT,
1237
+ about_point: Point3D | None = None,
1222
1238
  **kwargs,
1223
- ):
1239
+ ) -> Self:
1224
1240
  """Rotates the :class:`~.Mobject` about a certain point."""
1225
1241
  rot_matrix = rotation_matrix(angle, axis)
1226
1242
  self.apply_points_function_about_point(
@@ -1228,7 +1244,7 @@ class Mobject:
1228
1244
  )
1229
1245
  return self
1230
1246
 
1231
- def flip(self, axis=UP, **kwargs):
1247
+ def flip(self, axis: Vector3 = UP, **kwargs) -> Self:
1232
1248
  """Flips/Mirrors an mobject about its center.
1233
1249
 
1234
1250
  Examples
@@ -1247,7 +1263,7 @@ class Mobject:
1247
1263
  """
1248
1264
  return self.rotate(TAU / 2, axis, **kwargs)
1249
1265
 
1250
- def stretch(self, factor, dim, **kwargs):
1266
+ def stretch(self, factor: float, dim: int, **kwargs) -> Self:
1251
1267
  def func(points):
1252
1268
  points[:, dim] *= factor
1253
1269
  return points
@@ -1255,7 +1271,7 @@ class Mobject:
1255
1271
  self.apply_points_function_about_point(func, **kwargs)
1256
1272
  return self
1257
1273
 
1258
- def apply_function(self, function, **kwargs):
1274
+ def apply_function(self, function: MappingFunction, **kwargs) -> Self:
1259
1275
  # Default to applying matrix about the origin, not mobjects center
1260
1276
  if len(kwargs) == 0:
1261
1277
  kwargs["about_point"] = ORIGIN
@@ -1264,16 +1280,16 @@ class Mobject:
1264
1280
  )
1265
1281
  return self
1266
1282
 
1267
- def apply_function_to_position(self, function):
1283
+ def apply_function_to_position(self, function: MappingFunction) -> Self:
1268
1284
  self.move_to(function(self.get_center()))
1269
1285
  return self
1270
1286
 
1271
- def apply_function_to_submobject_positions(self, function):
1287
+ def apply_function_to_submobject_positions(self, function: MappingFunction) -> Self:
1272
1288
  for submob in self.submobjects:
1273
1289
  submob.apply_function_to_position(function)
1274
1290
  return self
1275
1291
 
1276
- def apply_matrix(self, matrix, **kwargs):
1292
+ def apply_matrix(self, matrix, **kwargs) -> Self:
1277
1293
  # Default to applying matrix about the origin, not mobjects center
1278
1294
  if ("about_point" not in kwargs) and ("about_edge" not in kwargs):
1279
1295
  kwargs["about_point"] = ORIGIN
@@ -1285,9 +1301,11 @@ class Mobject:
1285
1301
  )
1286
1302
  return self
1287
1303
 
1288
- def apply_complex_function(self, function, **kwargs):
1304
+ def apply_complex_function(
1305
+ self, function: Callable[[complex], complex], **kwargs
1306
+ ) -> Self:
1289
1307
  """Applies a complex function to a :class:`Mobject`.
1290
- The x and y coordinates correspond to the real and imaginary parts respectively.
1308
+ The x and y Point3Ds correspond to the real and imaginary parts respectively.
1291
1309
 
1292
1310
  Example
1293
1311
  -------
@@ -1319,7 +1337,9 @@ class Mobject:
1319
1337
 
1320
1338
  return self.apply_function(R3_func)
1321
1339
 
1322
- def wag(self, direction=RIGHT, axis=DOWN, wag_factor=1.0):
1340
+ def wag(
1341
+ self, direction: Vector3 = RIGHT, axis: Vector3 = DOWN, wag_factor: float = 1.0
1342
+ ) -> Self:
1323
1343
  for mob in self.family_members_with_points():
1324
1344
  alphas = np.dot(mob.points, np.transpose(axis))
1325
1345
  alphas -= min(alphas)
@@ -1331,12 +1351,12 @@ class Mobject:
1331
1351
  )
1332
1352
  return self
1333
1353
 
1334
- def reverse_points(self):
1354
+ def reverse_points(self) -> Self:
1335
1355
  for mob in self.family_members_with_points():
1336
1356
  mob.apply_over_attr_arrays(lambda arr: np.array(list(reversed(arr))))
1337
1357
  return self
1338
1358
 
1339
- def repeat(self, count: int):
1359
+ def repeat(self, count: int) -> Self:
1340
1360
  """This can make transition animations nicer"""
1341
1361
 
1342
1362
  def repeat_array(array):
@@ -1352,10 +1372,10 @@ class Mobject:
1352
1372
 
1353
1373
  def apply_points_function_about_point(
1354
1374
  self,
1355
- func,
1356
- about_point=None,
1375
+ func: MappingFunction,
1376
+ about_point: Point3D = None,
1357
1377
  about_edge=None,
1358
- ):
1378
+ ) -> Self:
1359
1379
  if about_point is None:
1360
1380
  if about_edge is None:
1361
1381
  about_edge = ORIGIN
@@ -1372,11 +1392,20 @@ class Mobject:
1372
1392
 
1373
1393
  # Positioning methods
1374
1394
 
1375
- def center(self):
1395
+ def center(self) -> Self:
1396
+ """Moves the center of the mobject to the center of the scene.
1397
+
1398
+ Returns
1399
+ -------
1400
+ :class:`.Mobject`
1401
+ The centered mobject.
1402
+ """
1376
1403
  self.shift(-self.get_center())
1377
1404
  return self
1378
1405
 
1379
- def align_on_border(self, direction, buff=DEFAULT_MOBJECT_TO_EDGE_BUFFER):
1406
+ def align_on_border(
1407
+ self, direction: Vector3, buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER
1408
+ ) -> Self:
1380
1409
  """Direction just needs to be a vector pointing towards side or
1381
1410
  corner in the 2d plane.
1382
1411
  """
@@ -1391,23 +1420,27 @@ class Mobject:
1391
1420
  self.shift(shift_val)
1392
1421
  return self
1393
1422
 
1394
- def to_corner(self, corner=LEFT + DOWN, buff=DEFAULT_MOBJECT_TO_EDGE_BUFFER):
1423
+ def to_corner(
1424
+ self, corner: Vector3 = DL, buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER
1425
+ ) -> Self:
1395
1426
  return self.align_on_border(corner, buff)
1396
1427
 
1397
- def to_edge(self, edge=LEFT, buff=DEFAULT_MOBJECT_TO_EDGE_BUFFER):
1428
+ def to_edge(
1429
+ self, edge: Vector3 = LEFT, buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER
1430
+ ) -> Self:
1398
1431
  return self.align_on_border(edge, buff)
1399
1432
 
1400
1433
  def next_to(
1401
1434
  self,
1402
- mobject_or_point,
1403
- direction=RIGHT,
1404
- buff=DEFAULT_MOBJECT_TO_MOBJECT_BUFFER,
1405
- aligned_edge=ORIGIN,
1406
- submobject_to_align=None,
1407
- index_of_submobject_to_align=None,
1408
- coor_mask=np.array([1, 1, 1]),
1409
- ):
1410
- """Move this :class:`~.Mobject` next to another's :class:`~.Mobject` or coordinate.
1435
+ mobject_or_point: Mobject | Point3D,
1436
+ direction: Vector3 = RIGHT,
1437
+ buff: float = DEFAULT_MOBJECT_TO_MOBJECT_BUFFER,
1438
+ aligned_edge: Vector3 = ORIGIN,
1439
+ submobject_to_align: Mobject | None = None,
1440
+ index_of_submobject_to_align: int | None = None,
1441
+ coor_mask: Vector3 = np.array([1, 1, 1]),
1442
+ ) -> Self:
1443
+ """Move this :class:`~.Mobject` next to another's :class:`~.Mobject` or Point3D.
1411
1444
 
1412
1445
  Examples
1413
1446
  --------
@@ -1446,7 +1479,7 @@ class Mobject:
1446
1479
  self.shift((target_point - point_to_align + buff * direction) * coor_mask)
1447
1480
  return self
1448
1481
 
1449
- def shift_onto_screen(self, **kwargs):
1482
+ def shift_onto_screen(self, **kwargs) -> Self:
1450
1483
  space_lengths = [config["frame_x_radius"], config["frame_y_radius"]]
1451
1484
  for vect in UP, DOWN, LEFT, RIGHT:
1452
1485
  dim = np.argmax(np.abs(vect))
@@ -1468,10 +1501,12 @@ class Mobject:
1468
1501
  return True
1469
1502
  return False
1470
1503
 
1471
- def stretch_about_point(self, factor, dim, point):
1504
+ def stretch_about_point(self, factor: float, dim: int, point: Point3D) -> Self:
1472
1505
  return self.stretch(factor, dim, about_point=point)
1473
1506
 
1474
- def rescale_to_fit(self, length, dim, stretch=False, **kwargs):
1507
+ def rescale_to_fit(
1508
+ self, length: float, dim: int, stretch: bool = False, **kwargs
1509
+ ) -> Self:
1475
1510
  old_length = self.length_over_dim(dim)
1476
1511
  if old_length == 0:
1477
1512
  return self
@@ -1481,7 +1516,7 @@ class Mobject:
1481
1516
  self.scale(length / old_length, **kwargs)
1482
1517
  return self
1483
1518
 
1484
- def scale_to_fit_width(self, width, **kwargs):
1519
+ def scale_to_fit_width(self, width: float, **kwargs) -> Self:
1485
1520
  """Scales the :class:`~.Mobject` to fit a width while keeping height/depth proportional.
1486
1521
 
1487
1522
  Returns
@@ -1507,7 +1542,7 @@ class Mobject:
1507
1542
 
1508
1543
  return self.rescale_to_fit(width, 0, stretch=False, **kwargs)
1509
1544
 
1510
- def stretch_to_fit_width(self, width, **kwargs):
1545
+ def stretch_to_fit_width(self, width: float, **kwargs) -> Self:
1511
1546
  """Stretches the :class:`~.Mobject` to fit a width, not keeping height/depth proportional.
1512
1547
 
1513
1548
  Returns
@@ -1533,7 +1568,7 @@ class Mobject:
1533
1568
 
1534
1569
  return self.rescale_to_fit(width, 0, stretch=True, **kwargs)
1535
1570
 
1536
- def scale_to_fit_height(self, height, **kwargs):
1571
+ def scale_to_fit_height(self, height: float, **kwargs) -> Self:
1537
1572
  """Scales the :class:`~.Mobject` to fit a height while keeping width/depth proportional.
1538
1573
 
1539
1574
  Returns
@@ -1559,7 +1594,7 @@ class Mobject:
1559
1594
 
1560
1595
  return self.rescale_to_fit(height, 1, stretch=False, **kwargs)
1561
1596
 
1562
- def stretch_to_fit_height(self, height, **kwargs):
1597
+ def stretch_to_fit_height(self, height: float, **kwargs) -> Self:
1563
1598
  """Stretches the :class:`~.Mobject` to fit a height, not keeping width/depth proportional.
1564
1599
 
1565
1600
  Returns
@@ -1585,36 +1620,36 @@ class Mobject:
1585
1620
 
1586
1621
  return self.rescale_to_fit(height, 1, stretch=True, **kwargs)
1587
1622
 
1588
- def scale_to_fit_depth(self, depth, **kwargs):
1623
+ def scale_to_fit_depth(self, depth: float, **kwargs) -> Self:
1589
1624
  """Scales the :class:`~.Mobject` to fit a depth while keeping width/height proportional."""
1590
1625
 
1591
1626
  return self.rescale_to_fit(depth, 2, stretch=False, **kwargs)
1592
1627
 
1593
- def stretch_to_fit_depth(self, depth, **kwargs):
1628
+ def stretch_to_fit_depth(self, depth: float, **kwargs) -> Self:
1594
1629
  """Stretches the :class:`~.Mobject` to fit a depth, not keeping width/height proportional."""
1595
1630
 
1596
1631
  return self.rescale_to_fit(depth, 2, stretch=True, **kwargs)
1597
1632
 
1598
- def set_coord(self, value, dim, direction=ORIGIN):
1633
+ def set_coord(self, value, dim: int, direction: Vector3 = ORIGIN) -> Self:
1599
1634
  curr = self.get_coord(dim, direction)
1600
1635
  shift_vect = np.zeros(self.dim)
1601
1636
  shift_vect[dim] = value - curr
1602
1637
  self.shift(shift_vect)
1603
1638
  return self
1604
1639
 
1605
- def set_x(self, x, direction=ORIGIN):
1640
+ def set_x(self, x: float, direction: Vector3 = ORIGIN) -> Self:
1606
1641
  """Set x value of the center of the :class:`~.Mobject` (``int`` or ``float``)"""
1607
1642
  return self.set_coord(x, 0, direction)
1608
1643
 
1609
- def set_y(self, y, direction=ORIGIN):
1644
+ def set_y(self, y: float, direction: Vector3 = ORIGIN) -> Self:
1610
1645
  """Set y value of the center of the :class:`~.Mobject` (``int`` or ``float``)"""
1611
1646
  return self.set_coord(y, 1, direction)
1612
1647
 
1613
- def set_z(self, z, direction=ORIGIN):
1648
+ def set_z(self, z: float, direction: Vector3 = ORIGIN) -> Self:
1614
1649
  """Set z value of the center of the :class:`~.Mobject` (``int`` or ``float``)"""
1615
1650
  return self.set_coord(z, 2, direction)
1616
1651
 
1617
- def space_out_submobjects(self, factor=1.5, **kwargs):
1652
+ def space_out_submobjects(self, factor: float = 1.5, **kwargs) -> Self:
1618
1653
  self.scale(factor, **kwargs)
1619
1654
  for submob in self.submobjects:
1620
1655
  submob.scale(1.0 / factor)
@@ -1622,11 +1657,11 @@ class Mobject:
1622
1657
 
1623
1658
  def move_to(
1624
1659
  self,
1625
- point_or_mobject,
1626
- aligned_edge=ORIGIN,
1627
- coor_mask=np.array([1, 1, 1]),
1628
- ):
1629
- """Move center of the :class:`~.Mobject` to certain coordinate."""
1660
+ point_or_mobject: Point3D | Mobject,
1661
+ aligned_edge: Vector3 = ORIGIN,
1662
+ coor_mask: Vector3 = np.array([1, 1, 1]),
1663
+ ) -> Self:
1664
+ """Move center of the :class:`~.Mobject` to certain Point3D."""
1630
1665
  if isinstance(point_or_mobject, Mobject):
1631
1666
  target = point_or_mobject.get_critical_point(aligned_edge)
1632
1667
  else:
@@ -1635,7 +1670,9 @@ class Mobject:
1635
1670
  self.shift((target - point_to_align) * coor_mask)
1636
1671
  return self
1637
1672
 
1638
- def replace(self, mobject, dim_to_match=0, stretch=False):
1673
+ def replace(
1674
+ self, mobject: Mobject, dim_to_match: int = 0, stretch: bool = False
1675
+ ) -> Self:
1639
1676
  if not mobject.get_num_points() and not mobject.submobjects:
1640
1677
  raise Warning("Attempting to replace mobject with no points")
1641
1678
  if stretch:
@@ -1653,16 +1690,16 @@ class Mobject:
1653
1690
  def surround(
1654
1691
  self,
1655
1692
  mobject: Mobject,
1656
- dim_to_match=0,
1657
- stretch=False,
1658
- buff=MED_SMALL_BUFF,
1659
- ):
1693
+ dim_to_match: int = 0,
1694
+ stretch: bool = False,
1695
+ buff: float = MED_SMALL_BUFF,
1696
+ ) -> Self:
1660
1697
  self.replace(mobject, dim_to_match, stretch)
1661
1698
  length = mobject.length_over_dim(dim_to_match)
1662
1699
  self.scale((length + buff) / length)
1663
1700
  return self
1664
1701
 
1665
- def put_start_and_end_on(self, start, end):
1702
+ def put_start_and_end_on(self, start: Point3D, end: Point3D) -> Self:
1666
1703
  curr_start, curr_end = self.get_start_and_end()
1667
1704
  curr_vect = curr_end - curr_start
1668
1705
  if np.all(curr_vect == 0):
@@ -1687,8 +1724,8 @@ class Mobject:
1687
1724
 
1688
1725
  # Background rectangle
1689
1726
  def add_background_rectangle(
1690
- self, color: Colors | None = None, opacity: float = 0.75, **kwargs
1691
- ):
1727
+ self, color: ParsableManimColor | None = None, opacity: float = 0.75, **kwargs
1728
+ ) -> Self:
1692
1729
  """Add a BackgroundRectangle as submobject.
1693
1730
 
1694
1731
  The BackgroundRectangle is added behind other submobjects.
@@ -1727,19 +1764,21 @@ class Mobject:
1727
1764
  self.add_to_back(self.background_rectangle)
1728
1765
  return self
1729
1766
 
1730
- def add_background_rectangle_to_submobjects(self, **kwargs):
1767
+ def add_background_rectangle_to_submobjects(self, **kwargs) -> Self:
1731
1768
  for submobject in self.submobjects:
1732
1769
  submobject.add_background_rectangle(**kwargs)
1733
1770
  return self
1734
1771
 
1735
- def add_background_rectangle_to_family_members_with_points(self, **kwargs):
1772
+ def add_background_rectangle_to_family_members_with_points(self, **kwargs) -> Self:
1736
1773
  for mob in self.family_members_with_points():
1737
1774
  mob.add_background_rectangle(**kwargs)
1738
1775
  return self
1739
1776
 
1740
1777
  # Color functions
1741
1778
 
1742
- def set_color(self, color: Color = YELLOW_C, family: bool = True):
1779
+ def set_color(
1780
+ self, color: ParsableManimColor = YELLOW_C, family: bool = True
1781
+ ) -> Self:
1743
1782
  """Condition is function which takes in one arguments, (x, y, z).
1744
1783
  Here it just recurses to submobjects, but in subclasses this
1745
1784
  should be further implemented based on the the inner workings
@@ -1748,20 +1787,30 @@ class Mobject:
1748
1787
  if family:
1749
1788
  for submob in self.submobjects:
1750
1789
  submob.set_color(color, family=family)
1751
- self.color = Color(color)
1790
+
1791
+ self.color = ManimColor.parse(color)
1752
1792
  return self
1753
1793
 
1754
- def set_color_by_gradient(self, *colors):
1794
+ def set_color_by_gradient(self, *colors: ParsableManimColor) -> Self:
1795
+ """
1796
+ Parameters
1797
+ ----------
1798
+ colors
1799
+ The colors to use for the gradient. Use like `set_color_by_gradient(RED, BLUE, GREEN)`.
1800
+
1801
+ self.color = ManimColor.parse(color)
1802
+ return self
1803
+ """
1755
1804
  self.set_submobject_colors_by_gradient(*colors)
1756
1805
  return self
1757
1806
 
1758
1807
  def set_colors_by_radial_gradient(
1759
1808
  self,
1760
- center=None,
1761
- radius=1,
1762
- inner_color=WHITE,
1763
- outer_color=BLACK,
1764
- ):
1809
+ center: Point3D | None = None,
1810
+ radius: float = 1,
1811
+ inner_color: ParsableManimColor = WHITE,
1812
+ outer_color: ParsableManimColor = BLACK,
1813
+ ) -> Self:
1765
1814
  self.set_submobject_colors_by_radial_gradient(
1766
1815
  center,
1767
1816
  radius,
@@ -1770,7 +1819,7 @@ class Mobject:
1770
1819
  )
1771
1820
  return self
1772
1821
 
1773
- def set_submobject_colors_by_gradient(self, *colors):
1822
+ def set_submobject_colors_by_gradient(self, *colors: Iterable[ParsableManimColor]):
1774
1823
  if len(colors) == 0:
1775
1824
  raise ValueError("Need at least one color")
1776
1825
  elif len(colors) == 1:
@@ -1785,11 +1834,11 @@ class Mobject:
1785
1834
 
1786
1835
  def set_submobject_colors_by_radial_gradient(
1787
1836
  self,
1788
- center=None,
1789
- radius=1,
1790
- inner_color=WHITE,
1791
- outer_color=BLACK,
1792
- ):
1837
+ center: Point3D | None = None,
1838
+ radius: float = 1,
1839
+ inner_color: ParsableManimColor = WHITE,
1840
+ outer_color: ParsableManimColor = BLACK,
1841
+ ) -> Self:
1793
1842
  if center is None:
1794
1843
  center = self.get_center()
1795
1844
 
@@ -1801,11 +1850,13 @@ class Mobject:
1801
1850
 
1802
1851
  return self
1803
1852
 
1804
- def to_original_color(self):
1853
+ def to_original_color(self) -> Self:
1805
1854
  self.set_color(self.color)
1806
1855
  return self
1807
1856
 
1808
- def fade_to(self, color, alpha, family=True):
1857
+ def fade_to(
1858
+ self, color: ParsableManimColor, alpha: float, family: bool = True
1859
+ ) -> Self:
1809
1860
  if self.get_num_points() > 0:
1810
1861
  new_color = interpolate_color(self.get_color(), color, alpha)
1811
1862
  self.set_color(new_color, family=False)
@@ -1814,19 +1865,19 @@ class Mobject:
1814
1865
  submob.fade_to(color, alpha)
1815
1866
  return self
1816
1867
 
1817
- def fade(self, darkness=0.5, family=True):
1868
+ def fade(self, darkness: float = 0.5, family: bool = True) -> Self:
1818
1869
  if family:
1819
1870
  for submob in self.submobjects:
1820
1871
  submob.fade(darkness, family)
1821
1872
  return self
1822
1873
 
1823
- def get_color(self):
1874
+ def get_color(self) -> ManimColor:
1824
1875
  """Returns the color of the :class:`~.Mobject`"""
1825
1876
  return self.color
1826
1877
 
1827
1878
  ##
1828
1879
 
1829
- def save_state(self):
1880
+ def save_state(self) -> Self:
1830
1881
  """Save the current state (position, color & size). Can be restored with :meth:`~.Mobject.restore`."""
1831
1882
  if hasattr(self, "saved_state"):
1832
1883
  # Prevent exponential growth of data
@@ -1835,14 +1886,14 @@ class Mobject:
1835
1886
 
1836
1887
  return self
1837
1888
 
1838
- def restore(self):
1889
+ def restore(self) -> Self:
1839
1890
  """Restores the state that was previously saved with :meth:`~.Mobject.save_state`."""
1840
1891
  if not hasattr(self, "saved_state") or self.save_state is None:
1841
1892
  raise Exception("Trying to restore without having saved")
1842
1893
  self.become(self.saved_state)
1843
1894
  return self
1844
1895
 
1845
- def reduce_across_dimension(self, reduce_func, dim: int) -> float:
1896
+ def reduce_across_dimension(self, reduce_func: Callable, dim: int):
1846
1897
  """Find the min or max value from a dimension across all points in this and submobjects."""
1847
1898
  assert dim >= 0 and dim <= 2
1848
1899
  if len(self.submobjects) == 0 and len(self.points) == 0:
@@ -1866,14 +1917,14 @@ class Mobject:
1866
1917
  rv = reduce_func([value, rv])
1867
1918
  return rv
1868
1919
 
1869
- def nonempty_submobjects(self):
1920
+ def nonempty_submobjects(self) -> list[Self]:
1870
1921
  return [
1871
1922
  submob
1872
1923
  for submob in self.submobjects
1873
1924
  if len(submob.submobjects) != 0 or len(submob.points) != 0
1874
1925
  ]
1875
1926
 
1876
- def get_merged_array(self, array_attr) -> np.ndarray:
1927
+ def get_merged_array(self, array_attr: str) -> np.ndarray:
1877
1928
  """Return all of a given attribute from this mobject and all submobjects.
1878
1929
 
1879
1930
  May contain duplicates; the order is in a depth-first (pre-order)
@@ -1884,7 +1935,7 @@ class Mobject:
1884
1935
  result = np.append(result, submob.get_merged_array(array_attr), axis=0)
1885
1936
  return result
1886
1937
 
1887
- def get_all_points(self) -> np.ndarray:
1938
+ def get_all_points(self) -> Point3D_Array:
1888
1939
  """Return all points from this mobject and all submobjects.
1889
1940
 
1890
1941
  May contain duplicates; the order is in a depth-first (pre-order)
@@ -1894,13 +1945,15 @@ class Mobject:
1894
1945
 
1895
1946
  # Getters
1896
1947
 
1897
- def get_points_defining_boundary(self):
1948
+ def get_points_defining_boundary(self) -> Point3D_Array:
1898
1949
  return self.get_all_points()
1899
1950
 
1900
- def get_num_points(self):
1951
+ def get_num_points(self) -> int:
1901
1952
  return len(self.points)
1902
1953
 
1903
- def get_extremum_along_dim(self, points=None, dim=0, key=0):
1954
+ def get_extremum_along_dim(
1955
+ self, points: Point3D_Array | None = None, dim: int = 0, key: int = 0
1956
+ ) -> np.ndarray | float:
1904
1957
  if points is None:
1905
1958
  points = self.get_points_defining_boundary()
1906
1959
  values = points[:, dim]
@@ -1911,7 +1964,7 @@ class Mobject:
1911
1964
  else:
1912
1965
  return np.max(values)
1913
1966
 
1914
- def get_critical_point(self, direction):
1967
+ def get_critical_point(self, direction: Vector3) -> Point3D:
1915
1968
  """Picture a box bounding the :class:`~.Mobject`. Such a box has
1916
1969
  9 'critical points': 4 corners, 4 edge center, the
1917
1970
  center. This returns one of them, along the given direction.
@@ -1940,28 +1993,28 @@ class Mobject:
1940
1993
 
1941
1994
  # Pseudonyms for more general get_critical_point method
1942
1995
 
1943
- def get_edge_center(self, direction) -> np.ndarray:
1944
- """Get edge coordinates for certain direction."""
1996
+ def get_edge_center(self, direction: Vector3) -> Point3D:
1997
+ """Get edge Point3Ds for certain direction."""
1945
1998
  return self.get_critical_point(direction)
1946
1999
 
1947
- def get_corner(self, direction) -> np.ndarray:
1948
- """Get corner coordinates for certain direction."""
2000
+ def get_corner(self, direction: Vector3) -> Point3D:
2001
+ """Get corner Point3Ds for certain direction."""
1949
2002
  return self.get_critical_point(direction)
1950
2003
 
1951
- def get_center(self) -> np.ndarray:
1952
- """Get center coordinates"""
2004
+ def get_center(self) -> Point3D:
2005
+ """Get center Point3Ds"""
1953
2006
  return self.get_critical_point(np.zeros(self.dim))
1954
2007
 
1955
- def get_center_of_mass(self):
2008
+ def get_center_of_mass(self) -> Point3D:
1956
2009
  return np.apply_along_axis(np.mean, 0, self.get_all_points())
1957
2010
 
1958
- def get_boundary_point(self, direction):
2011
+ def get_boundary_point(self, direction: Vector3) -> Point3D:
1959
2012
  all_points = self.get_points_defining_boundary()
1960
2013
  index = np.argmax(np.dot(all_points, np.array(direction).T))
1961
2014
  return all_points[index]
1962
2015
 
1963
- def get_midpoint(self) -> np.ndarray:
1964
- """Get coordinates of the middle of the path that forms the :class:`~.Mobject`.
2016
+ def get_midpoint(self) -> Point3D:
2017
+ """Get Point3Ds of the middle of the path that forms the :class:`~.Mobject`.
1965
2018
 
1966
2019
  Examples
1967
2020
  --------
@@ -1983,74 +2036,74 @@ class Mobject:
1983
2036
  """
1984
2037
  return self.point_from_proportion(0.5)
1985
2038
 
1986
- def get_top(self) -> np.ndarray:
1987
- """Get top coordinates of a box bounding the :class:`~.Mobject`"""
2039
+ def get_top(self) -> Point3D:
2040
+ """Get top Point3Ds of a box bounding the :class:`~.Mobject`"""
1988
2041
  return self.get_edge_center(UP)
1989
2042
 
1990
- def get_bottom(self) -> np.ndarray:
1991
- """Get bottom coordinates of a box bounding the :class:`~.Mobject`"""
2043
+ def get_bottom(self) -> Point3D:
2044
+ """Get bottom Point3Ds of a box bounding the :class:`~.Mobject`"""
1992
2045
  return self.get_edge_center(DOWN)
1993
2046
 
1994
- def get_right(self) -> np.ndarray:
1995
- """Get right coordinates of a box bounding the :class:`~.Mobject`"""
2047
+ def get_right(self) -> Point3D:
2048
+ """Get right Point3Ds of a box bounding the :class:`~.Mobject`"""
1996
2049
  return self.get_edge_center(RIGHT)
1997
2050
 
1998
- def get_left(self) -> np.ndarray:
1999
- """Get left coordinates of a box bounding the :class:`~.Mobject`"""
2051
+ def get_left(self) -> Point3D:
2052
+ """Get left Point3Ds of a box bounding the :class:`~.Mobject`"""
2000
2053
  return self.get_edge_center(LEFT)
2001
2054
 
2002
- def get_zenith(self) -> np.ndarray:
2003
- """Get zenith coordinates of a box bounding a 3D :class:`~.Mobject`."""
2055
+ def get_zenith(self) -> Point3D:
2056
+ """Get zenith Point3Ds of a box bounding a 3D :class:`~.Mobject`."""
2004
2057
  return self.get_edge_center(OUT)
2005
2058
 
2006
- def get_nadir(self) -> np.ndarray:
2007
- """Get nadir (opposite the zenith) coordinates of a box bounding a 3D :class:`~.Mobject`."""
2059
+ def get_nadir(self) -> Point3D:
2060
+ """Get nadir (opposite the zenith) Point3Ds of a box bounding a 3D :class:`~.Mobject`."""
2008
2061
  return self.get_edge_center(IN)
2009
2062
 
2010
- def length_over_dim(self, dim):
2063
+ def length_over_dim(self, dim: int) -> float:
2011
2064
  """Measure the length of an :class:`~.Mobject` in a certain direction."""
2012
2065
  return self.reduce_across_dimension(
2013
2066
  max,
2014
2067
  dim,
2015
2068
  ) - self.reduce_across_dimension(min, dim)
2016
2069
 
2017
- def get_coord(self, dim, direction=ORIGIN):
2070
+ def get_coord(self, dim: int, direction: Vector3 = ORIGIN):
2018
2071
  """Meant to generalize ``get_x``, ``get_y`` and ``get_z``"""
2019
2072
  return self.get_extremum_along_dim(dim=dim, key=direction[dim])
2020
2073
 
2021
- def get_x(self, direction=ORIGIN) -> np.float64:
2022
- """Returns x coordinate of the center of the :class:`~.Mobject` as ``float``"""
2074
+ def get_x(self, direction: Vector3 = ORIGIN) -> ManimFloat:
2075
+ """Returns x Point3D of the center of the :class:`~.Mobject` as ``float``"""
2023
2076
  return self.get_coord(0, direction)
2024
2077
 
2025
- def get_y(self, direction=ORIGIN) -> np.float64:
2026
- """Returns y coordinate of the center of the :class:`~.Mobject` as ``float``"""
2078
+ def get_y(self, direction: Vector3 = ORIGIN) -> ManimFloat:
2079
+ """Returns y Point3D of the center of the :class:`~.Mobject` as ``float``"""
2027
2080
  return self.get_coord(1, direction)
2028
2081
 
2029
- def get_z(self, direction=ORIGIN) -> np.float64:
2030
- """Returns z coordinate of the center of the :class:`~.Mobject` as ``float``"""
2082
+ def get_z(self, direction: Vector3 = ORIGIN) -> ManimFloat:
2083
+ """Returns z Point3D of the center of the :class:`~.Mobject` as ``float``"""
2031
2084
  return self.get_coord(2, direction)
2032
2085
 
2033
- def get_start(self):
2086
+ def get_start(self) -> Point3D:
2034
2087
  """Returns the point, where the stroke that surrounds the :class:`~.Mobject` starts."""
2035
2088
  self.throw_error_if_no_points()
2036
2089
  return np.array(self.points[0])
2037
2090
 
2038
- def get_end(self):
2091
+ def get_end(self) -> Point3D:
2039
2092
  """Returns the point, where the stroke that surrounds the :class:`~.Mobject` ends."""
2040
2093
  self.throw_error_if_no_points()
2041
2094
  return np.array(self.points[-1])
2042
2095
 
2043
- def get_start_and_end(self):
2096
+ def get_start_and_end(self) -> tuple[Point3D, Point3D]:
2044
2097
  """Returns starting and ending point of a stroke as a ``tuple``."""
2045
2098
  return self.get_start(), self.get_end()
2046
2099
 
2047
- def point_from_proportion(self, alpha):
2100
+ def point_from_proportion(self, alpha: float) -> Point3D:
2048
2101
  raise NotImplementedError("Please override in a child class.")
2049
2102
 
2050
- def proportion_from_point(self, point):
2103
+ def proportion_from_point(self, point: Point3D) -> float:
2051
2104
  raise NotImplementedError("Please override in a child class.")
2052
2105
 
2053
- def get_pieces(self, n_pieces):
2106
+ def get_pieces(self, n_pieces: float) -> Group:
2054
2107
  template = self.copy()
2055
2108
  template.submobjects = []
2056
2109
  alphas = np.linspace(0, 1, n_pieces + 1)
@@ -2061,7 +2114,7 @@ class Mobject:
2061
2114
  )
2062
2115
  )
2063
2116
 
2064
- def get_z_index_reference_point(self):
2117
+ def get_z_index_reference_point(self) -> Point3D:
2065
2118
  # TODO, better place to define default z_index_group?
2066
2119
  z_index_group = getattr(self, "z_index_group", self)
2067
2120
  return z_index_group.get_center()
@@ -2076,51 +2129,53 @@ class Mobject:
2076
2129
 
2077
2130
  # Match other mobject properties
2078
2131
 
2079
- def match_color(self, mobject: Mobject):
2132
+ def match_color(self, mobject: Mobject) -> Self:
2080
2133
  """Match the color with the color of another :class:`~.Mobject`."""
2081
2134
  return self.set_color(mobject.get_color())
2082
2135
 
2083
- def match_dim_size(self, mobject: Mobject, dim, **kwargs):
2136
+ def match_dim_size(self, mobject: Mobject, dim: int, **kwargs) -> Self:
2084
2137
  """Match the specified dimension with the dimension of another :class:`~.Mobject`."""
2085
2138
  return self.rescale_to_fit(mobject.length_over_dim(dim), dim, **kwargs)
2086
2139
 
2087
- def match_width(self, mobject: Mobject, **kwargs):
2140
+ def match_width(self, mobject: Mobject, **kwargs) -> Self:
2088
2141
  """Match the width with the width of another :class:`~.Mobject`."""
2089
2142
  return self.match_dim_size(mobject, 0, **kwargs)
2090
2143
 
2091
- def match_height(self, mobject: Mobject, **kwargs):
2144
+ def match_height(self, mobject: Mobject, **kwargs) -> Self:
2092
2145
  """Match the height with the height of another :class:`~.Mobject`."""
2093
2146
  return self.match_dim_size(mobject, 1, **kwargs)
2094
2147
 
2095
- def match_depth(self, mobject: Mobject, **kwargs):
2148
+ def match_depth(self, mobject: Mobject, **kwargs) -> Self:
2096
2149
  """Match the depth with the depth of another :class:`~.Mobject`."""
2097
2150
  return self.match_dim_size(mobject, 2, **kwargs)
2098
2151
 
2099
- def match_coord(self, mobject: Mobject, dim, direction=ORIGIN):
2100
- """Match the coordinates with the coordinates of another :class:`~.Mobject`."""
2152
+ def match_coord(
2153
+ self, mobject: Mobject, dim: int, direction: Vector3 = ORIGIN
2154
+ ) -> Self:
2155
+ """Match the Point3Ds with the Point3Ds of another :class:`~.Mobject`."""
2101
2156
  return self.set_coord(
2102
2157
  mobject.get_coord(dim, direction),
2103
2158
  dim=dim,
2104
2159
  direction=direction,
2105
2160
  )
2106
2161
 
2107
- def match_x(self, mobject: Mobject, direction=ORIGIN):
2162
+ def match_x(self, mobject: Mobject, direction=ORIGIN) -> Self:
2108
2163
  """Match x coord. to the x coord. of another :class:`~.Mobject`."""
2109
2164
  return self.match_coord(mobject, 0, direction)
2110
2165
 
2111
- def match_y(self, mobject: Mobject, direction=ORIGIN):
2166
+ def match_y(self, mobject: Mobject, direction=ORIGIN) -> Self:
2112
2167
  """Match y coord. to the x coord. of another :class:`~.Mobject`."""
2113
2168
  return self.match_coord(mobject, 1, direction)
2114
2169
 
2115
- def match_z(self, mobject: Mobject, direction=ORIGIN):
2170
+ def match_z(self, mobject: Mobject, direction=ORIGIN) -> Self:
2116
2171
  """Match z coord. to the x coord. of another :class:`~.Mobject`."""
2117
2172
  return self.match_coord(mobject, 2, direction)
2118
2173
 
2119
2174
  def align_to(
2120
2175
  self,
2121
- mobject_or_point: Mobject | np.ndarray | list,
2122
- direction=ORIGIN,
2123
- ):
2176
+ mobject_or_point: Mobject | Point3D,
2177
+ direction: Vector3 = ORIGIN,
2178
+ ) -> Self:
2124
2179
  """Aligns mobject to another :class:`~.Mobject` in a certain direction.
2125
2180
 
2126
2181
  Examples:
@@ -2152,33 +2207,33 @@ class Mobject:
2152
2207
  def __len__(self):
2153
2208
  return len(self.split())
2154
2209
 
2155
- def get_group_class(self):
2210
+ def get_group_class(self) -> type[Group]:
2156
2211
  return Group
2157
2212
 
2158
2213
  @staticmethod
2159
- def get_mobject_type_class():
2214
+ def get_mobject_type_class() -> type[Mobject]:
2160
2215
  """Return the base class of this mobject type."""
2161
2216
  return Mobject
2162
2217
 
2163
- def split(self):
2218
+ def split(self) -> list[Self]:
2164
2219
  result = [self] if len(self.points) > 0 else []
2165
2220
  return result + self.submobjects
2166
2221
 
2167
- def get_family(self, recurse=True):
2168
- sub_families = list(map(Mobject.get_family, self.submobjects))
2222
+ def get_family(self, recurse: bool = True) -> list[Self]:
2223
+ sub_families = [x.get_family() for x in self.submobjects]
2169
2224
  all_mobjects = [self] + list(it.chain(*sub_families))
2170
2225
  return remove_list_redundancies(all_mobjects)
2171
2226
 
2172
- def family_members_with_points(self):
2227
+ def family_members_with_points(self) -> list[Self]:
2173
2228
  return [m for m in self.get_family() if m.get_num_points() > 0]
2174
2229
 
2175
2230
  def arrange(
2176
2231
  self,
2177
- direction: Sequence[float] = RIGHT,
2178
- buff=DEFAULT_MOBJECT_TO_MOBJECT_BUFFER,
2179
- center=True,
2232
+ direction: Vector3 = RIGHT,
2233
+ buff: float = DEFAULT_MOBJECT_TO_MOBJECT_BUFFER,
2234
+ center: bool = True,
2180
2235
  **kwargs,
2181
- ):
2236
+ ) -> Self:
2182
2237
  """Sorts :class:`~.Mobject` next to each other on screen.
2183
2238
 
2184
2239
  Examples
@@ -2207,14 +2262,14 @@ class Mobject:
2207
2262
  rows: int | None = None,
2208
2263
  cols: int | None = None,
2209
2264
  buff: float | tuple[float, float] = MED_SMALL_BUFF,
2210
- cell_alignment: np.ndarray = ORIGIN,
2265
+ cell_alignment: Vector3 = ORIGIN,
2211
2266
  row_alignments: str | None = None, # "ucd"
2212
2267
  col_alignments: str | None = None, # "lcr"
2213
2268
  row_heights: Iterable[float | None] | None = None,
2214
2269
  col_widths: Iterable[float | None] | None = None,
2215
2270
  flow_order: str = "rd",
2216
2271
  **kwargs,
2217
- ):
2272
+ ) -> Self:
2218
2273
  """Arrange submobjects in a grid.
2219
2274
 
2220
2275
  Parameters
@@ -2320,15 +2375,15 @@ class Mobject:
2320
2375
 
2321
2376
  # calculate rows cols
2322
2377
  if rows is None and cols is None:
2323
- cols = ceil(np.sqrt(len(mobs)))
2378
+ cols = math.ceil(math.sqrt(len(mobs)))
2324
2379
  # make the grid as close to quadratic as possible.
2325
2380
  # choosing cols first can results in cols>rows.
2326
2381
  # This is favored over rows>cols since in general
2327
2382
  # the sceene is wider than high.
2328
2383
  if rows is None:
2329
- rows = ceil(len(mobs) / cols)
2384
+ rows = math.ceil(len(mobs) / cols)
2330
2385
  if cols is None:
2331
- cols = ceil(len(mobs) / rows)
2386
+ cols = math.ceil(len(mobs) / rows)
2332
2387
  if rows * cols < len(mobs):
2333
2388
  raise ValueError("Too few rows and columns to fit all submobjetcs.")
2334
2389
  # rows and cols are now finally valid.
@@ -2443,24 +2498,28 @@ class Mobject:
2443
2498
  self.move_to(start_pos)
2444
2499
  return self
2445
2500
 
2446
- def sort(self, point_to_num_func=lambda p: p[0], submob_func=None):
2501
+ def sort(
2502
+ self,
2503
+ point_to_num_func: Callable[[Point3D], ManimInt] = lambda p: p[0],
2504
+ submob_func: Callable[[Mobject], ManimInt] | None = None,
2505
+ ) -> Self:
2447
2506
  """Sorts the list of :attr:`submobjects` by a function defined by ``submob_func``."""
2448
2507
  if submob_func is None:
2449
2508
 
2450
- def submob_func(m):
2509
+ def submob_func(m: Mobject):
2451
2510
  return point_to_num_func(m.get_center())
2452
2511
 
2453
2512
  self.submobjects.sort(key=submob_func)
2454
2513
  return self
2455
2514
 
2456
- def shuffle(self, recursive=False):
2515
+ def shuffle(self, recursive: bool = False) -> None:
2457
2516
  """Shuffles the list of :attr:`submobjects`."""
2458
2517
  if recursive:
2459
2518
  for submob in self.submobjects:
2460
2519
  submob.shuffle(recursive=True)
2461
2520
  random.shuffle(self.submobjects)
2462
2521
 
2463
- def invert(self, recursive=False):
2522
+ def invert(self, recursive: bool = False) -> None:
2464
2523
  """Inverts the list of :attr:`submobjects`.
2465
2524
 
2466
2525
  Parameters
@@ -2484,10 +2543,10 @@ class Mobject:
2484
2543
  if recursive:
2485
2544
  for submob in self.submobjects:
2486
2545
  submob.invert(recursive=True)
2487
- list.reverse(self.submobjects)
2546
+ self.submobjects.reverse()
2488
2547
 
2489
2548
  # Just here to keep from breaking old scenes.
2490
- def arrange_submobjects(self, *args, **kwargs):
2549
+ def arrange_submobjects(self, *args, **kwargs) -> Self:
2491
2550
  """Arrange the position of :attr:`submobjects` with a small buffer.
2492
2551
 
2493
2552
  Examples
@@ -2508,11 +2567,11 @@ class Mobject:
2508
2567
  """
2509
2568
  return self.arrange(*args, **kwargs)
2510
2569
 
2511
- def sort_submobjects(self, *args, **kwargs):
2570
+ def sort_submobjects(self, *args, **kwargs) -> Self:
2512
2571
  """Sort the :attr:`submobjects`"""
2513
2572
  return self.sort(*args, **kwargs)
2514
2573
 
2515
- def shuffle_submobjects(self, *args, **kwargs):
2574
+ def shuffle_submobjects(self, *args, **kwargs) -> None:
2516
2575
  """Shuffles the order of :attr:`submobjects`
2517
2576
 
2518
2577
  Examples
@@ -2531,7 +2590,7 @@ class Mobject:
2531
2590
  return self.shuffle(*args, **kwargs)
2532
2591
 
2533
2592
  # Alignment
2534
- def align_data(self, mobject: Mobject, skip_point_alignment: bool = False):
2593
+ def align_data(self, mobject: Mobject, skip_point_alignment: bool = False) -> None:
2535
2594
  """Aligns the data of this mobject with another mobject.
2536
2595
 
2537
2596
  Afterwards, the two mobjects will have the same number of submobjects
@@ -2562,7 +2621,7 @@ class Mobject:
2562
2621
  msg = f"get_point_mobject not implemented for {self.__class__.__name__}"
2563
2622
  raise NotImplementedError(msg)
2564
2623
 
2565
- def align_points(self, mobject):
2624
+ def align_points(self, mobject: Mobject) -> Self:
2566
2625
  count1 = self.get_num_points()
2567
2626
  count2 = mobject.get_num_points()
2568
2627
  if count1 < count2:
@@ -2571,10 +2630,10 @@ class Mobject:
2571
2630
  mobject.align_points_with_larger(self)
2572
2631
  return self
2573
2632
 
2574
- def align_points_with_larger(self, larger_mobject):
2633
+ def align_points_with_larger(self, larger_mobject: Mobject):
2575
2634
  raise NotImplementedError("Please override in a child class.")
2576
2635
 
2577
- def align_submobjects(self, mobject):
2636
+ def align_submobjects(self, mobject: Mobject) -> Self:
2578
2637
  mob1 = self
2579
2638
  mob2 = mobject
2580
2639
  n1 = len(mob1.submobjects)
@@ -2599,14 +2658,14 @@ class Mobject:
2599
2658
  m2.push_self_into_submobjects()
2600
2659
  return self
2601
2660
 
2602
- def push_self_into_submobjects(self):
2661
+ def push_self_into_submobjects(self) -> Self:
2603
2662
  copy = self.copy()
2604
2663
  copy.submobjects = []
2605
2664
  self.reset_points()
2606
2665
  self.add(copy)
2607
2666
  return self
2608
2667
 
2609
- def add_n_more_submobjects(self, n):
2668
+ def add_n_more_submobjects(self, n: int) -> Self | None:
2610
2669
  if n == 0:
2611
2670
  return
2612
2671
 
@@ -2629,10 +2688,16 @@ class Mobject:
2629
2688
  self.submobjects = new_submobs
2630
2689
  return self
2631
2690
 
2632
- def repeat_submobject(self, submob):
2691
+ def repeat_submobject(self, submob: Mobject) -> Self:
2633
2692
  return submob.copy()
2634
2693
 
2635
- def interpolate(self, mobject1, mobject2, alpha, path_func=straight_path()):
2694
+ def interpolate(
2695
+ self,
2696
+ mobject1: Mobject,
2697
+ mobject2: Mobject,
2698
+ alpha: float,
2699
+ path_func: PathFuncType = straight_path(),
2700
+ ) -> Self:
2636
2701
  """Turns this :class:`~.Mobject` into an interpolation between ``mobject1``
2637
2702
  and ``mobject2``.
2638
2703
 
@@ -2657,7 +2722,7 @@ class Mobject:
2657
2722
  self.interpolate_color(mobject1, mobject2, alpha)
2658
2723
  return self
2659
2724
 
2660
- def interpolate_color(self, mobject1, mobject2, alpha):
2725
+ def interpolate_color(self, mobject1: Mobject, mobject2: Mobject, alpha: float):
2661
2726
  raise NotImplementedError("Please override in a child class.")
2662
2727
 
2663
2728
  def become(
@@ -2669,7 +2734,7 @@ class Mobject:
2669
2734
  match_depth: bool = False,
2670
2735
  match_center: bool = False,
2671
2736
  stretch: bool = False,
2672
- ):
2737
+ ) -> Self:
2673
2738
  """Edit points, colors and submobjects to be identical
2674
2739
  to another :class:`~.Mobject`
2675
2740
 
@@ -2726,7 +2791,7 @@ class Mobject:
2726
2791
  sm1.interpolate_color(sm1, sm2, 1)
2727
2792
  return self
2728
2793
 
2729
- def match_points(self, mobject: Mobject, copy_submobjects: bool = True):
2794
+ def match_points(self, mobject: Mobject, copy_submobjects: bool = True) -> Self:
2730
2795
  """Edit points, positions, and submobjects to be identical
2731
2796
  to another :class:`~.Mobject`, while keeping the style unchanged.
2732
2797
 
@@ -2748,7 +2813,7 @@ class Mobject:
2748
2813
  return self
2749
2814
 
2750
2815
  # Errors
2751
- def throw_error_if_no_points(self):
2816
+ def throw_error_if_no_points(self) -> None:
2752
2817
  if self.has_no_points():
2753
2818
  caller_name = sys._getframe(1).f_code.co_name
2754
2819
  raise Exception(
@@ -2760,7 +2825,7 @@ class Mobject:
2760
2825
  self,
2761
2826
  z_index_value: float,
2762
2827
  family: bool = True,
2763
- ) -> VMobject:
2828
+ ) -> T:
2764
2829
  """Sets the :class:`~.Mobject`'s :attr:`z_index` to the value specified in `z_index_value`.
2765
2830
 
2766
2831
  Parameters
@@ -2799,8 +2864,8 @@ class Mobject:
2799
2864
  self.z_index = z_index_value
2800
2865
  return self
2801
2866
 
2802
- def set_z_index_by_z_coordinate(self):
2803
- """Sets the :class:`~.Mobject`'s z coordinate to the value of :attr:`z_index`.
2867
+ def set_z_index_by_z_Point3D(self) -> Self:
2868
+ """Sets the :class:`~.Mobject`'s z Point3D to the value of :attr:`z_index`.
2804
2869
 
2805
2870
  Returns
2806
2871
  -------
@@ -2822,13 +2887,13 @@ class Group(Mobject, metaclass=ConvertToOpenGL):
2822
2887
  be added to the group.
2823
2888
  """
2824
2889
 
2825
- def __init__(self, *mobjects, **kwargs):
2890
+ def __init__(self, *mobjects, **kwargs) -> None:
2826
2891
  super().__init__(**kwargs)
2827
2892
  self.add(*mobjects)
2828
2893
 
2829
2894
 
2830
2895
  class _AnimationBuilder:
2831
- def __init__(self, mobject):
2896
+ def __init__(self, mobject) -> None:
2832
2897
  self.mobject = mobject
2833
2898
  self.mobject.generate_target()
2834
2899
 
@@ -2840,7 +2905,7 @@ class _AnimationBuilder:
2840
2905
  self.cannot_pass_args = False
2841
2906
  self.anim_args = {}
2842
2907
 
2843
- def __call__(self, **kwargs):
2908
+ def __call__(self, **kwargs) -> Self:
2844
2909
  if self.cannot_pass_args:
2845
2910
  raise ValueError(
2846
2911
  "Animation arguments must be passed before accessing methods and can only be passed once",
@@ -2851,7 +2916,7 @@ class _AnimationBuilder:
2851
2916
 
2852
2917
  return self
2853
2918
 
2854
- def __getattr__(self, method_name):
2919
+ def __getattr__(self, method_name) -> types.MethodType:
2855
2920
  method = getattr(self.mobject.target, method_name)
2856
2921
  has_overridden_animation = hasattr(method, "_override_animate")
2857
2922
 
@@ -2879,8 +2944,10 @@ class _AnimationBuilder:
2879
2944
 
2880
2945
  return update_target
2881
2946
 
2882
- def build(self):
2883
- from ..animation.transform import _MethodAnimation
2947
+ def build(self) -> Animation:
2948
+ from ..animation.transform import ( # is this to prevent circular import?
2949
+ _MethodAnimation,
2950
+ )
2884
2951
 
2885
2952
  if self.overridden_animation:
2886
2953
  anim = self.overridden_animation
@@ -2893,7 +2960,7 @@ class _AnimationBuilder:
2893
2960
  return anim
2894
2961
 
2895
2962
 
2896
- def override_animate(method):
2963
+ def override_animate(method) -> types.FunctionType:
2897
2964
  r"""Decorator for overriding method animations.
2898
2965
 
2899
2966
  This allows to specify a method (returning an :class:`~.Animation`)