关于 machine
machine 是用于制作机器交互式 3D 展示和影片的技能,面向希望呈现真实结构与运行原理的创作者。它以单行描述为起点,要求使用真实尺寸、实体部件和计算得出的物理数据,并输出独立 HTML 页面及影片。
主要功能
- 01生成自包含的 three.js 页面
- 02按真实尺寸构建实体部件
- 03呈现剖切、爆炸与透视模式
- 04用方程计算显示数据与运动
- 05制作标准时长的机器影片
适用场景
- 01制作涡扇发动机的交互式展示
- 02展示机器内部结构和部件装配
- 03演示滑块输入对运行状态的影响
- 04呈现故障及其计算结果
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ airsuphq/ machine-skill --skill machine安装后在 Claude Code 中输入/machine确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
README.mdLICENSECHANGELOG.md.gitignoreCONTRIBUTING.mdLAUNCH.mdV2-IDEAS.mdpackage.json.github/REPO.mdevals/evals.jsonexamples/compressor.htmlrocket-engine.htmlturbofan.htmlrefinery-pump.htmlfilm/README.mdreply.htmllaunch.htmlkit/template.htmllab-kit.jsreferences/solvers.mdscripts/inline.mjsshot.mjsrecord.mjspinkscan.mjsscripts/lib/browser.mjsguard.mjsserve.mjspng.mjs详细介绍
机器技能
像产品工作室拍摄机器、工程师讲解机器那样,打造一台机器:以真实尺寸、真实材料呈现真实设备,置于整洁的摄影棚布景中,并由真实方程驱动。输入一行命令,输出一个 HTML 文件,并通过一条命令制作影片。
输出始终包括:
<name>.html:一个独立页面(使用 jsDelivr 上的 three.js 0.170,工具包内嵌其中)。它可直接从磁盘打开,也可通过任意静态主机或在 iframe 中打开。- 一部影片:
node scripts/record.mjs <name>.html out/<name>.mp4 --music freepd:<Category>/<Name>。
先打开 examples/。每个示例都是根据页面顶部那一行内容制作的。examples/turbofan.html 是参考范例:动手写之前,先从头到尾读一遍。
标准
开始之前,先想象观众三秒后看到的画面。它一开始就必须像真实机器的摄影棚产品照:轮廓和比例正确,金属看起来像金属,纸面地板上有柔和的阴影,没有悬浮、穿插或占位内容。随后机器开始运动,屏幕上的每个数值都由计算得出。
只要存在以下任一问题,结果就还没有完成:
- 缺少技师理应看到的部件(燃烧室里没有燃油喷嘴、手表里没有擒纵机构、发动机里没有气门)
- 有部件悬浮、相交,或接缝处有明显的缝线或间隙
- 材料看起来像塑料而非金属,或所有部件都是同一种灰色
- 屏幕上的数值是手动输入的,而不是由求解器计算得出
- 剖切视图显示的是中空壳体,而非实心剖面
- 影片的第一帧不够美观
工作流程
1. 研究真实机器(5 分钟,不写代码)
在机器脚本顶部的注释块中,根据已有知识(如有条件,也可查阅网络)写下:
- 真实尺寸:以米为单位,列出 5 到 10 个决定机器轮廓的部件(以涡扇发动机为例:风扇直径 2.85 m、长度 4.9 m、短舱最大直径 3.44 m)。
- 部件清单:按装配顺序列出,并标注每个部件的材料。目标是列出 15 到 40 个有名称的部件;重复部件(叶片、齿、螺栓、线圈)分别计数。
- 物理原理:用 3 到 6 个你会实际计算的方程,说明机器如何工作,并给出真实常数和运行工况(以涡扇发动机为例:布雷顿循环、起飞时 N1 100 %、OPR 42、T4 1,750 K、推力约 330 kN)。
- 一个关键数值:观众最关心的数值,例如推力、扭矩、每小时振次、流量或功率。用醒目的大号衬线字体显示,并配一条细长进度条。
- 输入项:观众希望调整的一个滑块,例如油门、风速、转速、泵速或研磨粒度。
- 故障情形:工程师担心的故障及求解器给出的后果,例如风扇叶片脱落及其不平衡载荷、气门在红线转速以上发生浮阀、泵失速或超压。后果必须是计算得出的,不能只是动画效果。
2. 根据模板构建页面
将 kit/template.html 复制为 <name>.html。模板包含导入映射(固定使用 [email protected])、字体、用于放置工具包的标记区块,以及需要填写的四个部分:
const { THREE, Lab, MAT, GEO, heatGlow, clamp, lerp, approach, fmt } = window.LabKit
const lab = new Lab({ prompt, no, title, sub, size, view, cut }) // 1. the lab
// 2. the parts lab.mesh(GEO..., MAT..., { name, pos, explode, xray, count })
// 3. the solver lab.hero(...); lab.slider(...); lab.onTick((dt, lab) => { ... lab.setHero(...) })
// 4. break, explain, film lab.breakIt(...); lab.how(...); lab.autoFilm(...); lab.start()
复制后立即运行 node <skill dir>/scripts/inline.mjs <name>.html:它会将工具包粘贴到标记区块中,让页面成为一个独立文件,无论文件存放在哪里都能使用(模板中的 src="../kit/lab-kit.js" 只有在此仓库中才能解析)。然后在第二个脚本区块中编写机器。
3. 几何体:真实尺寸的实体
以机器自身坐标系中的米为单位建模,Y 轴朝上,除非设置 ground,否则地面位于 y = 0。将 size 设为最长的实际尺寸;工具包会缩放显示效果,让布景中的每台机器大小一致,比例尺则显示实际尺寸。
- 圆形部件(轴、圆盘、外壳、喷嘴、圆锥、旋转件、活塞、装饰圈):使用带闭合轮廓的
GEO.lathe([[r, y], ...])。壁面:GEO.shell(profile, thickness);管件:GEO.tube(rOut, rIn, h);倒角圆盘:GEO.disc(r, h)。转角保持锐利,曲面会自动平滑着色。 - 叶片和导叶:
GEO.rotor({ count, axis, r0, r1, chord, thick, camber, twist, pitch, sweep })可构建带弯度和扭转的真实翼型(NACA 厚度),并将其制成闭合实体和环形排列。弦长、厚度和弯度使用[root, tip]数组。 - 齿轮:
GEO.gear({ teeth, module, width, bore, helix, spokes, rim })。两齿轮的中心距设为(z1 + z2) * module / 2,并按齿数比的倒数转动,错开半个齿距。 - 管道、软管、电线:
GEO.pipe(points, r)(闭合、带端盖)。沿结构从一个接口布设至另一个接口,切勿穿过部件。 - 紧固件:每个法兰上都加
GEO.bolts(n, R, size, h)。弹簧:GEO.spring(R, wire, turns, len)。箱体:GEO.rbox(w, h, d, r)(始终为圆角,不要做成尖角)。带孔板件:GEO.extrude(shape, depth)。 - 质量和惯量根据几何体计算:
GEO.volume(geo)可得体积和质心,再乘以实际密度。
保持模型整洁的规则:
- 每个部件都是闭合实体(闭合的车削轮廓、带厚度的壳体、带端盖的管道)。这样剖切时才能绘制实体剖面。剖切时,开放曲面会显示为中空。
- **部件之间不可有明显交叠或悬空。**每个部件都必须接触支撑它的结构(法兰贴合端面、轴穿过轴承、支柱延伸至地面)。请在特写中检查连接处。
- 在视觉焦点处添加细节:法兰上的螺栓孔圈、倒角、凸缘、铭牌、燃油管路、线束。大片平面区域应添加接缝、面板线或纹理饰面。
- 为机器添加底座:支架、托架、基座、工作台或带落地支脚的底座。现实中的机器很少悬浮。
- 预算:最多约 70 万个三角形和 200 个网格。使用
GEO.merge/GEO.ring合并重复的静态部件;移动部件组则保持独立。
4. 材质:不能只有一种灰色
使用 MAT.* 预设;这些预设采用实测反射率,让钢、钛、铝、黄铜和铜并排时呈现出不同质感。每个预设都支持覆盖参数(color、roughness、clearcoat 以及任何 MeshPhysicalMaterial 字段)和 finish(微观粗糙度纹理:车削部件上的 turned 环纹、brushed 刷痕、cast 铸造斑点、smudge 污痕、knurl 滚花)。
| 用途 | 预设 |
|---|---|
| 轴、圆盘、机加工部件 | MAT.steel、MAT.stainless、MAT.chrome |
| 外壳、铸件 | MAT.aluminium、MAT.castIron、MAT.steelDark |
| 叶片、航空航天部件 | MAT.titanium、MAT.inconel(加上 heatGlow) |
| 接头、布线 | MAT.brass、MAT.copper、MAT.gold |
| 喷漆机身 | MAT.paint({ color })、MAT.satin、MAT.anodised({ color }) |
| 聚合物 | MAT.plastic、MAT.rubber、MAT.carbon |
| 窗口、晶体 | MAT.glass、MAT.sapphire、MAT.ruby、MAT.enamel |
| 光、火焰、高温气体 | MAT.glow、heatGlow(material, kelvin) |
像工业设计师一样选择配色:以金属色为主,搭配一两种喷漆颜色,最多使用一种强调色。热部件根据求解器给出的温度发光(material.userData.heat.value = T)。
5. 求解器:只用真实数值
编写一个简单的纯函数,根据输入和状态计算你展示的每个数值,并使用真实单位和真实常数。用 approach(一阶滞后:加速、热惯性)或 rk4(弹簧、擒纵机构、摆)积分动力学。然后用它驱动运动:求解器算出的 rpm 带动轴旋转,算出的流量推动粒子,算出的温度加热金属。
- 一个主指标:每个刻度调用
lab.hero({ label, unit, max }),然后调用lab.setHero(value, { state, sub, bad })。state用两三个词描述(加速中、起飞、阻塞流)。sub用一行显示另外 2 或 3 个数值。 - 一个滑块:
lab.slider({ id, label, min, max, value, unit, ends })。只有机器确实需要时才添加第二个。 - 在剖切平面的点位,将标签固定在静止部件上:
lab.label(obj, 'HP turbine', { at: [x, y, z], value: () => '12,979 rpm' })。 lab.how(words, equations)填写“计算方式”:用通俗文字说明模型,并写出代码中的方程。说明做了哪些简化。- 如果某个运动快到看不清(例如转速为 2,700 rpm 的风扇),就放慢显示速度,并在
how中说明(“显示转速为原来的 1:60”)。绝不要放慢数值。 - 根据第 1 步记录的公开数据检查工作点。如果偏差超过约 20%,就修正模型,而不是修改数据。
6. 流动、热量和效果
lab.flow({ paths, count, length, color, parent }):沿着根据真实流路构建的路径生成流线(空气穿过风道、血液流经泵、水流过冰球)。根据求解器设置.speed,根据lab.state.cut设置.opacity,让流线显示在剖切视图中。根据计算出的量(温度、压力)设置颜色。lab.plume({ radius, length, dir, color: 'rocket' | 'jet', shocks }):生成带马赫菱形的排气流;根据求解器设置.power。- 出现断裂时,使用
lab.sparks.emit(worldPos, n, speed)和lab.shed(mesh, v, w):火花受重力下落并弹跳;脱落的部件会变成刚体并落到地面。
7. 模式(工具包会处理;你负责设置)
- 爆炸视图:每个
lab.add/lab.mesh都可以在父级坐标系中使用explode: [dx, dy, dz](单位:米)。沿装配轴移动部件;外壳移动最远,并让核心保持原位。部件在移出时不得相互穿过。 - 剖切视图:在 Lab 上设置
cut: { a, b, center, reach }。a和b表示被移除区域的方向:a = [0,0,1], b = [0,1,0]会移除朝向观察者且位于上方的四分之一部分(最适合带轴的物体);b = a会移除一半。系统会自动为每个封闭实体绘制剖切面,并加上浅色剖面线。 - X 光视图:在外壳上设置
xray: 'shell',使其呈现玻璃质感并带有精细边缘,让运行中的核心显现出来。 - 慢动作、标签、暂停开箱即用(按键 S、L、Space)。交互方式包括鼠标旋转视角、滑块和按钮。
- 使其故障:使用
lab.breakIt({ label, run(lab), reset(lab) })。run会改变求解器状态(叶片脱落、阀门卡住、密封失效),由求解器计算后果。通过主指标(bad: true)以及火花、碎片或震动来展示故障。
8. 像评论家一样审视作品(必做)
渲染并仔细查看你制作的每张图片。使用以下脚本:
node scripts/shot.mjs <name>.html out/review.png # the first look
node scripts/shot.mjs <name>.html out/cut.png --js "lab.toggle('cut', true); lab.toggle('labels', true)"
node scripts/shot.mjs <name>.html out/near.png --js "lab.setView({ az: 70, el: 8, dist: 0.8, target: [x, y, z] })"
node scripts/shot.mjs <name>.html out/film --film 1,4,8,12,17,22,26 # film stills
至少进行四轮审查。每轮都要查看整体视图、带标签的剖切视图、爆炸视图、两张关节特写以及影片静帧。对照你记忆中的真实产品照片,检查比例、部件数量、材质和光线效果。列出所有问题,修复后再次渲染。只有问题清单为空时才能停止。截图脚本会输出 fps、部件数和三角形数;交互帧率必须高于 30。
9. 影片
lab.autoFilm({ runBeat, runSub, breakBeat, breakSub, sliderTo }) 会在你的机器上生成标准的 28 秒故事片,分为编号镜头,并配有以下编辑说明:
- 一句话就是全部任务说明(提示词栏会自动输入)。
- Claude 构建机器(部件按组装顺序飞入,同时计数器递增:“84 of 3,597 parts”)。
- 机器运行(光标拖动滑块;主数值根据求解器结果递增)。
- 剖开机器(剖切端盖、带实时数值的标签)。
- 拆解机器(爆炸视图)。
- 让机器故障(光标点击故障按钮;求解器决定故障点)。
影片会循环播放:最后一个摄像机关键帧会回到第一个关键帧。要制作自定义影片,请使用 lab.film('name', { len, assemble, shots, events }):镜头为摄像机关键帧 { t, az, el, dist, target, fov },事件为 { t, beat: ['07', 'Bold sentence.', 'Grey sentence.'], set: { cut: 1 }, slider: { id, to, dur }, cursor: { to: 'slider:id:0.8' | 'button:break' | [x, y], click: true }, do(lab) {} }。
录制(需要 Node 18+、带 Chromium 的 Playwright、ffmpeg):
node scripts/record.mjs <name>.html out/<name>.mp4 --music freepd:Classical/Easy_Lemon
node scripts/record.mjs <name>.html out/<name>-portrait.mp4 --w 1080 --h 1350
页面以影片模式运行(?film=1):只有录制器推进时钟,页面才会向前运行,因此每一帧都是完整的,每次录制的影片也完全相同。录制器会检查每张截图,防止停滞的无头 GPU 返回洋红色画面,并扫描成片;如果任何一帧呈粉色,程序就会以非零状态退出。配乐来自 FreePD,采用 CC0 许可;仍请注明曲目来源。
屏幕文案
页面是编辑呈现,不是仪表盘:提示词栏、衬线字体标题和斜体副标题、一个醒目的大数字(带斜体单位和细条)、一行辅助数字、一个滑块。文案要像出色的说明文字:简短、具体、不夸张,使用真实单位,单位前留空格(338 kN、1,750 K、4.2 L/min),千位之间加分隔符。镜头说明由一句粗体句子和一句灰色句子组成。
交付时要说明的内容
提供 HTML 文件的路径、影片命令、求解器达到的工作点与公开数据的对比,以及你做过的简化。并提出下一台机器。