前言

如果你看過 3Blue1Brown 的數學影片,你一定對那些流暢、精緻的數學動畫印象深刻。那些公式的優雅變形、幾何圖形的旋轉與變換、函數圖形的動態繪製——它們全都是用一個叫做 Manim 的 Python 函式庫製作的。

Manim 的全名是 Mathematical Animation Engine,最初由 3Blue1Brown 的創作者 Grant Sanderson 開發。後來社群接手維護,發展出了 Manim Community Edition(ManimCE),它更穩定、文件更完善,也更適合一般使用者。

這篇文章會帶你從安裝 Manim 開始,一步步學會製作基本的數學動畫。即使你不打算做 YouTube 頻道,Manim 也是一個強大的數學視覺化工具。

安裝 Manim

使用 pip 安裝

Manim 需要 Python 3.8 以上,以及一些系統依賴(FFmpeg、LaTeX 等)。

# 安裝 FFmpeg(macOS)
brew install ffmpeg

# 安裝 MacTeX(完整 LaTeX,約 4GB) brew install --cask mactex

# 或者安裝輕量版 brew install --cask basictex

# 安裝 Manim Community Edition pip install manim

# Linux (Ubuntu/Debian)
sudo apt update
sudo apt install build-essential python3-dev libcairo2-dev \
     libpango1.0-dev ffmpeg texlive texlive-latex-extra

pip install manim

# Windows
# 先安裝 Chocolatey,然後:
choco install ffmpeg miktex

pip install manim

驗證安裝

manim --version

建立一個測試檔案 test.py

from manim import *

class HelloManim(Scene): def construct(self): text = Text("Hello, Manim!", font_size=72) self.play(Write(text)) self.wait(2)

渲染:

manim -pql test.py HelloManim

參數說明:

  • -p:渲染後自動播放
  • -q:品質設定(l 低, m 中, h 高, k 4K)
  • -l:低品質(等同 -ql

如果一切正常,你會看到一段 “Hello, Manim!” 被書寫出來的動畫。

Scene 的基本結構

Manim 的核心概念是 Scene(場景)。每個場景是一個 Python 類別,繼承自 Scene,動畫邏輯寫在 construct() 方法裡。

from manim import *

class BasicStructure(Scene): def construct(self): # 1. 建立物件(Mobjects) circle = Circle(radius=1, color=BLUE) square = Square(side_length=2, color=RED)

# 2. 播放動畫 self.play(Create(circle)) # 建立動畫 self.wait(1) # 等待 1 秒 self.play(Transform(circle, square)) # 變形動畫 self.wait(1) self.play(FadeOut(square)) # 淡出

基本物件(Mobject)

Manim 中所有的視覺物件都叫做 Mobject(Mathematical Object)。常用的有:

# 幾何圖形
Circle(radius=1, color=BLUE)
Square(side_length=2, color=RED)
Triangle(color=GREEN)
Rectangle(width=4, height=2)
Dot(point=ORIGIN, color=WHITE)
Line(start=LEFT, end=RIGHT)
Arrow(start=LEFT, end=RIGHT)
Arc(radius=1, start_angle=0, angle=PI/2)
Polygon([-2, -1, 0], [0, 2, 0], [2, -1, 0])  # 三角形

# 文字 Text("Hello", font_size=48, color=WHITE) Tex(r"E = mc^2") # LaTeX 數學式 MathTex(r"\int_0^1 x^2 \, dx = \frac{1}{3}")

# 座標系統 Axes(x_range=[-3, 3], y_range=[-2, 2]) NumberPlane() NumberLine(x_range=[-5, 5])

物件的定位與排列

class Positioning(Scene):
    def construct(self):
        # 絕對位置
        circle = Circle(color=BLUE)
        circle.move_to(LEFT  2 + UP  1)  # 向左2, 向上1

# 相對位置 square = Square(color=RED) square.next_to(circle, RIGHT, buff=0.5) # 在 circle 右邊,間距 0.5

# 對齊 triangle = Triangle(color=GREEN) triangle.align_to(circle, DOWN) # 底部對齊 circle

# 群組 group = VGroup(circle, square, triangle) group.arrange(RIGHT, buff=1) # 水平排列,間距 1 group.center() # 置中

self.play(Create(group)) self.wait()

動畫方法

Manim 的動畫系統非常豐富。以下是最常用的動畫類型:

建立與消除

class AnimationTypes(Scene):
    def construct(self):
        circle = Circle(color=BLUE)
        text = Text("Animation", font_size=36)
        text.next_to(circle, DOWN)

# 建立動畫 self.play(Create(circle)) # 描繪邊框 self.play(Write(text)) # 書寫文字 self.play(FadeIn(circle)) # 淡入 self.play(GrowFromCenter(circle)) # 從中心放大 self.play(DrawBorderThenFill(circle)) # 先描邊再填色

# 消除動畫 self.play(FadeOut(circle)) # 淡出 self.play(Uncreate(circle)) # 反向描繪 self.play(ShrinkToCenter(circle)) # 縮到中心消失

變換動畫

class TransformDemo(Scene):
    def construct(self):
        circle = Circle(color=BLUE, fill_opacity=0.5)
        square = Square(color=RED, fill_opacity=0.5)
        triangle = Triangle(color=GREEN, fill_opacity=0.5)

self.play(Create(circle)) self.wait(0.5)

# Transform:circle 變成 square(circle 物件被替換) self.play(Transform(circle, square)) self.wait(0.5)

# ReplacementTransform:更直覺的變換 # self.play(ReplacementTransform(circle, square))

# 變形為三角形 self.play(Transform(circle, triangle)) self.wait()

屬性動畫

class PropertyAnimation(Scene):
    def construct(self):
        circle = Circle(radius=1, color=BLUE, fill_opacity=0.3)
        self.play(Create(circle))

# 移動 self.play(circle.animate.shift(RIGHT * 2))

# 縮放 self.play(circle.animate.scale(2))

# 旋轉 self.play(circle.animate.rotate(PI / 4))

# 變色 self.play(circle.animate.set_color(RED))

# 連鎖動畫 self.play( circle.animate .shift(LEFT * 4) .scale(0.5) .set_color(YELLOW) )

實戰:畫函數圖形

class FunctionGraph(Scene):
    def construct(self):
        # 建立座標軸
        axes = Axes(
            x_range=[-4, 4, 1],
            y_range=[-2, 2, 1],
            x_length=8,
            y_length=5,
            axis_config={"color": WHITE},
            tips=True,
        )
        labels = axes.get_axis_labels(x_label="x", y_label="y")

# sin 函數圖形 sin_graph = axes.plot( lambda x: np.sin(x), color=BLUE, x_range=[-4, 4], ) sin_label = axes.get_graph_label( sin_graph, label=r"\sin(x)", x_val=3, direction=UP )

# cos 函數圖形 cos_graph = axes.plot( lambda x: np.cos(x), color=RED, x_range=[-4, 4], ) cos_label = axes.get_graph_label( cos_graph, label=r"\cos(x)", x_val=2, direction=DOWN )

# 動畫序列 self.play(Create(axes), Write(labels)) self.wait(0.5)

self.play(Create(sin_graph), Write(sin_label)) self.wait(0.5)

self.play(Create(cos_graph), Write(cos_label)) self.wait(1)

# 加上面積 area = axes.get_area(sin_graph, x_range=[0, PI], color=BLUE, opacity=0.3) self.play(FadeIn(area)) self.wait()

實戰:公式推導動畫

Manim 最強大的功能之一是 LaTeX 公式動畫:

class FormulaDerivation(Scene):
    def construct(self):
        # 一步步推導畢氏定理
        title = Text("畢氏定理", font_size=48)
        title.to_edge(UP)
        self.play(Write(title))

# 畫直角三角形 triangle = Polygon( [-2, -1, 0], [2, -1, 0], [2, 1.5, 0], color=BLUE, fill_opacity=0.2 ) # 邊的標籤 a_label = MathTex("a").next_to(triangle, DOWN) b_label = MathTex("b").next_to(triangle, RIGHT) c_label = MathTex("c").move_to([-0.3, 0.5, 0])

self.play(Create(triangle)) self.play(Write(a_label), Write(b_label), Write(c_label)) self.wait()

# 公式動畫 formula1 = MathTex("a^2", "+", "b^2", "=", "c^2") formula1.shift(DOWN * 2) self.play(Write(formula1)) self.wait()

# 代入具體數字 formula2 = MathTex("3^2", "+", "4^2", "=", "5^2") formula2.shift(DOWN * 2) self.play(TransformMatchingTex(formula1, formula2)) self.wait()

formula3 = MathTex("9", "+", "16", "=", "25") formula3.shift(DOWN * 2) self.play(TransformMatchingTex(formula2, formula3)) self.wait()

TransformMatchingTex 的威力

TransformMatchingTex 會自動匹配兩個公式中對應的部分,產生平滑的過渡動畫。這是製作公式推導動畫的利器:

class TexTransform(Scene):
    def construct(self):
        # 展開 (a+b)²
        step1 = MathTex("(a+b)^2")
        step2 = MathTex("(a+b)(a+b)")
        step3 = MathTex("a^2 + ab + ba + b^2")
        step4 = MathTex("a^2 + 2ab + b^2")

self.play(Write(step1)) self.wait() self.play(TransformMatchingTex(step1, step2)) self.wait() self.play(TransformMatchingTex(step2, step3)) self.wait() self.play(TransformMatchingTex(step3, step4)) self.wait()

# 框起最終結果 box = SurroundingRectangle(step4, color=YELLOW) self.play(Create(box)) self.wait()

實戰:向量場動畫

class VectorFieldDemo(Scene):
    def construct(self):
        # 建立向量場
        func = lambda pos: np.array([
            -pos[1],  # x 分量 = -y
            pos[0],   # y 分量 = x
            0
        ])

vector_field = ArrowVectorField( func, x_range=[-4, 4, 0.5], y_range=[-3, 3, 0.5], length_func=lambda norm: 0.4 * sigmoid(norm), )

self.play(Create(vector_field)) self.wait()

# 加入流線 stream_lines = StreamLines( func, x_range=[-4, 4, 0.3], y_range=[-3, 3, 0.3], stroke_width=2, max_anchors_per_line=30, )

self.play(FadeOut(vector_field)) self.play(Create(stream_lines)) stream_lines.start_animation() self.wait(3)

實戰:3D 場景

Manim 也支援 3D 動畫:

class ThreeDScene(ThreeDScene):
    def construct(self):
        # 3D 座標軸
        axes = ThreeDAxes(
            x_range=[-3, 3, 1],
            y_range=[-3, 3, 1],
            z_range=[-2, 2, 1],
        )

# 3D 曲面 surface = Surface( lambda u, v: axes.c2p( u, v, np.sin(u) * np.cos(v) ), u_range=[-3, 3], v_range=[-3, 3], resolution=(30, 30), fill_opacity=0.7, ) surface.set_style(fill_color=BLUE)

# 設定攝影機角度 self.set_camera_orientation(phi=60 DEGREES, theta=-45 DEGREES)

self.play(Create(axes)) self.play(Create(surface))

# 旋轉攝影機 self.begin_ambient_camera_rotation(rate=0.3) self.wait(5) self.stop_ambient_camera_rotation()

匯出影片

# 低品質預覽(480p, 15fps)— 最快
manim -pql scene.py ClassName

# 中品質(720p, 30fps) manim -pqm scene.py ClassName

# 高品質(1080p, 60fps) manim -pqh scene.py ClassName

# 4K(2160p, 60fps) manim -pqk scene.py ClassName

# 只匯出最後一幀(做截圖用) manim -pqs scene.py ClassName

# 輸出 GIF manim -pql --format=gif scene.py ClassName

# 指定輸出目錄 manim -pql -o my_video scene.py ClassName

預設輸出位置是 ./media/videos/ 目錄下。

常用技巧

動畫速度控制

# 改變動畫時長
self.play(Create(circle), run_time=3)  # 3 秒

# 使用 rate_func 控制緩動 self.play( circle.animate.shift(RIGHT * 3), rate_func=smooth, # 平滑加減速(預設) run_time=2, )

# 其他 rate_func: # linear - 等速 # smooth - 平滑(預設) # rush_into - 加速衝入 # rush_from - 減速衝出 # there_and_back - 去了又回來 # wiggle - 抖動

同時播放多個動畫

# 同時播放
self.play(
    Create(circle),
    Write(text),
    FadeIn(square),
)

# 錯開播放(AnimationGroup + lag_ratio) self.play(AnimationGroup( *[Create(mob) for mob in mobjects], lag_ratio=0.2, # 每個動畫延遲 20% ))

自訂更新函數

class CustomUpdater(Scene):
    def construct(self):
        dot = Dot(color=RED)
        trace = TracedPath(dot.get_center, stroke_color=RED)

# 讓點沿著參數曲線移動 t = ValueTracker(0)

dot.add_updater( lambda m: m.move_to( np.array([ 2 * np.cos(t.get_value()), 2 * np.sin(t.get_value()), 0 ]) ) )

self.add(trace, dot) self.play(t.animate.set_value(2 * PI), run_time=4, rate_func=linear) self.wait()

小結

Manim 是一個將數學和程式設計結合得淋漓盡致的工具。它的學習曲線不算平坦——你需要同時具備 Python 程式設計能力、LaTeX 排版知識、以及對動畫時序的敏感度——但一旦上手,你就擁有了一個製作專業級數學動畫的能力。

我特別喜歡 Manim 的一點是:它迫使你用程式邏輯來思考動畫。每一個物件的位置、每一個動畫的時序、每一個公式的變換——都是明確的、可重現的、可版本控制的。這和用 After Effects 拖拉時間軸是完全不同的創作體驗。

即使你不做影片,Manim 也是一個絕佳的數學學習工具。當你嘗試用 Manim 動畫來解釋一個定理時,你會被迫去理解每一個步驟的邏輯,而這個過程本身就是深度學習。

延伸閱讀

  • Manim Community Edition 官方文件:docs.manim.community
  • 3Blue1Brown 的原始 Manim 版本(manim-gl,使用 OpenGL 渲染,更快但文件較少)
  • Theorem of Beethoven 的 Manim 教學 YouTube 頻道
  • Manim 的 GitHub Discussion 區:有大量範例和問答
  • 嘗試重現一段 3Blue1Brown 影片中的動畫片段,作為練習