记录「二十四节气 · 一纸山河」中实际使用到的程序化绘制能力:哪些对象比较稳定、分别是怎么画的、边界在哪里。
相关页面:二十四节气主页面 · 程序化绘制能力库 · 本次工作说明
可交互版本:程序化绘制能力库,含 40 个母题的实时预览、参数与源码。
记录时间:2026-10-21
#0. 先明确“稳定”是什么意思
这里的“稳定”不是指“每次都能一次画成”,而是:
在这套低饱和、纸本水墨、二维剪影式插画的风格里,给定 1–3 轮截图反馈(个别对象会更多),能比较可靠地得到一个可识别、可复用、不会明显崩坏的结果。
它依赖三个前提:
- 允许风格化:不要求照片级写实,也不要求植物学、动物学、建筑学上的精确复原。
- 有明确的母题:画山、雨、荷叶、灯笼,比画“任意复杂场景”容易得多。
- 有构图和配色托底:同样的线条,放在合适的留白、纸色和主色里,观感会显著提升。
因此,这份记录描述的是 二维程序化插画能力,不是“什么都能画”的通用图像生成能力。
#1. 能力分层
| 层级 | 典型对象 | 当前表现 | 主要限制 |
|---|---|---|---|
| 稳定 | 山、水、日月、云雨雪、草、芦苇、柳、麦穗、荷叶、菊花、飞鸟、蝉、蜻蜓、房屋、灯笼、渔船、石桥、露珠、霜、冰裂 | 可稳定生成风格化版本 | 不追求写实和精确解剖 |
| 中等 | 特定物种的精确复原、人物剪影、复杂建筑、复杂动物姿态、真实光影材质 | 需要参考和更多迭代 | 容易“像但不够准” |
| 较弱 | 人脸、手、复杂表情、写实人物、复杂机械、照片级材质、复杂多角色互动 | 不适合作为主能力 | 程序化拆解成本高,且容易失真 |
这张表是“当前这套代码 + 这套风格”的边界,不是理论上永远做不到。换 3D、骨骼、贴图、着色器或 AI 辅助,边界会变化。
#2. 稳定对象与绘制思路
#2.1 背景基底:纸、天空、山、水
纸感
- 做法:Canvas 铺低饱和纸色渐变,再叠 CSS 内联 SVG
feTurbulence噪点,最后加暗角和极细边框。 - 关键:纸色不是纯色,通常从偏亮的顶部过渡到更接近主色的底部;颗粒透明度很低,只负责“去塑料感”。
- 代码:paintBackground、纸纹 index.html。
- 注意:颗粒是浏览器滤镜生成的,不是我逐点画的;它属于“内置噪声”,不是外部图片。
天空/背景
- 做法:一条线性渐变 + 一个大范围径向色晕。
- 参数:纸色、主色、色晕中心、色晕半径、透明度。
- 作用:先把画面从“白底”变成有空气感的纸面,再往上放山、云、主体。
山脊
- 做法:多组正弦波叠加出轮廓,填充线性渐变,再描一条低透明度山脊线。
- 公式直觉:
y = y0 + sin(x * f1 + s1) * a1 + sin(x * f2 + s2) * a2 + sin(x * f3 + s3) * a3 - 分层:远山浅、低对比;中山略深;近山更深、更贴近纸色。3 层就足够产生纵深。
- 代码:ridge。
- 局限:只能做“山形轮廓”,不能做具体岩石、植被和真实地质结构。
水面
- 做法:以地平线为界,画一条从半透明主色到更浅纸色的竖直渐变;再叠若干水平短线或椭圆涟漪。
- 动效:涟漪用不断扩大的椭圆环;水纹用低透明度横线。
- 代码:ripples,水面渐变在各场景函数中内联。
- 局限:不是流体模拟,没有真实反射、折射和波纹交互。
雾/云气
- 做法:横向的线性渐变带,中间透明度高、两端透明;或大范围径向渐变。
- 参数:雾带高度、颜色、透明度、位置。
- 代码:haze。
- 作用:分隔山层、柔化边界、制造“空气透视”。
#2.2 天体与天气
太阳
- 做法:径向渐变圆盘 + 外层径向光晕 + 可选同心细环。
- 参数:半径、颜色、光晕强度、光环数量、透明度。
- 代码:orb。
- 变化:春分用暖金,夏至用朱砂,大暑用焦橙,立冬用几乎融入纸面的淡日。
- 局限:是图形化的太阳,不是物理天空模型。
月亮
- 做法:径向渐变圆盘 + 外部光晕 + 内部低透明度“陨石坑”圆斑;需要弯月时,用接近纸色的圆盘遮住一部分。
- 代码:moon。
- 注意:弯月本质上是“遮罩”,不是精确的月相几何;在深色场景里效果更自然。
云
- 做法:多个重叠椭圆 + 透明度 + 可选
blur,先铺大团,再补边缘小团。 - 代码:cloud。
- 经验:深色场景不要用“浅色墨 + 纸色”去混云色,容易越混越亮;应显式给暗色云团。
- 局限:是“云雾团块”,不是有体积、有自阴影的云。
雨
- 做法:基于种子伪随机的粒子;每个粒子有 x、y、速度、长度、透明度;绘制成带轻微倾角的线段,按时间循环。
- 代码:rain。
- 参数:数量、颜色、透明度、速度、角度、长度。
- 局限:没有碰撞、积水、风场变化;只是视觉雨幕。
雪
- 做法:与雨类似,但用圆点;部分大颗粒叠加三根短线做成六角雪花;x 方向加正弦漂移。
- 代码:snow。
- 参数:数量、大小、速度、是否画六角、透明度。
- 局限:雪不会堆积,也没有真实的湍流。
风
- 做法:两到三组贝塞尔曲线,随时间改变控制点和透明度,形成“风扫过”的线。
- 代码:windCurves。
- 作用:让静态画面产生方向感和季节感,尤其适合立秋、清明、小满。
涟漪
- 做法:以中心为原点,绘制不断增大、逐渐变淡的椭圆环;用
flat参数压扁成水面透视。 - 代码:ripples。
热浪
- 做法:多条水平折线,每条线的 y 加正弦扰动;越往下透明度越低。
- 代码:heatWaves。
- 作用:小暑、大暑的“空气在抖动”的感觉。
#2.3 植物
草
- 做法:一根从根部到叶尖的二次贝塞尔曲线,随时间轻微摆动;多个草叶通过
grassPatch成组生成。 - 参数:高度、弯曲方向、宽度、颜色、透明度、随机种子。
- 代码:grassPatch、单根草叶在场景中内联。
- 局限:是剪影草,不是有叶脉和厚度的真实草叶。
芦苇 / 芦花
- 做法:弯曲主茎 + 两片细叶 + 顶部的羽状穗;穗由多根从中心向外发散的细线组成,分深色轮廓和浅色高光两层。
- 代码:基础芦苇 reeds,白露用的羽状芦苇 plumeReed。
- 参数:高度、倾斜、穗长、颜色、透明度、种子。
- 局限:不是植物学精确的芦花结构,但远看辨识度足够。
柳
- 做法:一根三次贝塞尔主枝 + 沿线取点的小叶;叶子用旋转的椭圆/叶形,左右交替,形成垂坠感。
- 代码:willowStrand。
- 参数:长度、方向、弯曲、叶密度、叶色、种子。
- 经验:叶子太密会像珠帘;减少柳条数量、拉开间距、把叶子做成成组小叶,会更自然。
麦穗
- 做法:弯曲茎 + 一片软叶 + 穗头;穗头由一列交替倾斜的窄椭圆“麦粒”组成,再加几根麦芒。
- 代码:wheat。
- 参数:高度、倾斜、麦粒数量、茎色、穗色、种子。
- 局限:不是精确的禾本科结构,但能表达“麦浪”和“小满”的意象。
荷叶
- 做法:一个带缺口的圆,压扁成椭圆透视;从中心向外的放射状叶脉;填充径向渐变。
- 代码:lotusLeaf。
- 参数:半径、缺口角度、旋转、压扁比例、叶色、叶脉色。
- 作用:立夏、大暑的主要水面母题。
荷花 / 花苞
- 做法:多层尖卵形花瓣围绕中心旋转排列;花苞用更少、更闭合的花瓣。
- 代码:lotusBud,荷花在场景中组合。
- 局限:是风格化荷花,不是精确的莲属植物结构。
牡丹
- 做法:4 层左右的花瓣,从外到内逐渐变小、变深;每片花瓣是一个宽而圆的贝塞尔形状;中心加少量金色花蕊。
- 代码:peonyPetal、peony。
- 参数:花瓣层数、每层数量、长度、宽度、旋转偏移、外/中/内色。
- 经验:花瓣太尖会像莲花,太宽会像向日葵;牡丹的关键是“宽、圆、层叠、花心小”。
菊花
- 做法:5 层细长花瓣,每层数量不同、旋转偏移不同;花瓣有轻微侧弯,中心和内层颜色更深。
- 代码:chrysanthemum。
- 参数:5 层花瓣的长度、宽度、数量、弯曲、颜色。
- 经验:这是本次迭代最多的花。太细像蒲公英,太宽像向日葵,最后才找到“多层宽花瓣 + 小中心”的平衡。
银杏
- 做法:扇形贝塞尔外轮廓 + 中央缺口 + 从叶柄放射的叶脉;叶柄单独画线。
- 代码:ginkgoLeaf。
- 参数:半径、旋转、颜色、透明度。
- 局限:小尺寸时容易像蝴蝶或心形,需要配合树枝和尺寸层级使用。
桃花 / 梅花
- 做法:递归枝条 + 五瓣小花;花瓣是五个旋转的椭圆,中心一个小圆点;枝条用二次贝塞尔并递归分叉。
- 代码:peachBranch、plumBranch、blossom。
- 参数:递归深度、枝长、分叉角度、花色、花心色、种子。
- 局限:不是精确的蔷薇科花结构,但五瓣 + 枝干已经足够识别。
竹子
- 做法:弯曲主竿 + 横向竹节 + 从节点分出的侧枝 + 成组的披针形竹叶 + 叶面雪线。
- 代码:bambooLeaf,大雪场景中的竹竿和侧枝在场景函数中组合。
- 参数:竿高、倾斜、竹节数量、叶长、叶宽、雪线宽度。
- 经验:竹叶不能太大太散,否则像纸片;要成组挂在枝节上。
柿子
- 做法:径向渐变圆 + 顶部四/五瓣花萼 + 高光 + 细果柄;叶子用叶形函数。
- 代码:persimmon。
- 参数:半径、果色、叶色、花萼色。
- 局限:是剪影式果实,不是有真实表皮质感的柿子。
芦苇/莲蓬/其他
- 莲蓬:椭圆顶面 + 锥形身体 + 七个暗色种子孔 + 弯曲茎,见 lotusPod。
- 草叶、花瓣、叶片:基本都用贝塞尔或椭圆,组合方式比单个形状更重要。
#2.4 动物
飞鸟
- 做法:两条弯曲的翅膀笔画 + 小身体 + 分叉尾,远看像中国画里的墨鸟。
- 代码:distantBird。
- 经验:早期用完整填充剪影,结果像蝙蝠;改成两笔式后,小尺寸下反而更像鸟。
蝉
- 做法:透明的翅膀路径 + 翅脉 + 分节腹部 + 头胸 + 六条腿;翅膀用低透明度渐变和描边。
- 代码:cicada。
- 参数:身体色、翅膀色、角度、大小。
- 局限:是风格化蝉,不是精确的蝉科解剖。
蟋蟀
- 做法:细长腹部 + 折叠翅膀 + 头和触角 + 折叠后腿;整体侧视。
- 代码:cricket。
- 经验:早期版本腿太直、身体太圆,像蜘蛛;后来把后腿折起来、身体拉长,才像蟋蟀。
蜻蜓
- 做法:细长身体 + 两对透明翅膀 + 头部 + 分节腹部;翅膀用椭圆 + 旋转 + 低透明度。
- 代码:dragonfly。
- 作用:立夏、芒种、小暑的点睛元素。
喜鹊
- 做法:身体椭圆 + 头部 + 长尾 + 白色腹部 + 白色肩斑 + 腿和爪 + 喙。
- 代码:magpie。
- 经验:黑白对比和长尾是识别关键;早期版本像企鹅,补上尾巴和腿后改善。
白鹭
- 做法:椭圆身体 + S 形脖子 + 细腿 + 长喙 + 翅膀线;用深色描边保证在白纸背景上可见。
- 代码:egret。
- 局限:是剪影式涉禽,不是精确的鹭科结构。
甲虫
- 做法:椭圆鞘翅 + 头部 + 六条腿 + 触角 + 中缝线 + 高光。
- 代码:beetle。
- 作用:惊蛰的“苏醒昆虫”母题。
#2.5 人造物
房屋
- 做法:2.5D 小屋:正面墙 + 侧面墙 + 斜屋顶 + 雪顶 + 门 + 窗 + 烟囱 + 炊烟 + 屋檐冰凌。
- 代码:house。
- 参数:大小、墙色、屋顶色、窗光色、炊烟色。
- 经验:雪顶要和纸色拉开一点冷灰差,否则在雪景里会消失;窗户要用暖色,才有“有人居住”的感觉。
灯笼
- 做法:椭圆灯笼身 + 上下盖 + 竖向/椭圆肋线 + 内部暖光 + 挂绳 + 流苏 + 外发光。
- 代码:lantern。
- 经验:挂绳长度必须和树枝位置对齐,否则灯笼会像悬空;本体要做出肋线,才不只是一个橙色圆球。
渔船
- 做法:船体用两段二次贝塞尔收出船头和船尾 + 船板线 + 坐姿渔翁 + 斗笠 + 鱼竿 + 鱼线 + 鱼漂 + 小船灯 + 水面倒影。
- 代码:fisherBoat。
- 经验:船的识别关键是“两端翘起”的轮廓;渔翁的斗笠和钓线是叙事核心。
石桥
- 做法:半圆弧桥拱 + 桥面横线 + 栏杆竖线 + 低透明度倒影;在清明场景里再叠加撑伞小人。
- 代码:清明场景内联,见 index.html。
- 局限:是二维剪影桥,不是有砖石结构的建筑。
#2.6 微元素与氛围
露珠
- 做法:小径向渐变球 + 左上高光点 + 轻微透明边缘。
- 代码:dew。
- 作用:白露、寒露的关键细节,数量不需要多,点状高光就能表达“露”。
流萤
- 做法:径向光晕 + 小亮点 + 时间脉冲 + 正弦漂浮。
- 代码:fireflies。
- 作用:处暑夜景的主要动效。
霜
- 做法:递归分叉的细线,模拟霜晶;在叶缘、地面、果面上少量叠加。
- 代码:frostBranch。
- 局限:是二维霜纹,不是真实的冰晶生长模拟。
冰裂
- 做法:递归分叉线,每次分叉缩短、降低透明度。
- 代码:iceCrack。
- 作用:大寒、立冬的冻土/冰面纹理。
雾气/水汽
- 做法:低透明度线性渐变带 + 局部径向渐变。
- 代码:haze。
- 作用:把前后景分开,增加空气感。
#3. 为什么这些对象能稳定画出来
#3.1 可以拆成少量图元
这些对象基本都能还原成:
- 圆 / 椭圆;
- 三次或二次贝塞尔曲线;
- 多段线;
- 线性/径向渐变;
- 低透明度叠色;
- 重复 + 旋转 + 缩放。
不需要复杂的 3D 网格、物理模拟或真实材质。
#3.2 剪影识别优先于细节
在纸本水墨风格里,观众先认出轮廓,再注意细节:
- 荷叶先看“圆 + 缺口”;
- 麦穗先看“细长穗头”;
- 蝉先看“透明翅膀 + 分节身体”;
- 渔船先看“两端翘起的船体”;
- 灯笼先看“椭圆 + 挂绳 + 流苏”。
所以代码优先把剪影做对,再补叶脉、翅脉、肋线等细节。
#3.3 低细节容忍度高
风格化插画允许“像”而不是“精确”:
- 芦苇不需要每一根穗都符合植物学;
- 山不需要真实地质;
- 云不需要体积渲染;
- 鸟不需要解剖级准确。
这给程序化绘制留下了很大空间。
#3.4 参数化程度高
同一套函数可以通过参数复用:
- 大小、位置、旋转;
- 颜色、透明度;
- 种子、数量、层数;
- 弯曲方向、长度、宽度。
24 个场景不是 24 套完全不同的画法,而是同一套绘图词汇的不同组合。
#3.5 可以截图反馈
这些结果不是“盲写”出来的。实际流程是:
写代码 → headless Chromium 渲染 → 截图 → 读取截图 → 找问题 → 调参数 → 再截图
例如:
- 鸟像蝙蝠 → 改成两笔式墨鸟;
- 寒露的花像蒲公英 → 重新设计花瓣层次;
- 冬至灯笼悬空 → 对齐挂绳和树枝;
- 深色场景树枝发白 → 改用显式深色;
- 大寒雪堆像煎蛋 → 改成寒江独钓。
没有截图反馈,稳定度会明显下降。
#4. 通用绘制套路
如果要把一个新对象加入这套系统,可以按这个顺序:
- 先画剪影:只用一个颜色,确认远看能认出是什么。
- 拆 2–4 层:主体、暗部、亮部、细节;不要一开始就画很多线。
- 加主色和辅色:从所属节气的
paper / ink / accent / accent2里取色。 - 加纹理:叶脉、翅脉、竹节、灯肋、冰裂等,只加 1–2 种。
- 加动效:只让 1–2 个部分动,例如柳条摆动、翅膀轻颤、流萤呼吸。
- 截图检查:看小尺寸是否还能识别,看和相邻场景是否风格一致。
- 参数化:把大小、颜色、角度、种子抽出来,方便复用。
一句话:
剪影优先、层次少量、颜色克制、细节点到为止、动效只动局部。
#5. 不稳定或做不到的对象
| 对象 | 为什么难 | 可能改善方式 |
|---|---|---|
| 人脸、手、复杂表情 | 需要精确解剖和微妙比例;程序化拆解成本高 | 参考图 + 3D 基础 + 手工修正 |
| 写实人物、复杂姿态 | 骨骼、肌肉、布料、透视相互耦合 | 骨骼系统、动作捕捉、3D 模型 |
| 特定物种的精确复原 | 需要植物学/动物学结构知识 | 真实参考、标本图、专业建模 |
| 复杂建筑、机械 | 结构、材质、透视、细节层级复杂 | CAD/BIM、3D、纹理贴图 |
| 照片级材质 | 需要真实光照、反射、粗糙度、次表面散射 | PBR、着色器、渲染器 |
| 多角色复杂叙事 | 构图、遮挡、动作、表情同时变化 | 分镜 + 3D + 合成 |
| 精确复刻某张具体作品 | 风格、笔触、构图、色彩关系高度依赖参考 | 专门研究 + 人工绘制/训练 |
| 复杂手写字/书法 | 需要字形结构和笔势 | 字体、书法字库或人工书写 |
#6. 如果想继续提升
- 参考图驱动:给每个对象准备 2–3 张参考,先确定剪影和比例,再写代码。
- 3D 基础 + 2D 风格化:用简单 3D 模型确定透视和光影,再在 Canvas 里描线。
- 骨骼/参数化系统:给人物、动物加关节和姿态参数,避免每次都硬编码。
- 着色器/材质:如果允许 WebGL,可以做更真实的纸、墨、雾、光。
- L-system / 分形:适合树枝、竹叶、霜花、藤蔓。
- 纹理贴图:如果不再要求“无外部资源”,可以用授权的纸纹、墨迹贴图提升质感。
- AI 辅助:可用于概念参考、局部素材生成,但需要额外解决风格一致性和版权问题。
#7. 与本次交付的关系
- 24 个节气的数据在 index.html。
- 24 个场景函数在 index.html。
- 公共绘图函数在 index.html。
- 渲染循环与 5 秒计时在 index.html。
- 纸张颗粒在 index.html。
- 文字字形来自系统字体,不是程序化绘制;这是本记录中唯一需要单独说明的“非代码图形”来源。
#8. 结论
这套作品证明的是:
在明确的风格约束下,常见的二维场景元素可以被拆成少量图元,通过参数化组合和截图反馈,稳定地程序化绘制出来。
但它不等于“任意素材都能画”。稳定的是:
- 有清晰剪影的自然元素;
- 重复结构明显的植物;
- 低细节容忍度的动物剪影;
- 简单的人造物;
- 天气、雾、露、霜、冰裂等氛围元素。
不稳定的是:
- 高精度人物;
- 复杂解剖;
- 写实材质;
- 多角色复杂叙事;
- 必须精确复刻的参考对象。
理解这个边界,比笼统地说“AI 会画画”更有用。