mujoco-react 8.5.0 → 8.6.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 +63 -10
- package/bin/mujoco-react-codegen.mjs +3 -0
- package/bin/mujoco-react.mjs +86 -0
- package/dist/index.d.ts +36 -3
- package/dist/index.js +453 -76
- package/dist/index.js.map +1 -1
- package/dist/vite.d.ts +47 -0
- package/dist/vite.js +162 -0
- package/dist/vite.js.map +1 -0
- package/package.json +13 -1
- package/src/components/InstancedGeomRenderer.tsx +158 -0
- package/src/components/SceneRenderer.tsx +51 -12
- package/src/core/MujocoCanvas.tsx +2 -0
- package/src/core/MujocoPhysics.tsx +2 -0
- package/src/core/MujocoSimProvider.tsx +138 -10
- package/src/core/SceneLoader.ts +190 -60
- package/src/index.ts +1 -0
- package/src/types.ts +19 -1
- package/src/vite.ts +223 -0
package/README.md
CHANGED
|
@@ -306,10 +306,30 @@ const gripperIk = useIkController({
|
|
|
306
306
|
|
|
307
307
|
## Type-Safe Resource Names
|
|
308
308
|
|
|
309
|
-
Use
|
|
309
|
+
Use the Vite plugin to generate TanStack-style declaration merging for actuator, sensor, body, joint, site, geom, and keyframe names:
|
|
310
310
|
|
|
311
311
|
```ts
|
|
312
|
-
//
|
|
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
|
+
|
|
313
333
|
declare module "mujoco-react" {
|
|
314
334
|
interface Register {
|
|
315
335
|
actuators: "joint1" | "joint2" | "joint3" | "gripper";
|
|
@@ -319,7 +339,13 @@ declare module "mujoco-react" {
|
|
|
319
339
|
}
|
|
320
340
|
```
|
|
321
341
|
|
|
322
|
-
Once
|
|
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
|
+
```
|
|
323
349
|
|
|
324
350
|
## Loading Models
|
|
325
351
|
|
|
@@ -344,7 +370,8 @@ const custom: SceneConfig = {
|
|
|
344
370
|
```ts
|
|
345
371
|
interface SceneConfig {
|
|
346
372
|
src: string; // Base URL for model files
|
|
347
|
-
sceneFile: string; // Entry XML file, e.g. "scene.xml"
|
|
373
|
+
sceneFile: string; // Entry XML/URDF file, e.g. "scene.xml"
|
|
374
|
+
files?: File[]; // Local files for browser upload workflows
|
|
348
375
|
sceneObjects?: SceneObject[]; // Objects injected into scene XML at load time
|
|
349
376
|
homeJoints?: number[]; // Initial joint positions
|
|
350
377
|
xmlPatches?: XmlPatch[]; // Patches applied to XML files during loading
|
|
@@ -352,6 +379,30 @@ interface SceneConfig {
|
|
|
352
379
|
}
|
|
353
380
|
```
|
|
354
381
|
|
|
382
|
+
### Local Files and URDF
|
|
383
|
+
|
|
384
|
+
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
|
+
|
|
386
|
+
```tsx
|
|
387
|
+
function ModelUpload() {
|
|
388
|
+
const sim = useMujoco();
|
|
389
|
+
|
|
390
|
+
return (
|
|
391
|
+
<input
|
|
392
|
+
type="file"
|
|
393
|
+
multiple
|
|
394
|
+
// @ts-expect-error Chromium/WebKit folder uploads
|
|
395
|
+
webkitdirectory=""
|
|
396
|
+
onChange={(event) => {
|
|
397
|
+
if (sim.isReady && event.currentTarget.files) {
|
|
398
|
+
sim.api.loadFromFiles(event.currentTarget.files);
|
|
399
|
+
}
|
|
400
|
+
}}
|
|
401
|
+
/>
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
355
406
|
### Adding Objects to Any Scene
|
|
356
407
|
|
|
357
408
|
```tsx
|
|
@@ -552,6 +603,10 @@ Renders tendons as tube geometry from wrap paths.
|
|
|
552
603
|
|
|
553
604
|
Renders deformable flex bodies from `flexvert_xpos`.
|
|
554
605
|
|
|
606
|
+
### `<InstancedGeomRenderer />`
|
|
607
|
+
|
|
608
|
+
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`.
|
|
609
|
+
|
|
555
610
|
### `<ContactListener />`
|
|
556
611
|
|
|
557
612
|
Component wrapper for contact events:
|
|
@@ -861,6 +916,9 @@ The full API object available via `ref` or `useMujoco()` (when `isReady`):
|
|
|
861
916
|
|--------|-------------|
|
|
862
917
|
| `setGravity(g)` | Set gravity vector |
|
|
863
918
|
| `setTimestep(dt)` | Set timestep |
|
|
919
|
+
| `addBody(body)` | Add a `SceneObject` and recompile the scene |
|
|
920
|
+
| `removeBody(name)` | Remove a generated `SceneObject` and recompile |
|
|
921
|
+
| `recompile(patches?)` | Recompile current scene, optionally appending XML patches |
|
|
864
922
|
| `setBodyMass(name, mass)` | Domain randomization |
|
|
865
923
|
| `setGeomFriction(name, friction)` | Domain randomization |
|
|
866
924
|
| `setGeomSize(name, size)` | Domain randomization |
|
|
@@ -878,6 +936,7 @@ The full API object available via `ref` or `useMujoco()` (when `isReady`):
|
|
|
878
936
|
| Method | Description |
|
|
879
937
|
|--------|-------------|
|
|
880
938
|
| `loadScene(newConfig)` | Runtime model swap |
|
|
939
|
+
| `loadFromFiles(files, options?)` | Load MJCF/URDF from a browser `FileList` |
|
|
881
940
|
|
|
882
941
|
## Guides
|
|
883
942
|
|
|
@@ -916,13 +975,7 @@ Features planned but not yet implemented:
|
|
|
916
975
|
|
|
917
976
|
| Feature | Priority | Description |
|
|
918
977
|
|---------|----------|-------------|
|
|
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
978
|
| **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
979
|
|
|
927
980
|
### WASM Limitations (@mujoco/mujoco)
|
|
928
981
|
|
|
@@ -0,0 +1,86 @@
|
|
|
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
|
+
|
|
10
|
+
Vite users usually do not need this command. Prefer:
|
|
11
|
+
|
|
12
|
+
import { mujocoReact } from "mujoco-react/vite";
|
|
13
|
+
|
|
14
|
+
export default defineConfig({
|
|
15
|
+
plugins: [mujocoReact({ models: "models/panda/scene.xml" })],
|
|
16
|
+
});
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
const args = process.argv.slice(2);
|
|
20
|
+
const command = args[0];
|
|
21
|
+
|
|
22
|
+
if (!command || command === '--help' || command === '-h') {
|
|
23
|
+
console.log(usage.trim());
|
|
24
|
+
process.exit(command ? 0 : 1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (command !== 'codegen') {
|
|
28
|
+
console.error(`Unknown command: ${command}`);
|
|
29
|
+
console.error(usage.trim());
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const commandArgs = args.slice(1);
|
|
34
|
+
const out = valueAfter(commandArgs, '--out') ?? 'src/mujoco-register.gen.d.ts';
|
|
35
|
+
const moduleName = valueAfter(commandArgs, '--module') ?? 'mujoco-react';
|
|
36
|
+
const shouldWatch = commandArgs.includes('--watch');
|
|
37
|
+
const models = commandArgs.filter((arg, index) => {
|
|
38
|
+
if (arg.startsWith('--')) return false;
|
|
39
|
+
const previous = commandArgs[index - 1];
|
|
40
|
+
return previous !== '--out' && previous !== '--module';
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
if (!models.length) {
|
|
44
|
+
console.error(usage.trim());
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let watchedFiles = [];
|
|
49
|
+
await generate();
|
|
50
|
+
|
|
51
|
+
if (shouldWatch) {
|
|
52
|
+
console.log('[mujoco-react] watching model files...');
|
|
53
|
+
let timer;
|
|
54
|
+
const refreshWatchers = () => {
|
|
55
|
+
for (const file of watchedFiles) {
|
|
56
|
+
watch(file, { persistent: true }, () => {
|
|
57
|
+
clearTimeout(timer);
|
|
58
|
+
timer = setTimeout(() => {
|
|
59
|
+
generate().catch((error) => {
|
|
60
|
+
console.error('[mujoco-react] register generation failed');
|
|
61
|
+
console.error(error);
|
|
62
|
+
});
|
|
63
|
+
}, 50);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
refreshWatchers();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function generate() {
|
|
71
|
+
const result = await generateMujocoRegister({
|
|
72
|
+
models,
|
|
73
|
+
out,
|
|
74
|
+
moduleName,
|
|
75
|
+
root: process.cwd(),
|
|
76
|
+
});
|
|
77
|
+
watchedFiles = result.files;
|
|
78
|
+
const total = Object.values(result.counts).reduce((sum, count) => sum + count, 0);
|
|
79
|
+
console.log(`[mujoco-react] generated ${path.relative(process.cwd(), result.out)} (${total} names)`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function valueAfter(values, flag) {
|
|
83
|
+
const index = values.indexOf(flag);
|
|
84
|
+
if (index === -1) return undefined;
|
|
85
|
+
return values[index + 1];
|
|
86
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -275,11 +275,22 @@ interface XmlPatch {
|
|
|
275
275
|
injectAfter?: string;
|
|
276
276
|
replace?: [string, string];
|
|
277
277
|
}
|
|
278
|
+
type LocalMujocoFile = File;
|
|
279
|
+
interface LoadFromFilesOptions {
|
|
280
|
+
/** Entry MJCF/URDF file. Inferred from scene.xml, model.xml, robot.xml, or the first XML/URDF file when omitted. */
|
|
281
|
+
sceneFile?: string;
|
|
282
|
+
homeJoints?: number[];
|
|
283
|
+
xmlPatches?: XmlPatch[];
|
|
284
|
+
sceneObjects?: SceneObject[];
|
|
285
|
+
onReset?: (model: MujocoModel, data: MujocoData) => void;
|
|
286
|
+
}
|
|
278
287
|
interface SceneConfig {
|
|
279
288
|
/** Base URL for fetching model files. The loader fetches `src + sceneFile` and follows dependencies. */
|
|
280
289
|
src: string;
|
|
281
|
-
/** Entry MJCF XML file name, e.g. 'scene.xml'. */
|
|
290
|
+
/** Entry MJCF XML or URDF file name, e.g. 'scene.xml' or 'robot.urdf'. */
|
|
282
291
|
sceneFile: string;
|
|
292
|
+
/** Browser-selected files for local MJCF/URDF loading. Preserves webkitRelativePath when available. */
|
|
293
|
+
files?: readonly LocalMujocoFile[];
|
|
283
294
|
sceneObjects?: SceneObject[];
|
|
284
295
|
homeJoints?: number[];
|
|
285
296
|
xmlPatches?: XmlPatch[];
|
|
@@ -610,6 +621,10 @@ interface MujocoSimAPI {
|
|
|
610
621
|
getKeyframeNames(): string[];
|
|
611
622
|
getKeyframeCount(): number;
|
|
612
623
|
loadScene(newConfig: SceneConfig): Promise<void>;
|
|
624
|
+
loadFromFiles(files: FileList | readonly LocalMujocoFile[], options?: LoadFromFilesOptions): Promise<void>;
|
|
625
|
+
addBody(body: SceneObject): Promise<void>;
|
|
626
|
+
removeBody(name: Bodies): Promise<void>;
|
|
627
|
+
recompile(patches?: XmlPatch[]): Promise<void>;
|
|
613
628
|
getCanvasSnapshot(width?: number, height?: number, mimeType?: string): string;
|
|
614
629
|
project2DTo3D(x: number, y: number, cameraPos: THREE.Vector3, lookAt: THREE.Vector3): {
|
|
615
630
|
point: THREE.Vector3;
|
|
@@ -633,6 +648,7 @@ type MujocoCanvasProps = Omit<CanvasProps, 'onError'> & {
|
|
|
633
648
|
substeps?: number;
|
|
634
649
|
paused?: boolean;
|
|
635
650
|
speed?: number;
|
|
651
|
+
interpolate?: boolean;
|
|
636
652
|
};
|
|
637
653
|
interface SitePositionResult {
|
|
638
654
|
position: React__default.RefObject<THREE.Vector3>;
|
|
@@ -744,6 +760,8 @@ interface MujocoPhysicsProps {
|
|
|
744
760
|
paused?: boolean;
|
|
745
761
|
/** Simulation speed multiplier. */
|
|
746
762
|
speed?: number;
|
|
763
|
+
/** Interpolate rendered body poses between fixed physics steps. */
|
|
764
|
+
interpolate?: boolean;
|
|
747
765
|
children: React.ReactNode;
|
|
748
766
|
}
|
|
749
767
|
/**
|
|
@@ -811,9 +829,10 @@ interface MujocoSimProviderProps {
|
|
|
811
829
|
substeps?: number;
|
|
812
830
|
paused?: boolean;
|
|
813
831
|
speed?: number;
|
|
832
|
+
interpolate?: boolean;
|
|
814
833
|
children: React.ReactNode;
|
|
815
834
|
}
|
|
816
|
-
declare function MujocoSimProvider({ mujoco, config, apiRef: externalApiRef, onReady, onError, onStep, onSelection, gravity, timestep, substeps, paused, speed, children, }: MujocoSimProviderProps): react_jsx_runtime.JSX.Element;
|
|
835
|
+
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
836
|
|
|
818
837
|
/**
|
|
819
838
|
* @license
|
|
@@ -1043,6 +1062,20 @@ declare function TendonRenderer(props: Omit<ThreeElements['group'], 'ref'>): rea
|
|
|
1043
1062
|
*/
|
|
1044
1063
|
declare function FlexRenderer(props: Omit<ThreeElements['group'], 'ref'>): react_jsx_runtime.JSX.Element | null;
|
|
1045
1064
|
|
|
1065
|
+
interface InstancedGeomRendererProps extends Omit<ThreeElements['group'], 'ref'> {
|
|
1066
|
+
/** Only render geoms from this MuJoCo geom group. */
|
|
1067
|
+
geomGroup?: number;
|
|
1068
|
+
/** Predicate for selecting geoms. */
|
|
1069
|
+
filter?: (geom: GeomInfo) => boolean;
|
|
1070
|
+
/** Optional material override for every instanced batch. */
|
|
1071
|
+
material?: THREE.Material;
|
|
1072
|
+
/** Hide or show the instanced batches. */
|
|
1073
|
+
visible?: boolean;
|
|
1074
|
+
castShadow?: boolean;
|
|
1075
|
+
receiveShadow?: boolean;
|
|
1076
|
+
}
|
|
1077
|
+
declare function InstancedGeomRenderer({ geomGroup, filter, material, visible, castShadow, receiveShadow, ...groupProps }?: InstancedGeomRendererProps): react_jsx_runtime.JSX.Element | null;
|
|
1078
|
+
|
|
1046
1079
|
/**
|
|
1047
1080
|
* @license
|
|
1048
1081
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -1450,4 +1483,4 @@ interface CameraAnimationAPI {
|
|
|
1450
1483
|
*/
|
|
1451
1484
|
declare function useCameraAnimation(): CameraAnimationAPI;
|
|
1452
1485
|
|
|
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 };
|
|
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 };
|