mujoco-react 0.1.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.
Files changed (42) hide show
  1. package/LICENSE +177 -0
  2. package/README.md +510 -0
  3. package/dist/index.d.ts +1080 -0
  4. package/dist/index.js +3518 -0
  5. package/dist/index.js.map +1 -0
  6. package/package.json +64 -0
  7. package/src/components/ContactListener.tsx +26 -0
  8. package/src/components/ContactMarkers.tsx +81 -0
  9. package/src/components/Debug.tsx +227 -0
  10. package/src/components/DragInteraction.tsx +227 -0
  11. package/src/components/FlexRenderer.tsx +102 -0
  12. package/src/components/IkGizmo.tsx +146 -0
  13. package/src/components/SceneLights.tsx +131 -0
  14. package/src/components/SceneRenderer.tsx +104 -0
  15. package/src/components/SelectionHighlight.tsx +69 -0
  16. package/src/components/TendonRenderer.tsx +84 -0
  17. package/src/components/TrajectoryPlayer.tsx +44 -0
  18. package/src/core/GenericIK.ts +339 -0
  19. package/src/core/MujocoCanvas.tsx +72 -0
  20. package/src/core/MujocoProvider.tsx +78 -0
  21. package/src/core/MujocoSimProvider.tsx +1201 -0
  22. package/src/core/SceneLoader.ts +275 -0
  23. package/src/hooks/useActuators.ts +36 -0
  24. package/src/hooks/useBodyState.ts +56 -0
  25. package/src/hooks/useContacts.ts +125 -0
  26. package/src/hooks/useCtrl.ts +40 -0
  27. package/src/hooks/useCtrlNoise.ts +59 -0
  28. package/src/hooks/useGamepad.ts +77 -0
  29. package/src/hooks/useGravityCompensation.ts +22 -0
  30. package/src/hooks/useJointState.ts +64 -0
  31. package/src/hooks/useKeyboardTeleop.ts +97 -0
  32. package/src/hooks/usePolicy.ts +56 -0
  33. package/src/hooks/useSensor.ts +83 -0
  34. package/src/hooks/useSitePosition.ts +62 -0
  35. package/src/hooks/useTrajectoryPlayer.ts +105 -0
  36. package/src/hooks/useTrajectoryRecorder.ts +97 -0
  37. package/src/hooks/useVideoRecorder.ts +82 -0
  38. package/src/index.ts +108 -0
  39. package/src/rendering/CapsuleGeometry.ts +35 -0
  40. package/src/rendering/GeomBuilder.ts +140 -0
  41. package/src/rendering/Reflector.ts +225 -0
  42. package/src/types.ts +619 -0
@@ -0,0 +1,1080 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { CanvasProps } from '@react-three/fiber';
3
+ import * as THREE from 'three';
4
+ import * as react from 'react';
5
+
6
+ /**
7
+ * @license
8
+ * SPDX-License-Identifier: Apache-2.0
9
+ */
10
+
11
+ /**
12
+ * Minimal interface for MuJoCo Model to avoid 'any'.
13
+ */
14
+ interface MujocoModel {
15
+ nbody: number;
16
+ ngeom: number;
17
+ nsite: number;
18
+ nu: number;
19
+ njnt: number;
20
+ nq: number;
21
+ nv: number;
22
+ nkey: number;
23
+ nsensor: number;
24
+ nsensordata: number;
25
+ nlight: number;
26
+ ntendon: number;
27
+ nflex: number;
28
+ nmesh: number;
29
+ nmat: number;
30
+ names: Int8Array;
31
+ name_bodyadr: Int32Array;
32
+ name_jntadr: Int32Array;
33
+ name_geomadr: Int32Array;
34
+ name_siteadr: Int32Array;
35
+ name_actuatoradr: Int32Array;
36
+ name_keyadr: Int32Array;
37
+ name_sensoradr: Int32Array;
38
+ name_tendonadr: Int32Array;
39
+ body_mass: Float64Array;
40
+ body_parentid: Int32Array;
41
+ body_jntnum: Int32Array;
42
+ body_jntadr: Int32Array;
43
+ body_pos: Float64Array;
44
+ body_quat: Float64Array;
45
+ body_geomnum: Int32Array;
46
+ body_geomadr: Int32Array;
47
+ body_inertia: Float64Array;
48
+ jnt_qposadr: Int32Array;
49
+ jnt_dofadr: Int32Array;
50
+ jnt_type: Int32Array;
51
+ jnt_range: Float64Array;
52
+ jnt_bodyid: Int32Array;
53
+ jnt_limited: Uint8Array;
54
+ geom_group: Int32Array;
55
+ geom_type: Int32Array;
56
+ geom_size: Float64Array;
57
+ geom_pos: Float64Array;
58
+ geom_quat: Float64Array;
59
+ geom_matid: Int32Array;
60
+ geom_rgba: Float32Array;
61
+ geom_dataid: Int32Array;
62
+ geom_bodyid: Int32Array;
63
+ geom_contype: Int32Array;
64
+ geom_conaffinity: Int32Array;
65
+ geom_friction: Float64Array;
66
+ mat_rgba: Float32Array;
67
+ mesh_vertadr: Int32Array;
68
+ mesh_vertnum: Int32Array;
69
+ mesh_faceadr: Int32Array;
70
+ mesh_facenum: Int32Array;
71
+ mesh_vert: Float32Array;
72
+ mesh_face: Int32Array;
73
+ mesh_normal: Float32Array;
74
+ site_bodyid: Int32Array;
75
+ actuator_trnid: Int32Array;
76
+ actuator_ctrlrange: Float64Array;
77
+ actuator_trntype: Int32Array;
78
+ actuator_gainprm: Float64Array;
79
+ actuator_biasprm: Float64Array;
80
+ sensor_type: Int32Array;
81
+ sensor_dim: Int32Array;
82
+ sensor_adr: Int32Array;
83
+ sensor_objtype: Int32Array;
84
+ sensor_objid: Int32Array;
85
+ key_qpos: Float64Array;
86
+ key_ctrl: Float64Array;
87
+ key_time: Float64Array;
88
+ key_qvel: Float64Array;
89
+ light_pos: Float64Array;
90
+ light_dir: Float64Array;
91
+ light_diffuse: Float32Array;
92
+ light_specular: Float32Array;
93
+ light_type: Int32Array;
94
+ light_active: Uint8Array;
95
+ light_castshadow: Uint8Array;
96
+ light_attenuation: Float32Array;
97
+ light_cutoff: Float32Array;
98
+ light_exponent: Float32Array;
99
+ light_intensity: Float32Array;
100
+ ten_wrapadr: Int32Array;
101
+ ten_wrapnum: Int32Array;
102
+ ten_range: Float64Array;
103
+ ten_rgba: Float32Array;
104
+ ten_width: Float64Array;
105
+ flex_vertadr: Int32Array;
106
+ flex_vertnum: Int32Array;
107
+ flex_faceadr: Int32Array;
108
+ flex_facenum: Int32Array;
109
+ flex_face: Int32Array;
110
+ flex_rgba: Float32Array;
111
+ opt: {
112
+ timestep: number;
113
+ gravity: Float64Array;
114
+ integrator: number;
115
+ [key: string]: unknown;
116
+ };
117
+ delete: () => void;
118
+ [key: string]: unknown;
119
+ }
120
+ /**
121
+ * Minimal interface for MuJoCo Data to avoid 'any'.
122
+ */
123
+ interface MujocoData {
124
+ time: number;
125
+ qpos: Float64Array;
126
+ qvel: Float64Array;
127
+ ctrl: Float64Array;
128
+ act: Float64Array;
129
+ xpos: Float64Array;
130
+ xquat: Float64Array;
131
+ xfrc_applied: Float64Array;
132
+ qfrc_applied: Float64Array;
133
+ qfrc_bias: Float64Array;
134
+ site_xpos: Float64Array;
135
+ site_xmat: Float64Array;
136
+ sensordata: Float64Array;
137
+ ncon: number;
138
+ contact: unknown;
139
+ cvel: Float64Array;
140
+ cfrc_ext: Float64Array;
141
+ ten_length: Float64Array;
142
+ wrap_xpos: Float64Array;
143
+ ten_wrapadr: Int32Array;
144
+ flexvert_xpos: Float64Array;
145
+ geom_xpos: Float64Array;
146
+ geom_xmat: Float64Array;
147
+ delete: () => void;
148
+ [key: string]: unknown;
149
+ }
150
+ /**
151
+ * Minimal interface for the MuJoCo WASM Module.
152
+ */
153
+ interface MujocoModule {
154
+ MjModel: {
155
+ loadFromXML: (path: string) => MujocoModel;
156
+ [key: string]: unknown;
157
+ };
158
+ MjData: new (model: MujocoModel) => MujocoData;
159
+ MjvOption: new () => {
160
+ delete: () => void;
161
+ [key: string]: unknown;
162
+ };
163
+ mj_forward: (m: MujocoModel, d: MujocoData) => void;
164
+ mj_step: (m: MujocoModel, d: MujocoData) => void;
165
+ mj_resetData: (m: MujocoModel, d: MujocoData) => void;
166
+ mj_step1: (m: MujocoModel, d: MujocoData) => void;
167
+ mj_step2: (m: MujocoModel, d: MujocoData) => void;
168
+ mj_applyFT: (model: MujocoModel, data: MujocoData, force: Float64Array, torque: Float64Array, point: Float64Array, bodyId: number, qfrc_target: Float64Array) => void;
169
+ mj_ray: (model: MujocoModel, data: MujocoData, pnt: Float64Array, vec: Float64Array, geomgroup: Uint8Array | null, flg_static: number, bodyexclude: number, geomid: Int32Array) => number;
170
+ mj_name2id: (model: MujocoModel, type: number, name: string) => number;
171
+ mjtObj: Record<string, number>;
172
+ mjtGeom: Record<string, number | {
173
+ value: number;
174
+ }>;
175
+ mjtJoint: Record<string, number | {
176
+ value: number;
177
+ }>;
178
+ mjtSensor: Record<string, number | {
179
+ value: number;
180
+ }>;
181
+ FS: {
182
+ writeFile: (path: string, content: string | Uint8Array) => void;
183
+ readFile: (path: string, opts?: {
184
+ encoding: string;
185
+ }) => string | Uint8Array;
186
+ mkdir: (path: string) => void;
187
+ unmount: (path: string) => void;
188
+ };
189
+ [key: string]: unknown;
190
+ }
191
+ interface SceneObject {
192
+ name: string;
193
+ type: 'box' | 'sphere' | 'cylinder';
194
+ size: [number, number, number];
195
+ position: [number, number, number];
196
+ rgba: [number, number, number, number];
197
+ mass?: number;
198
+ freejoint?: boolean;
199
+ friction?: string;
200
+ solref?: string;
201
+ solimp?: string;
202
+ condim?: number;
203
+ }
204
+ interface XmlPatch {
205
+ target: string;
206
+ inject?: string;
207
+ injectAfter?: string;
208
+ replace?: [string, string];
209
+ }
210
+ interface SceneConfig {
211
+ robotId: string;
212
+ sceneFile: string;
213
+ baseUrl?: string;
214
+ sceneObjects?: SceneObject[];
215
+ tcpSiteName?: string;
216
+ gripperActuatorName?: string;
217
+ numArmJoints?: number;
218
+ homeJoints?: number[];
219
+ xmlPatches?: XmlPatch[];
220
+ onReset?: (model: MujocoModel, data: MujocoData) => void;
221
+ }
222
+ interface SceneMarker {
223
+ id: number;
224
+ position: THREE.Vector3;
225
+ label: string;
226
+ }
227
+ interface PhysicsConfig {
228
+ gravity?: [number, number, number];
229
+ timestep?: number;
230
+ substeps?: number;
231
+ paused?: boolean;
232
+ speed?: number;
233
+ interpolate?: boolean;
234
+ }
235
+ type IKSolveFn = (pos: THREE.Vector3, quat: THREE.Quaternion, currentQ: number[]) => number[] | null;
236
+ type PhysicsStepCallback = (model: MujocoModel, data: MujocoData) => void;
237
+ interface StateSnapshot {
238
+ time: number;
239
+ qpos: Float64Array;
240
+ qvel: Float64Array;
241
+ ctrl: Float64Array;
242
+ act: Float64Array;
243
+ qfrc_applied: Float64Array;
244
+ }
245
+ interface BodyInfo {
246
+ id: number;
247
+ name: string;
248
+ mass: number;
249
+ parentId: number;
250
+ }
251
+ interface JointInfo {
252
+ id: number;
253
+ name: string;
254
+ type: number;
255
+ typeName: string;
256
+ range: [number, number];
257
+ limited: boolean;
258
+ bodyId: number;
259
+ qposAdr: number;
260
+ dofAdr: number;
261
+ }
262
+ interface GeomInfo {
263
+ id: number;
264
+ name: string;
265
+ type: number;
266
+ typeName: string;
267
+ size: [number, number, number];
268
+ bodyId: number;
269
+ }
270
+ interface SiteInfo {
271
+ id: number;
272
+ name: string;
273
+ bodyId: number;
274
+ }
275
+ interface ActuatorInfo {
276
+ id: number;
277
+ name: string;
278
+ range: [number, number];
279
+ }
280
+ interface SensorInfo {
281
+ id: number;
282
+ name: string;
283
+ type: number;
284
+ typeName: string;
285
+ dim: number;
286
+ adr: number;
287
+ }
288
+ interface ContactInfo {
289
+ geom1: number;
290
+ geom1Name: string;
291
+ geom2: number;
292
+ geom2Name: string;
293
+ pos: [number, number, number];
294
+ depth: number;
295
+ }
296
+ interface RayHit {
297
+ point: THREE.Vector3;
298
+ bodyId: number;
299
+ geomId: number;
300
+ distance: number;
301
+ }
302
+ interface ModelOptions {
303
+ timestep: number;
304
+ gravity: [number, number, number];
305
+ integrator: number;
306
+ }
307
+ interface TrajectoryFrame {
308
+ time: number;
309
+ qpos: Float64Array;
310
+ qvel?: Float64Array;
311
+ ctrl?: Float64Array;
312
+ sensordata?: Float64Array;
313
+ }
314
+ interface TrajectoryData {
315
+ frames: TrajectoryFrame[];
316
+ fps: number;
317
+ }
318
+ interface KeyBinding {
319
+ actuator: string;
320
+ delta?: number;
321
+ toggle?: [number, number];
322
+ set?: number;
323
+ }
324
+ interface KeyboardTeleopConfig {
325
+ bindings: Record<string, KeyBinding>;
326
+ enabled?: boolean;
327
+ }
328
+ interface PolicyConfig {
329
+ frequency: number;
330
+ onObservation: (model: MujocoModel, data: MujocoData) => Float32Array | Float64Array | number[];
331
+ onAction: (action: Float32Array | Float64Array | number[], model: MujocoModel, data: MujocoData) => void;
332
+ }
333
+ interface DebugProps {
334
+ showGeoms?: boolean;
335
+ showSites?: boolean;
336
+ showJoints?: boolean;
337
+ showContacts?: boolean;
338
+ showCOM?: boolean;
339
+ showInertia?: boolean;
340
+ showTendons?: boolean;
341
+ }
342
+ interface IkGizmoProps {
343
+ siteName?: string;
344
+ scale?: number;
345
+ onDrag?: (position: THREE.Vector3, quaternion: THREE.Quaternion) => void;
346
+ }
347
+ interface DragInteractionProps {
348
+ stiffness?: number;
349
+ showArrow?: boolean;
350
+ }
351
+ interface SceneLightsProps {
352
+ /** Override intensity for all MJCF lights. Default: 1.0. */
353
+ intensity?: number;
354
+ }
355
+ interface TrajectoryPlayerProps {
356
+ trajectory: number[][];
357
+ fps?: number;
358
+ loop?: boolean;
359
+ playing?: boolean;
360
+ onFrame?: (frameIdx: number) => void;
361
+ }
362
+ interface SelectionHighlightProps {
363
+ bodyId: number | null;
364
+ color?: string;
365
+ emissiveIntensity?: number;
366
+ }
367
+ interface ContactListenerProps {
368
+ body: string;
369
+ onContactEnter?: (info: ContactInfo) => void;
370
+ onContactExit?: (info: ContactInfo) => void;
371
+ }
372
+ interface MujocoSimAPI {
373
+ readonly status: 'loading' | 'ready' | 'error';
374
+ readonly config: SceneConfig;
375
+ reset(): void;
376
+ setSpeed(multiplier: number): void;
377
+ togglePause(): boolean;
378
+ setPaused(paused: boolean): void;
379
+ step(n?: number): void;
380
+ getTime(): number;
381
+ getTimestep(): number;
382
+ applyKeyframe(nameOrIndex: string | number): void;
383
+ saveState(): StateSnapshot;
384
+ restoreState(snapshot: StateSnapshot): void;
385
+ setQpos(values: Float64Array | number[]): void;
386
+ setQvel(values: Float64Array | number[]): void;
387
+ getQpos(): Float64Array;
388
+ getQvel(): Float64Array;
389
+ setCtrl(nameOrValues: string | Record<string, number>, value?: number): void;
390
+ getCtrl(): Float64Array;
391
+ applyForce(bodyName: string, force: THREE.Vector3, point?: THREE.Vector3): void;
392
+ applyTorque(bodyName: string, torque: THREE.Vector3): void;
393
+ setExternalForce(bodyName: string, force: THREE.Vector3, torque: THREE.Vector3): void;
394
+ applyGeneralizedForce(values: Float64Array | number[]): void;
395
+ getSensorData(name: string): Float64Array | null;
396
+ getContacts(): ContactInfo[];
397
+ getBodies(): BodyInfo[];
398
+ getJoints(): JointInfo[];
399
+ getGeoms(): GeomInfo[];
400
+ getSites(): SiteInfo[];
401
+ getActuators(): ActuatorInfo[];
402
+ getSensors(): SensorInfo[];
403
+ getModelOption(): ModelOptions;
404
+ setGravity(g: [number, number, number]): void;
405
+ setTimestep(dt: number): void;
406
+ raycast(origin: THREE.Vector3, direction: THREE.Vector3, maxDist?: number): RayHit | null;
407
+ getKeyframeNames(): string[];
408
+ getKeyframeCount(): number;
409
+ loadScene(newConfig: SceneConfig): Promise<void>;
410
+ setIkEnabled(enabled: boolean): void;
411
+ moveTarget(pos: THREE.Vector3, duration?: number): void;
412
+ syncTargetToSite(): void;
413
+ solveIK(pos: THREE.Vector3, quat: THREE.Quaternion, currentQ: number[]): number[] | null;
414
+ getGizmoStats(): {
415
+ pos: THREE.Vector3;
416
+ rot: THREE.Euler;
417
+ } | null;
418
+ getCanvasSnapshot(width?: number, height?: number, mimeType?: string): string;
419
+ project2DTo3D(x: number, y: number, cameraPos: THREE.Vector3, lookAt: THREE.Vector3): {
420
+ point: THREE.Vector3;
421
+ bodyId: number;
422
+ geomId: number;
423
+ } | null;
424
+ setBodyMass(name: string, mass: number): void;
425
+ setGeomFriction(name: string, friction: [number, number, number]): void;
426
+ setGeomSize(name: string, size: [number, number, number]): void;
427
+ getCameraState(): {
428
+ position: THREE.Vector3;
429
+ target: THREE.Vector3;
430
+ };
431
+ moveCameraTo(position: THREE.Vector3, target: THREE.Vector3, durationMs: number): Promise<void>;
432
+ readonly mjModelRef: React.RefObject<MujocoModel | null>;
433
+ readonly mjDataRef: React.RefObject<MujocoData | null>;
434
+ }
435
+ type MujocoCanvasProps = Omit<CanvasProps, 'onError'> & {
436
+ config: SceneConfig;
437
+ onReady?: (api: MujocoSimAPI) => void;
438
+ onError?: (error: Error) => void;
439
+ onStep?: (time: number) => void;
440
+ onSelection?: (bodyId: number, name: string) => void;
441
+ gravity?: [number, number, number];
442
+ timestep?: number;
443
+ substeps?: number;
444
+ paused?: boolean;
445
+ speed?: number;
446
+ interpolate?: boolean;
447
+ gravityCompensation?: boolean;
448
+ mjcfLights?: boolean;
449
+ };
450
+ interface SitePositionResult {
451
+ position: React.RefObject<THREE.Vector3>;
452
+ quaternion: React.RefObject<THREE.Quaternion>;
453
+ }
454
+ interface MujocoContextValue {
455
+ mujoco: MujocoModule | null;
456
+ status: 'loading' | 'ready' | 'error';
457
+ error: string | null;
458
+ }
459
+ interface SensorResult {
460
+ value: React.RefObject<Float64Array>;
461
+ size: number;
462
+ }
463
+ interface BodyStateResult {
464
+ position: React.RefObject<THREE.Vector3>;
465
+ quaternion: React.RefObject<THREE.Quaternion>;
466
+ linearVelocity: React.RefObject<THREE.Vector3>;
467
+ angularVelocity: React.RefObject<THREE.Vector3>;
468
+ }
469
+ interface JointStateResult {
470
+ position: React.RefObject<number | Float64Array>;
471
+ velocity: React.RefObject<number | Float64Array>;
472
+ }
473
+
474
+ /**
475
+ * Hook to access the MuJoCo WASM module.
476
+ */
477
+ declare function useMujoco(): MujocoContextValue;
478
+ interface MujocoProviderProps {
479
+ wasmUrl?: string;
480
+ children: React.ReactNode;
481
+ onError?: (error: Error) => void;
482
+ }
483
+ /**
484
+ * MujocoProvider — WASM / module lifecycle.
485
+ * Loads the MuJoCo WASM module on mount and provides it to children via context.
486
+ */
487
+ declare function MujocoProvider({ wasmUrl, children, onError }: MujocoProviderProps): react_jsx_runtime.JSX.Element;
488
+
489
+ /**
490
+ * MujocoCanvas — thin R3F Canvas wrapper for MuJoCo scenes.
491
+ * Accepts all R3F Canvas props and forwards them through.
492
+ * Supports declarative physics config props (spec 1.1).
493
+ */
494
+ declare const MujocoCanvas: react.ForwardRefExoticComponent<Omit<MujocoCanvasProps, "ref"> & react.RefAttributes<HTMLCanvasElement>>;
495
+
496
+ /**
497
+ * @license
498
+ * SPDX-License-Identifier: Apache-2.0
499
+ */
500
+
501
+ interface GenericIKOptions {
502
+ maxIterations: number;
503
+ damping: number;
504
+ tolerance: number;
505
+ epsilon: number;
506
+ posWeight: number;
507
+ rotWeight: number;
508
+ }
509
+ /**
510
+ * Generic Damped Least-Squares IK solver.
511
+ * Uses finite-difference Jacobian via MuJoCo's mj_forward.
512
+ * Works for any MuJoCo model — no robot-specific parameters.
513
+ */
514
+ declare class GenericIK {
515
+ private mujoco;
516
+ constructor(mujoco: MujocoModule);
517
+ /**
518
+ * Solve IK for a target 6-DOF pose.
519
+ * @param model MuJoCo model
520
+ * @param data MuJoCo data (qpos will be temporarily modified, then restored)
521
+ * @param siteId Index of the end-effector site to control
522
+ * @param numJoints Number of arm joints (assumes qpos[0..numJoints-1])
523
+ * @param targetPos Target position in world frame
524
+ * @param targetQuat Target orientation in world frame
525
+ * @param currentQ Current joint angles (length = numJoints)
526
+ * @param opts Optional solver parameters
527
+ * @returns Joint angles array, or null if solver diverged
528
+ */
529
+ solve(model: MujocoModel, data: MujocoData, siteId: number, numJoints: number, targetPos: THREE.Vector3, targetQuat: THREE.Quaternion, currentQ: number[], opts?: Partial<GenericIKOptions>): number[] | null;
530
+ }
531
+
532
+ interface MujocoSimContextValue {
533
+ api: MujocoSimAPI;
534
+ mjModelRef: React.RefObject<MujocoModel | null>;
535
+ mjDataRef: React.RefObject<MujocoData | null>;
536
+ mujocoRef: React.RefObject<MujocoModule>;
537
+ configRef: React.RefObject<SceneConfig>;
538
+ siteIdRef: React.RefObject<number>;
539
+ gripperIdRef: React.RefObject<number>;
540
+ ikEnabledRef: React.RefObject<boolean>;
541
+ ikCalculatingRef: React.RefObject<boolean>;
542
+ pausedRef: React.RefObject<boolean>;
543
+ speedRef: React.RefObject<number>;
544
+ substepsRef: React.RefObject<number>;
545
+ ikTargetRef: React.RefObject<THREE.Group>;
546
+ genericIkRef: React.RefObject<GenericIK>;
547
+ ikSolveFnRef: React.RefObject<IKSolveFn>;
548
+ firstIkEnableRef: React.RefObject<boolean>;
549
+ gizmoAnimRef: React.RefObject<{
550
+ active: boolean;
551
+ startPos: THREE.Vector3;
552
+ endPos: THREE.Vector3;
553
+ startRot: THREE.Quaternion;
554
+ endRot: THREE.Quaternion;
555
+ startTime: number;
556
+ duration: number;
557
+ }>;
558
+ cameraAnimRef: React.RefObject<{
559
+ active: boolean;
560
+ startPos: THREE.Vector3;
561
+ endPos: THREE.Vector3;
562
+ startRot: THREE.Quaternion;
563
+ endRot: THREE.Quaternion;
564
+ startTarget: THREE.Vector3;
565
+ endTarget: THREE.Vector3;
566
+ startTime: number;
567
+ duration: number;
568
+ resolve: (() => void) | null;
569
+ }>;
570
+ onSelectionRef: React.RefObject<((bodyId: number, name: string) => void) | undefined>;
571
+ beforeStepCallbacks: React.RefObject<Set<PhysicsStepCallback>>;
572
+ afterStepCallbacks: React.RefObject<Set<PhysicsStepCallback>>;
573
+ status: 'loading' | 'ready' | 'error';
574
+ }
575
+ declare function useMujocoSim(): MujocoSimContextValue;
576
+ declare function useBeforePhysicsStep(callback: PhysicsStepCallback): void;
577
+ declare function useAfterPhysicsStep(callback: PhysicsStepCallback): void;
578
+ interface MujocoSimProviderProps {
579
+ mujoco: MujocoModule;
580
+ config: SceneConfig;
581
+ onReady?: (api: MujocoSimAPI) => void;
582
+ onError?: (error: Error) => void;
583
+ onStep?: (time: number) => void;
584
+ onSelection?: (bodyId: number, name: string) => void;
585
+ gravity?: [number, number, number];
586
+ timestep?: number;
587
+ substeps?: number;
588
+ paused?: boolean;
589
+ speed?: number;
590
+ interpolate?: boolean;
591
+ children: React.ReactNode;
592
+ }
593
+ declare function MujocoSimProvider({ mujoco, config, onReady, onError, onStep, onSelection, gravity, timestep, substeps, paused, speed, interpolate, children, }: MujocoSimProviderProps): react_jsx_runtime.JSX.Element;
594
+
595
+ /**
596
+ * @license
597
+ * SPDX-License-Identifier: Apache-2.0
598
+ */
599
+
600
+ /**
601
+ * Reads a null-terminated C string from MuJoCo's WASM memory.
602
+ */
603
+ declare function getName(mjModel: MujocoModel, address: number): string;
604
+ /**
605
+ * Find a site by name in the MuJoCo model. Returns -1 if not found.
606
+ */
607
+ declare function findSiteByName(mjModel: MujocoModel, name: string): number;
608
+ /**
609
+ * Find an actuator by name in the MuJoCo model. Returns -1 if not found.
610
+ */
611
+ declare function findActuatorByName(mjModel: MujocoModel, name: string): number;
612
+ /**
613
+ * Find a keyframe by name in the MuJoCo model. Returns -1 if not found.
614
+ */
615
+ declare function findKeyframeByName(mjModel: MujocoModel, name: string): number;
616
+ /**
617
+ * Find a body by name in the MuJoCo model. Returns -1 if not found.
618
+ */
619
+ declare function findBodyByName(mjModel: MujocoModel, name: string): number;
620
+ /**
621
+ * Find a joint by name in the MuJoCo model. Returns -1 if not found.
622
+ */
623
+ declare function findJointByName(mjModel: MujocoModel, name: string): number;
624
+ /**
625
+ * Find a geom by name in the MuJoCo model. Returns -1 if not found.
626
+ */
627
+ declare function findGeomByName(mjModel: MujocoModel, name: string): number;
628
+ /**
629
+ * Find a sensor by name in the MuJoCo model. Returns -1 if not found.
630
+ */
631
+ declare function findSensorByName(mjModel: MujocoModel, name: string): number;
632
+ /**
633
+ * Find a tendon by name in the MuJoCo model. Returns -1 if not found.
634
+ */
635
+ declare function findTendonByName(mjModel: MujocoModel, name: string): number;
636
+ interface LoadResult {
637
+ mjModel: MujocoModel;
638
+ mjData: MujocoData;
639
+ siteId: number;
640
+ gripperId: number;
641
+ }
642
+ /**
643
+ * Config-driven scene loader — replaces the old RobotLoader + patchSingleRobot approach.
644
+ */
645
+ declare function loadScene(mujoco: MujocoModule, config: SceneConfig, onProgress?: (msg: string) => void): Promise<LoadResult>;
646
+
647
+ /**
648
+ * @license
649
+ * SPDX-License-Identifier: Apache-2.0
650
+ */
651
+ /**
652
+ * SceneRenderer — creates and syncs MuJoCo body meshes every frame.
653
+ * Replaces RenderSystem.initScene() + RenderSystem.update() body loop.
654
+ */
655
+ declare function SceneRenderer(): react_jsx_runtime.JSX.Element;
656
+
657
+ /**
658
+ * IkGizmo — drei PivotControls that tracks a MuJoCo site.
659
+ *
660
+ * Props:
661
+ * - `siteName` — MuJoCo site to track. Defaults to `SceneConfig.tcpSiteName`.
662
+ * - `scale` — Gizmo handle scale. Default: 0.18.
663
+ * - `onDrag` — Custom drag callback `(pos, quat) => void`.
664
+ * When omitted, dragging enables IK and writes to the provider's IK target.
665
+ * When provided, the consumer handles what happens during drag.
666
+ *
667
+ * Multiple gizmos can be rendered — each tracks its own site.
668
+ * Zero gizmos is fine — programmatic IK control works via the provider API.
669
+ *
670
+ * Uses a tiny invisible mesh as child instead of axesHelper — PivotControls
671
+ * computes an anchor offset from children's bounding box, and axesHelper's
672
+ * (0→0.15) bounds would shift the handles away from the TCP origin.
673
+ */
674
+ declare function IkGizmo({ siteName, scale, onDrag }: IkGizmoProps): react_jsx_runtime.JSX.Element | null;
675
+
676
+ /**
677
+ * @license
678
+ * SPDX-License-Identifier: Apache-2.0
679
+ *
680
+ * ContactMarkers — instanced sphere visualization of MuJoCo contacts (spec 6.2)
681
+ *
682
+ * Fixed from original: reads data.ncon first, accesses contact via .get(i),
683
+ * limits to maxContacts to avoid WASM heap OOM.
684
+ */
685
+ interface ContactMarkersProps {
686
+ /** Maximum contacts to render. Default: 100. */
687
+ maxContacts?: number;
688
+ /** Sphere radius. Default: 0.005. */
689
+ radius?: number;
690
+ /** Color. Default: '#4f46e5'. */
691
+ color?: string;
692
+ /** Show markers. Default: true. */
693
+ visible?: boolean;
694
+ }
695
+ declare function ContactMarkers({ maxContacts, radius, color, visible, }?: ContactMarkersProps): react_jsx_runtime.JSX.Element | null;
696
+
697
+ /**
698
+ * DragInteraction — Ctrl/Cmd+click-drag to apply spring forces to MuJoCo bodies.
699
+ *
700
+ * Raycasts against scene meshes to identify bodies, then applies a spring
701
+ * force pulling the grabbed point toward the cursor each physics frame.
702
+ * Requires Ctrl (or Cmd on macOS) to avoid conflicting with OrbitControls.
703
+ *
704
+ * - `stiffness` — Spring constant * body mass. Default: 250.
705
+ * - `showArrow` — Show arrow from grab point toward cursor. Default: true.
706
+ *
707
+ * Forces compose with useGravityCompensation — the provider zeros
708
+ * qfrc_applied each frame, then all consumers add to it.
709
+ */
710
+ declare function DragInteraction({ stiffness, showArrow, }: DragInteractionProps): react_jsx_runtime.JSX.Element | null;
711
+
712
+ /**
713
+ * @license
714
+ * SPDX-License-Identifier: Apache-2.0
715
+ *
716
+ * SceneLights — auto-create Three.js lights from MJCF <light> elements (spec 6.3)
717
+ *
718
+ * WASM fields used: model.nlight, light_pos, light_dir, light_diffuse,
719
+ * light_specular, light_active, light_type, light_castshadow,
720
+ * light_attenuation, light_cutoff, light_exponent, light_intensity
721
+ *
722
+ * light_type: 0 = directional, 1 = spot (maps to mjLIGHT_DIRECTIONAL/mjLIGHT_SPOT)
723
+ * Note: light_directional does NOT exist in WASM — use light_type instead.
724
+ */
725
+
726
+ declare function SceneLights({ intensity }: SceneLightsProps): null;
727
+
728
+ /**
729
+ * Declarative debug visualization component.
730
+ * Renders wireframe geoms, site markers, joint axes, contact forces, COM markers, etc.
731
+ */
732
+ declare function Debug({ showGeoms, showSites, showJoints, showContacts, showCOM, showInertia, showTendons, }: DebugProps): react_jsx_runtime.JSX.Element | null;
733
+
734
+ /**
735
+ * @license
736
+ * SPDX-License-Identifier: Apache-2.0
737
+ *
738
+ * TendonRenderer — render tendons as tube geometries (spec 6.4)
739
+ *
740
+ * WASM fields used: model.ntendon, model.ten_wrapadr, model.ten_wrapnum
741
+ * data.wrap_xpos, data.ten_wrapadr (runtime)
742
+ *
743
+ * Note: ten_rgba and ten_width are NOT available in mujoco-js 0.0.7.
744
+ * Tendons use a default color and width.
745
+ */
746
+ declare function TendonRenderer(): react_jsx_runtime.JSX.Element | null;
747
+
748
+ /**
749
+ * @license
750
+ * SPDX-License-Identifier: Apache-2.0
751
+ *
752
+ * FlexRenderer — render deformable flex bodies (spec 6.4)
753
+ */
754
+ /**
755
+ * Renders MuJoCo flex (deformable) bodies as dynamic meshes.
756
+ * Vertices are updated every frame from flexvert_xpos.
757
+ */
758
+ declare function FlexRenderer(): react_jsx_runtime.JSX.Element | null;
759
+
760
+ /**
761
+ * @license
762
+ * SPDX-License-Identifier: Apache-2.0
763
+ *
764
+ * ContactListener — component form of contact events (spec 2.5)
765
+ */
766
+
767
+ /**
768
+ * Component form of useContactEvents.
769
+ * Fires onContactEnter/onContactExit callbacks when contacts change.
770
+ */
771
+ declare function ContactListener({ body, onContactEnter, onContactExit, }: ContactListenerProps): null;
772
+
773
+ /**
774
+ * @license
775
+ * SPDX-License-Identifier: Apache-2.0
776
+ *
777
+ * TrajectoryPlayer — component form of trajectory playback (spec 13.2)
778
+ */
779
+
780
+ /**
781
+ * Component wrapper for useTrajectoryPlayer.
782
+ * Provides declarative trajectory playback controlled via props.
783
+ */
784
+ declare function TrajectoryPlayer({ trajectory, fps, loop, playing, onFrame, }: TrajectoryPlayerProps): null;
785
+
786
+ /**
787
+ * @license
788
+ * SPDX-License-Identifier: Apache-2.0
789
+ *
790
+ * SelectionHighlight — highlight a selected body with emissive color (spec 6.5)
791
+ */
792
+
793
+ /**
794
+ * Applies emissive highlight to all meshes belonging to a body.
795
+ * Restores original emissive when bodyId changes or component unmounts.
796
+ */
797
+ declare function SelectionHighlight({ bodyId, color, emissiveIntensity, }: SelectionHighlightProps): null;
798
+
799
+ /**
800
+ * @license
801
+ * SPDX-License-Identifier: Apache-2.0
802
+ */
803
+
804
+ /**
805
+ * Returns a stable array of actuator metadata for building control UIs.
806
+ * Computed once when the model loads. Consumer reads/writes data.ctrl[id] directly.
807
+ */
808
+ declare function useActuators(): ActuatorInfo[];
809
+
810
+ /**
811
+ * @license
812
+ * SPDX-License-Identifier: Apache-2.0
813
+ */
814
+
815
+ /**
816
+ * Returns reactive refs for a MuJoCo site's world position and orientation.
817
+ * Refs are updated every frame without triggering React re-renders.
818
+ */
819
+ declare function useSitePosition(siteName: string): SitePositionResult;
820
+
821
+ /**
822
+ * @license
823
+ * SPDX-License-Identifier: Apache-2.0
824
+ */
825
+ /**
826
+ * Applies gravity compensation each physics frame by adding qfrc_bias
827
+ * (gravity + Coriolis forces) to qfrc_applied for each DOF.
828
+ *
829
+ * The provider zeros qfrc_applied at the start of each frame, so this
830
+ * hook (and DragInteraction) compose correctly — both add to a clean slate.
831
+ */
832
+ declare function useGravityCompensation(enabled?: boolean): void;
833
+
834
+ /**
835
+ * @license
836
+ * SPDX-License-Identifier: Apache-2.0
837
+ *
838
+ * useSensor / useSensors — MuJoCo sensor access hooks (spec 2.1)
839
+ */
840
+
841
+ /**
842
+ * Access a single MuJoCo sensor by name. Returns a ref-based value
843
+ * updated every physics frame without causing React re-renders.
844
+ */
845
+ declare function useSensor(name: string): SensorResult;
846
+ /**
847
+ * Enumerate all sensors in the loaded MuJoCo model.
848
+ * Returns a stable array recomputed only when the model changes.
849
+ */
850
+ declare function useSensors(): SensorInfo[];
851
+
852
+ /**
853
+ * @license
854
+ * SPDX-License-Identifier: Apache-2.0
855
+ *
856
+ * useJointState — per-joint position/velocity access (spec 2.3)
857
+ */
858
+
859
+ /**
860
+ * Track a MuJoCo joint's position and velocity by name.
861
+ * Values are updated every physics frame via refs (no re-renders).
862
+ *
863
+ * For hinge/slide joints, position/velocity are scalar (stored as Float64Array of length 1).
864
+ * For ball joints, position is quat (4), velocity is angular vel (3).
865
+ * For free joints, position is pos+quat (7), velocity is lin+ang vel (6).
866
+ */
867
+ declare function useJointState(name: string): JointStateResult;
868
+
869
+ /**
870
+ * @license
871
+ * SPDX-License-Identifier: Apache-2.0
872
+ *
873
+ * useBodyState — per-body position/velocity tracking (spec 2.2)
874
+ */
875
+
876
+ /**
877
+ * Track a MuJoCo body's world position, quaternion, and velocities.
878
+ * All values are ref-based — updated every physics frame without re-renders.
879
+ */
880
+ declare function useBodyState(name: string): BodyStateResult;
881
+
882
+ /**
883
+ * @license
884
+ * SPDX-License-Identifier: Apache-2.0
885
+ *
886
+ * useCtrl — clean read/write access to a named actuator's ctrl value (spec 3.1)
887
+ */
888
+ /**
889
+ * Access a single actuator's control value by name.
890
+ *
891
+ * Returns [currentValue, setValue]:
892
+ * - `currentValue` is a ref updated every frame (no re-renders).
893
+ * - `setValue` writes directly to `data.ctrl[actuatorId]`.
894
+ */
895
+ declare function useCtrl(name: string): [React.RefObject<number>, (value: number) => void];
896
+
897
+ /**
898
+ * @license
899
+ * SPDX-License-Identifier: Apache-2.0
900
+ *
901
+ * useContacts — structured contact query hook (spec 2.4)
902
+ * useContactEvents — contact enter/exit events (spec 2.5)
903
+ */
904
+
905
+ /**
906
+ * Track contacts for a specific body (or all contacts if no body specified).
907
+ * Calls the callback every physics frame with current contact list.
908
+ * Reads `data.ncon` first to avoid allocating for zero contacts.
909
+ */
910
+ declare function useContacts(bodyName?: string, callback?: (contacts: ContactInfo[]) => void): React.RefObject<ContactInfo[]>;
911
+ /**
912
+ * Contact enter/exit events for a specific body (spec 2.5).
913
+ * Tracks which geom pairs are in contact frame-to-frame and fires
914
+ * onEnter/onExit callbacks on transitions.
915
+ */
916
+ declare function useContactEvents(bodyName: string, handlers: {
917
+ onEnter?: (info: ContactInfo) => void;
918
+ onExit?: (info: ContactInfo) => void;
919
+ }): void;
920
+
921
+ /**
922
+ * @license
923
+ * SPDX-License-Identifier: Apache-2.0
924
+ *
925
+ * useKeyboardTeleop — keyboard teleoperation hook (spec 12.1)
926
+ */
927
+
928
+ /**
929
+ * Map keyboard keys to actuator commands.
930
+ *
931
+ * Supports three binding modes:
932
+ * - `delta`: Add delta to actuator value while key is held
933
+ * - `toggle`: Toggle between two values on key press
934
+ * - `set`: Set actuator to a fixed value while key is held
935
+ */
936
+ declare function useKeyboardTeleop(config: KeyboardTeleopConfig): void;
937
+
938
+ /**
939
+ * @license
940
+ * SPDX-License-Identifier: Apache-2.0
941
+ *
942
+ * usePolicy — policy decimation loop hook (spec 10.1)
943
+ */
944
+
945
+ /**
946
+ * Framework-agnostic policy execution hook.
947
+ *
948
+ * Manages a decimation loop: calls `onObservation` to build observations
949
+ * at the specified frequency, then calls `onAction` to apply the policy output.
950
+ * The actual inference (ONNX, TF.js, custom) is the consumer's responsibility.
951
+ *
952
+ * @param config Policy configuration
953
+ * @returns { step, isRunning } control handles
954
+ */
955
+ declare function usePolicy(config: PolicyConfig): {
956
+ readonly isRunning: boolean;
957
+ start: () => void;
958
+ stop: () => void;
959
+ readonly lastObservation: Float64Array<ArrayBufferLike> | Float32Array<ArrayBufferLike> | number[] | null;
960
+ };
961
+
962
+ /**
963
+ * @license
964
+ * SPDX-License-Identifier: Apache-2.0
965
+ *
966
+ * useTrajectoryPlayer — trajectory playback/scrubbing (spec 13.2)
967
+ */
968
+ interface TrajectoryPlayerOptions {
969
+ fps?: number;
970
+ loop?: boolean;
971
+ }
972
+ /**
973
+ * Play back a sequence of qpos frames, overriding simulation state.
974
+ *
975
+ * When playing, the simulation is effectively paused and qpos is set
976
+ * from the trajectory each render frame at the specified FPS.
977
+ */
978
+ declare function useTrajectoryPlayer(trajectory: number[][], options?: TrajectoryPlayerOptions): {
979
+ play: () => void;
980
+ pause: () => void;
981
+ seek: (frameIdx: number) => void;
982
+ reset: () => void;
983
+ readonly frame: number;
984
+ readonly playing: boolean;
985
+ readonly totalFrames: number;
986
+ };
987
+
988
+ /**
989
+ * @license
990
+ * SPDX-License-Identifier: Apache-2.0
991
+ *
992
+ * useTrajectoryRecorder — trajectory recording hook (spec 13.1)
993
+ */
994
+
995
+ interface RecorderOptions {
996
+ fields?: ('qpos' | 'qvel' | 'ctrl' | 'sensordata')[];
997
+ }
998
+ /**
999
+ * Record simulation trajectories for analysis, replay, or training data.
1000
+ */
1001
+ declare function useTrajectoryRecorder(options?: RecorderOptions): {
1002
+ start: () => void;
1003
+ stop: () => TrajectoryFrame[];
1004
+ downloadJSON: () => void;
1005
+ downloadCSV: () => void;
1006
+ readonly recording: boolean;
1007
+ readonly frameCount: number;
1008
+ readonly frames: TrajectoryFrame[];
1009
+ };
1010
+
1011
+ /**
1012
+ * @license
1013
+ * SPDX-License-Identifier: Apache-2.0
1014
+ *
1015
+ * useGamepad — gamepad teleoperation hook (spec 12.2)
1016
+ */
1017
+ interface GamepadConfig {
1018
+ /** Map gamepad axis index to actuator name. */
1019
+ axes?: Record<number, string>;
1020
+ /** Map gamepad button index to actuator name. */
1021
+ buttons?: Record<number, string>;
1022
+ /** Axis deadzone. Default: 0.1. */
1023
+ deadzone?: number;
1024
+ /** Scale factor for axis values. Default: 1.0. */
1025
+ scale?: number;
1026
+ /** Gamepad index. Default: 0 (first connected). */
1027
+ gamepadIndex?: number;
1028
+ enabled?: boolean;
1029
+ }
1030
+ /**
1031
+ * Map gamepad axes and buttons to actuator controls.
1032
+ * Axes map their -1..1 value (scaled) to the actuator.
1033
+ * Buttons map their 0..1 pressed value to the actuator.
1034
+ */
1035
+ declare function useGamepad(config: GamepadConfig): void;
1036
+
1037
+ /**
1038
+ * @license
1039
+ * SPDX-License-Identifier: Apache-2.0
1040
+ *
1041
+ * useVideoRecorder — canvas video recording hook (spec 13.3)
1042
+ */
1043
+ interface VideoRecorderOptions {
1044
+ fps?: number;
1045
+ mimeType?: string;
1046
+ }
1047
+ /**
1048
+ * Record the R3F canvas to a video file using MediaRecorder.
1049
+ */
1050
+ declare function useVideoRecorder(options?: VideoRecorderOptions): {
1051
+ start: () => void;
1052
+ stop: () => Promise<Blob>;
1053
+ download: (filename?: string) => Promise<void>;
1054
+ readonly recording: boolean;
1055
+ };
1056
+
1057
+ /**
1058
+ * @license
1059
+ * SPDX-License-Identifier: Apache-2.0
1060
+ *
1061
+ * useCtrlNoise — control noise / perturbation hook (spec 3.2)
1062
+ */
1063
+ interface CtrlNoiseConfig {
1064
+ /** Exponential filter rate (0-1). Higher = faster noise changes. Default: 0.01. */
1065
+ rate?: number;
1066
+ /** Standard deviation of Gaussian noise. Default: 0.05. */
1067
+ std?: number;
1068
+ /** Enable/disable. Default: true. */
1069
+ enabled?: boolean;
1070
+ }
1071
+ /**
1072
+ * Apply Gaussian noise with exponential filtering to all ctrl values.
1073
+ * Useful for robustness testing and domain randomization.
1074
+ *
1075
+ * noise[i] = (1 - rate) * noise[i] + rate * N(0, std)
1076
+ * data.ctrl[i] += noise[i]
1077
+ */
1078
+ declare function useCtrlNoise(config?: CtrlNoiseConfig): void;
1079
+
1080
+ export { type ActuatorInfo, type BodyInfo, type BodyStateResult, type ContactInfo, ContactListener, type ContactListenerProps, ContactMarkers, Debug, type DebugProps, DragInteraction, type DragInteractionProps, FlexRenderer, type GeomInfo, type IKSolveFn, IkGizmo, type IkGizmoProps, type JointInfo, type JointStateResult, type KeyBinding, type KeyboardTeleopConfig, type ModelOptions, MujocoCanvas, type MujocoCanvasProps, type MujocoContextValue, type MujocoData, type MujocoModel, type MujocoModule, MujocoProvider, type MujocoSimAPI, MujocoSimProvider, type PhysicsConfig, type PhysicsStepCallback, type PolicyConfig, type RayHit, type SceneConfig, SceneLights, type SceneLightsProps, type SceneMarker, type SceneObject, SceneRenderer, SelectionHighlight, type SelectionHighlightProps, type SensorInfo, type SensorResult, type SiteInfo, type SitePositionResult, type StateSnapshot, TendonRenderer, type TrajectoryData, type TrajectoryFrame, TrajectoryPlayer, type TrajectoryPlayerProps, type XmlPatch, findActuatorByName, findBodyByName, findGeomByName, findJointByName, findKeyframeByName, findSensorByName, findSiteByName, findTendonByName, getName, loadScene, useActuators, useAfterPhysicsStep, useBeforePhysicsStep, useBodyState, useContactEvents, useContacts, useCtrl, useCtrlNoise, useGamepad, useGravityCompensation, useJointState, useKeyboardTeleop, useMujoco, useMujocoSim, usePolicy, useSensor, useSensors, useSitePosition, useTrajectoryPlayer, useTrajectoryRecorder, useVideoRecorder };