Manim is a python library for programming images or video. It finds appeal among science communicators as it can be used to make high-quality graphics. I consider many well-made Manim graphics to be borderline art.

Manim started as a personal project of Grant Sanderson for creating 3Blue1Brown ↗ videos and later spawned a community that created Manim community edition ↗. It is perhaps the best way to convert mathematics to video. To use this tool to create a good video one needs a field expertise and some knowledge of programming.

In this post, we introduce Manim from the very beginning and provide tutorial and practice examples to streamline learning. To avoid any confusion all examples contain the entire source code.

Basics & Drawing images

First, we focus on how to draw non-animated images. We explore various shapes and how to connect them.

Project setup & compilation

Follow installation instructions ↗ to get Manim on your system. Then setup a project ↗.

This tutorial is created with conjunction with a public Github repository ↗ that you may download and try. In general, you will be able to run a command of the following structure to get an output.

manim [-p] -ql <file.py> <Class>
  • Command itself depends on the version you get – manim (community version, used here) or manimgl (Grant’s version).
  • Flags you will usually use are -p to display the output, and -ql or -qh to set quality. They can be squished to e.g. -pql.
  • Next, file.py points to your source code. For cleanliness, we split examples into different sources and put them into folders, so our command usually contains e.g. examples/shapes.py.
  • Last, Class refers to a class (that inherits Scene) within the source code. One file can contain many scenes and setting this class selects which one should be prepared. We default its name to Main but this is just our convention.

If you set up Manim correctly and download the repository you should be able to run the following command that produces and opens the final picture.

manim -pql examples/sample.py Main
import manim

class Main(manim.Scene):
    def construct(self):
        self.add(manim.Text("Hello Manim!"))
sample

Once you can run Manim and get picture or video proceed with this tutorial.

A note about python

Make sure you are using Python 3 (not Python 2).

To use Manim classes, methods, and constants, we need to include them. Manim tutorials usually have from manim include * as the first line. This includes all Manim things to the main namespace. At first, this tutorial will include explicitly using from manim include <thing, ...> or call through Manim (e.g. instead of Scene and importing it, just import manim and call manim.Scene) or its alias (include manim as m and call m.Scene). We will use star inclusion in later examples as we should be familiar with how includes work at that point.

Brief introduction & first examples

A Manim project consists of scenes. Manim distinguishes two main types of things you have in your code – objects and animations. When you render a scene that does not include any animation (calling self.animate or self.wait) you will get an image, otherwise, the output is video.

As you already saw above, Manim has a class for a scene. Your python code can live outside of this scene, but whatever you want to be drawn must do something in the scene’s construct(self) method. The self here represents the scene and it provides methods that allow you to interact with the scene. A typical way to add shapes to a scene is via self.add method. By default, any object is placed at $(0,0)$ coordinates.

import manim
# <imports>
# other code

class SceneName(manim.Scene):
    def construct(self):
        # your Manim code
        self.add(manim.Text("Hello Manim!"))

There are many things that can be added to a scene. You may find Manim objects (also called Mobjects) in the documentation ↗. Many objects “inherit” from others and allow you to add objects using a simpler input method. For example, Line draws a line if you provide start and end; TangentLine is based on Line and given a specific circle it computes proper endpoints so that the line is tangent to it.

Let us now list majority of the useful geometric Mobjects.

Note that the following (and some of the further) code generates an overview picture. In such cases, the resulting image is more important than the code. It is not necessary to understand the code right now.

from manim import *
config.frame_width=2

class Main(Scene):
    def construct(self):
        label = MathTex(r'\alpha', color=BLACK)
        grp = Group(*[
            Dot(),
            AnnotationDot(),
            LabeledDot(label),
        ])
        self.add(grp.arrange())
dots
from manim import *
config.frame_width=5.5

class Main(MovingCameraScene):
    def construct(self):
        s = ORIGIN
        t = 2*DOWN
        self.camera.frame.set(ratio=3)
        grp = Group(*[
            Line(s, t),
            Arrow(s, t),
            Arrow(s, t, buff=0),
            DoubleArrow(s, t, buff=0),
            ArcBetweenPoints(s, t),
            CurvedArrow(s, t),
            CurvedDoubleArrow(s, t),
            CubicBezier(s, s+LEFT/2, t+RIGHT/3, t),
        ])
        self.add(grp.arrange())
edges
from manim import *
config.frame_width=5

def build_arrow(tip):
    return Arrow(ORIGIN, 2*DOWN, tip_shape=tip)

class Main(Scene):
    def construct(self):
        tips = [ArrowTriangleTip, ArrowTriangleFilledTip,
                ArrowCircleTip, ArrowCircleFilledTip,
                ArrowSquareTip, ArrowSquareFilledTip,
                StealthTip]
        self.add(Group(*map(build_arrow, tips)).arrange())
arrows
from manim import *
config.frame_width = 10

class Main(Scene):
    def construct(self):
        grp = Group(*[
            Square(),
            Triangle(),
            Circle(),
            RegularPolygon(5),
            Star(5),
            Rectangle(width=3, height=1),
            Polygon([0,0,0], [0,1,0], [1,0,0]),
        ])
        self.add(grp.arrange_in_grid(2,4))
polygons
from manim import *
config.frame_width=9.5

class Main(Scene):
    def construct(self):
        grp = Group(*[
            Arc(1, 0, PI/2),
            ArcBetweenPoints(ORIGIN, DOWN),
            AnnularSector(1, 1.2, PI*3/2),
            Annulus(1, 1.2),
            Circle(1),
            Ellipse(1.5, 2),
        ])
        self.add(grp.arrange_in_grid(2,3))
circles
plots

order of adding objects

object methods

  • shift
  • move_to
  • allign_to

other

  • to_edge?

group vs vgroup

arrange arrange_in_grid

Configuration

frame size background

Coordinates

[1,2,3]

Manim units (Munits)

8 high, 14.22… wide

configuration?

  • frame_width, frame_rate = 60, pixel_height ….background_color, notify_outdated_version
  • searches: in the project, OS directory, library’s global config manim cfg write -l cwd

NumberPlane

Animations

add

wait

play

animations:

  • add
  • change
  • mark
  • remove