Anatomy:让 Claude Code 把抽象概念画成可交互机械装置的技能
Anatomy · a Skill for Claude Code
作者发布 Anatomy,一个 Claude Code 技能,输入一行想法即可让 Claude 自行发明一台能体现该概念的机械装置,并绘制成可旋转、按压、读取数据的等距交互图。
用一行字说出一个想法,Claude 就会画出实现它的机器。
大多数解释某物如何运作的方式都是用方框和箭头画出来的。它们告诉你各个部件存在,却不告诉你这些部件做什么,读者只能自己想象箭头所代表的运动。我希望 Claude 画出事物本身:一个真实的物体,其运动部件的行为方式与这个想法一致。
Anatomy 是 Claude Code 的一项技能,正是做这件事的。你用一行字说出一个想法,Claude 发明一台实现它的机器,并把它画成一个可实时交互的等轴测图形,你可以旋转、按压和阅读。每个图形都由几十到几百个小实体部件组成,它显示的每一个数字都来自驱动它们运动的同一个模型。
这是一个机械表机芯。它来自一行字,/anatomy explain how a mechanical watch keeps time, interactive,以及 Claude 独自工作不到两小时。1活跃时间一小时五十四分钟,一次构建完成,并由同一个智能体检查。
向上拖动表冠给它上弦:棘轮转动,棘爪咔哒作响,动力储备上升。按 S 把时间放慢到二十分之一,再按一次到百分之一,你就能看到擒纵叉让十五齿的擒纵轮一次只过一个半齿。按 E 把夹板抬开,看到下面的轮系,它的轮子按真实传动比切削:四轮每分钟转一圈,中心轮每小时转一圈。
这项技能基于一条规则,写在它指令的最上方,高于一切:
物体本身就是解释。SKILL.md,“唯一重要的想法”
没有方框,没有箭头,没有漂浮在空中的标签。Claude 必须发明一个真实、制作精良的东西,其运作就是这个概念,并用一句话说明什么在动以及这种运动意味着什么。
一个图形会以两种方式失败,在这条规则存在之前,我多次看到它以这两种方式失败。太抽象:堆叠的板、漂浮的块和贴了标签的方框,读起来什么也不像。太扁平:一整块大板,上面画几条线,没有体积,没有部件,没有什么可发现的。两者的解药是一样的:一台由许多小部件构成的可辨认的机器,每个部件都各司其职。2机器从不照参考图复制。参考图可以提供表面处理、材质和氛围;物体是发明出来的。
有些想法几乎能自行对应。队列就是一条弹珠轨道:两个料斗供给一条倾斜的通道,弹珠在一个擒纵机构后面按顺序等待,直到一个定时滚筒把它们带走。一个会遗忘最旧条目的缓存是一个书架,顶部有四个位置,最近使用的在左边。其他的则需要更多发明。布隆过滤器是一台水果机,它的三个转轮就是三个哈希函数,只有当某个词的三面旗标都已竖起时它才会派彩。
这些都不是手绘的。每一个都从一行命名该想法的文字开始。目前共有 33 个,全部在合集中实时运行。
提示词是想法,而不是图画。我几乎从不说该画什么。“解释 LRU 缓存如何逐出条目”就够了,而决定它应该是一个书架,正是要求 Claude 去做的部分。
有三个词会改变你得到的结果,只有当你把它们写进那一行时,Claude 才会去用它们:
interactive | 图形会响应指针和键盘:拖动、按下、按住某个键。省略这些,你得到的只是一幅静止的图画。 |
|---|---|
WebGL | 火焰、水、等离子体、流动的空气和光的着色器,绘制在与部件相同的等距相机内。 |
3D | 真正在深度上转动的部件,每一帧都重新投影和重新排序,而不是仅仅看起来是等距的。慢:需要数小时来构建,而不是几分钟。 |
如果你已经知道这个物体,就说出它的名字,并附上任何重要的真实数字。如果图形要去某个特定的地方,就说明是哪里。该技能会编写不依赖框架的 TypeScript,输出 SVG 和 HTML,或为 Next.js 网站输出 React 组件,支持深色或浅色主题。
你并不总是需要命令。该技能的描述涵盖了任何对解释性图表、技术插图或交互式讲解的请求,即使请求中从未提到“等距”,所以 Claude 会自行使用它。3在请求匹配之前,Claude 只能看到技能的名称和描述。它只在需要时才读取其余部分。
从你的描述到完成的图形,Claude 会按照固定的顺序进行。大部分质量在前四步就已决定,那时还没有任何几何图形。
确定规模。 一开始就说明这是 Figure、Hero 还是 Epic,以及大致需要多长时间。
真实优先。 收集真实的数字和行为,并将它们写成一个小模型,让运动和读数都从中读取。
发明物体。 一台其机制与想法一一对应的机器。
列出部件。 至少四十个,分为底座、结构、机制、控制装置和一个被照亮的主题。每个都位于另一个之上。
规划世界。 世界单位,平面用圆角矩形和圆形表示,一个相机,然后适配到卡片。
一次性构建几何图形。 每条静态路径都提前计算好。运动部件在静止状态下构建,然后移动。
从后到前绘制。 按深度排序,包裹部件一分为二,一旦密集就通过审计来证明顺序。
装框。 一张带有标题、交互提示和实时读数的卡片。文字不进入绘图。
让它活起来。 平静的、基于时间的运动,空闲巡览,指针和键盘,以及在减少动态效果下保持静止。
像评论家一样验证。 截图、联系表、四倍裁剪和两次自动检查,直到没有需要修复的地方。
第二步在实践中是这样的。测试装置是该技能的一个示例,它解释了玻璃按钮如何在手指下膨胀和倾斜,其整个行为都存在于一个小型弹簧模型中。部件、读数、屏幕阅读器文本和说明文字都从中读取,因此它们不可能相互矛盾。
rig.ts
function spring(held: Spring, want: number, dt: number, [stiff, drag]: Tuning, calm: boolean) { const damping = calm ? 2 * Math.sqrt(stiff) : drag; const steps = Math.max(Math.ceil(dt * SUB_RATE), 1); const slice = dt / steps; for (let step = 0; step < steps; step++) { held.rate += (want - held.at) * stiff * slice - held.rate * damping * slice; held.at += held.rate * slice; } if (Math.abs(want - held.at) < QUIET && Math.abs(held.rate) < QUIET) { held.at = want; held.rate = 0; } }
还有第六步。表盘指示器是最小的示例,从它的底座开始:四个按深度顺序排列的车削支脚,一块带斜面的板,一个距边缘五单位的内嵌凹槽,以及每个角上带环的螺丝。其中每一个都是套件中的实体,而不是手工绘制的线条。
build.mjs
function plate() { const out = [`<path class="iso-halo" d="${k.haloOf(PLATE, -PLATE_H - FOOT_H, PLATE_H, P)}"/>`]; for (const [x, y] of byDepth(k.corners(PLATE, 22))) { out.push(S(k.cylinder(x, y, 7, -PLATE_H - FOOT_H, 1.6, P, 28), { tone: "lo" })); out.push(S(k.cylinder(x, y, 5.4, -PLATE_H - FOOT_H + 1.6, FOOT_H - 1.6, P, 28), { tone: "mid" })); } out.push(S(k.slabOf(PLATE, -PLATE_H, PLATE_H, P, 8, 1.6), { tone: "mid" })); out.push(L(k.planOutline(k.insetPlan(PLATE, 5), 0, P), { tone: "lo" })); const screws = k.corners(PLATE, 10); out.push(L(screws.map(([x, y]) => k.ring(x, y, 2.2, 0, P, 16)).join(""), { tone: "lo" })); out.push(D(screws.map(([x, y]) => at([x, y, 0])), { size: 0.5 })); return out.join(""); }
第一步设定预算。每个请求都属于三种规模之一:
| 规模 | 包含内容 | 时间 |
|---|---|---|
| Figure | 40–80 个部件,SVG,最多一个着色器 | 30–90 分钟 |
| Hero | 80–150 个部件,多个着色器或一个转动部件 | 2–4 小时 |
| Epic | 整个车辆、建筑或工厂 | 6 小时或更长 |
Figure 是直接做出来的。Hero 则先公布,再做出来。Epic 绝不会在没有你的情况下启动:Claude 给出估算,提出一个保留想法核心的 Hero,并列出完整版本会增加什么。4无论规模大小,第一个小时内浏览器里就会有一个可用的页面。剩下的时间都用来深化它。
每个 figure 都遵循相同的绘制规则。正是这些规则让它读起来像一件坚实的、做出来的东西,而不是一张草图。
- 一台相机
- 等轴测,从一个角向下看 30°。没有透视,所以平行边保持平行。
- 实体
- 每个部分都按顺序填充和上色,所以前面的会遮住后面的。没有透视边缘。
- 四种色调
- 每一面根据它朝向光的方式着色,顶部更亮。
- 一个强调
- 恰好有一个部分被点亮:读者应该关注的那个。
- 线条收束
- 每条线都终止于一个面、另一条线或一个点。没有引线、标注框或箭头。
- 4× 下的细节
- 正常尺寸下它读起来像一台机器。放大后,每个区域仍然有真实的东西可发现。
- 内部无文字
- 文字围绕在绘图周围,绝不放在图上,最多只有一个微小的雕刻标签。
- 真实数字
- 每个读数都来自驱动这些部件的模型。
Figure 也是一个小程序。没人触碰时它会播放一段空闲导览,当你悬停或聚焦时暂停,响应指针和键盘,滚出屏幕时停止,在减少动态效果时保持静止。它的读数在变化时会向屏幕阅读器播报。
在它自己的页面上,figure 位于一张卡片中,四个角分别是它的编号、标题、提示和实时读数。在这个网站上,我把提示和读数移到了每个 figure 旁边的页边距里,这样绘图就能独自立在页面上。
这个合集最好一次读一台机器。每个名字先点出想法,然后是 Claude 为它选择的对象;打开一个来玩一玩。
哈希映射冲突
分拣台
哈希映射把每个键归档到一个桶里,落到同一个桶里的键会堆叠起来。一个邮局分拣台。一台编码机打印每个字母的桶号,即其名称哈希值 mod 8,并把它归入那个鸽巢,放在已有字母的上面。
布隆过滤器
水果机
布隆过滤器可以确定地说“绝对没有”,但只能说“也许”有。一台水果机。三个转轮是三个哈希函数,一排十六个标志是位数组;只有当某个单词的三个标志都已亮起时它才会出奖。
互斥锁
水箱与钥匙
两个写入者同时读取同一个值,都会基于过时的数字行动。一个由两台泵注水的水箱。没有互锁钥匙时,两个控制器读到相同的水位并把它注得过满;有了它,只有持有钥匙的那个才能读取和运行。
TCP 握手
邮件索道
在任何数据移动之前,两端都必须同意对方在监听。两个站点之间的邮件索道。挂着 SYN、带 ACK 旗的 SYN、然后是 ACK 的罐子沿绳索飞过,每个站点的信号机显示其连接状态。
温度
轮盘
温度重塑下一个 token 的概率,但不改变哪些 token 是可能的。一个轮盘,其十六个口袋是最可能的下一个 token,每个的宽度等于其概率。一个恒温器旋钮设定温度并移动档格。
防抖、节流
八音盒记录器
防抖等待安静下来;节流在每个窗口内只放行一次调用,无论到达多少次。 一台带旋转销盘的八音盒录音机。旋钮的每一次咔哒都是一次调用;节流和防抖阻尼器各自设定自己的销钉,因此你可以读出每个函数实际运行的时间。
每次的模式都一样。对象必须做出这个想法,而不是代表它,所以你看着移动的东西就是被解释的东西。
小想法造小机器。大想法才是技艺真正体现价值的地方:数百个零件、真实的工程数字,以及存在于绘图内部而非覆盖其上的着色器。
一台劳斯莱斯 Trent 970,A380 的发动机,悬挂在地面试车推力架上,其靠近观察者的上四分之一被剖开。拖动操纵杆,风扇、中压和高压转子以各自的速度旋转起来。风扇每秒吞入 1.2 吨空气,其中大部分作为冷涵道射流排出,其余在燃烧室中燃烧,测力传感器显示推力从 14 攀升到 334 kN。按空格键进行起飞滑跑。5审计测量了 541 个实体中 6,320 对重叠对,发现每一对都按正确顺序绘制。
Raptor 2,SpaceX 的全流量分级燃烧发动机,悬挂在试车台上。它是这门技艺自身的示例之一,也是密集管路的参考。悬停它,它会拆解成十一个组件,从万向架到喷管;按 I 点火。每一滴氧气都经过一个富氧预燃室驱动氧气泵,每一滴甲烷都经过一个富燃预燃室驱动甲烷泵,两股热气在主燃烧室中以 300 bar 相遇。6羽流、激波、飞溅和水蒸气是 WebGL,绘制在背面和正面 SVG 之间,因此试车台从火焰前方经过。
第一个可运行的版本花了 38 分钟。把它做对又花了十个小时,现在一次审计证明没有任何管路穿过任何东西,无论是在静止状态、拆解状态,还是其间的每一帧。
大多数图形是纯 SVG。当一个想法需要火、水、等离子体或光时,Claude 会添加以同一等距相机绘制的 WebGL 着色器,因此火焰位于绘图内部而非覆盖其上。少数图形更进一步,在真正的 3D 中旋转。
SVG。 手表仅用 SVG:四个音调按朝向区分,以及一个画家顺序,在其桥板拆开时每一帧都重新求解。它只重绘移动的部分。
WebGL。 涡扇添加了一个画布,用于进气条纹、涵道风、燃烧室火焰、涡轮辉光和排气。每个值都遵循一条包络线,因此没有任何跳变,读数也从不与画面矛盾。
3D。 Seasons 在真正的 3D 中旋转 26 个零件,每一帧重新投影,并用两个画布表现灯光。其读数来自 Almanac 的太阳公式:在北纬 50°,六月白昼持续 16 小时 22 分,十二月为 8 小时 04 分。73D 仍处于测试阶段。一个小的旋转图形以 60 fps 运行;一个密集的 380 零件测试手大约以 20 fps 运行。
细节需要时间,我宁愿展示真实数字而不是猜测。这些是 Claude 从第一个提示到最终成品图的活跃时间,包含评审轮次,不含空闲间隔。
| Watch movement | 1 小时 54 分钟 | 一遍完成,由同一个 agent 检查并修复。 |
|---|---|---|
| Seasons | 1 小时 57 分钟 | 与手表同时构建,包含 3D 审查。 |
| Raptor engine | 10 小时 33 分钟 | 38 分钟内完成第一个可用版本。 |
| Turbofan | 14 小时 | 首次构建用时 4 小时 41 分钟,之后经过五轮评审和修复。 |
整个系列都遵循这个规律。能运行的第一个版本很快就出来了。大部分时间花在第二遍审视上,以四倍的尺寸,去发现那些缺陷:穿过管道的线缆、分步着色的喷嘴、在切割处折成细条的叶片。
系列中的每个图形也是一个 React 组件,实时可用,可主题化,精细到其最后一条线的颜色。
npm install anatomy-figures
page.tsx
import { Watch } from "anatomy-figures"; export default function Page() { return <Watch theme="light" />; }
每个图形都是独立入口,因此导入一个不会连带引入其他图形:
import Turbofan from "anatomy-figures/turbofan";
随附五种主题:dark、light、paper、blueprint 和 sepia。将其中一个作为 theme 传入,用 AnatomyTheme 为整棵树设置一个主题,或传入你自己的 --anatomy-* 令牌。本站上的图形是 light 主题,卡片颜色设为页面颜色。
page.tsx
import { AnatomyTheme, Turbofan } from "anatomy-figures"; <AnatomyTheme theme="paper"> <Turbofan /> </AnatomyTheme> <Turbofan theme={{ base: "light", "--anatomy-card": "#fafafa" }} />
每一个令牌。图形中的每个填充、线条和标签都读取这 26 个变量之一。在 tokens 中传入其中任意一个,或在主题对象中传入。它们设置在图形本身上,因此会覆盖来自外部的 CSS。
page.tsx
<Watch theme="light" tokens={{ "--anatomy-card": "#ffffff", "--anatomy-lit": "#e5484d", "--anatomy-weight": "0.8px", }} />
| Light | Dark | 令牌 |
|---|---|---|
| 表面 | ||
--anatomy-card图形背后的卡片。 | ||
--anatomy-paper每个实体下方的填充。保持与卡片一致。 | ||
--anatomy-top每个实体的顶面。 | ||
--anatomy-shade-0背向光源最远的侧面。 | ||
--anatomy-shade-1略微朝向光源的侧面。 | ||
--anatomy-shade-2大部分朝向光源的侧面。 | ||
--anatomy-shade-3正对光源的侧面。 | ||
--anatomy-face唯一受光部件的主体。 | ||
--anatomy-lit-top受光部件的顶部。 | ||
--anatomy-lit-shade受光部件的侧面。 | ||
| 线条 | ||
--anatomy-hi最强的线条:主体的轮廓。 | ||
--anatomy-mid结构、主刻度和雕刻标签。 | ||
--anatomy-lo底座、支脚和次要线条。默认线条。 | ||
--anatomy-faint凹槽和最淡的辅助线。 | ||
--anatomy-dot点阵网格和螺丝头。 | ||
--anatomy-halo底座下方和抬起部件下方的柔和阴影。 | ||
| 强调色与颜色 | ||
--anatomy-lit唯一的强调色:读者应该关注的部分。 | ||
--anatomy-red红色,仅用于颜色本身是主题的地方。 | ||
--anatomy-green绿色,同样如此。 | ||
--anatomy-blue蓝色,同样如此。 | ||
| 文字 | ||
--anatomy-text图形编号和卡片角落的实时读数。 | ||
--anatomy-muted角落的标题和提示。 | ||
--anatomy-strong图形绘制的最亮文字。 | ||
| 形状 | ||
| 0.6px | 0.6px | --anatomy-weight每条线的宽度。 |
| 0.32 | 0.9 | --anatomy-halo-opacity柔和阴影的深浅程度。 |
| ui-monospace | ui-monospace | --anatomy-mono角落和雕刻标签的字体。 |
不使用 React 时,每个图形也是一个自定义元素:
index.html
import { define } from "anatomy-figures/element/turbofan"; define(); <anatomy-turbofan theme="dark"></anatomy-turbofan>
用一条命令将技能添加到 Claude Code:
npx skills add wheresryan22/anatomy
或者下载该技能并解压到你的 skills 文件夹:
unzip anatomy.zip -d ~/.claude/skills
然后在你的项目中打开 Claude Code,请求任何能用的东西。说出想法,而不是画法。8该技能附带六个完整示例,从约 300 行的表盘量规到 Raptor engine,Claude 在开始前会打开最接近的那个。
Claude 非常擅长构建这些,但并不总是擅长看出它们的问题。它会针对一个数字上成立的图形进行优化,而一个部件可能每个数字都对,看起来却仍然不对。最重要的修正来自观看一个图形运转,并描述哪里感觉不对。
它做得好的时候很慢。这项技能要求每个图形至少四十个部件,并且不会自行为了速度而牺牲细节。如果你需要快速完成,请说明,并预期得到一个 Figure 而不是 Hero。
3D 是测试版。它一次只转动一个主体,而对一个转动图形进行完整审查需要十五到二十分钟,所以只有当某个部件确实需要在深度上移动时才值得要求它。
参考图用于营造氛围。给它一张照片,它会取用其质感,而不是其物体。忠实复制别人的画作并不是它的用途。
所以把第一个图形当作草稿。把玩它,注意哪里不对,说出来,然后再次要求。 我是如何构建它的 展示了这项技能本身的这个循环是什么样子。
它需要 React 吗?
不需要。这项技能编写无框架的 TypeScript,为任何页面输出 SVG 和 HTML,或者为 React 或 Next.js 站点输出 React 组件。集合中的每个图形也是一个自定义元素,你可以将其放入纯 HTML 中。
图形制作完成后我可以修改它吗?
可以。图形是你项目中的普通代码。要求 Claude 进行更改,或者自己编辑模型:部件、读数显示和运动都读取同一个模型,所以更改一个数字会带动所有内容随之改变。
它会让我的页面变慢吗?
图形在滚出屏幕时会停止,并且只重绘移动的部分。着色器仅在其效果处于活动且可见时渲染,设备像素比上限为 1.5,并且在减少动态效果模式下只绘制一帧静止画面。
它是否可访问?
每个图形都接受键盘焦点,并响应按键和指针。它的读数显示在变化时会被朗读给屏幕阅读器,并且在减少动态效果模式下会静止,同时仍然响应输入。
浅色还是深色?
两者皆可。无框架图形可在任一主题下构建,React 组件自带五种主题,或者采用你自己的颜色令牌。
我怎样才能获得最佳结果?
说出想法,添加你在意的真实数字,并在需要时使用那三个词。然后把玩第一个图形,说出哪里感觉不对,然后再次要求。大部分质量来自第二次审视。
许可证是什么?
MIT,适用于这项技能和这些图形。
- 1一小时五十四分钟的活跃时间,一次构建完成,并由同一个智能体检查。
- 2机器从不从参考图片复制。参考图可以提供质感、材料和氛围;物体是虚构的。
- 3在请求匹配之前,Claude 只看到技能的名称及其描述。它只在需要时才读取其余内容。
- 4无论规模大小,第一个小时内浏览器中都会有一个可运行的页面。其余时间用于深化它。
- 5该审查测量了 541 个实体之间的 6,320 对重叠,并发现每一对都按正确顺序绘制。
- 6羽流、冲击、飞溅和蒸汽是 WebGL,绘制在后置和前置 SVG 之间,因此支架会从火焰前方经过。
- 73D 仍是测试版。一个小型转动图形以 60 fps 运行;一个密集的 380 部件测试手大约以 20 运行。
- 8该技能附带六个完整示例,从约 300 行的千分表到 Raptor 发动机,Claude 在开始前会打开最接近的一个。
来源:Hacker News · skills.wheresryan.sh