跳转至

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

两种请求,一套机器:

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

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

工作流

  1. 按物理实际说出题材和媒介(写在文件头注释里,和每个样张一样):工具是什么,纸有什么表现,色调怎么叠出来,起结构用的铅笔是哪种。
  2. 说明让它读得出来的解剖 / 结构(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 那堂课是照着项目所有者从另一位艺术家的影片里裁出的画面画的,所以它的产出保持私有。