mujoco-react 8.5.0 → 8.7.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 CHANGED
@@ -18,6 +18,72 @@ 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
+
50
+ declare module "mujoco-react" {
51
+ interface Register {
52
+ robots: {
53
+ franka: {
54
+ actuators: "joint1" | "joint2" | "joint3" | "gripper";
55
+ sensors: "force_sensor" | "torque_sensor";
56
+ bodies: "link0" | "link1" | "hand";
57
+ joints: "joint1" | "joint2" | "joint3";
58
+ sites: "tcp";
59
+ geoms: "floor";
60
+ keyframes: "home";
61
+ };
62
+ spot: {
63
+ actuators: "fl_hx" | "fl_hy" | "fl_kn";
64
+ sensors: never;
65
+ bodies: "body" | "fl_hip" | "fl_uleg";
66
+ joints: "fl_hx" | "fl_hy" | "fl_kn";
67
+ sites: never;
68
+ geoms: "floor";
69
+ keyframes: "home";
70
+ };
71
+ };
72
+ actuators: "joint1" | "joint2" | "joint3" | "gripper" | "fl_hx" | "fl_hy" | "fl_kn";
73
+ sensors: "force_sensor" | "torque_sensor";
74
+ bodies: "link0" | "link1" | "hand" | "body" | "fl_hip" | "fl_uleg";
75
+ }
76
+ }
77
+ ```
78
+
79
+ Once generated, hooks like `useCtrl`, `useSensor`, `useBodyState`, and API methods like `setCtrl`, `applyForce`, `getSensorData` accept the global union. For robot-scoped reusable code, use helpers such as `RobotActuators<"franka">`, `RobotSites<"franka">`, and `RobotBodies<"franka">`. When no `Register` augmentation is present, names fall back to `string`.
80
+
81
+ Non-Vite projects can generate the same file with:
82
+
83
+ ```bash
84
+ npx mujoco-react codegen franka=models/panda/scene.xml spot=models/spot/scene.xml
85
+ ```
86
+
21
87
  ## Load a Model
22
88
 
23
89
  ```tsx
@@ -87,6 +153,23 @@ function MyController() {
87
153
 
88
154
  Controllers are just React children that read sensors, write `data.ctrl`, apply forces, or call the `MujocoSimAPI` at physics-step time.
89
155
 
156
+ 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:
157
+
158
+ ```tsx
159
+ import { useCtrl, useIkController } from "mujoco-react";
160
+ import type { RobotActuators, RobotSites } from "mujoco-react";
161
+
162
+ const frankaGripper = "gripper" satisfies RobotActuators<"franka">;
163
+ const frankaTcp = "tcp" satisfies RobotSites<"franka">;
164
+
165
+ function FrankaTypedControls() {
166
+ const gripper = useCtrl(frankaGripper);
167
+ const ik = useIkController({ siteName: frankaTcp });
168
+
169
+ return null;
170
+ }
171
+ ```
172
+
90
173
  ## Use the Sim API
91
174
 
92
175
  ```tsx
@@ -304,23 +387,6 @@ const gripperIk = useIkController({
304
387
  });
305
388
  ```
306
389
 
307
- ## Type-Safe Resource Names
308
-
309
- Use TypeScript module augmentation to get autocomplete and type checking for actuator, sensor, body, joint, site, geom, and keyframe names:
310
-
311
- ```ts
312
- // e.g. in src/mujoco-register.d.ts
313
- declare module "mujoco-react" {
314
- interface Register {
315
- actuators: "joint1" | "joint2" | "joint3" | "gripper";
316
- sensors: "force_sensor" | "torque_sensor";
317
- bodies: "link0" | "link1" | "hand";
318
- }
319
- }
320
- ```
321
-
322
- Once declared, hooks like `useCtrl`, `useSensor`, `useBodyState`, and API methods like `setCtrl`, `applyForce`, `getSensorData` will only accept the declared names. When no `Register` augmentation is provided, all names fall back to `string`.
323
-
324
390
  ## Loading Models
325
391
 
326
392
  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.
@@ -344,7 +410,8 @@ const custom: SceneConfig = {
344
410
  ```ts
345
411
  interface SceneConfig {
346
412
  src: string; // Base URL for model files
347
- sceneFile: string; // Entry XML file, e.g. "scene.xml"
413
+ sceneFile: string; // Entry XML/URDF file, e.g. "scene.xml"
414
+ files?: File[]; // Local files for browser upload workflows
348
415
  sceneObjects?: SceneObject[]; // Objects injected into scene XML at load time
349
416
  homeJoints?: number[]; // Initial joint positions
350
417
  xmlPatches?: XmlPatch[]; // Patches applied to XML files during loading
@@ -352,6 +419,30 @@ interface SceneConfig {
352
419
  }
353
420
  ```
354
421
 
422
+ ### Local Files and URDF
423
+
424
+ 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:
425
+
426
+ ```tsx
427
+ function ModelUpload() {
428
+ const sim = useMujoco();
429
+
430
+ return (
431
+ <input
432
+ type="file"
433
+ multiple
434
+ // @ts-expect-error Chromium/WebKit folder uploads
435
+ webkitdirectory=""
436
+ onChange={(event) => {
437
+ if (sim.isReady && event.currentTarget.files) {
438
+ sim.api.loadFromFiles(event.currentTarget.files);
439
+ }
440
+ }}
441
+ />
442
+ );
443
+ }
444
+ ```
445
+
355
446
  ### Adding Objects to Any Scene
356
447
 
357
448
  ```tsx
@@ -552,6 +643,10 @@ Renders tendons as tube geometry from wrap paths.
552
643
 
553
644
  Renders deformable flex bodies from `flexvert_xpos`.
554
645
 
646
+ ### `<InstancedGeomRenderer />`
647
+
648
+ Opt-in renderer for repeated compatible geoms. It batches matching geom shape/material signatures into Three.js `InstancedMesh` objects and syncs instance transforms from `data.geom_xpos` / `data.geom_xmat`.
649
+
555
650
  ### `<ContactListener />`
556
651
 
557
652
  Component wrapper for contact events:
@@ -861,6 +956,9 @@ The full API object available via `ref` or `useMujoco()` (when `isReady`):
861
956
  |--------|-------------|
862
957
  | `setGravity(g)` | Set gravity vector |
863
958
  | `setTimestep(dt)` | Set timestep |
959
+ | `addBody(body)` | Add a `SceneObject` and recompile the scene |
960
+ | `removeBody(name)` | Remove a generated `SceneObject` and recompile |
961
+ | `recompile(patches?)` | Recompile current scene, optionally appending XML patches |
864
962
  | `setBodyMass(name, mass)` | Domain randomization |
865
963
  | `setGeomFriction(name, friction)` | Domain randomization |
866
964
  | `setGeomSize(name, size)` | Domain randomization |
@@ -878,6 +976,7 @@ The full API object available via `ref` or `useMujoco()` (when `isReady`):
878
976
  | Method | Description |
879
977
  |--------|-------------|
880
978
  | `loadScene(newConfig)` | Runtime model swap |
979
+ | `loadFromFiles(files, options?)` | Load MJCF/URDF from a browser `FileList` |
881
980
 
882
981
  ## Guides
883
982
 
@@ -916,13 +1015,7 @@ Features planned but not yet implemented:
916
1015
 
917
1016
  | Feature | Priority | Description |
918
1017
  |---------|----------|-------------|
919
- | **User-uploaded model loading** | P2 | `loadFromFiles(FileList)` -- detect meshdir, write to VFS |
920
- | **URDF loading** | P2 | Load URDF models via MuJoCo's built-in URDF compiler |
921
- | **XML mutation / recompile** | P1 | `addBody()`, `removeBody()`, `recompile()` for runtime XML editing |
922
- | **Physics interpolation** | P1 | Smooth rendering between physics ticks for very high refresh displays |
923
- | **Instanced geom rendering** | P2 | `<InstancedGeomRenderer />` for particle/granular sims |
924
1018
  | **Web Worker physics** | P2 | Run `mj_step` off main thread via SharedArrayBuffer |
925
- | **Register codegen** | P2 | CLI to auto-generate `Register` type augmentation from MJCF XML |
926
1019
 
927
1020
  ### WASM Limitations (@mujoco/mujoco)
928
1021
 
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ process.argv.splice(2, 0, 'codegen');
3
+ await import('./mujoco-react.mjs');
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env node
2
+ import { watch } from 'node:fs';
3
+ import path from 'node:path';
4
+ import { generateMujocoRegister } from '../dist/vite.js';
5
+
6
+ const usage = `
7
+ Usage:
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
10
+
11
+ Vite users usually do not need this command. Prefer:
12
+
13
+ import { mujocoReact } from "mujoco-react/vite";
14
+
15
+ export default defineConfig({
16
+ plugins: [mujocoReact({ models: { franka: "models/panda/scene.xml" } })],
17
+ });
18
+ `;
19
+
20
+ const args = process.argv.slice(2);
21
+ const command = args[0];
22
+
23
+ if (!command || command === '--help' || command === '-h') {
24
+ console.log(usage.trim());
25
+ process.exit(command ? 0 : 1);
26
+ }
27
+
28
+ if (command !== 'codegen') {
29
+ console.error(`Unknown command: ${command}`);
30
+ console.error(usage.trim());
31
+ process.exit(1);
32
+ }
33
+
34
+ const commandArgs = args.slice(1);
35
+ const out = valueAfter(commandArgs, '--out') ?? 'src/mujoco-register.gen.d.ts';
36
+ const moduleName = valueAfter(commandArgs, '--module') ?? 'mujoco-react';
37
+ const shouldWatch = commandArgs.includes('--watch');
38
+ const models = commandArgs.filter((arg, index) => {
39
+ if (arg.startsWith('--')) return false;
40
+ const previous = commandArgs[index - 1];
41
+ return previous !== '--out' && previous !== '--module';
42
+ });
43
+ const modelInput = parseModels(models);
44
+
45
+ if (!models.length) {
46
+ console.error(usage.trim());
47
+ process.exit(1);
48
+ }
49
+
50
+ let watchedFiles = [];
51
+ await generate();
52
+
53
+ if (shouldWatch) {
54
+ console.log('[mujoco-react] watching model files...');
55
+ let timer;
56
+ const refreshWatchers = () => {
57
+ for (const file of watchedFiles) {
58
+ watch(file, { persistent: true }, () => {
59
+ clearTimeout(timer);
60
+ timer = setTimeout(() => {
61
+ generate().catch((error) => {
62
+ console.error('[mujoco-react] register generation failed');
63
+ console.error(error);
64
+ });
65
+ }, 50);
66
+ });
67
+ }
68
+ };
69
+ refreshWatchers();
70
+ }
71
+
72
+ async function generate() {
73
+ const result = await generateMujocoRegister({
74
+ models: modelInput,
75
+ out,
76
+ moduleName,
77
+ root: process.cwd(),
78
+ });
79
+ watchedFiles = result.files;
80
+ const total = Object.values(result.counts).reduce((sum, count) => sum + count, 0);
81
+ console.log(`[mujoco-react] generated ${path.relative(process.cwd(), result.out)} (${total} names)`);
82
+ }
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
+
94
+ function valueAfter(values, flag) {
95
+ const index = values.indexOf(flag);
96
+ if (index === -1) return undefined;
97
+ return values[index + 1];
98
+ }
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;
@@ -275,11 +296,22 @@ interface XmlPatch {
275
296
  injectAfter?: string;
276
297
  replace?: [string, string];
277
298
  }
299
+ type LocalMujocoFile = File;
300
+ interface LoadFromFilesOptions {
301
+ /** Entry MJCF/URDF file. Inferred from scene.xml, model.xml, robot.xml, or the first XML/URDF file when omitted. */
302
+ sceneFile?: string;
303
+ homeJoints?: number[];
304
+ xmlPatches?: XmlPatch[];
305
+ sceneObjects?: SceneObject[];
306
+ onReset?: (model: MujocoModel, data: MujocoData) => void;
307
+ }
278
308
  interface SceneConfig {
279
309
  /** Base URL for fetching model files. The loader fetches `src + sceneFile` and follows dependencies. */
280
310
  src: string;
281
- /** Entry MJCF XML file name, e.g. 'scene.xml'. */
311
+ /** Entry MJCF XML or URDF file name, e.g. 'scene.xml' or 'robot.urdf'. */
282
312
  sceneFile: string;
313
+ /** Browser-selected files for local MJCF/URDF loading. Preserves webkitRelativePath when available. */
314
+ files?: readonly LocalMujocoFile[];
283
315
  sceneObjects?: SceneObject[];
284
316
  homeJoints?: number[];
285
317
  xmlPatches?: XmlPatch[];
@@ -610,6 +642,10 @@ interface MujocoSimAPI {
610
642
  getKeyframeNames(): string[];
611
643
  getKeyframeCount(): number;
612
644
  loadScene(newConfig: SceneConfig): Promise<void>;
645
+ loadFromFiles(files: FileList | readonly LocalMujocoFile[], options?: LoadFromFilesOptions): Promise<void>;
646
+ addBody(body: SceneObject): Promise<void>;
647
+ removeBody(name: Bodies): Promise<void>;
648
+ recompile(patches?: XmlPatch[]): Promise<void>;
613
649
  getCanvasSnapshot(width?: number, height?: number, mimeType?: string): string;
614
650
  project2DTo3D(x: number, y: number, cameraPos: THREE.Vector3, lookAt: THREE.Vector3): {
615
651
  point: THREE.Vector3;
@@ -633,6 +669,7 @@ type MujocoCanvasProps = Omit<CanvasProps, 'onError'> & {
633
669
  substeps?: number;
634
670
  paused?: boolean;
635
671
  speed?: number;
672
+ interpolate?: boolean;
636
673
  };
637
674
  interface SitePositionResult {
638
675
  position: React__default.RefObject<THREE.Vector3>;
@@ -744,6 +781,8 @@ interface MujocoPhysicsProps {
744
781
  paused?: boolean;
745
782
  /** Simulation speed multiplier. */
746
783
  speed?: number;
784
+ /** Interpolate rendered body poses between fixed physics steps. */
785
+ interpolate?: boolean;
747
786
  children: React.ReactNode;
748
787
  }
749
788
  /**
@@ -811,9 +850,10 @@ interface MujocoSimProviderProps {
811
850
  substeps?: number;
812
851
  paused?: boolean;
813
852
  speed?: number;
853
+ interpolate?: boolean;
814
854
  children: React.ReactNode;
815
855
  }
816
- declare function MujocoSimProvider({ mujoco, config, apiRef: externalApiRef, onReady, onError, onStep, onSelection, gravity, timestep, substeps, paused, speed, children, }: MujocoSimProviderProps): react_jsx_runtime.JSX.Element;
856
+ declare function MujocoSimProvider({ mujoco, config, apiRef: externalApiRef, onReady, onError, onStep, onSelection, gravity, timestep, substeps, paused, speed, interpolate, children, }: MujocoSimProviderProps): react_jsx_runtime.JSX.Element;
817
857
 
818
858
  /**
819
859
  * @license
@@ -1043,6 +1083,20 @@ declare function TendonRenderer(props: Omit<ThreeElements['group'], 'ref'>): rea
1043
1083
  */
1044
1084
  declare function FlexRenderer(props: Omit<ThreeElements['group'], 'ref'>): react_jsx_runtime.JSX.Element | null;
1045
1085
 
1086
+ interface InstancedGeomRendererProps extends Omit<ThreeElements['group'], 'ref'> {
1087
+ /** Only render geoms from this MuJoCo geom group. */
1088
+ geomGroup?: number;
1089
+ /** Predicate for selecting geoms. */
1090
+ filter?: (geom: GeomInfo) => boolean;
1091
+ /** Optional material override for every instanced batch. */
1092
+ material?: THREE.Material;
1093
+ /** Hide or show the instanced batches. */
1094
+ visible?: boolean;
1095
+ castShadow?: boolean;
1096
+ receiveShadow?: boolean;
1097
+ }
1098
+ declare function InstancedGeomRenderer({ geomGroup, filter, material, visible, castShadow, receiveShadow, ...groupProps }?: InstancedGeomRendererProps): react_jsx_runtime.JSX.Element | null;
1099
+
1046
1100
  /**
1047
1101
  * @license
1048
1102
  * SPDX-License-Identifier: Apache-2.0
@@ -1450,4 +1504,4 @@ interface CameraAnimationAPI {
1450
1504
  */
1451
1505
  declare function useCameraAnimation(): CameraAnimationAPI;
1452
1506
 
1453
- 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, 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 };