mujoco-react 0.2.0 → 1.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 +287 -48
- package/dist/index.d.ts +215 -135
- package/dist/index.js +1176 -795
- package/dist/index.js.map +1 -1
- package/package.json +6 -4
- package/src/components/ContactMarkers.tsx +19 -22
- package/src/components/Debug.tsx +173 -36
- package/src/components/DragInteraction.tsx +5 -3
- package/src/components/FlexRenderer.tsx +3 -2
- package/src/components/IkController.tsx +262 -0
- package/src/components/IkGizmo.tsx +17 -25
- package/src/components/SceneLights.tsx +2 -112
- package/src/components/SceneRenderer.tsx +13 -8
- package/src/components/SelectionHighlight.tsx +2 -49
- package/src/components/TendonRenderer.tsx +93 -28
- package/src/components/TrajectoryPlayer.tsx +14 -10
- package/src/core/IkContext.tsx +40 -0
- package/src/core/MujocoCanvas.tsx +1 -5
- package/src/core/MujocoPhysics.tsx +79 -0
- package/src/core/MujocoProvider.tsx +12 -4
- package/src/core/MujocoSimProvider.tsx +56 -340
- package/src/core/SceneLoader.ts +45 -18
- package/src/core/createController.tsx +91 -0
- package/src/hooks/useCameraAnimation.ts +102 -0
- package/src/hooks/useContacts.ts +52 -22
- package/src/hooks/useJointState.ts +18 -2
- package/src/hooks/useSceneLights.ts +117 -0
- package/src/hooks/useSelectionHighlight.ts +65 -0
- package/src/index.ts +18 -1
- package/src/types.ts +53 -26
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# mujoco-react
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A thin, unopinionated wrapper around [mujoco-js](https://github.com/nicepkg/mujoco-js) — composable and extensible via React. Built on [React Three Fiber](https://docs.pmnd.rs/react-three-fiber). Works with **any robot, any scene**.
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
## Install
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
MujocoProvider,
|
|
17
17
|
MujocoCanvas,
|
|
18
18
|
SceneRenderer,
|
|
19
|
+
IkController,
|
|
19
20
|
IkGizmo,
|
|
20
21
|
} from 'mujoco-react';
|
|
21
22
|
import type { SceneConfig, MujocoSimAPI } from 'mujoco-react';
|
|
@@ -24,9 +25,6 @@ import { OrbitControls } from '@react-three/drei';
|
|
|
24
25
|
const config: SceneConfig = {
|
|
25
26
|
robotId: 'franka_emika_panda',
|
|
26
27
|
sceneFile: 'scene.xml',
|
|
27
|
-
numArmJoints: 7,
|
|
28
|
-
tcpSiteName: 'tcp',
|
|
29
|
-
gripperActuatorName: 'gripper',
|
|
30
28
|
homeJoints: [1.707, -1.754, 0.003, -2.702, 0.003, 0.951, 2.490],
|
|
31
29
|
};
|
|
32
30
|
|
|
@@ -44,7 +42,9 @@ function App() {
|
|
|
44
42
|
>
|
|
45
43
|
<OrbitControls enableDamping makeDefault />
|
|
46
44
|
<SceneRenderer />
|
|
47
|
-
<
|
|
45
|
+
<IkController config={{ siteName: 'tcp', numJoints: 7 }}>
|
|
46
|
+
<IkGizmo />
|
|
47
|
+
</IkController>
|
|
48
48
|
<ambientLight intensity={0.7} />
|
|
49
49
|
<directionalLight position={[1, 2, 5]} intensity={1.2} castShadow />
|
|
50
50
|
</MujocoCanvas>
|
|
@@ -55,20 +55,154 @@ function App() {
|
|
|
55
55
|
|
|
56
56
|
## Architecture
|
|
57
57
|
|
|
58
|
+
Two ways to set up your scene:
|
|
59
|
+
|
|
60
|
+
### `<MujocoCanvas>` — Quick Start
|
|
61
|
+
|
|
62
|
+
Wraps R3F `<Canvas>` for you. Fastest path to a working scene:
|
|
63
|
+
|
|
58
64
|
```
|
|
59
|
-
<MujocoProvider>
|
|
60
|
-
<MujocoCanvas config={...}>
|
|
61
|
-
<
|
|
62
|
-
<
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
<
|
|
66
|
-
<
|
|
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
|
|
67
73
|
</MujocoCanvas>
|
|
68
74
|
</MujocoProvider>
|
|
69
75
|
```
|
|
70
76
|
|
|
71
|
-
|
|
77
|
+
### `<MujocoPhysics>` — Bring Your Own Canvas
|
|
78
|
+
|
|
79
|
+
Use inside your own `<Canvas>` for full control over gl settings, post-processing, and R3F context composition:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
<MujocoProvider>
|
|
83
|
+
<Canvas shadows camera={...} gl={...}> <- Your Canvas, your settings
|
|
84
|
+
<MujocoPhysics config={config}> <- Physics context only
|
|
85
|
+
<SceneRenderer />
|
|
86
|
+
<YourController />
|
|
87
|
+
</MujocoPhysics>
|
|
88
|
+
<OrbitControls />
|
|
89
|
+
<EffectComposer>...</EffectComposer> <- Post-processing, etc.
|
|
90
|
+
</Canvas>
|
|
91
|
+
</MujocoProvider>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The library provides **only MuJoCo engine concerns**: WASM lifecycle, physics stepping, and body rendering. Controllers (IK, teleoperation, RL policies) are composable plugins you opt into — or bring your own.
|
|
95
|
+
|
|
96
|
+
## Bring Your Own Controller
|
|
97
|
+
|
|
98
|
+
**Controllers are just React components.** Write a function that calls `useBeforePhysicsStep` to drive `data.ctrl` each frame, return `null`, and drop it into your scene tree. No base class, no registration — just hooks.
|
|
99
|
+
|
|
100
|
+
```tsx
|
|
101
|
+
import { useBeforePhysicsStep } from 'mujoco-react';
|
|
102
|
+
|
|
103
|
+
function MyController() {
|
|
104
|
+
useBeforePhysicsStep((_model, data) => {
|
|
105
|
+
data.ctrl[0] = Math.sin(data.time); // sine wave on actuator 0
|
|
106
|
+
data.ctrl[1] = data.sensordata[0] * -0.5; // feedback from a sensor
|
|
107
|
+
});
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Drop it in:
|
|
112
|
+
<MujocoCanvas config={config}>
|
|
113
|
+
<SceneRenderer />
|
|
114
|
+
<MyController />
|
|
115
|
+
</MujocoCanvas>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
This is the primary way to use the library. IK, teleoperation, RL policies, state machines — they're all just components that read input and write to `data.ctrl`.
|
|
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:
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
import type { IKSolveFn } from 'mujoco-react';
|
|
126
|
+
|
|
127
|
+
const myIK: IKSolveFn = (pos, quat, currentQ) => {
|
|
128
|
+
return myAnalyticalSolver(pos, currentQ); // return joint angles or null
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
<IkController config={{ siteName: 'tcp', numJoints: 7, ikSolveFn: myIK }}>
|
|
132
|
+
<IkGizmo />
|
|
133
|
+
</IkController>
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Or skip `<IkController>` entirely and solve IK yourself inside `useBeforePhysicsStep`:
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
function MyIKController() {
|
|
140
|
+
useBeforePhysicsStep((model, data) => {
|
|
141
|
+
const joints = myCustomIKSolve(model, data);
|
|
142
|
+
if (joints) {
|
|
143
|
+
for (let i = 0; i < joints.length; i++) data.ctrl[i] = joints[i];
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### `createController<TConfig>()` Factory
|
|
151
|
+
|
|
152
|
+
For reusable controller plugins with typed config and default merging:
|
|
153
|
+
|
|
154
|
+
```tsx
|
|
155
|
+
import { createController, useBeforePhysicsStep } from 'mujoco-react';
|
|
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
|
+
}
|
|
168
|
+
|
|
169
|
+
export const MyController = createController<MyConfig>(
|
|
170
|
+
{ name: 'MyController', defaultConfig: { gain: 1.0 } },
|
|
171
|
+
MyControllerImpl,
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
// Usage: <MyController config={{ gain: 2.0, targetJoint: 'shoulder' }} />
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Built-in `<IkController>`
|
|
178
|
+
|
|
179
|
+
The library ships one controller out of the box — an IK gizmo you can drop in for interactive end-effector control:
|
|
180
|
+
|
|
181
|
+
```tsx
|
|
182
|
+
<IkController config={{ siteName: 'tcp', numJoints: 7 }}>
|
|
183
|
+
<IkGizmo />
|
|
184
|
+
</IkController>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
| Config | Type | Default | Description |
|
|
188
|
+
|--------|------|---------|-------------|
|
|
189
|
+
| `siteName` | `string` | **required** | MuJoCo site to track |
|
|
190
|
+
| `numJoints` | `number` | **required** | Number of joints for IK |
|
|
191
|
+
| `ikSolveFn` | `IKSolveFn` | built-in DLS | Custom solver function |
|
|
192
|
+
| `damping` | `number` | `0.01` | DLS damping |
|
|
193
|
+
| `maxIterations` | `number` | `50` | Max solver iterations |
|
|
194
|
+
|
|
195
|
+
Access IK state from inside `<IkController>` with `useIk()`:
|
|
196
|
+
|
|
197
|
+
```tsx
|
|
198
|
+
const { setIkEnabled, moveTarget, solveIK } = useIk();
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Pass `{ optional: true }` for components that may or may not be inside an `<IkController>`:
|
|
202
|
+
|
|
203
|
+
```tsx
|
|
204
|
+
const ikCtx = useIk({ optional: true });
|
|
205
|
+
```
|
|
72
206
|
|
|
73
207
|
## Loading Models
|
|
74
208
|
|
|
@@ -85,7 +219,7 @@ const franka: SceneConfig = {
|
|
|
85
219
|
const so101: SceneConfig = {
|
|
86
220
|
robotId: 'so101',
|
|
87
221
|
sceneFile: 'SO101.xml',
|
|
88
|
-
baseUrl: 'https://raw.githubusercontent.com/
|
|
222
|
+
baseUrl: 'https://raw.githubusercontent.com/your-org/your-repo/main/models/',
|
|
89
223
|
};
|
|
90
224
|
|
|
91
225
|
// Self-hosted
|
|
@@ -106,9 +240,6 @@ interface SceneConfig {
|
|
|
106
240
|
sceneFile: string; // Entry XML file, e.g. 'scene.xml'
|
|
107
241
|
baseUrl?: string; // Base URL for fetching model files
|
|
108
242
|
sceneObjects?: SceneObject[]; // Objects injected into scene XML at load time
|
|
109
|
-
tcpSiteName?: string; // MuJoCo site for IK. Default: 'tcp'
|
|
110
|
-
gripperActuatorName?: string; // Gripper actuator name. Default: 'gripper'
|
|
111
|
-
numArmJoints?: number; // Number of arm joints for IK. Default: 7
|
|
112
243
|
homeJoints?: number[]; // Initial joint positions
|
|
113
244
|
xmlPatches?: XmlPatch[]; // Patches applied to XML files during loading
|
|
114
245
|
onReset?: (model, data) => void; // Called during reset after mj_resetData
|
|
@@ -168,28 +299,64 @@ Thin wrapper around R3F `<Canvas>`. Accepts all R3F Canvas props plus:
|
|
|
168
299
|
| `substeps` | `number` | mj_step calls per frame |
|
|
169
300
|
| `paused` | `boolean` | Declarative pause |
|
|
170
301
|
| `speed` | `number` | Simulation speed multiplier |
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
302
|
+
|
|
303
|
+
### `<MujocoPhysics>`
|
|
304
|
+
|
|
305
|
+
Physics provider for use inside your own R3F `<Canvas>`. Same physics props as `<MujocoCanvas>` without the Canvas wrapper. Accepts a `ref` for the `MujocoSimAPI`.
|
|
306
|
+
|
|
307
|
+
```tsx
|
|
308
|
+
<MujocoProvider>
|
|
309
|
+
<Canvas shadows camera={{ position: [2, 2, 2] }}>
|
|
310
|
+
<MujocoPhysics ref={apiRef} config={config} paused={paused}>
|
|
311
|
+
<SceneRenderer />
|
|
312
|
+
<MyController />
|
|
313
|
+
</MujocoPhysics>
|
|
314
|
+
<OrbitControls />
|
|
315
|
+
</Canvas>
|
|
316
|
+
</MujocoProvider>
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
| Prop | Type | Description |
|
|
320
|
+
|------|------|-------------|
|
|
321
|
+
| `config` | `SceneConfig` | **Required.** Scene/robot configuration |
|
|
322
|
+
| `onReady` | `(api: MujocoSimAPI) => void` | Fires when model is loaded |
|
|
323
|
+
| `onError` | `(error: Error) => void` | Fires on scene load failure |
|
|
324
|
+
| `onStep` | `(time: number) => void` | Called each physics step |
|
|
325
|
+
| `onSelection` | `(bodyId: number, name: string) => void` | Called on double-click |
|
|
326
|
+
| `gravity` | `[number, number, number]` | Override model gravity |
|
|
327
|
+
| `timestep` | `number` | Override model.opt.timestep |
|
|
328
|
+
| `substeps` | `number` | mj_step calls per frame |
|
|
329
|
+
| `paused` | `boolean` | Declarative pause |
|
|
330
|
+
| `speed` | `number` | Simulation speed multiplier |
|
|
174
331
|
|
|
175
332
|
### `<SceneRenderer />`
|
|
176
333
|
|
|
177
|
-
Syncs MuJoCo bodies to Three.js meshes every frame. Must be inside `<MujocoCanvas>`.
|
|
334
|
+
Syncs MuJoCo bodies to Three.js meshes every frame. Must be inside `<MujocoCanvas>` or `<MujocoPhysics>`.
|
|
178
335
|
|
|
179
336
|
### `<IkGizmo />`
|
|
180
337
|
|
|
181
|
-
drei PivotControls gizmo that tracks a MuJoCo site and drives IK on drag.
|
|
338
|
+
drei PivotControls gizmo that tracks a MuJoCo site and drives IK on drag. Must be inside `<IkController>`.
|
|
182
339
|
|
|
183
340
|
| Prop | Type | Default | Description |
|
|
184
341
|
|------|------|---------|-------------|
|
|
185
|
-
| `siteName` | `string?` |
|
|
342
|
+
| `siteName` | `string?` | IkController's site | MuJoCo site to track |
|
|
186
343
|
| `scale` | `number?` | `0.18` | Gizmo handle scale |
|
|
187
|
-
| `onDrag` | `(pos, quat) => void` |
|
|
344
|
+
| `onDrag` | `(pos, quat) => void` | -- | Custom drag handler (disables auto-IK) |
|
|
188
345
|
|
|
189
346
|
### `<DragInteraction />`
|
|
190
347
|
|
|
191
348
|
Click-drag to apply spring forces to bodies. Raycasts to find bodies, applies `F = (mouseWorld - grabWorld) * body_mass * stiffness` via `mj_applyFT`.
|
|
192
349
|
|
|
350
|
+
### R3F Group Props
|
|
351
|
+
|
|
352
|
+
All visual components (`SceneRenderer`, `DragInteraction`, `ContactMarkers`, `Debug`, `TendonRenderer`, `FlexRenderer`) accept standard R3F group props — `position`, `rotation`, `scale`, `visible`, etc.
|
|
353
|
+
|
|
354
|
+
```tsx
|
|
355
|
+
<SceneRenderer position={[0, 0, 1]} />
|
|
356
|
+
<ContactMarkers visible={showContacts} />
|
|
357
|
+
<Debug showJoints scale={0.5} />
|
|
358
|
+
```
|
|
359
|
+
|
|
193
360
|
### `<ContactMarkers />`
|
|
194
361
|
|
|
195
362
|
InstancedMesh showing MuJoCo contact points for debugging.
|
|
@@ -197,12 +364,13 @@ InstancedMesh showing MuJoCo contact points for debugging.
|
|
|
197
364
|
| Prop | Type | Default | Description |
|
|
198
365
|
|------|------|---------|-------------|
|
|
199
366
|
| `maxContacts` | `number?` | `100` | Max contacts to display |
|
|
200
|
-
| `
|
|
201
|
-
| `color` | `string?` | `'
|
|
367
|
+
| `radius` | `number?` | `0.005` | Marker sphere radius |
|
|
368
|
+
| `color` | `string?` | `'#4f46e5'` | Marker color |
|
|
369
|
+
| `visible` | `boolean?` | `true` | Toggle visibility |
|
|
202
370
|
|
|
203
371
|
### `<SceneLights />`
|
|
204
372
|
|
|
205
|
-
Auto-creates Three.js lights from MJCF `<light>` elements.
|
|
373
|
+
Auto-creates Three.js lights from MJCF `<light>` elements. Also available as `useSceneLights(intensity?)` hook.
|
|
206
374
|
|
|
207
375
|
### `<Debug />`
|
|
208
376
|
|
|
@@ -215,6 +383,12 @@ Visualization overlays:
|
|
|
215
383
|
| `showJoints` | `boolean?` | `false` | Joint axes |
|
|
216
384
|
| `showContacts` | `boolean?` | `false` | Contact force vectors |
|
|
217
385
|
| `showCOM` | `boolean?` | `false` | Center of mass markers |
|
|
386
|
+
| `showInertia` | `boolean?` | `false` | Inertia ellipsoids |
|
|
387
|
+
| `showTendons` | `boolean?` | `false` | Tendon paths |
|
|
388
|
+
| `geomColor` | `string?` | `'#00ff00'` | Color for wireframe geoms |
|
|
389
|
+
| `siteColor` | `string?` | `'#ff00ff'` | Color for site markers |
|
|
390
|
+
| `contactColor` | `string?` | `'#ff4444'` | Color for contact force arrows |
|
|
391
|
+
| `comColor` | `string?` | `'#ff0000'` | Color for COM markers |
|
|
218
392
|
|
|
219
393
|
### `<TendonRenderer />`
|
|
220
394
|
|
|
@@ -238,7 +412,7 @@ Component wrapper for contact events:
|
|
|
238
412
|
|
|
239
413
|
### `<SelectionHighlight />`
|
|
240
414
|
|
|
241
|
-
Emissive highlight on selected body meshes.
|
|
415
|
+
Emissive highlight on selected body meshes. Also available as `useSelectionHighlight(bodyId, options?)` hook.
|
|
242
416
|
|
|
243
417
|
### `<TrajectoryPlayer />`
|
|
244
418
|
|
|
@@ -268,6 +442,25 @@ useBeforePhysicsStep((model, data) => {
|
|
|
268
442
|
|
|
269
443
|
Run logic **after** `mj_step` each frame. Read results, compute rewards, log telemetry.
|
|
270
444
|
|
|
445
|
+
### `useIk()` / `useIk({ optional: true })`
|
|
446
|
+
|
|
447
|
+
Access IK controller state. `useIk()` throws if not inside `<IkController>`. Pass `{ optional: true }` to get `null` instead.
|
|
448
|
+
|
|
449
|
+
### `useCameraAnimation()`
|
|
450
|
+
|
|
451
|
+
Standalone camera animation hook:
|
|
452
|
+
|
|
453
|
+
```tsx
|
|
454
|
+
const { getCameraState, moveCameraTo } = useCameraAnimation();
|
|
455
|
+
|
|
456
|
+
// Animate camera over 1 second
|
|
457
|
+
await moveCameraTo(
|
|
458
|
+
new THREE.Vector3(3, 0, 2),
|
|
459
|
+
new THREE.Vector3(0, 0, 0.5),
|
|
460
|
+
1000
|
|
461
|
+
);
|
|
462
|
+
```
|
|
463
|
+
|
|
271
464
|
### `useSensor(name)` / `useSensors()`
|
|
272
465
|
|
|
273
466
|
Read sensor values by name (ref-based, no re-renders):
|
|
@@ -367,7 +560,7 @@ Record the canvas as video:
|
|
|
367
560
|
|
|
368
561
|
```tsx
|
|
369
562
|
const video = useVideoRecorder({ fps: 30, mimeType: 'video/webm' });
|
|
370
|
-
// video.start(), video.stop()
|
|
563
|
+
// video.start(), video.stop() -> returns Blob
|
|
371
564
|
```
|
|
372
565
|
|
|
373
566
|
### `useCtrlNoise(config)`
|
|
@@ -390,6 +583,22 @@ Returns actuator metadata for building control UIs.
|
|
|
390
583
|
|
|
391
584
|
Ref-based site position/quaternion tracking.
|
|
392
585
|
|
|
586
|
+
### `useSelectionHighlight(bodyId, options?)`
|
|
587
|
+
|
|
588
|
+
Hook form of `<SelectionHighlight>`. Apply emissive highlights imperatively:
|
|
589
|
+
|
|
590
|
+
```tsx
|
|
591
|
+
useSelectionHighlight(selectedBodyId, { color: '#00ff00', emissiveIntensity: 0.5 });
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
### `useSceneLights(intensity?)`
|
|
595
|
+
|
|
596
|
+
Hook form of `<SceneLights>`. Create Three.js lights from MJCF definitions imperatively:
|
|
597
|
+
|
|
598
|
+
```tsx
|
|
599
|
+
useSceneLights(1.5);
|
|
600
|
+
```
|
|
601
|
+
|
|
393
602
|
## MujocoSimAPI
|
|
394
603
|
|
|
395
604
|
The full API object available via `ref` or `useMujocoSim().api`:
|
|
@@ -458,31 +667,61 @@ The full API object available via `ref` or `useMujocoSim().api`:
|
|
|
458
667
|
|--------|-------------|
|
|
459
668
|
| `raycast(origin, direction, maxDist?)` | Physics raycast via `mj_ray` |
|
|
460
669
|
| `project2DTo3D(x, y, camPos, lookAt)` | Screen-to-world raycast (returns bodyId + geomId) |
|
|
461
|
-
| `
|
|
462
|
-
| `moveCameraTo(pos, target, ms)` | Smooth camera animation |
|
|
463
|
-
|
|
464
|
-
### IK Control
|
|
465
|
-
|
|
466
|
-
| Method | Description |
|
|
467
|
-
|--------|-------------|
|
|
468
|
-
| `setIkEnabled(enabled)` | Enable/disable IK tracking |
|
|
469
|
-
| `moveTarget(pos, duration?)` | Move IK target with optional animation |
|
|
470
|
-
| `syncTargetToSite()` | Snap IK target to current TCP position |
|
|
471
|
-
| `solveIK(pos, quat, currentQ)` | Solve IK for a target pose |
|
|
670
|
+
| `getCanvasSnapshot(w?, h?, mime?)` | Base64 screenshot |
|
|
472
671
|
|
|
473
672
|
### Scene Management
|
|
474
673
|
|
|
475
674
|
| Method | Description |
|
|
476
675
|
|--------|-------------|
|
|
477
676
|
| `loadScene(newConfig)` | Runtime model swap |
|
|
478
|
-
|
|
677
|
+
|
|
678
|
+
## Guides
|
|
679
|
+
|
|
680
|
+
### Building Controllers
|
|
681
|
+
|
|
682
|
+
See [Building Controllers](https://mujoco-react.mintlify.app/guides/building-controllers) for full patterns including config-driven controllers, IK gizmo coexistence, multi-arm support, and the `createController` factory.
|
|
683
|
+
|
|
684
|
+
### Graspable Objects
|
|
685
|
+
|
|
686
|
+
Objects need specific MuJoCo contact parameters to be picked up by grippers:
|
|
687
|
+
|
|
688
|
+
```tsx
|
|
689
|
+
sceneObjects: [{
|
|
690
|
+
name: 'cube',
|
|
691
|
+
type: 'box',
|
|
692
|
+
size: [0.025, 0.025, 0.025],
|
|
693
|
+
position: [0.4, 0, 0.025],
|
|
694
|
+
rgba: [0.9, 0.2, 0.15, 1],
|
|
695
|
+
mass: 0.05,
|
|
696
|
+
freejoint: true,
|
|
697
|
+
friction: '1.5 0.3 0.1', // high sliding friction
|
|
698
|
+
solref: '0.01 1', // stiff contact solver
|
|
699
|
+
solimp: '0.95 0.99 0.001 0.5 2', // tight impedance
|
|
700
|
+
condim: 4, // elliptic friction cone
|
|
701
|
+
}]
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
Without `condim: 4` and high friction, objects slide out of the gripper when lifted. See [Graspable Objects](https://mujoco-react.mintlify.app/guides/graspable-objects) for details.
|
|
705
|
+
|
|
706
|
+
### Click-to-Select
|
|
707
|
+
|
|
708
|
+
Combine R3F raycasting with `<SelectionHighlight />` for body selection:
|
|
709
|
+
|
|
710
|
+
```tsx
|
|
711
|
+
function ClickSelectOverlay() {
|
|
712
|
+
const selectedBodyId = useClickSelect(); // your raycasting hook
|
|
713
|
+
return <SelectionHighlight bodyId={selectedBodyId} />;
|
|
714
|
+
}
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
See [Click-to-Select](https://mujoco-react.mintlify.app/guides/click-to-select) for the full implementation.
|
|
479
718
|
|
|
480
719
|
## useFrame Priority
|
|
481
720
|
|
|
482
721
|
| Priority | Owner | Purpose |
|
|
483
722
|
|----------|-------|---------|
|
|
484
|
-
| -1 | MujocoSimProvider | beforeStep,
|
|
485
|
-
| 0 (default) | SceneRenderer, your code | Body mesh sync, rendering |
|
|
723
|
+
| -1 | MujocoSimProvider | beforeStep, mj_step, afterStep |
|
|
724
|
+
| 0 (default) | SceneRenderer, IkController, your code | Body mesh sync, IK, rendering |
|
|
486
725
|
|
|
487
726
|
## Roadmap
|
|
488
727
|
|
|
@@ -490,11 +729,11 @@ Features planned but not yet implemented:
|
|
|
490
729
|
|
|
491
730
|
| Feature | Priority | Description |
|
|
492
731
|
|---------|----------|-------------|
|
|
493
|
-
| **User-uploaded model loading** | P2 | `loadFromFiles(FileList)`
|
|
732
|
+
| **User-uploaded model loading** | P2 | `loadFromFiles(FileList)` -- detect meshdir, write to VFS |
|
|
494
733
|
| **URDF loading** | P2 | Load URDF models via MuJoCo's built-in URDF compiler |
|
|
495
734
|
| **XML mutation / recompile** | P1 | `addBody()`, `removeBody()`, `recompile()` for runtime XML editing |
|
|
496
735
|
| **Observation builder utilities** | P2 | Helpers for projected gravity, joint positions/velocities for RL |
|
|
497
|
-
| **Physics interpolation** | P1 | Smooth rendering between physics ticks for
|
|
736
|
+
| **Physics interpolation** | P1 | Smooth rendering between physics ticks for very high refresh displays |
|
|
498
737
|
| **Instanced geom rendering** | P2 | `<InstancedGeomRenderer />` for particle/granular sims |
|
|
499
738
|
| **Web Worker physics** | P2 | Run `mj_step` off main thread via SharedArrayBuffer |
|
|
500
739
|
|
|
@@ -502,8 +741,8 @@ Features planned but not yet implemented:
|
|
|
502
741
|
|
|
503
742
|
These MuJoCo features are not yet exposed in the WASM binding:
|
|
504
743
|
|
|
505
|
-
- `flex_faceadr` / `flex_facenum` / `flex_face`
|
|
506
|
-
- `ten_rgba` / `ten_width`
|
|
744
|
+
- `flex_faceadr` / `flex_facenum` / `flex_face` -- FlexRenderer renders vertices without face indices
|
|
745
|
+
- `ten_rgba` / `ten_width` -- TendonRenderer uses default color/width
|
|
507
746
|
|
|
508
747
|
## License
|
|
509
748
|
|