mujoco-react 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -98
- package/dist/index.d.ts +1 -7
- package/dist/index.js +533 -530
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/MujocoSimProvider.tsx +2 -0
- package/src/index.ts +0 -1
package/README.md
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/images/mj2.gif" alt="mujoco-react demo" width="100%" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
1
5
|
# mujoco-react
|
|
2
6
|
|
|
3
|
-
|
|
7
|
+
Composable [React Three Fiber](https://docs.pmnd.rs/react-three-fiber) wrapper around [mujoco-js](https://www.npmjs.com/package/mujoco-js). Load any MuJoCo model, step physics, render bodies, and write controllers as React components.
|
|
4
8
|
|
|
9
|
+
**[Live Demo](https://mujoco-react-example.pages.dev)** | **[Docs](https://dadd.mintlify.app)** | **[Example Source](https://github.com/noah-wardlow/mujoco-react-example)**
|
|
5
10
|
|
|
6
11
|
## Install
|
|
7
12
|
|
|
@@ -15,7 +20,6 @@ npm install mujoco-react three @react-three/fiber @react-three/drei
|
|
|
15
20
|
import {
|
|
16
21
|
MujocoProvider,
|
|
17
22
|
MujocoCanvas,
|
|
18
|
-
SceneRenderer,
|
|
19
23
|
IkController,
|
|
20
24
|
IkGizmo,
|
|
21
25
|
} from 'mujoco-react';
|
|
@@ -41,7 +45,6 @@ function App() {
|
|
|
41
45
|
style={{ width: '100%', height: '100vh' }}
|
|
42
46
|
>
|
|
43
47
|
<OrbitControls enableDamping makeDefault />
|
|
44
|
-
<SceneRenderer />
|
|
45
48
|
<IkController config={{ siteName: 'tcp', numJoints: 7 }}>
|
|
46
49
|
<IkGizmo />
|
|
47
50
|
</IkController>
|
|
@@ -53,49 +56,28 @@ function App() {
|
|
|
53
56
|
}
|
|
54
57
|
```
|
|
55
58
|
|
|
56
|
-
##
|
|
57
|
-
|
|
58
|
-
Two ways to set up your scene:
|
|
59
|
-
|
|
60
|
-
### `<MujocoCanvas>` — Quick Start
|
|
59
|
+
## Direct WASM Access
|
|
61
60
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
```
|
|
65
|
-
<MujocoProvider> <- WASM module lifecycle
|
|
66
|
-
<MujocoCanvas config={...}> <- R3F Canvas + physics context
|
|
67
|
-
<SceneRenderer /> <- Syncs MuJoCo bodies to Three.js meshes
|
|
68
|
-
<IkController config={..}> <- Opt-in controller plugin
|
|
69
|
-
<IkGizmo />
|
|
70
|
-
</IkController>
|
|
71
|
-
<YourController /> <- Bring your own controller
|
|
72
|
-
<YourLights /> <- You compose your own scene
|
|
73
|
-
</MujocoCanvas>
|
|
74
|
-
</MujocoProvider>
|
|
75
|
-
```
|
|
61
|
+
`useMujoco()` gives you the full typed MuJoCo WASM binary — `mj_step`, `mj_forward`, `MjModel`, `MjData`, and everything else:
|
|
76
62
|
|
|
77
|
-
|
|
63
|
+
```tsx
|
|
64
|
+
import { useMujoco } from 'mujoco-react';
|
|
78
65
|
|
|
79
|
-
|
|
66
|
+
const { mujoco, status } = useMujoco();
|
|
80
67
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
</MujocoPhysics>
|
|
88
|
-
<OrbitControls />
|
|
89
|
-
<EffectComposer>...</EffectComposer> <- Post-processing, etc.
|
|
90
|
-
</Canvas>
|
|
91
|
-
</MujocoProvider>
|
|
68
|
+
if (mujoco) {
|
|
69
|
+
const model = mujoco.MjModel.loadFromXML('/path/to/scene.xml');
|
|
70
|
+
const data = new mujoco.MjData(model);
|
|
71
|
+
mujoco.mj_step(model, data);
|
|
72
|
+
console.log(data.qpos); // joint positions after one step
|
|
73
|
+
}
|
|
92
74
|
```
|
|
93
75
|
|
|
94
|
-
|
|
76
|
+
Most users won't need this — `<MujocoCanvas>` and hooks like `useBeforePhysicsStep` handle the model/data lifecycle for you. But the raw module is always available when you need it.
|
|
95
77
|
|
|
96
|
-
##
|
|
78
|
+
## Writing a Controller
|
|
97
79
|
|
|
98
|
-
|
|
80
|
+
A controller is a React component that calls `useBeforePhysicsStep` to write `data.ctrl` each frame:
|
|
99
81
|
|
|
100
82
|
```tsx
|
|
101
83
|
import { useBeforePhysicsStep } from 'mujoco-react';
|
|
@@ -107,76 +89,68 @@ function MyController() {
|
|
|
107
89
|
});
|
|
108
90
|
return null;
|
|
109
91
|
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Drop it into the tree:
|
|
110
95
|
|
|
111
|
-
|
|
96
|
+
```tsx
|
|
112
97
|
<MujocoCanvas config={config}>
|
|
113
|
-
<SceneRenderer />
|
|
114
98
|
<MyController />
|
|
115
99
|
</MujocoCanvas>
|
|
116
100
|
```
|
|
117
101
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
### Bring Your Own IK
|
|
121
|
-
|
|
122
|
-
The built-in `<IkController>` uses a generic Damped Least-Squares solver, but you can plug in **any** IK solver — analytical, learned, or from another library:
|
|
102
|
+
The `createController<TConfig>()` factory adds typed config and default merging for reusable plugins:
|
|
123
103
|
|
|
124
104
|
```tsx
|
|
125
|
-
import
|
|
105
|
+
import { createController, useBeforePhysicsStep } from 'mujoco-react';
|
|
126
106
|
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
}
|
|
107
|
+
export const MyController = createController<{ gain: number }>(
|
|
108
|
+
{ name: 'MyController', defaultConfig: { gain: 1.0 } },
|
|
109
|
+
({ config }) => {
|
|
110
|
+
useBeforePhysicsStep((_model, data) => {
|
|
111
|
+
data.ctrl[0] = config.gain * Math.sin(data.time);
|
|
112
|
+
});
|
|
113
|
+
return null;
|
|
114
|
+
},
|
|
115
|
+
);
|
|
130
116
|
|
|
131
|
-
<
|
|
132
|
-
<IkGizmo />
|
|
133
|
-
</IkController>
|
|
117
|
+
// <MyController config={{ gain: 2.0 }} />
|
|
134
118
|
```
|
|
135
119
|
|
|
136
|
-
|
|
120
|
+
## Architecture
|
|
121
|
+
|
|
122
|
+
`<MujocoCanvas>` wraps R3F `<Canvas>` and forwards all Canvas props (`camera`, `shadows`, `gl`, etc.). For full control over the Canvas, use `<MujocoPhysics>` inside your own:
|
|
137
123
|
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
124
|
+
```
|
|
125
|
+
<MujocoProvider> <MujocoProvider>
|
|
126
|
+
<MujocoCanvas config={...}> <Canvas shadows gl={...}>
|
|
127
|
+
<IkController config={..}> <MujocoPhysics config={...}>
|
|
128
|
+
<IkGizmo /> <MyController />
|
|
129
|
+
</IkController> </MujocoPhysics>
|
|
130
|
+
<MyController /> <EffectComposer>...</EffectComposer>
|
|
131
|
+
</MujocoCanvas> </Canvas>
|
|
132
|
+
</MujocoProvider> </MujocoProvider>
|
|
148
133
|
```
|
|
149
134
|
|
|
150
|
-
###
|
|
135
|
+
### Custom IK Solvers
|
|
151
136
|
|
|
152
|
-
|
|
137
|
+
The built-in `<IkController>` uses Damped Least-Squares. Pass `ikSolveFn` to swap in your own solver (analytical, learned, etc.):
|
|
153
138
|
|
|
154
139
|
```tsx
|
|
155
|
-
import {
|
|
156
|
-
|
|
157
|
-
interface MyConfig {
|
|
158
|
-
gain: number;
|
|
159
|
-
targetJoint: string;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function MyControllerImpl({ config }: { config: MyConfig; children?: React.ReactNode }) {
|
|
163
|
-
useBeforePhysicsStep((_model, data) => {
|
|
164
|
-
data.ctrl[0] = config.gain * Math.sin(data.time);
|
|
165
|
-
});
|
|
166
|
-
return null;
|
|
167
|
-
}
|
|
140
|
+
import type { IKSolveFn } from 'mujoco-react';
|
|
168
141
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
);
|
|
142
|
+
const myIK: IKSolveFn = (pos, quat, currentQ) => {
|
|
143
|
+
return myAnalyticalSolver(pos, currentQ); // return joint angles or null
|
|
144
|
+
};
|
|
173
145
|
|
|
174
|
-
|
|
146
|
+
<IkController config={{ siteName: 'tcp', numJoints: 7, ikSolveFn: myIK }}>
|
|
147
|
+
<IkGizmo />
|
|
148
|
+
</IkController>
|
|
175
149
|
```
|
|
176
150
|
|
|
177
|
-
###
|
|
151
|
+
### `<IkController>`
|
|
178
152
|
|
|
179
|
-
The library
|
|
153
|
+
The library includes one controller for interactive end-effector control:
|
|
180
154
|
|
|
181
155
|
```tsx
|
|
182
156
|
<IkController config={{ siteName: 'tcp', numJoints: 7 }}>
|
|
@@ -209,7 +183,7 @@ const ikCtx = useIk({ optional: true });
|
|
|
209
183
|
Models are loaded from any HTTP source via `SceneConfig.baseUrl`. Defaults to [MuJoCo Menagerie](https://github.com/google-deepmind/mujoco_menagerie) on GitHub.
|
|
210
184
|
|
|
211
185
|
```tsx
|
|
212
|
-
// Menagerie robots
|
|
186
|
+
// Menagerie robots: just set robotId
|
|
213
187
|
const franka: SceneConfig = {
|
|
214
188
|
robotId: 'franka_emika_panda',
|
|
215
189
|
sceneFile: 'scene.xml',
|
|
@@ -308,7 +282,6 @@ Physics provider for use inside your own R3F `<Canvas>`. Same physics props as `
|
|
|
308
282
|
<MujocoProvider>
|
|
309
283
|
<Canvas shadows camera={{ position: [2, 2, 2] }}>
|
|
310
284
|
<MujocoPhysics ref={apiRef} config={config} paused={paused}>
|
|
311
|
-
<SceneRenderer />
|
|
312
285
|
<MyController />
|
|
313
286
|
</MujocoPhysics>
|
|
314
287
|
<OrbitControls />
|
|
@@ -329,10 +302,6 @@ Physics provider for use inside your own R3F `<Canvas>`. Same physics props as `
|
|
|
329
302
|
| `paused` | `boolean` | Declarative pause |
|
|
330
303
|
| `speed` | `number` | Simulation speed multiplier |
|
|
331
304
|
|
|
332
|
-
### `<SceneRenderer />`
|
|
333
|
-
|
|
334
|
-
Syncs MuJoCo bodies to Three.js meshes every frame. Must be inside `<MujocoCanvas>` or `<MujocoPhysics>`.
|
|
335
|
-
|
|
336
305
|
### `<IkGizmo />`
|
|
337
306
|
|
|
338
307
|
drei PivotControls gizmo that tracks a MuJoCo site and drives IK on drag. Must be inside `<IkController>`.
|
|
@@ -349,10 +318,9 @@ Click-drag to apply spring forces to bodies. Raycasts to find bodies, applies `F
|
|
|
349
318
|
|
|
350
319
|
### R3F Group Props
|
|
351
320
|
|
|
352
|
-
All visual components (`
|
|
321
|
+
All visual components (`DragInteraction`, `ContactMarkers`, `Debug`, `TendonRenderer`, `FlexRenderer`) accept standard R3F group props like `position`, `rotation`, `scale`, `visible`.
|
|
353
322
|
|
|
354
323
|
```tsx
|
|
355
|
-
<SceneRenderer position={[0, 0, 1]} />
|
|
356
324
|
<ContactMarkers visible={showContacts} />
|
|
357
325
|
<Debug showJoints scale={0.5} />
|
|
358
326
|
```
|
|
@@ -420,9 +388,23 @@ Plays back recorded qpos trajectories with scrubbing.
|
|
|
420
388
|
|
|
421
389
|
## Hooks
|
|
422
390
|
|
|
391
|
+
### `useMujoco()`
|
|
392
|
+
|
|
393
|
+
Access the WASM module lifecycle from any child of `<MujocoProvider>`:
|
|
394
|
+
|
|
395
|
+
```tsx
|
|
396
|
+
const { mujoco, status, error } = useMujoco();
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
| Field | Type | Description |
|
|
400
|
+
|-------|------|-------------|
|
|
401
|
+
| `mujoco` | `MujocoModule \| null` | The raw WASM module, or `null` while loading |
|
|
402
|
+
| `status` | `'pending' \| 'error'` | Lifecycle state (absent once loaded) |
|
|
403
|
+
| `error` | `string \| null` | Error message if loading failed |
|
|
404
|
+
|
|
423
405
|
### `useMujocoSim()`
|
|
424
406
|
|
|
425
|
-
Access the simulation API and internal refs:
|
|
407
|
+
Access the simulation API and internal refs (must be inside `<MujocoCanvas>` or `<MujocoPhysics>`):
|
|
426
408
|
|
|
427
409
|
```tsx
|
|
428
410
|
const { api, mjModelRef, mjDataRef } = useMujocoSim();
|
|
@@ -679,7 +661,7 @@ The full API object available via `ref` or `useMujocoSim().api`:
|
|
|
679
661
|
|
|
680
662
|
### Building Controllers
|
|
681
663
|
|
|
682
|
-
See [Building Controllers](https://
|
|
664
|
+
See [Building Controllers](https://dadd.mintlify.app/guides/building-controllers) for full patterns including config-driven controllers, IK gizmo coexistence, multi-arm support, and the `createController` factory.
|
|
683
665
|
|
|
684
666
|
### Graspable Objects
|
|
685
667
|
|
|
@@ -701,7 +683,7 @@ sceneObjects: [{
|
|
|
701
683
|
}]
|
|
702
684
|
```
|
|
703
685
|
|
|
704
|
-
Without `condim: 4` and high friction, objects slide out of the gripper when lifted. See [Graspable Objects](https://
|
|
686
|
+
Without `condim: 4` and high friction, objects slide out of the gripper when lifted. See [Graspable Objects](https://dadd.mintlify.app/guides/graspable-objects) for details.
|
|
705
687
|
|
|
706
688
|
### Click-to-Select
|
|
707
689
|
|
|
@@ -714,14 +696,14 @@ function ClickSelectOverlay() {
|
|
|
714
696
|
}
|
|
715
697
|
```
|
|
716
698
|
|
|
717
|
-
See [Click-to-Select](https://
|
|
699
|
+
See [Click-to-Select](https://dadd.mintlify.app/guides/click-to-select) for the full implementation.
|
|
718
700
|
|
|
719
701
|
## useFrame Priority
|
|
720
702
|
|
|
721
703
|
| Priority | Owner | Purpose |
|
|
722
704
|
|----------|-------|---------|
|
|
723
705
|
| -1 | MujocoSimProvider | beforeStep, mj_step, afterStep |
|
|
724
|
-
| 0 (default) | SceneRenderer, IkController, your code | Body mesh sync, IK, rendering |
|
|
706
|
+
| 0 (default) | SceneRenderer (internal), IkController, your code | Body mesh sync, IK, rendering |
|
|
725
707
|
|
|
726
708
|
## Roadmap
|
|
727
709
|
|
package/dist/index.d.ts
CHANGED
|
@@ -718,12 +718,6 @@ declare function useIk(options: {
|
|
|
718
718
|
optional: true;
|
|
719
719
|
}): IkContextValue | null;
|
|
720
720
|
|
|
721
|
-
/**
|
|
722
|
-
* SceneRenderer — creates and syncs MuJoCo body meshes every frame.
|
|
723
|
-
* Accepts standard R3F group props (position, rotation, scale, visible, etc.).
|
|
724
|
-
*/
|
|
725
|
-
declare function SceneRenderer(props: Omit<ThreeElements['group'], 'ref'>): react_jsx_runtime.JSX.Element;
|
|
726
|
-
|
|
727
721
|
/**
|
|
728
722
|
* IkGizmo — drei PivotControls that tracks a MuJoCo site.
|
|
729
723
|
*
|
|
@@ -1160,4 +1154,4 @@ interface CameraAnimationAPI {
|
|
|
1160
1154
|
*/
|
|
1161
1155
|
declare function useCameraAnimation(): CameraAnimationAPI;
|
|
1162
1156
|
|
|
1163
|
-
export { type ActuatorInfo, type BodyInfo, type BodyStateResult, type CameraAnimationAPI, type ContactInfo, ContactListener, type ContactListenerProps, ContactMarkers, type ControllerComponent, type ControllerOptions, Debug, type DebugProps, DragInteraction, type DragInteractionProps, FlexRenderer, type GeomInfo, type IKSolveFn, type IkConfig, type IkContextValue, IkController, IkGizmo, type IkGizmoProps, type JointInfo, type JointStateResult, type KeyBinding, type KeyboardTeleopConfig, type ModelOptions, MujocoCanvas, type MujocoCanvasProps, type MujocoContact, type MujocoContactArray, type MujocoContextValue, type MujocoData, type MujocoModel, type MujocoModule, MujocoPhysics, type MujocoPhysicsProps, MujocoProvider, type MujocoSimAPI, MujocoSimProvider, type PhysicsConfig, type PhysicsStepCallback, type PolicyConfig, type RayHit, type SceneConfig, SceneLights, type SceneLightsProps, type SceneMarker, type SceneObject,
|
|
1157
|
+
export { type ActuatorInfo, type BodyInfo, type BodyStateResult, type CameraAnimationAPI, type ContactInfo, ContactListener, type ContactListenerProps, ContactMarkers, type ControllerComponent, type ControllerOptions, Debug, type DebugProps, DragInteraction, type DragInteractionProps, FlexRenderer, type GeomInfo, type IKSolveFn, type IkConfig, type IkContextValue, IkController, IkGizmo, type IkGizmoProps, type JointInfo, type JointStateResult, type KeyBinding, type KeyboardTeleopConfig, type ModelOptions, MujocoCanvas, type MujocoCanvasProps, type MujocoContact, type MujocoContactArray, type MujocoContextValue, type MujocoData, type MujocoModel, type MujocoModule, MujocoPhysics, type MujocoPhysicsProps, MujocoProvider, type MujocoSimAPI, MujocoSimProvider, type PhysicsConfig, type PhysicsStepCallback, type PolicyConfig, type RayHit, type SceneConfig, SceneLights, type SceneLightsProps, type SceneMarker, type SceneObject, SelectionHighlight, type SelectionHighlightProps, type SensorInfo, type SensorResult, type SiteInfo, type SitePositionResult, type StateSnapshot, TendonRenderer, type TrajectoryData, type TrajectoryFrame, TrajectoryPlayer, type TrajectoryPlayerProps, type XmlPatch, createController, findActuatorByName, findBodyByName, findGeomByName, findJointByName, findKeyframeByName, findSensorByName, findSiteByName, findTendonByName, getContact, getName, loadScene, useActuators, useAfterPhysicsStep, useBeforePhysicsStep, useBodyState, useCameraAnimation, useContactEvents, useContacts, useCtrl, useCtrlNoise, useGamepad, useGravityCompensation, useIk, useJointState, useKeyboardTeleop, useMujoco, useMujocoSim, usePolicy, useSceneLights, useSelectionHighlight, useSensor, useSensors, useSitePosition, useTrajectoryPlayer, useTrajectoryRecorder, useVideoRecorder };
|