mujoco-react 8.11.0 → 9.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 +17 -17
- package/dist/{chunk-SEWQULWO.js → chunk-33CV6HSV.js} +3 -3
- package/dist/chunk-33CV6HSV.js.map +1 -0
- package/dist/index.d.ts +13 -13
- package/dist/index.js +50 -38
- package/dist/index.js.map +1 -1
- package/dist/spark.d.ts +1 -1
- package/dist/spark.js +1 -1
- package/dist/{types-BmneHLBM.d.ts → types-izZlUweI.d.ts} +52 -13
- package/package.json +1 -1
- package/src/components/DragInteraction.tsx +1 -1
- package/src/components/IkGizmo.tsx +2 -2
- package/src/components/SceneRenderer.tsx +1 -1
- package/src/components/TrajectoryPlayer.tsx +4 -1
- package/src/components/VisualScenario.tsx +1 -1
- package/src/core/MujocoPhysics.tsx +10 -4
- package/src/core/MujocoSimProvider.tsx +15 -12
- package/src/core/createController.tsx +2 -2
- package/src/hooks/useBodyState.ts +1 -1
- package/src/hooks/useContacts.ts +1 -1
- package/src/hooks/useCtrlNoise.ts +1 -1
- package/src/hooks/useGamepad.ts +1 -1
- package/src/hooks/useGravityCompensation.ts +1 -1
- package/src/hooks/useIkController.ts +22 -13
- package/src/hooks/useJointState.ts +1 -1
- package/src/hooks/useKeyboardTeleop.ts +1 -1
- package/src/hooks/usePolicy.ts +1 -1
- package/src/hooks/useSensor.ts +1 -1
- package/src/hooks/useTrajectoryPlayer.ts +4 -4
- package/src/hooks/useTrajectoryRecorder.ts +1 -1
- package/src/index.ts +10 -0
- package/src/types.ts +60 -18
- package/dist/chunk-SEWQULWO.js.map +0 -1
package/dist/spark.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as _sparkjsdev_spark from '@sparkjsdev/spark';
|
|
3
|
-
import {
|
|
3
|
+
import { n as SplatEnvironmentProps } from './types-izZlUweI.js';
|
|
4
4
|
import 'react';
|
|
5
5
|
import '@react-three/fiber';
|
|
6
6
|
import 'three';
|
package/dist/spark.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useSplatEnvironment, SplatEnvironment } from './chunk-
|
|
1
|
+
import { useSplatEnvironment, SplatEnvironment } from './chunk-33CV6HSV.js';
|
|
2
2
|
import { useThree } from '@react-three/fiber';
|
|
3
3
|
import { useState, useEffect, useCallback, useMemo, useRef } from 'react';
|
|
4
4
|
import * as THREE from 'three';
|
|
@@ -327,7 +327,7 @@ interface LoadFromFilesOptions {
|
|
|
327
327
|
homeJoints?: number[];
|
|
328
328
|
xmlPatches?: XmlPatch[];
|
|
329
329
|
sceneObjects?: SceneObject[];
|
|
330
|
-
onReset?: (
|
|
330
|
+
onReset?: (input: ResetCallbackInput) => void;
|
|
331
331
|
}
|
|
332
332
|
interface SceneConfig {
|
|
333
333
|
/** Base URL for fetching model files. The loader fetches `src + sceneFile` and follows dependencies. */
|
|
@@ -347,7 +347,7 @@ interface SceneConfig {
|
|
|
347
347
|
sceneObjects?: SceneObject[];
|
|
348
348
|
homeJoints?: number[];
|
|
349
349
|
xmlPatches?: XmlPatch[];
|
|
350
|
-
onReset?: (
|
|
350
|
+
onReset?: (input: ResetCallbackInput) => void;
|
|
351
351
|
}
|
|
352
352
|
type ResourceSelector<TInfo, TName extends string = string> = TName | readonly TName[] | RegExp | ((info: TInfo) => boolean);
|
|
353
353
|
interface IkConfig {
|
|
@@ -380,7 +380,7 @@ interface IkContextValue {
|
|
|
380
380
|
setIkEnabled: (enabled: boolean) => void;
|
|
381
381
|
moveTarget: (pos: THREE.Vector3, duration?: number) => void;
|
|
382
382
|
syncTargetToSite: () => void;
|
|
383
|
-
solveIK: (
|
|
383
|
+
solveIK: (input: IkSolveInput) => number[] | null;
|
|
384
384
|
getGizmoStats: () => {
|
|
385
385
|
pos: THREE.Vector3;
|
|
386
386
|
rot: THREE.Euler;
|
|
@@ -398,14 +398,38 @@ interface PhysicsConfig {
|
|
|
398
398
|
paused?: boolean;
|
|
399
399
|
speed?: number;
|
|
400
400
|
}
|
|
401
|
-
type IKSolveFn = (
|
|
401
|
+
type IKSolveFn = (input: IkSolveInput) => number[] | null;
|
|
402
|
+
interface IkSolveInput {
|
|
403
|
+
position: THREE.Vector3;
|
|
404
|
+
quaternion: THREE.Quaternion;
|
|
405
|
+
currentQ: number[];
|
|
406
|
+
context?: IKSolveContext;
|
|
407
|
+
}
|
|
402
408
|
interface IKSolveContext {
|
|
403
409
|
model: MujocoModel;
|
|
404
410
|
data: MujocoData;
|
|
405
411
|
siteId: number;
|
|
406
412
|
controlGroup: ControlGroupInfo;
|
|
407
413
|
}
|
|
408
|
-
|
|
414
|
+
interface PhysicsStepInput {
|
|
415
|
+
model: MujocoModel;
|
|
416
|
+
data: MujocoData;
|
|
417
|
+
}
|
|
418
|
+
interface ResetCallbackInput extends PhysicsStepInput {
|
|
419
|
+
}
|
|
420
|
+
interface ReadyCallbackInput {
|
|
421
|
+
api: MujocoSimAPI;
|
|
422
|
+
}
|
|
423
|
+
interface StepCallbackInput {
|
|
424
|
+
time: number;
|
|
425
|
+
model: MujocoModel;
|
|
426
|
+
data: MujocoData;
|
|
427
|
+
}
|
|
428
|
+
interface SelectionCallbackInput {
|
|
429
|
+
bodyId: number;
|
|
430
|
+
name: string;
|
|
431
|
+
}
|
|
432
|
+
type PhysicsStepCallback = (input: PhysicsStepInput) => void;
|
|
409
433
|
interface StateSnapshot {
|
|
410
434
|
time: number;
|
|
411
435
|
qpos: Float64Array;
|
|
@@ -606,7 +630,11 @@ interface IkGizmoProps {
|
|
|
606
630
|
controller: IkContextValue;
|
|
607
631
|
siteName?: string;
|
|
608
632
|
scale?: number;
|
|
609
|
-
onDrag?: (
|
|
633
|
+
onDrag?: (input: IkGizmoDragInput) => void;
|
|
634
|
+
}
|
|
635
|
+
interface IkGizmoDragInput {
|
|
636
|
+
position: THREE.Vector3;
|
|
637
|
+
quaternion: THREE.Quaternion;
|
|
610
638
|
}
|
|
611
639
|
interface DragInteractionProps {
|
|
612
640
|
stiffness?: number;
|
|
@@ -718,7 +746,11 @@ interface VisualScenarioEffectsProps {
|
|
|
718
746
|
background?: THREE.ColorRepresentation;
|
|
719
747
|
fogNear?: number;
|
|
720
748
|
fogFar?: number;
|
|
721
|
-
materialFilter?: (
|
|
749
|
+
materialFilter?: (input: VisualScenarioMaterialFilterInput) => boolean;
|
|
750
|
+
}
|
|
751
|
+
interface VisualScenarioMaterialFilterInput {
|
|
752
|
+
object: THREE.Object3D;
|
|
753
|
+
material: THREE.Material;
|
|
722
754
|
}
|
|
723
755
|
type TrajectoryInput = TrajectoryFrame[] | number[][];
|
|
724
756
|
interface TrajectoryPlayerProps {
|
|
@@ -728,9 +760,16 @@ interface TrajectoryPlayerProps {
|
|
|
728
760
|
loop?: boolean;
|
|
729
761
|
playing?: boolean;
|
|
730
762
|
mode?: 'kinematic' | 'physics';
|
|
731
|
-
onFrame?: (
|
|
763
|
+
onFrame?: (input: TrajectoryFrameCallbackInput) => void;
|
|
732
764
|
onComplete?: () => void;
|
|
733
|
-
onStateChange?: (
|
|
765
|
+
onStateChange?: (input: TrajectoryStateChangeInput) => void;
|
|
766
|
+
}
|
|
767
|
+
interface TrajectoryFrameCallbackInput {
|
|
768
|
+
frameIndex: number;
|
|
769
|
+
frame: TrajectoryFrame | number[] | undefined;
|
|
770
|
+
}
|
|
771
|
+
interface TrajectoryStateChangeInput {
|
|
772
|
+
state: PlaybackState;
|
|
734
773
|
}
|
|
735
774
|
interface ContactListenerProps {
|
|
736
775
|
body: Bodies;
|
|
@@ -814,10 +853,10 @@ type MujocoCanvasProps = Omit<CanvasProps, 'onError'> & {
|
|
|
814
853
|
config: SceneConfig;
|
|
815
854
|
/** R3F content rendered while the MuJoCo WASM module is still loading. */
|
|
816
855
|
loadingFallback?: ReactNode;
|
|
817
|
-
onReady?: (
|
|
856
|
+
onReady?: (input: ReadyCallbackInput) => void;
|
|
818
857
|
onError?: (error: Error) => void;
|
|
819
|
-
onStep?: (
|
|
820
|
-
onSelection?: (
|
|
858
|
+
onStep?: (input: StepCallbackInput) => void;
|
|
859
|
+
onSelection?: (input: SelectionCallbackInput) => void;
|
|
821
860
|
gravity?: [number, number, number];
|
|
822
861
|
timestep?: number;
|
|
823
862
|
substeps?: number;
|
|
@@ -868,4 +907,4 @@ interface JointStateResult {
|
|
|
868
907
|
velocity: React__default.RefObject<number | Float64Array>;
|
|
869
908
|
}
|
|
870
909
|
|
|
871
|
-
export { type
|
|
910
|
+
export { type PolicyConfig as $, type ActuatedJointInfo as A, type BodyProps as B, type ControlGroupInfo as C, type DragInteractionProps as D, type ActuatorInfo as E, type Sites as F, type GeomInfo as G, type SitePositionResult as H, type IkConfig as I, type Sensors as J, type SensorHandle as K, type SensorInfo as L, type MujocoContextValue as M, type Joints as N, type ObservationConfig as O, type PhysicsStepCallback as P, type JointStateResult as Q, type ReadyCallbackInput as R, type SceneConfig as S, type TrajectoryPlayerProps as T, type Bodies as U, type VisualScenarioEffectsProps as V, type BodyStateResult as W, type Actuators as X, type CtrlHandle as Y, type ContactInfo as Z, type KeyboardTeleopConfig as _, type MujocoCanvasProps as a, type PolicyVector as a0, type ObservationHandle as a1, type TrajectoryInput as a2, type TrajectoryStateChangeInput as a3, type PlaybackState as a4, type TrajectoryFrame as a5, type BodyInfo as a6, type ControlJointInfo as a7, type Geoms as a8, type IKSolveFn as a9, RobotResources as aA, RobotSensors as aB, RobotSites as aC, type Robots as aD, type ScenarioCameraConfig as aE, type ScenarioMaterialConfig as aF, type SceneMarker as aG, type SceneObject as aH, type SensorResult as aI, type SiteInfo as aJ, type SplatAssetConfig as aK, type SplatScenarioConfig as aL, type StateSnapshot as aM, type TrajectoryData as aN, type TrajectoryFrameCallbackInput as aO, type VisualScenarioMaterialFilterInput as aP, type XmlPatch as aQ, getContact as aR, registerRobotResources as aS, type IkGizmoDragInput as aa, type IkSolveInput as ab, type JointInfo as ac, type KeyBinding as ad, type Keyframes as ae, type ModelOptions as af, type MujocoContact as ag, type MujocoContactArray as ah, type ObservationLayoutItem as ai, type ObservationOutput as aj, type PhysicsConfig as ak, type PhysicsStepInput as al, type PolicyActionInput as am, type PolicyInferenceInput as an, type PolicyObservationInput as ao, type RayHit as ap, type Register as aq, type RegisteredRobotMap as ar, type ResetCallbackInput as as, type ResourceSelector as at, RobotActuators as au, RobotBodies as av, RobotGeoms as aw, RobotJoints as ax, RobotKeyframes as ay, type RobotResource as az, type MujocoSimAPI as b, type StepCallbackInput as c, type SelectionCallbackInput as d, type MujocoModule as e, type MujocoModel as f, type MujocoData as g, type ControlGroupSelector as h, type ObservationResult as i, type IkContextValue as j, type IkGizmoProps as k, type SceneLightsProps as l, type ScenarioLightingProps as m, type SplatEnvironmentProps as n, type VisualScenarioConfig as o, type SplatRendererKind as p, type PairedSplatEnvironmentConfig as q, type SplatFormat as r, type SplatCollisionProxyConfig as s, type SplatCollisionPrimitive as t, type ScenarioLightingPreset as u, type SplatEnvironmentMetadataInput as v, type SplatEnvironmentMetadata as w, type SplatSceneInput as x, type DebugProps as y, type ContactListenerProps as z };
|
package/package.json
CHANGED
|
@@ -168,7 +168,7 @@ export function DragInteraction({
|
|
|
168
168
|
}, [gl, camera, scene, controls, mjDataRef]);
|
|
169
169
|
|
|
170
170
|
// Apply spring force each physics frame
|
|
171
|
-
useBeforePhysicsStep((model, data) => {
|
|
171
|
+
useBeforePhysicsStep(({ model, data }) => {
|
|
172
172
|
if (!draggingRef.current || bodyIdRef.current <= 0) return;
|
|
173
173
|
|
|
174
174
|
const bid = bodyIdRef.current;
|
|
@@ -26,7 +26,7 @@ const _scale = new THREE.Vector3(1, 1, 1);
|
|
|
26
26
|
* - `controller` — IkContextValue from `useIkController()`.
|
|
27
27
|
* - `siteName` — MuJoCo site to track. Defaults to the controller's configured site.
|
|
28
28
|
* - `scale` — Gizmo handle scale. Default: 0.18.
|
|
29
|
-
* - `onDrag` — Custom drag callback `(
|
|
29
|
+
* - `onDrag` — Custom drag callback `({ position, quaternion }) => void`.
|
|
30
30
|
* When omitted, dragging enables IK and writes to the IK target.
|
|
31
31
|
* When provided, the consumer handles what happens during drag.
|
|
32
32
|
*/
|
|
@@ -112,7 +112,7 @@ export function IkGizmo({ controller, siteName, scale = 0.18, onDrag }: IkGizmoP
|
|
|
112
112
|
world.decompose(_pos, _quat, _scale);
|
|
113
113
|
if (onDrag) {
|
|
114
114
|
// Custom: consumer handles the drag
|
|
115
|
-
onDrag(_pos.clone(), _quat.clone());
|
|
115
|
+
onDrag({ position: _pos.clone(), quaternion: _quat.clone() });
|
|
116
116
|
} else {
|
|
117
117
|
// Default: write to IK target
|
|
118
118
|
const target = ikTargetRef.current;
|
|
@@ -139,7 +139,7 @@ export function SceneRenderer(props: Omit<ThreeElements['group'], 'ref'>) {
|
|
|
139
139
|
const model = mjModelRef.current;
|
|
140
140
|
if (model && bodyID < model.nbody && onSelectionRef.current) {
|
|
141
141
|
const name = getName(model, model.name_bodyadr[bodyID]);
|
|
142
|
-
onSelectionRef.current(bodyID, name);
|
|
142
|
+
onSelectionRef.current({ bodyId: bodyID, name });
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
145
|
}}
|
|
@@ -54,7 +54,10 @@ export function TrajectoryPlayer({
|
|
|
54
54
|
const currentFrame = player.frame;
|
|
55
55
|
if (currentFrame !== lastReportedFrameRef.current && player.playing) {
|
|
56
56
|
lastReportedFrameRef.current = currentFrame;
|
|
57
|
-
onFrameRef.current(
|
|
57
|
+
onFrameRef.current({
|
|
58
|
+
frameIndex: currentFrame,
|
|
59
|
+
frame: trajectory[currentFrame],
|
|
60
|
+
});
|
|
58
61
|
}
|
|
59
62
|
});
|
|
60
63
|
|
|
@@ -490,7 +490,7 @@ function applyScenarioMaterials(
|
|
|
490
490
|
for (const material of normalizeMaterials(object.material)) {
|
|
491
491
|
const mutable = getMutableScenarioMaterial(material);
|
|
492
492
|
if (!mutable) continue;
|
|
493
|
-
if (materialFilter && !materialFilter(object, material)) continue;
|
|
493
|
+
if (materialFilter && !materialFilter({ object, material })) continue;
|
|
494
494
|
|
|
495
495
|
if (!snapshots.has(material)) {
|
|
496
496
|
snapshots.set(material, {
|
|
@@ -6,19 +6,25 @@
|
|
|
6
6
|
import { forwardRef, useEffect } from 'react';
|
|
7
7
|
import { useMujocoWasm } from './MujocoProvider';
|
|
8
8
|
import { MujocoSimProvider } from './MujocoSimProvider';
|
|
9
|
-
import type {
|
|
9
|
+
import type {
|
|
10
|
+
MujocoSimAPI,
|
|
11
|
+
ReadyCallbackInput,
|
|
12
|
+
SceneConfig,
|
|
13
|
+
SelectionCallbackInput,
|
|
14
|
+
StepCallbackInput,
|
|
15
|
+
} from '../types';
|
|
10
16
|
|
|
11
17
|
export interface MujocoPhysicsProps {
|
|
12
18
|
/** Scene/robot configuration. */
|
|
13
19
|
config: SceneConfig;
|
|
14
20
|
/** Fires when model is loaded and API is ready. */
|
|
15
|
-
onReady?: (
|
|
21
|
+
onReady?: (input: ReadyCallbackInput) => void;
|
|
16
22
|
/** Fires on scene load failure. */
|
|
17
23
|
onError?: (error: Error) => void;
|
|
18
24
|
/** Called each physics step. */
|
|
19
|
-
onStep?: (
|
|
25
|
+
onStep?: (input: StepCallbackInput) => void;
|
|
20
26
|
/** Called on body double-click selection. */
|
|
21
|
-
onSelection?: (
|
|
27
|
+
onSelection?: (input: SelectionCallbackInput) => void;
|
|
22
28
|
/** Override model gravity. */
|
|
23
29
|
gravity?: [number, number, number];
|
|
24
30
|
/** Override model.opt.timestep. */
|
|
@@ -31,11 +31,14 @@ import {
|
|
|
31
31
|
MujocoSimAPI,
|
|
32
32
|
PhysicsStepCallback,
|
|
33
33
|
RayHit,
|
|
34
|
+
ReadyCallbackInput,
|
|
34
35
|
SceneConfig,
|
|
35
36
|
SceneObject,
|
|
37
|
+
SelectionCallbackInput,
|
|
36
38
|
SensorInfo,
|
|
37
39
|
SiteInfo,
|
|
38
40
|
StateSnapshot,
|
|
41
|
+
StepCallbackInput,
|
|
39
42
|
XmlPatch,
|
|
40
43
|
} from '../types';
|
|
41
44
|
import {
|
|
@@ -117,7 +120,7 @@ export interface MujocoSimContextValue {
|
|
|
117
120
|
interpolateRef: React.RefObject<boolean>;
|
|
118
121
|
interpolationStateRef: React.RefObject<BodyInterpolationState>;
|
|
119
122
|
onSelectionRef: React.RefObject<
|
|
120
|
-
((
|
|
123
|
+
((input: SelectionCallbackInput) => void) | undefined
|
|
121
124
|
>;
|
|
122
125
|
beforeStepCallbacks: React.RefObject<Set<PhysicsStepCallback>>;
|
|
123
126
|
afterStepCallbacks: React.RefObject<Set<PhysicsStepCallback>>;
|
|
@@ -197,7 +200,7 @@ export function useBeforePhysicsStep(callback: PhysicsStepCallback) {
|
|
|
197
200
|
callbackRef.current = callback;
|
|
198
201
|
|
|
199
202
|
useEffect(() => {
|
|
200
|
-
const wrapped: PhysicsStepCallback = (
|
|
203
|
+
const wrapped: PhysicsStepCallback = (input) => callbackRef.current(input);
|
|
201
204
|
beforeStepCallbacks.current.add(wrapped);
|
|
202
205
|
return () => { beforeStepCallbacks.current.delete(wrapped); };
|
|
203
206
|
}, [beforeStepCallbacks]);
|
|
@@ -209,7 +212,7 @@ export function useAfterPhysicsStep(callback: PhysicsStepCallback) {
|
|
|
209
212
|
callbackRef.current = callback;
|
|
210
213
|
|
|
211
214
|
useEffect(() => {
|
|
212
|
-
const wrapped: PhysicsStepCallback = (
|
|
215
|
+
const wrapped: PhysicsStepCallback = (input) => callbackRef.current(input);
|
|
213
216
|
afterStepCallbacks.current.add(wrapped);
|
|
214
217
|
return () => { afterStepCallbacks.current.delete(wrapped); };
|
|
215
218
|
}, [afterStepCallbacks]);
|
|
@@ -219,10 +222,10 @@ interface MujocoSimProviderProps {
|
|
|
219
222
|
mujoco: MujocoModule;
|
|
220
223
|
config: SceneConfig;
|
|
221
224
|
apiRef?: React.ForwardedRef<MujocoSimAPI>;
|
|
222
|
-
onReady?: (
|
|
225
|
+
onReady?: (input: ReadyCallbackInput) => void;
|
|
223
226
|
onError?: (error: Error) => void;
|
|
224
|
-
onStep?: (
|
|
225
|
-
onSelection?: (
|
|
227
|
+
onStep?: (input: StepCallbackInput) => void;
|
|
228
|
+
onSelection?: (input: SelectionCallbackInput) => void;
|
|
226
229
|
// Declarative physics config props
|
|
227
230
|
gravity?: [number, number, number];
|
|
228
231
|
timestep?: number;
|
|
@@ -380,7 +383,7 @@ export function MujocoSimProvider({
|
|
|
380
383
|
useEffect(() => {
|
|
381
384
|
if (status === 'ready') {
|
|
382
385
|
const api = apiRef.current;
|
|
383
|
-
if (onReady) onReady(api);
|
|
386
|
+
if (onReady) onReady({ api });
|
|
384
387
|
// Assign the forwarded ref
|
|
385
388
|
if (externalApiRef) {
|
|
386
389
|
if (typeof externalApiRef === 'function') {
|
|
@@ -409,7 +412,7 @@ export function MujocoSimProvider({
|
|
|
409
412
|
|
|
410
413
|
// Before-step callbacks
|
|
411
414
|
for (const cb of beforeStepCallbacks.current) {
|
|
412
|
-
cb(model, data);
|
|
415
|
+
cb({ model, data });
|
|
413
416
|
}
|
|
414
417
|
|
|
415
418
|
const numSubsteps = substepsRef.current;
|
|
@@ -466,17 +469,17 @@ export function MujocoSimProvider({
|
|
|
466
469
|
interpolationStateRef.current.valid = true;
|
|
467
470
|
|
|
468
471
|
if (!stepped) {
|
|
469
|
-
onStepRef.current?.(data.time);
|
|
472
|
+
onStepRef.current?.({ time: data.time, model, data });
|
|
470
473
|
return;
|
|
471
474
|
}
|
|
472
475
|
}
|
|
473
476
|
|
|
474
477
|
// After-step callbacks
|
|
475
478
|
for (const cb of afterStepCallbacks.current) {
|
|
476
|
-
cb(model, data);
|
|
479
|
+
cb({ model, data });
|
|
477
480
|
}
|
|
478
481
|
|
|
479
|
-
onStepRef.current?.(data.time);
|
|
482
|
+
onStepRef.current?.({ time: data.time, model, data });
|
|
480
483
|
}, -1);
|
|
481
484
|
|
|
482
485
|
function ensureInterpolationBuffers(model: MujocoModel) {
|
|
@@ -515,7 +518,7 @@ export function MujocoSimProvider({
|
|
|
515
518
|
}
|
|
516
519
|
}
|
|
517
520
|
|
|
518
|
-
configRef.current.onReset?.(model, data);
|
|
521
|
+
configRef.current.onReset?.({ model, data });
|
|
519
522
|
mujoco.mj_forward(model, data);
|
|
520
523
|
|
|
521
524
|
// Notify composable plugins (e.g. IkController)
|
|
@@ -43,7 +43,7 @@ export type ControllerComponent<TConfig> = React.FC<{
|
|
|
43
43
|
* const MyController = createController<{ speed: number }>(
|
|
44
44
|
* { name: 'my-controller', defaultConfig: { speed: 1.0 } },
|
|
45
45
|
* function MyControllerImpl({ config }) {
|
|
46
|
-
* useBeforePhysicsStep((
|
|
46
|
+
* useBeforePhysicsStep(({ data }) => {
|
|
47
47
|
* data.ctrl[0] = config.speed;
|
|
48
48
|
* });
|
|
49
49
|
* return null;
|
|
@@ -100,7 +100,7 @@ export function createController<TConfig>(
|
|
|
100
100
|
* { name: 'useMyController', defaultConfig: { gain: 1.0 } },
|
|
101
101
|
* function useMyControllerImpl(config) {
|
|
102
102
|
* // config is MyConfig | null — hooks must be called unconditionally
|
|
103
|
-
* useBeforePhysicsStep((
|
|
103
|
+
* useBeforePhysicsStep(({ data }) => {
|
|
104
104
|
* if (!config) return;
|
|
105
105
|
* data.ctrl[0] = config.gain * Math.sin(data.time);
|
|
106
106
|
* });
|
|
@@ -29,7 +29,7 @@ export function useBodyState(name: Bodies): BodyStateResult {
|
|
|
29
29
|
bodyIdRef.current = findBodyByName(model, name);
|
|
30
30
|
}, [name, status, mjModelRef]);
|
|
31
31
|
|
|
32
|
-
useAfterPhysicsStep((
|
|
32
|
+
useAfterPhysicsStep(({ data }) => {
|
|
33
33
|
const bid = bodyIdRef.current;
|
|
34
34
|
if (bid < 0) return;
|
|
35
35
|
|
package/src/hooks/useContacts.ts
CHANGED
|
@@ -60,7 +60,7 @@ export function useContacts(
|
|
|
60
60
|
bodyResolvedRef.current = true;
|
|
61
61
|
}, [bodyName, status, mjModelRef]);
|
|
62
62
|
|
|
63
|
-
useAfterPhysicsStep((model, data) => {
|
|
63
|
+
useAfterPhysicsStep(({ model, data }) => {
|
|
64
64
|
// Resolve body id lazily once model exists, to avoid missing the first ready frame.
|
|
65
65
|
if (bodyName && !bodyResolvedRef.current) {
|
|
66
66
|
bodyIdRef.current = findBodyByName(model, bodyName);
|
|
@@ -30,7 +30,7 @@ export function useCtrlNoise(config: CtrlNoiseConfig = {}) {
|
|
|
30
30
|
configRef.current = config;
|
|
31
31
|
const noiseRef = useRef<Float64Array | null>(null);
|
|
32
32
|
|
|
33
|
-
useBeforePhysicsStep((
|
|
33
|
+
useBeforePhysicsStep(({ data }) => {
|
|
34
34
|
const cfg = configRef.current;
|
|
35
35
|
if (cfg.enabled === false) return;
|
|
36
36
|
|
package/src/hooks/useGamepad.ts
CHANGED
|
@@ -50,7 +50,7 @@ export function useGamepad(config: GamepadConfig) {
|
|
|
50
50
|
}
|
|
51
51
|
}, [config.axes, config.buttons, status, mjModelRef]);
|
|
52
52
|
|
|
53
|
-
useBeforePhysicsStep((
|
|
53
|
+
useBeforePhysicsStep(({ data }) => {
|
|
54
54
|
const cfg = configRef.current;
|
|
55
55
|
if (cfg.enabled === false) return;
|
|
56
56
|
|
|
@@ -13,7 +13,7 @@ import { useBeforePhysicsStep } from '../core/MujocoSimProvider';
|
|
|
13
13
|
* hook (and DragInteraction) compose correctly — both add to a clean slate.
|
|
14
14
|
*/
|
|
15
15
|
export function useGravityCompensation(enabled = true): void {
|
|
16
|
-
useBeforePhysicsStep((model, data) => {
|
|
16
|
+
useBeforePhysicsStep(({ model, data }) => {
|
|
17
17
|
if (!enabled) return;
|
|
18
18
|
for (let i = 0; i < model.nv; i++) {
|
|
19
19
|
data.qfrc_applied[i] += data.qfrc_bias[i];
|
|
@@ -10,7 +10,7 @@ import { createControllerHook } from '../core/createController';
|
|
|
10
10
|
import { useMujocoContext, useBeforePhysicsStep } from '../core/MujocoSimProvider';
|
|
11
11
|
import { GenericIK } from '../core/GenericIK';
|
|
12
12
|
import { createContiguousControlGroup, findSiteByName, resolveControlGroup } from '../core/SceneLoader';
|
|
13
|
-
import type { ControlGroupInfo, IkConfig, IkContextValue, IKSolveFn, MujocoData } from '../types';
|
|
13
|
+
import type { ControlGroupInfo, IkConfig, IkContextValue, IKSolveFn, IkSolveInput, MujocoData } from '../types';
|
|
14
14
|
|
|
15
15
|
// Preallocated temp for syncGizmoToSite
|
|
16
16
|
const _syncMat4 = new THREE.Matrix4();
|
|
@@ -84,16 +84,16 @@ export const useIkController = createControllerHook<IkConfig, IkContextValue>(
|
|
|
84
84
|
|
|
85
85
|
// IK solve function
|
|
86
86
|
const ikSolveFn = useCallback(
|
|
87
|
-
(
|
|
87
|
+
({ position, quaternion, currentQ, context }: IkSolveInput): number[] | null => {
|
|
88
88
|
if (!config) return null;
|
|
89
|
-
if (config.ikSolveFn) return config.ikSolveFn(
|
|
89
|
+
if (config.ikSolveFn) return config.ikSolveFn({ position, quaternion, currentQ, context });
|
|
90
90
|
const model = mjModelRef.current;
|
|
91
91
|
const data = mjDataRef.current;
|
|
92
92
|
const controlGroup = controlGroupRef.current;
|
|
93
93
|
if (!model || !data || !controlGroup || siteIdRef.current === -1) return null;
|
|
94
94
|
return genericIkRef.current.solve(
|
|
95
95
|
model, data, siteIdRef.current, controlGroup.qposAdr,
|
|
96
|
-
|
|
96
|
+
position, quaternion, currentQ,
|
|
97
97
|
{ damping: config.damping, maxIterations: config.maxIterations },
|
|
98
98
|
);
|
|
99
99
|
},
|
|
@@ -128,7 +128,7 @@ export const useIkController = createControllerHook<IkConfig, IkContextValue>(
|
|
|
128
128
|
});
|
|
129
129
|
|
|
130
130
|
// IK solve in physics loop
|
|
131
|
-
useBeforePhysicsStep((model, data) => {
|
|
131
|
+
useBeforePhysicsStep(({ model, data }) => {
|
|
132
132
|
if (!config || !ikEnabledRef.current) {
|
|
133
133
|
ikCalculatingRef.current = false;
|
|
134
134
|
return;
|
|
@@ -142,13 +142,22 @@ export const useIkController = createControllerHook<IkConfig, IkContextValue>(
|
|
|
142
142
|
|
|
143
143
|
const currentQ = Array.from(controlGroup.readQpos(data));
|
|
144
144
|
const solution = config.ikSolveFn
|
|
145
|
-
? config.ikSolveFn(
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
145
|
+
? config.ikSolveFn({
|
|
146
|
+
position: target.position,
|
|
147
|
+
quaternion: target.quaternion,
|
|
148
|
+
currentQ,
|
|
149
|
+
context: {
|
|
150
|
+
model,
|
|
151
|
+
data,
|
|
152
|
+
siteId: siteIdRef.current,
|
|
153
|
+
controlGroup,
|
|
154
|
+
},
|
|
150
155
|
})
|
|
151
|
-
: ikSolveFnRef.current(
|
|
156
|
+
: ikSolveFnRef.current({
|
|
157
|
+
position: target.position,
|
|
158
|
+
quaternion: target.quaternion,
|
|
159
|
+
currentQ,
|
|
160
|
+
});
|
|
152
161
|
if (solution) {
|
|
153
162
|
controlGroup.writeCtrl(data, solution);
|
|
154
163
|
}
|
|
@@ -192,8 +201,8 @@ export const useIkController = createControllerHook<IkConfig, IkContextValue>(
|
|
|
192
201
|
}, [mjDataRef]);
|
|
193
202
|
|
|
194
203
|
const solveIK = useCallback(
|
|
195
|
-
(
|
|
196
|
-
return ikSolveFnRef.current(
|
|
204
|
+
(input: IkSolveInput): number[] | null => {
|
|
205
|
+
return ikSolveFnRef.current(input);
|
|
197
206
|
},
|
|
198
207
|
[],
|
|
199
208
|
);
|
|
@@ -59,7 +59,7 @@ export function useJointState(name: Joints): JointStateResult {
|
|
|
59
59
|
jointIdRef.current = -1;
|
|
60
60
|
}, [name, status, mjModelRef]);
|
|
61
61
|
|
|
62
|
-
useAfterPhysicsStep((
|
|
62
|
+
useAfterPhysicsStep(({ data }) => {
|
|
63
63
|
if (jointIdRef.current < 0) return;
|
|
64
64
|
const qa = qposAdrRef.current;
|
|
65
65
|
const da = dofAdrRef.current;
|
|
@@ -70,7 +70,7 @@ export function useKeyboardTeleop(config: KeyboardTeleopConfig) {
|
|
|
70
70
|
}, []);
|
|
71
71
|
|
|
72
72
|
// Apply bindings each physics frame
|
|
73
|
-
useBeforePhysicsStep((
|
|
73
|
+
useBeforePhysicsStep(({ data }) => {
|
|
74
74
|
if (!enabledRef.current) return;
|
|
75
75
|
const bindings = bindingsRef.current;
|
|
76
76
|
const cache = actuatorCacheRef.current;
|
package/src/hooks/usePolicy.ts
CHANGED
|
@@ -28,7 +28,7 @@ export function usePolicy(config: PolicyConfig) {
|
|
|
28
28
|
configRef.current = config;
|
|
29
29
|
isRunningRef.current = config.enabled ?? isRunningRef.current;
|
|
30
30
|
|
|
31
|
-
useBeforePhysicsStep((model, data) => {
|
|
31
|
+
useBeforePhysicsStep(({ model, data }) => {
|
|
32
32
|
if (!isRunningRef.current) return;
|
|
33
33
|
|
|
34
34
|
const cfg = configRef.current;
|
package/src/hooks/useSensor.ts
CHANGED
|
@@ -39,7 +39,7 @@ export function useSensor(name: Sensors): SensorHandle {
|
|
|
39
39
|
}, [name, status, mjModelRef]);
|
|
40
40
|
|
|
41
41
|
// Update every frame after physics step
|
|
42
|
-
useAfterPhysicsStep((
|
|
42
|
+
useAfterPhysicsStep(({ data }) => {
|
|
43
43
|
if (sensorIdRef.current < 0) return;
|
|
44
44
|
const adr = sensorAdrRef.current;
|
|
45
45
|
const dim = sensorDimRef.current;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { useCallback, useRef } from 'react';
|
|
9
9
|
import { useFrame } from '@react-three/fiber';
|
|
10
10
|
import { useMujocoContext, useBeforePhysicsStep } from '../core/MujocoSimProvider';
|
|
11
|
-
import type { PlaybackState, TrajectoryFrame, TrajectoryInput } from '../types';
|
|
11
|
+
import type { PlaybackState, TrajectoryStateChangeInput, TrajectoryFrame, TrajectoryInput } from '../types';
|
|
12
12
|
|
|
13
13
|
export interface TrajectoryPlayerOptions {
|
|
14
14
|
fps?: number;
|
|
@@ -16,7 +16,7 @@ export interface TrajectoryPlayerOptions {
|
|
|
16
16
|
loop?: boolean;
|
|
17
17
|
mode?: 'kinematic' | 'physics';
|
|
18
18
|
onComplete?: () => void;
|
|
19
|
-
onStateChange?: (
|
|
19
|
+
onStateChange?: (input: TrajectoryStateChangeInput) => void;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
/** Check if input is TrajectoryFrame[] (vs number[][]) */
|
|
@@ -74,7 +74,7 @@ export function useTrajectoryPlayer(
|
|
|
74
74
|
const setState = useCallback((next: PlaybackState) => {
|
|
75
75
|
if (stateRef.current === next) return;
|
|
76
76
|
stateRef.current = next;
|
|
77
|
-
optionsRef.current.onStateChange?.(next);
|
|
77
|
+
optionsRef.current.onStateChange?.({ state: next });
|
|
78
78
|
}, []);
|
|
79
79
|
|
|
80
80
|
const play = useCallback(() => {
|
|
@@ -181,7 +181,7 @@ export function useTrajectoryPlayer(
|
|
|
181
181
|
});
|
|
182
182
|
|
|
183
183
|
// --- Physics mode: set ctrl values each physics step ---
|
|
184
|
-
useBeforePhysicsStep((model, data) => {
|
|
184
|
+
useBeforePhysicsStep(({ model, data }) => {
|
|
185
185
|
if (stateRef.current !== 'playing') return;
|
|
186
186
|
if ((optionsRef.current.mode ?? 'kinematic') !== 'physics') return;
|
|
187
187
|
|
|
@@ -22,7 +22,7 @@ export function useTrajectoryRecorder(options: RecorderOptions = {}) {
|
|
|
22
22
|
const framesRef = useRef<TrajectoryFrame[]>([]);
|
|
23
23
|
const fields = options.fields ?? ['qpos'];
|
|
24
24
|
|
|
25
|
-
useAfterPhysicsStep((
|
|
25
|
+
useAfterPhysicsStep(({ data }) => {
|
|
26
26
|
if (!recordingRef.current) return;
|
|
27
27
|
|
|
28
28
|
const frame: TrajectoryFrame = {
|
package/src/index.ts
CHANGED
|
@@ -110,8 +110,14 @@ export type {
|
|
|
110
110
|
IkConfig,
|
|
111
111
|
IkContextValue,
|
|
112
112
|
IKSolveFn,
|
|
113
|
+
IkSolveInput,
|
|
113
114
|
// Callbacks
|
|
114
115
|
PhysicsStepCallback,
|
|
116
|
+
PhysicsStepInput,
|
|
117
|
+
ResetCallbackInput,
|
|
118
|
+
ReadyCallbackInput,
|
|
119
|
+
StepCallbackInput,
|
|
120
|
+
SelectionCallbackInput,
|
|
115
121
|
// State management
|
|
116
122
|
StateSnapshot,
|
|
117
123
|
// Model introspection
|
|
@@ -155,6 +161,7 @@ export type {
|
|
|
155
161
|
// Component props
|
|
156
162
|
BodyProps,
|
|
157
163
|
IkGizmoProps,
|
|
164
|
+
IkGizmoDragInput,
|
|
158
165
|
DragInteractionProps,
|
|
159
166
|
DebugProps,
|
|
160
167
|
SceneLightsProps,
|
|
@@ -175,7 +182,10 @@ export type {
|
|
|
175
182
|
ScenarioMaterialConfig,
|
|
176
183
|
SplatEnvironmentProps,
|
|
177
184
|
VisualScenarioEffectsProps,
|
|
185
|
+
VisualScenarioMaterialFilterInput,
|
|
178
186
|
TrajectoryPlayerProps,
|
|
187
|
+
TrajectoryFrameCallbackInput,
|
|
188
|
+
TrajectoryStateChangeInput,
|
|
179
189
|
ContactListenerProps,
|
|
180
190
|
// API
|
|
181
191
|
MujocoSimAPI,
|