⚡

机械三维仿真Skill machine

将一句机器名称转化为照片级、基于物理的交互式 3D 机械仿真:生成单文件 HTML 页面和 20–30 秒发布短片,包含真实尺寸与比例、PBR 金属/涂装/聚合物/玻璃材质、工作室灯光与软阴影、由求解器驱动的运动部件和真实数值(推力、扭矩、转速、流量、压力、效率),并支持爆炸、剖切、X 光、慢放、标注和故障破坏模式。

场景建模 0 次安装 2 次浏览 更新于 10/28/2026
名称 machine
描述 将一句话(“涡扇喷气发动机”“机械手表”“LVAD 心室辅助血泵”)转化为照片级、基于物理的交互式 3D 机械仿真,输出为单个 HTML 文件,并生成 20 到 30 秒的短片用于发布。真实比例以米为单位,真实材质(PBR 金属、涂料、聚合物、玻璃),带软阴影的工作室灯光,由小型求解器驱动的运动部件并计算真实数值(推力、扭矩、转速、流量、压力、效率),以及爆炸、干净截面封盖的剖切、X 光、慢放、标注和破坏等模式。只要有人要求构建、模拟、可视化、解释或“展示 X 如何工作”,对象是任何机器、发动机、机构、设备、仪器或硬件,或想要交互式 3D 模型或剖视图,或想要用于发布的机器视频,即使他们从未说出“仿真”或“three.js”,都应使用此技能。

机械技能

你构建机器的方式,就像产品摄影工作室拍摄机器、工程师讲解机器一样:真实物体、真实尺寸、真实材质、干净的摄影棚布景,并运行真实方程。一句话输入,输出一个 HTML 文件,一条命令生成短片。

输出始终为:

  1. <name>.html:一个自包含页面(来自 jsDelivr 的 three.js 0.170,工具包已内联)。它可以从磁盘、任意静态托管或 iframe 中打开。
  2. 一段短片: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。它包含 import map(固定 three@0.170.0)、字体、一个用于放置工具包的标记块,以及你要填写的四个部分:

const { THREE, Lab, MAT, GEO, heatGlow, clamp, lerp, approach, fmt } = window.LabKit
const lab = new Lab({ prompt, no, title, sub, size, view, cut })   // 1. 实验室
// 2. 零件      lab.mesh(GEO..., MAT..., { name, pos, explode, xray, count })
// 3. 求解器     lab.hero(...); lab.slider(...); lab.onTick((dt, lab) => { ... lab.setHero(...) })
// 4. 破坏、解释、短片      lab.breakIt(...); lab.how(...); lab.autoFilm(...); lab.start()

复制后立即运行 node <skill dir>/scripts/inline.mjs <name>.html:它会把工具包粘贴到标记块中,使页面无论位于何处都是单个自包含文件(模板中的 src="../kit/lab-kit.js" 只在此仓库内可解析)。然后在第二个 script 块中编写你的机器。

3. 几何:真实尺寸的真实实体

在机器自身坐标系中以米为单位工作,Y 向上,除非设置 ground,否则地板位于 y = 0。将 size 设为最长真实尺寸;工具包会缩放显示,使每台机器在布景上占据相同大小,比例尺显示真实尺寸。

  • 圆形零件(轴、盘、壳体、喷嘴、锥体、整流锥、活塞、表圈):使用 CLOSED 轮廓的 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) 给出体积和质心,乘以真实密度。

保持干净的规则:

  • 每个零件都是闭合实体(lathe 轮廓闭合,壳体有厚度,管道带端盖)。这正是剖切能绘制实心截面的原因。开放表面在剖切时会显示为空心。
  • 没有明显相交,没有悬浮。 每个零件都与其支撑物接触(法兰坐在面上,轴在轴承中运行,支柱到达地板)。在特写中检查连接处。
  • 把细节放在视线所及处:法兰上的螺栓圈、倒角、唇边、铭牌、燃油管、线束。大平面要有接缝、分模线或纹理饰面。
  • 给机器一个底座:支架、托架、基座、工作台或安装座,脚落在地板上。机器在现实中很少悬浮。
  • 预算:最多约 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 }),然后每 tick 调用 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                               # 第一眼
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                 # 短片静帧

至少进行四轮审查。每轮中:整体视图、带标签的剖切、爆炸视图、两个连接处特写,以及短片静帧。与你记忆中该机器的真实产品摄影比较:比例、零件数量、材质、光线如何落在其上。列出问题,修正,再次渲染。只有当列表为空时才停止。shot 脚本会打印 fps、零件数和三角形数;保持交互帧率高于 30。

9. 短片

lab.autoFilm({ runBeat, runSub, breakBeat, breakSub, sliderTo }) 根据你的机器编写标准的 28 秒故事,以编号节拍和编辑字幕呈现:

  1. 一句话就是整个简报(提示条自行输入)。
  2. Claude 构建机器(零件按装配顺序飞入,计数器攀升:“84 / 3,597 个零件”)。
  3. 它运行(光标拖动滑块;主角数字由求解器攀升)。
  4. 剖开它(截面封盖、带实时数值的标签)。
  5. 拆开它(爆炸)。
  6. 破坏它(光标点击破坏按钮;求解器决定什么失效)。

它会循环:最后一个相机关键帧返回第一个。对于自定义短片,使用 lab.film('name', { len, assemble, shots, events }):shots 是相机关键帧 { t, az, el, dist, target, fov },events 是 { 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 文件的路径、短片命令、求解器达到的工作点与公开数据的对比,以及你简化了什么。提供下一台机器。