teardown为何是技能范本——亲手运行验证
機械翻訳 / Machine-translated

機械翻訳 / Machine-translated
原文:teardown为何是技能范本——亲手运行验证(cccskills)
技能页面:teardown
本文结论
teardown 是一个技能,能将真实存在的机械组装成可拆解的 3D 模拟器,以单个 HTML 文件呈现,并可导出视频与音频。
cccskills 将其选为技能编写范本"推荐"栏目的第一篇。
本文列举三条将其称为范本的理由,并报告本地运行结果及常规运行验证的结果。
teardown 是一个将真实机械组装为"可拆解 3D 模拟器"的技能,输出为单个 HTML 文件。
发动机、飞机起落架、行走机构等,均可通过按钮逐件展开或切换截面视图并实时运动。
周围的仪表和图表所显示的数字,来自与驱动部件运动的完全相同的计算。
无人操作时,页面会自动移动光标,引导观看者欣赏重点画面。
点击或拖拽后,操控权转移到观看者手中;若 25 秒内无任何操作,则自动恢复引导模式。
页面可依据同一脚本逐帧导出 60fps 视频,并按相同时间轴生成音频。
cccskills 将此技能选为"cccskills 推荐"的第一篇。
原因不在于吸引眼球的外观,而在于内部的编写方式。
以下依次说明将其称为范本的理由及本地验证结果。
teardown 的核心规则是"先收集实际尺寸数字,用一个输入驱动所有内容"。
发动机用曲轴转角,飞机起落架用 0 到 1 的伸缩量,Strandbeest 用风速作为输入。
部件姿态、面板数字和图表,均作为该输入的函数进行计算。
这样从原理上就不会出现画面数字与动作相互矛盾的情况。
无需手动打关键帧,因此可交互页面、录制视频与音频之间也不会出现偏差。
SKILL.md 中甚至给出了验算示例:
在 Cessna 的示例中,32 齿 × 模数 4mm,节圆直径为 128mm。
其半周长即为 201mm 的行程。
本地计算结果:π × 128 ÷ 2 = 201.06mm。
代码中的常数同样为 pinionR: 0.064(32 齿,模数 4mm)和 stroke: 0.201,文档与实现一致。
Strandbeest 示例中包含了 Theo Jansen 的 13 个原始尺寸(从 a=38 到 m=15)。
将曲柄旋转 720 帧并重新测量各连杆长度,误差最大不超过 1e-14。
足尖的上下幅度为 22.5,距地面 1 单位以内的区间为曲柄 155° 范围,与代码注释"约 155°"一致。
技能中包含完整的三个示例:V8 发动机、Cessna 337 主起落架和 Strandbeest。
三者均遵循相同的结构编写,规定新机械从最相近的示例复制后开始编写。
| 文件 | 作用 |
|---|---|
| kin.js 等 | 仅负责计算。根据实际尺寸和单一输入,输出姿态与显示数字。不含 three.js |
| engine.js 等 | 负责形状。用代码创建部件,通过 update(input) 确定姿态 |
| console.js | 仪表与图表的叠加显示。根据帧状态重绘 |
| film.js | 脚本,以及仅凭时刻绘制单帧的 render(t) |
| live.js | 可交互页面。放置不管时会按脚本自动引导 |
| score.py | 与脚本时刻对应的音频 |
计算与渲染分离,因此可以单独用 Node 对计算部分进行验算。
render(t) 是仅凭时刻绘制单帧的纯函数,规定不使用随机数或时钟。
搜索拍摄用代码,Math.random 和 Date 一个都没有,performance.now 仅出现在实时交互用的 live.js 中。
SKILL.md 中写道:"你无法查看视频。
你能看到的只有单帧画面。"
在此基础上,规定为每个重点场景制作静止画面排列表,对照检查清单,修改后重新拍摄。
结束条件为"完整过一遍后不再发现任何问题"。
检查清单非常具体,涵盖应该可以触碰的部件是否可触、距边缘 60px 以内是否没有重要内容、在 1080 分辨率下文字是否不小于 34px 等项目。
此外还列出了 three.js 中容易导致画面崩坏的数值,例如发光强度须低于 1.0、大面积金属表面粗糙度须不低于 0.45 等。
另一个亮点是作者将自己实际踩过的坑保留了下来。
包括 Windows ANGLE 下 smoothstep 参数顺序颠倒会返回 0、NaN 出现在一个像素时 bloom 会导致整个画面变黑等,共 5 条,均附有原因说明。
在 Apple M2 Ultra 的 Mac 上,按照 README 步骤进行了测试。
Mac 上遇到了一个问题。
Playwright 默认使用的轻量版 Chromium 无法创建 WebGL,导致拍摄在 60 秒后停止。
将环境变量 CHROMIUM 指定为正式版 Chromium 后,通过 Metal 调用 GPU 完成了拍摄。
由于每次拍摄都会显示所用 GPU,原因很快便查明了。
SKILL.md 规定:"所有重点场景的时刻均写入 timeline.json,音频也读取同一文件。"
然而,三台机械的 timeline.json 中实际上只有视频时长。
生成 V8 音频的 score.py 将脚本时刻手动写成了 CLICKS = (3.5, 6.9, …) 的形式。
目前数值一致,音频没有偏差。
但一旦修改脚本时刻,音频就会被落下。
用于截取各重点场景静止画面的 --stills beats,以及用于最终确认的 sheet.mjs,由于缺少重点场景时刻,均只能输出 1 帧或 0 帧。
本次验证是从脚本中手动提取时刻并直接指定,才得以继续确认工作。
既然作为范本推荐,这个漏洞也应如实说明。
将其引入自己的技能时,请不仅核查规则本身,还要确认示例是否真正遵守了规则。
cccskills 的运行验证方式是:将相同任务分别交给"无技能"和"有技能"的 Claude Code 求解,再进行比较。
验证用的沙盒环境中只有 Node.js 和 Python 标准库,不能添加软件包,也不能访问互联网。
teardown 所依赖的 three.js、esbuild、Playwright、ffmpeg 在该环境中均无法运行。
在此条件下自动生成的题目为以下两道:
将这两道题分别对"无技能"和"有技能"各运行一次。
由于答题者设定为无法查看画面,生成的页面由笔者在浏览器中打开后进行对比。
发动机题目势均力敌。
两者均输出了 90° 时的活塞位置 30.875mm(与手算结果一致),截面显示、摄像机和自动引导均正常运作。
有技能版遵循了 SKILL.md 中"明亮背景配单一强调色"的视觉偏好。
不过无技能版的画面同样相当清晰,难以分出胜负。
差距出现在 Strandbeest 题目上。
自动生成的连杆表中有两处结线被互换(d 与 e、h 与 i)。
按照该表组装,笔者计算后发现 360° 中有 264° 的范围内机构无法成立。
无技能版按照表中结线,通过穷举法寻找可行的组合。
足尖轨迹底部不平坦,处于最低点 1 单位以内的区间仅为曲柄 29°。
接地判定放宽至 6 单位才勉强自圆其说。
有技能版在读取 SKILL.md 和 Strandbeest 示例后,指出表中的足部三角形与原典不符。
按原典结线组装后,处于最低点 1 单位以内的区间为 155°,与示例轨迹一致。
"不靠想象,依据参考来构建"的规则一,以及示例的存在,在此发挥了作用。
也就是说,即使在无法使用工具的沙盒环境中,编写方式层面的效果也切实发挥出来了。
另一方面,teardown 的优势——拍摄与复查步骤——在本次验证中无法衡量。
若仅凭运行验证的分数来评判这个技能,会遗漏其优点的一半。
从 teardown 中可以借鉴的编写方式,并不局限于机械 3D 领域。
teardown 是一个技能,其优秀之处不在于成品 3D 的外观,而在于达成它的编写方式。
它将数字来源统一为一处,通过示例展示规范,并将无法直接查看的输出转化为可确认的形式。
本地验证中,主要数字与画面表现均与 SKILL.md 的描述一致。
示例中存在 timeline.json 为空的漏洞,但修复方向明确。
编写技能的人,不妨通读一遍 SKILL.md。
本文转载自 cccskills 的文章「teardown为何是技能范本——亲手运行验证」。
技能详情与安装方法请参见 cccskills 的 teardown 页面。