Diorama Pixel:一个会动的像素艺术微缩场景
你正在制作一个小空间——一个摊位、一个码头、一个花园地块或一个门口——从固定的等距视角观察,并绘制成像素艺术:整个画面以 320 x 240 渲染,并使用最近邻插值放大像素;每个表面通过 8x8 拜耳矩阵量化为一组短小的柔和色阶;材质带有程序化纹理(木板线、茅草条纹、石头、点状草地、斑驳水面);地面边缘渐隐于白色页面;阳光投下柔和阴影;一两个小人循环做一个清晰的动作。examples/ 中的三个场景就是标杆,请按此格式编写。
此技能是三件套之一。diorama 绘制矢量 SVG 插图(UI 场景、线稿、空状态、主题);diorama-worlds 渲染带有可活动关节人物和四种风格的详细 Three.js 世界。当用户想要像素效果、抖动、复古或 16 位风格,或者一个必须保持小巧且无依赖的像素场景时,请使用此技能。
你只需编写一样东西:场景,一个 .js 文件。内核(kit/pixel.js)和页面(kit/page.html)是固定的。切勿编辑它们,切勿粘贴修改后的副本,切勿重写内核已提供的功能(相机、灯光、阴影、纹理、抖动、地面、人物骨架、树木和灌木、一个在屏幕外休眠的时钟、指针)。
下面列出的每个文件都在此技能的文件夹中。请在工作目录中编写场景和构建后的页面,并通过此文件夹中的路径运行脚本。
1. 构思
在编写任何代码之前,用一行写出构思:
名称。 地点及其中的东西。人物做的一个动作,以及还有什么在动。指针和点击的作用。
选择一个有故事和用途的地点:一个市场摊位、一个码头、一个面包店门口、一块菜地、一个公交站、一个屋顶花园。一个动作贯穿整个场景(扎花束、钓鱼、浇水、揉面),包含预备动作和停顿,以及两三个安静的循环(布料、水、树叶、旗帜)。然后用四行写出部件清单:地面(区域:草地、铺路石、水面、沙子、土壤、一条小径)、结构(什么立着:一个摊位、一个棚屋、一道栅栏)、人物(谁、在哪、面向哪、在做什么)、生命(什么在摇摆、上下浮动或闪烁)。一个场景包含 10–25 个对象。如果清单读起来很单薄,场景也会如此。
当有人可询问时,提供两到三个构思并等待。如果无人可问,选择静态帧最有力的那个,并说明原因。
2. 构建
- 阅读
references/art-direction.md:调色板、材质、抖动、地面边缘、人物比例、什么让一个帧看起来像像素微缩模型而不是模糊渲染。 - 阅读
references/scene-api.md:所有图元、材质、帮助函数和 tick 约定。不要阅读kit/pixel.js中其索引注释以下的部分。 - 阅读最近的示例:
examples/flower-stall.js(铺路石和草地、条纹遮阳篷、两个人、一面三角旗)、examples/pier.js(水面和岸边、一个坐着拿鱼竿的人、一条船、一个茅草棚)或examples/allotment.js(土壤、砖块小径、抬高的苗床、一个正在浇水的园丁、一个稻草人)。 - 编写
<名称>.js:一个Pixel.scene({ … })调用,包含name、title、means(一句话,最多 140 个字符)、hint(悬停什么,点击什么)、duration、still、ground、可选的materials、build(P)(返回parts,其中parts.hot包含命名热区)和tick(ctx)(根据ctx.t/ctx.q为所有元素设置姿势)。 - 构建:
node <skill>/scripts/build.mjs <名称>.js会生成pixel-<名称>.html,一个无网络请求的自包含页面。
3. 检查
node <skill>/scripts/validate.mjs <名称>.js pixel-<名称>.html:检查声明、时钟、自包含性、无外部 URL、内核逐字节比对、大小预算和指针。修复每个FAIL。npm ci --ignore-scripts --prefix <skill>执行一次,然后node <skill>/scripts/look.mjs <名称>.js <输出目录>。它会在无头 Chromium 中打开页面(网络阻断),并生成<名称>-look.json,包含静态帧、循环中的四个时刻、悬停、按下和移动端视图,并检查填充、动画、循环接缝、拾取、悬停、按下、减少动画偏好、帧成本及移动端溢出。帧成本针对场景的帧预算(24fps 时为 41.7 毫秒)进行评判;--throttle 4会在速度慢四倍的 CPU 上测试,模拟 CI 运行器或手机环境。CHROME_PATH可指定浏览器;否则使用已安装的 Chrome 或 Chromium。- 打开 PNG 图片并仔细查看。 通过检查不代表图片好看。审视静态帧:在这个尺寸下,动作是否清晰可辨(手、工具、正在加工的物体)?是否有人被柱子或屋顶遮挡?每个表面是否都显示了其材质?地面是否在每侧都渐隐于页面中,没有被画框截断?地面上的阴影是否与阳光方向一致?然后修正场景,而非内核,并再次查看。
在验证器拒绝的情况下,不要交付页面。如果你没有打开图片,不要声称“查看”步骤已完成。如果没有浏览器环境,请如实说明并在“查看”未经验证的情况下交付。
4. 交付
按用户要求的方式交付 pixel-<名称>.html(文件,或者如果可以发布,则作为产物)。然后,每项一行:构思;选择的静态帧时刻及其原因;文件大小(约 50 KB,无依赖);如何嵌入(references/scene-api.md 的“嵌入”部分:一个 <canvas>、内核和场景在两个 <script> 标签中并使用 Pixel.mount,或使用那里描述的 React 组件);你无法验证的任何事项。
5. 调整
当用户要求更改时,只编辑 <名称>.js,然后重新构建、验证并再次查看。
常见问题
| 如果你发现自己… | 请执行此操作… |
|---|---|
| 使用 three.js、WebGL 或图像文件 | 这里没有这些:内核在 2D Canvas 上光栅化实体;使用 P.box、P.cyl、P.ball、P.wedge、P.line |
编写 requestAnimationFrame、setTimeout 或 Math.random | 在 tick 中根据 ctx.t / ctx.q 设置所有姿势;使用 P.hash(i, j) 获取保持一致的随机变异 |
position.x += speed * dt | 使用 P.phase(t, period) 生成位置,使静态帧和循环接缝精确 |
| 人物被柜台、柱子或屋顶遮挡 | 移动人物、降低柜台、抬高屋顶:相机是固定的,而他们是故事的核心 |
| 手臂与身体读成一个整体 | 摆出前臂伸出的姿势(P.pose(p, 'work' / 'hold')),手中握持具有自身颜色的物体 |
| 树是一个大球 | 使用 P.tree 和 P.bush:一组带圆形阴影的叶片簇 |
| 大表面使用纯色 | 使用纹理材质:'wood'、'thatch'、'stone'、'paving'、'leaf'、'cloth',或使用 tex 的色阶 |
| 地面末端出现硬边 | 地面是 ground: { rx, rz, wobble, fade }:它已经渐隐;绝不要添加平板或基座 |
| 场景比其地面更宽 | 将所有物体保持在 rx 和 rz 内;画框适配地面大小 |
| 内部宽度超过 480 像素 | 320 x 240 是标准风格;更多像素看起来像渲染图,而非像素艺术 |
编辑 kit/pixel.js 以使场景工作 | 场景错了;改变场景 |
参考资料
references/scene-api.md:声明、P(图元、材质、人物、姿势、树木、噪声)、tick 上下文和指针、运行时和嵌入。references/art-direction.md:调色板和色阶、材质和纹理、抖动、地面边缘、光照与阴影、像素尺度下的人物、构图。