---
name: vividpaper
description: VividPaper——把一篇论文做成约 3 分钟的动效解读页（张指导出品）：一个双击就能在浏览器打开的单文件 HTML，竖屏 3:4 画面配字幕，可播放、拖进度、按章节跳、切 1×/2×/4× 倍速，可选一键配音（免费的 edge-tts 中文男声，字幕和动作自动跟着声音走）。流程是拉原文和原图、定一个主线问题、拆成 5–8 幕、用论文原图加动效讲机制，最后自动自查（出界、字太小、压字幕、画面不动）。用户说「把这篇论文做成动效」「3 分钟看懂这篇论文」「动效解读」「视觉化读论文」「vividpaper」「VividPaper」「给动效配个音」，或丢一个 arXiv 链接或 PDF 说「做成动画讲讲」时用。不用于：写文字版解读、做 PPT/deck、导出 mp4 或真人出镜的口播视频。
---

# VividPaper · 视觉化读论文

> **署名。** 引擎会在片尾自动画上「本视频由开源工具 VividPaper 生成」和徽章「★ Star | ManagerZhang10/vividpaper」，页面标题和页脚（带仓库链接）也写着 VividPaper。**不要删、不要改、不要遮挡**，也不要在 film.js 里另画东西盖住它们。每一帧右上角和片头的品牌字默认是「VividPaper」；用户要署自己的名字时，在 film.js 写 `brand: '…'`（见 api.md「署名」），不要用别的办法改。

产物是一个单文件 HTML：读者看完动效，3 分钟左右就能直观建立对这篇论文的理解。画面是 1080×1440（3:4）的 canvas（要出竖屏视频时写 `layout: 'portrait'`，改成 1080×1920 的 9:16），每一帧都是时间 t 的纯函数，所以能拖、能倍速，也能自动自查。

下文 `$PM` 指本 skill 所在目录（SKILL.md 旁边）。依赖：Python 3、`pip install pymupdf`、本机装有 Chrome（或设环境变量 `CHROME`）。

## 流程

1. **拉原文**：`python3 $PM/scripts/fetch_paper.py <arXiv id | 链接 | 本地.pdf> -o <短名>`
   得到 `<短名>/source/`：`paper.pdf`、`meta.json`、`paper.txt`（带页码）、`captions.txt`（全部图表标题）、`pages/pNN.png`（每页缩略图）。
   读论文用 `grep` 和按页读 `paper.txt`，先读摘要、引言、方法和主结果；数字只从原文取。
   - `paper.txt` 里表格的数字一个一行、和行名列名是分开的：**表格数字一律对着裁出来的表格图核对**，确认每个数归哪一行哪一列。
   - 片头 `byline` 的会议名：先看 `meta.json` 的 `comment` / `journal_ref`（作者自己填的）；都没有就只写年份，不凭记忆补。
2. **定主线**（最重要，写在 `<短名>/story.md`）：
   - 一句话主线问题：这篇论文到底回答了什么问题。写进 `question`。
   - **片头用 `opening` 模板**（见 `references/api.md`「片头模板」）：先抛问题，再说「今天解读<机构 会议>的论文 <方法名>」，最后一句讲为什么值得读（具体的结果、落地、开源）；`hero` 画第 0 帧的封面主图。`paper.title` 只写方法名。
   - 一个**主角**：一个具体的例子（一句话、一张图、一个 token），从头跟到尾。优先用论文自己图里用过的例子。
   - 6–8 幕，每幕一句标题，都在回答主线；不回答主线的内容删掉。总长 2.5–3.5 分钟：6 幕时每幕 4–5 句，7–8 幕时每幕 3–4 句。
   - 每幕列出：字幕、画面上的主体、要用的论文原图。
   - 用户只说「做一个」就直接往下做，不停下来等确认；用户说「先给我看分镜」才停在这里。
3. **裁图**：先看 `pages/` 缩略图找到图在哪页，再
   `python3 $PM/scripts/crop.py <短名>/source/paper.pdf <页码> --fig <N> -o <短名>/figures/<名字>.png`
   - 自动模式按图注所在的栏裁，只取图注正上方紧挨着的图，分辨率自动定（输出 ≥ 1400px 宽）。
   - 表格、算法框、图注在图下方以外的情况、自动裁不准时：先 `crop.py <pdf> <页码> --page-grid` 出带 0.05 网格的整页图，读出坐标后用 `--box x0 y0 x1 y1`（0–1 页面比例）。
   - 每次裁图还会在 `<短名>/_grid/` 下出一张带 0.1 网格的同名图，**写 `F.box()` 的坐标直接从这张图上读**，不要凭感觉估。
   - **裁完一定打开看一眼**：子图小标题被切、带进了图注或旁边一栏的正文，都要重裁。
   - `figures/` 里的每张图都会打进 HTML，没用到的删掉；文件名以 `_` 开头的不打包。
4. **写 `<短名>/film.js`**：照 `references/api.md` 的接口和 `references/craft.md` 的画法规则写。
   完整范例：`references/example-attention.js`（Attention Is All You Need），先通读一遍再动笔。
   - 片尾回顾 3–4 条，**新片默认每条配一个小动效**：条目写成 `{ text, draw(g, box, u) }`，画那一幕机制的简化版，文字压到一行（≤ 12 字）。接口见 api.md「回顾小动效」，画法见 craft.md 第 7 条。
5. **打包 + 自查**：
   ```bash
   python3 $PM/scripts/build.py <短名> -o <短名>/<短名>.html
   python3 $PM/scripts/check.py <短名>/<短名>.html            # 可加 --at 12.5,40 导出整帧
   ```
   check 会出 `<短名>_sheet.png`（每句字幕结束那一刻一格）和问题清单。**有 ✗ 就改到没有**，然后**打开 sheet 自己看一遍**：check 查不出线条压住字、标签盖住原图里的字、大块空屏，这些只能靠眼睛。需要细看就 `--at 12.5,40` 导整帧（放在 `_frames/`，草稿用，不算产物）。
6. **配音（可选，用户要声音时做）**：画面定稿后再配，字幕每改一次都要重跑。
   ```bash
   pip install -U edge-tts                                    # 只有配音要它；微软改接口后旧版会 403，所以带 -U
   python3 $PM/scripts/voice.py <短名>                         # 默认云希男声、+30% 语速；--voice zh-CN-YunyangNeural 换声音
   python3 $PM/scripts/build.py <短名> -o <短名>/<短名>.html && python3 $PM/scripts/check.py <短名>/<短名>.html
   ```
   - 念的是每句字幕、片头的主线问题和片尾回顾，存在 `<短名>/voice/`；只合成新增或改过的句子。配了音以后每句字幕念完才切下一句，挂在 `g.L(i)` 上的动作自动跟着走。
   - 念得比按字数估的慢，总长一般会多出 15–20%。check 报「画面静止」时，在那句后半段补一个动作，挂在「这句念到几成」的时刻：`g.lerp(L(i), g.Le(i), .6)`，例如念到「降到 14.45」时圈出那根条。这样配不配音都对得上。
   - **公式要写口语念法**：引擎已自动处理下划线（`x_t` 念「x t」）、下标数字、`²`、两项之间的 `−`（念「减」）和 `→`；括号、`^`、`/`、`{}` 还会念坏，比如 `(6 − 2)` 念成「左圆括号」，`10000^(−2i/d)` 念成一串乱数。voice.py 会列出带这些符号的句子：给那句写 `say`，或者在 `pronounce` 里统一替换（见 api.md）。英文名逐字母念时也这样处理（如 `RoFormer` → `Roformer`）。
   - edge-tts 偶尔只返回开头一小段，voice.py 会自动重试；check 报「配音太短」时重跑 voice.py 即可。
   - 播放器多一个 🔊 按钮（M 键）；1×、2× 有声，4× 静音只看画面。`build.py --mute` 打包无声版。
   - 换别的 TTS：`voice.py <短名> --cmd '<命令> {text} {out}'`，命令把 {text} 念成 {out}（.wav）就行，例如在有 GPU 的机器上跑 CosyVoice。
7. **交付**：打开 HTML（macOS `open <文件>`），给用户 HTML 的绝对路径、总时长和每幕标题。

## 报错怎么办

| 现象 | 处理 |
| --- | --- |
| `fetch_paper` 说查不到 | 确认 arXiv id；没有 arXiv 的论文下载 PDF 后传本地路径 |
| `crop --fig` 找不到标题 / 裁得不对 | `--page-grid` 出网格整页图，读坐标改用 `--box` |
| check 报「报错」 | 是 film.js 抛异常，消息里有幕名；常见是 `L(i)` 超出字幕条数、图片名写错 |
| check 报「这句画面不动」「画面静止」 | 给那一句加一个跟字幕同步的动作（出现、移动、标框、连线），见 craft.md 第 3 条 |
| check 报「压字幕」 | 内容伸到了 y>1190 的字幕区，往上挪或缩小 |
| check 报「出界」 | 东西从画面外滑进来也算出界：入场改成在画面内淡入或短距离位移 |
| check 报「文字重叠」 | 两段字画在了同一处，挪开或让前一个先淡出 |
| check 报「总长」 | 不到 140 秒加一幕或每幕加句；超过 240 秒砍幕，不要压字幕。配了音超时也可以 `voice.py --rate +40%` |
| check 报「配音」 | 有字幕改过但没重新配音：重跑 `voice.py <短名>` 再 build |
| voice.py 报 edge-tts 失败 / 403 | `pip install -U edge-tts`；还不行就检查网络（要能连 speech.platform.bing.com） |
| check 没跑出结果 | 找不到 Chrome 时设 `CHROME=<路径>`；其余看报出的错误信息 |
