mujoco-react 8.6.0 → 8.8.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 +103 -45
- package/bin/mujoco-react.mjs +14 -2
- package/dist/index.d.ts +22 -1
- package/dist/index.js.map +1 -1
- package/dist/vite.d.ts +5 -4
- package/dist/vite.js +74 -8
- package/dist/vite.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +10 -0
- package/src/types.ts +27 -0
- package/src/vite.ts +103 -12
package/README.md
CHANGED
|
@@ -18,6 +18,83 @@ Composable [React Three Fiber](https://docs.pmnd.rs/react-three-fiber) wrapper a
|
|
|
18
18
|
npm install mujoco-react three @react-three/fiber @react-three/drei
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
## Vite Plugin and Type-Safe Names
|
|
22
|
+
|
|
23
|
+
Use the Vite plugin to generate TanStack-style declaration merging for actuator, sensor, body, joint, site, geom, and keyframe names:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
// vite.config.ts
|
|
27
|
+
import { defineConfig } from "vite";
|
|
28
|
+
import { mujocoReact } from "mujoco-react/vite";
|
|
29
|
+
|
|
30
|
+
export default defineConfig({
|
|
31
|
+
plugins: [
|
|
32
|
+
mujocoReact({
|
|
33
|
+
models: {
|
|
34
|
+
franka: "models/panda/scene.xml",
|
|
35
|
+
spot: "models/spot/scene.xml",
|
|
36
|
+
},
|
|
37
|
+
}),
|
|
38
|
+
],
|
|
39
|
+
});
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The plugin writes `src/mujoco-register.gen.d.ts` during dev and build. Commit that generated file:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
// src/mujoco-register.gen.d.ts
|
|
46
|
+
// Auto-generated by mujoco-react. Do not edit.
|
|
47
|
+
|
|
48
|
+
import "mujoco-react";
|
|
49
|
+
import type { RobotResource } from "mujoco-react";
|
|
50
|
+
|
|
51
|
+
declare module "mujoco-react" {
|
|
52
|
+
interface Register {
|
|
53
|
+
robots: {
|
|
54
|
+
franka: {
|
|
55
|
+
actuators: "joint1" | "joint2" | "joint3" | "gripper";
|
|
56
|
+
sensors: "force_sensor" | "torque_sensor";
|
|
57
|
+
bodies: "link0" | "link1" | "hand";
|
|
58
|
+
joints: "joint1" | "joint2" | "joint3";
|
|
59
|
+
sites: "tcp";
|
|
60
|
+
geoms: "floor";
|
|
61
|
+
keyframes: "home";
|
|
62
|
+
};
|
|
63
|
+
spot: {
|
|
64
|
+
actuators: "fl_hx" | "fl_hy" | "fl_kn";
|
|
65
|
+
sensors: never;
|
|
66
|
+
bodies: "body" | "fl_hip" | "fl_uleg";
|
|
67
|
+
joints: "fl_hx" | "fl_hy" | "fl_kn";
|
|
68
|
+
sites: never;
|
|
69
|
+
geoms: "floor";
|
|
70
|
+
keyframes: "home";
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
actuators: "joint1" | "joint2" | "joint3" | "gripper" | "fl_hx" | "fl_hy" | "fl_kn";
|
|
74
|
+
sensors: "force_sensor" | "torque_sensor";
|
|
75
|
+
bodies: "link0" | "link1" | "hand" | "body" | "fl_hip" | "fl_uleg";
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export namespace RobotActuators {
|
|
79
|
+
export type franka = RobotResource<"franka", "actuators">;
|
|
80
|
+
export type spot = RobotResource<"spot", "actuators">;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export namespace RobotSites {
|
|
84
|
+
export type franka = RobotResource<"franka", "sites">;
|
|
85
|
+
export type spot = RobotResource<"spot", "sites">;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Once generated, hooks like `useCtrl`, `useSensor`, `useBodyState`, and API methods like `setCtrl`, `applyForce`, `getSensorData` accept the global union. For robot-scoped reusable code, use generated namespace types such as `RobotActuators.franka`, `RobotSites.franka`, and `RobotBodies.franka`. Generic helpers like `RobotActuators<"franka">` are still available for reusable library code. When no `Register` augmentation is present, names fall back to `string`.
|
|
91
|
+
|
|
92
|
+
Non-Vite projects can generate the same file with:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
npx mujoco-react codegen franka=models/panda/scene.xml spot=models/spot/scene.xml
|
|
96
|
+
```
|
|
97
|
+
|
|
21
98
|
## Load a Model
|
|
22
99
|
|
|
23
100
|
```tsx
|
|
@@ -87,6 +164,23 @@ function MyController() {
|
|
|
87
164
|
|
|
88
165
|
Controllers are just React children that read sensors, write `data.ctrl`, apply forces, or call the `MujocoSimAPI` at physics-step time.
|
|
89
166
|
|
|
167
|
+
With generated resource types, reusable controllers can be scoped to one robot. Configure stable robot keys in the Vite plugin, then use those keys in helper types:
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
import { useCtrl, useIkController } from "mujoco-react";
|
|
171
|
+
import type { RobotActuators, RobotSites } from "mujoco-react";
|
|
172
|
+
|
|
173
|
+
const frankaGripper: RobotActuators.franka = "gripper";
|
|
174
|
+
const frankaTcp: RobotSites.franka = "tcp";
|
|
175
|
+
|
|
176
|
+
function FrankaTypedControls() {
|
|
177
|
+
const gripper = useCtrl(frankaGripper);
|
|
178
|
+
const ik = useIkController({ siteName: frankaTcp });
|
|
179
|
+
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
90
184
|
## Use the Sim API
|
|
91
185
|
|
|
92
186
|
```tsx
|
|
@@ -304,49 +398,6 @@ const gripperIk = useIkController({
|
|
|
304
398
|
});
|
|
305
399
|
```
|
|
306
400
|
|
|
307
|
-
## Type-Safe Resource Names
|
|
308
|
-
|
|
309
|
-
Use the Vite plugin to generate TanStack-style declaration merging for actuator, sensor, body, joint, site, geom, and keyframe names:
|
|
310
|
-
|
|
311
|
-
```ts
|
|
312
|
-
// vite.config.ts
|
|
313
|
-
import { defineConfig } from "vite";
|
|
314
|
-
import { mujocoReact } from "mujoco-react/vite";
|
|
315
|
-
|
|
316
|
-
export default defineConfig({
|
|
317
|
-
plugins: [
|
|
318
|
-
mujocoReact({
|
|
319
|
-
models: "models/panda/scene.xml",
|
|
320
|
-
}),
|
|
321
|
-
],
|
|
322
|
-
});
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
The plugin writes `src/mujoco-register.gen.d.ts` during dev and build. Commit that generated file:
|
|
326
|
-
|
|
327
|
-
```ts
|
|
328
|
-
// src/mujoco-register.gen.d.ts
|
|
329
|
-
// Auto-generated by mujoco-react. Do not edit.
|
|
330
|
-
|
|
331
|
-
import "mujoco-react";
|
|
332
|
-
|
|
333
|
-
declare module "mujoco-react" {
|
|
334
|
-
interface Register {
|
|
335
|
-
actuators: "joint1" | "joint2" | "joint3" | "gripper";
|
|
336
|
-
sensors: "force_sensor" | "torque_sensor";
|
|
337
|
-
bodies: "link0" | "link1" | "hand";
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
Once generated, hooks like `useCtrl`, `useSensor`, `useBodyState`, and API methods like `setCtrl`, `applyForce`, `getSensorData` will only accept the declared names. When no `Register` augmentation is present, names fall back to `string`.
|
|
343
|
-
|
|
344
|
-
Non-Vite projects can generate the same file with:
|
|
345
|
-
|
|
346
|
-
```bash
|
|
347
|
-
npx mujoco-react codegen models/panda/scene.xml
|
|
348
|
-
```
|
|
349
|
-
|
|
350
401
|
## Loading Models
|
|
351
402
|
|
|
352
403
|
The loader fetches `src + sceneFile`, parses the XML for dependencies (meshes, textures, includes), recursively fetches those too, and writes everything to MuJoCo's in-memory WASM filesystem.
|
|
@@ -384,15 +435,22 @@ interface SceneConfig {
|
|
|
384
435
|
Load browser-selected MJCF or URDF files directly. Folder uploads preserve `webkitRelativePath`, and flat uploads fall back to matching referenced mesh/texture assets by basename:
|
|
385
436
|
|
|
386
437
|
```tsx
|
|
438
|
+
import { useEffect, useRef } from "react";
|
|
439
|
+
import { useMujoco } from "mujoco-react";
|
|
440
|
+
|
|
387
441
|
function ModelUpload() {
|
|
388
442
|
const sim = useMujoco();
|
|
443
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
|
444
|
+
|
|
445
|
+
useEffect(() => {
|
|
446
|
+
inputRef.current?.setAttribute("webkitdirectory", "");
|
|
447
|
+
}, []);
|
|
389
448
|
|
|
390
449
|
return (
|
|
391
450
|
<input
|
|
451
|
+
ref={inputRef}
|
|
392
452
|
type="file"
|
|
393
453
|
multiple
|
|
394
|
-
// @ts-expect-error Chromium/WebKit folder uploads
|
|
395
|
-
webkitdirectory=""
|
|
396
454
|
onChange={(event) => {
|
|
397
455
|
if (sim.isReady && event.currentTarget.files) {
|
|
398
456
|
sim.api.loadFromFiles(event.currentTarget.files);
|
package/bin/mujoco-react.mjs
CHANGED
|
@@ -6,13 +6,14 @@ import { generateMujocoRegister } from '../dist/vite.js';
|
|
|
6
6
|
const usage = `
|
|
7
7
|
Usage:
|
|
8
8
|
mujoco-react codegen <scene.xml> [...more.xml] [--out src/mujoco-register.gen.d.ts] [--watch]
|
|
9
|
+
mujoco-react codegen franka=models/panda/scene.xml spot=models/spot/scene.xml
|
|
9
10
|
|
|
10
11
|
Vite users usually do not need this command. Prefer:
|
|
11
12
|
|
|
12
13
|
import { mujocoReact } from "mujoco-react/vite";
|
|
13
14
|
|
|
14
15
|
export default defineConfig({
|
|
15
|
-
plugins: [mujocoReact({ models: "models/panda/scene.xml" })],
|
|
16
|
+
plugins: [mujocoReact({ models: { franka: "models/panda/scene.xml" } })],
|
|
16
17
|
});
|
|
17
18
|
`;
|
|
18
19
|
|
|
@@ -39,6 +40,7 @@ const models = commandArgs.filter((arg, index) => {
|
|
|
39
40
|
const previous = commandArgs[index - 1];
|
|
40
41
|
return previous !== '--out' && previous !== '--module';
|
|
41
42
|
});
|
|
43
|
+
const modelInput = parseModels(models);
|
|
42
44
|
|
|
43
45
|
if (!models.length) {
|
|
44
46
|
console.error(usage.trim());
|
|
@@ -69,7 +71,7 @@ if (shouldWatch) {
|
|
|
69
71
|
|
|
70
72
|
async function generate() {
|
|
71
73
|
const result = await generateMujocoRegister({
|
|
72
|
-
models,
|
|
74
|
+
models: modelInput,
|
|
73
75
|
out,
|
|
74
76
|
moduleName,
|
|
75
77
|
root: process.cwd(),
|
|
@@ -79,6 +81,16 @@ async function generate() {
|
|
|
79
81
|
console.log(`[mujoco-react] generated ${path.relative(process.cwd(), result.out)} (${total} names)`);
|
|
80
82
|
}
|
|
81
83
|
|
|
84
|
+
function parseModels(values) {
|
|
85
|
+
if (values.every((value) => value.includes('='))) {
|
|
86
|
+
return Object.fromEntries(values.map((value) => {
|
|
87
|
+
const index = value.indexOf('=');
|
|
88
|
+
return [value.slice(0, index), value.slice(index + 1)];
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
return values;
|
|
92
|
+
}
|
|
93
|
+
|
|
82
94
|
function valueAfter(values, flag) {
|
|
83
95
|
const index = values.indexOf(flag);
|
|
84
96
|
if (index === -1) return undefined;
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,13 @@ import * as THREE from 'three';
|
|
|
16
16
|
* ```ts
|
|
17
17
|
* declare module 'mujoco-react' {
|
|
18
18
|
* interface Register {
|
|
19
|
+
* robots: {
|
|
20
|
+
* panda: {
|
|
21
|
+
* actuators: 'joint1' | 'joint2' | 'gripper';
|
|
22
|
+
* sensors: 'force_sensor' | 'torque_sensor';
|
|
23
|
+
* bodies: 'link0' | 'link1' | 'hand';
|
|
24
|
+
* };
|
|
25
|
+
* };
|
|
19
26
|
* actuators: 'joint1' | 'joint2' | 'gripper';
|
|
20
27
|
* sensors: 'force_sensor' | 'torque_sensor';
|
|
21
28
|
* bodies: 'link0' | 'link1' | 'hand';
|
|
@@ -27,6 +34,20 @@ import * as THREE from 'three';
|
|
|
27
34
|
*/
|
|
28
35
|
interface Register {
|
|
29
36
|
}
|
|
37
|
+
type RegisteredRobotMap = Register extends {
|
|
38
|
+
robots: infer T extends Record<string, Record<string, string>>;
|
|
39
|
+
} ? T : never;
|
|
40
|
+
type Robots = [RegisteredRobotMap] extends [never] ? string : Extract<keyof RegisteredRobotMap, string>;
|
|
41
|
+
type RobotResource<TRobot extends string, TKey extends string> = [
|
|
42
|
+
RegisteredRobotMap
|
|
43
|
+
] extends [never] ? string : TRobot extends keyof RegisteredRobotMap ? TKey extends keyof RegisteredRobotMap[TRobot] ? RegisteredRobotMap[TRobot][TKey] : string : never;
|
|
44
|
+
type RobotActuators<TRobot extends string> = RobotResource<TRobot, 'actuators'>;
|
|
45
|
+
type RobotSensors<TRobot extends string> = RobotResource<TRobot, 'sensors'>;
|
|
46
|
+
type RobotBodies<TRobot extends string> = RobotResource<TRobot, 'bodies'>;
|
|
47
|
+
type RobotJoints<TRobot extends string> = RobotResource<TRobot, 'joints'>;
|
|
48
|
+
type RobotSites<TRobot extends string> = RobotResource<TRobot, 'sites'>;
|
|
49
|
+
type RobotGeoms<TRobot extends string> = RobotResource<TRobot, 'geoms'>;
|
|
50
|
+
type RobotKeyframes<TRobot extends string> = RobotResource<TRobot, 'keyframes'>;
|
|
30
51
|
type Actuators = Register extends {
|
|
31
52
|
actuators: infer T extends string;
|
|
32
53
|
} ? T : string;
|
|
@@ -1483,4 +1504,4 @@ interface CameraAnimationAPI {
|
|
|
1483
1504
|
*/
|
|
1484
1505
|
declare function useCameraAnimation(): CameraAnimationAPI;
|
|
1485
1506
|
|
|
1486
|
-
export { type ActuatedJointInfo, type ActuatorInfo, type Actuators, type Bodies, Body, type BodyInfo, type BodyProps, type BodyStateResult, type CameraAnimationAPI, type ContactInfo, ContactListener, type ContactListenerProps, ContactMarkers, type ControlGroupInfo, type ControlGroupSelector, type ControlJointInfo, type ControllerComponent, type ControllerOptions, type CtrlHandle, Debug, type DebugProps, DragInteraction, type DragInteractionProps, FlexRenderer, type GeomInfo, type Geoms, type IKSolveFn, type IkConfig, type IkContextValue, IkGizmo, type IkGizmoProps, InstancedGeomRenderer, type JointInfo, type JointStateResult, type Joints, type KeyBinding, type KeyboardTeleopConfig, type Keyframes, type ModelOptions, MujocoCanvas, type MujocoCanvasProps, type MujocoContact, type MujocoContactArray, type MujocoContextValue, type MujocoData, type MujocoLoader, type MujocoLoaderOptions, type MujocoModel, type MujocoModule, MujocoPhysics, type MujocoPhysicsProps, MujocoProvider, type MujocoProviderProps, type MujocoSimAPI, MujocoSimProvider, type MujocoWasmVariant, type ObservationConfig, type ObservationHandle, type ObservationLayoutItem, type ObservationOutput, type ObservationResult, type PhysicsConfig, type PhysicsStepCallback, type PlaybackState, type PolicyConfig, type RayHit, type Register, type ResourceSelector, type SceneConfig, SceneLights, type SceneLightsProps, type SceneMarker, type SceneObject, type SensorHandle, type SensorInfo, type SensorResult, type Sensors, type SiteInfo, type SitePositionResult, type Sites, type StateSnapshot, TendonRenderer, type TrajectoryData, type TrajectoryFrame, type TrajectoryInput, TrajectoryPlayer, type TrajectoryPlayerProps, type XmlPatch, buildObservation, createContiguousControlGroup, createController, createControllerHook, findActuatorByName, findBodyByName, findGeomByName, findJointByName, findKeyframeByName, findSensorByName, findSiteByName, findTendonByName, getActuatedJoints, getContact, getControlMap, getName, loadScene, resolveControlGroup, useActuators, useAfterPhysicsStep, useBeforePhysicsStep, useBodyMeshes, useBodyState, useCameraAnimation, useContactEvents, useContacts, useCtrl, useCtrlNoise, useGamepad, useGravityCompensation, useIkController, useJointState, useKeyboardTeleop, useMujoco, useMujocoWasm, useObservation, usePolicy, useSceneLights, useSelectionHighlight, useSensor, useSensors, useSitePosition, useTrajectoryPlayer, useTrajectoryRecorder, useVideoRecorder };
|
|
1507
|
+
export { type ActuatedJointInfo, type ActuatorInfo, type Actuators, type Bodies, Body, type BodyInfo, type BodyProps, type BodyStateResult, type CameraAnimationAPI, type ContactInfo, ContactListener, type ContactListenerProps, ContactMarkers, type ControlGroupInfo, type ControlGroupSelector, type ControlJointInfo, type ControllerComponent, type ControllerOptions, type CtrlHandle, Debug, type DebugProps, DragInteraction, type DragInteractionProps, FlexRenderer, type GeomInfo, type Geoms, type IKSolveFn, type IkConfig, type IkContextValue, IkGizmo, type IkGizmoProps, InstancedGeomRenderer, type JointInfo, type JointStateResult, type Joints, type KeyBinding, type KeyboardTeleopConfig, type Keyframes, type ModelOptions, MujocoCanvas, type MujocoCanvasProps, type MujocoContact, type MujocoContactArray, type MujocoContextValue, type MujocoData, type MujocoLoader, type MujocoLoaderOptions, type MujocoModel, type MujocoModule, MujocoPhysics, type MujocoPhysicsProps, MujocoProvider, type MujocoProviderProps, type MujocoSimAPI, MujocoSimProvider, type MujocoWasmVariant, type ObservationConfig, type ObservationHandle, type ObservationLayoutItem, type ObservationOutput, type ObservationResult, type PhysicsConfig, type PhysicsStepCallback, type PlaybackState, type PolicyConfig, type RayHit, type Register, type RegisteredRobotMap, type ResourceSelector, type RobotActuators, type RobotBodies, type RobotGeoms, type RobotJoints, type RobotKeyframes, type RobotResource, type RobotSensors, type RobotSites, type Robots, type SceneConfig, SceneLights, type SceneLightsProps, type SceneMarker, type SceneObject, type SensorHandle, type SensorInfo, type SensorResult, type Sensors, type SiteInfo, type SitePositionResult, type Sites, type StateSnapshot, TendonRenderer, type TrajectoryData, type TrajectoryFrame, type TrajectoryInput, TrajectoryPlayer, type TrajectoryPlayerProps, type XmlPatch, buildObservation, createContiguousControlGroup, createController, createControllerHook, findActuatorByName, findBodyByName, findGeomByName, findJointByName, findKeyframeByName, findSensorByName, findSiteByName, findTendonByName, getActuatedJoints, getContact, getControlMap, getName, loadScene, resolveControlGroup, useActuators, useAfterPhysicsStep, useBeforePhysicsStep, useBodyMeshes, useBodyState, useCameraAnimation, useContactEvents, useContacts, useCtrl, useCtrlNoise, useGamepad, useGravityCompensation, useIkController, useJointState, useKeyboardTeleop, useMujoco, useMujocoWasm, useObservation, usePolicy, useSceneLights, useSelectionHighlight, useSensor, useSensors, useSitePosition, useTrajectoryPlayer, useTrajectoryRecorder, useVideoRecorder };
|