-
Notifications
You must be signed in to change notification settings - Fork 6.2k
Anatomy of manim
The manim library has most of its functionality broken up into functionally distinct folders. The main ones used in scripting an animation are the scene, mobject, camera, and animation folders which contain their respective classes. Of those four, the mobject folder is what users will interact with most of the time. It contains the classes for all the geometry, text, and graphics that are used in animations.
The actual structure of a program is easy to get a hold on. Animations, or scenes, are created by declaring a subclass of the Scene class in a python file. The actual code for animations goes into a method called construct. This is a keyword for scenes in manim. Whenever an object in the Scene class is initialized, it calls self.setup()
and self.construct()
methods. If the latter isn't implemented, you will get an error. The former, however, is optional but useful when working with several scenes at once.
Playing and saving animations takes place from the command line. The basic command for playing animations is shown above, with the name of the python file and the scene subclass passed to manim.py (which is actually manimlib/__init__.py). The -pm
flag will preview an animation in medium (720p) quality and save it in the media folder. More flag types can be found in config.py, such as flags that crop certain frames or flags to export .gif animations.
Any python code outside of a scene declaration is also executed when the command line calls its file. This means that code that doesn't depend explicitly on manim's functionality can be taken out of construct(self)
. This is helpful since it prevents clutter in the definition of construct.
Most classes in manim come with a CONFIG
dictionary associated to them. This always appears at the top of class definitions. This is the CONFIG for the Camera class:
class Camera(object):
CONFIG = {
"background_image": None,
"pixel_height": DEFAULT_PIXEL_HEIGHT,
"pixel_width": DEFAULT_PIXEL_WIDTH,
"frame_rate": DEFAULT_FRAME_RATE,
"frame_height": FRAME_HEIGHT,
"frame_width": FRAME_WIDTH,
"frame_center": ORIGIN,
"background_color": BLACK,
"background_opacity": 1,
"max_allowable_norm": FRAME_WIDTH,
"image_mode": "RGBA",
"n_channels": 4,
"pixel_array_dtype": 'uint8',
"z_buff_func": lambda m: np.round(m.get_center()[2], 2),
"cairo_line_width_multiple": 0.01,
}
When objects are initialized, the entries of CONFIG are used as keyword arguments to be passed through __init__. This is very convenient for creating scenes as it's cumbersome to pass several keyword arguments to the scene of interest within the command line. This is typically where users interact with the Camera class too, since the camera CONFIG is an entry in the scene CONFIG.
class Scene(Container):
CONFIG = {
"camera_class": Camera,
"camera_config": {},
"file_writer_config": {},
"skip_animations": False,
"always_update_mobjects": False,
"random_seed": 0,
"start_at_animation_number": None,
"end_at_animation_number": None,
"leave_progress_bars": False,
}
All of the uppercase variables come from the file constants.py
, which is useful as a reference as many classes and methods take these constants as default arguments. CONFIG dictionaries respect inheritance between classes and subclasses, so many classes in manim have larger CONFIG arguments than it may look in their class definitions. This is especially relevant for mobjects, which make extensive use of subclassing. For example, here's the subclass structure of mobject/geometry.py
.