Skip to main content

manim-teaching-figures

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

Zur Installation springen

Quellinformationen

Repository
yangwhale/CloseCrab
Letzte Quellaktivität
25. September 2026 um 11:41
Erkannte Sprache von SKILL.md
Chinesisch
Sterne
4
Forks
0

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

Datei-Explorer
5 Dateien

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
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`)。两份是故意的: > 那边是部署好的守卫,这边是拿去装进新项目的模板。 > 改了这边,想一下要不要同步过去。
Auf GitHub ansehen