最近一段时间,我经常被问到一个问题:AI 写代码到底能不能真正落地,而不只是生成一段“看起来对、跑起来废”的示例代码。与其争论,不如直接拿一个具体的东西试试。我随手选了一道非常经典的最值题——“矩形周长为 20,面积最大是多少”,然后用 AI 把它做成一段 Manim 动画。Manim 是 3Blue1Brown 带火的开源数学动画引擎,用 Python 写场景,特别适合做数学、物理相关的可视化视频。整个流程走下来,我最大的感受是:AI 生成代码的能力已经不是瓶颈,真正值钱的,是你给 AI 的“画面剧本”和“验收标准”。
这篇文章就把整个完整流程拆开讲清楚。题目怎么选、Manim 怎么装、提示词怎么设计、代码怎么迭代、中途踩了哪些坑,最后我会放一份可以直接运行的完整动态版代码。无论你是数学老师想做课件,还是内容创作者想做科普视频,或者单纯想学 Manim,这篇文章都应该能帮你少走一大截弯路。
1. 先选对题:这道最值题为什么值得做成动画
1.1 一道看起来平平无奇的最值题
先说题目本身。矩形周长为 20,问面积最大是多少。
这题在初中就很常见,解法也简单。设长为 a,则宽为 b = 10 - a,面积 S(a) = a(10 - a) = -a² + 10a。这是一个开口向下的二次函数,对称轴在 a = 5,最大值是 S(5) = 25。换句话说,当矩形长宽相等、变成正方形时,面积最大。
单看答案非常普通,但这道题有一个特别适合动画化的特点:它描述的是一个“连续变化”的过程。a 从 1 慢慢变到 9,矩形会从又高又窄逐渐变成又矮又宽,面积会先涨后跌,抛物线上的轨迹清清楚楚。这种“过程感”是静态公式给不了的——公式只告诉你答案在 a=5,但动画能让你亲眼看到面积在 a=5 之前一直涨、过了 a=5 又开始跌,最值点不是一个抽象记号,而是曲线拱起的那个顶点。
所以我在选题目的时候有一条标准:动态过程比最终结论更有看点。纯计算题不适合,几何证明题又太重,像这种“一个变量变化、另一个量随之变化、中间有个峰顶或谷底”的题,几乎是为动画量身定做的。
1.2 Manim 能把这题讲出几层意思
很多第一次接触 Manim 的人以为它就是把图形“画出来”,其实它能做的事情至少可以分成三层。
第一层是把图形画对。矩形、坐标轴、抛物线、标注点,这些是基本功,属于“静态呈现”。
第二层是让关系动起来。用 ValueTracker 绑定一个变量 a,矩形宽度跟着变,高度自动等于 10 - a,面积跟着更新,同时抛物线上有一个红点实时标出当前 (a, S(a))。到这一步,观众能直观看到:矩形形状变化和面积数值变化是同步的,他会在脑子里把“几何形状”和“函数图像”这两套语言绑定起来。
第三层是制造“发现感”。Manim 可以做节奏设计,比如在最值点附近放慢速度、让红点变大、把 S_max 的公式在关键时刻放出来。这些“剧情节点”能把一道普通习题变成一次 mini 探索,观众不是被动接收答案,而是跟着动画走完一次发现的过程。
我这次只用到第二层和一点第三层,但已经足够说明:Manim 的价值不在炫技,而在把抽象关系可视化。这也是我建议想学 Manim 的人不要从一堆图形 API 开始学,而要从“我到底想讲清哪个关系”开始想的原因。
2. 开工前把工具链备好:Manim 安装与 AI 协作方式
2.1 装好 Manim 社区版,先跑通一个最小场景
AI 写代码之前,建议先把环境装好。否则 AI 输出一坨代码,你连跑都跑不起来,根本没法和它进入“生成-调试-迭代”的循环。
Manim 有两个常见版本:一个是 3Blue1Brown 仓库里的 manim 老版,也叫 manimgl,另一个是社区维护的 Manim Community Edition。社区版安装简单、文档齐全、用的人多,我这次用的就是社区版。
安装本身很简单:
pip install manim装完验证一下,随手建一个文件 hello.py:
from manim import * class Hello(Scene): def construct(self): text = Text("Hello Manim") self.play(Write(text)) self.wait(1)然后渲染:
manim -pql hello.py Hello-p是渲染完自动播放预览,-q指定画质,l是 low quality。第一次调试用低画质就够,速度会快很多,等最后出成品再换-qm或-qh。
如果这一步顺利,说明 Python、pip、Manim 依赖(主要是 numpy、pycairo、pango)都正常。如果这一步就报错,先别急着往下走,去搜对应的报错信息补装系统依赖。Windows 上有时缺 cairo 相关 dll,macOS 上可能需要brew install pango,Linux 需要 apt 装 libpango 等。我见过最多的人卡在这一步,其实不是 Manim 本身难,而是系统依赖没补齐。
2.2 AI 辅助编程,先把边界说清楚
环境好了,开始用 AI。我用的就是平时随手开的对话式大模型,国内国外主流的都试过。这类模型在写 Python 小场景上完全够用,关键是你要把边界说清楚,否则它就会自由发挥。
先说清楚 AI 的边界有三个。
第一,AI 负责生成“能跑的代码”,不负责保证“数学完全正确”。比如它可能写错公式、写错坐标映射,你必须自己在关键处核对。所以我在让它写之前,自己先把 S(a) = a(10 - a)、最大值 25 推导清楚,这是验收标准。
第二,AI 的知识库有滞后性,Manim 社区版 API 迭代很快,旧版写法(比如 Axes 的 x_min/x_max 参数、c2p 方法名)可能已经改了。AI 很容易写出旧 API,遇到报错时别慌,把报错信息原样甩给它,让它对照新版文档改。
第三,AI 不知道你的“画面审美”。它不知道矩形应该放左边、坐标轴放右边、颜色怎么搭。这些是你要在提示词里给的信息,或者在第一版跑出来之后继续对话调整。
我把这样的协作方式叫作“AI 猛冲第一版,人来做验收和指挥”。第一次生成只要骨架是合理的,后面慢慢调,效率通常很高。
2.3 我选的 AI 交互方式:让大模型当“猛冲的第一版”,自己当“验收”
接下来聊聊交互方式。很多人把 AI 当成搜索引擎,问一句“怎么写 Manim 动画”,然后复制代码,发现跑不通就直接放弃。我的做法不太一样,大致分四步。
第一步,我给 AI 一段足够具体的任务描述,包含题目、变量、想呈现的画面顺序、技术约束,而不是一句“帮我做个动画”。
第二步,第一版代码不管跑不跑得通,先跑到报错为止,再把报错信息原样粘贴给 AI,让它解释并修复。注意是“原样粘贴”,不要自己改几个字再问,那样反而浪费时间。
第三步,代码能跑之后,把渲染出来的画面截图回看,指出布局、节奏、配色问题:“矩形和坐标轴重叠了”“数字变化太快看不清”“最值点要停留两秒”。AI 会根据这些反馈继续改。
第四步,等画面稳定后,我会自己手动微调一些参数,比如字体、动画时长、坐标轴刻度范围。这些小改动自己来,比跟 AI 来回对话更省时间。
这套流程跑下来,AI 的角色更像一个“手速很快但需要明确指令的实习生”,而不是“全能老师”。用它之前你要知道自己要什么,这才是关键。
3. 提示词怎么写:让 AI 一次听懂你的需求
3.1 提示词的四个核心要素
我写提示词一般包含四个部分,缺一个,后面可能就要多对话两轮。
第一个是角色和目标。开头写明“你是 Manim 社区版动画专家,请生成 Python 场景代码”,这能显著降低它拿 manimgl 代码来糊弄的概率。
第二个是数学背景。把题目、变量关系、函数、取值范围写清楚。我这次就明确写了“宽为 a,高为 10 - a,面积 S = a(10 - a),a 在 1 到 9 之间变化”。数学关系写清楚,AI 才不用自己推导,也才不会推错。
第三个是画面流程。这个最容易被忽略。你要描述“先出现题目,再显示坐标轴,画抛物线,矩形跟着变化,红点跟着移动,最后标注最值点”。AI 不是导演,它不知道你想先展示哪个、后展示哪个,把流程写清楚,生成的 Scene 结构才有层次。
第四个是技术约束。比如“使用 from manim import *”、“不要用 manimgl”、“中文用 Text 显示”、“坐标轴 x 范围 0 到 10,y 范围 0 到 26”。这些约束能减少大量无谓返工。
3.2 第一版提示词示范
我这次的第一版提示词大概是这样的:
你是 Manim 社区版动画专家。请用 Python + Manim Community Edition 写一个场景类 RectMaxArea。 数学背景:矩形周长固定为 20,设长为 a,则宽 b = 10 - a,面积 S = a * (10 - a),a 的取值范围是 [1, 9]。 画面流程: 1. 顶部显示题目文字“矩形周长为20,面积何时最大?” 2. 画面左侧显示矩形,矩形宽高随 a 变化 3. 画面右侧显示坐标轴,横轴为 a(范围0到10),纵轴为 S(范围0到26),画出 S(a) 的抛物线 4. 抛物线上用一个红点标出当前 (a, S(a)) 5. 用文字实时显示当前的 a、b、S 数值 6. 动画最后让 a 停在 5,突出最大面积点 技术约束: - 用 from manim import * 开头 - 用 ValueTracker 控制 a 的变化,用 always_redraw 更新图形 - 中文文字用 Text,如果支持可以指定中文字体 - 只输出一个完整 Python 文件,并在关键行加中文注释注意我没有让它“一次性做到完美”,而是给了它一个合理的分镜:左边矩形、右边坐标轴、下方数值,最后停在最值点。这个分镜是我在写提示词之前就定好的,AI 只是帮我实现。
3.3 怎么应对 AI 生成“局部正确、整体跑不通”
坦白说,第一版往往不是一次跑通的。我这次遇到的情况是:AI 生成的代码结构完整,ValueTracker 和 always_redraw 都用了,但矩形和坐标轴重叠在画面中央,坐标轴参数也是旧版写法,一运行就报错。
遇到这种情况,我的原则是“先修跑不动的,再调不好看的”。直接把报错信息粘贴给 AI,像这样:
运行报错:TypeError: Axes.__init__() got an unexpected keyword argument 'x_min' 请改成社区版当前支持的写法,并用 coords_to_point 替代 c2p。大多数情况下 AI 会很快修正。等能跑出第一帧,再进入下一轮对话,让它调布局。
这里想特别说一个经验:不要期待 AI 一次生成完美作品,也不要因为它第一次出错就否定这个工作流。真实的效率提升来自“轮次”。每一轮对话都在往前走,而不是从零开始重写代码。AI 出的第一版,哪怕只能跑到 50%,剩下的 50% 你只需要告诉它哪里不对、它来改,比自己打开文档翻 API 快得多。
4. 代码从无到有:渲染实录与动态升级
4.1 基础版:静态场景,先让画面出现
在跑动态版之前,我先让 AI 出了一个“静态版”,目的是确认基础元素都没问题。这个策略适合新手:不要一上来就追求复杂动画,先把文字、坐标轴、抛物线、标注点这些基础元素一次性显示出来,确认环境、字体都正常,再上动态。
这是简化后的静态版思路代码:
from manim import * class RectMaxAreaBase(Scene): def construct(self): # 题目文字 title = Text("矩形周长为20,面积何时最大?", font_size=34, color=WHITE) title.to_edge(UP) self.play(Write(title)) # 坐标系:横轴 a,纵轴 S axes = Axes( x_range=[0, 10, 1], y_range=[0, 26, 5], x_length=6, y_length=3.5, ) axes.to_edge(DOWN, buff=0.6) labels = axes.get_axis_labels(x_label="a", y_label="S") # 抛物线 S = a(10 - a) graph = axes.plot(lambda x: x * (10 - x), x_range=[0, 10], color=YELLOW) self.play(Create(axes), Write(labels)) self.play(Create(graph)) self.wait(1) # 最值点标注 max_point = axes.coords_to_point(5, 25) dot_max = Dot(max_point, color=RED) formula = Text("S_max = 25", font_size=28, color=RED).next_to(max_point, RIGHT) self.play(Create(dot_max)) self.play(Write(formula)) self.wait(2)这里我特意把最值点公式用 Text 而不是 MathTex,因为 MathTex 需要系统预装 LaTeX,很多机器没有,会直接报 latex 相关错误。用 Text 虽然不是排版精美的公式,但胜在稳定。如果你系统装了 LaTeX,想换成公式形式,把Text("S_max = 25")换成MathTex(r"S_{\max}=25")也行。
4.2 渲染命令与第一轮报错处理
文件保存成 rect_scene.py 后,我在终端执行:
manim -pql rect_scene.py RectMaxAreaBase第一次跑大概率会遇到两类问题。一类是“中文文字变成方块”,这是因为 Text 默认字体不支持中文,需要在 Text 里指定中文字体。Windows 常见字体名是SimHei或Microsoft YaHei,macOS 常见是PingFang SC,Linux 常见是Noto Sans CJK SC。比如:
title = Text("矩形周长为20,面积何时最大?", font="Noto Sans CJK SC")另一类是“MathTex 报 latex not found”,就是上面说的 LaTeX 缺失问题。如果你不想装 LaTeX 发行版,就一直用 Text 代替公式渲染。如果想支持公式,Windows 装 MiKTeX,macOS 装 MacTeX(体积比较大),Linux 装 TeX Live,装完重启终端再试。
这里有个小建议:调试阶段尽量用低画质-ql,一帧渲染几秒就完。如果用-qh高清渲染,一个 10 秒动画可能要跑十几分钟,来回迭代心态容易崩。等所有内容都确认了,最后再出一版高清。
4.3 动态版:ValueTracker 让矩形和曲线动起来
动态版的核心就两个:ValueTracker控制 a 的数值,always_redraw让每一个依赖 a 的图形跟着更新。
简单解释一下。ValueTracker 像一个“遥控器”,你改变它的值,画面并不会自动变化;always_redraw 像一个“每帧都重新执行的订阅函数”,只要遥控器变了,它就重新生成对应的矩形、红点、文字。两者的关系,用生活类比来说,就像你在手机上滑动进度条(ValueTracker 变化),视频画面(always_redraw 重绘的内容)才会跟着跳。
下面这份代码可以直接保存运行,是我最终调出来的动态版参考实现:
from manim import * class RectMaxAreaDynamic(Scene): def construct(self): title = Text("矩形周长为20,面积何时最大?", font_size=32) title.to_edge(UP) self.play(Write(title)) # 参数 a,从 1 开始 a = ValueTracker(1) # 左侧矩形:宽 = a,高 = 10 - a def create_rect(): w = a.get_value() h = 10 - w scale = 0.4 return Polygon( ORIGIN, RIGHT * w * scale, RIGHT * w * scale + UP * h * scale, UP * h * scale, color=BLUE, fill_opacity=0.5, stroke_width=3, ) rect = always_redraw(lambda: create_rect().move_to(LEFT * 3.6 + DOWN * 1.2)) # 右侧坐标轴与抛物线 axes = Axes( x_range=[0, 10, 1], y_range=[0, 26, 5], x_length=5.5, y_length=3.5, ).to_edge(DOWN, buff=0.4).shift(RIGHT * 1.8) labels = axes.get_axis_labels(x_label="a", y_label="S") graph = axes.plot(lambda x: x * (10 - x), x_range=[0, 10], color=YELLOW) # 当前点:横坐标 a,纵坐标 S(a) dot = always_redraw( lambda: Dot( axes.coords_to_point( a.get_value(), a.get_value() * (10 - a.get_value()) ), color=RED, ) ) # 实时数值 text = always_redraw( lambda: Text( f"a = {a.get_value():.2f}\n" f"b = {10 - a.get_value():.2f}\n" f"S = {a.get_value() * (10 - a.get_value()):.2f}", font_size=24, ).to_corner(UL) ) self.play(Create(axes), Write(labels), Create(graph)) self.play(Create(rect), FadeIn(dot), FadeIn(text)) self.play(a.animate.set_value(9), run_time=6) self.play(a.animate.set_value(5), run_time=3) self.wait(2)这个版本做了两段变速。第一段让 a 从 1 匀速变到 9,6 秒,观众能看到面积先涨后跌的完整过程;第二段再从 9 慢慢回到 5,3 秒,最后停在最值点,做一个“回马枪”式的强调。这种节奏本身就是剧情设计的一部分。
5. 动画的“剧情”比画面更重要:把最值讲清楚
5.1 左右对照:矩形形状与抛物线同步更新
第一版动态代码跑通后,我让 AI 把“矩形”和“抛物线上的点”放在同一帧里联动。为什么强调这一点?因为这道题最容易讲不清的地方是:面积 S 到底是怎么跟着 a 变的。
如果只有矩形在变,观众能看到形状变化,但很难感知面积的大小。如果只有抛物线在动,观众能看到曲线轨迹,但不知道这个点对应的矩形长什么样。只有左右同时呈现,一个在几何侧、一个在函数侧,观众的视线才能在两者之间来回跳,从而真正建立“矩形的宽高”和“面积函数”之间的联系。这个“动态映射”才是动画相对静态图最核心的增量价值。
在实现上,这个联动其实非常简单,就是前面代码里的always_redraw,让矩形、红点、数字都从同一个ValueTracker获取 a 的值。技术上不复杂,但呈现效果一下就不一样了。
5.2 关键剧情的三个节点
跑通联动后,接下来是设计“剧情节奏”。最后我给动画安排了三个节点。
第一个节点是“漫游期”。a 从 1 走到 9,期间数字不断变化,矩形从竖长条变横长条,抛物线上的点从左侧开始爬坡、过顶、下坡。这个阶段的目的是让观众看到全局变化:面积不是一直变大,也不是一直变小,中间有峰顶。
第二个节点是“回马枪”。a 从 9 走回 5,速度稍慢,让观众聚焦在“从右边走回顶峰”这个过程。很多人看第一遍只会记住“抛物线顶点附近是最大”,但回马枪这一步是在用第二次机会强化“顶点”这个记忆点。
第三个节点是“定格强调”。a 停在 5,红点停在顶点,矩形此时恰好是正方形,用一个短暂的停顿和一个S_max = 25的标注收尾。这个“定住”的动作非常重要:动画里信息一直在流动,如果不给一个静止的最终画面,观众很难记住结论。
这三个节点是我自己加的,AI 第一版只会老老实实把 a 从头走到尾,没有任何节奏感。这也是我前面说的,AI 可以做执行,但“讲故事的节奏”需要人来设计。
5.3 向 AI 提“加工需求”的正确姿势
当你想让 AI 改节奏时,不要笼统说“动画太平了”,而是给出具体指令。比如我会这样追加:
请把 a 的变化拆成两段:第一段 6 秒从 1 到 9,第二段 3 秒从 9 到 5,最后停在 5 并保持 2 秒。再在最后用红色文字标出 S_max = 25,放在抛物线顶点旁边。这类指令越具体,AI 的修改就越精准。反过来,一句“做得好看点”几乎等于没说。
另外,涉及布局调整时,我会直接告诉它坐标级的要求,比如“矩形放左侧屏幕中心偏下,坐标轴放右侧下方,横向不重叠”;涉及颜色时直接指定,“矩形用蓝色半透明,抛物线用黄色,当前点用红色”。这些偏好你一开始不说,AI 就会用默认配色和很笨拙的布局,来回对话轮次也会增加。
6. 常见问题速查与协作心得
6.1 跑不出画面?多半是这几个原因
实际操作中,我把最多人问的问题整理成一个速查表,基本都是我这次亲测踩过或者看别人踩过的坑:
| 现象 | 常见原因 | 处理办法 |
|---|---|---|
| 中文变方块/乱码 | Text 默认字体不支持中文 | 指定中文字体,如 font="Noto Sans CJK SC" |
| MathTex 报 latex 相关错误 | 系统没装 LaTeX 发行版 | 装 MiKTeX / TeX Live / MacTeX,或用 Text 代替 |
| Axes 初始化报参数不识别 | 用了旧版 API 参数 | 让 AI 改成新版写法,或查社区版文档 |
| c2p 方法不存在 | 新版改名 coords_to_point | 全部替换成 axes.coords_to_point |
| 渲染很慢 | 用了高清画质做调试 | 调试用 -ql,最后出片再用 -qm / -qh |
| 动画不同步/数字跳变 | 数值变化太快 | 调大 run_time,或把 a 的变化拆成多段 |
| 图形重叠混乱 | 没给元素指定位置 | 用 to_edge、to_corner、shift、move_to 显式摆位 |
这个表不一定覆盖所有平台差异,但能覆盖大多数新手第一晚遇到的情况。记住一个原则:报错信息是调试的第一手资料,把完整的报错原文丢给 AI,通常比你自己瞎猜快。
6.2 我和 AI 协作的几条经验
最后说几条我反复验证过的协作经验。
第一,提示词里写清楚“Manim Community Edition”,并且让它“用 from manim import *”,能有效避免 AI 输出 manimgl 老代码。网上很多旧教程都是 manimgl 写法,AI 训练数据里混着这些,不强调版本它很容易写串。
第二,AI 的代码跑起来之后,先不要急着加新功能。我的顺序是:先把静态画面摆对,再把动态联动跑通,最后才加节奏和标注。每加一步,都要重新渲染确认,不要一次性堆一个大需求,否则报错时根本不知道哪块出的问题。
第三,AI 生成代码后,自己至少要把数学部分检查一遍。比如这道题的 S = a(10 - a),在代码里出现的位置有好几处:图形函数、红点 y 坐标、文字显示,任何一处写错了,画面就会自相矛盾。AI 会复制自己的错误,人得做最后一道数学审计。
第四,最终微调别依赖 AI。调整动画时长、字体大小、颜色、坐标轴刻度这类小参数,自己直接在代码里改更快,来回对话反而浪费 token 和时间。
7. 做这类“AI 数学动画”的几个扩展方向
做完这道题,我顺手想了想这类流程还能往哪些方向扩展,给有兴趣的读者做个参考。
一是“多题模板化”。把提示词里的数学关系、变量范围、画面流程抽象成一个模板,以后遇到类似的函数最值题、线性规划题,只需要替换公式和取值范围,就能套出新的动画。我试过让 AI 一次生成三个不同题目版本的场景类,放在同一个文件里,用命令行参数选择渲染哪个,效率很高。
二是“自动配音脚本”。Manim 本身就支持视频时间轴和字幕配合,我下一步打算让 AI 根据画面分镜生成一段讲解文案,再配合 TTS 工具转成旁白。这样一条数学讲解视频的“脚本-动画-配音”链路也能半自动跑起来。
三是“交互式参数面板”。Manim 社区版可以通过插件实现滑杆控制参数,把 a 从固定动画改成鼠标拖动控制,观众自己拖拽观察矩形变化和面积曲线的关系,互动感会更强。不过这个对代码结构要求更高,目前我也还在摸索。
我个人的体会是:把题目喂给 AI 只需要几秒钟,但把题目“讲明白”才是真正需要花时间的地方。AI 把编码成本大幅打下来之后,剩下的数学表达、画面设计、节奏把控,恰恰才是区分一段动画有没有灵魂的关键。这套“人出剧本、AI 写代码、人做验收”的工作流,在数学可视化这条路上还能走很远。