Skip to content

Commit e48d467

Browse files
leotrsbehackl
andauthored
New tutorial: manim internals basic (#394)
* add a section to the quickstart explaining the basics of building a scene * add the internals_basic tutorial. Currently contains the section for Mobjects only Co-authored by @behackl Co-authored-by: Benjamin Hackl <[email protected]>
1 parent dc238b0 commit e48d467

File tree

8 files changed

+378
-3
lines changed

8 files changed

+378
-3
lines changed
5.15 KB
Loading
11.8 KB
Loading
11.9 KB
Loading
10.7 KB
Loading
11.1 KB
Loading

docs/source/tutorials.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ Tutorials
33

44
.. toctree::
55
:caption: Table of Contents
6+
:maxdepth: 2
67

78
tutorials/quickstart
89
tutorials/a_deeper_look
10+
tutorials/building_blocks
911
tutorials/configuration
Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
#######################
2+
Manim's building blocks
3+
#######################
4+
5+
This document explains the building blocks of manim and will give you all the
6+
necessary tools to start producing your own videos.
7+
8+
Essentially, manim puts at your disposal three different concepts that you can
9+
orchestrate together in order to produce mathematical animations: the
10+
**mathematical object** (or **mobject** for short) the **animation**, and the
11+
**scene**. As we will see in the following sections, each of these three
12+
concepts is implemented in manim as a separate class: the :class:`.Mobject`,
13+
:class:`.Animation`, and :class:`.Scene` classes.
14+
15+
.. note:: It is recommended that you read the tutorials :doc:`quickstart` and
16+
:doc:`a_deeper_look` before reading this page.
17+
18+
19+
********
20+
Mobjects
21+
********
22+
23+
Mobjects are the basic building block for all manim animations. Each class
24+
that derives from :class:`.Mobject` represents an object that can be displayed
25+
on screen. For example, simple shapes such as :class:`.Circle`,
26+
:class:`.Arrow`, and :class:`.Rectangle` are all mobjects. More complicated
27+
constructs such as :class:`.Axes`, :class:`.FunctionGraph`, or
28+
:class:`.BarChart` are mobjects as well.
29+
30+
If you try to display on screen an instance of :class:`.Mobject`, you will only
31+
see an empty frame. The reason is that the :class:`.Mobject` class is an
32+
abstract base class of all other mobjects, i.e. it does not have any
33+
pre-determined visual shape that can be displayed on screen. It is only the
34+
skeleton of a thing that *could* be displayed. Therefore, you will rarely need
35+
to use plain instances of :class:`.Mobject`; instead you will most likely
36+
create instances of its derived classes. One of these derived classes is
37+
:class:`.VMobject`. The ``V`` stands for Vectorized Mobject. In essence, a
38+
vmobject is a mobject that uses vector `vector graphics
39+
<https://en.wikipedia.org/wiki/Vector_graphics/>`_ to be displayed. Most of
40+
the time, you will be dealing with vmobjects, though we will continue to use
41+
the term "mobject" to refer to the class of shapes that can be displayed on
42+
screen, as it is more general.
43+
44+
.. note:: Any object that can be displayed on screen is a ``mobject``, even if
45+
it is not necessarily *mathematical* in nature.
46+
47+
.. tip:: To see examples of classes derived from :class:`.Mobject`, see the
48+
:mod:`.geometry` module. Most of these are in fact derived from
49+
:class:`.VMobject` as well.
50+
51+
52+
Creating and displaying mobjects
53+
================================
54+
55+
As explained in :doc:`quickstart`, usually all of the code in a manim
56+
script is put inside the :meth:`.construct` method of a :class:`.Scene` class.
57+
To display a mobject on the screen, call the :meth:`~.Scene.add` method of the
58+
containing :class:`.Scene`. This is the principal way of displaying a mobject
59+
on the screen when it is not being animated. To remove a mobject from the
60+
screen, simply call the :meth:`~.Scene.remove` method from the containing
61+
:class:`.Scene`.
62+
63+
.. manim:: CreatingMobjects
64+
:display_source:
65+
:quality: medium
66+
67+
class CreatingMobjects(Scene):
68+
def construct(self):
69+
circle = Circle()
70+
self.add(circle)
71+
self.wait(1)
72+
self.remove(circle)
73+
self.wait(1)
74+
75+
76+
Placing mobjects
77+
================
78+
79+
Let's define a new :class:`.Scene` called ``Shapes`` and :meth:`~.Scene.add`
80+
some mobjects to it. This script generates a static picture that displays a
81+
circle, a square, and a triangle:
82+
83+
.. manim:: Shapes
84+
:display_source:
85+
:quality: medium
86+
87+
class Shapes(Scene):
88+
def construct(self):
89+
circle = Circle()
90+
square = Square()
91+
triangle = Triangle()
92+
93+
circle.shift(LEFT)
94+
square.shift(UP)
95+
triangle.shift(RIGHT)
96+
97+
self.add(circle, square, triangle)
98+
self.wait(1)
99+
100+
By default, mobjects are placed at the center of coordinates, or *origin*, when
101+
they are first created. They are also given some default colors. Further, the
102+
``Shapes`` scene places the mobjects by using the :meth:`.shift` method. The
103+
square is shifted one unit in the ``UP`` direction from the origin, while the
104+
circle and triangle are shifted one unit ``LEFT`` and ``RIGHT``, respectively.
105+
106+
.. attention:: Unlike other graphics software, manim places the center of
107+
coordinates at the center of the screen. The positive vertical
108+
direction is up, and the positive horizontal direction is right.
109+
See also the constants ``ORIGIN``, ``UP``, ``DOWN``, ``LEFT``,
110+
``RIGHT``, and others, defined in the :mod:`.constants` module.
111+
112+
There are many other possible ways to place mobjects on the screen, for example
113+
:meth:`.move_to`, :meth:`.next_to`, and :meth:`.align_to`. The next scene
114+
``MobjectPlacement`` uses all three.
115+
116+
.. manim:: MobjectPlacement
117+
:display_source:
118+
:quality: medium
119+
120+
class MobjectPlacement(Scene):
121+
def construct(self):
122+
circle = Circle()
123+
square = Square()
124+
triangle = Triangle()
125+
126+
# place the circle two units left from the origin
127+
circle.move_to(LEFT * 2)
128+
# place the square to the left of the circle
129+
square.next_to(circle, LEFT)
130+
# align the left border of the triangle to the left border of the circle
131+
triangle.align_to(circle, LEFT)
132+
133+
self.add(circle, square, triangle)
134+
self.wait(1)
135+
136+
The :meth:`.move_to` method uses absolute units (measured relative to the
137+
``ORIGIN``), while :meth:`.next_to` uses relative units (measured from the
138+
mobject passed as the first argument). :meth:`align_to` uses ``LEFT`` not as
139+
measuring units but as a way to determine the border to use for alignment. The
140+
coordinates of the borders of a mobject are determined using an imaginary
141+
bounding box around it.
142+
143+
.. tip:: Many methods in manim can be chained together. For example the two
144+
lines
145+
146+
.. code-block:: python
147+
148+
square = Square()
149+
square.shift(LEFT)
150+
151+
can be replaced by
152+
153+
.. code-block:: python
154+
155+
square = Square().shift(LEFT)
156+
157+
Technically, this is possible because most methods calls return the modified mobject.
158+
159+
160+
Styling mobjects
161+
================
162+
163+
The following scene changes the default aesthetics of the mobjects.
164+
165+
.. manim:: MobjectStyling
166+
:display_source:
167+
:quality: medium
168+
169+
class MobjectStyling(Scene):
170+
def construct(self):
171+
circle = Circle().shift(LEFT)
172+
square = Square().shift(UP)
173+
triangle = Triangle().shift(RIGHT)
174+
175+
circle.set_stroke(color=GREEN, width=20)
176+
square.set_fill(YELLOW, opacity=1.0)
177+
triangle.set_fill(PINK, opacity=0.5)
178+
179+
self.add(circle, square, triangle)
180+
self.wait(1)
181+
182+
This scene uses two of the main functions that change the visual style of a
183+
mobject: :meth:`.set_stroke` and :meth:`.set_fill`. The former changes the
184+
visual style of the mobject's border while the latter changes the style of the
185+
interior. By default, most mobjects have a fully transparent interior so you
186+
must specify the ``opacity`` parameter in order to display the color. An
187+
opacity of ``1.0`` means fully opaque, while ``0.0`` means fully transparent.
188+
189+
Only instances of :class:`.VMobject` implement :meth:`.set_stroke` and
190+
:meth:`.set_fill`. Instances of :class:`.Mobject` implement
191+
:meth:`.~Mobject.set_color` instead. The vast majority of pre-defined classes
192+
are derived from :class:`.VMobject` so it is usually safe to assume that you
193+
have access to :meth:`.set_stroke` and :meth:`.set_fill`.
194+
195+
196+
Mobject on-screen order
197+
=======================
198+
199+
The next scene is exactly the same as the ``MobjectStyling`` scene from the
200+
previous section, except for exactly one line.
201+
202+
.. manim:: MobjectZOrder
203+
:display_source:
204+
:quality: medium
205+
206+
class MobjectZOrder(Scene):
207+
def construct(self):
208+
circle = Circle().shift(LEFT)
209+
square = Square().shift(UP)
210+
triangle = Triangle().shift(RIGHT)
211+
212+
circle.set_stroke(color=GREEN, width=20)
213+
square.set_fill(YELLOW, opacity=1.0)
214+
triangle.set_fill(PINK, opacity=0.5)
215+
216+
self.add(triangle, square, circle)
217+
self.wait(1)
218+
219+
The only difference here (besides the scene name) is the order in which the
220+
mobjects are added to the scene. In ``MobjectStyling``, we added them as
221+
``add(circle, square, triangle)``, whereas in ``MobjectZOrder`` we add them as
222+
``add(triangle, square, circle)``.
223+
224+
As you can see, the order of the arguments of :meth:`~.Scene.add` determines
225+
the order that the mobjects are displayed on screen, with the left-most
226+
arguments being put in the back.
227+
228+
229+
**********
230+
Animations
231+
**********
232+
233+
At the heart of manim is animation. Generally, you can add an animation to
234+
your scene by calling the :meth:`~.Scene.play` method.
235+
236+
.. manim:: SomeAnimations
237+
:display_source:
238+
:quality: medium
239+
240+
class SomeAnimations(Scene):
241+
def construct(self):
242+
square = Square()
243+
self.add(square)
244+
245+
# some animations display mobjects, ...
246+
self.play(FadeIn(square))
247+
248+
# ... some move or rotate mobjects around...
249+
self.play(Rotate(square, PI/4))
250+
251+
# some animations remove mobjects from the screen
252+
self.play(FadeOut(square))
253+
254+
self.wait(1)
255+
256+
Put simply, animations are procedures that interpolate between two mobjects.
257+
For example, :code:`FadeIn(square)` starts with a fully transparent version of
258+
:code:`square` and ends with a fully opaque version, interpolating between them
259+
by gradually increasing the opacity. :class:`.FadeOut` works in the opposite
260+
way: it interpolates from fully opaque to fully transparent. As another
261+
example, :class:`.Rotate` starts with the mobject passed to it as argument, and
262+
ends with the same object but rotated by a certain amount, this time
263+
interpolating the mobject's angle instead of its opacity.
264+
265+
266+
Animating methods
267+
=================
268+
269+
Any property of a mobject that can be changed can be animated. In fact, any
270+
method that changes a mobject's property can be used as an animation, through
271+
the use of :class:`.ApplyMethod`.
272+
273+
.. manim:: ApplyMethodExample
274+
:display_source:
275+
:quality: medium
276+
277+
class ApplyMethodExample(Scene):
278+
def construct(self):
279+
square = Square().set_fill(RED, opacity=1.0)
280+
self.add(square)
281+
282+
# animate the change of color
283+
self.play(ApplyMethod(square.set_fill, WHITE))
284+
self.wait(1)
285+
286+
# animate the change of position
287+
self.play(ApplyMethod(square.shift, UP))
288+
self.wait(1)
289+
290+
:meth:`.ApplyMethod` receives one mandatory argument which is the method of the
291+
mobject to animate (e.g. :code:`square.set_fill` or :code:`square.shift`), and
292+
any number of optional arguments which are then passed to the method call. For
293+
example, :code:`ApplyMethod(square.shift, UP)` executes
294+
:code:`square.shift(UP)`, but animates it instead of applying it immediately.
295+
296+
Animation run time
297+
==================
298+
299+
By default, any animation passed to :meth:`play` lasts for exactly one second.
300+
Use the :code:`run_time` argument to control the duration.
301+
302+
.. manim:: RunTime
303+
:display_source:
304+
:quality: medium
305+
306+
class RunTime(Scene):
307+
def construct(self):
308+
square = Square()
309+
self.add(square)
310+
self.play(ApplyMethod(square.shift, UP), run_time=3)
311+
self.wait(1)
312+
313+
314+
******
315+
Scenes
316+
******
317+
318+
The :class:`.Scene` class is the connective tissue of manim. Every mobject has
319+
to be :meth:`added <.Scene.add>` to a scene to be displayed, or :meth:`removed
320+
<.Scene.remove>` from it to cease being displayed. Every animation has to be
321+
:meth:`played <.Scene.play>` by a scene, and every time interval where no
322+
animation occurs is determined by a call to :meth:`~.Scene.wait`. All of the
323+
code of your video must be contained in the :meth:`~.Scene.construct` method of
324+
a class that derives from :class:`.Scene`. Finally, a single file may contain
325+
multiple :class:`.Scene` subclasses in the event that multiple scenes are to be
326+
rendered at the same time.

0 commit comments

Comments
 (0)