跳到正文
FunCoding

edu-math-video

Use when asked to make an explainer / walkthrough video (讲解视频、解题视频、例题精讲、微课) for a math problem (数学题, geometry, algebra, functions, motion/行程 problems), from a problem screenshot or text, with Chinese voice-over (GLM-TTS / 智谱 TTS), bilingual zh+en subtitles and hand-drawn canvas animation rendered to MP4.

Star
1,492
许可证
Apache-2.0
最近提交
2026年10月10日

skills/edu-math-video/SKILL.md

在 GitHub 上查看

数学题讲解视频 (edu-math-video)

把一道数学题做成 16:9、1920×1080、带中文配音 + 中英双语字幕 + 手绘笔记本风格动画的 MP4。

流水线(每个视频一个文件夹):

script.json ──build_audio.py──► build/timeline.json + build/mix.wav + ../<name>.srt
     (旁白)     (GLM-TTS + 合成音乐)          │
anim.js + engine.js ◄─────────────────────────┘ (按旁白时间点驱动动画)
     └──node render.mjs video──► ../<name>.mp4

核心原则:画面跟着旁白走,而且图会"讲题"。 每句旁白,图上都有一个动作把这句推理演出来(线段滑过去重合、三角形叠上去、相机转到俯视、动点移动……),不是只多出一条线、一个标签。每个动画都用"第 k 句旁白开始的时刻"S.at(k, f) 定时,绝不写死秒数。

本技能自带全部代码,不要从别的项目复制文件:

  • template/:可直接运行的完整示例项目(直角三角形斜边中线题)。engine.js 是通用引擎(不改),anim.js / script.json / episode.json / problem.png 是每道题都要重写的。
  • shared/pron.py + shared/pron.json:读音控制(GLM-TTS 没有 SSML/拼音输入)。
  • examples/cone-parallel/:立体几何完整示例(anim.js + storyboard.md + script.json):相机斜视↔俯视、侧面展开成扇形、内错角旋转、平面平移。做立体几何、圆、多问题时先读它。
  • scripts/:new_video.sh(建项目)、setup_check.sh(查环境)、make_problem_png.py(文字题→图片+高亮框)、problem_boxes.py(截图→高亮框坐标)、contact_sheet.py(截图拼图审查)。

下文 SKILL = 本文件所在目录,WS = 用户当前所在的目录(你的工作目录,$PWD):视频文件夹建在这里,mp4/srt 也输出到这里。不要因为别的目录(包括本技能所在的项目)已经有 .env、node_modules、pron.json 就把 WS 换过去,缺什么由 new_video.sh 和第 2 步补齐。PROJ = 本视频文件夹,PY = setup_check.sh 报告的 python(macOS 上一般是 /usr/bin/python3;PATH 里的 python3 可能没有 numpy)。

必须遵守的规则

退出码不是 0 就是没完成。 --check 退出码 1(哪怕只剩一个 ⚠ 多音字)、motion 退出码 1、截图里有问题,都不能写"只是警告、不影响"然后继续。修好再往下走。

  1. 严格按下面 10 步顺序做,每步的"通过标准"满足了才能进入下一步。 不要跳步,不要"最后一起检查"。
  2. 先讲清楚题目。 视频第一幕必须展示原题图片(截图或 make_problem_png.py 生成的图),旁白逐条读条件,每读一条就在图上框出那一条。
  3. tts 字段只能是能念出来的中文。 不能有阿拉伯数字、= + − × ÷ / ^ √ ∠ △ ∥ ° ( ) 等符号:AC=3 写成 AC等于三,x² 写成 x的平方。字幕 zh 字段保留正常数学写法。--check 会报错拦住。
  4. 读音必须固定。 调 TTS 之前 --check 必须显示 未固定读音的生僻字/多音字: 0 且 script errors: 0。多音字的标注写在该字后面:长[cháng]、要[yào]求。不能写成 中点[zhōng](那会把"点"读成 zhōng)。
  5. API Key 只能由用户提供。 缺 GLM_API_KEY 时先问用户:配置 key(音质最好,推荐),还是用兜底引擎(edge-tts / macOS say,见 reference/glm-tts-setup.md)。不要编造 key、模型名或接口地址,不要把 key 打印出来或写进项目文件夹。
  6. 所有画面内容在 y ≤ 860 以内(y≈9141044 是字幕框)。图形放左半边 x 60900,推导文字写在右边的横线板 board() 上。
  7. 先写分镜,再写动画。 storyboard.md 给每句旁白规划"指/动/留",按 reference/visual-design.md 的动作表选动作;node render.mjs motion 必须通过。
  8. 先预览再花钱。 用 --preview + stills auto 检查版面,没问题再跑真正的 TTS。
  9. 看图验证。 每次渲染截图后都要打开 build/sheet.png 亲眼检查(用读图工具),不能只看命令有没有报错。汇报时写你实际看到了什么,不要凭印象全部打勾。
  10. 不要修改 engine.js,除非用户要求换风格;需要新图形就在 anim.js 里写函数。
  11. 不要把 node_modules、package*.json 复制进视频文件夹,依赖在 WS 根目录装一次,所有视频共享。

11 个步骤

第 1 步:弄清题目,自己先把题解对

  • 拿到题目文字(有截图就先读图)。先自己完整解一遍并验算,写下:已知条件清单、所求、关键思路(1~2 个)、每一步计算、最终答案、验算方法。
  • 答案不确定或题目看不清时,问用户,不要猜。
  • 通过标准: 你能用 3~6 个"幕"讲完,每一幕一句话说清目的;答案已验算。

第 2 步:建项目、查环境

bash SKILL/scripts/new_video.sh "$PWD" <ascii_folder_name>     # WS 就是当前目录
bash SKILL/scripts/setup_check.sh WS/<ascii_folder_name>
  • new_video.sh 会把 pron.py/pron.json 链接到技能自带的共享词表,并在找得到时把 node_modules 链接到已有安装(不复制);找不到才需要在 WS 下 npm install。python 包用 PY -m pip install --user numpy requests pypinyin pillow。
  • new_video.sh 报 ERROR: ... is where the skill is installed 说明你把 WS 设成了技能所在的项目,改用当前目录。
  • 默认音色是 chuichui(锤锤),用户可以在 .env 里用 GLM_VOICE 换。
  • 缺 GLM_API_KEY:停下,按 reference/glm-tts-setup.md 引导用户配置(推荐放 ~/.config/math-problem-video/.env,所有目录通用),然后继续。不要去别的项目里找 .env 用,也不要因此换工作目录。 用户没有 key 或不想配:TTS_ENGINE=auto(默认)会自动改用兜底引擎,setup_check.sh 会显示用的是哪个;装 edge-tts 前先征得用户同意。
  • 通过标准: setup_check.sh 输出 ALL OK。

第 3 步:测试 TTS(验证 key 和音色)

cd PROJ && PY build_audio.py --say "你好,我们来看一道数学题。"
  • 成功会打印 WROTE build/say_xxxx.wav 和 voice: ...(edge: / say: 开头 = 兜底引擎)。401/403 = key 错或没余额,告诉用户,不要重试 10 次。
  • 第一次给这个用户做视频时,把这个 wav 路径告诉用户试听,确认音色(音色表见 glm-tts-setup.md)。
  • 通过标准: 生成了 wav。

第 4 步:准备题目图片 problem.png 和高亮框

二选一(细节见 reference/animation.md):

  • 只有文字:PY SKILL/scripts/make_problem_png.py --text "完整题目" --mark "条件1" "条件2" ... "所求" --out PROJ/problem.png,它直接输出 srcW/srcH/boxes。
  • 有截图:复制到 PROJ/,必要时 problem_boxes.py crop 裁掉无关部分并存为 problem.png;然后 problem_boxes.py grid 出坐标网格图,读出每个条件的像素框;再 problem_boxes.py check 画框确认。
  • 把尺寸和框填进 anim.js 顶部的 PROBLEM。
  • 通过标准: 你打开了 *.preview.png 或 *.check.png,文字完整(没有 ☒/□ 方框),每个框都恰好罩住对应文字。

第 5 步:写 episode.json 和 script.json

按 reference/script-writing.md 写。要点:

  • episode.json:title(视频标题)、output_name(输出文件名,如 斜边中线_Median_to_Hypotenuse)、pop_scenes(要加"啵"音效的幕)。
  • script.json:幕的数组,每幕 {"scene": "英文id", "lines": [{"zh","tts","en"}, ...]}。第一幕 intro 读题,最后一幕 outro 回顾 + 报答案。
  • 每句旁白 ≤ 36 个汉字宽(否则字幕折两行),一句只讲一件事。
  • 通过标准: JSON 合法;每一幕的 id 都有计划好的画面。

第 6 步:写分镜 storyboard.md

先读 reference/visual-design.md,再按 template/storyboard.md 的格式给每句旁白写一行:| 幕id 句号 | 旁白要点 | 指 | 动 | 留 | 板书 |。

  • "指":这句提到的元素怎么点亮。"动":图上一个体现推理的动作,从动作表里选(相等→复制滑过去重合,全等→三角形叠上去,立体↔平面→相机转动,求长度→数字计数……)。"留":动作后留下的标记。
  • 除第一幕和最后一幕外,"动"不能空,也不能只写"出现/显示"。每幕至少一个连续运动。
  • 先想清楚:只看图、不看板子,观众能不能看懂这一步为什么成立?不能就换动作。
  • 先在 storyboard.md 顶部写图形清单:题目里所有的点、线段、平行/垂直/中点关系、已知长度,全部要画出来,位置按数据计算。
  • 通过标准: 每句都有一行;图形清单完整;你能说出每一幕里"最能让人看懂"的那个动作。

第 7 步:读音与脚本检查,修到 0

cd PROJ && PY build_audio.py --check ; cat build/pron_report.txt
  • ERROR 行:按提示改 script.json(通常是 tts 里有数字/符号,或 anim.js 缺 SC.<id>;第 8 步写完 anim.js 前后者会报错,属正常)。
  • ⚠ 多音/生僻 行:按 reference/pronunciation.md 处理:该字后面加 [拼音],或反复出现的词加进 pron.json 的 words,确认默认读音正确的词加进 ok。
  • 通过标准: 未固定读音的生僻字/多音字: 0 且 script errors: 0,退出码 0。

第 8 步:写 anim.js

按 storyboard.md 逐句实现,API 见 reference/animation.md。先通读 template/anim.js(示例)再动手,结构保持一致:

  • PROBLEM(第 4 步的数据)、TAGS(每幕左上角标签)、图形函数(如 fig(st))、SC.<id> = (lt, S) => {...}(每幕一个)。
  • 每个元素的出现时间 = 旁白提到它的时刻:S.P(S.at(k, f), 时长)。
  • 每句:glow(..., bump(lt, at(k))) 点亮提到的元素 → 分镜里的动作(slideSeg、movePoly、camTween、动点、countTo…)→ 留下标记。
  • 右侧 board() + bl(行号, 文字, S.at(k, f), lt) 逐行写推导(与图同色),最后 stamp() 盖章给答案。
  • 通过标准: PY build_audio.py --check 无 ERROR。

第 9 步:免费预览:动作检查 + 版面检查

cd PROJ && PY build_audio.py --preview && node render.mjs motion && node render.mjs stills auto && PY SKILL/scripts/contact_sheet.py .
  • motion 在每句里取 6 帧,比较左半边图形区的变化:STATIC(没变化)必须修;每幕至少一句 MOVE。不通过就回到分镜换更好的动作,不要只加一个无意义的晃动来凑数。
  • stills auto 在每句旁白快结束时截一帧(此时这句该出现的东西都应在画面上)。命令输出 FAILED: page error 说明 anim.js 有 JS 错误,先修。
  • 打开 build/sheet.png(多于 12 张时是 sheet_1.png、sheet_2.png…)逐张检查,对照 reference/animation.md 的审查清单:没有重叠、没有出界、没有挡住字幕、每句提到的东西都画出来了、数值与解答一致。
  • 有问题 → 改 anim.js → 重跑本步。
  • 通过标准: motion check passed;全部截图检查通过(在回复里逐幕说明你看到了什么)。

第 10 步:真正生成配音,自动听写核对,再检查一次画面

cd PROJ && PY build_audio.py && PY build_audio.py --asr && node render.mjs stills auto && PY SKILL/scripts/contact_sheet.py .
  • TTS 按文本缓存在 build/tts/,改了某句只会重新合成那一句。
  • --asr 用智谱语音识别把每句配音转回文字,写入 build/asr_report.txt(结果有缓存)。字母序列对不上的句子标 ✗,退出码 1:修改那句(见 pronunciation.md 的"字母"一节)后重跑这两条命令。报告里的汉字也要扫一遍,发现明显读错的字(不是同音字,也不是 ASR 把"三"写成"3"这种)就按第 7 步处理。
  • 真实时长与预览不同,重新看一遍 sheet。
  • 通过标准: 打印 mix + srt written;--asr 显示 字母读错的句子: 0(没有 GLM key 时显示 ASR SKIPPED:交付时告诉用户字母读音没有机器核对,列出含点名的句子请用户重点听);截图检查通过。

第 11 步:渲染视频并交付

cd PROJ && node render.mjs video 6      # 6 = 并行浏览器页数(不是帧率!帧率固定 30)
  • 输出 WS/<output_name>.mp4 和 WS/<output_name>.srt(WS = 用户的当前目录)。2~3 分钟的视频约需几分钟。
  • 交付时告诉用户:mp4/srt 路径、时长、各幕内容;说明你无法听音频,请用户试听读音,特别列出你标注过读音的字。用户反馈读错时:加到 pron.json 或行内标注 → 再跑第 10、11 步(只会重合成改过的句子)。

常见错误(真实发生过)

错误做法正确做法
当前目录没有 .env/node_modules,就把项目建到有这些东西的别的目录(例如技能所在的项目)WS 永远是用户当前目录;缺依赖由 new_video.sh 链接,缺 key 请用户配置 ~/.config/math-problem-video/.env
从别的视频文件夹(化学 chem 等)复制代码用 new_video.sh 从本技能 template/ 建项目
编造 GLM_MODEL=glm-4-voice、api.zhipuai.cn 等配置模型只有 glm-tts,地址已写在 build_audio.py;只需用户提供 GLM_API_KEY,可选 GLM_VOICE
node render.mjs video 24 以为是 24fps参数是并行数;预览版面用 stills auto,不要反复渲染整段视频
中点[zhōng]标注只作用于紧挨着的前一个字:中[zhōng]点(其实"中点"不需要标)
tts 里写 AC=3、60 − 7t、x²AC等于三、六十减七t、x的平方
题目截图随便放在 (50,50) 400×400用 PROBLEM + problemCard() 自动适配到标题下方的卡片里
用绝对秒数定时 if (lt > 12.5)S.at(k, f):第 k 句开始后 f 比例处
渲染完不看画面就交付每次都看 build/sheet.png
tts 里手动写 C、O 或 C,O 来分开字母不用管:pron.py 自动把相邻字母拆成 C O(实测逗号、顿号会多出停顿)
--check 还有 ⚠ 就调 TTS修到 0;否则会花钱合成出错误读音
为了"保险"把常见词都加进 pron.json 或行内标注只标会读错的字;替换成同音字会破坏断句(直搅三搅形),pron.py 已经只在上下文会读错时才替换
一个分句二十多个字不加标点在换气处加逗号,分句 ≤ 18 字(--check 会 warn),否则 TTS 自己在词中间停
题目图片里 x² 显示成 x☒ 却没发现审查时放大看文字;make_problem_png.py 已自动换字体
用编辑工具改 JSON 后出现弯引号 “,解析失败JSON 语法引号必须是英文 ";见 troubleshooting.md
图一次画好,之后每句只多一条线/一个标签,解释全在板子上每句都有"指→动→留";相等就滑过去重合,立体↔俯视用 camTween;render.mjs motion 必须通过
需要俯视图时在旁边另画一张图同一个 3D 模型 camTween 转到 pitch = π/2
一句旁白塞三四个知识点一句一个点,画面同步出现一个元素

参考文件

相似的 Skill

blender-motion-state-inspection

AFaffaan-m/ECC278k近 7 天新增 4,046 个 star

官方

slack-gif-creator

ANanthropics/skills181k近 7 天新增 1,119 个 star

精选

algorithmic-art

用 p5.js 生成流场和粒子系统,通过种子随机性创作原创算法艺术。

ANanthropics/skills181k近 7 天新增 1,119 个 star

thinking-out-loud

SHShubhamsaboo/awesome-llm-apps141k近 7 天新增 808 个 star

moneyprinterturbo-video

HAharry0703/MoneyPrinterTurbo130k近 7 天新增 1,722 个 star

complain

PApaperclipai/paperclip101k近 7 天新增 2,948 个 star