mujoco-react 9.1.0 → 9.3.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.
@@ -0,0 +1,94 @@
1
+ /**
2
+ * @license
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ *
5
+ * React state wrapper around MuJoCo/R3F offscreen camera-frame capture.
6
+ */
7
+
8
+ import { useCallback, useState } from 'react';
9
+ import { useMujoco } from '../core/MujocoSimProvider';
10
+ import type {
11
+ CameraFrameCaptureAPI,
12
+ CameraFrameCaptureOptions,
13
+ FrameCaptureStatus,
14
+ } from '../types';
15
+
16
+ export function useCameraFrameCapture(
17
+ defaultOptions: CameraFrameCaptureOptions = {}
18
+ ): CameraFrameCaptureAPI {
19
+ const mujoco = useMujoco();
20
+ const [status, setStatus] = useState<FrameCaptureStatus>('idle');
21
+ const [error, setError] = useState<Error | null>(null);
22
+
23
+ const reset = useCallback(() => {
24
+ setStatus('idle');
25
+ setError(null);
26
+ }, []);
27
+
28
+ const capture = useCallback(
29
+ async (options: CameraFrameCaptureOptions = {}) => {
30
+ if (!mujoco.api) {
31
+ throw new Error('MuJoCo scene is not ready for camera frame capture.');
32
+ }
33
+
34
+ setStatus('capturing');
35
+ setError(null);
36
+
37
+ try {
38
+ const result = await mujoco.api.captureCameraFrame({
39
+ ...defaultOptions,
40
+ ...options,
41
+ });
42
+ setStatus('captured');
43
+ return result;
44
+ } catch (nextError) {
45
+ const error =
46
+ nextError instanceof Error
47
+ ? nextError
48
+ : new Error('Unable to capture the requested camera frame.');
49
+ setError(error);
50
+ setStatus('error');
51
+ throw error;
52
+ }
53
+ },
54
+ [defaultOptions, mujoco.api]
55
+ );
56
+
57
+ const captureBlob = useCallback(
58
+ async (options: CameraFrameCaptureOptions = {}) => {
59
+ if (!mujoco.api) {
60
+ throw new Error('MuJoCo scene is not ready for camera frame capture.');
61
+ }
62
+
63
+ setStatus('capturing');
64
+ setError(null);
65
+
66
+ try {
67
+ const result = await mujoco.api.captureCameraFrameBlob({
68
+ ...defaultOptions,
69
+ ...options,
70
+ });
71
+ setStatus('captured');
72
+ return result;
73
+ } catch (nextError) {
74
+ const error =
75
+ nextError instanceof Error
76
+ ? nextError
77
+ : new Error('Unable to capture the requested camera frame.');
78
+ setError(error);
79
+ setStatus('error');
80
+ throw error;
81
+ }
82
+ },
83
+ [defaultOptions, mujoco.api]
84
+ );
85
+
86
+ return {
87
+ status,
88
+ error,
89
+ isCapturing: status === 'capturing',
90
+ capture,
91
+ captureBlob,
92
+ reset,
93
+ };
94
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * @license
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ *
5
+ * React state wrapper around fixed-camera simulation sequence recording.
6
+ */
7
+
8
+ import { useCallback, useState } from 'react';
9
+ import { useMujoco } from '../core/MujocoSimProvider';
10
+ import type {
11
+ CameraFrameSequenceOptions,
12
+ CameraFrameSequenceRecorderAPI,
13
+ FrameCaptureStatus,
14
+ } from '../types';
15
+
16
+ export function useCameraSequenceRecorder(): CameraFrameSequenceRecorderAPI {
17
+ const mujoco = useMujoco();
18
+ const [status, setStatus] = useState<FrameCaptureStatus>('idle');
19
+ const [error, setError] = useState<Error | null>(null);
20
+
21
+ const reset = useCallback(() => {
22
+ setStatus('idle');
23
+ setError(null);
24
+ }, []);
25
+
26
+ const record = useCallback(
27
+ async (options: CameraFrameSequenceOptions) => {
28
+ if (!mujoco.api) {
29
+ throw new Error('MuJoCo scene is not ready for camera sequence recording.');
30
+ }
31
+
32
+ setStatus('capturing');
33
+ setError(null);
34
+
35
+ try {
36
+ const result = await mujoco.api.recordCameraSequence(options);
37
+ setStatus('captured');
38
+ return result;
39
+ } catch (nextError) {
40
+ const error =
41
+ nextError instanceof Error
42
+ ? nextError
43
+ : new Error('Unable to record the requested camera sequence.');
44
+ setError(error);
45
+ setStatus('error');
46
+ throw error;
47
+ }
48
+ },
49
+ [mujoco.api]
50
+ );
51
+
52
+ return {
53
+ status,
54
+ error,
55
+ isRecording: status === 'capturing',
56
+ record,
57
+ reset,
58
+ };
59
+ }
@@ -0,0 +1,107 @@
1
+ /**
2
+ * @license
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ *
5
+ * React state wrapper for named MuJoCo camera/site/body sequence recording.
6
+ */
7
+
8
+ import { useCallback, useState } from 'react';
9
+ import { useMujoco } from '../core/MujocoSimProvider';
10
+ import {
11
+ createMountedCameraFrameSequencePlanFromApi,
12
+ recordMountedCameraFrameSequence,
13
+ type MountedCameraFrameSequencePlan,
14
+ type MountedCameraFrameSequencePlanOptions,
15
+ type MountedCameraFrameSequenceRecordOptions,
16
+ type MountedCameraFrameSequenceRecordResult,
17
+ } from '../rendering/cameraFrameSource';
18
+ import type {
19
+ CameraFrameSequenceRecorderAPI,
20
+ FrameCaptureStatus,
21
+ } from '../types';
22
+
23
+ export type MountedCameraSequencePlanOptions =
24
+ MountedCameraFrameSequencePlanOptions;
25
+ export type MountedCameraSequenceRecordOptions =
26
+ MountedCameraFrameSequenceRecordOptions;
27
+ export type MountedCameraSequenceRecordResult =
28
+ MountedCameraFrameSequenceRecordResult;
29
+
30
+ export interface MountedCameraSequenceRecorderAPI
31
+ extends Omit<CameraFrameSequenceRecorderAPI, 'record'> {
32
+ createPlan: (
33
+ cameraKeys: readonly string[],
34
+ options?: MountedCameraSequencePlanOptions
35
+ ) => MountedCameraFrameSequencePlan;
36
+ record: (
37
+ options: MountedCameraSequenceRecordOptions
38
+ ) => Promise<MountedCameraSequenceRecordResult>;
39
+ }
40
+
41
+ export function useMountedCameraSequenceRecorder(
42
+ defaultOptions: MountedCameraSequencePlanOptions = {}
43
+ ): MountedCameraSequenceRecorderAPI {
44
+ const mujoco = useMujoco();
45
+ const [status, setStatus] = useState<FrameCaptureStatus>('idle');
46
+ const [error, setError] = useState<Error | null>(null);
47
+
48
+ const reset = useCallback(() => {
49
+ setStatus('idle');
50
+ setError(null);
51
+ }, []);
52
+
53
+ const createPlan = useCallback(
54
+ (
55
+ cameraKeys: readonly string[],
56
+ options: MountedCameraSequencePlanOptions = {}
57
+ ) => {
58
+ if (!mujoco.api) {
59
+ throw new Error('MuJoCo scene is not ready for mounted camera sequence planning.');
60
+ }
61
+
62
+ return createMountedCameraFrameSequencePlanFromApi(mujoco.api, cameraKeys, {
63
+ ...defaultOptions,
64
+ ...options,
65
+ });
66
+ },
67
+ [defaultOptions, mujoco.api]
68
+ );
69
+
70
+ const record = useCallback(
71
+ async (options: MountedCameraSequenceRecordOptions) => {
72
+ if (!mujoco.api) {
73
+ throw new Error('MuJoCo scene is not ready for mounted camera sequence recording.');
74
+ }
75
+
76
+ setStatus('capturing');
77
+ setError(null);
78
+
79
+ try {
80
+ const result = await recordMountedCameraFrameSequence(mujoco.api, {
81
+ ...defaultOptions,
82
+ ...options,
83
+ });
84
+ setStatus('captured');
85
+ return result;
86
+ } catch (nextError) {
87
+ const error =
88
+ nextError instanceof Error
89
+ ? nextError
90
+ : new Error('Unable to record the requested mounted camera sequence.');
91
+ setError(error);
92
+ setStatus('error');
93
+ throw error;
94
+ }
95
+ },
96
+ [defaultOptions, mujoco.api]
97
+ );
98
+
99
+ return {
100
+ status,
101
+ error,
102
+ isRecording: status === 'capturing',
103
+ createPlan,
104
+ record,
105
+ reset,
106
+ };
107
+ }
package/src/index.ts CHANGED
@@ -48,9 +48,11 @@ export {
48
48
  createPairedSplatEnvironment,
49
49
  createSparkSplatViewerUrl,
50
50
  createSplatEnvironmentUserData,
51
+ getSplatEnvironmentReadiness,
51
52
  getScenarioBackground,
52
53
  getScenarioCameraPosition,
53
54
  useSplatEnvironment,
55
+ useSplatSceneConfig,
54
56
  useVisualScenarioEffects,
55
57
  withSplatEnvironment,
56
58
  } from './components/VisualScenario';
@@ -82,6 +84,49 @@ export {
82
84
  captureFrameBlob,
83
85
  useFrameCapture,
84
86
  } from './hooks/useFrameCapture';
87
+ export { useCameraFrameCapture } from './hooks/useCameraFrameCapture';
88
+ export { useCameraSequenceRecorder } from './hooks/useCameraSequenceRecorder';
89
+ export { useMountedCameraSequenceRecorder } from './hooks/useMountedCameraSequenceRecorder';
90
+ export type {
91
+ MountedCameraSequencePlanOptions,
92
+ MountedCameraSequenceRecorderAPI,
93
+ MountedCameraSequenceRecordOptions,
94
+ MountedCameraSequenceRecordResult,
95
+ } from './hooks/useMountedCameraSequenceRecorder';
96
+ export {
97
+ captureCameraFrame,
98
+ captureCameraFrameBlob,
99
+ createCameraFrameCaptureSession,
100
+ renderCameraFrameToCanvas,
101
+ } from './rendering/cameraFrameCapture';
102
+ export {
103
+ createMountedCameraFrameSequenceReadiness,
104
+ MountedCameraFrameSequenceReadinessStatus,
105
+ createMountedCameraFrameSequencePlanFromApi,
106
+ createMountedCameraFrameSequencePlan,
107
+ getCameraFrameCaptureSourceTarget,
108
+ getMountedCameraFrameCaptureSource,
109
+ isMountedCameraFrameCaptureSource,
110
+ recordMountedCameraFrameSequence,
111
+ resolveMountedCameraFrameSource,
112
+ } from './rendering/cameraFrameSource';
113
+ export type {
114
+ CameraFrameMountSelector,
115
+ CreateMountedCameraFrameSequencePlanOptions,
116
+ MountedCameraFrameCaptureSource,
117
+ MountedCameraFrameSequencePlanOptions,
118
+ MountedCameraFrameSequenceRecorderTarget,
119
+ MountedCameraFrameSequenceCameraOptions,
120
+ MountedCameraFrameSequenceDefaults,
121
+ MountedCameraFrameSequencePlan,
122
+ MountedCameraFrameSequenceReadiness,
123
+ MountedCameraFrameSequenceRecordOptions,
124
+ MountedCameraFrameSequenceRecordResult,
125
+ MountedCameraFrameSequenceSourceReadiness,
126
+ NamedCameraFrameResource,
127
+ ResolveMountedCameraFrameSourceOptions,
128
+ ResolvedMountedCameraFrameSource,
129
+ } from './rendering/cameraFrameSource';
85
130
  export { useCtrlNoise } from './hooks/useCtrlNoise';
86
131
  export { useBodyMeshes } from './hooks/useBodyMeshes';
87
132
  export { useSelectionHighlight } from './hooks/useSelectionHighlight';
@@ -123,6 +168,7 @@ export type {
123
168
  SiteInfo,
124
169
  ActuatorInfo,
125
170
  SensorInfo,
171
+ CameraInfo,
126
172
  // Contacts
127
173
  ContactInfo,
128
174
  // Raycast
@@ -165,8 +211,11 @@ export type {
165
211
  SplatScenarioConfig,
166
212
  SplatCollisionProxyConfig,
167
213
  PairedSplatEnvironmentConfig,
214
+ SplatEnvironmentReadiness,
168
215
  SplatEnvironmentMetadataInput,
169
216
  SplatEnvironmentMetadata,
217
+ SplatSceneConfigInput,
218
+ SplatSceneConfigState,
170
219
  SplatSceneInput,
171
220
  VisualScenarioConfig,
172
221
  ScenarioLightingProps,
@@ -181,6 +230,21 @@ export type {
181
230
  // API
182
231
  MujocoSimAPI,
183
232
  MujocoFrameCaptureOptions,
233
+ CameraFrameCaptureAPI,
234
+ CameraFrameCaptureBlobResult,
235
+ CameraFrameCaptureOptions,
236
+ CameraFrameCaptureQuaternion,
237
+ CameraFrameCaptureResult,
238
+ CameraFrameCaptureSource,
239
+ CameraFrameCaptureVector3,
240
+ CameraFrameSequenceCamera,
241
+ CameraFrameSequenceCameraSummary,
242
+ CameraFrameSequenceFrame,
243
+ CameraFrameSequenceOptions,
244
+ CameraFrameSequenceRecorderAPI,
245
+ CameraFrameSequenceResult,
246
+ CameraFrameSequenceSampleInput,
247
+ CameraFrameSequenceStepInput,
184
248
  MujocoCanvasProps,
185
249
  MujocoContextValue,
186
250
  // Hook return types
@@ -209,6 +273,7 @@ export type {
209
273
  Sites,
210
274
  Geoms,
211
275
  Keyframes,
276
+ Cameras,
212
277
  } from './types';
213
278
 
214
279
  export {
@@ -221,6 +286,8 @@ export {
221
286
  RobotSites,
222
287
  RobotGeoms,
223
288
  RobotKeyframes,
289
+ RobotCameras,
290
+ SplatEnvironmentReadinessStatus,
224
291
  } from './types';
225
292
 
226
293
  // Re-export MuJoCo types for convenience