This library is a React Three Fiber wrapper around the official MuJoCo WASM bindings. Public APIs should feel natural in React/R3F apps while preserving direct access to MuJoCo model/data state for robotics work.
- Prefer composable React components and hooks over app-specific workflows.
- Keep MuJoCo as the source of physics truth; Three objects should mirror or visualize simulation state, not replace it.
- Keep the library useful at three levels: declarative JSX, React hooks, and the
imperative
MujocoSimAPI. - Make production robotics and dataset workflows explicit about provenance, timing, and resource names.
- Avoid adding consumer setup burden unless there is a clear runtime benefit.
- Hooks use
useXnames and return stable, small APIs with explicitstatus,error, action methods, and reset methods when async work is involved. - Components should accept normal R3F props where possible and compose inside
<MujocoCanvas>without requiring global app state. - Imperative helpers use verb-first names such as
captureCameraFrame,recordMountedCameraFrameSequence, andresolveMountedCameraFrameSource. - API options should be plain objects with conservative defaults. Prefer optional callbacks with object arguments over positional callback arguments.
- Do not hide important dataset or robotics assumptions. For example, mounted camera recording should expose source provenance and fail on missing streams by default.
- Use TypeScript string literal unions for public status values. When consumers
benefit from enum-like names, export an
as constobject plus the derived union type rather than a native TypeScriptenum. - Prefer discriminated unions for variants such as camera capture sources.
- Resource names should integrate with the declaration-merging
Registerpattern and fall back tostringwhen no generated register exists. - If a new resource category is added, update all surfaces together: runtime registry, exported resource category, Vite/codegen scanner, generated declaration shape, docs, and type tests.
- Use strict option types for helpers that require exactly one selector. Runtime validation should mirror the type-level guarantee for untyped consumers.
- Use R3F context hooks such as
useThreeinside components/hooks that need the renderer, scene, or active camera. - Do not mutate the user's interactive camera for offscreen capture. Clone or prepare a capture camera and restore renderer state after rendering.
- Drei should be a peer dependency and used for familiar controls/gizmos where it fits the existing API, not wrapped unnecessarily.
- Keep visual helpers renderer-agnostic unless they live behind an optional
adapter entrypoint such as
mujoco-react/spark.
- Use the official
@mujoco/mujocopackage as the underlying engine. - Keep
@mujoco/mujocoas a library dependency so default consumers do not need an extra install step. - Let bundlers resolve the default single-threaded WASM asset through
@mujoco/mujoco/mujoco.wasm?url. - Multi-threaded WASM remains opt-in: apps pass the threaded loader and MT WASM URL only when they can provide cross-origin isolation.
- Do not require app-level Vite
server.fs.allowchanges for normal use or localnpm linkdevelopment.
- Every public feature should have a README mention, focused docs page updates, and a runnable example when the behavior is visual or workflow-oriented.
- Docs snippets must use real exported API names. Prefer small snippets that show the ergonomic path first, then the lower-level path when relevant.
- Example app changes should demonstrate reusable patterns, not one-off test scaffolding. Keep demo controls compact and remove temporary test artifacts.
- Generated files such as
src/mujoco-register.gen.tsshould be regenerated by the plugin and committed when their shape changes.
- Run
npm run typecheckandnpm run buildin the library before committing. - Link the local library into the example and run
npx tsc --noEmitplusnpm run buildbefore publishing. - Use browser/Playwright smoke tests for renderer, capture, or interaction changes, and remove temporary test files/dependencies afterward.
- Publish through semantic-release only. Do not run
npm versionornpm publishmanually. - Release notes should be concise, user-facing, and grouped by capability.