# 教绘画：根据一个请求或某人的图出一堂课

两种请求，一套机器：

- **「怎么画一只坐着的猫？」** 一堂基础绘画课：由你来选定题材的姿势和结构，像绘画老师那样去教。
- **「这是我的画，给我演示它是怎么画出来的。」** 重现这幅图，并教一种画出它的方法。这是 anidoodle 唯一可以紧跟一张图的场合（临摹：用户要的就是**这一张**图）。给它加上标注 **「一种画法，而不是它当初如何画成的记录」**：谁也不知道真实的顺序，这堂课也绝不能假装知道。

一堂课就是一份**绘制谱**（drawing score，`engine/src/canvas-core/drawingScore.ts`）：题材的各个部件、带稳定 id 的笔触、依赖关系、教学阶段、图层、橡皮和修正，全都以数据形式编写。一份谱可以出完成的静帧、延时绘制、步骤图，以及任意一帧的回放，全都来自**同一个**渲染器，所以延时绘制的最后一帧就是完成的画。

## 工作流

1. **按物理实际说出题材和媒介**（写在文件头注释里，和每个样张一样）：工具是什么，纸有什么表现，色调怎么叠出来，起结构用的铅笔是哪种。
2. **说明让它读得出来的解剖 / 结构**（[realism-and-craft.md](../realism-and-craft.md)），以及老师会用的结构画法（坐着的猫：头部一个球 + 胸腔一个蛋形 + 后腿一个圆；方块角色：一个盒子和它的比例）。
3. **对用户的图：** 分析它（`tools/analyze-style.mjs`），从中量出大的体块（包围盒、成排的线、位置：几行 python 或者分析结果就够了），再用相应媒介的笔触把它们重新画出来。用该媒介样张的工具包来出笔触。
4. **先写步骤，再写笔触。** 6 到 8 步，按教学顺序：定位和动势 → 大形 → 结构 → 明暗体块 → 固有色 → 边缘和细节 → 点睛。不是每种媒介都会用上每个阶段；结构可以重复出现（「检查并修正」这一步就是结构）。每一步带有：
    - `title`（几个词）和 `caption`（不超过 24 个词，画在步骤图上，也画在影片里），
    - `look`：要看什么，附一个真实的比例或测量值，
    - `how`：技法（握笔、力度、方向、橡皮），
    - `mistake`：常见的错误，以及它为什么会出错。

    一个带字幕的编号逐步揭示不是一堂课。每一步都要教点东西。

5. **编写这份谱**，用 `ScoreBuilder`：`layer()`、`part(id, label, dependsOn)`、`step()`，然后在每一步下面用 `add()` / `addAll()` / `erase()`。笔触来自 `drawingMarks.ts`：`stroke`、`hatch`（裁剪到一个区域，用密度函数表现色调）、`contour`（相互重叠的笔画，粗细由一个保留函数决定）、`sketchEllipse`、`guideLine`、`scribbleDot`。
    - **结构线用蓝色**，放在它自己的图层上（`kind: "guide"`）；用一遍橡皮**擦掉它**（`erase()`，残影取 0.05 到 0.3：可塑橡皮会留下痕迹；在上彩色铅笔之前，把它擦淡成残影，因为蜡会把底下的任何东西封住）。
    - **修正**是编写出来的事件：把错误的笔触放在它自己的图层上，擦掉那个图层，再用 `supersedes: oldId` 画新的笔触。如果一个修正的旧笔触没有先被擦掉，校验器会拒绝它。要把修正教出来：说出量了什么，以及它为什么是错的。
6. **导出三部影片**（参见 `lessonCat.ts` + `lessonCatSheet.ts` + `lessonCatFinal.ts`，每个各配一个 `page-*.ts` 宿主）：`lessonFilm(score)`（带字幕的延时绘制；它的 `.final` 是给身份闸门用的冷渲染）和 `lessonSheet(score, { crop })`。从课程模块里导出 `LESSON = { score, sheet, final, source? }`。
7. **运行** `node tools/lesson.mjs <lessonFilm> --out <dir> [--ref image --ref-crop x,y,w,h]`。它会写出 `<name>-steps.png`、`<name>-timelapse.mp4`、`<name>-contact.png`、`<name>-final.png`、`LESSON.md`、`gates.txt`，并运行：
    - **schema**（结构）：id 唯一，部件和图层都能解析，依赖无环且顺序正确，修正之前先擦除，字幕不超过 24 个词，每条辅助线都被擦掉；
    - **identity**（同一性）：延时绘制的最后一帧（用前缀缓存回放）与冷渲染出的完成画哈希相同；
    - **time travel**（时间旅行）：抽样的各帧无论正向渲染、倒序渲染，还是每帧在一个新挂载的页面里渲染，哈希都相同；
    - **fidelity**（保真度，`--ref`，仅限重现类课程）：与用户图片之间的明暗体块 IoU（参考图按它自己的三个明度色阶做色调分离）和平均 OKLab 色差。
8. **亲眼看。** 以原尺寸读步骤图，看联系表，检查每一步的字幕对它那一格来说是否属实。没有哪道闸门能告诉你这个顺序读起来像不像一只手在画，或者教的东西对不对。

## 产出物的语法

- **步骤图**：每步一格；之前各步的所有东西都在一层纸面薄罩下显得很淡，本步的新笔触浓重；擦除步骤把擦除后的状态显示得很淡。每格下面是步骤编号、标题、阶段和字幕，全部是钢笔笔画（`drafting.ts`），绝不用 `fillText`。
- **延时绘制**：一次一道笔触，每道花的时间与它的长度成正比，再加上一次提笔；本步的字幕在这一步开始时被写上去；最前面是一张标题卡；最后是一句结束语和一段定格的完成画面。各步都在拍子网格上开始。
- **LESSON.md**：每一步都完整写出来，带 look / how / mistake、它在影片中的时间、它的笔触和部件，以及图层。

## 验证（2026-09-25）

| 课程 | 来源 | 步骤 | 笔触数 |
|---|---|---|---|
| 怎么画一只坐着的猫（石墨铅笔、蓝色 Col-Erase 可擦彩铅、可塑橡皮） | 一个普通的请求 | 8 步，含一次经过测量的耳朵修正 | 844 |
| 弹钢琴的 Clawd（彩色铅笔） | 项目所有者从 Kevin Ngo 的钢琴影片里裁出的画面 | 8 步，上色之前把辅助线擦淡成残影 | 9676 |

猫这堂课随 skill 一起发布：`node tools/lesson.mjs lessonCat --out out/lesson-cat` 会重建它的步骤图、延时绘制、联系表和 LESSON.md（`engine/src/canvas-core/lessonCat.ts`）。Clawd 那堂课是照着项目所有者从另一位艺术家的影片里裁出的画面画的，所以它的产出保持私有。
