| 名称 | anatomy |
| 描述 | 构建精心雕琢、高度精细、可交互的等轴测 SVG 图形,把技术想法解释为一件真实的物理对象(测试台架、千分表、抽屉柜、绘图仪、锁),其中包含大量细小而精确的实体零件、四段色调明暗、正确的绘制顺序(画家算法)、带标题/提示/实时读数的画框卡片,以及平缓的缓动运动。只要有人想要等轴测插图、说明性图表或图示(用于文档、博客文章、落地页或文章)、"Linear 风格"或"高级感"的技术绘图、可交互解说图,或一张展示系统/算法/组件如何工作的 SVG,即使他们从未说出"等轴测"这个词,都应使用本技能。它不依赖框架(用 TypeScript/JS 生成 SVG 和 HTML),也可用于 React/Next.js,并能加入逼真的 WebGL 着色器(火焰、排气、水、焦散、灯光),这些效果以同一等轴测透视存在于图中。当被要求时,还可把完成的图发布到 Anatomy 社区画廊。 |
| 开源协议 | MIT compatibility: 为 Claude Code 编写;也可在 Antigravity、OpenCode、Codex 和 MiniMax Code 中运行。需要 Node.js 20.10+,以及用于各项检查的 Chrome 或 Chromium。 metadata: opencode/slash: “true” |
Anatomy
此技能让图形看起来像工作台上的一台小仪器:带脚的厚重底座、带刻度尺的导轨、装在轴套上的滑架、滚花旋钮、螺旋弹簧、指针会动的千分表、作为小点的螺钉。读者之所以能看懂这个想法,是因为他们认出了这台机器。图中显示的每一个数字都来自驱动其零件运动的同一个模型。
技能自带八个完整示例。开工前先打开最接近的一个。每个不依赖框架的示例都用 node examples/<name>/build.mjs 构建,生成的独立 HTML 页面就写在脚本旁边;加 --light 得到浅色主题。
examples/dial-indicator/是最小的一个:支架上的千分表,总共约 300 行。examples/desk-computer/是不依赖框架的 SVG:一台带可敲击键盘的台式电脑。输入的那一行显示在机箱正面平面内绘制的 CRT 屏幕上,关机时画面坍缩成一条线和一个点。它约有 85 个实体和 850 条路径。examples/arcade-cabinet/是一台竖直街机柜,侧板已拆下,Hero 规模,约 240 个实体和 15 根线缆。一枚 25 美分硬币飞入投币口,以 30° 斜面上滚盘能达到的速度沿币道滚下,碰到投币开关的线,落入钱箱;开关的脉冲沿其线缆一段一段传到电路板,CRT 预热、自检并运行吸引模式(在倾斜显示器平面内绘制)。摇杆倾斜并闭合面板下的微动开关。它展示了如何放置相机让剖面机构始终可见、如何把凹形电路板画成沿任意轴的棱柱、如何在页面中用构建时同一个模块重建运动零件,以及在已确定顺序的保留槽位中绘制实时硬币和线缆。node build.mjs --audit可证明几何正确。examples/raptor-engine/是一台吊在测试台架上的火箭发动机。它的圆形零件来自kit/lathe.mjs,它的管线与线束来自kit/tube.mjs。它可拆成 11 个装配体,带错峰弹簧和逐帧深度重排序。每个零件都记录自己的真实形状,node build.mjs --audit(kit/audit.mjs)证明:在任何静止、拆解状态以及爆炸动画回放的每一帧中,没有任何东西穿透任何东西,每个端点都坐在真实支座上,没有弯折被夹扁、折叠或压在另一条线上,没有曲线轮廓的斜率抖动,并且每个重叠都按深度顺序绘制。WebGL 羽流、激波、飞溅和蒸汽渲染在后层 SVG 与前层 SVG 之间。它是密集管线、平滑着色和淡出的参考。examples/ripple-tank/是一所学校的波纹水槽,高腿架在纸屏上方,从上方 44° 观察。两个 WebGL 层(灯光、阴影和纸上的焦散,以及水的反射和玻璃)对齐到等轴测平面,并由一个纯色散与光学模型(model.mjs)驱动;频率变化通过历史纹理从振子向外传播。examples/test-rig/是一张来自真实站点的生产图(React/Next):弹簧安装滑架上的一颗玻璃按钮、导轨上按压并拉动的指状探头,以及读取倾斜量的千分表。它有 53 个实体和约 470 条路径。examples/spot-plate/是来自同一站点的第二张生产图:凹点板上的六对玻璃水滴,每对由一个距离场绘制,因此比merge相距更近的一对会融合成一块玻璃。一扇塞尺片设定了merge,每个间隙对应一片。它是形状互相变形、以及一个控制驱动多个零件的参考。examples/turning-dial/是可选的 3D 模式:一个在真正 3D 中旋转的密码拨盘,上面有一只小机器人手。它有约 90 个金属材质的实时零件、第二个旋转组、一个铰链、一个会抬起的三铰链手指,以及一个作为自由体断开的舱体。WebGL LED、它的光斑和火花跟随运动零件。它旁边的stress.mjs是一只约 380 个零件的密集手,位于杂乱车间中,用于测量性能。
测试台架是绘图本身的质量标杆。Raptor 是着色器工作的标杆:WebGL 效果必须达到它世界空间、无跳变、无缝渲染的水准。
唯一重要的理念
物体就是解释。 不要画方框、箭头和标签。去发明一件真实的、做工精良的物理事物,它的运作就是那个概念。以下是此前的图如何映射的:
| 概念 | 物体 |
|---|---|
| 一个共享 GPU 上下文服务多个画布 | 龙门绘图仪:一个打印头访问 16 个井 |
| 内容不变时跳过工作的缓存键 | 弹子锁:当每颗弹子都匹配时,锁芯转动,什么也不用重绘 |
| 七个渲染目标,每个 texel 的字节数不同 | 七层抽屉柜,每层深度等于它的字节数 |
| 可分离模糊(49 × 49 次采样 vs 49 + 49) | 钉床印章旁边是导轨上的两把梳子 |
| 一个按压并倾斜的弹簧 | 带弹簧、探头和千分表的测试台架 |
| 高度轮廓 | 轮廓(仿形)规压在边缘上 |
| 取决于朝向的光 | 小型摄影棚:转盘周围的钥匙灯和补光灯 |
两种失败方式在实践中都见过:
- 过于抽象。 堆叠的平板、漂浮的板块或贴标签的方框,读起来什么都不像。
- 过于扁平平淡。 一块大板加几条线,没有体积、没有零件、没有可发现的东西。
两者的解法相同:一台可识别的机器,由许多细小、精确、有目的的零件构成。
每一件作品都高度精细。 这对每张图都成立,无论想法或需求多小:一张快速解说图仍是一台密集、真实的机器,绝不是几块板。随规模(工作流第 1 步)变化的只是你推进的深度:Figure 对其主题和机构做 4× 扫描,Hero 或 Epic 扫描整张图。
- 读真实的东西。 按真实物体的建造方式去建:每颗螺钉、每条缝、每个倒角、轴套、标签板、带连接器的线缆、带刻度的标尺,以及支撑零件的零件。
- 两种看法。 在 1× 下它读作一台清晰的机器。在 4× 下每个区域仍有真实的东西可发现;光秃的表面或空角是未完成的活,而非宁静。
- 有目的,绝不喧闹。 细节来自属于机构的零件。每个零件都坐在另一个零件上,结束在边缘上,并且是渐隐而不是陡然停止。
- 最后检查。 完成前放大到 4×(Figure 看主题和机构,Hero 或 Epic 看整张图),在区域平淡处补上缺失的真实零件。
工作流
按这个顺序工作。在写任何几何之前先写下概念和零件清单。大部分质量在那里就已决定。
- 开工前先定规模。 在做任何其他工作之前先说出规模,并在下述分级要求估算时大致告诉用户需要多久。
- Figure:一个机构,40–80 个零件,SVG 最多一个 WebGL 层。说出规模并直接构建,不必询问。不要向用户报时间,因为 Figure 常常不到一小时就完成。对下面的进度检查,按最多一小时预算。
- Hero:一个密集物体,多个 WebGL 层或一个 3D 主体,80–150 个零件。约 2–4 小时。先说明,然后构建,除非用户要求做个快的。
- Epic:整个车辆、建筑或带许多运动系统的工厂,或在多个主体上使用 3D 模式。6 小时或更多。不要开始。给出估算,提出一个保留想法核心的 Hero 版本,并列出完整版本会增加什么。只有当用户选择时才构建 Epic。
- 无论规模如何,第一个小时内都要有一个能在浏览器中打开的可用页面,然后从那里加深。开始时和每一步运行
date,当某一步超过其估算份额的两倍时,告诉用户进展到哪、还剩什么。
- 真实优先。 收集被解释事物的真实数字和行为:尺寸、数量、阈值、曲线。读数、运动和说明文字都必须为真。如果可以,把模型写成一个小的纯模块,如 test-rig 示例中的
rig.ts,并让一切由它驱动。 - 发明物体。 选择一台机器、工具、仪器或家具,其机构与概念一一对应。用一句话说明什么在动、这个运动意味着什么。绝不要复制参考图:取其质感,而非其物体。
- 零件清单。 写至少 40 个零件(Figure 40–80,Hero 80–150,Epic 更多),分组:底座(板、脚、槽、角螺钉、标签板、标尺条)、结构(立柱、导轨、框架杆、端挡)、机构(滑架、轴套、弹簧、柱塞、指针)、控制(滚花旋钮、拇指螺钉、表冠)以及主体本身,即唯一被点亮的零件。每个零件坐在另一个零件上。
references/craft.md有零件词汇表和配方。 - 规划世界。 使用约等于实物 1 px 的世界单位:x 和 y 在地面,z 向上。用圆角矩形
{x, y, w, d, r}和圆来布局平面图。选择相机:默认方位角 45°,35–60° 用于展示长边,仰角 30°(更高,如波纹水槽的 44°,用于看清开阔内部)。然后用fitProjection(points, width, height, { pad, azimuth })适配。 - 几何只构建一次。 用套件(
slabOf、cylinder、extrude、planOutline、topTicks、knurl、coil、radialTicks等)在几何模块中预计算每条静态路径。任意轴上的圆形零件(钟形罩、法兰、阀门、执行器)来自kit/lathe.mjs,管线和线缆来自kit/tube.mjs。运动零件在静止位置构建一次,并用translateAlong移动。只有形状会变的零件才每帧重建。 - 从后到前、从下到上绘制。 用
depthOf对重复零件排序。把包裹另一零件的任何东西拆成后半和前半:绕杆的弹簧、绕滑架的框架杆。运动零件画在它物理所在的槽位。见references/craft.md的"画家顺序"。一旦图有了管线、线缆和圆形零件,就不要再凭眼睛调键:把绘制每个物品的真实形状记录到A.recorder(P, { order, spring }),让A.settle(R, P)在任何两个物品重叠处测量真实深度并设置键,最后用A.auditOrExit(R, P)结束构建。画之前先布线:两端有真实端口、腿沿结构走、航线在直段相交、套环在管的缺口处(references/craft.md第 8 节)。记录你绘制内容的真实形状:用替身形状让审计静默是一个 bug,审计会失败。从压盖中滑出的杆是由G.rodOut生成的一根杆,用A.slide记录。 - 装框。 把图放进卡片:左上
Fig n,右上简短标题,左下交互提示,右下实时读数。图例键和真实说明放在卡片下方,除至多一个极小的雕刻标签外,图内不出现文字。 - 让它活起来。 使用平缓的基于时间的运动:指数跟随或真实弹簧。无人触碰时,空闲巡游循环。图响应指针和键盘,离开屏幕时停止,在减弱运动(reduced motion)下静止。在 refs 上写属性,不要每帧重新渲染。见
references/motion.md。 - 像评论家一样验证。 业主会放大找毛病,所以你先放大。读你做的每张 PNG。
- 用
scripts/capture.mjs捕获桌面、手机(宽 390)、悬停和若干运动瞬间;用scripts/drive.mjs做序列、拆解姿态和--no-webgl回退。 - 把审计跑到零。 有管线、线缆或圆形零件时,
node build.mjs --audit必须以audit passed结束,每一行失败项都为 0:静止、拆解和飞行中的间隙、端子、松散端、折叠、自重叠、拥挤(也包括与细长实体的)、替身形状、支撑、抖动、鞍座和深度顺序。在几何中修复干涉,绝不用键偏置。 - 把线段检查跑到零。 审计从来看不到线条标记。
node scripts/lines.mjs page.html --out shots/lines.png(以及在-light页面、以及在drive.mjs的["lines"]动作下每个静止姿态)必须打印line ends: 0:每条缝、规则线、肋、刻度和指针都结束在一条描边、一个点或一个轮廓上。读带圈的 PNG。 - 两种主题下每个接合处的 4× 特写(也构建
--light),装配与拆解状态:每个法兰、三通、弯头、卡箍、阀门、波纹管、箍带、鞍座、球接头和交叉处,每个弯曲体(无色调阶梯),纹理结束的每个位置(在边缘上或渐隐中),带缝的平面盒面,每根纹理软管在块接缝处,每根滑动杆在静止与全行程时,以及每个含文字或着色器内容的窗口。 - 着色器: 用
["slow", 0.05]在每个过渡上放慢的接触表;不能有跳变,不能有颜色突变,边缘读数为 0。浅色主题中,还要在每个过渡中逐帧记录墨量(必须随光单调变化),并在墨与描边相接处以 8–16× 裁切(references/verify.md的 “Light-theme shaders”)。 - 把你的 PNG 放到示例旁边问:它是否一眼就是真实物体,充满小零件且有体积,每条线都结束在某个东西上?它在 1× 时是否高度精细,在 4× 时仍值得探索,没有光秃表面或空角?迭代直到是。清单:
references/verify.md。
安装
套件位于 kit/:
| 文件 | 用途 |
|---|---|
kit/iso-kit.ts |
整个核心在一个文件里:相机、实体、零件库、SVG 字符串渲染器、卡片和页面构建器,以及 CSS(ISO_CSS)。复制到 TypeScript 项目中。 |
kit/iso-kit.mjs |
同一核心编译为纯 ESM,供 Node 脚本使用。直接导入。 |
kit/iso.css |
写出的 ISO_CSS。导入一次,并在包裹器或 <body> 上加 class="iso"(浅色再加 data-theme="light")。 |
kit/react/draw.tsx |
服务端安全的 React 组件:Solid、Line、Wire、Dots、FaceText、IsoFigure、Plate。 |
kit/react/live.tsx |
"use client" hooks:useReadout、useLoop、useEased、useInView、useStillness,以及 spring 和 follow。 |
kit/lathe.mjs |
沿任意轴的圆形零件:frameAlong、lathe(任何带平滑节点的轮廓会自动开启平滑着色)、solidOf、disc、ringBand、sphereOf、saddleOf、bandsOf(把一个弯曲体切成可深度排序的带,共用一个表面,轮廓由 sidesOf 给出)、可见弧线、圆面上的肋和螺栓圈(ribsOf 和 dotsOf 接受 fade,ribsOf 接受 seams)、用于从压盖中滑出的杆的 rodOut,以及管道走线的 fillet。 |
kit/tube.mjs |
tubePieces 把 3D 管或线缆拆成可深度排序的块(带 breaks、套环和卡箍下的 gaps、椭圆端盖,以及沿横截面穿过每个接头的编织/波纹/缠绕 rings),tubeSvg 绘制其中一块;crossingsOf 找出一条路径穿过卡箍的位置,runsOf 找出绘制的行程。.tb-* 填充在 ISO_CSS 中。 |
kit/audit.mjs |
证明几何。recorder(P, { order, spring }) 在辅助函数绘制时收集物品、形状(车削体、板、棱柱、盒、球、管、被其宿主切出的垫)和走线;settle(R, P) 对每个重叠对做光线投射求真深度,在静止、拆解和重放的爆炸动画中,并设置绘制键(overlapsOf、orderKeys);auditOrExit(R, P) 是 --audit 钩子,运行所有检查(clearances、solidClearances、terminals、looseEnds、supports、folds、selfOverlaps、crowding(把细长实体视为线)、coverage(替身形状)、wobble、seats、depthOrder),有任何问题就以非零退出。A.slide 记录从压盖中滑出的杆。references/kit.md 第 12 节。 |
kit/gl.mjs |
图中着色器的 WebGL 层:GLSL_ISO(GLSL 中的相机,含 rayOf 和 pixelOf)、glCamera(P)、glLayer(...),以及 JS 包络 smooth、burst 和 settle。对 3D 图,GLSL_TURN 和 glslPose(name) 把世界点带入运动组,并用 coverOf 遮罩前层画布。 |
kit/turn.mjs、kit/turn-build.mjs、kit/turn-audit.mjs |
可选的 3D 模式。turn-build.mjs 有 turning(P, { recorder }):组(turn、slide、hinge、free)、实时层、带材质的凸零件,以及 T.build。turn.mjs 是运行时:TURN.mount、控制器、TURN.cover、TURN.poseUniforms 和 TURN_CSS。turn-audit.mjs 有 orbitOrExit,对每个转角与运动片段做环绕审计。references/3d.md。 |
scripts/capture.mjs |
无头 Chrome 截图、特写和 console 检查,开启 WebGL。用 node 运行。 |
scripts/drive.mjs |
带 WebGL 的脚本化无头 Chrome:move、click、key、slow motion、wait-until、eval、shots 和能捕捉跳变的接触表;--no-webgl 和 --preload。 |
scripts/lines.mjs |
对已构建页面的线端检查,在无头 Chrome 中:每条纹理线都必须结束在描边、点或轮廓上。用 --out 给失败项加圈;任一处失败就以 1 退出。 |
scripts/inline-kit.mjs |
kitScript()、glScript() 和 turnScript() 把套件、WebGL 层和 3D 运行时作为源码返回,可内联到独立页面。 |
scripts/turn-check.mjs、scripts/turn-bench.mjs |
3D 图:对照套件构建器的保真度、z 缓冲顺序检查、像素跳变、24 个角度的线端和浏览器中的帧计时;Node 中每种零件类型的 CPU 时间。 |
选择适合项目的路径:
- 独立 HTML、静态 SVG、博客文章或任何非 React 站点。 写一个像
examples/dial-indicator/build.mjs的 Node 构建脚本。它导入kit/iso-kit.mjs,用solidSvg、lineSvg、dotsSvg、wireSvg和faceTextSvg组装字符串,用figureSvg和plateHtml包裹,并用pageHtml({ script: kitScript() + live })写出页面,有着色器时用kitScript() + glScript() + live。对于单个.svg文件,用figureSvg({ standalone: "dark" | "light" }),它会内嵌样式。 - React 或 Next.js。 把
kit/复制到项目中(例如components/iso/)。把几何保留在普通.ts模块中,在服务端组件里用draw.tsx组件构建静态图,并作为 element props 传给一个"use client"的实时组件来移动东西。references/react.md解释这个拆分以及大页面下的一个陷阱。
工艺规则(简版)
这些规则把工艺图与示意图区分开。references/craft.md 给出完整推理和配方。
- 实体,不是线框。 每个零件都用纸色填充并按顺序绘制,所以前面的东西遮住后面的。没有透视边,没有虚线隐藏线。
- 让套件着色。
extrude返回四个侧面色调(按朝向)外加更浅的顶面。任何有高度的东西都保留它,仅在底面和薄于 1 单位的内嵌中使用flat。 - 色调层级。 底座和脚用
lo,结构用mid,主体用hi。恰好一个强调色用lit(深色中为白,浅色中为黑):读者应注视的零件。槽用faint,次刻度lo,主刻度mid,零刻度hi。只有当颜色本身是主题(如红、绿、蓝通道)时才使用颜色。 - 细小精确的细节,绝不喧闹。 使用 0.4–1.6 的倒角、距边缘内缩 3–5 的槽、板角上带环的 0.4–0.55 点螺钉、旋钮上的滚花、每 4–5 单位一个刻度且每第 5 个为主刻度的标尺,以及带三条规则线的标签板。每个细节都属于某个零件。
- 线条要收束。 每条线都结束在某个东西上:一个面、另一条线或一个端子点。连接器是
Wire,其端子点落在物体上。没有引线、气泡标注、尺寸箭头或漂浮在空中的标签。 - 没有管线或线缆穿过任何东西。 不在静止、拆解或爆炸动画的任何帧中穿过另一根管、线缆或实体。除线自身连接外,与其他一切保持约 1.5 个半径的间隙;沿结构走线而不是横穿主体正面;凡法兰、箍带、波纹管、卡箍或阀门包裹管道处都要留缺口。零件要齐平、相切或边缘贴面相接,绝不沉入:法兰的背面落在其端口上(端口为曲面时落在鞍座垫
G.saddleOf上),分支从球三通引出,每个端点(拆解时也是)都收在法兰、联轴器、连接器外壳或端子点上。 - 每个交叉都按真实深度顺序绘制。 两个物品在屏幕上重叠处,近者绘于其上,由
A.settle和审计证明,而非凭眼调。线条在直段、深度差足够处相交:一个弯、端点或卡箍落在另一条线的轮廓上会被读作接头(杆、拉杆、立柱或导轨都算作线:管道的最后一段绝不在屏幕上沿着它们走),一条腿先指向观察者再转向会夹成 V 形(这类端口通过弯头球出去),一条走线绝不在屏幕上折返。无法排序的一对必须互锁,修复办法是切分或相切接触,绝不是偏置。 - 曲面平滑着色,绝不成阶梯。 把曲线节点标为平滑(
[s, r, 1]),lathe会从一条同时绘制轮廓的单调曲线为其着色;任何大于接头的弯曲体都要用带smooth: { slope }的解析轮廓,长体用G.bandsOf切分,球用G.sphereOf。色调带渐隐至无,而不是止于直切口,接缝放在轮廓之下(inner)。 - 纹理结束在真实边缘上或渐隐。 肋、螺栓圈、规则线、接缝和槽绝不在平面或曲面中间停止:
ribsOf和dotsOf接受fade(渐隐的肋用fadedSvg绘制),一排肋结束在其接缝上(ribsOf(…, { seams: true })),盒上的接缝或焊缝绕其角(k.sideSeam,如板的inner),一个面上的线从边到边,通风口是闭合槽,刻度悬挂在标尺条的边缘,一条必须停止的单线用fadeLineSvg渐隐退出,朝上的特征行(环顶部的孔)要四周都可见(all: true)。管上的纹理(编织、波纹、缠绕)沿其横截面并在每个块接缝处连续:用tubePieces(…, { rings }),绝不用沿中心线的虚线描边。管的光泽与阴影要延伸到其端盖并穿过每个块接缝。只有代表印刷文字的规则线、指针的尾部和指示器的尖端可以停在光秃表面上,标为free。 - 着色器绝不跳变或截断。 每个 uniform 都沿带上升和衰减的包络运行,相位变化是由物理量驱动的交叉淡化,每一项都在任何边界或画布边缘之前归零,效果存在于图自身相机的世界空间中(见下文)。
- 面上的东西要适配它们。 机器显示的文本在其最宽字符串处适配其窗口并被裁剪到窗口;透过开口看到的内容既被开口裁剪也被其自身平面裁剪,并绘制凹槽壁。
- 体积。 给东西真实厚度,让它们站在别的东西上,并在底座下和任何被抬起的东西下放柔和光晕。
- 构图。 让图居中并填充卡片的约 55–65%。在一组图中保持一致的尺度,并确保在 390 px 宽时仍能读懂。
绘制中的 WebGL
只在线条画不出来的地方使用着色器:火焰与排气、水与焦散、真实的灯光、辉光、蒸汽。零件仍是 SVG。核心规则来自第一张着色器图——它在相位之间的颜色变化看起来像被切开的,而不是交叉淡化的:
- 三层。 后层 SVG 承载效果所覆盖的东西,canvas 承载效果(
pointer-events: none),前层 SVG 承载覆盖效果的东西。当一个零件或效果同时位于两侧时,将其拆分。 - 世界空间,同一相机。 用
onFloor、onWallX和onWallY构建每个着色器点,或步进像素的射线rayOf(vb) + t·towardViewer()。一切以世界单位乘以uK计量。任何位于平面上的东西都与该平面的 SVG 线精确重合。 - 绝不跳变。 每个 uniform 都遵循带上升与衰减的包络(套件的
burst用于事件,settle用于电平)。相位变化是交叉淡化,颜色随物理量连续变化,淡出只会变暗。 - 没有硬截断。 每一项都在任何
if、边界或画布边缘之前,以及任何单元噪声的单元边缘之前归零。 - 透过开口看,遮罩两次。 窗口或凹槽后面的内容在其自身平面内被遮罩,也被面平面内的开口遮罩,两者相乘(
references/webgl.md第 5 节)。 - 混合。 使用
tonemap()和抖动。深色主题中,只加光的画布用预乘输出配mix-blend-mode: screen,而必须同时变暗的(波纹水槽的水)保持正常混合。 - 浅色主题必须交付,其着色器为纸张设计。 使用正常预乘 alpha,绝不用 screen。写出纸张应显示的颜色,并反解出墨水。辉光是饱和的主体配苍白的核心、有色边缘和 alpha 下限,绝不是变暗的深色主题颜色:那曾导致 Raptor 的"红墨水烟雾"。
- 光照到的物体带上一层色调,容纳它的空腔得到更暗的物理底色(烟灰、耐火材料、水深)。
- 高温物体遵循与回退方案共用的一张黑体墨水表。
- 墨水只随光增长:把完成的墨水淡化一次,绝不逐项淡化。
- 墨水在每条描边的内边缘处结束。
- 逐帧测量墨水。
references/webgl.md第 8 节有配方和审阅者发现的缺陷。
- 克制。 设备像素比上限 1.5,仅在效果活动且在屏时渲染。减弱运动只得到一帧静止画面,且 SVG 在没有 WebGL 时仍必须可读。
编写任何着色器之前先读 references/webgl.md。
3D:会转动的图(beta)
3D 像 WebGL 一样是一个选项。当零件在深度中运动就是想法时使用它:旋转的表盘或转盘、弯曲的手指、断裂掉落的物件。图的其余部分保持静态套件艺术。
它是 beta:引擎已在其示例和一张测试图上得到验证,尚未用于生产图。一次只旋转一个主体,并让周围杂物保持静止。小图以 60 fps 运行;一只密集的 380 零件弯曲手在 1440 下测得约 20 fps,在负荷沉重的机器上以手机配置(390 px、4× CPU 节流)测得 13–15 fps。
- 实时零件就是套件自己的画面。 每帧,凸的套件基元(棱柱、圆体、穹顶、带平面的球、车削体、管)都按套件的规则重新投影和重新着色。转角 θ 就是套件在方位角
a − θ处绘制。 - 顺序来自分离平面。 同组对获得一个在组内固定的平面,不同连杆上的对获得一个在其共同坐标系中固定的平面,其余的每帧求解。审计证明在任何角度或任何片段帧中都没有环。
- 接触是齐平、相切或边缘贴面。 关节是子组上的同轴指节盘,接触父级的连杆,否则审计会称整个子组是松的。没有实时线跨越两个运动组:线缆通过两侧的线夹跨过关节,或通过轮毂处的滑环到达转盘。
- 实时管在近水平面内或在配件内弯曲,绝不沿视线方向。 一个弯需要 R ≥ 2r / sin²(e − θmax),其中 θmax 包括它所依附的每个铰链的俯仰范围:平坦时边界为 8r,在 ±12° 铰链上为 21r。每条走线从安装面到安装面,其端口在
gaps中。这在每个角度和每个姿态都成立。 - 材质重映射明暗阶梯。 金、铬、钢、枪金属、橡胶、黄铜和铜各有明暗两套;色调仍来自朝向。
- 自由组断开时无跳变。 同轴零件是带转动纹理的固定画面。
- 着色器跟随运动。 用
controller.anchor或toGroup把它们锚定到组,用coverOf遮挡前层画布,并让世界效果(烟雾、下落火花、工作台上的油)留在组空间之外。 - 用
--audit验证(turn audit passed)和scripts/turn-check.mjs(--fidelity、--order、--pops、--lines、--perf)。用--quick --only=…迭代。只有完整运行才能证明图,30 个零件需 15–20 分钟,所以放到后台运行。
先读 references/3d.md。
参考
按需阅读:
references/craft.md:外观深入,包括带代码的零件词汇、色调表、画家顺序模式、圆形零件、管线与线束、爆炸图、面上的屏幕,以及被拒图的那些反模式。设计前阅读。references/kit.md:API,带签名和示例。references/motion.md:实时行为(循环、弹簧、巡游、指针、键盘、可访问性、减弱运动),以及一次性事件、爆炸图、深度重排序和布防的包络,含 vanilla JS 和 React。references/react.md:React/Next.js 服务端/客户端拆分、element props,以及大负载的 key 警告陷阱。references/verify.md:capture.mjs和drive.mjs命令、审查清单(含着色器)和常见缺陷。references/webgl.md:绘制中的着色器:何时值得、层堆栈、相机契约、在等轴测相机中光线步进、带最小页面的完整 API、带教训 bug 的工艺规则、浅色主题(纸上的墨水、逐现象配方、审阅者的缺陷),以及如何验证。references/walkthrough.md:测试台架如何被设计,从概念到代码,一步步。references/3d.md:可选的 3D 模式:组与姿态、实时层、凸零件及其规则、材质、自由组、铰链链、画家顺序、转盘周围的静态杂物、跟随转动的着色器、环绕审计、浏览器检查、性能和限制。references/publish.md:用scripts/publish.mjs在社区画廊分享完成的图,仅在用户要求时;不会替他们推送任何东西。