Community编程与开发github.com

bugeng777/teardown

构建一个真实机器或机构的交互式3D模拟器(如发动机、起落架、行走连杆、泵、齿轮箱),生成单个离线HTML页面,用户可拆解部件。页面包含由同一模型驱动的实时面板、每个子系统的按钮、剖视图、摄像机视角以及自动导览(自动将控制权交给访客)。支持逐帧录制为60fps视频并同步生成程序化配乐。适用于有人询问机器工作原理、需要“可视化讲解器”、“模拟器”、“剖视图”、“爆炸视图”或“交互式3D课程”时,或希望展示3D物体如何工作而非仅用文字描述。

teardown 是什么?

Teardown 是一个专为开发者设计的 AI 技能,用于创建单个离线 HTML 页面中的交互式 3D 机器模拟器。它允许用户拆解和探索真实机械装置的内部工作原理,如发动机、起落架或行走机构。该技能的核心优势在于其“纯粹函数式”设计:所有运动、仪表读数和 UI 元素都由同一个单一输入(如曲轴角度、行程或风力)驱动,确保模拟、记录和配乐之间的完美同步。它支持在 Cursor、Claude Code 和其他 AI 代理平台中运行,并提供了一套完整的工具链,用于构建模拟、生成 60 fps 视频和程序化配乐。技能附带了三个现实世界的示例(V8 发动机、Cessna 起落架和 Strandbeest 行走机构),为构建新机器提供了经过验证的架构和可复用的组件。最终输出是一个完全自包含的 HTML 文件,可通过点击、拖拽和键盘控制实时交互,并自动播放解说导览。

兼容平台✓Claude Code~Codex CLI✓Cursor
npx skills add bugeng777/teardown-cursor

Installed? Explore more 编程与开发 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

teardown 是做什么的?

一台机器,一个页面。访客看到机器运行,按下按钮,执行工作的部件便会展开,同时周围仪表显示真实数据。若无人操作,页面会通过光标自动导览。同一段代码会逐帧录制导览的影片,并使用同一时间轴生成配乐。

下面的 SKILL_DIR 指的是该文件所在的文件夹(对于 Cursor 安装,通常是 ~/.cursor/skills/teardown、~/.agents/skills/teardown 或项目内的 .cursor/skills/teardown)。构建和渲染结果将输出到您运行命令的文件夹下的 ./teardown-out 目录。

首次运行

cd "$SKILL_DIR" && npm install && npx playwright install chromium

页面不需要其他依赖。视频录制需要 ffmpeg 在 PATH 环境变量中,配乐生成需要 Python 3(仅使用标准库)。您可以通过设置 FFMPEG、PYTHON 或 CHROMIUM 环境变量来指定其他二进制文件路径。

3个示例

构建一个,打开HTML,按下按钮。开始新机器时,从最接近的示例复制代码。

机器驱动方式值得借鉴的部分
v8-*带玻璃缸套的十字曲轴V8发动机:您追踪的汽缸内燃烧过程清晰可见,气门在凸轮上抬起,8个活塞通过精确的曲柄滑块机构运动。曲轴角度。点火顺序1-8-4-3-6-5-7-2,以及用于示功图的缸压模型。剖切模式(玻璃、截面、实体),点火顺序作为气缸选择器,与曲轴同步的实时图表。
cessna-*Cessna 337飞机的主起落架,在起飞时收进机身,降落时放下。行程0..1:一个201毫米的齿条驱动一个32齿的齿轮(模数4毫米),精确旋转180°。一个自由度驱动整个机构,飞行阶段作为时间的函数,在模型下方滚动的跑道。
strandbeest-*Theo Jansen的Strandbeest,一个曲轴上连接20条腿,在沙地上横向行走。风力。曲轴速度由风力积分得出;每个关节通过Jansen的11个连杆长度的圆交点计算得出。一个仅67行的精确连杆求解器,实例化管道,脚部轨迹,所有20只脚的接触图表。

每个示例包含3个文件夹:<name>-shared/ 存放机器,<name>-film/ 存放录制的导览,<name>-live/ 存放可驱动的页面。

node "$SKILL_DIR/sims/build.mjs" v8-live          # → teardown-out/dist/v8-live.html,离线,约800 KB
node "$SKILL_DIR/sims/build.mjs"                  # 构建全部6个

如何构建一台机器

每个机器一个文件夹,按职责拆分。示例严格遵循以下结构:

文件职责
kin.js / gear.js / jansen.js数学计算。使用真实单位和真实尺寸,一个输入(曲轴角度、行程、风力),所有姿态和读数都作为该输入的函数。这里没有 three.js 代码。
engine.js / gear.js / beast.js几何体,通过代码构建:车削部件、管道、实例化连杆。update(input) 方法用于更新姿态。
stage.js场景、灯光、阴影、后期处理(GTAO、泛光)。frame(state, cam) 方法绘制一帧。
console.js叠加层:固定的 1600 x 900 CSS 布局,包含面板、图表、开关、带引出线的标注。update(state) 方法根据当前帧的状态重新绘制。
film.js一个操作者动作的剧本(视角切换、隔离部件、剖切、油门控制)以及 render(t) 作为时间的纯函数。
live.js同一机器的实时交互版本:按钮、滑块、轨道控制、缩放、键盘。若无输入,则播放 film.js 的剧本作为带有光标的自动导览;任何点击、拖拽、滚轮或按键操作都会接管控制权,静默25秒后交回控制权。
score.py影片时间轴上的配乐。

对于 SKILL_DIR 之外的机器,创建一个包含 main.js 的文件夹,并通过名称导入工具包:import {runSim} from 'teardown-kit/runtime.js'。使用命令构建:node "$SKILL_DIR/sims/build.mjs" ./my-machine。

决定成败的规则

  1. 从参考开始,而非凭空想象。 一张照片、一张手册里的剖视图、一段真实机器的视频片段。以此为参考进行构建并逐帧对比。凭空想象出来的机器总是显得千篇一律;而拥有对照物的模型则可以精确地重建真实机器。
  2. 使用真实数字,单一来源。 首先获取真实尺寸(缸径、行程、齿数、连杆长度)。每个仪表、图表和标签都读取与驱动部件姿态相同的函数,因此屏幕上没有任何内容会与运动相矛盾。手动验证一个:在 Cessna 示例中,32齿 × 4毫米模数 = 128毫米节圆直径,其半周长即为201毫米的行程。
  3. 单一输入驱动一切。 根据曲轴角度、行程或风力进行姿态调整。没有任何手动关键帧,因此影片、实时页面和配乐永远不会漂移不同步。
  4. 执行工作的部件应当展开。 隔离它、剖切它、透视它。一个能进入内部的摄像机镜头胜过十个外部轨道镜头。
  5. 灯光工作室,一种强调色。 浅色背景在信息流中更易阅读;深色背景会丢失最初几秒的注意力。强调色用于标记正在变化的部分。注意浅色背景上的近白色零件:为其添加墨线轮廓或更暗的地面。
  6. 根据机构选择摄像机角度。 正视视角下,平面连杆机构会折叠成网状;一个沿其脊柱的3/4视角则能让每条腿都清晰可辨。
  7. 用数字修复碰撞。 当一个零件穿透另一个零件时,在参数块中缩放或移动它。切勿用摄像机视角来隐藏它。

实时页面规则

  • 在集成显卡上测试。 在台式机显卡上能以60fps运行的页面,在笔记本电脑的内置显卡上可能降至15fps。示例中设置了质量等级(live.js中的 TIERS):禁用环境光遮蔽、降低像素比、使用更小的阴影贴图、隔帧重绘面板。首先找到最耗性能的着色器:一个每个顶点计算5次的置换位移,比所有质量等级加起来都更耗费性能。
  • 预热着色器。 kit/warm.js 在第一帧渲染前并行编译所有程序,确保页面在首次绘制时不会卡顿。
  • 保持页面小于1 MB。 链接爬虫(如X、Slack)会从HTML中读取分享卡片,对于一个15MB的页面会选择放弃。大型模型应作为独立文件放在页面旁边:build.json → {"external": {"heavy.glb": "light.glb"}}。

render(t) 契约

import {runSim} from '../kit/runtime.js';

const DEFAULTS = {duration: 20, fps: 60, hud: {enabled: false}, director: {enabled: false}};

runSim(DEFAULTS, async ({cfg, canvas, capture}) => {
  // 构建场景,预计算任何有状态的内容
  return {render(t) { /* 从头绘制第t帧 */ return {}; }, resize() {}};
});
  • render(t) 是纯函数:没有 Math.random(在设置时使用 kit/util.js 中的 rng(seed)),没有 Date,帧之间不携带状态。捕获系统会在任意时间点调用它。
  • 任何按自身规则运动的对象(智能体、粒子)在加载时被模拟到类型化数组中;render 只读取它们。随时间积分变化的量(如Strandbeest在变化风力下的曲轴)以闭合形式积分或在加载时制成表格。
  • 每个节拍都写入 <name>-film/timeline.json,单位是秒。配乐读取相同的文件。
  • 第0帧是缩略图。它必须已经展示出机器。

命令

node "$SKILL_DIR/sims/build.mjs" v8-film
node "$SKILL_DIR/sims/capture.mjs" v8-film --size 1600x900 --dpr 1.2 --stills beats --cols 4 --out teardown-out/v8-beats.png
node "$SKILL_DIR/sims/capture.mjs" v8-film --size 1600x900 --dpr 1.2 --still 12.5 --out teardown-out/v8-12.5.png
node "$SKILL_DIR/sims/capture.mjs" v8-film --size 1600x900 --dpr 1.2 --out teardown-out/v8-silent.mp4
python "$SKILL_DIR/run_sfx.py" "$SKILL_DIR/sims/v8-shared/score.py"
ffmpeg -y -i teardown-out/v8-silent.mp4 -i teardown-out/v8-score.wav -map 0:v -map 1:a -c:v copy -c:a aac -b:a 256k -shortest -movflags +faststart teardown-out/v8.mp4
node "$SKILL_DIR/wave.mjs" teardown-out/v8.mp4 --timeline "$SKILL_DIR/sims/v8-film/timeline.json"

--size 是CSS布局尺寸,--dpr 是倍率:1600 x 900 在 1.2 dpr 下输出 1920 x 1080。捕获时会打印所使用的GPU;如果显示为软件渲染器,则表明 paths.mjs 中的GPU标志未生效。

审查循环

您无法观看视频,但可以查看帧。切勿在未检查当前渲染的多帧图之前就报告机器已完成。

  1. --stills beats:每个时间轴节拍生成一张平铺图,节拍后0.3秒,每张标注 t=。
  2. 对照下面的检查清单逐一检查每张图。
  3. 放大查看:--stills every:0.2 --from A --to B 用于检查过渡动画,--still T 用于查看一整帧。
  4. 修复,重建,返回步骤1。当完整一轮检查未发现任何问题时停止。
  5. 最终检查:node "$SKILL_DIR/sheet.mjs" --video <final.mp4> --timeline <timeline.json>,并再次审查该输出:它能显示编码器实际写入了什么。

检查清单:

  • 机械机构。 每个应接触的部件都接触了;没有部件穿过其他部件;面板上的数字与姿态匹配。
  • 构图。 每帧一个焦点。没有重要内容距离边缘60像素以内。标签永远不会遮盖其命名的部件。
  • 文字。 无文字被裁剪。关键读数在手机宽度屏幕上也可辨认。
  • 3D。 泛光会吞噬细节:保持自发光层强度低于1.0。近白色表面容易过曝。弱光下的光泽金属会产生条纹:大面积表面的粗糙度应 ≥ 0.45,环境贴图强度 ≈ 0.5。
  • 节奏。 每个状态停留时间足够长以被阅读:短句1秒,超过三个单词后每多一个词增加0.25秒。

示例已踩过的 three.js 陷阱

  • smoothstep(a, b, x) 在 a > b 时,Windows系统(ANGLE/D3D)会返回0。请写成 1.0 - smoothstep(b, a, x)。
  • 离地面仅零点几毫米的 ShadowMaterial 或贴花,在后处理渲染目标内会丢失深度测试。请使用 polygonOffset。
  • 放置在地面上带有镜面映射的四边形,会被作为背面剔除。请使用 DoubleSide。
  • 一个NaN像素会通过泛光效应导致整帧变黑。请确保在着色器中钳制所有 pow() 函数的底数。
  • 对于被裁剪(剖切)的模型使用GTAO时,需要在 gtao.normalMaterial 上设置相同的裁剪平面,否则被切掉的部分会以浅色鬼影形式出现。

音效

sfx/ 文件夹使用纯Python(48kHz,可重现)合成所有声音,并读取影片的时间轴,确保音效与画面精确同步。python "$SKILL_DIR/run_sfx.py" --list 可列出可用的发生器。sample() 函数用于添加 sfx/samples/ 中的CC0录音。sfx/score_kit.py 包含三个配乐示例使用的基础音色和强调音:和弦背景、每个作功行程的柔和重击声、马达声、气流风声。

  • 所有时间点均来自时间轴,绝不手动输入数字。
  • 母带处理是自动的:响度 −14 LUFS,真实峰值 ≤ −2 dBFS。
  • 强调而非叙述:连续运动保持静音。每个音调声音只使用一个键。

品味,以数字量化

  • 缓动:进入动画 cubic-bezier(0.16, 1, 0.3, 1),退出动画 cubic-bezier(0.6, 0, 0.9, 0.35) 时长是进入动画的一半,状态切换 cubic-bezier(0.65, 0, 0.35, 1)。仅在连续运动中使用线性缓动。
  • 机器应占据视口的60-70%。在1080画布上,标签字体不小于34px。
  • 一种强调色,且必须具有意义:标记当前正在工作的部件。
  • 不能有任何元素是完全静止的:至少有一个元素始终处于运动状态。

致谢

Cursor 移植版由 bugeng777/teardown-cursor 基于 elvarofficial/teardown (MIT 许可证) 完成。工具包、帧捕获、音效引擎和审查规则来自 whaleyxbt/claude-motion (MIT 许可证)。录制的样本为 Freesound 上的 CC0 素材,由 Barty-Bart/motion-graphics (MIT 许可证)剪辑;来源见 sfx/samples/SOURCES.md。

相关技能