manim-teaching-figures
Skill5 starsChanged 3 months agoApache-2.0View on GitHub
用 Manim 给大模型 / AI 基础设施课程画「会动的」教学图 —— 矩阵与线性变换、梯度下降与优化器轨迹、动量与梯度场、loss 地形与鞍点、注意力与 KV cache 的时间演化、高维不可视时的降维表示。产出是挂 loop 的无声 mp4,配静态图与页面图注使用。当用户说「画个动图」「这段用 manim 画」「梯度下降/动量/矩阵变换要动起来」「三蓝一棕那种图」「给课件加动画」,或者一格内容的增量只能来自「时间」或「第三维」时使用。也用于检查已有动画的循环接缝对不对得上。
In this repository54 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- agent-teamsSkill
- bilibili-channelSkill
- bot-configSkill
- browser-cliSkill
- bwrap-bypassSkill
- cc-pages-backupSkill
- chat-styleSkill
- chinese-dictationSkill
- code-wiki-reconSkill
- deck-builderSkill
- docx-form-fillerSkill
- evolutionSkill
- explainer-distillSkill
- feishu-bitableSkill
- feishu-docSkill
- feishu-mailSkill
- feishu-sheetSkill
- feishu-user-msgSkill
- fireworks-tech-graphSkill
- frontend-slidesSkill
- gemini-ui-reviewerSkill
- hk-busSkill
- hk-share-award-tax-dipn38Skill
- imagen-generatorSkill
- issue-handlerSkill
- lecture-videoSkill
- lecture-voiceSkill
- lesson-read-aloudSkill
- live-canvasSkill
- lustre-mounterSkill
- math-video-tutorSkill
- memory-gcSkill
- memory-lintSkill
- multimodal-explainerSkill
- music-generatorSkill
- notifySkill
- page-styleSkill
- paper-explainerSkill
- session-handoffSkill
- skill-creatorSkill
- smoke-testSkill
- study-materialSkill
- tmux-installerSkill
- tmux-orchestratorSkill
- tpuguruSkill
- tts-generatorSkill
- veo-generatorSkill
- vscode-referenceSkill
- weather-forecastSkill
- wechat-readerSkill
- wikiSkill
- youtube-channelSkill
- zsh-installerSkill
The file
Files
用 Manim 画教学动画
⭐ 一句话认领它长什么样:manim 原生深色(
#000000底、BLUE #58C4DD/RED #FC6255/GREY #888888、线宽 4),每一支都无缝循环、页面上不给播放器, 画面里的每一句话都在aria-label里复述一遍。 —— 这三条是身份,不是偏好。
这个 skill 解决什么
一段教学动画真正难的不是画出来,是画对且能循环播。三件事反复出错:
- 该不该做成动画 —— 不占「时间」也不占「第三维」的内容,静态 SVG 更好
- 首尾接不接得上 —— 挂
loop的片子首末帧对不上就每轮跳一下, 而你播一遍是看不出来的,得等它循环到第二遍 - 有没有用对类 —— manim 自带
Matrix/LinearTransformationScene/VectorField,拿Rectangle手摆格子是在重造轮子
环境
~/.venvs/manim/bin/manim Manim CE 0.21.0;LaTeX 齐全,Matrix / MathTex 可用⛔ manim 不能输出 SVG。 静态图走项目自己的 SVG 基元,manim 只管会动的那部分。
房规(2026-09-18 松绑过一次,读完再动手)
⭐⭐⭐ 最初那版是「一个字都不放 + 15 秒 + 首尾同帧 + 数据当场算」。 做完六段之后被问:「为啥没有 3b1b 那么 fancy?」 答案不是能力,是前两条在压表现力:
| 原规矩 | 它砍掉了什么 |
| 一个字都不放 | 公式与图形同步变形 —— 3b1b 最强的手法,直接没了 |
| 15 秒 + 首尾同帧 | 一个概念只能铺 15 秒,还得留一段复位 |
⭐ 所以现在是这样:
⛔ 每次动手前先判这一句
它缺的是「解释」还是「铺陈」?
| 缺的是 | 那就 |
| 解释 —— 读者看得懂画面,但不知道这在说什么概念 | 加公式/字幕,时长和 loop 都不动 |
| 铺陈 —— 一个动作太快,或者有起承转合讲不完 | 才放长到 20 秒以上,改 controls 不给 loop |
⭐⭐ 「不够 fancy」的解药是信息密度,不是时长。 一段 15 秒循环片配一条公式,可能比拉成 30 秒更好看也更好懂。
① 文字为讲解服务,不为装饰。
可以放:MathTex 公式、Text 中文短句(走 Pango,不需要 CJK LaTeX 宏包)。
⛔ 但多出一条硬义务:视频里的字选不中、读屏读不到、搜索搜不到 ——
所以 aria-label 必须把画面里出现过的每一句话都复述一遍。
⛔ 还有:别把静态图已经说清的话再抄一遍进画面。
② 静态图排在动画上面 —— 视频加载不出来也要能读懂。(没松)
②b ⭐⭐⭐ 配色:manim 自带的原生那套,<u>这就是这个 skill 的样子</u>。
2026-09-19 拍板,2026-09-20 复核后确认为默认,不再讨论: 「现在你这种黑色背景的图画得非常好,以后经常用 —— 就要这种跟三蓝一棕的原始用法一模一样的画图方式。」
⛔ 新开一支动画时,这一节不用再判断、直接照抄。 要偏离(比如某个场合非要亮底)得有具体理由,并且做并排对照再定。
# ⛔ 不要写 self.camera.background_color —— 默认 #000000 就是作者的用法
from manim import BLUE, RED, GREEN, YELLOW, WHITE, GREY, GREY_B
# BLUE #58C4DD RED #FC6255 GREEN #83C167 YELLOW #F7D96F
# GREY #888888 GREY_B #BBBBBB 线宽默认 4,别往下调实证(扒 3b1b 神经网络系列那三个源文件):background_color 出现 0 次,
用色频率 YELLOW 103 / WHITE 101 / BLUE 78 / RED 70 / GREEN 44。
⛔ 三条配套的坑:
- 黄不能当正负号用。 他讲分量符号那一幕用的也是蓝/红;黄是强调色不是语义色。
- 黑底的辅助线要比白底亮。
GREY_D #444444在黑底上整幕消失,得用GREY #888888。 对比度是相对背景的,不是绝对的。 ⛔⛔
rate_func要分两种 play,不能一刀切(2026-09-19 实测打脸,原来这里写的是 「不要显式传 linear,匀速是机器感的来源」—— 那条一刀切是错的):play 在动什么 rate_func一个物体( mob.animate.*、FadeIn、Write、Indicate、镜头推拉…)smooth(默认,别显式写 linear)一个时钟( ValueTracker.animate.set_value,后面挂always_redraw/clock())⭐ 必须显式 rate_func=linear⭐⭐ 为什么:
smooth把 play 两端的速度压到零。动物体时那是自然的收势; 驱动时钟时那是让时间停摆。 而本 skill 的主力写法(ValueTracker+always_redraw) 几乎每个 play 都在驱动时钟 —— 一刀切换成 smooth,等于让画面在每个段界卡住。实测(
anim-descend,段界在 4.6 秒,量 50 ms 内整帧平均变化):t=3.6 … 4.6 变化 0.00 ← 段界前整整一秒画面完全静止 t=5.2 … 6.0 变化 0.0x ← 下一段开头又是慢启动⛔ 复位段尤其不能碰:
clock()倒放、三角波对称,都建立在时钟匀速上。
⭐ 判据(这一轮学到的):「作者怎么用」是证据,不是结论。 先看约束对不对得上 —— 他的默认是为全屏播放的独立视频调的。 本项目的视频嵌在亮底网页里,一度因此选了白底;对照之后仍然选原生深色, 但那是看过并排对照才定的,不是照搬。
③ ⭐⭐⭐ 全部都循环,一律不给播放器。(2026-09-20 现场拍板,这一条收紧了)
原话:「这种能放一个动图搞定的东西,就不要放一个视频啦。」
<video src="…" autoplay loop muted playsinline> <!-- 唯一的写法 -->⛔ controls 这个出口没有了。 之前的规矩是「>20 秒的叙事片给 controls 不给 loop,
因为它首尾本来就不一样」—— 那是把「我没做复位」说成了「它不该循环」。
⭐⭐ 24.6 秒的叙事片照样能循环,做法就一句话:
结尾把画面恢复成第 0 帧的样子。
# ⭐ 通用收尾模板:清干净,再摆一个跟第 0 帧一模一样的静态件
_keep = [m for m in self.mobjects if m is not curve] # curve 是第 0 帧就在的
self.play(*[FadeOut(m) for m in _keep], run_time=0.9)
self.remove(*_keep) # ⛔ FadeOut 之后补一刀,别留残影
self.add(Dot(P(TRAJ[0][0]), radius=0.13, color=GY2_)) # = 第 0 帧那颗球
self.wait(0.6)⛔ 两个真栽过的坑(2026-09-20,anim-momentum,一次改对花了三版):
| 做法 | 结果 | 不一致度 |
| 只留那条曲线 | ⛔ 首帧那颗灰球没了 | 22.9% —— 跟正常循环同档,完全看不出来 |
tracker.set_value(0) + self.add(球) | ⛔ 那颗球中途已经被 self.remove 换成静态点,唤不回来 | 27.7% —— 还是看不出来 |
| 清干净 + 摆一个静态件 | ✅ | 15.7% |
⭐ 判据一:复位不要去唤醒一个已经被移走的 always_redraw,直接清干净再摆静态件。
确定性比聪明重要 —— 你很难记清一个 mobject 在二十几个 play 之后还在不在场上。
⭐⭐ 判据二:首尾一致<u>别只看那个百分比</u>,一定要看拼接图。
上面两次都是图抓到的,数字一次都没报警 ——
一颗小球的有无,在整幅画的平均差异里几乎不占面积。
⛔ baseline 里那个 "loop": false 现在应该是空的。真要用它,
在 note 里写清「为什么这一支做不到复位」—— 而不是「它是叙事片所以不循环」。
④ 数据全部当场算 —— 等高线真二分、轨迹真迭代、精度边界真从位模式读。
⛔ 这条永远不松,而且参数也算数据:与其手调到「看着对」,
不如把「要满足的条件」写成筛子去搜一遍(见 references/traps.md §3.4)。
⛔ 多步过程类动画(环、流水线、一步一步的算法)
2026-09-25 现场纠正,原话:「你怎么 A 往右,然后剩下都往左。它应该是环形的,大家都往右发,到头了转一圈回来…… 第一步慢点,还没看明白呢,停一下再跳第二步。」
- 运动方向跟算法方向一致:绕回的那一块也往右走(出画面右边 → 底下车道 → 从左边进来),不许横穿画面往回飞。
- 不拿「直接飞到终点」的逻辑视图冒充过程:有真实步骤的,就按步骤走。
- 每一步落地后停住(飞约 1.8 秒、停约 2 秒),字幕写「第 s 步完成:……」。
- 停顿点写成数据:每次停顿记
self.renderer.time,渲染完落一份steps/<Scene>.json; 页面把它挂成<video data-pauses="…">,播到就暂停、出「下一步」按钮。这是loop之外唯一被允许的播放控制。 - 手工模式第一步也等人点:一上来停在第 0 帧、按钮写「开始」;播完绕回开头也停住;配一个「⟲ 重来」。
- 落点被占就换布局(例:每张卡分「寄出」「收到」两列),别让块叠在一起。
流程
第 0 步 · 先问它该不该动
⭐⭐ 判据:增量只能来自「时间」或「第三维」。 两个都不占就别做视频。
| 该动 | 不该动 |
| 「你得重复 N 遍」—— 重复本身就是时间 | 并列对比两种方案 |
| 「一步步降下去」—— 过程就是内容 | 结构图 / 数据通路 |
| 「这个矩阵把空间掰成什么样」 | 一组数字、一张口径表 |
| 曲面要转着看才知道是鞍还是碗 | 流程先后(箭头就够) |
第 1 步 · 写场景
主力写法是 ValueTracker + always_redraw:把「第 t 秒画面长什么样」
写成纯函数,让一个 tracker 从 0 走到 T。
⭐ 为什么不用一串 self.play:每一帧都能由 t 算出来,于是
「首尾同一帧」这类不变量可以被直接验证 —— 拼出来的时间线做不到。
复位段只在一个地方定义(把时钟拨回 0,或让它倒着走回去),
不要在每个绘制函数里各写一份 if —— 见 references/traps.md §1.3。
选类去查 references/toolbox.md:
按「要讲什么」列了对应的类、标了哪些实测过,
并给了 LinearTransformationScene 改成亮底的完整写法。
第 2 步 · 草稿迭代
scripts/render.sh <脚本.py> <SceneName> /tmp/draft.mp4 --draft4–8 秒出一版 480p。构图、时序、接缝在草稿上全看得出来 —— 一次正式渲染要 2–5 分钟,够你在草稿上试二十轮。
第 3 步 · 正式渲染 + 查接缝
scripts/render.sh <脚本.py> <SceneName> path/to/out.mp4渲染 → 压到 960 宽 crf 30 → 查首尾接缝,一条命令走完。 十几秒的动画通常落在 50–300 KB,可以直接进仓库。
⛔ 放后台跑,并且配一个 watch-task —— turn 结束你就不在了, 「渲完我再报」说出口即落空。
第 4 步 · ⭐ 看那张拼接图
/tmp/loopdiff-<名字>.png 上=首帧,下=末帧必须真的看。 工具报的那个百分比分不开「末帧是另一幕」和 「末帧偏了一像素」—— 实测同一个 51.2%,一次是差着整整一幕, 一次是转多了半度。
这就是它做成基线回归而不是阈值判定的原因:只问「有没有比记录的更糟」,
判定权在人,判完把结论写进 baseline 的 note。
scripts/check-loop.py --media <放 mp4 的目录> # 查
scripts/check-loop.py --media <目录> --update # 人眼判过了,登记新片子没有基线会报红,逼你看一眼再登记。 ⭐ 建议把这一句接进项目的 build(只读 mp4 不重渲,四支片子 1.4 秒)—— 否则「构建全绿」永远只覆盖单帧的几何与文字,盖不到产物的时间维度。
第 5 步 · 嵌页面
<figure class="fbox fwide" id="anim-xxx">
<video src="media/xxx.mp4" autoplay loop muted playsinline
aria-label="……这段在演什么,给读屏用……"></video>
<figcaption>……分幕讲清楚论点……
<span class="sub">(15 秒无声循环,Manim 渲染。)</span>
</figcaption></figure>⛔ 图注里那句「N 秒」会过期 —— 改了时长它不会自己变。
check-loop.py 带了这一项体检,拿实测时长去对(容差 0.6 秒)。
讲课视频(录音 + 课件 → mp4)的坑
另一种「会动的」:录音配课件画面,流程在 lecture-video skill。2026-09-29 从一套姊妹课程三条主线的试做里回填(手册 10 · 十一 是公开版):
| 坑 | 症状 | 修法 / 判据 |
| 提示表选择器只在字符串里查过 | 标题 ~ table 在 html 字符串里「id 存在」照样过,render.py 才断言失败 —— 表外面包着 div.tbl | 生成提示表时开真浏览器逐条 querySelector(和 render.py 同一种选法),配一个反例:改回 ~ table 必须报错、退出码非 0 |
render.py 输出路径写相对路径 | 分片清单目录拼两遍,ffmpeg 拼接失败 | 写绝对路径(2026-09-29 起脚本自己转) |
| 把页面拷到别处渲染 | 没有样式:样式表是相对路径 | 就地渲染成品目录;多个 agent 同时重建那个目录时等构建完再渲 |
页面图片 loading="lazy" | 没滚到的图尺寸为 0,截图超时/空框 | 截图前改 eager(临时副本用完即删) |
| 互动答案已在画面上 | 自动提示做不出先遮后揭 | 分镜手写揭晓时刻(addclass),或揭晓前切到不含答案的一屏 |
⭐ 判据:选择器在字符串里存在,不等于浏览器里选得中。
⛔ 版权:借思路,不抄代码
manim 本身是 MIT,随便用。但 3b1b/videos 那个仓库里的内容是
CC BY-NC-SA 4.0(署名 / 非商业 / 相同方式共享)—— 跟 manim 的 license
完全不是一回事,抄代码或画面会把它传染给你的仓库。
⭐ 可以借的是思想:叙事顺序、编码手法(颜色表符号、长度表大小)、 「先一维讲通 → 升到二维 → 承认高维想不出来 → 于是不再画空间」这类教学结构。 借了就在图注里写明出处。
出错了先看这里
references/traps.md —— 全部来自真实事故:
循环接缝判据的三次误判、FadeOut 会把东西移出 scene、Scene.add 追加到最上层、
wait() 不一定驱动 updater、偶函数导致两个谷必然等深、
「断言挡住时先看它挡的是什么」、渲染成本实测。
文件
scripts/render.sh | 渲染 → 压缩 → 查接缝,一条命令 |
scripts/check-loop.py | 首尾接缝基线回归 + 图注秒数体检,可单独接进 build |
references/toolbox.md | 按教学主题选类;哪些实测过、哪些没有 |
references/traps.md | 踩过的坑 |
📖 课程仓库
Courses/构建手册/10-Manim动画.md是这份房规的公开版(外部读者看不到本 skill)。 改了这里的房规,同步改那一篇,否则就是「一条规矩复制 N 份,N 份会过期」。课程仓库
Courses/tools/manim/下另有一份钉在那个项目上的check-loop.py副本(已接进它的build-all.sh)。两份是故意的: 那边是部署好的守卫,这边是拿去装进新项目的模板。 改了这边,想一下要不要同步过去。
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

