mujoco-react 0.3.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,12 @@
1
+ <p align="center">
2
+ <img src="docs/images/mj2.gif" alt="mujoco-react demo" width="100%" />
3
+ </p>
4
+
1
5
  # mujoco-react
2
6
 
3
- A thin, unopinionated wrapper around [mujoco-js](https://github.com/nicepkg/mujoco-js) composable and extensible via React. Built on [React Three Fiber](https://docs.pmnd.rs/react-three-fiber). Works with **any robot, any scene**.
7
+ Composable [React Three Fiber](https://docs.pmnd.rs/react-three-fiber) wrapper around [mujoco-js](https://www.npmjs.com/package/mujoco-js). Load any MuJoCo model, step physics, render bodies, and write controllers as React components.
4
8
 
9
+ **[Live Demo](https://mujoco-react-example.pages.dev)** | **[Docs](https://dadd.mintlify.app)** | **[Example Source](https://github.com/noah-wardlow/mujoco-react-example)**
5
10
 
6
11
  ## Install
7
12
 
@@ -15,7 +20,6 @@ npm install mujoco-react three @react-three/fiber @react-three/drei
15
20
  import {
16
21
  MujocoProvider,
17
22
  MujocoCanvas,
18
- SceneRenderer,
19
23
  IkController,
20
24
  IkGizmo,
21
25
  } from 'mujoco-react';
@@ -41,7 +45,6 @@ function App() {
41
45
  style={{ width: '100%', height: '100vh' }}
42
46
  >
43
47
  <OrbitControls enableDamping makeDefault />
44
- <SceneRenderer />
45
48
  <IkController config={{ siteName: 'tcp', numJoints: 7 }}>
46
49
  <IkGizmo />
47
50
  </IkController>
@@ -53,32 +56,101 @@ function App() {
53
56
  }
54
57
  ```
55
58
 
59
+ ## Direct WASM Access
60
+
61
+ `useMujoco()` gives you the full typed MuJoCo WASM binary — `mj_step`, `mj_forward`, `MjModel`, `MjData`, and everything else:
62
+
63
+ ```tsx
64
+ import { useMujoco } from 'mujoco-react';
65
+
66
+ const { mujoco, status } = useMujoco();
67
+
68
+ if (mujoco) {
69
+ const model = mujoco.MjModel.loadFromXML('/path/to/scene.xml');
70
+ const data = new mujoco.MjData(model);
71
+ mujoco.mj_step(model, data);
72
+ console.log(data.qpos); // joint positions after one step
73
+ }
74
+ ```
75
+
76
+ Most users won't need this — `<MujocoCanvas>` and hooks like `useBeforePhysicsStep` handle the model/data lifecycle for you. But the raw module is always available when you need it.
77
+
78
+ ## Writing a Controller
79
+
80
+ A controller is a React component that calls `useBeforePhysicsStep` to write `data.ctrl` each frame:
81
+
82
+ ```tsx
83
+ import { useBeforePhysicsStep } from 'mujoco-react';
84
+
85
+ function MyController() {
86
+ useBeforePhysicsStep((_model, data) => {
87
+ data.ctrl[0] = Math.sin(data.time); // sine wave on actuator 0
88
+ data.ctrl[1] = data.sensordata[0] * -0.5; // feedback from a sensor
89
+ });
90
+ return null;
91
+ }
92
+ ```
93
+
94
+ Drop it into the tree:
95
+
96
+ ```tsx
97
+ <MujocoCanvas config={config}>
98
+ <MyController />
99
+ </MujocoCanvas>
100
+ ```
101
+
102
+ The `createController<TConfig>()` factory adds typed config and default merging for reusable plugins:
103
+
104
+ ```tsx
105
+ import { createController, useBeforePhysicsStep } from 'mujoco-react';
106
+
107
+ export const MyController = createController<{ gain: number }>(
108
+ { name: 'MyController', defaultConfig: { gain: 1.0 } },
109
+ ({ config }) => {
110
+ useBeforePhysicsStep((_model, data) => {
111
+ data.ctrl[0] = config.gain * Math.sin(data.time);
112
+ });
113
+ return null;
114
+ },
115
+ );
116
+
117
+ // <MyController config={{ gain: 2.0 }} />
118
+ ```
119
+
56
120
  ## Architecture
57
121
 
122
+ `<MujocoCanvas>` wraps R3F `<Canvas>` and forwards all Canvas props (`camera`, `shadows`, `gl`, etc.). For full control over the Canvas, use `<MujocoPhysics>` inside your own:
123
+
58
124
  ```
59
- <MujocoProvider> <- WASM module lifecycle
60
- <MujocoCanvas config={...}> <- Thin R3F Canvas wrapper + physics context
61
- <OrbitControls /> <- You add your own controls
62
- <SceneRenderer /> <- Syncs MuJoCo bodies to Three.js meshes
63
- <IkController config={..}> <- Opt-in controller plugin
64
- <IkGizmo /> <- PivotControls-based IK handle
65
- </IkController>
66
- <YourController /> <- Bring your own controller
67
- <YourLights /> <- You compose your own scene
68
- <YourGrid />
69
- </MujocoCanvas>
70
- </MujocoProvider>
125
+ <MujocoProvider> <MujocoProvider>
126
+ <MujocoCanvas config={...}> <Canvas shadows gl={...}>
127
+ <IkController config={..}> <MujocoPhysics config={...}>
128
+ <IkGizmo /> <MyController />
129
+ </IkController> </MujocoPhysics>
130
+ <MyController /> <EffectComposer>...</EffectComposer>
131
+ </MujocoCanvas> </Canvas>
132
+ </MujocoProvider> </MujocoProvider>
71
133
  ```
72
134
 
73
- The library provides **only MuJoCo engine concerns**: WASM lifecycle, physics stepping, and body rendering. Controllers (IK, teleoperation, RL policies) are composable plugins you opt into — or bring your own.
135
+ ### Custom IK Solvers
74
136
 
75
- ## Controller Plugins
137
+ The built-in `<IkController>` uses Damped Least-Squares. Pass `ikSolveFn` to swap in your own solver (analytical, learned, etc.):
76
138
 
77
- Controllers are opt-in plugins that compose library hooks. The library ships `IkController` built with the `createController` factory, but the real power is building your own.
139
+ ```tsx
140
+ import type { IKSolveFn } from 'mujoco-react';
141
+
142
+ const myIK: IKSolveFn = (pos, quat, currentQ) => {
143
+ return myAnalyticalSolver(pos, currentQ); // return joint angles or null
144
+ };
145
+
146
+ <IkController config={{ siteName: 'tcp', numJoints: 7, ikSolveFn: myIK }}>
147
+ <IkGizmo />
148
+ </IkController>
149
+ ```
78
150
 
79
151
  ### `<IkController>`
80
152
 
81
- The built-in IK controller. Wraps children with IK context — `<IkGizmo>` must be a descendant.
153
+ The library includes one controller for interactive end-effector control:
82
154
 
83
155
  ```tsx
84
156
  <IkController config={{ siteName: 'tcp', numJoints: 7 }}>
@@ -94,9 +166,7 @@ The built-in IK controller. Wraps children with IK context — `<IkGizmo>` must
94
166
  | `damping` | `number` | `0.01` | DLS damping |
95
167
  | `maxIterations` | `number` | `50` | Max solver iterations |
96
168
 
97
- ### `useIk()`
98
-
99
- Access IK state from inside `<IkController>`:
169
+ Access IK state from inside `<IkController>` with `useIk()`:
100
170
 
101
171
  ```tsx
102
172
  const { setIkEnabled, moveTarget, solveIK } = useIk();
@@ -106,36 +176,6 @@ Pass `{ optional: true }` for components that may or may not be inside an `<IkCo
106
176
 
107
177
  ```tsx
108
178
  const ikCtx = useIk({ optional: true });
109
- if (ikCtx?.ikEnabledRef.current) {
110
- ikCtx.setIkEnabled(false);
111
- }
112
- ```
113
-
114
- ### `createController<TConfig>(options, Impl)`
115
-
116
- Build your own controller plugin with the typed factory:
117
-
118
- ```tsx
119
- import { createController, useBeforePhysicsStep, useMujocoSim } from 'mujoco-react';
120
-
121
- interface MyConfig {
122
- gain: number;
123
- targetJoint: string;
124
- }
125
-
126
- function MyControllerImpl({ config }: { config: MyConfig; children?: React.ReactNode }) {
127
- useBeforePhysicsStep((_model, data) => {
128
- data.ctrl[0] = config.gain * Math.sin(data.time);
129
- });
130
- return null;
131
- }
132
-
133
- export const MyController = createController<MyConfig>(
134
- { name: 'MyController', defaultConfig: { gain: 1.0 } },
135
- MyControllerImpl,
136
- );
137
-
138
- // Usage: <MyController config={{ gain: 2.0, targetJoint: 'shoulder' }} />
139
179
  ```
140
180
 
141
181
  ## Loading Models
@@ -143,7 +183,7 @@ export const MyController = createController<MyConfig>(
143
183
  Models are loaded from any HTTP source via `SceneConfig.baseUrl`. Defaults to [MuJoCo Menagerie](https://github.com/google-deepmind/mujoco_menagerie) on GitHub.
144
184
 
145
185
  ```tsx
146
- // Menagerie robots just set robotId
186
+ // Menagerie robots: just set robotId
147
187
  const franka: SceneConfig = {
148
188
  robotId: 'franka_emika_panda',
149
189
  sceneFile: 'scene.xml',
@@ -233,13 +273,34 @@ Thin wrapper around R3F `<Canvas>`. Accepts all R3F Canvas props plus:
233
273
  | `substeps` | `number` | mj_step calls per frame |
234
274
  | `paused` | `boolean` | Declarative pause |
235
275
  | `speed` | `number` | Simulation speed multiplier |
236
- | `interpolate` | `boolean` | Interpolate body transforms between physics frames |
237
- | `gravityCompensation` | `boolean` | Auto-apply gravity compensation |
238
- | `mjcfLights` | `boolean` | Auto-create lights from MJCF model |
239
276
 
240
- ### `<SceneRenderer />`
277
+ ### `<MujocoPhysics>`
241
278
 
242
- Syncs MuJoCo bodies to Three.js meshes every frame. Must be inside `<MujocoCanvas>`.
279
+ Physics provider for use inside your own R3F `<Canvas>`. Same physics props as `<MujocoCanvas>` without the Canvas wrapper. Accepts a `ref` for the `MujocoSimAPI`.
280
+
281
+ ```tsx
282
+ <MujocoProvider>
283
+ <Canvas shadows camera={{ position: [2, 2, 2] }}>
284
+ <MujocoPhysics ref={apiRef} config={config} paused={paused}>
285
+ <MyController />
286
+ </MujocoPhysics>
287
+ <OrbitControls />
288
+ </Canvas>
289
+ </MujocoProvider>
290
+ ```
291
+
292
+ | Prop | Type | Description |
293
+ |------|------|-------------|
294
+ | `config` | `SceneConfig` | **Required.** Scene/robot configuration |
295
+ | `onReady` | `(api: MujocoSimAPI) => void` | Fires when model is loaded |
296
+ | `onError` | `(error: Error) => void` | Fires on scene load failure |
297
+ | `onStep` | `(time: number) => void` | Called each physics step |
298
+ | `onSelection` | `(bodyId: number, name: string) => void` | Called on double-click |
299
+ | `gravity` | `[number, number, number]` | Override model gravity |
300
+ | `timestep` | `number` | Override model.opt.timestep |
301
+ | `substeps` | `number` | mj_step calls per frame |
302
+ | `paused` | `boolean` | Declarative pause |
303
+ | `speed` | `number` | Simulation speed multiplier |
243
304
 
244
305
  ### `<IkGizmo />`
245
306
 
@@ -255,6 +316,15 @@ drei PivotControls gizmo that tracks a MuJoCo site and drives IK on drag. Must b
255
316
 
256
317
  Click-drag to apply spring forces to bodies. Raycasts to find bodies, applies `F = (mouseWorld - grabWorld) * body_mass * stiffness` via `mj_applyFT`.
257
318
 
319
+ ### R3F Group Props
320
+
321
+ All visual components (`DragInteraction`, `ContactMarkers`, `Debug`, `TendonRenderer`, `FlexRenderer`) accept standard R3F group props like `position`, `rotation`, `scale`, `visible`.
322
+
323
+ ```tsx
324
+ <ContactMarkers visible={showContacts} />
325
+ <Debug showJoints scale={0.5} />
326
+ ```
327
+
258
328
  ### `<ContactMarkers />`
259
329
 
260
330
  InstancedMesh showing MuJoCo contact points for debugging.
@@ -318,9 +388,23 @@ Plays back recorded qpos trajectories with scrubbing.
318
388
 
319
389
  ## Hooks
320
390
 
391
+ ### `useMujoco()`
392
+
393
+ Access the WASM module lifecycle from any child of `<MujocoProvider>`:
394
+
395
+ ```tsx
396
+ const { mujoco, status, error } = useMujoco();
397
+ ```
398
+
399
+ | Field | Type | Description |
400
+ |-------|------|-------------|
401
+ | `mujoco` | `MujocoModule \| null` | The raw WASM module, or `null` while loading |
402
+ | `status` | `'pending' \| 'error'` | Lifecycle state (absent once loaded) |
403
+ | `error` | `string \| null` | Error message if loading failed |
404
+
321
405
  ### `useMujocoSim()`
322
406
 
323
- Access the simulation API and internal refs:
407
+ Access the simulation API and internal refs (must be inside `<MujocoCanvas>` or `<MujocoPhysics>`):
324
408
 
325
409
  ```tsx
326
410
  const { api, mjModelRef, mjDataRef } = useMujocoSim();
@@ -577,34 +661,7 @@ The full API object available via `ref` or `useMujocoSim().api`:
577
661
 
578
662
  ### Building Controllers
579
663
 
580
- Controllers are thin components that compose library hooks. The simplest is a `useKeyboardTeleop` call:
581
-
582
- ```tsx
583
- function FrankaController() {
584
- useKeyboardTeleop({
585
- bindings: { v: { actuator: 'gripper', toggle: [0, 255] } },
586
- });
587
- return null;
588
- }
589
- ```
590
-
591
- For custom control (IK solvers, velocity control), use `useBeforePhysicsStep`:
592
-
593
- ```tsx
594
- function MyController() {
595
- const keys = useRef<Record<string, boolean>>({});
596
- // ... keyboard listeners ...
597
-
598
- useBeforePhysicsStep((_model, data) => {
599
- if (keys.current['KeyW']) data.ctrl[0] += 0.01;
600
- });
601
- return null;
602
- }
603
- ```
604
-
605
- For reusable controller plugins, use `createController<TConfig>()` to build typed components with config merging and metadata.
606
-
607
- See [Building Controllers](https://mujoco-react.mintlify.app/guides/building-controllers) for config-driven patterns, IK gizmo coexistence, and multi-arm support.
664
+ See [Building Controllers](https://dadd.mintlify.app/guides/building-controllers) for full patterns including config-driven controllers, IK gizmo coexistence, multi-arm support, and the `createController` factory.
608
665
 
609
666
  ### Graspable Objects
610
667
 
@@ -626,7 +683,7 @@ sceneObjects: [{
626
683
  }]
627
684
  ```
628
685
 
629
- Without `condim: 4` and high friction, objects slide out of the gripper when lifted. See [Graspable Objects](https://mujoco-react.mintlify.app/guides/graspable-objects) for details.
686
+ Without `condim: 4` and high friction, objects slide out of the gripper when lifted. See [Graspable Objects](https://dadd.mintlify.app/guides/graspable-objects) for details.
630
687
 
631
688
  ### Click-to-Select
632
689
 
@@ -639,14 +696,14 @@ function ClickSelectOverlay() {
639
696
  }
640
697
  ```
641
698
 
642
- See [Click-to-Select](https://mujoco-react.mintlify.app/guides/click-to-select) for the full implementation.
699
+ See [Click-to-Select](https://dadd.mintlify.app/guides/click-to-select) for the full implementation.
643
700
 
644
701
  ## useFrame Priority
645
702
 
646
703
  | Priority | Owner | Purpose |
647
704
  |----------|-------|---------|
648
705
  | -1 | MujocoSimProvider | beforeStep, mj_step, afterStep |
649
- | 0 (default) | SceneRenderer, IkController, your code | Body mesh sync, IK, rendering |
706
+ | 0 (default) | SceneRenderer (internal), IkController, your code | Body mesh sync, IK, rendering |
650
707
 
651
708
  ## Roadmap
652
709
 
@@ -658,7 +715,7 @@ Features planned but not yet implemented:
658
715
  | **URDF loading** | P2 | Load URDF models via MuJoCo's built-in URDF compiler |
659
716
  | **XML mutation / recompile** | P1 | `addBody()`, `removeBody()`, `recompile()` for runtime XML editing |
660
717
  | **Observation builder utilities** | P2 | Helpers for projected gravity, joint positions/velocities for RL |
661
- | **Physics interpolation** | P1 | Smooth rendering between physics ticks for 120Hz+ displays |
718
+ | **Physics interpolation** | P1 | Smooth rendering between physics ticks for very high refresh displays |
662
719
  | **Instanced geom rendering** | P2 | `<InstancedGeomRenderer />` for particle/granular sims |
663
720
  | **Web Worker physics** | P2 | Run `mj_step` off main thread via SharedArrayBuffer |
664
721
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { CanvasProps } from '@react-three/fiber';
2
+ import { CanvasProps, ThreeElements } from '@react-three/fiber';
3
3
  import * as THREE from 'three';
4
4
  import * as react from 'react';
5
5
 
@@ -240,12 +240,6 @@ interface SceneConfig {
240
240
  homeJoints?: number[];
241
241
  xmlPatches?: XmlPatch[];
242
242
  onReset?: (model: MujocoModel, data: MujocoData) => void;
243
- /** @deprecated Use IkController config.siteName instead. */
244
- tcpSiteName?: string;
245
- /** @deprecated Use your own gripper control logic instead. */
246
- gripperActuatorName?: string;
247
- /** @deprecated Use IkController config.numJoints instead. */
248
- numArmJoints?: number;
249
243
  }
250
244
  interface IkConfig {
251
245
  /** MuJoCo site name for IK target. */
@@ -270,7 +264,6 @@ interface PhysicsConfig {
270
264
  substeps?: number;
271
265
  paused?: boolean;
272
266
  speed?: number;
273
- interpolate?: boolean;
274
267
  }
275
268
  type IKSolveFn = (pos: THREE.Vector3, quat: THREE.Quaternion, currentQ: number[]) => number[] | null;
276
269
  type PhysicsStepCallback = (model: MujocoModel, data: MujocoData) => void;
@@ -470,9 +463,6 @@ type MujocoCanvasProps = Omit<CanvasProps, 'onError'> & {
470
463
  substeps?: number;
471
464
  paused?: boolean;
472
465
  speed?: number;
473
- interpolate?: boolean;
474
- gravityCompensation?: boolean;
475
- mjcfLights?: boolean;
476
466
  };
477
467
  interface SitePositionResult {
478
468
  position: React.RefObject<THREE.Vector3>;
@@ -524,6 +514,50 @@ declare function MujocoProvider({ wasmUrl, timeout, children, onError }: MujocoP
524
514
  */
525
515
  declare const MujocoCanvas: react.ForwardRefExoticComponent<Omit<MujocoCanvasProps, "ref"> & react.RefAttributes<MujocoSimAPI>>;
526
516
 
517
+ interface MujocoPhysicsProps {
518
+ /** Scene/robot configuration. */
519
+ config: SceneConfig;
520
+ /** Fires when model is loaded and API is ready. */
521
+ onReady?: (api: MujocoSimAPI) => void;
522
+ /** Fires on scene load failure. */
523
+ onError?: (error: Error) => void;
524
+ /** Called each physics step. */
525
+ onStep?: (time: number) => void;
526
+ /** Called on body double-click selection. */
527
+ onSelection?: (bodyId: number, name: string) => void;
528
+ /** Override model gravity. */
529
+ gravity?: [number, number, number];
530
+ /** Override model.opt.timestep. */
531
+ timestep?: number;
532
+ /** mj_step calls per frame. */
533
+ substeps?: number;
534
+ /** Declarative pause. */
535
+ paused?: boolean;
536
+ /** Simulation speed multiplier. */
537
+ speed?: number;
538
+ children: React.ReactNode;
539
+ }
540
+ /**
541
+ * MujocoPhysics — physics provider for use inside a user-owned R3F Canvas.
542
+ *
543
+ * This is the R3F-idiomatic alternative to MujocoCanvas. Instead of wrapping
544
+ * the Canvas, place this inside your own <Canvas>:
545
+ *
546
+ * ```tsx
547
+ * <MujocoProvider>
548
+ * <Canvas shadows camera={...}>
549
+ * <MujocoPhysics config={config} paused={paused}>
550
+ * <SceneRenderer />
551
+ * <OrbitControls />
552
+ * </MujocoPhysics>
553
+ * </Canvas>
554
+ * </MujocoProvider>
555
+ * ```
556
+ *
557
+ * Forward ref exposes MujocoSimAPI.
558
+ */
559
+ declare const MujocoPhysics: react.ForwardRefExoticComponent<MujocoPhysicsProps & react.RefAttributes<MujocoSimAPI>>;
560
+
527
561
  interface MujocoSimContextValue {
528
562
  api: MujocoSimAPI;
529
563
  mjModelRef: React.RefObject<MujocoModel | null>;
@@ -555,10 +589,9 @@ interface MujocoSimProviderProps {
555
589
  substeps?: number;
556
590
  paused?: boolean;
557
591
  speed?: number;
558
- interpolate?: boolean;
559
592
  children: React.ReactNode;
560
593
  }
561
- declare function MujocoSimProvider({ mujoco, config, apiRef: externalApiRef, onReady, onError, onStep, onSelection, gravity, timestep, substeps, paused, speed, interpolate, children, }: MujocoSimProviderProps): react_jsx_runtime.JSX.Element;
594
+ declare function MujocoSimProvider({ mujoco, config, apiRef: externalApiRef, onReady, onError, onStep, onSelection, gravity, timestep, substeps, paused, speed, children, }: MujocoSimProviderProps): react_jsx_runtime.JSX.Element;
562
595
 
563
596
  /**
564
597
  * @license
@@ -604,8 +637,6 @@ declare function findTendonByName(mjModel: MujocoModel, name: string): number;
604
637
  interface LoadResult {
605
638
  mjModel: MujocoModel;
606
639
  mjData: MujocoData;
607
- siteId: number;
608
- gripperId: number;
609
640
  }
610
641
  /**
611
642
  * Config-driven scene loader — replaces the old RobotLoader + patchSingleRobot approach.
@@ -687,16 +718,6 @@ declare function useIk(options: {
687
718
  optional: true;
688
719
  }): IkContextValue | null;
689
720
 
690
- /**
691
- * @license
692
- * SPDX-License-Identifier: Apache-2.0
693
- */
694
- /**
695
- * SceneRenderer — creates and syncs MuJoCo body meshes every frame.
696
- * Replaces RenderSystem.initScene() + RenderSystem.update() body loop.
697
- */
698
- declare function SceneRenderer(): react_jsx_runtime.JSX.Element;
699
-
700
721
  /**
701
722
  * IkGizmo — drei PivotControls that tracks a MuJoCo site.
702
723
  *
@@ -711,15 +732,6 @@ declare function SceneRenderer(): react_jsx_runtime.JSX.Element;
711
732
  */
712
733
  declare function IkGizmo({ siteName, scale, onDrag }: IkGizmoProps): react_jsx_runtime.JSX.Element | null;
713
734
 
714
- /**
715
- * @license
716
- * SPDX-License-Identifier: Apache-2.0
717
- *
718
- * ContactMarkers — instanced sphere visualization of MuJoCo contacts (spec 6.2)
719
- *
720
- * Fixed from original: reads data.ncon first, accesses contact via .get(i),
721
- * limits to maxContacts to avoid WASM heap OOM.
722
- */
723
735
  interface ContactMarkersProps {
724
736
  /** Maximum contacts to render. Default: 100. */
725
737
  maxContacts?: number;
@@ -730,7 +742,7 @@ interface ContactMarkersProps {
730
742
  /** Show markers. Default: true. */
731
743
  visible?: boolean;
732
744
  }
733
- declare function ContactMarkers({ maxContacts, radius, color, visible, }?: ContactMarkersProps): react_jsx_runtime.JSX.Element | null;
745
+ declare function ContactMarkers({ maxContacts, radius, color, visible, ...groupProps }?: ContactMarkersProps & Omit<ThreeElements['group'], 'ref' | 'visible'>): react_jsx_runtime.JSX.Element | null;
734
746
 
735
747
  /**
736
748
  * DragInteraction — Ctrl/Cmd+click-drag to apply spring forces to MuJoCo bodies.
@@ -745,7 +757,7 @@ declare function ContactMarkers({ maxContacts, radius, color, visible, }?: Conta
745
757
  * Forces compose with useGravityCompensation — the provider zeros
746
758
  * qfrc_applied each frame, then all consumers add to it.
747
759
  */
748
- declare function DragInteraction({ stiffness, showArrow, }: DragInteractionProps): react_jsx_runtime.JSX.Element | null;
760
+ declare function DragInteraction({ stiffness, showArrow, ...groupProps }: DragInteractionProps & Omit<ThreeElements['group'], 'ref'>): react_jsx_runtime.JSX.Element | null;
749
761
 
750
762
  /**
751
763
  * @license
@@ -767,33 +779,15 @@ declare function SceneLights({ intensity }: SceneLightsProps): null;
767
779
  * Declarative debug visualization component.
768
780
  * Renders wireframe geoms, site markers, joint axes, contact forces, COM markers, etc.
769
781
  */
770
- declare function Debug({ showGeoms, showSites, showJoints, showContacts, showCOM, showInertia, showTendons, }: DebugProps): react_jsx_runtime.JSX.Element | null;
782
+ declare function Debug({ showGeoms, showSites, showJoints, showContacts, showCOM, showInertia, showTendons, ...groupProps }: DebugProps & Omit<ThreeElements['group'], 'ref'>): react_jsx_runtime.JSX.Element | null;
771
783
 
772
- /**
773
- * @license
774
- * SPDX-License-Identifier: Apache-2.0
775
- *
776
- * TendonRenderer — render tendons as tube geometries (spec 6.4)
777
- *
778
- * WASM fields used: model.ntendon, model.ten_wrapadr, model.ten_wrapnum
779
- * data.wrap_xpos, data.ten_wrapadr (runtime)
780
- *
781
- * Note: ten_rgba and ten_width are NOT available in mujoco-js 0.0.7.
782
- * Tendons use a default color and width.
783
- */
784
- declare function TendonRenderer(): react_jsx_runtime.JSX.Element | null;
784
+ declare function TendonRenderer(props: Omit<ThreeElements['group'], 'ref'>): react_jsx_runtime.JSX.Element | null;
785
785
 
786
- /**
787
- * @license
788
- * SPDX-License-Identifier: Apache-2.0
789
- *
790
- * FlexRenderer — render deformable flex bodies (spec 6.4)
791
- */
792
786
  /**
793
787
  * Renders MuJoCo flex (deformable) bodies as dynamic meshes.
794
788
  * Vertices are updated every frame from flexvert_xpos.
795
789
  */
796
- declare function FlexRenderer(): react_jsx_runtime.JSX.Element | null;
790
+ declare function FlexRenderer(props: Omit<ThreeElements['group'], 'ref'>): react_jsx_runtime.JSX.Element | null;
797
791
 
798
792
  /**
799
793
  * @license
@@ -1160,4 +1154,4 @@ interface CameraAnimationAPI {
1160
1154
  */
1161
1155
  declare function useCameraAnimation(): CameraAnimationAPI;
1162
1156
 
1163
- export { type ActuatorInfo, type BodyInfo, type BodyStateResult, type CameraAnimationAPI, type ContactInfo, ContactListener, type ContactListenerProps, ContactMarkers, type ControllerComponent, type ControllerOptions, Debug, type DebugProps, DragInteraction, type DragInteractionProps, FlexRenderer, type GeomInfo, type IKSolveFn, type IkConfig, type IkContextValue, IkController, IkGizmo, type IkGizmoProps, type JointInfo, type JointStateResult, type KeyBinding, type KeyboardTeleopConfig, type ModelOptions, MujocoCanvas, type MujocoCanvasProps, type MujocoContact, type MujocoContactArray, 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, createController, findActuatorByName, findBodyByName, findGeomByName, findJointByName, findKeyframeByName, findSensorByName, findSiteByName, findTendonByName, getContact, getName, loadScene, useActuators, useAfterPhysicsStep, useBeforePhysicsStep, useBodyState, useCameraAnimation, useContactEvents, useContacts, useCtrl, useCtrlNoise, useGamepad, useGravityCompensation, useIk, useJointState, useKeyboardTeleop, useMujoco, useMujocoSim, usePolicy, useSceneLights, useSelectionHighlight, useSensor, useSensors, useSitePosition, useTrajectoryPlayer, useTrajectoryRecorder, useVideoRecorder };
1157
+ export { type ActuatorInfo, type BodyInfo, type BodyStateResult, type CameraAnimationAPI, type ContactInfo, ContactListener, type ContactListenerProps, ContactMarkers, type ControllerComponent, type ControllerOptions, Debug, type DebugProps, DragInteraction, type DragInteractionProps, FlexRenderer, type GeomInfo, type IKSolveFn, type IkConfig, type IkContextValue, IkController, IkGizmo, type IkGizmoProps, type JointInfo, type JointStateResult, type KeyBinding, type KeyboardTeleopConfig, type ModelOptions, MujocoCanvas, type MujocoCanvasProps, type MujocoContact, type MujocoContactArray, type MujocoContextValue, type MujocoData, type MujocoModel, type MujocoModule, MujocoPhysics, type MujocoPhysicsProps, MujocoProvider, type MujocoSimAPI, MujocoSimProvider, type PhysicsConfig, type PhysicsStepCallback, type PolicyConfig, type RayHit, type SceneConfig, SceneLights, type SceneLightsProps, type SceneMarker, type SceneObject, SelectionHighlight, type SelectionHighlightProps, type SensorInfo, type SensorResult, type SiteInfo, type SitePositionResult, type StateSnapshot, TendonRenderer, type TrajectoryData, type TrajectoryFrame, TrajectoryPlayer, type TrajectoryPlayerProps, type XmlPatch, createController, findActuatorByName, findBodyByName, findGeomByName, findJointByName, findKeyframeByName, findSensorByName, findSiteByName, findTendonByName, getContact, getName, loadScene, useActuators, useAfterPhysicsStep, useBeforePhysicsStep, useBodyState, useCameraAnimation, useContactEvents, useContacts, useCtrl, useCtrlNoise, useGamepad, useGravityCompensation, useIk, useJointState, useKeyboardTeleop, useMujoco, useMujocoSim, usePolicy, useSceneLights, useSelectionHighlight, useSensor, useSensors, useSitePosition, useTrajectoryPlayer, useTrajectoryRecorder, useVideoRecorder };