Compare commits

...

54 commits

Author SHA1 Message Date
JasonGrace2282
f2f35cf7e1
add sphinx-togglebutton as dep 2025-01-20 10:57:12 -05:00
pre-commit-ci[bot]
aae02f6fc3 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2025-01-20 15:54:54 +00:00
JasonGrace2282
be9443f8e3
add missing comma 2025-01-20 10:53:29 -05:00
JasonGrace2282
b81b7ecaa3
Merge branch 'main' of https://github.com/ManimCommunity/manim into guide 2025-01-20 10:51:26 -05:00
Aarush Deshpande
7267c722c9
Fill out the basic project guide 2024-10-19 10:01:25 -04:00
JasonGrace2282
e614b08077
Move sphinx-togglebutton into dev-dependencies 2024-10-19 10:00:05 -04:00
fnieri
83d5f9d4dc Fixed override_animation reference from :meth: to :func: 2024-10-16 16:09:45 +02:00
fnieri
b7fc13ac89 Added dropdown admonition in "Adding Admonitions" section for contributing 2024-10-15 23:24:58 +02:00
fnieri
ae0509c028 Changed basic project to reflect feedback 2024-10-15 23:02:50 +02:00
fnieri
03ae492e92 Added poetry dependency 2024-10-15 23:00:55 +02:00
fnieri
e9fe3f81ae Added subsections for algebraic and geometric vector addition 2024-10-10 14:20:49 +02:00
fnieri
ccbb3d3f1e Fixed dropdown not working in project adventure 2024-10-06 00:20:09 +02:00
JasonGrace2282
a866bb6e11
Change to manim init 2024-08-30 16:39:17 -04:00
JasonGrace2282
6de9a0ac45
Merge branch 'main' of https://github.com/ManimCommunity/manim into guide 2024-08-27 20:28:13 -04:00
JasonGrace2282
fbd04a7472
some more hyperlinks 2024-08-27 20:27:27 -04:00
pre-commit-ci[bot]
5d29e2a24b [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2024-07-09 12:38:44 +00:00
JasonGrace2282
79e5b8022d
Merge branch 'main' of https://github.com/ManimCommunity/manim into guide 2024-07-09 08:38:11 -04:00
adeshpande
527b68c272
doing -> executing
Co-authored-by: Tristan Schulz <mrdiverlp@gmail.com>
2024-07-09 08:35:25 -04:00
adeshpande
cd88ffd497
better explanation of Transform vs ReplacementTransform
Co-authored-by: Tristan Schulz <mrdiverlp@gmail.com>
2024-07-09 08:34:53 -04:00
adeshpande
3c1a01ab44
Reword introduction of :class:Transform
Co-authored-by: Tristan Schulz <mrdiverlp@gmail.com>
2024-05-26 14:10:31 -04:00
JasonGrace2282
716425247e Add progress on project 2024-03-31 14:18:36 -04:00
adeshpande
978b3e71b4
Merge branch 'main' into guide 2024-03-31 14:00:26 -04:00
dependabot[bot]
95f7d0cb2c Bump github/codeql-action from 2 to 3 (#3567)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2 to 3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-31 13:18:20 -04:00
JasonGrace2282
ab042d37ac Reword adventure/index.rst 2024-03-11 19:15:11 -04:00
JasonGrace2282
6d4b595949 Change typo from nonlocal var to local parameter 2024-02-02 16:34:46 -05:00
Jason Grace
96c224250a
Merge branch 'main' into guide 2024-01-15 21:18:31 -05:00
JasonGrace2282
c31e1b121f Fix reST 2024-01-15 21:17:53 -05:00
Jason Grace
0a9d095372
Merge branch 'main' into guide 2024-01-15 21:16:34 -05:00
JasonGrace2282
59175d8d41 Added ref classes and fixed typos 2024-01-15 21:15:52 -05:00
JasonGrace2282
4ea674342e Merge branch 'guide' of https://github.com/MrDiver/manim into guide 2024-01-15 12:25:55 -05:00
JasonGrace2282
45431916cf Add Updater section 2024-01-15 12:25:50 -05:00
Jason Grace
fbe933596b
Merge branch 'main' into guide 2024-01-15 11:00:02 -05:00
Jason Grace
9596c7169f
Merge branch 'main' into guide 2023-12-28 14:44:23 -05:00
JasonGrace2282
1c8b1c9481 Added rate functions animation 2023-12-28 14:43:24 -05:00
JasonGrace2282
dd9798adc5 Merge branch 'guide' of https://github.com/MrDiver/manim into guide 2023-12-28 09:52:24 -05:00
JasonGrace2282
12198f949b update docstring of ManimColor 2023-12-28 09:37:28 -05:00
JasonGrace2282
3c3f4d83e3 Modified Authors 2023-12-22 13:01:54 -05:00
pre-commit-ci[bot]
d8235da776 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2023-12-21 21:02:42 +00:00
JasonGrace2282
a668648cb6 grammer fixes 2023-12-21 16:00:31 -05:00
Jason Grace
223a4e1393
Merge branch 'main' into guide 2023-12-21 12:12:24 -05:00
JasonGrace2282
8ebc17289b Made into section 2023-12-21 12:06:35 -05:00
Jason Grace
7866e007d3
Merge branch 'main' into guide 2023-12-20 19:22:02 -05:00
pre-commit-ci[bot]
636265ba51 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2023-12-20 17:01:50 +00:00
JasonGrace2282
d261fd3d6f Added VGroup demo 2023-12-20 12:00:51 -05:00
Jason Grace
94121e4d4a
Added knowledge check
Added knowledge check
2023-12-09 18:00:01 -05:00
JasonGrace2282
ba7e90b359 Added knowledge check 2023-12-09 17:57:41 -05:00
Tristan Schulz
0bf0b1a906
Merge branch 'main' into guide 2023-12-09 12:24:25 +01:00
Jason Grace
72753ab0b2
Update `adventure.rst` 2023-12-08 21:07:06 -05:00
JasonGrace2282
59231a89c1 Added Transform and Rate functions 2023-12-08 12:34:52 -05:00
JasonGrace2282
6a74bc22ed Revert commits 2023-12-08 12:34:09 -05:00
JasonGrace2282
598828abfb Added Transform stuff and rate functions 2023-12-08 11:59:43 -05:00
JasonGrace2282
cc06740f95 Added Transform vs ReplacementTransform 2023-12-07 14:14:03 -05:00
JasonGrace2282
1a7cf2affa Added introduction animations 2023-12-07 14:04:34 -05:00
MrDiver
0e9f2f80eb Adding a tour through manim 2023-12-05 19:14:11 +01:00
14 changed files with 1510 additions and 213 deletions

View file

View file

@ -4,4 +4,5 @@ sphinx>=7.3
sphinx-copybutton sphinx-copybutton
sphinxext-opengraph sphinxext-opengraph
sphinx-design sphinx-design
sphinx-togglebutton
sphinx-reredirects sphinx-reredirects

View file

@ -1,2 +1,3 @@
jupyterlab jupyterlab
sphinxcontrib-programoutput sphinxcontrib-programoutput
sphinx-design

View file

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

View file

@ -0,0 +1,696 @@
******************************************************
An Adventure through Manim's Features and Capabilities
******************************************************
.. image:: ../_static/AdventureManim.png
:align: center
**Authors:** `Tristan Schulz <https://github.com/MrDiver>`__ and `Aarush Deshpande <https://github.com/JasonGrace2282>`__
.. note:: This is a work in progress guide and might not be complete at this point
##############
What to expect
##############
This guide will take you on a Tour through the features and capabilities of Manim. The goal is to give you a good overview of what Manim can do and how to use it. It is not meant to be a complete reference, but rather a starting point for your own explorations.
The goal of this guide is to give you a clear path from the basics of Manim to a finished animation. It will not go into detail about the inner workings of Manim, but rather focus on the practical aspects of using it.
At the end of this guide you should be able to create your own animations and have a good understanding of how to use Manim.
.. warning::
Please note that this guide is only for Manim and expects basic knowledge about programming with Python. If you are new to Python you should first learn the basics of Python before you start with Manim.
You can find a full introduction to Python here: https://docs.python.org/3/tutorial/
You can still follow this guide with basic knowledge of Python, but you will have to learn some Python basics along the way in order to understand the code examples.
#################
What are Mobjects
#################
Mobjects are the basic building blocks of Manim. They are the objects that are animated and displayed on the screen.
Mobjects can be anything from simple shapes to complex 3D objects. They can be animated, moved, rotated, scaled and much more.
In this guide we will focus on the 2D Mobjects, but the same principles apply to 3D Mobjects as well.
.. manim:: MobjectsFloating
:hide_source:
class MobjectsFloating(Scene):
def construct(self):
c = Circle()
s = Square()
t = Triangle()
c.shift(UP)
t.shift(LEFT*3+DOWN)
s.shift(RIGHT*3+DOWN)
self.add(c, s, t)
timer = ValueTracker(0)
c.add_updater(lambda m: m.move_to(UP+0.2*DOWN*np.sin(timer.get_value()+1)))
s.add_updater(lambda m: m.move_to(RIGHT*3+DOWN+0.3*DOWN*np.sin(timer.get_value()+2)))
t.add_updater(lambda m: m.move_to(LEFT*3+DOWN+0.3*DOWN*np.sin(timer.get_value()+4)))
self.add(timer)
self.play(timer.animate.set_value(2*np.pi), run_time=5, rate_func=linear)
For a list of all Mobjects you can look at the :doc:`/reference_index/mobjects` Documentation Page. There are many more to explore and you can even create your own Mobjects, which we will cover later.
.. manim:: PredefinedMobjects
:save_last_frame:
:hide_source:
class PredefinedMobjects(Scene):
def construct(self):
c = Circle()
s = Square().set_color(GREEN)
t = Triangle()
graph = FunctionGraph(lambda x: np.sin(x))
axis = Axes()
par = ParametricFunction(lambda t: np.array([np.cos(3*t), np.sin(2*t), 0]), [0, 2*np.pi])
mat = Matrix([["\\pi", 0], [0, 1]])
chart = BarChart(
values=[-5, 40, -10, 20, -3],
bar_names=["one", "two", "three", "four", "five"],
y_range=[-20, 50, 10],
y_length=6,
x_length=10,
x_axis_config={"font_size": 36},
).shift(RIGHT/2)
func = lambda pos: ((pos[0] * UR + pos[1] * LEFT) - pos) / 3
vecfield = ArrowVectorField(func,x_range=[-3,3],y_range=[-3,3])
cross = VGroup(
Line(UP + LEFT, DOWN + RIGHT),
Line(UP + RIGHT, DOWN + LEFT))
a = Circle().set_color(RED).scale(0.5)
b = cross.set_color(BLUE).scale(0.5)
t3 = MobjectTable(
[[a.copy(),b.copy(),a.copy()],
[b.copy(),a.copy(),a.copy()],
[a.copy(),b.copy(),b.copy()]])
t3.add(Line(
t3.get_corner(DL), t3.get_corner(UR)
).set_color(RED))
group = [c, s, t, graph, axis, par, mat, chart, vecfield, t3]
names = ["Circle", "Square", "Triangle", "FunctionGraph", "Axes", "ParametricFunction", "Matrix", "BarChart" ,"ArrowVectorField", "MobjectTable"]
zipped = zip(group, names)
combined = []
for mob, name in zipped:
square = Square()
name = Text(name).scale(0.5)
mob.scale_to_fit_width(square.get_width())
square.scale(1.2)
name.next_to(square, DOWN)
group = VGroup(mob, name, square)
combined.append(group)
all = VGroup(*combined).arrange_in_grid(buff=1,rows=2).scale(0.8).to_edge(UP)
dots = MathTex("\\dots").next_to(all, DOWN, buff=1)
self.add(all, dots)
.. note::
The type of Mobject that is used most of the time is the `VMobject`. This is a Mobject that is made up of `VectorizedPoints`. These are points that are defined by their coordinates and can be connected by lines or curves.
Every time we talk about Mobjects in this guide we mean VMobjects, unless we state otherwise.
=============================
Mobjects and their Attributes
=============================
In order to display Mobjects in your animations you need to add them to the scene. You can do this by calling ``self.add(mobject)`` in the ``construct`` method of your scene.
This tells Manim that you want to display the Mobject in your scene.
.. manim:: CreatingMobjects
:save_last_frame:
class CreatingMobjects(Scene):
def construct(self):
c = Circle()
self.add(c)
This will be the basic structure of all your animations. You will create Mobjects and add them to the scene. Then you can animate them and change their properties.
Try the "Make Interactive" Button and see if you can create a `Square` instead of a `Circle`.
The first line is the name of your scene, in this case it is ``CreatingMobjects``. It inherits from ``Scene``: as we explore later, you'll find examples where we inherit from
class other than ``Scene`` to gain access to more specialized methods. Your animation must take place in the ``construct`` method of your scene, otherwise it will not render.
You can run this scene on your local machine by saving it in a file called ``my_first_scene.py`` and running ``manim -pqm my_first_scene.py`` in the terminal.
------------------
Mobject Attributes
------------------
Mobjects also posses many attributes that you can change. For example you can change the color of a Mobject by calling ``mobject.set_color(color)`` or scale it by calling ``mobject.scale(factor)``.
The basic attributes are the ``points``, ``fill_color``, ``fill_opacity``, ``stroke_color``, ``stroke_opacity``, ``stroke_width``.
The ``points`` define the outline of the Mobject, whereas the color attributes define how this outline is displayed.
A full list of the attributes of :class:`VMobject` can be found in the :doc:`../reference/manim.mobject.types.vectorized_mobject.VMobject` Documentation Page. Please note that depending
on the type of Mobject you are using, there might be additional attributes, which are listed on the corresponding documentation page.
-------------------
Changing the Points
-------------------
Most of the function that you will use in Manim will be functions that change the points of a Mobject. For example ``mobject.shift(direction)`` will move the Mobject in the given direction.
On the other hand, ``mobject.rotate(angle)`` will rotate the Mobject by the given angle.
.. manim:: MobjectPoints
:save_last_frame:
class MobjectPoints(Scene):
def construct(self):
c = Circle()
s = Square()
t = Triangle()
c.shift(3*LEFT)
s.rotate(PI/4)
t.shift(3*RIGHT)
self.add(c, s, t)
------------------
Changing the Color
------------------
Changing the color works in the same way but instead of modifying it you can set it to a new value. For example ``mobject.set_fill(color=color)`` will set the fill color of the Mobject to the given color.
You can also pass in attributes through the constructor of the Mobject. For example ``Circle(fill_color=RED)`` will create a circle with a red fill color.
For a list of parameters that you can pass you can always visit the corresponding Documentation Page in the Reference Manual.
.. manim:: MobjectColor
:save_last_frame:
class MobjectColor(Scene):
def construct(self):
c = Circle(fill_color=YELLOW).shift(3*LEFT)
s = Square()
t = Triangle().shift(3*RIGHT)
c.set_fill(color=RED).set_opacity(1)
s.set_stroke(color=GREEN)
t.set_color(color=BLUE).set_opacity(0.5)
self.add(c, s, t)
-------------------
Test your Knowledge
-------------------
Now that you saw the basic ways to change Mobjects, try to reproduce the following Image. You can use the "Make Interactive" Button of the above Scene to get started.
.. manim:: TestYourKnowledge1
:save_last_frame:
:hide_source:
class TestYourKnowledge1(Scene):
def construct(self):
c = Circle(fill_color=RED,stroke_color=GREEN).shift(3*LEFT)
s = Square(fill_color=GREEN,stroke_color=BLUE).set_opacity(0.2)
t = Triangle(fill_color=RED,stroke_opacity=0).shift(RIGHT)
c.set_fill(color=RED).set_opacity(1)
s.set_stroke(color=GREEN)
t.set_color(color=BLUE).set_opacity(0.5)
self.add(c, s, t)
###################
Animations in Manim
###################
Now that we looked long enough at static Images, let's get to the fun part of Manim. Animations!
Animations are at the core of Manim and are what makes it so powerful. You can animate almost anything in Manim and you can do it in many different ways.
In this section we will look at the different ways to animate Mobjects and how to control the animations.
.. manim:: Manimations1
:hide_source:
class Manimations1(Scene):
def construct(self):
c = Circle().shift(UP).set_color(RED)
s = Square().shift(LEFT*3)
t = Triangle().shift(RIGHT*3)
l = MathTex(r"\mathbf{M}").shift(DOWN).set_fill(opacity=0).set_stroke(color=WHITE, opacity=1, width=5).scale(4)
self.play(AnimationGroup(Create(c), GrowFromCenter(s), Write(l), FadeIn(t), lag_ratio=0.2))
group = VGroup(l,c, s, t)
self.play(group.animate.arrange(RIGHT))
self.play(group.animate.arrange(DOWN))
self.play(group.animate.arrange_in_grid(buff=1,rows=2))
self.play(Unwrite(group))
================================
Introduction to Basic Animations
================================
There are multiple ways to animate the addition and removal of mobjects from the scene. The most common ways to introduce mobjects is with ``FadeIn`` or ``Create``,
and the most common ways to remove objects from the scene are their counterparts: ``FadeOut`` and ``Uncreate``.
.. manim:: BasicAnimations
class BasicAnimations(Scene):
def construct(self):
c1 = Circle().shift(2*LEFT)
c2 = Circle().shift(2*RIGHT)
self.play(FadeIn(c1), Create(c2))
self.play(FadeOut(c1), Uncreate(c2))
--------
Runtimes
--------
You can adjust the duration of each animation individually, or you can set a duration for all in animations in a ``Scene.play`` call.
.. manim:: AnimationRuntimes
class AnimationRuntimes(Scene):
def construct(self):
c = Circle().shift(2*LEFT)
s = Square().shift(2*RIGHT)
# set animation runtimes individually
self.play(Create(c, run_time=2), Create(s, run_time=1))
# in this call, the individual runtimes of each animation
# are overridden by the runtime in the self.play call
self.play(FadeOut(c, run_time=2), FadeOut(s, run_time=1), run_time=1.5)
--------------
Rate Functions
--------------
A rate function allows you to adjust the speed at an animation proceeds.
.. manim:: RateFunctionsExample
class RateFunctionsExample(Scene):
def construct(self):
c1 = Circle().shift(2*LEFT)
c2 = Circle().shift(2*RIGHT)
self.play(
Create(c1, rate_func=rate_functions.linear),
Create(c2, rate_func=rate_functions.ease_in_sine),
run_time=5
)
You can see all of the current ones below:
.. manim:: AllRateFunctions
:hide_source:
class AllRateFunctions(Scene):
def construct(self):
time_progress = ValueTracker(0)
func_grid = VGroup()
exclude = ["wraps", "bezier", "sigmoid", "unit_interval", "zero", "not_quite_there", "squish_rate_func"]
rate_funcs = list(filter(
lambda t: str(t[1])[:10] == "<function " and all(t[0] != s for s in exclude),
rate_functions.__dict__.items(),
))
for name, rate_func in rate_funcs:
plot_bg = Rectangle(height=1.5, width=2.0)
y_zero = DashedLine(stroke_width=1.5, stroke_color=YELLOW)
y_one = DashedLine(stroke_width=0.5, stroke_color=BLUE).shift(0.5*UP)
y_minus_one = y_one.copy().shift(DOWN)
plot_title = (
Text(name, weight=SEMIBOLD, font="Open Sans")
.scale(0.4)
.next_to(plot_bg, UP, buff=0.1)
)
func_grid.add(VGroup(plot_bg, y_zero, y_one, y_minus_one, plot_title))
func_grid.arrange_in_grid(cols=8)
func_grid.stretch_to_fit_height(0.9 * config.frame_height)
func_grid.stretch_to_fit_width(0.9 * config.frame_width)
func_grid.move_to(ORIGIN)
y_zero, y_one = func_grid.submobjects[0].submobjects[1:3]
origin = y_zero.get_start()
height = (y_one.get_start() - origin)[1]
width = (y_zero.get_end() - origin)[0]
funcs = []
dots = VGroup()
for plot_group, (_, rate_func) in zip(func_grid.submobjects, rate_funcs):
origin = plot_group.submobjects[1].get_start()
func = lambda t, o=origin, rf=rate_func: o + np.array([width*t, height*rf(t), 0])
funcs.append(func)
plot = (
ParametricFunction(
func,
t_range=[0, 1, 0.01],
use_smoothing=False,
color=YELLOW,
)
)
plot_group.add(plot)
dot = Dot().scale(0.5).move_to(func(0))
dots.add(dot)
def dot_updater(dots):
t = time_progress.get_value()
for dot, func in zip(dots.submobjects, funcs):
dot.move_to(func(t))
self.add(func_grid, dots)
dots.add_updater(dot_updater)
# there is some wacky rate function giving out-of-bounds results...
self.play(
time_progress.animate.set_value(1),
run_time=3,
)
Alternatively, you can create your own. A rate function takes in a value between 0 and 1 representing the "progress" of the animation. You can think of this as the
ratio of the time passed since the animation started, to the runtime of the animation. It should return how much of the animation should have been completed by that time.
As an example, check out the rate function below.
.. manim:: CustomRateFunctions
class CustomRateFunctions(Scene):
def construct(self):
def there_and_back_three(alpha: float):
if alpha <= 1/3:
return 3*alpha
elif alpha <= 2/3:
return 1-3*(alpha-1/3)
else:
return 3*(alpha-2/3)
self.play(Create(Circle(), rate_func=there_and_back_three), run_time=4)
This rate function will spend 1/3rd of the time finishing the animate, the next 1/3rd of the time "undoing" the animation,
and the final 1/3rd of the animation replaying the first 1/3rd. As you can see, it returns the amount of the animation
completed as a value between 0 to 1.
----------------------
The ``Wait`` Animation
----------------------
Now all these animations seem a bit rushed. Luckily, Manim allows us to create periods of time where nothing is happening.
Let's look at an example:
.. manim:: BasicAnimationWithWait
class BasicAnimationWithWait(Scene):
def construct(self):
c = Circle()
self.play(Create(c))
self.wait() # wait for one second by default
self.play(FadeOut(c))
self.wait(0.5) # wait half a second
A little bit later on, we will learn how to leverage the ``stop_condition`` parameter to stop after a certain event happens.
=====================
Transforming Mobjects
=====================
Manim allows us to smoothly transform one :class:`.Mobject` into another using :class:`.Transform` and :class:`.ReplacementTransform`.
``Transform(mob1, mob2)`` turns the attributes of ``mob1`` into the attributes of ``mob2``.
.. manim:: TransformAnimation
class TransformAnimation(Scene):
def construct(self):
c = Circle()
self.add(c)
self.play(Transform(c, Square()))
self.play(FadeOut(c)) # fadeout c
-----------------------------------------
``Transform`` vs ``ReplacementTransform``
-----------------------------------------
While :class:`Transform(mob1, mob2)` changes the attributes of ``mob1`` into the attributes of ``mob2`` by copying the values, :class:`ReplacementTransform(mob1, mob2)` instead replaces ``mob1`` in the
scene with ``mob2``.
Here is the same scene in the last section, but using :class:`.ReplacementTransform`:
.. manim:: ReplacementTransformAnimation
class ReplacementTransformAnimation(Scene):
def construct(self):
c = Circle()
s = Square()
self.add(c)
self.play(ReplacementTransform(c, s))
self.play(FadeOut(s)) # fadeout s
Ultimately, the choice of which to use is up to the programmer. However, some examples like the one below make the code simpler when using one over the other.
.. manim:: CyclingShapesAnimation
class CyclingShapesAnimation(Scene):
def construct(self):
mob = Circle()
shapes = (Square(), Triangle(), Circle().set_fill(color=RED, opacity=0.5))
self.add(mob)
for shape in shapes:
# if we use transform, we avoid having to
# keep track of the previously transformed
# shape
self.play(Transform(mob, shape))
self.wait(0.3)
-------------------
``.animate`` Syntax
-------------------
One of the most powerful features of Manim is it's :attr:`~.Mobject.animate` syntax.
It allows you to animate the changing of an attribute of a mobject. You can see an example below:
.. manim:: AnimateSyntaxExample
class AnimateSyntaxExample(Scene):
def construct(self):
c = Circle()
self.add(c)
self.play(c.animate.shift(RIGHT))
self.play(c.animate.to_corner(DL).set_fill(color=RED, opacity=0.4))
.. note::
``.animate`` works by interpolating between the initial and the final mobject. As such, beware when using ``.animate.rotate`` with angles greater than pi radians
as it may not produce the intended animation.
-------------------
Test Your Knowledge
-------------------
Try to create the following animation!
.. manim:: TestBasicAnimationKnowledge
:hide_source:
class TestBasicAnimationKnowledge(Scene):
def construct(self):
c = Circle().set_fill(color=RED, opacity=0.5)
s = Star().set_stroke(color=YELLOW).set_fill(color=YELLOW, opacity=0.3)
t = Triangle().set_fill(color=BLUE, opacity=0.1)
VGroup(c, s, t).arrange(RIGHT).move_to(ORIGIN) # users will arrange manually
self.play(
DrawBorderThenFill(c),
GrowFromPoint(s, ORIGIN),
SpinInFromNothing(t),
run_time=2
)
self.wait()
for mob in (s, t):
self.play(Transform(c, mob))
self.remove(mob)
self.wait(0.2)
self.play(c.animate.move_to(ORIGIN))
Hint: you might need to look at different :doc:`/reference_index/animations`!
=================
Grouping Mobjects
=================
Oftentimes it is convenient to animate the movement of several mobjects at once. To help accomplish this goal, manim provides two classes: ``Group`` and ``VGroup``.
99% of the time, ``VGroup``'s are used, but if you're dealing with some form of an ``ImageMobject`` you will have to use ``Group``. Here's an example of how groups can be useful:
.. manim:: GroupingExample
class GroupingExample(Scene):
def construct(self):
tri = Triangle()
sq = Square()
circ = Circle()
grp1 = VGroup(tri,sq,circ).arrange(RIGHT)
grp2 = VGroup(tri,circ)
self.add(tri,sq,circ)
self.play(grp1.animate.shift(UP))
self.play(grp2.animate.shift(2*DOWN))
self.play(tri.animate.next_to(circ,RIGHT))
self.play(grp1.animate.shift(UP))
self.wait()
.. note::
From now onwards, if we refer to a group we are referring to a ``VGroup``, unless specifically stated otherwise.
Groups also have a bunch of methods to make your life easier. Take a look at some in the example below:
.. manim:: GroupingMethodsExample
class GroupingMethodsExample(Scene):
def construct(self):
group = VGroup(
Square(),
Star(color=YELLOW).set_fill(color=YELLOW, opacity=0.5),
Triangle(),
Circle().set_fill(color=RED, opacity=0.5)
)
self.play(group.animate.arrange(DOWN), run_time=2)
self.play(group.animate.arrange_in_grid(cols=2), run_time=2)
for mob in group:
self.play(Uncreate(mob))
self.wait(0.2)
##################
Syncing Animations
##################
In many animations it makes sense to have things moving together at the same rate.
However, Manim gives you better ways to accomplish this task then by copying the same parameters
everywhere.
=========
Updaters
=========
Manim allows you to "update" the attributes of a mobject every frame of an animation
via something called updaters. There are two types: normal updaters, and time-based updaters.
.. note::
The way manim works with time based updaters is going to be reworked at some point. Stay
up to date with the changelogs to make sure your code will work.
---------------
Normal Updaters
---------------
You can attach an updater to a mobject via the `.add_updater` method. It takes a function whose
first parameter is the mobject itself, and you can modify the mobject however you want.
For example, here we used ``lambda m: m.next_to(d, RIGHT)``. In this case, ``m`` is the Mobject ``Text("Hi!")``.
.. manim:: UpdaterExample
:ref_classes: MoveAlongPath TracedPath
class UpdaterExample(Scene):
def construct(self):
t = Text("Hi!")
d = Dot(color=ORANGE)
trace = TracedPath(d.get_center, dissipating_time=1, stroke_color=RED)
t.add_updater(lambda m: m.next_to(d, RIGHT))
self.add(t, trace)
self.play(MoveAlongPath(d, Square(), rate_func=linear, run_time=3))
self.wait()
-------------------
Time Based Updaters
-------------------
Time based updaters are just like normal updaters, but take an extra parameter ``dt``.
This represents how much time has passed between the last call of your updater.
.. manim:: TimeBasedUpdater
class TimeBasedUpdater(Scene):
def construct(self):
time = 0
d = DecimalNumber(0)
def updater(m: VMobject, dt: float):
# access the time defined outside this function
nonlocal time
time+=dt
m.set_value(time)
d.add_updater(updater)
self.add(d)
self.wait(1.1)
=============
ValueTrackers
=============
ValueTrackers are the real things that allow you to synchronize multiple animations at once.
They are basically just stored values, but you can animate their ``.set_value`` to produce animations.
.. manim:: ValueTrackerShowcase
class ValueTrackerShowcase(Scene):
def construct(self):
line = Rectangle(height=1, width=4).set_stroke(color=WHITE, opacity=1).move_to(ORIGIN)
vt = ValueTracker(1e-2) # setting to zero creates bugs with stretch_to_fit_width
progress = Rectangle(height=1, width=vt.get_value()).set_stroke(color=RED,opacity=1)
progress.add_updater(lambda p: p.stretch_to_fit_width(vt.get_value()).align_to(line, LEFT))
d = DecimalNumber(0).to_edge(UP)
d.add_updater(lambda d: d.set_value(vt.get_value()))
self.add(d,line,progress)
self.play(vt.animate.set_value(4), rate_func=linear, run_time=1.5)
self.wait(0.1)
-------------
always_redraw
-------------
``always_redraw`` is a simple function that allows you to recreate a mobject at
every frame of the animation. As an example, check out this animation:
.. manim:: AlwaysRedrawTangentAnimation
class AlwaysRedrawTangentAnimation(Scene):
def construct(self):
ax = Axes()
sine = ax.plot(np.sin, color=RED)
alpha = ValueTracker(0)
point = always_redraw(
lambda: Dot(
sine.point_from_proportion(alpha.get_value()),
color=BLUE
)
)
tangent = always_redraw(
lambda: TangentLine(
sine,
alpha=alpha.get_value(),
color=YELLOW,
length=4
)
)
self.add(ax, sine, point, tangent)
self.play(alpha.animate.set_value(1), rate_func=linear, run_time=2)
-------------------
Test Your Knowledge
-------------------
Try to recreate the following animation!
.. manim:: KnowledgeCheckUpdaters
:hide_source:
class KnowledgeCheckUpdaters(Scene):
def construct(self):
l1 = Line(6*LEFT,6*RIGHT)
l2 = Line(4*DL,3*UR)
vt = ValueTracker(0)
d1, d2 = Dot(color=RED), Dot(color=ORANGE)
txt = MathTex(r"\Delta", color=RED).add_updater(lambda t: t.next_to(d2, LEFT)).scale(2)
bt = TracedPath(d1.get_center, stroke_color=RED)
tt = TracedPath(d2.get_center, stroke_color=ORANGE)
d1.add_updater(lambda d: d.move_to(l1.point_from_proportion(vt.get_value())))
d2.add_updater(lambda d: d.move_to(l2.point_from_proportion(vt.get_value())))
self.add(d1, d2, bt, tt, txt)
self.play(vt.animate.set_value(1), run_time=1.5)
self.play(vt.animate.set_value(0.8))
self.play(Create(Line(d1.get_center(), d2.get_center(), color=YELLOW)))
vmob = VMobject(color=ORANGE).set_points_as_corners([ORIGIN, d1.get_center(), d2.get_center(), ORIGIN]).set_fill(color=[RED,ORANGE,YELLOW], opacity=1).set_z_index(-50)
txt.clear_updaters()
self.play(Create(vmob), txt.animate.move_to(vmob.get_center()).set_z_index(50).set_color(BLUE))

View file

@ -0,0 +1,38 @@
##############################
Exploring Manim's Capabilities
##############################
=============
What is this?
=============
One of the hardest parts of learning how to use Manim is to deviate from the quickstart and basic examples given in the documentation,
and coding your own animation. By the end of this, you should have had some experience learning how to go about with this!
--------------------
Part One: The Basics
--------------------
Here we talk about the basics: what are Mobjects, Animations, Groups, Updaters, and many other basic aspects of Manim. It gives many examples
about each concept, and encourages you to test your understanding by recreating certain sequences of animations.
Feel free to return to this section anytime you need a refresher on something during part two.
---------------------
Part Two: The Project
---------------------
.. note:: As of right now, this section is still under construction.
Here is the fun part: We go through and make our own creation from start to finish, explaining how to effectively search the documentation,
and come up with the logic to make your ideas come to life. By the end of this section, you should be fully prepared to tackle your own project.
=================
Table of Contents
=================
.. toctree::
:maxdepth: 2
basics
project

View file

@ -0,0 +1,519 @@
***************
A Basic Project
***************
.. image:: ../_static/AdventureManim.png
:align: center
**Authors:** `Tristan Schulz <https://github.com/MrDiver>`__ and `Aarush Deshpande <https://github.com/JasonGrace2282>`__
.. note:: This is a work in progress guide and might not be complete at this point
############
Introduction
############
Throughout this guide, we'll walk you through how to create a simple 30 second video about vector addition. If you don't
already know what that is, it's recommended you watch `this <https://youtu.be/fNk_zzaMoSs?si=fQDML214IeNl0OZ1>`_ video
by the original creator of manim, 3Blue1Brown.
The next step is figuring out how the project should look: what content should it cover, in what order, etc. In this
tutorial, we'll focus on two parts of vector addition: the algebraic way, and the geometric way. For the algebraic way,
we'll show two vectors (as matrices) being added, and give a short explanation. After that we'll show the typical tip-to-tail
method for adding vectors graphically. Of course, choosing good examples is very important to help the viewer understand.
In our case, we'll use the two vectors :math:`v_1\equiv\langle 2, 1\rangle` and :math:`v_2\equiv\langle 0,-3 \rangle`.
################
Vector Addition
################
We'll start with the basic setup needed for every manim video.
To do this, we can use the manim cli to speed stuff up. In the terminal,
run::
manim init project VectorAddition
This should create a folder called ``VectorAddition`` with the basic setup.
.. hint::
You may want to open this folder in your IDE (like VS Code, or PyCharm).
You will have a ``manim.cfg`` file, where you configuration will be stored, and a ``main.py`` script.
The ``main.py`` script is where you will write your scenes.
If you did it correctly, running the python file with ``manim -p main.py`` should render a scene
with a circle being created:
.. manim:: CreateCircle
:hide_source:
class CreateCircle(Scene):
def construct(self):
circle = Circle()
circle.set_fill(PINK, opacity=0.5)
square = Square()
square.flip(RIGHT)
square.rotate(-3 * TAU / 8)
self.play(Create(square))
self.play(Transform(square, circle))
self.play(FadeOut(square))
============
Introduction
============
First we need to introduce the viewer to what we're going to talk about. Ideally,
it would be an interesting hook, but for the sake of learning the library we will
stick with a simple text-based intro. Try to recreate the following:
.. manim:: AdventureIntro
:hide_source:
:ref_classes: Tex Text Write Unwrite Create
class AdventureIntro(Scene):
def construct(self):
intro = Text("Let's try to add two vectors!")
# put an r"" instead of a normal string so we don't have any special characters like \n
vec_txts = Tex(r"We'll use $\boldsymbol{\vec{v}_1}=(2, 2)$ and $\boldsymbol{\vec{v}_2}=(0, -3)$")
self.play(Create(intro))
self.wait(1)
# "grey out" the intro and shift it upwards as we write the second line
self.play(intro.animate.shift(2*UP).set_opacity(0.5), Write(vec_txts))
self.wait(1)
self.play(Unwrite(intro), Unwrite(vec_txts), run_time=.5)
self.wait(0.2)
.. admonition:: Authors solution
:class: dropdown
.. code-block:: python
class AdventureIntro(Scene):
def construct(self):
intro = Text("Let's try to add two vectors!")
# put an r"" instead of a normal string so we don't have any special characters like \n
vec_txts = Tex(
r"We'll use $\boldsymbol{\vec{v}_1}=(2, 2)$ and $\boldsymbol{\vec{v}_2}=(0, -3)$"
)
self.play(Create(intro))
self.wait(1)
# "grey out" the intro and shift it upwards as we write the second line
self.play(intro.animate.shift(2 * UP).set_opacity(0.5), Write(vec_txts))
self.wait(1)
self.play(Unwrite(intro), Unwrite(vec_txts), run_time=0.5)
self.wait(0.2)
============================
Algebraic vector addition
============================
Then, let's show the viewer how vector addition between two vectors is done algebraically.
Once again, try to recreate the following:
.. manim:: AlgebraicAddition
:hide_source:
:ref_classes: Title MathTex Paragraph Tex Text Write Unwrite Create FadeIn
class AlgebraicAddition(Scene):
def construct(self):
title = Title("Vector Addition Algebraically")
v1x, v1y = (2, 2)
v2x, v2y = (0, -3)
math = MathTex(r"""
\begin{bmatrix} %(v1x)d \\ %(v1y)d \end{bmatrix}
+\begin{bmatrix} %(v2x)d \\ %(v2y)d \end{bmatrix}
""" % {
'v1x': v1x,
'v2x': v2x,
'v1y': v1y,
'v2y': v2y
}).shift(DOWN)
resultant_vector = r"=\begin{bmatrix} %(x)d \\ %(y)d \end{bmatrix}" % {
'x': v1x+v2x,
'y': v1y+v2y
}
math_with_answer = MathTex(
math.get_tex_string()+resultant_vector
).move_to(math.get_center())
self.play(Write(math), FadeIn(title))
self.wait(2)
self.play(
math.animate.shift(2*UP).set_opacity(0.5),
Write(math_with_answer)
)
conclusion = Paragraph("As you can see,\nYou add each component individually").to_edge(DOWN)
self.play(Write(conclusion))
self.wait(2)
self.play(Unwrite(math), Unwrite(math_with_answer), Unwrite(conclusion), Unwrite(title))
Hints
-----
Use :class:`.Title` to display the title at the top of the Scene.
Use :class:`.MathTex` to represent the matrices, and try not to hardcode the values into the LaTeX string. Instead, you can use python string formatting and numpy vector addition, which will make it easier to change the vectors later if we need to.
.. code-block:: python
v1x, v1y = (2, 2)
v2x, v2y = ...
math = MathTex(r"""
... %(v1x)d \\ %(v1y)d ...
+ ... %(v2x)d \\ %(v2y)d ...
""" % {
'v1x': v1x,
'v2x': v2x,
'v1y': v1y,
'v2y': v2y
})
.. admonition:: Authors solution
:class: dropdown
.. code-block:: python
class AlgebraicAddition(Scene):
def construct(self):
title = Title("Vector Addition Algebraically")
v1x, v1y = (2, 2)
v2x, v2y = (0, -3)
math = MathTex(r"""
\begin{bmatrix} %(v1x)d \\ %(v1y)d \end{bmatrix}
+\begin{bmatrix} %(v2x)d \\ %(v2y)d \end{bmatrix}
""" % {
'v1x': v1x,
'v2x': v2x,
'v1y': v1y,
'v2y': v2y
}).shift(DOWN)
resultant_vector = r"=\begin{bmatrix} %(x)d \\ %(y)d \end{bmatrix}" % {
'x': v1x+v2x,
'y': v1y+v2y
}
math_with_answer = MathTex(
math.get_tex_string()+resultant_vector
).move_to(math.get_center())
self.play(Write(math), FadeIn(title))
self.wait(2)
self.play(
math.animate.shift(2*UP).set_opacity(0.5),
Write(math_with_answer)
)
conclusion = Paragraph("As you can see,\nYou add each component individually").to_edge(DOWN)
self.play(Write(conclusion))
self.wait(2)
self.play(Unwrite(math), Unwrite(math_with_answer), Unwrite(conclusion), Unwrite(title))
============================
Geometric vector addition
============================
Lastly, let's show the vector addition geometrically. Try your best to reconstruct the following:
.. manim:: GeometricAddition
:hide_source:
:ref_classes: Title MathTex Paragraph Tex Text Write Unwrite Create FadeIn NumberPlane Arrow AnimationGroup ReplacementTransform VGroup
class VectorGroup(VGroup):
def __init__(
self, start, end, labelname: str,
vector_color: ParsableManimColor, direction = RIGHT,
plane: NumberPlane | None = None, **kwargs
) -> None:
if plane is not None:
# if using a plane convert from plane units
# to Munits
start = plane.c2p(*start)
end = plane.c2p(*end)
self.vector = Arrow(
start,
end,
color=vector_color,
buff=0
)
self.label = MathTex(labelname, color=vector_color)
def label_updater(m: MathTex, d=direction):
m.next_to(self.vector, direction=d, **kwargs)
self.label.add_updater(label_updater, call_updater=True)
super().__init__(self.vector, self.label, **kwargs)
@override_animation(Create)
def _create_vec_write_label(self) -> AnimationGroup:
return AnimationGroup(
Create(self.vector),
Write(self.label),
lag_ratio=0
)
@override_animation(Uncreate)
def _uncreate_vec_unwrite_label(self) -> AnimationGroup:
return AnimationGroup(
Uncreate(self.vector),
Unwrite(self.label),
lag_ratio=0
)
class GeometricAddition(Scene):
def construct(self):
title = Text("Now let's take a look at it geometrically")
self.play(Write(title))
self.wait(2)
self.play(Unwrite(title))
plane = NumberPlane()
sum_point = (2, -1, 0)
v1 = VectorGroup(
ORIGIN,
(2, 2, 0),
r"\boldsymbol{\vec{v}_1}",
RED,
direction=UP,
plane=plane
)
v2 = VectorGroup(
ORIGIN,
(0, -3, 0),
r"\boldsymbol{\vec{v}_2}",
YELLOW,
direction=LEFT,
plane=plane
)
v1moved = VectorGroup(
(0, -3, 0),
sum_point,
r"\boldsymbol{\vec{v}_1}",
v1.vector.get_color(),
plane=plane
)
v2moved = VectorGroup(
(2, 2, 0),
sum_point,
r"\boldsymbol{\vec{v}_2}",
v2.vector.get_color(),
plane=plane
)
sum_vec = VectorGroup(
ORIGIN,
sum_point,
r"\boldsymbol{\vec{v}_1}+\boldsymbol{\vec{v}_2}",
ORANGE,
direction=DOWN,
plane=plane
)
self.play(Create(plane), Create(v1))
self.wait(0.5)
self.play(Create(v2))
self.wait()
# animate movement of vectors
self.play(
Succession(
ReplacementTransform(v1.copy(), v1moved),
ReplacementTransform(v2.copy(), v2moved)
)
)
self.wait()
# draw sum vector
self.play(Create(sum_vec))
self.wait()
self.play(*[
Uncreate(x)
for x in (
plane,
v1,
v2,
v1moved,
v2moved,
sum_vec
)
])
Hints
-----
Use :class:`.NumberPlane` to define the cartesian plane.
Use :class:`.Arrow` for the vectors.:
To make sure the label of the vector and the vector shift together, you can define a custom :class:`.VGroup` subclass.
Take a look at the decorator :func:`.override_animation` to override the :class:`.Create` and :class:`.Uncreate` animations, it will come in handy when animating the subclass.
.. code-block:: python
class VectorGroup(VGroup):
def __init__(
...
) -> None:
...
@override_animation(Create)
def _create_vec_write_label(self) -> AnimationGroup:
return AnimationGroup(
...
)
@override_animation(Uncreate)
def _uncreate_vec_unwrite_label(self) -> AnimationGroup:
return AnimationGroup(
...
)
.. admonition:: Authors solution
:class: dropdown
.. code-block:: python
class VectorGroup(VGroup):
def __init__(
self, start, end, labelname: str,
vector_color: ParsableManimColor, direction = RIGHT,
plane: NumberPlane | None = None, **kwargs
) -> None:
if plane is not None:
# if using a plane convert from plane units
# to Munits
start = plane.c2p(*start)
end = plane.c2p(*end)
self.vector = Arrow(
start,
end,
color=vector_color,
buff=0
)
self.label = MathTex(labelname, color=vector_color)
def label_updater(m: MathTex, d=direction):
m.next_to(self.vector, direction=d, **kwargs)
self.label.add_updater(label_updater, call_updater=True)
super().__init__(self.vector, self.label, **kwargs)
@override_animation(Create)
def _create_vec_write_label(self) -> AnimationGroup:
return AnimationGroup(
Create(self.vector),
Write(self.label),
lag_ratio=0
)
@override_animation(Uncreate)
def _uncreate_vec_unwrite_label(self) -> AnimationGroup:
return AnimationGroup(
Uncreate(self.vector),
Unwrite(self.label),
lag_ratio=0
)
class GeometricAddition(Scene):
def construct(self):
title = Text("Now let's take a look at it geometrically")
self.play(Write(title))
self.wait(2)
self.play(Unwrite(title))
plane = NumberPlane()
sum_point = (2, -1, 0)
v1 = VectorGroup(
ORIGIN,
(2, 2, 0),
r"\boldsymbol{\vec{v}_1}",
RED,
direction=UP,
plane=plane
)
v2 = VectorGroup(
ORIGIN,
(0, -3, 0),
r"\boldsymbol{\vec{v}_2}",
YELLOW,
direction=LEFT,
plane=plane
)
v1moved = VectorGroup(
(0, -3, 0),
sum_point,
r"\boldsymbol{\vec{v}_1}",
v1.vector.get_color(),
plane=plane
)
v2moved = VectorGroup(
(2, 2, 0),
sum_point,
r"\boldsymbol{\vec{v}_2}",
v2.vector.get_color(),
plane=plane
)
sum_vec = VectorGroup(
ORIGIN,
sum_point,
r"\boldsymbol{\vec{v}_1}+\boldsymbol{\vec{v}_2}",
ORANGE,
direction=DOWN,
plane=plane
)
self.play(Create(plane), Create(v1))
self.wait(0.5)
self.play(Create(v2))
self.wait()
# animate movement of vectors
self.play(
Succession(
ReplacementTransform(v1.copy(), v1moved),
ReplacementTransform(v2.copy(), v2moved)
)
)
self.wait()
# draw sum vector
self.play(Create(sum_vec))
self.wait()
self.play(*[
Uncreate(x)
for x in (
plane,
v1,
v2,
v1moved,
v2moved,
sum_vec
)
])
################
The Final Result
################
Putting it all together, we can render the final result.
.. include:: vector_addition.rst

View file

@ -0,0 +1,179 @@
.. manim:: Adventure
:hide_source:
class VectorGroup(VGroup):
def __init__(
self, start, end, labelname: str,
vector_color: ParsableManimColor, direction = RIGHT,
plane: NumberPlane | None = None, **kwargs
) -> None:
if plane is not None:
# if using a plane convert from plane units
# to Munits
start = plane.c2p(*start)
end = plane.c2p(*end)
self.vector = Arrow(
start,
end,
color=vector_color,
buff=0
)
self.label = MathTex(labelname, color=vector_color)
def label_updater(m: MathTex, d=direction):
m.next_to(self.vector, direction=d, **kwargs)
self.label.add_updater(label_updater, call_updater=True)
super().__init__(self.vector, self.label, **kwargs)
@override_animation(Create)
def _create_vec_write_label(self) -> AnimationGroup:
return AnimationGroup(
Create(self.vector),
Write(self.label),
lag_ratio=0
)
@override_animation(Uncreate)
def _uncreate_vec_unwrite_label(self) -> AnimationGroup:
return AnimationGroup(
Uncreate(self.vector),
Unwrite(self.label),
lag_ratio=0
)
class Adventure(Scene):
"""Goal: Make an example showcasing manim's features"""
def construct(self) -> None:
intro = Text("Let's try to add two vectors!")
vec_txts = Tex(r"We'll use $\boldsymbol{\vec{v}_1}=(2, 2)$ and $\boldsymbol{\vec{v}_2}=(0, -3)$")
self.play(Create(intro))
self.wait(1)
self.play(intro.animate.shift(2*UP).set_opacity(0.5), Write(vec_txts))
self.wait(1)
self.play(Unwrite(intro), Unwrite(vec_txts), run_time=.5)
self.wait(0.2)
self.show_addition_math()
self.wait(0.2)
self.show_vector_addition()
outro = Text("Thanks for watching!")
self.play(Create(outro))
self.wait()
def show_addition_math(self) -> None:
title = Title("Vector Addition Algebraically")
v1x, v1y = (2, 2)
v2x, v2y = (0, -3)
math = MathTex(r"""
\begin{bmatrix} %(v1x)d \\ %(v1y)d \end{bmatrix}
+\begin{bmatrix} %(v2x)d \\ %(v2y)d \end{bmatrix}
""" % {
'v1x': v1x,
'v2x': v2x,
'v1y': v1y,
'v2y': v2y
}).shift(DOWN)
resultant_vector = r"=\begin{bmatrix} %(x)d \\ %(y)d \end{bmatrix}" % {
'x': v1x+v2x,
'y': v1y+v2y
}
math_with_answer = MathTex(
math.get_tex_string()+resultant_vector
).move_to(math.get_center())
self.play(Write(math), FadeIn(title))
self.wait(2)
self.play(
math.animate.shift(2*UP).set_opacity(0.5),
Write(math_with_answer)
)
conclusion = Paragraph("As you can see,\nYou add each component individually").to_edge(DOWN)
self.play(Write(conclusion))
self.wait(2)
self.play(Unwrite(math), Unwrite(math_with_answer), Unwrite(conclusion), Unwrite(title))
def show_vector_addition(self) -> None:
title = Text("Now let's take a look at it geometrically")
self.play(Write(title))
self.wait(2)
self.play(Unwrite(title))
plane = NumberPlane()
sum_point = (2, -1, 0)
v1 = VectorGroup(
ORIGIN,
(2, 2, 0),
r"\boldsymbol{\vec{v}_1}",
RED,
direction=UP,
plane=plane
)
v2 = VectorGroup(
ORIGIN,
(0, -3, 0),
r"\boldsymbol{\vec{v}_2}",
YELLOW,
direction=LEFT,
plane=plane
)
v1moved = VectorGroup(
(0, -3, 0),
sum_point,
r"\boldsymbol{\vec{v}_1}",
v1.vector.get_color(),
plane=plane
)
v2moved = VectorGroup(
(2, 2, 0),
sum_point,
r"\boldsymbol{\vec{v}_2}",
v2.vector.get_color(),
plane=plane
)
sum_vec = VectorGroup(
ORIGIN,
sum_point,
r"\boldsymbol{\vec{v}_1}+\boldsymbol{\vec{v}_2}",
ORANGE,
direction=DOWN,
plane=plane
)
self.play(Create(plane), Create(v1))
self.wait(0.5)
self.play(Create(v2))
self.wait()
# animate movement of vectors
self.play(
Succession(
ReplacementTransform(v1.copy(), v1moved),
ReplacementTransform(v2.copy(), v2moved)
)
)
self.wait()
# draw sum vector
self.play(Create(sum_vec))
self.wait()
self.play(*[
Uncreate(x)
for x in (
plane,
v1,
v2,
v1moved,
v2moved,
sum_vec
)
])

View file

@ -51,6 +51,7 @@ extensions = [
"sphinx.ext.inheritance_diagram", "sphinx.ext.inheritance_diagram",
"sphinxcontrib.programoutput", "sphinxcontrib.programoutput",
"myst_parser", "myst_parser",
"sphinx_togglebutton",
"sphinx_design", "sphinx_design",
"sphinx_reredirects", "sphinx_reredirects",
] ]

View file

@ -85,4 +85,22 @@ Attention
.. attention:: .. attention::
A attention A attention
Dropdown
~~~~~~~~~
.. code-block:: rest
.. admonition:: A dropdown
:class: dropdown
A dropdown
Make sure you leave a line between ":class:" and the text below, otherwise the dropdown won't render.
.. admonition:: A dropdown
:class: dropdown
A dropdown
You can find further information about Admonitions here: https://pradyunsg.me/furo/reference/admonitions/ You can find further information about Admonitions here: https://pradyunsg.me/furo/reference/admonitions/

View file

@ -7,4 +7,5 @@ Tutorials & Guides
tutorials/index tutorials/index
guides/index guides/index
adventure/index
faq/index faq/index

268
poetry.lock generated

File diff suppressed because it is too large Load diff

View file

@ -92,6 +92,7 @@ Sphinx = "^7.2.6"
sphinx-copybutton = "^0.5.2" sphinx-copybutton = "^0.5.2"
sphinxcontrib-programoutput = "^0.17" sphinxcontrib-programoutput = "^0.17"
sphinxext-opengraph = "^0.9.1" sphinxext-opengraph = "^0.9.1"
sphinx-togglebutton = "^0.3.2"
types-decorator = "^0.1.7" types-decorator = "^0.1.7"
types-Pillow = "^10.1.0.2" types-Pillow = "^10.1.0.2"
types-Pygments = "^2.17.0.0" types-Pygments = "^2.17.0.0"