最近在整理数学可视化相关的资料时又翻出了 3Blue1Brown简称 3b1b的动画引擎 manim顺手把从小白到能独立做出一个数学动画的完整过程梳理了一遍。如果你看过 3b1b 的线性代数、微积分或者神经网络系列视频大概率会被那种丝滑的公式推导和几何变换动画吸引。那些视频背后正是 manim 这个开源项目。这篇文章我会围绕 manim 是什么、怎么安装、核心对象体系怎么理解、如何写一个完整动画、以及常见报错和工程化建议来展开。不论你是数学系学生、算法工程师还是单纯想用代码做知识可视化这篇文章都值得收藏备用。1. manim 是什么为什么值得学1.1 从 3b1b 到 manim 的开源之路manim 的全称是Mathematical Animation Engine即数学动画引擎由 Grant Sanderson也就是 3Blue1Brown 频道的主理人开发。3b1b 频道在 YouTube 上拥有数百万粉丝其视频以直观、优雅的数学解释著称而这些视觉效果几乎全部来自 manim。后来社区在此基础上维护了一个更加活跃、易用的分支称为Manim Community Edition简写为manimce或直接叫manim。目前我们在 PyPI 上直接执行pip install manim安装的就是社区版它由社区维护文档完善API 稳定兼容性也更好。需要区分的是两个主要版本版本维护方命令适用场景3b1b 原版 manimGrant Sandersonmanimgl复刻原版视频效果学习源码社区版 manim社区维护manim日常工作、学习、二次开发社区版是我的首选教程也多排错参考容易找到。1.2 manim 能解决什么问题先举个直观例子。假如你想在文章里解释“为什么圆的面积是 πr²”用文字描述半天读者可能还是似懂非懂但把圆切成若干扇形再拼接成近似矩形读者一眼就能看出面积关系。manim 最擅长把这种“动态推导过程”可视化。它适合以下几类场景数学概念可视化函数图像、极限、导数、积分、线性变换。算法过程演示排序、搜索、动态规划、图遍历。物理模型模拟运动轨迹、场、波动、力学分析。教学视频制作配合画外音生成高质量的类 3b1b 风格动画。论文汇报和 Live Demo生成 GIF 或短视频直接嵌入 PPT 或网页。1.3 掌握 manim 的成本和收益manim 的上手路径和传统动画工具完全不同。它不需要像 AE 那样拖拽时间轴也不需要像 OpenGL 那样手动管理顶点和渲染管线。你只需要用 Python 描述“在什么时间点什么对象做什么动作”剩下的交渲染引擎处理。如果你已经熟悉 Python 基础语法通常在半天内就能写出第一个动画一周内就能做出一段像样的数学短视频。2. 环境准备与版本选择2.1 系统与运行环境manim 是一个跨平台工具支持 Windows、macOS、Linux。渲染底层依赖FFmpeg和LaTeX可选因此安装时需要额外配置这两项。以我常用的环境为例操作系统Windows 10 / macOS 均可编程语言Python 3.9 及以上包管理工具pip 或 conda渲染依赖FFmpeg公式支持TeX Live 或 MiKTeX可选但强烈推荐版本需要根据你的项目实际情况调整本文示例以常见环境为例重点演示配置思路。2.2 安装 manim推荐使用虚拟环境安装避免污染系统 Pythonpython -m venv manim-env # Windows manim-env\Scripts\activate # macOS / Linux source manim-env/bin/activate pip install manim安装完成后验证版本manim --version如果输出类似Manim Community Edition v0.18.1的版本号说明安装成功。没有装 LaTeX 也能运行大部分不依赖公式的动画但一旦出现MathTex就会报错。2.3 安装 FFmpegFFmpeg 负责把 manim 渲染出的帧序列合成为视频缺少它会直接报“FFmpeg not found”的错误。Windows建议通过winget install FFmpeg或下载 Gyan 编译版并配置系统 PATH。macOS执行brew install ffmpeg。Linux执行sudo apt install ffmpeg。验证方式ffmpeg -version能正常输出版本信息即表示安装成功。2.4 安装 LaTeX可选但重要如果要在动画里使用公式必须安装 LaTeX。Windows 上推荐安装 MiKTeXmacOS 推荐 MacTeX体积较大也可以安装 BasicTeX 再补充宏包Linux 下方便执行sudo apt install texlive texlive-latex-extra。安装完成后可以用第一个MathTex案例验证。建议先在本机测试latex --version出现版本信息即可。如果暂时不想装也能先跳过所有 TeX 相关示例。3. 核心对象体系与基础语法manim 的编程模型可以浓缩成一句话在 Scene场景中对 Mobject数学对象施加 Animation动画。理解这三者的关系基本就掌握了 80% 的用法。3.1 Scene一切发生的舞台Scene 是 manim 最基本的执行单元。所有动画都必须定义在一个继承自Scene的类中然后重写construct方法。construct内部的代码按顺序执行manim 会把每条语句翻译成渲染指令。# 文件路径first_scene.py from manim import * class FirstScene(Scene): def construct(self): circle Circle() self.play(Create(circle)) self.wait(1)这个场景做了三件事创建了一个圆Circle()。调用self.play(Create(circle))播放“圆从无到有被绘制出来”的动画。等待 1 秒静止画面。self.play是动画的入口它接收一个或多个动画对象self.wait是等待若干秒。这两个方法构成了最基础的时间轴控制。3.2 Mobject所有可视化对象的基类MobjectMathematical Object代表屏幕上的一个可视化元素可以是几何图形、文字、公式、坐标轴、图片甚至一组子对象的组合。常见的内置 Mobject 包括类别示例类说明基础几何Circle、Square、Triangle、Line最常使用的图形文字Text、Paragraph、MarkupText普通文本渲染公式Tex、MathTex基于 LaTeX 渲染数学公式坐标轴Axes、NumberPlane、Graph生成坐标系、函数图像组合VGroup、Group把多个对象打包成一个整体每个 Mobject 都有属性和方法。最核心的属性是position相关接口最常用的方法有shift、scale、rotate、to_edge、set_color等。# 文件路径mobject_demo.py from manim import * class MobjectDemo(Scene): def construct(self): c Circle(colorBLUE).shift(LEFT * 2) s Square(colorRED).shift(RIGHT * 2) self.add(c, s) self.wait(1)这段代码里shift(LEFT * 2)把圆向左移动 2 个单位。add(c, s)直接把对象添加到画布上不产生动画。self.wait(1)等待 1 秒。注意add和play的区别add是静态添加画面不会产生过渡效果play是播放动画画面会产生平滑过渡。3.3 Animation如何让对象动起来动画类负责描述“对象从什么状态变成什么状态”。manim 内置了几十种动画类型初期掌握以下几个就足够动画用途Create从无到有地绘制对象轮廓适合几何图形FadeIn/FadeOut淡入淡出适合文字和对象切换Transform把一个对象平滑地变换成另一个对象ReplacementTransform功能与 Transform 类似常用于公式推导Rotate旋转对象Write模拟手写文字或公式的效果来看一个稍复杂的变换示例# 文件路径transform_demo.py from manim import * class TransformDemo(Scene): def construct(self): circle Circle(colorBLUE) square Square(colorRED) self.play(Create(circle)) self.play(Transform(circle, square)) self.wait(1)运行后你会看到先绘制一个圆然后圆平滑地“变成”一个方。Transform的底层原理是插值两个对象顶点位置所以如果两个对象顶点数量差异较大效果可能不够平滑但大多数场景下已经足够。3.4 坐标体系与配置参数manim 默认使用笛卡尔坐标系原点位于画布中心。横向为 $x$ 轴纵向为 $y$ 轴。单位长度默认以像素映射但更常用的是逻辑单位比如LEFT表示向左移动一个单位UP表示为 $y$ 增加一个单位。# 文件路径coordinate_demo.py from manim import * class CoordinateDemo(Scene): def construct(self): dot Dot(ORIGIN, colorYELLOW) self.play(dot.animate.shift(RIGHT * 2 UP)) self.play(dot.animate.shift(LEFT * 2 DOWN)) self.wait(1)这里ORIGIN是坐标原点dot.animate是 manim 提供的属性动画语法可以直接对位置属性做插值。3.5 渲染命令与质量参数写好了场景类如何输出视频这是很多初学者第一次懵住的地方。manim 的渲染命令格式是manim -pql 文件名.py 场景类名参数解释参数含义-p渲染后预览视频-ql低质量渲染适合调试-qm中等质量-qh高质量渲染适合最终输出-s只渲染最后一帧输出图片-a渲染文件中所有场景例如渲染transform_demo.py中的TransformDemo执行manim -pqm transform_demo.py TransformDemomanim 会在当前目录生成media/videos/transform_demo/720p30/TransformDemo.mp4。这里有一个小坑文件路径中的场景类名必须与代码中类名完全一致否则会找不到目标。4. 完整实战制作一个“导数定义”动画下面做一个有代表性的实战任务用 manim 展示导数定义——即割线斜率逐渐趋近于切线斜率的过程。这个案例覆盖了坐标轴、函数图像、点、线、动画变换和文字标注足以帮你建立一套完整的代码组织思路。4.1 创建项目结构建议在一个独立目录中管理代码方便后续扩展manim-demo/ ├── scenes/ │ └── derivative_demo.py ├── outputs/ └── requirements.txtrequirements.txt内容manim0.18.04.2 编写核心代码完整代码如下# 文件路径scenes/derivative_demo.py from manim import * class DerivativeDemo(Scene): def construct(self): # 1. 绘制坐标轴 axes Axes( x_range[-1, 5, 1], y_range[-1, 10, 1], x_length8, y_length5, axis_config{include_numbers: True} ) self.play(Create(axes)) # 2. 绘制函数 f(x) x^2 graph axes.plot( lambda x: x**2, x_range[-0.5, 4.5], colorBLUE ) graph_label MathTex(f(x) x^2).next_to(graph, UR, buff0.5) self.play(Create(graph), Write(graph_label)) # 3. 在函数上取两个点 A 和 B a_x 1.0 b_x 3.0 dot_a Dot(axes.c2p(a_x, a_x**2), colorYELLOW) dot_b Dot(axes.c2p(b_x, b_x**2), colorYELLOW) label_a MathTex(A).next_to(dot_a, DL) label_b MathTex(B).next_to(dot_b, DR) self.play(FadeIn(dot_a), FadeIn(dot_b), Write(label_a), Write(label_b)) # 4. 绘制割线 AB secant Line(dot_a.get_center(), dot_b.get_center(), colorRED) self.play(Create(secant)) # 5. 让 B 点逐渐靠近 A 点 steps [2.8, 2.5, 2.2, 1.9, 1.6, 1.3, 1.1] for new_x in steps: new_dot Dot(axes.c2p(new_x, new_x**2), colorYELLOW) new_secant Line( dot_a.get_center(), axes.c2p(new_x, new_x**2), colorRED ) self.play( Transform(dot_b, new_dot), Transform(secant, new_secant), run_time0.6 ) # 6. 高亮切线 tangent axes.plot( lambda x: 2 * a_x * (x - a_x) a_x**2, x_range[0, 3], colorGREEN ) tangent_label MathTex(f(1) 2).next_to(tangent, UR, buff0.4) self.play(Create(tangent), Write(tangent_label)) self.wait(2)这段代码比较长拆开来看Axes生成带坐标数字的坐标轴。axes.plot(lambda x: x**2, x_range[-0.5, 4.5], colorBLUE)绘制函数曲线。axes.c2p(x, y)是 coordinate to point 的缩写负责把数学坐标转换为画布坐标。Line绘制线段传入的是get_center()位置。循环里连续执行Transform实现 B 点沿曲线滑动、割线随之变化的动态效果。最后用axes.plot绘制切线其斜率是 $f(1)2$。运行后观察重点一开始是一条穿过 A、B 两点的割线随着 B 点不断靠近 A割线会逐渐旋转最终和绿色切线几乎重合。这个画面非常直观地呼应了“导数就是切线斜率”这一定义。4.3 运行与验证在项目根目录执行manim -pqm scenes/derivative_demo.py DerivativeDemo如果命令执行成功控制台会输出渲染进度和生成路径并自动弹出视频播放窗口。第一次运行时由于需要初始化缓存速度会偏慢后续渲染会明显变快。4.4 结果说明输出视频中你会依次看到以下阶段坐标轴和刻度出现。蓝色抛物线从左到右被绘制出来同时显示函数表达式。两个黄色点 A、B 出现红色割线连接两点。B 点分多次靠近 A 点红色割线不断变化。绿色切线出现并标注导数结果。这个流程已经具备一个数学微课视频的基本骨架。你可以继续替换函数、增加解说文字、添加背景音乐甚至可以制作分 P 视频。5. 进阶技巧公式、样式与效率优化学会第一个动画后你可能很快会遇到以下进阶需求。5.1 使用 MathTex 排版公式manim 的公式渲染基于 LaTeX使用MathTex类。它支持行内数学模式和\\换行。# 文件路径math_tex_demo.py from manim import * class MathTexDemo(Scene): def construct(self): formula MathTex( r\frac{d}{dx} x^2 2x, font_size60 ) self.play(Write(formula)) self.wait(1)几个容易踩坑的点字符串要写成原始字符串r...否则 LaTeX 反斜杠会被 Python 转义。公式中空格需要用\或自动处理直接写空格往往不生效。如果出现latex error可能是宏包缺失优先检查 LaTeX 环境和日志输出。5.2 使用 VGroup 组合对象在复杂动画中经常需要把多个对象作为一个整体移动、缩放、变色。VGroup是垂直方向组合的容器子对象会保持相对位置。# 文件路径vgroup_demo.py from manim import * class VGroupDemo(Scene): def construct(self): title Text(向量加法) vec_a Arrow(ORIGIN, RIGHT * 2, colorRED) vec_b Arrow(RIGHT * 2, RIGHT * 2 UP * 2, colorGREEN) group VGroup(title, vec_a, vec_b) group.scale(0.8).shift(UP * 2) self.add(group) result Arrow(ORIGIN, RIGHT * 2 UP * 2, colorBLUE) self.play(Create(result)) self.wait(1)VGroup最大的好处是统一管理一条group.shift(LEFT)就能让所有子对象一起移动不用逐个处理。5.3 控制动画节奏与缓存manim 动画对象共有的参数包括参数作用run_time动画持续秒数rate_func速率函数常用smooth、linear、there_and_backlag_ratio多对象动画的错峰比例例如self.play(Create(circle), run_time3, rate_funclinear)表示用 3 秒匀速画圆。控制好节奏视频观感会显著提升。manim 自带缓存机制。同样的代码不会重复渲染相同场景除非代码发生变化。如果需要清理缓存可以删除项目目录下的media文件夹。5.4 渲染 GIF 和图片有些场景不需要视频只需要一张图或 GIF。可以用-s参数manim -sqm scenes/derivative_demo.py DerivativeDemoGIF 需要配合 ImageMagick或者用 ffmpeg 自行转换。最简单的方式是先用高质量参数渲染 MP4再用 ffmpeg 转成 GIFffmpeg -i output.mp4 -vf fps10,scale480:-1 output.gif6. 常见问题与排查思路和任何开源工具一样manim 真正劝退新人的往往是环境配置阶段。下面把最常见的 6 类问题统一整理一下。问题现象常见原因解决思路command not found: manim虚拟环境未激活或未安装确认pip install manim成功执行which manim检查FFmpeg not found未安装 FFmpeg 或未配置 PATH安装 FFmpeg重启终端验证ffmpeg -versionLatex errorLaTeX 未安装或缺少宏包安装 MiKTeX/TeX Live重试看日志定位缺失宏包Class Not Found类名与命令不匹配检查文件内的类名和终端传入的类名是否完全一致渲染动画一闪而过没有wait场景逻辑很快结束在关键节点加self.wait(1)图像文字显示为方块缺少字体或中文环境配置使用Text指定中文字体如Text(测试, fontSimHei)下面重点展开几个比较隐蔽的问题。6.1 中文显示乱码manim 默认字体对中文支持不好直接写Text(你好)可能显示为方框。解决办法是在构造时明确指定系统字体Text(你好, fontSimHei)macOS 可以换成PingFang SCLinux 可以根据系统情况设置Noto Sans CJK SC。6.2run_time不生效有时候发现self.play(..., run_time2)仍然很快结束。这通常是因为传入的动画参数写错了位置或者把run_time写在了对象创建参数中。正确的写法是作为play方法的命名参数传入。6.3 渲染视频体积过大问题原因通常是分辨率太高、帧率太高或动画过于复杂。建议调试时统一使用-ql低质量模式最终输出时再用-qh。还可以通过减少run_time、压缩动画帧数来降低文件体积。7. 最佳实践与工程建议当你已经能够连续完成几个 demo 后建议从“能跑”过渡到“工程化”。下面这些经验来自我自身做知识可视化项目时的总结希望能让你少走弯路。7.1 场景拆分原则一个Scene类只做一个核心知识片段不要把所有内容塞进同一个场景。比如“导数的定义”可以拆成三个场景场景一展示割线逼近切线的过程。场景二展示函数图像上各点的切线斜率变化。场景三展示导数公式与几何意义的对应。这样做的直接好处是便于复用、渲染并行和排错。manim 的渲染是按场景类的场景拆细后每次修改只重新渲染一个片段大大加快迭代速度。7.2 对象命名与 git 管理建议为每个 Scene 类使用描述性名称例如DerivativeDefinition、TangentLineDemo、RiemannSumDemo。文件名建议与类名对应方便查找。由于media目录体积庞大建议加入.gitignoremedia/ __pycache__/ *.pyc7.3 使用配置模块统一样式多场景项目里颜色、字体、坐标范围应该集中管理。可以使用 Python 的常量文件或者 manim 的config模块。例如# 文件路径style_config.py from manim import config config.frame_width 12 config.frame_height 8 config.pixel_width 1280 config.pixel_height 720在渲染时统一从配置模块导入颜色常量避免每个文件里魔法数字重复出现。7.4 调试优先渲染后置我的习惯是先在脚本中把动画拆成一个一个的小步骤使用-ql -s参数输出单帧图片快速确认布局和位置再渲染视频。这一步能显著节省时间。manim -sql scenes/derivative_demo.py DerivativeDemo -s当单帧图片符合预期后再执行全片渲染。7.5 内容安全与版权意识在制作教学视频时需要注意两个方面引用他人视频、公式、图片时应尊重版权尽量使用原创素材或开放授权素材。在公网发布涉及用户名、账号、内部数据的动画时先做脱敏处理。7.6 备份与版本管理manim 脚本本身是代码建议使用 Git 管理。对于重要的教学资源除了 Git 之外还要定期导出 MP4 或 GIF 到独立的备份目录避免误操作删除原始文件。8. 总结与学习路线从纯零基础到独立完成数学动画通常需要经历下面几个学习阶段掌握 Python 基础重点是数组合、循环、函数。理解 Scene、Mobject、Animation 三者之间的关系。模仿 3b1b 经典视频复刻其中的简单画面。独立设计一套知识可视化场景并发布成视频或 GIF。学习 manim 源码或阅读官方文档扩展自定义对象和动画。官方文档docs.manim.community是学习社区版最好的一手资料Sphinx 风格清晰示例代码也全。相比阅读零散博客直接查阅官方文档 修改源码示例的学习效率更高。如果你手头有想讲清楚的数学概念或算法过程不妨从今天开始先搭好环境把第一段Create(Circle())跑起来。等你看惯了那些线条从无到有地绘制出来就自然知道下一步该怎么做了。如果本文对你有帮助可以收藏备用。你在使用 manim 的过程中遇到过哪些奇怪的问题欢迎在评论区交流我会尽量根据实际经验给出排查方向。