我开源了一个浏览器三维模拟 Skill:货轮能开、还能固定帧导出

Administrator 1 阅读 技术

看过 @itsfazley 的 Ocean Lab 演示 之后,我深感这种在浏览器里拖动水体、操纵机械的高沉浸交互极具张力。但我更想解决的,是如何跳过单次手工写的玩具 Demo,在浏览器里做一套能开、能拖、能录,且能被 Codex 随叫随到一键脚手架(Scaffold)的可复用 Agent Skill。

原演示我未曾拿到源码,本篇也不是 Fork,而是看着推文效果由我独立重构而成。代码现已公开:

  • 开源仓库:github.com/HuaJuan2023/simulator-foundry(Public 仓,原代码采用 MIT 许可)
  • Skill 调用名:$interactive-simulator(仓库名为 Simulator Foundry,安装到技能目录后即以此调用,不会改成别的名字)

注:前一阵写的机械蚁 Teardown 是另一套参数化拆解思路;本篇对应独立仓库与独立 Skill,复刻机制不在此复读。

演示视频

三块硬点速览

  1. 镜头防弹回(No Snapback)
    解决自由跟随模式下每帧 lookAt 强抢相机控制权的问题,确保预设视角仅负责初态,拖动环绕不弹回。

  2. 尾迹钉死世界坐标
    波浪白沫生成时刻立即固定在世界空间,船只转弯时旧航迹留在原地,避免「白沫贴着船屁股跟着甩」。

  3. 确定性固定帧导出
    区分掉帧的实时录屏与按固定时间步推进的 WebCodecs 导出:仿真时间步长锁定 1/30s,基线 45 秒对应 1350 帧成片(名义 30fps;墙钟生成时间可以更久)。

一、货轮基线踩过的三块硬点

Starter 项目默认装载的是深蓝航道上的远洋货轮场景(路由访问 /?scene=cargo)。船体约 150 米长,航速支持 0–26 节任意调节,具备完整的浮力姿态交互——能拖动船体、拖动水面浮标,也能随时在自由跟随、驾驶台主视、高空俯视、左舷(Port-side)、日月观测等预设视角间切换。

然而在实际工程开发中,真正容易翻车的不是「多画一艘模型船」,而是镜头控制、流体航迹与视频导出这三处深水区:

1. 镜头别被每帧 lookAt 抢回去

在 3D 场景开发中,开启对象追踪后,很多人习惯在渲染循环里每帧执行 camera.lookAt(target)。这会导致冲突:当你试图用鼠标拖拽轨道做自由环绕观察时,鼠标刚松开(甚至还在拖动中),视角瞬间被下一帧的 lookAt 拽回原位(即 Snapback 现象)。

基线做法:镜头预设仅在触发时负责一次性矩阵初始化,此后必须把相机的旋转输入交还给用户自由控制。验收用例里记过:切至 Port-side 视角后随意拖动空水面进行旋转环绕,不应出现强行归位弹回。

2. 航迹必须钉在世界坐标系

船只在水面高速破浪时,尾迹扩散与边缘泡沫在生成的那一瞬间,其世界三维坐标就应固化。当船体大幅度打舵转向或继续向前航行时,旧航迹应平稳消散在原处,而不能以船体为父级局部坐标系跟着甩动。

在仓库的 README.md 以及 references/ocean-baseline.md 中对此作了标定:调整船速、急变航向后,回头看海面上的旧白沫是笔直留在原来的航道上,还是像尾巴一样跟着船尾一起扭转,一眼就能验明真伪。

3. 两种录屏机制不要混淆

系统底栏的 Record(录制)功能拆成两套底层逻辑:

手动实时录屏

  • 底层:captureStream + MediaRecorder
  • 帧率:跟随浏览器真实渲染管线调度,不保证固定实时 FPS;切到后台或 GPU 繁忙即掉帧(可回落至 WebM)
  • 适用:操作过程即时预览、快速草稿沟通

自动演示导出

  • 底层:Mediabunny 驱动原生 WebCodecs 编码
  • 帧率:仿真时间按固定 1/30 秒时间步长推进,挂起等待编码器背压;基线对齐 45 秒/1350 帧 MP4(名义 30fps;生成可以比 45 秒墙钟更久)
  • 适用:需要帧数对得上的成片、社交平台发布

基线自动化验收实测数据:H.264 视频编码 + AAC 音频封装,分辨率 1280×720,全长 45 秒(1350 帧),前 90 个动态帧逐帧互异且解码错误数为 0。若本地录屏时界面闪过「实时渲染 · 7 FPS」,那仅代表受限硬件下的瞬时屏幕观感,不代表自动导出管线最终成片的名义帧率。

全套流水线均在前端浏览器沙盒内完成预览与下载,不涉及桌面原生采集权限,不调用麦克风,亦无需向后端云服务器上传资产。

二、Skill 怎么装,Scaffold 怎么验

基础环境准备:需要 Node.js 20.19+ 或 22.12+ 长期支持版本,浏览器需完整支持 WebGL 2 与 WebCodecs(推荐使用近期版本的 Chrome 或 Edge)。

  1. 克隆仓库:
git clone https://github.com/HuaJuan2023/simulator-foundry.git
cd simulator-foundry
  1. 安装 Skill 至 Codex:

支持通过 $skill-installer 直接安装 skills/interactive-simulator;亦可直接将该目录完整复制到 Codex 的技能根目录(常见路径为用户级 ~/.agents/skills 或项目级 .agents/skills)。其外部调用名固定为 $interactive-simulator。

  1. 脚手架一键生成全新工程:

执行脚手架命令将样板工程生成至一个空白目录中(目标目录必须为空,避免意外覆写):

node skills/interactive-simulator/scripts/scaffold.mjs ../my-simulator
cd ../my-simulator
npm ci
npm test
npm run dev

运行完毕后将看到终端打出 Vite 本地调试地址,同时自动化测试应全部通过。

  1. 在浏览器中查看场景:

浏览器打开本地服务地址:访问 /?scene=cargo 进入标杆远洋货轮场景;访问 /?scene=ocean 可进入本 starter 里的 Ocean Lab 场景名(包含快艇、浮标与漂流木桶测试)——不是对方产品名。

  1. 基线自动化验证与验收:

先在技能目录运行脚手架完整性自检:

node skills/interactive-simulator/scripts/scaffold.mjs --verify

该命令会自动校验 Bundled Manifest 的哈希 SHA 完整性;随后在生成的项目中运行 npm test,基线标准记录为 13 项自动化测试全数 PASS。关键指标可直接对照 skills/interactive-simulator/assets/quality/baseline.json(记录于 2026-11-01)逐一核验导出总帧数与防回弹事件。生产构建也可再跑一遍 npm run build。

默认日落仿真参数:时间设定为 17:36,海浪波幅 1.2m,风速 7m/s,表面杂波系数(Choppiness)0.55。截图与演示中出现的「星辰远航号」仅为 QA 验收时输入的文本测试用例,默认出厂船名为 HORIZON。

三、上游致谢与开源协议边界

在设计逻辑与交互质感上,本项目深受 @itsfazley Ocean Lab 视觉创意的启发;但全部代码与数学实现均为独立编写,未采用其任何闭源资产或未授权代码。

开源协议声明:请勿将整套技术栈笼统称为「全部 MIT」

本项目原创代码采用宽松的 MIT License。然而,现代复杂 Web 3D 工程由多个上游项目支撑,各组件保留其原有授权约束,分列如下:

  • Three.js 0.180.0 —— 遵循 MIT 协议
  • Mediabunny 1.65.0 —— 遵循 MPL-2.0 协议(Mozilla Public License 2.0,涉及源码修改时需遵循其要求)
  • Vite 7.3.7 —— 遵循 MIT 协议

技能打包体系参考公开的 Codex skills 与 Agent Skills 文档。本仓库与 OpenAI、Three.js、Mediabunny、Vite 官方团队及灵感原作者均无官方隶属或商业背书关系。

四、能力边界:别指望它能包打一切

为避免对工程期待造成误导,须坦诚界定本项目的能力边界:

  • 它属于高拟真「视觉模拟器」,而非工业仿真软件:水体浮力基于流体多项式经验估算,水面涟漪采用 2D 贴图相位扰动,未运行纳维-斯托克斯完整六自由度高开销流体动力学;系统未搭载高精度刚体碰撞引擎,亦不具备商用航海航线规划逻辑。太阳与月球的升沉轨迹为几何理想化函数,非真实天文星历。
  • 它不是开箱即用的万能插件引擎:当前的 Starter UI 和自动演示脚本中,仍包含深度契合海洋与船只业务的定制逻辑分支。如果你打算用它构建卫星轨道模拟或机械臂逆运动学场景,必须自己重新搭建 3D 模型、交互控制器与章节镜头;不能指望把海洋分支当成乐高积木直接硬套。
  • 渲染帧率具有硬件相关性:受各设备 GPU 驱动、着色器浮点精度与粒子数量影响,不同机器的实时渲染帧率与光泽度存在客观差异,请以 WebCodecs 固定时间步导出的视频文件作为客观验收基准。参考截图只作观感对照,不是像素金标准。

五、动手自检清单(建议按此顺序执行)

  1. 克隆公开仓,按指引安装 $interactive-simulator,或通过 scaffold.mjs 一键部署至新目录跑通 npm test。
  2. 浏览器启动 /?scene=cargo,手动拖拽 Port-side 侧舷相机,确认松手后镜头无异常回弹。
  3. 执行一次 45 秒全流程自动导出,验收输出的 MP4 成片是否对齐 1350 帧(名义 30fps);别拿手动录屏的实时掉帧与之混淆。
  4. 调试船名、波浪振幅或风速参数前,先行查阅 baseline.json 确认基线验收边界。
  5. 探索跨行业新场景时,规范重构模型几何与演示编排,理清业务与引擎底座的边界。

传送门