首页
/ ManimGL 快速上手:从第一个 Scene 到交互式渲染的完整实战指南

ManimGL 快速上手:从第一个 Scene 到交互式渲染的完整实战指南

2026-09-03 17:23:12作者:柏廷章Berta

本篇围绕 ManimGL(3b1b 风格的 OpenGL 版 manim)的 Quick Start 展开,覆盖从编写第一个 Scene、预览窗口中的镜头交互(平移/缩放/3D 视角)、用 -os / -o 导出静态图片与视频,到通过 self.embed() 进入 IPython 交互模式的全部流程。读完你将能独立完成“写场景 → 实时预览 → 导出成品 → 交互式调试”的完整开发闭环,并能对照仓库源码理解每一条 manimgl 命令行参数在底层是如何生效的。

一、先分清:这是 ManimGL,不是社区版

ManimGL 是 3blue1brown 的 3b1b 维护的 OpenGL 版本,其核心特性是实时 GPU 预览窗口:运行命令后直接弹出窗口实时播放动画,而不是先渲染再播放。如果你要找的是 ManimCommunity 维护的社区版(Community Edition),两者包名与安装方式完全不同,不要混用文档。因此本篇所有内容(manimgl 命令、manimlib 包名、实时窗口交互)都只适用于当前仓库实现的 ManimGL。

当前仓库的目录结构(即文档要求你建立的场景文件布局)如下:

manim/
├── manimlib/
│   ├── animation/
│   ├── ...
│   ├── default_config.yml
│   └── window.py
├── custom_config.yml
└── start.py

可以看到,你只需要把自己的 start.py 放在 manimlib/ 同级目录下。若需要覆盖默认配置,可在同目录再放一个 custom_config.yml——manimlib/config.pyinitialize_manim_config() 会按“manimlib/default_config.ymlcustom_config.yml--config_file 指定的文件”的顺序递归合并配置,命令行参数优先级最高。

二、编写第一个场景:一个蓝色圆圈

新建 start.py,写入以下代码(稍后逐行讲解):

from manimlib import *

class SquareToCircle(Scene):
    def construct(self):
        circle = Circle()
        circle.set_fill(BLUE, opacity=0.5)
        circle.set_stroke(BLUE_E, width=4)

        self.add(circle)

然后运行:

manimgl start.py SquareToCircle

屏幕上会弹出一个预览窗口,其中已经画好了那个蓝色圆圈。

逐行代码解析

第 1 行from manimlib import * 导入使用 manim 时可能用到的全部类。

第 3 行class SquareToCircle(Scene): 创建 Scene 的子类,这就是你要编写并渲染的场景。Scene 基类定义在 manimlib/scene/scene.py 中。

第 4 行def construct(self): 编写 construct() 方法,它决定如何在屏幕上创建 mobject(数学对象)以及执行哪些操作。Scene.run() 的调用链是 setup() → construct() → interact()(见 manimlib/scene/scene.py#L150-L159),其中 construct 是你的动画主体,interact 则负责在进入窗口循环后持续更新画面。

第 5 行circle = Circle() 创建一个 Circle 实例,命名为 circle

第 6~7 行:通过实例方法设置样式:

  • .set_fill(BLUE, opacity=0.5):填充色设为蓝色(BLUE,颜色常量集中定义在 manimlib/constants.pymanimlib/default_config.ymlcolors 段),填充透明度 0.5;
  • .set_stroke(BLUE_E, width=4):描边色设为深蓝(BLUE_E),描边宽度 4。

第 9 行self.add(circle) 通过 Scene.add() 方法把这个圆加到屏幕上。从源码看(manimlib/scene/scene.py#L314-L330),add() 会先把对象从场景移除再重新加入(保证置顶),并把对象家族的所有成员登记进 id_to_mobject_map,这也是交互模式下按 id 选回 mobject 的基础。

三、预览窗口的交互操作

窗口弹出后,可以这样操作画面(这些键位来自 manimlib/default_config.ymlkey_bindings 段与 Scene 的事件处理):

操作 效果 源码依据
滚轮滚动 画面上下移动(以鼠标位置为中心缩放) Scene.on_mouse_scrollself.frame.scale(..., about_point=point)
按住 z + 滚轮 缩放画面 对应 z_grab 键位,按住时拖动可沿 z 方向抓取选区
按住 s 移动鼠标 平移画面(框选/拖动) select: "s"on_mouse_dragself.frame.shift(-d_point)
按住 d 移动鼠标 改变三维透视角度 pan_3d: "d"on_mouse_motionframe.increment_theta/increment_phi

另外,直接拖动鼠标即可平移画面(drag_to_pan 默认为 True),按 q 关闭窗口并退出程序。r 键可把镜头复位到默认状态,command/ctrl + q 也可退出。这些按键处理都写在 manimlib/scene/scene.pyon_key_pressmanimlib/window.py 的事件分发中:底层窗口把 GLFW 事件翻译成 manimlib/event_keys.py 中的统一键名,再交给 Scene 处理。

四、导出静态图片:-os 参数

再次运行:

manimgl start.py SquareToCircle -os

这次不会弹出窗口。程序结束后会自动打开渲染出的图片——默认保存在 start.py 所在目录的 images/ 子目录中。

结合 manimlib/config.pyparse_cli() 可以确认这两个字母参数的真实含义:

  • -o--open):Automatically open the saved file once its done,渲染完成后自动打开产物;
  • -s--skip_animations):跳过动画只取最后一帧,即 save_last_frame=True

update_file_writer_config 中,write_to_moviesave_last_frame 是互斥分支:加了 -s 就走“保存最后一帧”路径,所以 -os 合起来就是“不弹窗、静默渲染、存图并自动打开”。输出目录由 manimlib/default_config.ymldirectories 段决定(output: "videos",图片同理归到 images),并且当 mirror_module_path: True 时,输出路径会镜像源码文件的目录结构。

五、加入动画:让场景动起来

把代码改成下面这样,加入动画,让输出变成视频而不只是图片:

from manimlib import *

class SquareToCircle(Scene):
    def construct(self):
        circle = Circle()
        circle.set_fill(BLUE, opacity=0.5)
        circle.set_stroke(BLUE_E, width=4)
        square = Square()

        self.play(ShowCreation(square))
        self.wait()
        self.play(ReplacementTransform(square, circle))
        self.wait()

运行 manimgl start.py SquareToCircle,窗口会播放“画出一个正方形 → 变形为圆形”的动画。若要保存视频,运行:

manimgl start.py SquareToCircle -o

同样不弹窗,结束后自动打开视频文件——默认保存在 start.py 同级的 videos/ 子目录中。

动画代码逐行解析

前 7 行与之前相同,第 8 行 square = Square() 创建一个 Square 实例。

第 10 行self.play(ShowCreation(square)) 通过 Scene.play() 方法播放动画。ShowCreation(定义于 manimlib/animation/creation.py)是一个展示“创建某个 mobject 过程”的动画,效果即沿路径逐步描绘出 square

第 11 行self.wait() 使用 Scene.wait() 方法暂停,默认 1 秒(default_wait_time,见 manimlib/default_config.ymlscene 段);可传参指定时长,如 self.wait(3) 表示暂停 3 秒。

第 12 行self.play(ReplacementTransform(square, circle)) 播放把 square 变形为 circle 的动画。ReplacementTransform(A, B)(定义于 manimlib/animation/transform.py)的语义是:把 A 变换成 B 的形状,并在动画结束后用 B 替换 A。

第 13 行:与第 11 行相同,暂停 1 秒。

从实现上看,Scene.play() 会依次执行 pre_play → begin_animations → progress_through_animations → finish_animations → post_playmanimlib/scene/scene.py#L574-L592):progress_through_animations1/fps 步进时间轴,逐帧调用 animation.interpolate(alpha) 插值,再绘制并写出帧。这也解释了为什么默认帧率是 30fps(camerafps: 30)。

六、启用交互模式:self.embed() 与裸 manimgl

交互是 ManimGL 的招牌特性。在场景代码末尾加一行:

self.embed()

再运行 manimgl start.py SquareToCircle。前面的动画执行完后,命令行会打开一个 IPython 终端,之后你输入的语句按下回车立即执行(该模式下 self.play 可简写为 play)。依次输入:

# Stretched 4 times in the vertical direction
play(circle.animate.stretch(4, dim=0))
# Rotate the ellipse 90°
play(Rotate(circle, TAU / 4))
# Move 2 units to the right and shrink to 1/4 of the original
play(circle.animate.shift(2 * RIGHT), circle.animate.scale(0.25))
# Insert 10 curves into circle for non-linear transformation (no animation will play)
circle.insert_n_curves(10)
# Apply a complex transformation of f(z)=z^2 to all points on the circle
play(circle.animate.apply_complex_function(lambda z: z**2))
# Close the window and exit the program
exit()

依次可以看到椭圆拉伸、旋转 90°、平移缩小、插入 10 条曲线后再施加复函数 f(z)=z² 的非线性形变。最后 exit() 关闭窗口退出。

不想写只含 self.embed() 的空场景时,也可以直接运行:

manimgl

不带任何参数即可弹出窗口并直接进入 IPython 终端。从源码看,manimlib/extract_scene.py 定义了 BlankScene(InteractiveScene),其 construct 会执行 universal_import_line(默认即 from manimlib import *,见 manimlib/default_config.yml)后自动 self.embed()

交互模式背后的机制

Scene.embed()manimlib/scene/scene.py#L203-L219)会先停掉跳帧、强制绘制一帧,然后启动 manimlib/scene/scene_embed.py 中的 InteractiveSceneEmbed,它注入了几个关键能力:

  • 快捷键命名空间get_shortcuts() 向 IPython 命名空间注入 playwaitaddremoveclearundoredosave_statei2gi2mreloadcheckpoint_paste 等——这就是上文 play(...) 简写能工作的原因;
  • 输入时窗口不卡死enable_gui() 注册了名为 manim 的 pt_inputhooks,在 shell 等待输入的间隙按 1/fps 的节奏持续 update_frame 并处理窗口事件;
  • 每个 cell 执行后自动刷新画面post_run_cell 钩子强制绘制一帧,所以每条语句回车后画面立即更新;
  • 出错时红框闪烁提示:自定义异常处理器会让全屏红色边框闪一下,方便注意到报错;
  • reload():不退出内核即可重新加载整个场景文件,run_scenesmanimlib/main.py)会捕获由 exit_raise 触发的 KillEmbedded 并复用同一个窗口重新执行场景,实现“热重载”;
  • checkpoint_paste:粘贴以注释开头的代码块时,会先回滚到该注释首次出现时的场景状态再执行,方便反复调试同一段动画。

另外,命令行也提供 -e <行号> 参数:manimlib/extract_scene.pyinsert_embed_line_to_module() 会在源文件指定行注入 self.embed(),效果等同于手动加 self.embed(),且未指定场景名时会自动取该行上方最近的类名。

七、常用命令行参数速查

manimgl 的完整参数定义在 manimlib/config.pyparse_cli(),日常最常用的有:

参数 说明
file / scene_names 场景文件路径与要渲染的 Scene 类名(可多个;不指定类名时若文件里只有一个场景则直接运行,多个则交互选择)
-o, --open 渲染完成后自动打开输出文件
-s, --skip_animations 跳过动画,保存最后一帧(常与 -o 组合成 -os 存图)
-w, --write_file 渲染为视频文件(隐含开启写文件)
-l / -m / --hd / --uhd 分别按 480p / 720p / 1080p / 4K 渲染,分辨率映射见 manimlib/default_config.ymlresolution_options(默认输出 1920×1080)
-r WxH / --fps 自定义分辨率与帧率
-i, --gif 保存为 gif
-t, --transparent 渲染带 alpha 通道的视频(自动改用 prores_ks 编码、输出 .mov
-n start[,end] 从第 N 个动画开始渲染,"3,6" 表示渲染第 3 到第 6 个
-e 行号 在指定行插入 self.embed() 断点,进入交互会话
-a, --write_all 渲染文件内所有场景
-f, --full_screen 窗口全屏显示
-p, --presenter_mode wait 时保持暂停,按空格或右箭头继续,类似幻灯片放映
-c 颜色 指定背景色
--subdivide 把输出拆分为每个动画一个文件
--config_file 指定额外的自定义配置文件
--clear-cache 清除 Tex/Text mobject 的编译缓存
-v, --version 显示版本

manimlib/main.py 的入口流程可以看到整体链路:main() 打印版本 → parse_cli() 解析参数 → run_scenes()show_in_window(未写文件时)时创建一个可复用的 Windowmanimlib/window.py,基于 GLFW + WebGPU/wgpu 渲染管线)→ 调用 manimlib.extract_scene.main() 加载模块、筛选场景类、实例化并 run()。窗口生命周期长于场景,所以 reload 时能复用同一个窗口对象。

八、接下来去哪

完成本篇后,你已经掌握了 ManimGL 的核心工作流:编写 Scene、窗口实时交互、导出图片/视频、IPython 嵌入调试。建议按仓库文档顺序继续:

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
980
502
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384