Skip to main content

manim-teaching-figures

用 Manim 给大模型 / AI 基础设施课程画「会动的」教学图 —— 矩阵与线性变换、梯度下降与优化器轨迹、动量与梯度场、loss 地形与鞍点、注意力与 KV cache 的时间演化、高维不可视时的降维表示。产出是挂 loop 的无声 mp4,配静态图与页面图注使用。当用户说「画个动图」「这段用 manim 画」「梯度下降/动量/矩阵变换要动起来」「三蓝一棕那种图」「给课件加动画」,或者一格内容的增量只能来自「时间」或「第三维」时使用。也用于检查已有动画的循环接缝对不对得上。

Jump to install

Source facts

Repository
yangwhale/CloseCrab
Last source activity
September 25, 2026 at 11:41
Detected SKILL.md language
Chinese
Stars
4
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
5 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
manim-teaching-figures
description
用 Manim 给大模型 / AI 基础设施课程画「会动的」教学图 —— 矩阵与线性变换、梯度下降与优化器轨迹、动量与梯度场、loss 地形与鞍点、注意力与 KV cache 的时间演化、高维不可视时的降维表示。产出是挂 loop 的无声 mp4,配静态图与页面图注使用。当用户说「画个动图」「这段用 manim 画」「梯度下降/动量/矩阵变换要动起来」「三蓝一棕那种图」「给课件加动画」,或者一格内容的增量只能来自「时间」或「第三维」时使用。也用于检查已有动画的循环接缝对不对得上。
# 用 Manim 画教学动画 > ⭐ **一句话认领它长什么样**:manim 原生深色(`#000000` 底、`BLUE #58C4DD` / > `RED #FC6255` / `GREY #888888`、线宽 4),**每一支都无缝循环、页面上不给播放器**, > 画面里的每一句话都在 `aria-label` 里复述一遍。 > ——&nbsp;这三条是**身份**,不是偏好。 ## 这个 skill 解决什么 一段教学动画真正难的**不是画出来,是画对且能循环播**。三件事反复出错: 1. **该不该做成动画** —— 不占「时间」也不占「第三维」的内容,静态 SVG 更好 2. **首尾接不接得上** —— 挂 `loop` 的片子首末帧对不上就每轮跳一下, 而**你播一遍是看不出来的**,得等它循环到第二遍 3. **有没有用对类** —— 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?」** 答案不是能力,是**前两条在压表现力**: | 原规矩 | 它砍掉了什么 | |---|---| | 一个字都不放 | **公式与图形同步变形** ——&nbsp;3b1b 最强的手法,直接没了 | | 15 秒 + 首尾同帧 | 一个概念只能铺 15 秒,还得留一段复位 | ⭐ 所以现在是这样: ### ⛔ 每次动手前先判这一句 **它缺的是「解释」还是「铺陈」?** | 缺的是 | 那就 | |---|---| | **解释** ——&nbsp;读者看得懂画面,但不知道这在说什么概念 | 加公式/字幕,**时长和 `loop` 都不动** | | **铺陈** ——&nbsp;一个动作太快,或者有起承转合讲不完 | 才放长到 20 秒以上,改 `controls` 不给 `loop` | ⭐⭐ **「不够 fancy」的解药是信息密度,不是时长。** 一段 15 秒循环片配一条公式,可能比拉成 30 秒更好看也更好懂。 **① 文字为讲解服务,不为装饰。** 可以放:`MathTex` 公式、`Text` 中文短句(走 Pango,**不需要 CJK LaTeX 宏包**)。 ⛔ 但多出一条**硬义务**:视频里的字**选不中、读屏读不到、搜索搜不到** —— 所以 `aria-label` 必须把画面里出现过的**每一句话都复述一遍**。 ⛔ 还有:别把静态图已经说清的话再抄一遍进画面。 **② 静态图排在动画上面** ——&nbsp;视频加载不出来也要能读懂。(没松) **②b ⭐⭐⭐ 配色:manim 自带的原生那套,<u>这就是这个 skill 的样子</u>。** > 2026-09-19 拍板,2026-09-20 复核后确认为**默认,不再讨论**: > 「现在你这种**黑色背景的图画得非常好**,以后经常用 ——&nbsp; > 就要这种**跟三蓝一棕的原始用法一模一样**的画图方式。」 ⛔ **新开一支动画时,这一节不用再判断、直接照抄。** 要偏离(比如某个场合非要亮底)得有具体理由,并且**做并排对照再定**。 ```python # ⛔ 不要写 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,匀速是机器感的来源」——&nbsp;**那条一刀切是错的**): | 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 都在驱动时钟 ——&nbsp;一刀切换成 smooth,等于让画面在每个段界卡住。 实测(`anim-descend`,段界在 4.6 秒,量 50 ms 内整帧平均变化): ``` t=3.6 … 4.6 变化 0.00 ← 段界前整整一秒画面完全静止 t=5.2 … 6.0 变化 0.0x ← 下一段开头又是慢启动 ``` ⛔ 复位段尤其不能碰:`clock()` 倒放、三角波对称,**都建立在时钟匀速上**。 ⭐ 判据(这一轮学到的):**「作者怎么用」是证据,不是结论。** 先看约束对不对得上 ——&nbsp;他的默认是为**全屏播放的独立视频**调的。 本项目的视频嵌在亮底网页里,一度因此选了白底;对照之后仍然选原生深色, 但那是**看过并排对照才定的**,不是照搬。 **③ ⭐⭐⭐ 全部都循环,一律不给播放器。**(2026-09-20 现场拍板,**这一条收紧了**) > 原话:「**这种能放一个动图搞定的东西,就不要放一个视频啦。**」 ```html <video src="…" autoplay loop muted playsinline> <!-- 唯一的写法 --> ``` ⛔ **`controls` 这个出口没有了。** 之前的规矩是「>20 秒的叙事片给 controls 不给 loop, 因为它首尾本来就不一样」——&nbsp;**那是把「我没做复位」说成了「它不该循环」。** ⭐⭐ **24.6 秒的叙事片照样能循环**,做法就一句话: > **结尾把画面恢复成第 0 帧的样子。** ```python # ⭐ 通用收尾模板:清干净,再摆一个跟第 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% ——&nbsp;跟正常循环同档,**完全看不出来** | | `tracker.set_value(0)` + `self.add(球)` | ⛔ 那颗球**中途已经被 `self.remove` 换成静态点**,唤不回来 | 27.7% ——&nbsp;还是看不出来 | | 清干净 + 摆一个静态件 | ✅ | **15.7%** | ⭐ 判据一:**复位不要去唤醒一个已经被移走的 `always_redraw`,直接清干净再摆静态件。** 确定性比聪明重要 ——&nbsp;你很难记清一个 mobject 在二十几个 play 之后还在不在场上。 ⭐⭐ 判据二:**首尾一致<u>别只看那个百分比</u>,一定要看拼接图。** 上面两次都是**图**抓到的,数字一次都没报警 ——&nbsp; **一颗小球的有无,在整幅画的平均差异里几乎不占面积。** ⛔ baseline 里那个 `"loop": false` 现在应该是**空的**。真要用它, 在 note 里写清「为什么这一支做不到复位」——&nbsp;而不是「它是叙事片所以不循环」。 **④ 数据全部当场算** ——&nbsp;等高线真二分、轨迹真迭代、精度边界真从位模式读。 ⛔ **这条永远不松**,而且**参数也算数据**:与其手调到「看着对」, 不如把「要满足的条件」写成筛子去搜一遍(见 `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 遍」——&nbsp;重复本身就是时间 | 并列对比两种方案 | | 「一步步降下去」——&nbsp;过程就是内容 | 结构图 / 数据通路 | | 「这个矩阵把空间掰成什么样」 | 一组数字、一张口径表 | | 曲面要转着看才知道是鞍还是碗 | 流程先后(箭头就够) | ### 第 1 步 · 写场景 主力写法是 **`ValueTracker` + `always_redraw`**:把「第 t 秒画面长什么样」 写成纯函数,让一个 tracker 从 0 走到 T。 ⭐ 为什么不用一串 `self.play`:**每一帧都能由 t 算出来**,于是 「首尾同一帧」这类不变量可以被直接验证 ——&nbsp;拼出来的时间线做不到。 复位段**只在一个地方定义**(把时钟拨回 0,或让它倒着走回去), 不要在每个绘制函数里各写一份 `if` —— 见 `references/traps.md` §1.3。 选类去查 **[`references/toolbox.md`](references/toolbox.md)**: 按「要讲什么」列了对应的类、标了哪些实测过, 并给了 `LinearTransformationScene` 改成亮底的完整写法。 ### 第 2 步 · 草稿迭代 ```bash scripts/render.sh <脚本.py> <SceneName> /tmp/draft.mp4 --draft ``` **4–8 秒**出一版 480p。构图、时序、接缝在草稿上全看得出来 —— 一次正式渲染要 2–5 分钟,够你在草稿上试二十轮。 ### 第 3 步 · 正式渲染 + 查接缝 ```bash scripts/render.sh <脚本.py> <SceneName> path/to/out.mp4 ``` 渲染 → 压到 960 宽 crf 30 → 查首尾接缝,一条命令走完。 十几秒的动画通常落在 50–300 KB,可以直接进仓库。 ⛔ 放后台跑,**并且配一个 watch-task** —— turn 结束你就不在了, 「渲完我再报」说出口即落空。 ### 第 4 步 · ⭐ 看那张拼接图 ``` /tmp/loopdiff-<名字>.png 上=首帧,下=末帧 ``` **必须真的看。** 工具报的那个百分比**分不开**「末帧是另一幕」和 「末帧偏了一像素」——&nbsp;实测同一个 51.2%,一次是差着整整一幕, 一次是转多了半度。 这就是它做成**基线回归**而不是阈值判定的原因:只问「有没有比记录的更糟」, 判定权在人,判完把结论写进 baseline 的 `note`。 ```bash scripts/check-loop.py --media <放 mp4 的目录> # 查 scripts/check-loop.py --media <目录> --update # 人眼判过了,登记 ``` 新片子没有基线会报红,逼你看一眼再登记。 ⭐ 建议把这一句接进项目的 build(只读 mp4 不重渲,四支片子 1.4 秒)—— 否则「构建全绿」永远只覆盖单帧的几何与文字,**盖不到产物的时间维度**。 ### 第 5 步 · 嵌页面 ```html <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 秒)。 ## ⛔ 版权:借思路,不抄代码 **manim 本身是 MIT**,随便用。但 **`3b1b/videos` 那个仓库里的内容是 CC BY-NC-SA 4.0**(署名 / 非商业 / 相同方式共享)——&nbsp;跟 manim 的 license **完全不是一回事**,抄代码或画面会把它传染给你的仓库。 ⭐ 可以借的是**思想**:叙事顺序、编码手法(颜色表符号、长度表大小)、 「先一维讲通 → 升到二维 → 承认高维想不出来 → 于是不再画空间」这类教学结构。 借了就在图注里写明出处。 ## 出错了先看这里 **[`references/traps.md`](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`)。两份是故意的: > 那边是部署好的守卫,这边是拿去装进新项目的模板。 > 改了这边,想一下要不要同步过去。
View on GitHub