Files
Mujoco_WASM/Plan.md
T
chenlin 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
feat: add browser-based MuJoCo simulation platform
2026-08-20 15:12:08 +08:00

181 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 核心绑定或生成产物。
初步分层:
1. **UI / 工程层**:工程导入、资源树、属性/控制面板、全局状态和错误展示。
2. **应用服务层**:工程文件规范化、入口模型识别、仿真会话生命周期、命令调度。
3. **物理层**:封装 `MjModel``MjData`、step/reset/ctrl,并集中管理 `.delete()`
4. **文件系统层**:将上传文件按相对路径写入 Emscripten MEMFS,校验引用与加载错误。
5. **渲染层**:Three.js 场景、相机、灯光、MuJoCo primitive/mesh 映射和逐帧位姿同步。
6. **交互控制层**Three.js Raycaster 完成选择;关节拖动映射到 `qpos` 并调用 `mj_forward`,外力拖拽通过 `MjvPerturb`/`mjv_applyPerturbForce` 在 step 前施加。
7. **线程边界**: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/ellipsoidmesh 与贴图需补齐,且不可直接复制其全局 `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`/`MjData` typed-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 与 URDFVFS 可容纳 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. 需求与架构定稿
- [x] 确认 React + Zustand,采用 Vitest + Playwright;仅支持桌面版 Chrome/Edge/Firefox 最新两个大版本。
- [x] 确认 MVP 输入格式为 MJCF/XML、URDF、文件夹和 ZIP;工程入口规则见后续步骤。
- [x] 确认 MVP 使用主线程、单线程 WASM,不实现 Worker/MT。
- [x] 明确参考站点只借鉴本地导入、工程树、中心视口、属性/控制面板的信息架构。
- [x] 输出模块边界、数据流、错误模型和资源生命周期设计。
### 1. 应用骨架与质量基线
- [x] 创建独立平台应用入口、Vite 配置、TailwindCSS 和基础布局。
- [x] 配置 TypeScript 严格检查、lint、单元测试与最小 E2E 测试。
- [x] 配置 WASM 静态资源定位及开发/生产构建路径,保持 `base: './'` 以支持任意静态子路径。
- [x] 验证本地静态 HTTP 服务器可正确提供 JS/CSS/WASM;不支持直接以 `file://` 打开,也不注册 service worker。
- [x] 建立错误边界、加载状态、日志和中文可诊断错误展示。
### 2. 工程导入与 MEMFS
- [x] 定义 `ProjectFile`、虚拟路径、入口模型和资源清单模型。
- [x] 支持单文件、多文件和目录拖放/选择,保留 `webkitRelativePath`;使用 ZIP 库在浏览器内解包 `.zip`,拒绝加密包、目录穿越和超限压缩内容。
- [x] 统一 `/workspace/<project-id>/...` 虚拟根目录,规范化路径后通过 `FS.mkdirTree/writeFile` 写入 MEMFS;二进制文件保持 `Uint8Array`,文本 XML 使用 UTF-8。
- [x] 入口规则:单个 XML/URDF 自动选中;多候选优先根目录 `model.xml`/`scene.xml`/唯一 `.urdf`,否则弹窗选择且按根元素 `<mujoco>`/`<robot>`标识类型。
- [x] 使用 `MjModel.mj_loadXML(entryPath)` 让 MuJoCo 原生解析 MJCF/URDF 及相对资源;加载失败保留工程树并展示入口、资源路径和 MuJoCo 错误。
- [x] 切换工程前按逆序释放会话对象,再递归删除 MEMFS 工作区;对文件数、单文件、解压总量设置可配置上限。
- [x] 为 MJCF include + OBJ/STL/PNG、URDF + mesh、目录、ZIP、路径冲突和缺失资源添加测试夹具。
### 3. MuJoCo 会话与仿真控制
- [x] 封装 WASM 单例初始化和 `SimulationSession` 生命周期。
- [x] 创建/销毁 `MjModel``MjData`,实现异常路径下的确定性释放。
- [x] 实现播放、暂停、单步、重置、时间倍率、固定步长累积器。
- [x] 实现 actuator 控件和 qpos/qvel/ctrl 等状态快照。
- [x] 实现同步 `PhysicsAdapter` 接口并保持 UI 不直接持有 Embind 对象;Worker/message protocol 仅记录为后续扩展点。
### 4. Three.js 可视化与交互
- [x] 复用官方 demo 的 primitive 构建与 `mjv_updateScene` 方法,抽离为可测试的场景适配器。
- [x] 支持 MuJoCo primitive;对 mesh 根据 `mjvGeom.dataid` 读取 `mesh_vert/face/normal/texcoord` 及地址/数量数组构建缓存的 `BufferGeometry`,并从 `tex_data/width/height` 创建纹理,覆盖材质和坐标/矩阵转换。
- [x] 每帧同步动态 body/geom 位姿,避免重复分配临时对象。
- [x] 实现 OrbitControls、相机复位、网格/坐标轴、灯光和 resize。
- [x] 用 Raycaster 实现对象拾取、选中高亮及与属性面板联动,并维护 Three.js object → MuJoCo body/geom id 映射。
- [x] 关节拖动仅对可直接编辑的 hinge/slide joint 开放:暂停仿真、按 joint axis 将拖动量写入对应 `qpos`、按 `jnt_range` 限位并执行 `mj_forward`free/ball joint MVP 只读。
- [x] 外力施加:选中动态 body 后以拖拽箭头显示方向/大小,在每个 `mj_step` 前通过 `MjvPerturb`/`mjv_applyPerturbForce` 施力,松开即清零,并提供强度刻度。
- [x] 在模型切换/卸载时释放 geometry、material、texture、Embind 临时 accessor/vector 和渲染循环资源。
### 5. 平台 UI 与状态管理
- [x] 搭建参考站点式布局:顶部工具栏、左侧工程树、中心视口、右侧属性/控制面板、底部状态区。
- [x] 实现 MJCF/XML、URDF、文件夹、ZIP 导入流程、入口选择、最近错误、加载进度与空状态。
- [x] 实现播放/暂停/单步/重置/速度控件、基于 `actuator_ctrlrange` 的 actuator 滑杆,以及 joint 拖动/外力模式开关。
- [x] 实现模型信息、body/joint/geom 属性检查器。
- [x] 针对桌面宽屏提供可调整/折叠面板、中文文案、键盘操作和基本无障碍语义;手机和平板不在 MVP 验收范围。
### 6. 性能、健壮性与交付
- [x] 建立 FPS、step 耗时、模型规模和内存趋势监控。
- [x] 验证大模型、资源缺失、无效 XML、重复加载和长时间运行。
- [x] 对主线程 step 设置每帧预算与最大追赶步数,超预算时显示性能警告而非无限追帧;Worker/SharedArrayBuffer 留作后续版本。
- [x] 完成生产构建、纯静态部署/离线使用说明、示例工程和用户文档。
- [x] 更新本计划进度看板并记录遗留项。
## 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 均返回 200WASM MIME 为 `application/wasm`
- 依赖审计:`npm audit` 0 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 服务器启动,`.wasm` MIME 与相对资源路径正确;明确 `file://` 不受支持。
## Confirmed Decisions
1. React + Zustand。
2. MVP 支持 MJCF/XML、URDF、文件夹、ZIPURDF 交由 MuJoCo 原生 loader 解析。
3. 首版不做 XML 编辑、热重载和工程导出。
4. 首版主线程单线程 WASM。
5. 纯静态、离线应用,无后端和账号体系。
6. 首版交互优先 actuator 滑杆、关节拖动、外力施加;关节拖动时暂停且仅支持 hinge/slide,外力拖拽期间持续施加、松开清零。
7. 仅支持桌面浏览器,中文界面;多个入口由用户弹窗选择。
8. 通过本地静态 HTTP 服务器运行,不实现 PWA。