1eb05132f1
build / setup (compute matrix) (pull_request) Has been cancelled
build / ${{ matrix.label }} (pull_request) Has been cancelled
build / macos-15-arm64-studio (pull_request) Has been cancelled
build / ubuntu-24.04-clang-18-studio (pull_request) Has been cancelled
build / ubuntu-24.04-gcc-14-studio (pull_request) Has been cancelled
build / windows-2025-ninja-studio (pull_request) Has been cancelled
build / ubuntu-24.04-clang-18-wasm (pull_request) Has been cancelled
build / ubuntu-24.04-clang-18-mjx (pull_request) Has been cancelled
lint / pre-commit (pull_request) Has been cancelled
15 KiB
15 KiB
MuJoCo Web 仿真平台实施计划
计划状态:✅ MVP 已实施并通过自动化验证
进度维护规则:实施时将阶段/任务复选框由[ ]更新为[x],并同步“进度看板”中的状态、完成日期与备注。
Context
目标是在本仓库官方 wasm/ JavaScript/TypeScript 绑定和 Three.js 示例之上,建设一个纯浏览器 MuJoCo 仿真平台,支持模型工程上传、浏览器内文件组织、模型加载、三维展示、仿真控制和状态查看,交互布局参考 urdf.enkeebot.com。
已确认的仓库基础:
wasm/dist/有本地构建的绑定产物,但当前build/CMakeCache.txt显示其启用了线程;MVP 因此使用同版本官方@mujoco/mujoco默认单线程入口。wasm/demo_app/已有 Vite + TypeScript + Three.js 的最小示例,可作为加载、场景构建与逐帧同步的起点。- 官方绑定要求显式调用
.delete()管理 Embind/C++ 对象生命周期。 - 官方同时支持默认单线程入口与需要 COOP/COEP 的多线程入口;MVP 已确定使用默认单线程入口。
Scope / MVP 边界
- 技术栈:React + TypeScript + Zustand + Vite + TailwindCSS + Three.js。
- 输入:单个 MJCF/XML、单个 URDF、保留相对路径的文件夹、ZIP 工程;关联 mesh/贴图随工程导入。
- 编辑边界:首版只负责导入、查看和仿真,不提供 XML 编辑、热重载、工程保存或导出。
- 物理执行:首版使用主线程、单线程
mujoco.wasm;模块边界保留未来迁移 Worker 的能力,但不在 MVP 实现 Worker。 - 控制优先级:actuator 滑杆、关节拖动、外力施加,另含播放、暂停、单步、重置和速度控制。
- 部署边界:桌面浏览器中的中文界面,通过本地静态 HTTP 服务器运行;无 PWA、账号、后端、云存储或分享服务,导入工程仅驻留当前浏览器会话内存。
- 非目标:URDF/MJCF 互转、Xacro 展开、控制脚本、轨迹编辑与多线程 WASM。
Approach
已采用 React + TypeScript + Vite + TailwindCSS + Three.js,在 wasm/web_platform/ 新增独立平台应用,复用官方 WASM 包和示例逻辑,未改动 MuJoCo 核心绑定或生成产物。
初步分层:
- UI / 工程层:工程导入、资源树、属性/控制面板、全局状态和错误展示。
- 应用服务层:工程文件规范化、入口模型识别、仿真会话生命周期、命令调度。
- 物理层:封装
MjModel、MjData、step/reset/ctrl,并集中管理.delete()。 - 文件系统层:将上传文件按相对路径写入 Emscripten MEMFS,校验引用与加载错误。
- 渲染层:Three.js 场景、相机、灯光、MuJoCo primitive/mesh 映射和逐帧位姿同步。
- 交互控制层:Three.js Raycaster 完成选择;关节拖动映射到
qpos并调用mj_forward,外力拖拽通过MjvPerturb/mjv_applyPerturbForce在 step 前施加。 - 线程边界:MVP 直接调用主线程单线程绑定,但通过
PhysicsAdapter隔离 UI,未来可在不改 UI 的情况下迁移 Worker。
数据流、错误与生命周期
- 数据流:File/Directory/ZIP → 路径校验与入口识别 → MEMFS workspace →
mj_loadXML→SimulationSession→mjv_updateScene/状态快照 → Three.js 与 Zustand UI。 - 状态边界:Zustand 只保存可序列化的工程元数据、控制参数、选择和 UI 状态;
MjModel/MjData/Three.js 实例由服务对象持有,避免 React 重渲染复制 WASM 视图。 - 错误模型:按导入、ZIP、文件系统、模型编译、仿真、渲染分类,统一包含中文摘要、阶段、相关路径和原始错误;致命错误停止当前会话但保留工程树供排查。
- 生命周期:新模型采用“先释放旧渲染资源和 Embind 对象 → 清理旧 workspace → 写入新工程 → 创建新会话”的串行切换;所有失败分支使用
finally回收已创建对象。
Files to modify
Plan.md:计划与持续进度记录。wasm/demo_app/app.ts:只读复用来源,原则上不直接扩建为平台。wasm/package.json、wasm/package-lock.json:加入 React、Zustand、TailwindCSS、fflate、Vitest、Playwright 及平台脚本。wasm/web_platform/index.html、wasm/web_platform/vite.config.ts:平台入口、WASM 静态资源定位和相对路径静态部署配置。wasm/web_platform/src/app/:React 壳层、布局、全局错误边界与启动流程。wasm/web_platform/src/stores/:Zustand 工程、仿真、选择和 UI 状态切片。wasm/web_platform/src/project/:文件/目录/ZIP 导入、路径规范化、入口识别和 MEMFS 工作区。wasm/web_platform/src/simulation/:WASM 初始化、PhysicsAdapter、SimulationSession、步进和控制命令。wasm/web_platform/src/viewer/:Three.js renderer、MuJoCo 场景适配、拾取、关节拖动和外力交互。wasm/web_platform/src/**/*.test.ts(x)、wasm/web_platform/e2e/、wasm/web_platform/fixtures/:单测、浏览器测试与示例工程。@mujoco/mujoco:作为默认单线程构建输入;wasm/dist/*未手工修改。
Reuse
wasm/demo_app/app.ts:复用loadMujoco()初始化、mjv_updateScene场景提取、Z-up 相机、固定仿真时长步进、矩阵同步和确定性释放思路;现有getBufferGeometry仅覆盖 plane/sphere/capsule/box/cylinder/ellipsoid,mesh 与贴图需补齐,且不可直接复制其全局app/DOM 写法。wasm/demo_app/vite.demo.config.ts:复用root、相对base、独立输出目录和开发响应头模式;MVP 单线程不依赖 COOP/COEP。wasm/tests/bindings_test.ts:复用FS.writeFile/unlink、MjModel.mj_loadXML(path)、MjVFS.addBuffer、带外部 OBJ 的加载测试以及finally + .delete()生命周期范式。@mujoco/mujoco类型:使用MjModel/MjDatatyped-array 视图、named accessor、MjvPerturb与mjv_applyPerturbForce等 API;避开 bool typed-memory-view 的绑定限制,并显式删除 accessor。doc/overview.rst、doc/modeling.rst、doc/APIreference/functions_override.rst:MuJoCo 原生mj_loadXML可解析 MJCF 与 URDF,VFS 可容纳 XML/include、STL、PNG 等资源,因此 URDF 不另做平台侧转换。- 参考站点仅复用信息架构理念:本地导入、3D 视口、关节树/属性与控制面板;MVP 不复刻其编辑、格式转换或云端工具能力。
Steps
进度看板
| 阶段 | 状态 | 完成度 | 完成日期 | 备注 |
|---|---|---|---|---|
| 0. 需求与架构定稿 | 🟢 已完成 | 100% | 当前 | 产品边界、交互语义和架构已确认 |
| 1. 应用骨架与质量基线 | 🟢 已完成 | 100% | 当前 | typecheck、lint、Vitest、Playwright、build 通过 |
| 2. 工程导入与 MEMFS | 🟢 已完成 | 100% | 当前 | 单/多文件、目录、ZIP、安全限制与入口选择 |
| 3. MuJoCo 会话与仿真控制 | 🟢 已完成 | 100% | 当前 | 主线程单线程、固定步进、控制与确定性释放 |
| 4. Three.js 可视化与交互 | 🟢 已完成 | 100% | 当前 | primitive/mesh/texture、拾取、关节与外力交互 |
| 5. 平台 UI 与状态管理 | 🟢 已完成 | 100% | 当前 | 中文桌面布局、面板、属性和状态栏 |
| 6. 性能、健壮性与交付 | 🟢 已完成 | 100% | 当前 | 预算保护、夹具/E2E、静态部署文档 |
0. 需求与架构定稿
- 确认 React + Zustand,采用 Vitest + Playwright;仅支持桌面版 Chrome/Edge/Firefox 最新两个大版本。
- 确认 MVP 输入格式为 MJCF/XML、URDF、文件夹和 ZIP;工程入口规则见后续步骤。
- 确认 MVP 使用主线程、单线程 WASM,不实现 Worker/MT。
- 明确参考站点只借鉴本地导入、工程树、中心视口、属性/控制面板的信息架构。
- 输出模块边界、数据流、错误模型和资源生命周期设计。
1. 应用骨架与质量基线
- 创建独立平台应用入口、Vite 配置、TailwindCSS 和基础布局。
- 配置 TypeScript 严格检查、lint、单元测试与最小 E2E 测试。
- 配置 WASM 静态资源定位及开发/生产构建路径,保持
base: './'以支持任意静态子路径。 - 验证本地静态 HTTP 服务器可正确提供 JS/CSS/WASM;不支持直接以
file://打开,也不注册 service worker。 - 建立错误边界、加载状态、日志和中文可诊断错误展示。
2. 工程导入与 MEMFS
- 定义
ProjectFile、虚拟路径、入口模型和资源清单模型。 - 支持单文件、多文件和目录拖放/选择,保留
webkitRelativePath;使用 ZIP 库在浏览器内解包.zip,拒绝加密包、目录穿越和超限压缩内容。 - 统一
/workspace/<project-id>/...虚拟根目录,规范化路径后通过FS.mkdirTree/writeFile写入 MEMFS;二进制文件保持Uint8Array,文本 XML 使用 UTF-8。 - 入口规则:单个 XML/URDF 自动选中;多候选优先根目录
model.xml/scene.xml/唯一.urdf,否则弹窗选择且按根元素<mujoco>/<robot>标识类型。 - 使用
MjModel.mj_loadXML(entryPath)让 MuJoCo 原生解析 MJCF/URDF 及相对资源;加载失败保留工程树并展示入口、资源路径和 MuJoCo 错误。 - 切换工程前按逆序释放会话对象,再递归删除 MEMFS 工作区;对文件数、单文件、解压总量设置可配置上限。
- 为 MJCF include + OBJ/STL/PNG、URDF + mesh、目录、ZIP、路径冲突和缺失资源添加测试夹具。
3. MuJoCo 会话与仿真控制
- 封装 WASM 单例初始化和
SimulationSession生命周期。 - 创建/销毁
MjModel、MjData,实现异常路径下的确定性释放。 - 实现播放、暂停、单步、重置、时间倍率、固定步长累积器。
- 实现 actuator 控件和 qpos/qvel/ctrl 等状态快照。
- 实现同步
PhysicsAdapter接口并保持 UI 不直接持有 Embind 对象;Worker/message protocol 仅记录为后续扩展点。
4. Three.js 可视化与交互
- 复用官方 demo 的 primitive 构建与
mjv_updateScene方法,抽离为可测试的场景适配器。 - 支持 MuJoCo primitive;对 mesh 根据
mjvGeom.dataid读取mesh_vert/face/normal/texcoord及地址/数量数组构建缓存的BufferGeometry,并从tex_data/width/height创建纹理,覆盖材质和坐标/矩阵转换。 - 每帧同步动态 body/geom 位姿,避免重复分配临时对象。
- 实现 OrbitControls、相机复位、网格/坐标轴、灯光和 resize。
- 用 Raycaster 实现对象拾取、选中高亮及与属性面板联动,并维护 Three.js object → MuJoCo body/geom id 映射。
- 关节拖动仅对可直接编辑的 hinge/slide joint 开放:暂停仿真、按 joint axis 将拖动量写入对应
qpos、按jnt_range限位并执行mj_forward;free/ball joint MVP 只读。 - 外力施加:选中动态 body 后以拖拽箭头显示方向/大小,在每个
mj_step前通过MjvPerturb/mjv_applyPerturbForce施力,松开即清零,并提供强度刻度。 - 在模型切换/卸载时释放 geometry、material、texture、Embind 临时 accessor/vector 和渲染循环资源。
5. 平台 UI 与状态管理
- 搭建参考站点式布局:顶部工具栏、左侧工程树、中心视口、右侧属性/控制面板、底部状态区。
- 实现 MJCF/XML、URDF、文件夹、ZIP 导入流程、入口选择、最近错误、加载进度与空状态。
- 实现播放/暂停/单步/重置/速度控件、基于
actuator_ctrlrange的 actuator 滑杆,以及 joint 拖动/外力模式开关。 - 实现模型信息、body/joint/geom 属性检查器。
- 针对桌面宽屏提供可调整/折叠面板、中文文案、键盘操作和基本无障碍语义;手机和平板不在 MVP 验收范围。
6. 性能、健壮性与交付
- 建立 FPS、step 耗时、模型规模和内存趋势监控。
- 验证大模型、资源缺失、无效 XML、重复加载和长时间运行。
- 对主线程 step 设置每帧预算与最大追赶步数,超预算时显示性能警告而非无限追帧;Worker/SharedArrayBuffer 留作后续版本。
- 完成生产构建、纯静态部署/离线使用说明、示例工程和用户文档。
- 更新本计划进度看板并记录遗留项。
Implementation Result
- 平台代码:
wasm/web_platform/;使用@mujoco/mujoco@3.11.0默认单线程入口。 - 自动化结果:TypeScript、ESLint、10 个 Vitest 测试、5 个 Chrome Playwright E2E、生产构建均通过。
- E2E 覆盖:单文件 MJCF、MJCF include + OBJ/STL/PNG、URDF + OBJ、中等规模持续步进/重复加载、无效模型错误保留;另用完整 Go2W ZIP 实测 ROS
package://、重复 material 和 DAE 降级后可编译。 - 静态服务验证:Python HTTP server 对 HTML 与 WASM 均返回 200,WASM MIME 为
application/wasm。 - 依赖审计:
npm audit0 vulnerabilities。
遗留验收项
- Edge/Firefox 最新版本尚未在当前环境做人工交互验收。
- 关节拖动、外力箭头与超大模型的视觉手感仍需结合真实机器人工程人工调参。
- 当前构建有约 865 KiB JS chunk 的 Vite 体积警告;不影响 MVP,后续可按面板/Three.js 做代码分割。
- E2E 的持续步进是秒级冒烟;发布前建议增加 30–60 分钟内存与稳定性 soak test。
Verification
- 自动化:TypeScript 类型检查、单元测试、构建测试、浏览器 E2E 冒烟测试。
- 导入:MJCF/URDF 与其 mesh/texture 相对引用可加载;缺失/冲突/非法路径给出可定位错误。
- 物理:播放、暂停、单步、重置和 actuator 控制结果符合 MuJoCo 时间步;重复加载无悬挂循环。
- 渲染:primitive/mesh 位姿与
xpos/xquat一致,相机和选中交互稳定,窗口缩放正常。 - 生命周期:连续切换模型和长时间仿真时,WASM/Three.js 资源无持续异常增长。
- 浏览器:桌面版 Chrome、Edge、Firefox 最新两个大版本完成手工验收;不测试手机、平板和多线程模式。
- 交付:生产构建可由本地静态 HTTP 服务器启动,
.wasmMIME 与相对资源路径正确;明确file://不受支持。
Confirmed Decisions
- React + Zustand。
- MVP 支持 MJCF/XML、URDF、文件夹、ZIP;URDF 交由 MuJoCo 原生 loader 解析。
- 首版不做 XML 编辑、热重载和工程导出。
- 首版主线程单线程 WASM。
- 纯静态、离线应用,无后端和账号体系。
- 首版交互优先 actuator 滑杆、关节拖动、外力施加;关节拖动时暂停且仅支持 hinge/slide,外力拖拽期间持续施加、松开清零。
- 仅支持桌面浏览器,中文界面;多个入口由用户弹窗选择。
- 通过本地静态 HTTP 服务器运行,不实现 PWA。