跳到主要内容

一句愿望,二十四页纸

#网页#Canvas#程序化绘制#AI

灵感来自亿模亿样:https://gallery.arenaofbias.icu/#/q-48c3b43eeb284f6d

1017,深度求索上线了让大量AI用户震惊瘫坐的新DSF1017,官方说明是小优化,实际上却带来一次能力飞跃。我也赶着热度给 dsh(DeepSeek Harness)和 dsf1017 写了一句不到一百字的愿望:

做一个「二十四节气」HTML 动画,单文件交付。24 个场景,每 5 秒自动切换,
按空格键可手动切换到下一个。要求视觉风格统一又各节气有区分,有设计感,
不依赖外部资源。输出单个 html 文件。(模型能力测试)

交卷的是 二十四节气 · 一纸山河:一个 139 KiB 的 html 文件,二十四页纸本画面自己翻过去,山、水、花木、鸟虫、雨雪全部由代码画出。打开页面时,网络请求列表里只有它自己。

二十四节气动画的立春场景:暖米色纸面、朱印、竖排的立春二字、一株嫩芽和淡金色太阳
立春。纸色、墨色、朱印、竖排标题与右下角的节气轮盘,二十四个场景共用这一套版式。

我关心的不是“它居然能画出来”。我关心的是另一件事:一句模糊的愿望,是经由什么步骤,变成一个可以放心打开的作品的。让它自己总结了实现过程,受到很多启发。

先翻译,再动笔

拿到愿望,它没有急着画立春。第一步是把输入的愿望拆成六条硬约束——单文件、二十四个场景、五秒切换、空格切换、统一而有区分、零外部资源——再往下翻译成工程问题:画面用什么技术画;二十四个场景怎么复用图形,而不是写二十四份重复代码;文字层压在二十四种深浅不同的纸上,怎么保证可读;没有浏览器和字体的环境里,怎么知道画对了没有。

模糊的从来是表述,不是约束。一句话只要肯拆,最后都会落成一串可执行、可验证的条件。这一步不产生任何画面,却决定了后面所有画面长什么样。

为什么是纸本水墨

技术选择是 Canvas 画主画面,DOM 和 CSS 画文字与信息层。理由分两边:主画面要的是有机曲线、天气粒子和透明叠色,这是 Canvas 的领地;节气名、拼音、日期、轮盘要的是排版与可访问性,交给 DOM 更清晰。文字不画进画布,这个决定顺带解决了一件事——页面在没有脚本时,仍保留基本信息。

风格定向纸本水墨,考虑也并不玄:节气、物候、山水、花鸟天然就长在这个方向上;Canvas 的细线、透明叠色和渐变,恰好能模拟墨色与纸感;更实际的一点是,纸色、墨线、朱印、细边框一旦定下来,二十四个画面天然就像一套东西,统一的成本很低。

于是定下一个概念:二十四个场景是同一本图鉴的二十四页,每页有自己的纸色、墨色、主色、辅色,但共用同一套骨架——左上角的朱印,左侧竖排的节气名,右上的太阳黄经,右下的节气轮盘,底部一条五秒进度线。变化的是母题、天气、构图重心和明暗。深色场景没有平均分配,而是放在需要戏剧性的节点上:大暑、处暑、秋分、大雪、冬至。二十四页因此有了呼吸,不会一直淡,也不会一直重。

先造一个能看的环境

它通过获取浏览器截图来确认绘制效果,用反馈驱动迭代。它把 Playwright 自带的 Chromium 和 Noto CJK 字体解包到 /tmp,Chromium 缺的三个系统库(libnss3、libnspr4、libasound2t64)也下载 deb 解包到同一处,再靠四个环境变量(NODE_PATH、PLAYWRIGHT_BROWSERS_PATH、LD_LIBRARY_PATH、FONTCONFIG_FILE)把这条链路跑起来。然后逐场景截图、模拟键盘、记录网络请求和 console 错误。

这么做只有一个原因:画面好不好,读代码读不出来,必须渲染出来看。后面所有迭代都建立在这条链路上,它在复盘里也把这一步列为整次任务里最值钱的投入。

截图循环:能跑,不等于对

第一轮二十四张截图出来,问题几乎成片出现,而且都不是语法错误。

鸟的剪影翅膀太宽,像蝙蝠;收窄、拉长尾叉,还是像蝙蝠,最后改成两笔式的墨鸟——两条弯翅、一个小身体、一条分叉尾,小尺寸下反而更像中国画里的飞鸟。寒露的菊花先像蒲公英,改宽又像向日葵,试了三四轮才找到多层宽花瓣、小中心、深色花心的平衡。冬至的灯笼挂绳没有接到树枝,灯笼浮在半空。大雪的竹叶太大太散,像落了一地白纸片。小满的麦穗画成一串圆珠子。清明的柳枝密密垂下来,像珠帘,把太阳和纸鸢遮了个干净。大寒原本的“雪下种子”,怎么看都像一只煎蛋,最后整个场景推翻,换成寒江独钓:枯山、冰面、芦苇、孤舟、戴斗笠的渔翁、一根钓线。孤独感比雪下种子准确得多。

真正语法层面的问题也有——括号不匹配、把数字当成颜色传进函数、闪电引用了不存在的色值——这些 node –check 和 pageerror 都能抓住。但上面那些“能跑但不对”的毛病,只有截图能抓住。流程于是固定成:写代码,渲染,截图,读图,找问题,调参数,再截图。

联系表:先看整本书,再修一页

二十四张单张截图之外,它还把它们拼成一张四乘六的联系表。单看一张,只能判断这一页好不好;摆在一起,才看得出整本书的节奏——哪几页太满,哪几页太空,明暗分布是否均匀,标题和轮盘是否始终在同一位置。据此它的策略是批量验证优先,定点修最影响整体观感的几页,而不是二十四页平均用力。

用测量收尾

最后是一轮行为测量:五秒自动切换、手动切换后计时重置、连续二十四次切换回到立春、按钮点击、按钮聚焦后按空格不双跳、六种视口无横向溢出、重场景在桌面和手机上约六十帧、pageerror 与 console error 为零、网络请求只有文件本身。

这些数字不浪漫,但它们决定了一件作品能不能被放心地打开。

尾声

回到那句愿望。许愿本身只提供方向,落地质量取决于代码外面那一圈:把模糊表述拆成硬约束,为验收搭出真实环境,用截图代替想象,用测量代替“应该没问题”。同一句愿望交给不同的闭环,交出来的会是完全不同的东西。

十四万字节的 html 是这次的结果,那套闭环才是可以带走的部分。至于二十四页里验证过的画法,后来被整理成了一座 程序化绘制能力库,哪些元素少轮反馈就能画好、哪些会失真,是另一篇文章的事了。

← 返回文章列表