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.
- package/README.md +121 -17
- package/dist/{chunk-33CV6HSV.js → chunk-T3GVZJ4F.js} +222 -8
- package/dist/chunk-T3GVZJ4F.js.map +1 -0
- package/dist/index.d.ts +198 -6
- package/dist/index.js +1109 -216
- package/dist/index.js.map +1 -1
- package/dist/spark.d.ts +24 -2
- package/dist/spark.js +89 -3
- package/dist/spark.js.map +1 -1
- package/dist/{types-C5gTvR7b.d.ts → types-oxbxOkAx.d.ts} +190 -2
- package/dist/vite.d.ts +1 -1
- package/dist/vite.js +6 -3
- package/dist/vite.js.map +1 -1
- package/package.json +1 -1
- package/src/components/VisualScenario.tsx +178 -1
- package/src/core/MujocoSimProvider.tsx +473 -11
- package/src/core/SceneLoader.ts +13 -0
- package/src/core/createController.tsx +6 -2
- package/src/hooks/useCameraFrameCapture.ts +94 -0
- package/src/hooks/useCameraSequenceRecorder.ts +59 -0
- package/src/hooks/useMountedCameraSequenceRecorder.ts +107 -0
- package/src/index.ts +67 -0
- package/src/rendering/cameraFrameCapture.ts +353 -0
- package/src/rendering/cameraFrameSource.ts +375 -0
- package/src/spark.tsx +144 -0
- package/src/types.ts +212 -2
- package/src/vite.ts +5 -2
- package/dist/chunk-33CV6HSV.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 { n as SplatEnvironmentProps } from './types-
|
|
3
|
+
import { n as SplatEnvironmentProps, q as PairedSplatEnvironmentConfig, S as SceneConfig, t as SplatEnvironmentReadiness, o as VisualScenarioConfig } from './types-oxbxOkAx.js';
|
|
4
4
|
import 'react';
|
|
5
5
|
import '@react-three/fiber';
|
|
6
6
|
import 'three';
|
|
@@ -17,6 +17,14 @@ interface SparkSplatLifecycle {
|
|
|
17
17
|
props: Pick<SparkSplatEnvironmentProps, 'onStatusChange' | 'onError'>;
|
|
18
18
|
reset: () => void;
|
|
19
19
|
}
|
|
20
|
+
interface SparkSplatEnvironmentState {
|
|
21
|
+
environment: PairedSplatEnvironmentConfig | undefined;
|
|
22
|
+
sceneConfig: SceneConfig;
|
|
23
|
+
readiness: SplatEnvironmentReadiness;
|
|
24
|
+
lifecycle: SparkSplatLifecycle;
|
|
25
|
+
props: Pick<SparkSplatEnvironmentProps, 'environment' | 'scenario' | 'src' | 'format' | 'onStatusChange' | 'onError'>;
|
|
26
|
+
enabled: boolean;
|
|
27
|
+
}
|
|
20
28
|
interface SparkSplatEnvironmentProps extends SplatEnvironmentProps {
|
|
21
29
|
/** Enable Spark LoD handling for large splat assets. Default: true. */
|
|
22
30
|
lod?: boolean | 'quality';
|
|
@@ -30,6 +38,20 @@ interface SparkSplatEnvironmentProps extends SplatEnvironmentProps {
|
|
|
30
38
|
onLoad?: (mesh: SparkSplatMeshInstance) => void;
|
|
31
39
|
onError?: (error: Error) => void;
|
|
32
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Resolve a visual scenario's paired splat environment, compose its MJCF
|
|
43
|
+
* collision proxy into the MuJoCo scene config, and expose Spark lifecycle
|
|
44
|
+
* props for `<SparkSplatEnvironment />`.
|
|
45
|
+
*/
|
|
46
|
+
declare function useSparkSplatEnvironment({ sceneConfig, scenario, environment, enabled, renderer, onError, onStatusChange, }: {
|
|
47
|
+
sceneConfig: SceneConfig;
|
|
48
|
+
scenario?: VisualScenarioConfig;
|
|
49
|
+
environment?: PairedSplatEnvironmentConfig;
|
|
50
|
+
enabled?: boolean;
|
|
51
|
+
renderer?: 'spark';
|
|
52
|
+
onError?: (error: Error) => void;
|
|
53
|
+
onStatusChange?: (status: SparkSplatStatus) => void;
|
|
54
|
+
}): SparkSplatEnvironmentState;
|
|
33
55
|
/**
|
|
34
56
|
* Tracks Spark 3DGS loading state for UI that wraps `SparkSplatEnvironment`.
|
|
35
57
|
*
|
|
@@ -50,4 +72,4 @@ declare function useSparkSplatLifecycle({ enabled, initialStatus, onError, onSta
|
|
|
50
72
|
*/
|
|
51
73
|
declare function SparkSplatEnvironment({ environment, scenario, renderer, src, format, collisionProxy, collisionProxyMetadata, showPlaceholder, children, lod, hideGroundMeshes, onStatusChange, onLoad, onError, ...groupProps }: SparkSplatEnvironmentProps): react_jsx_runtime.JSX.Element;
|
|
52
74
|
|
|
53
|
-
export { SparkSplatEnvironment, type SparkSplatEnvironmentProps, type SparkSplatLifecycle, type SparkSplatStatus, useSparkSplatLifecycle };
|
|
75
|
+
export { SparkSplatEnvironment, type SparkSplatEnvironmentProps, type SparkSplatEnvironmentState, type SparkSplatLifecycle, type SparkSplatStatus, useSparkSplatEnvironment, useSparkSplatLifecycle };
|
package/dist/spark.js
CHANGED
|
@@ -1,9 +1,56 @@
|
|
|
1
|
-
import { useSplatEnvironment, SplatEnvironment } from './chunk-
|
|
1
|
+
import { useSplatSceneConfig, useSplatEnvironment, SplatEnvironment } from './chunk-T3GVZJ4F.js';
|
|
2
2
|
import { useThree } from '@react-three/fiber';
|
|
3
|
-
import { useState, useEffect, useCallback,
|
|
3
|
+
import { useMemo, useState, useEffect, useCallback, useRef } from 'react';
|
|
4
4
|
import * as THREE from 'three';
|
|
5
5
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
6
|
|
|
7
|
+
var sparkDisposeRejectionHandlerRegistered = false;
|
|
8
|
+
function useSparkSplatEnvironment({
|
|
9
|
+
sceneConfig,
|
|
10
|
+
scenario,
|
|
11
|
+
environment,
|
|
12
|
+
enabled = true,
|
|
13
|
+
renderer = "spark",
|
|
14
|
+
onError,
|
|
15
|
+
onStatusChange
|
|
16
|
+
}) {
|
|
17
|
+
const splatScene = useSplatSceneConfig({
|
|
18
|
+
sceneConfig,
|
|
19
|
+
scenario,
|
|
20
|
+
environment,
|
|
21
|
+
enabled,
|
|
22
|
+
renderer
|
|
23
|
+
});
|
|
24
|
+
const metadata = useSplatEnvironment({
|
|
25
|
+
scenario,
|
|
26
|
+
environment: splatScene.environment,
|
|
27
|
+
renderer
|
|
28
|
+
});
|
|
29
|
+
const renderEnabled = enabled && Boolean(metadata.src);
|
|
30
|
+
const readiness = enabled ? metadata.readiness : splatScene.readiness;
|
|
31
|
+
const lifecycle = useSparkSplatLifecycle({
|
|
32
|
+
enabled: renderEnabled,
|
|
33
|
+
onError,
|
|
34
|
+
onStatusChange
|
|
35
|
+
});
|
|
36
|
+
return useMemo(
|
|
37
|
+
() => ({
|
|
38
|
+
environment: splatScene.environment,
|
|
39
|
+
sceneConfig: splatScene.sceneConfig,
|
|
40
|
+
readiness,
|
|
41
|
+
lifecycle,
|
|
42
|
+
props: {
|
|
43
|
+
environment: splatScene.environment,
|
|
44
|
+
scenario: enabled ? scenario : void 0,
|
|
45
|
+
src: enabled ? metadata.src : void 0,
|
|
46
|
+
format: metadata.format,
|
|
47
|
+
...lifecycle.props
|
|
48
|
+
},
|
|
49
|
+
enabled: renderEnabled
|
|
50
|
+
}),
|
|
51
|
+
[enabled, lifecycle, metadata, readiness, renderEnabled, scenario, splatScene]
|
|
52
|
+
);
|
|
53
|
+
}
|
|
7
54
|
function useSparkSplatLifecycle({
|
|
8
55
|
enabled = true,
|
|
9
56
|
initialStatus,
|
|
@@ -101,6 +148,7 @@ function SparkSplatEnvironment({
|
|
|
101
148
|
}, [onError]);
|
|
102
149
|
useEffect(() => {
|
|
103
150
|
let disposed = false;
|
|
151
|
+
ensureSparkDisposeRejectionHandler();
|
|
104
152
|
function setLifecycleStatus(nextStatus) {
|
|
105
153
|
setStatus(nextStatus);
|
|
106
154
|
onStatusChangeRef.current?.(nextStatus);
|
|
@@ -208,6 +256,7 @@ function SparkSplatEnvironment({
|
|
|
208
256
|
}
|
|
209
257
|
function safelyDisposeSparkResource(resource) {
|
|
210
258
|
try {
|
|
259
|
+
silenceSparkWorkerTerminateRejections(resource);
|
|
211
260
|
const result = resource.dispose?.();
|
|
212
261
|
if (isPromiseLike(result)) {
|
|
213
262
|
void Promise.resolve(result).catch(handleSparkDisposeError);
|
|
@@ -219,17 +268,54 @@ function safelyDisposeSparkResource(resource) {
|
|
|
219
268
|
function isPromiseLike(value) {
|
|
220
269
|
return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
|
|
221
270
|
}
|
|
271
|
+
function silenceSparkWorkerTerminateRejections(resource) {
|
|
272
|
+
const workers = getSparkWorkers(resource);
|
|
273
|
+
for (const worker of workers) {
|
|
274
|
+
if (!worker.messages) continue;
|
|
275
|
+
for (const message of Object.values(worker.messages)) {
|
|
276
|
+
const reject = message.reject;
|
|
277
|
+
if (!reject) continue;
|
|
278
|
+
message.reject = (error) => {
|
|
279
|
+
if (!isSparkWorkerTerminateError(error)) {
|
|
280
|
+
reject(error);
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
function getSparkWorkers(resource) {
|
|
287
|
+
const sparkResource = resource;
|
|
288
|
+
return [
|
|
289
|
+
sparkResource.worker,
|
|
290
|
+
sparkResource.sortWorker,
|
|
291
|
+
sparkResource.lodWorker
|
|
292
|
+
].filter((worker) => Boolean(worker));
|
|
293
|
+
}
|
|
222
294
|
function handleSparkDisposeError(error) {
|
|
223
295
|
if (error instanceof Error && error.message.toLowerCase().includes("worker terminate")) {
|
|
224
296
|
return;
|
|
225
297
|
}
|
|
226
298
|
console.warn("[mujoco-react] Spark resource disposal failed.", error);
|
|
227
299
|
}
|
|
300
|
+
function ensureSparkDisposeRejectionHandler() {
|
|
301
|
+
if (sparkDisposeRejectionHandlerRegistered || typeof window === "undefined" || typeof window.addEventListener !== "function") {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
sparkDisposeRejectionHandlerRegistered = true;
|
|
305
|
+
window.addEventListener("unhandledrejection", (event) => {
|
|
306
|
+
if (isSparkWorkerTerminateError(event.reason)) {
|
|
307
|
+
event.preventDefault();
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
function isSparkWorkerTerminateError(reason) {
|
|
312
|
+
return reason instanceof Error && reason.message.toLowerCase().includes("worker terminate");
|
|
313
|
+
}
|
|
228
314
|
/**
|
|
229
315
|
* @license
|
|
230
316
|
* SPDX-License-Identifier: Apache-2.0
|
|
231
317
|
*/
|
|
232
318
|
|
|
233
|
-
export { SparkSplatEnvironment, useSparkSplatLifecycle };
|
|
319
|
+
export { SparkSplatEnvironment, useSparkSplatEnvironment, useSparkSplatLifecycle };
|
|
234
320
|
//# sourceMappingURL=spark.js.map
|
|
235
321
|
//# sourceMappingURL=spark.js.map
|
package/dist/spark.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/spark.tsx"],"names":[],"mappings":"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","file":"spark.js","sourcesContent":["/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { useThree } from '@react-three/fiber';\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport * as THREE from 'three';\nimport {\n SplatEnvironment,\n useSplatEnvironment,\n} from './components/VisualScenario';\nimport type {\n SplatEnvironmentProps,\n} from './types';\n\ntype SparkModule = typeof import('@sparkjsdev/spark');\ntype SparkRendererInstance = InstanceType<SparkModule['SparkRenderer']>;\ntype SparkSplatMeshInstance = InstanceType<SparkModule['SplatMesh']>;\ntype SparkDisposable = {\n dispose?: () => unknown;\n};\n\nexport type SparkSplatStatus = 'idle' | 'loading' | 'ready' | 'error';\n\nexport interface SparkSplatLifecycle {\n status: SparkSplatStatus;\n error: Error | null;\n isLoading: boolean;\n isReady: boolean;\n isError: boolean;\n props: Pick<SparkSplatEnvironmentProps, 'onStatusChange' | 'onError'>;\n reset: () => void;\n}\n\nexport interface SparkSplatEnvironmentProps extends SplatEnvironmentProps {\n /** Enable Spark LoD handling for large splat assets. Default: true. */\n lod?: boolean | 'quality';\n /**\n * Hide meshes whose names include floor, ground, or plane while the splat is\n * active. This mirrors the common hybrid-rendering setup where MJCF keeps\n * collision geometry but the splat owns the visual environment.\n */\n hideGroundMeshes?: boolean;\n onStatusChange?: (status: SparkSplatStatus) => void;\n onLoad?: (mesh: SparkSplatMeshInstance) => void;\n onError?: (error: Error) => void;\n}\n\n/**\n * Tracks Spark 3DGS loading state for UI that wraps `SparkSplatEnvironment`.\n *\n * Use the returned `props` with `<SparkSplatEnvironment {...lifecycle.props} />`\n * to avoid repeating status/error state in app code.\n */\nexport function useSparkSplatLifecycle({\n enabled = true,\n initialStatus,\n onError,\n onStatusChange,\n}: {\n enabled?: boolean;\n initialStatus?: SparkSplatStatus;\n onError?: (error: Error) => void;\n onStatusChange?: (status: SparkSplatStatus) => void;\n} = {}): SparkSplatLifecycle {\n const [status, setStatus] = useState<SparkSplatStatus>(\n initialStatus ?? (enabled ? 'loading' : 'idle')\n );\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n setStatus(enabled ? initialStatus ?? 'loading' : 'idle');\n setError(null);\n }, [enabled, initialStatus]);\n\n const handleStatusChange = useCallback(\n (nextStatus: SparkSplatStatus) => {\n setStatus(nextStatus);\n if (nextStatus !== 'error') {\n setError(null);\n }\n onStatusChange?.(nextStatus);\n },\n [onStatusChange]\n );\n\n const handleError = useCallback(\n (nextError: Error) => {\n setError(nextError);\n setStatus('error');\n onError?.(nextError);\n },\n [onError]\n );\n\n const reset = useCallback(() => {\n setStatus(enabled ? initialStatus ?? 'loading' : 'idle');\n setError(null);\n }, [enabled, initialStatus]);\n\n return useMemo(\n () => ({\n status,\n error,\n isLoading: status === 'loading',\n isReady: status === 'ready',\n isError: status === 'error',\n props: {\n onStatusChange: handleStatusChange,\n onError: handleError,\n },\n reset,\n }),\n [error, handleError, handleStatusChange, reset, status]\n );\n}\n\n/**\n * Optional SparkJS-backed Gaussian splat renderer for React Three Fiber scenes.\n *\n * Import from `mujoco-react/spark` and install `@sparkjsdev/spark` in the app\n * that uses it. The core `mujoco-react` entrypoint does not depend on Spark.\n */\nexport function SparkSplatEnvironment({\n environment,\n scenario,\n renderer = 'spark',\n src,\n format,\n collisionProxy,\n collisionProxyMetadata,\n showPlaceholder,\n children,\n lod = true,\n hideGroundMeshes = false,\n onStatusChange,\n onLoad,\n onError,\n ...groupProps\n}: SparkSplatEnvironmentProps) {\n const groupRef = useRef<THREE.Group>(null);\n const sparkRef = useRef<SparkRendererInstance | null>(null);\n const meshRef = useRef<SparkSplatMeshInstance | null>(null);\n const hiddenMeshesRef = useRef<THREE.Mesh[]>([]);\n const onStatusChangeRef = useRef(onStatusChange);\n const onLoadRef = useRef(onLoad);\n const onErrorRef = useRef(onError);\n const [status, setStatus] = useState<SparkSplatStatus>('idle');\n const { gl, invalidate } = useThree();\n const metadata = useSplatEnvironment({\n environment,\n scenario,\n renderer,\n src,\n format,\n collisionProxy: collisionProxyMetadata,\n });\n\n useEffect(() => {\n onStatusChangeRef.current = onStatusChange;\n }, [onStatusChange]);\n\n useEffect(() => {\n onLoadRef.current = onLoad;\n }, [onLoad]);\n\n useEffect(() => {\n onErrorRef.current = onError;\n }, [onError]);\n\n useEffect(() => {\n let disposed = false;\n\n function setLifecycleStatus(nextStatus: SparkSplatStatus) {\n setStatus(nextStatus);\n onStatusChangeRef.current?.(nextStatus);\n }\n\n function restoreHiddenMeshes() {\n for (const mesh of hiddenMeshesRef.current) {\n mesh.visible = true;\n }\n hiddenMeshesRef.current = [];\n }\n\n async function loadSplat() {\n if (!metadata.src) {\n setLifecycleStatus('idle');\n return;\n }\n\n if (metadata.format !== 'spz') {\n const unsupportedFormatError = new Error(\n `SparkSplatEnvironment only supports .spz assets; received \"${metadata.format}\".`\n );\n setLifecycleStatus('error');\n onErrorRef.current?.(unsupportedFormatError);\n return;\n }\n\n setLifecycleStatus('loading');\n\n try {\n const sparkModule = await import('@sparkjsdev/spark');\n if (disposed || !groupRef.current) return;\n\n const spark = new sparkModule.SparkRenderer({\n renderer: gl,\n onDirty: invalidate,\n });\n const mesh = new sparkModule.SplatMesh({\n url: metadata.src,\n lod,\n });\n mesh.name = 'GaussianSplatMesh';\n\n groupRef.current.add(spark);\n groupRef.current.add(mesh);\n sparkRef.current = spark;\n meshRef.current = mesh;\n\n if (hideGroundMeshes && groupRef.current.parent) {\n groupRef.current.parent.traverse((object) => {\n if (\n !(object instanceof THREE.Mesh) ||\n object === (mesh as unknown as THREE.Object3D)\n ) {\n return;\n }\n const name = object.name.toLowerCase();\n if (\n name.includes('floor') ||\n name.includes('ground') ||\n name.includes('plane')\n ) {\n object.visible = false;\n hiddenMeshesRef.current.push(object);\n }\n });\n }\n\n await mesh.initialized;\n if (disposed) return;\n setLifecycleStatus('ready');\n onLoadRef.current?.(mesh);\n invalidate();\n } catch (error) {\n const normalizedError =\n error instanceof Error ? error : new Error(String(error));\n setLifecycleStatus('error');\n onErrorRef.current?.(normalizedError);\n }\n }\n\n void loadSplat();\n\n return () => {\n disposed = true;\n restoreHiddenMeshes();\n\n if (meshRef.current) {\n groupRef.current?.remove(meshRef.current);\n safelyDisposeSparkResource(meshRef.current);\n meshRef.current = null;\n }\n\n if (sparkRef.current) {\n groupRef.current?.remove(sparkRef.current);\n safelyDisposeSparkResource(sparkRef.current);\n sparkRef.current = null;\n }\n };\n }, [\n gl,\n hideGroundMeshes,\n invalidate,\n lod,\n metadata.format,\n metadata.src,\n ]);\n\n return (\n <SplatEnvironment\n {...groupProps}\n environment={environment}\n scenario={scenario}\n renderer={renderer}\n src={metadata.src}\n format={metadata.format}\n collisionProxyMetadata={metadata.collisionProxy}\n collisionProxy={collisionProxy}\n showPlaceholder={showPlaceholder ?? status !== 'ready'}\n >\n <group ref={groupRef} />\n {children}\n </SplatEnvironment>\n );\n}\n\nfunction safelyDisposeSparkResource(resource: SparkDisposable) {\n try {\n const result = resource.dispose?.();\n if (isPromiseLike(result)) {\n void Promise.resolve(result).catch(handleSparkDisposeError);\n }\n } catch (error) {\n handleSparkDisposeError(error);\n }\n}\n\nfunction isPromiseLike(value: unknown): value is PromiseLike<unknown> {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'then' in value &&\n typeof (value as { then?: unknown }).then === 'function'\n );\n}\n\nfunction handleSparkDisposeError(error: unknown) {\n if (\n error instanceof Error &&\n error.message.toLowerCase().includes('worker terminate')\n ) {\n return;\n }\n\n console.warn('[mujoco-react] Spark resource disposal failed.', error);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/spark.tsx"],"names":[],"mappings":"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","file":"spark.js","sourcesContent":["/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { useThree } from '@react-three/fiber';\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport * as THREE from 'three';\nimport {\n SplatEnvironment,\n useSplatEnvironment,\n useSplatSceneConfig,\n} from './components/VisualScenario';\nimport type {\n PairedSplatEnvironmentConfig,\n SceneConfig,\n SplatEnvironmentProps,\n SplatEnvironmentReadiness,\n VisualScenarioConfig,\n} from './types';\n\ntype SparkModule = typeof import('@sparkjsdev/spark');\ntype SparkRendererInstance = InstanceType<SparkModule['SparkRenderer']>;\ntype SparkSplatMeshInstance = InstanceType<SparkModule['SplatMesh']>;\ntype SparkDisposable = {\n dispose?: () => unknown;\n};\ntype SparkWorkerMessage = {\n reject?: (error: unknown) => void;\n};\ntype SparkWorkerLike = {\n messages?: Record<string, SparkWorkerMessage>;\n};\ntype SparkResourceWithWorkers = SparkDisposable & {\n worker?: SparkWorkerLike;\n sortWorker?: SparkWorkerLike;\n lodWorker?: SparkWorkerLike;\n};\n\nexport type SparkSplatStatus = 'idle' | 'loading' | 'ready' | 'error';\n\nlet sparkDisposeRejectionHandlerRegistered = false;\n\nexport interface SparkSplatLifecycle {\n status: SparkSplatStatus;\n error: Error | null;\n isLoading: boolean;\n isReady: boolean;\n isError: boolean;\n props: Pick<SparkSplatEnvironmentProps, 'onStatusChange' | 'onError'>;\n reset: () => void;\n}\n\nexport interface SparkSplatEnvironmentState {\n environment: PairedSplatEnvironmentConfig | undefined;\n sceneConfig: SceneConfig;\n readiness: SplatEnvironmentReadiness;\n lifecycle: SparkSplatLifecycle;\n props: Pick<\n SparkSplatEnvironmentProps,\n 'environment' | 'scenario' | 'src' | 'format' | 'onStatusChange' | 'onError'\n >;\n enabled: boolean;\n}\n\nexport interface SparkSplatEnvironmentProps extends SplatEnvironmentProps {\n /** Enable Spark LoD handling for large splat assets. Default: true. */\n lod?: boolean | 'quality';\n /**\n * Hide meshes whose names include floor, ground, or plane while the splat is\n * active. This mirrors the common hybrid-rendering setup where MJCF keeps\n * collision geometry but the splat owns the visual environment.\n */\n hideGroundMeshes?: boolean;\n onStatusChange?: (status: SparkSplatStatus) => void;\n onLoad?: (mesh: SparkSplatMeshInstance) => void;\n onError?: (error: Error) => void;\n}\n\n/**\n * Resolve a visual scenario's paired splat environment, compose its MJCF\n * collision proxy into the MuJoCo scene config, and expose Spark lifecycle\n * props for `<SparkSplatEnvironment />`.\n */\nexport function useSparkSplatEnvironment({\n sceneConfig,\n scenario,\n environment,\n enabled = true,\n renderer = 'spark',\n onError,\n onStatusChange,\n}: {\n sceneConfig: SceneConfig;\n scenario?: VisualScenarioConfig;\n environment?: PairedSplatEnvironmentConfig;\n enabled?: boolean;\n renderer?: 'spark';\n onError?: (error: Error) => void;\n onStatusChange?: (status: SparkSplatStatus) => void;\n}): SparkSplatEnvironmentState {\n const splatScene = useSplatSceneConfig({\n sceneConfig,\n scenario,\n environment,\n enabled,\n renderer,\n });\n const metadata = useSplatEnvironment({\n scenario,\n environment: splatScene.environment,\n renderer,\n });\n const renderEnabled = enabled && Boolean(metadata.src);\n const readiness = enabled ? metadata.readiness : splatScene.readiness;\n const lifecycle = useSparkSplatLifecycle({\n enabled: renderEnabled,\n onError,\n onStatusChange,\n });\n\n return useMemo(\n () => ({\n environment: splatScene.environment,\n sceneConfig: splatScene.sceneConfig,\n readiness,\n lifecycle,\n props: {\n environment: splatScene.environment,\n scenario: enabled ? scenario : undefined,\n src: enabled ? metadata.src : undefined,\n format: metadata.format,\n ...lifecycle.props,\n },\n enabled: renderEnabled,\n }),\n [enabled, lifecycle, metadata, readiness, renderEnabled, scenario, splatScene]\n );\n}\n\n/**\n * Tracks Spark 3DGS loading state for UI that wraps `SparkSplatEnvironment`.\n *\n * Use the returned `props` with `<SparkSplatEnvironment {...lifecycle.props} />`\n * to avoid repeating status/error state in app code.\n */\nexport function useSparkSplatLifecycle({\n enabled = true,\n initialStatus,\n onError,\n onStatusChange,\n}: {\n enabled?: boolean;\n initialStatus?: SparkSplatStatus;\n onError?: (error: Error) => void;\n onStatusChange?: (status: SparkSplatStatus) => void;\n} = {}): SparkSplatLifecycle {\n const [status, setStatus] = useState<SparkSplatStatus>(\n initialStatus ?? (enabled ? 'loading' : 'idle')\n );\n const [error, setError] = useState<Error | null>(null);\n\n useEffect(() => {\n setStatus(enabled ? initialStatus ?? 'loading' : 'idle');\n setError(null);\n }, [enabled, initialStatus]);\n\n const handleStatusChange = useCallback(\n (nextStatus: SparkSplatStatus) => {\n setStatus(nextStatus);\n if (nextStatus !== 'error') {\n setError(null);\n }\n onStatusChange?.(nextStatus);\n },\n [onStatusChange]\n );\n\n const handleError = useCallback(\n (nextError: Error) => {\n setError(nextError);\n setStatus('error');\n onError?.(nextError);\n },\n [onError]\n );\n\n const reset = useCallback(() => {\n setStatus(enabled ? initialStatus ?? 'loading' : 'idle');\n setError(null);\n }, [enabled, initialStatus]);\n\n return useMemo(\n () => ({\n status,\n error,\n isLoading: status === 'loading',\n isReady: status === 'ready',\n isError: status === 'error',\n props: {\n onStatusChange: handleStatusChange,\n onError: handleError,\n },\n reset,\n }),\n [error, handleError, handleStatusChange, reset, status]\n );\n}\n\n/**\n * Optional SparkJS-backed Gaussian splat renderer for React Three Fiber scenes.\n *\n * Import from `mujoco-react/spark` and install `@sparkjsdev/spark` in the app\n * that uses it. The core `mujoco-react` entrypoint does not depend on Spark.\n */\nexport function SparkSplatEnvironment({\n environment,\n scenario,\n renderer = 'spark',\n src,\n format,\n collisionProxy,\n collisionProxyMetadata,\n showPlaceholder,\n children,\n lod = true,\n hideGroundMeshes = false,\n onStatusChange,\n onLoad,\n onError,\n ...groupProps\n}: SparkSplatEnvironmentProps) {\n const groupRef = useRef<THREE.Group>(null);\n const sparkRef = useRef<SparkRendererInstance | null>(null);\n const meshRef = useRef<SparkSplatMeshInstance | null>(null);\n const hiddenMeshesRef = useRef<THREE.Mesh[]>([]);\n const onStatusChangeRef = useRef(onStatusChange);\n const onLoadRef = useRef(onLoad);\n const onErrorRef = useRef(onError);\n const [status, setStatus] = useState<SparkSplatStatus>('idle');\n const { gl, invalidate } = useThree();\n const metadata = useSplatEnvironment({\n environment,\n scenario,\n renderer,\n src,\n format,\n collisionProxy: collisionProxyMetadata,\n });\n\n useEffect(() => {\n onStatusChangeRef.current = onStatusChange;\n }, [onStatusChange]);\n\n useEffect(() => {\n onLoadRef.current = onLoad;\n }, [onLoad]);\n\n useEffect(() => {\n onErrorRef.current = onError;\n }, [onError]);\n\n useEffect(() => {\n let disposed = false;\n ensureSparkDisposeRejectionHandler();\n\n function setLifecycleStatus(nextStatus: SparkSplatStatus) {\n setStatus(nextStatus);\n onStatusChangeRef.current?.(nextStatus);\n }\n\n function restoreHiddenMeshes() {\n for (const mesh of hiddenMeshesRef.current) {\n mesh.visible = true;\n }\n hiddenMeshesRef.current = [];\n }\n\n async function loadSplat() {\n if (!metadata.src) {\n setLifecycleStatus('idle');\n return;\n }\n\n if (metadata.format !== 'spz') {\n const unsupportedFormatError = new Error(\n `SparkSplatEnvironment only supports .spz assets; received \"${metadata.format}\".`\n );\n setLifecycleStatus('error');\n onErrorRef.current?.(unsupportedFormatError);\n return;\n }\n\n setLifecycleStatus('loading');\n\n try {\n const sparkModule = await import('@sparkjsdev/spark');\n if (disposed || !groupRef.current) return;\n\n const spark = new sparkModule.SparkRenderer({\n renderer: gl,\n onDirty: invalidate,\n });\n const mesh = new sparkModule.SplatMesh({\n url: metadata.src,\n lod,\n });\n mesh.name = 'GaussianSplatMesh';\n\n groupRef.current.add(spark);\n groupRef.current.add(mesh);\n sparkRef.current = spark;\n meshRef.current = mesh;\n\n if (hideGroundMeshes && groupRef.current.parent) {\n groupRef.current.parent.traverse((object) => {\n if (\n !(object instanceof THREE.Mesh) ||\n object === (mesh as unknown as THREE.Object3D)\n ) {\n return;\n }\n const name = object.name.toLowerCase();\n if (\n name.includes('floor') ||\n name.includes('ground') ||\n name.includes('plane')\n ) {\n object.visible = false;\n hiddenMeshesRef.current.push(object);\n }\n });\n }\n\n await mesh.initialized;\n if (disposed) return;\n setLifecycleStatus('ready');\n onLoadRef.current?.(mesh);\n invalidate();\n } catch (error) {\n const normalizedError =\n error instanceof Error ? error : new Error(String(error));\n setLifecycleStatus('error');\n onErrorRef.current?.(normalizedError);\n }\n }\n\n void loadSplat();\n\n return () => {\n disposed = true;\n restoreHiddenMeshes();\n\n if (meshRef.current) {\n groupRef.current?.remove(meshRef.current);\n safelyDisposeSparkResource(meshRef.current);\n meshRef.current = null;\n }\n\n if (sparkRef.current) {\n groupRef.current?.remove(sparkRef.current);\n safelyDisposeSparkResource(sparkRef.current);\n sparkRef.current = null;\n }\n };\n }, [\n gl,\n hideGroundMeshes,\n invalidate,\n lod,\n metadata.format,\n metadata.src,\n ]);\n\n return (\n <SplatEnvironment\n {...groupProps}\n environment={environment}\n scenario={scenario}\n renderer={renderer}\n src={metadata.src}\n format={metadata.format}\n collisionProxyMetadata={metadata.collisionProxy}\n collisionProxy={collisionProxy}\n showPlaceholder={showPlaceholder ?? status !== 'ready'}\n >\n <group ref={groupRef} />\n {children}\n </SplatEnvironment>\n );\n}\n\nfunction safelyDisposeSparkResource(resource: SparkDisposable) {\n try {\n silenceSparkWorkerTerminateRejections(resource);\n const result = resource.dispose?.();\n if (isPromiseLike(result)) {\n void Promise.resolve(result).catch(handleSparkDisposeError);\n }\n } catch (error) {\n handleSparkDisposeError(error);\n }\n}\n\nfunction isPromiseLike(value: unknown): value is PromiseLike<unknown> {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'then' in value &&\n typeof (value as { then?: unknown }).then === 'function'\n );\n}\n\nfunction silenceSparkWorkerTerminateRejections(resource: SparkDisposable) {\n const workers = getSparkWorkers(resource);\n for (const worker of workers) {\n if (!worker.messages) continue;\n\n for (const message of Object.values(worker.messages)) {\n const reject = message.reject;\n if (!reject) continue;\n\n message.reject = (error: unknown) => {\n if (!isSparkWorkerTerminateError(error)) {\n reject(error);\n }\n };\n }\n }\n}\n\nfunction getSparkWorkers(resource: SparkDisposable): SparkWorkerLike[] {\n const sparkResource = resource as SparkResourceWithWorkers;\n return [\n sparkResource.worker,\n sparkResource.sortWorker,\n sparkResource.lodWorker,\n ].filter((worker): worker is SparkWorkerLike => Boolean(worker));\n}\n\nfunction handleSparkDisposeError(error: unknown) {\n if (\n error instanceof Error &&\n error.message.toLowerCase().includes('worker terminate')\n ) {\n return;\n }\n\n console.warn('[mujoco-react] Spark resource disposal failed.', error);\n}\n\nfunction ensureSparkDisposeRejectionHandler() {\n if (\n sparkDisposeRejectionHandlerRegistered ||\n typeof window === 'undefined' ||\n typeof window.addEventListener !== 'function'\n ) {\n return;\n }\n\n sparkDisposeRejectionHandlerRegistered = true;\n window.addEventListener('unhandledrejection', (event) => {\n if (isSparkWorkerTerminateError(event.reason)) {\n event.preventDefault();\n }\n });\n}\n\nfunction isSparkWorkerTerminateError(reason: unknown) {\n return (\n reason instanceof Error &&\n reason.message.toLowerCase().includes('worker terminate')\n );\n}\n"]}
|
|
@@ -39,7 +39,7 @@ type Robots = [RegisteredRobotMap] extends [never] ? string : Extract<keyof Regi
|
|
|
39
39
|
type RobotResource<TRobot extends string, TKey extends string> = [
|
|
40
40
|
RegisteredRobotMap
|
|
41
41
|
] extends [never] ? string : TRobot extends keyof RegisteredRobotMap ? TKey extends keyof RegisteredRobotMap[TRobot] ? RegisteredRobotMap[TRobot][TKey] : string : never;
|
|
42
|
-
type RegisterResourceKey = 'actuators' | 'sensors' | 'bodies' | 'joints' | 'sites' | 'geoms' | 'keyframes';
|
|
42
|
+
type RegisterResourceKey = 'actuators' | 'sensors' | 'bodies' | 'joints' | 'sites' | 'geoms' | 'keyframes' | 'cameras';
|
|
43
43
|
type RobotResourceObject<TRobot extends string, TKey extends RegisterResourceKey> = string extends RobotResource<TRobot, TKey> ? Record<string, string> : {
|
|
44
44
|
readonly [K in RobotResource<TRobot, TKey>]: K;
|
|
45
45
|
};
|
|
@@ -68,6 +68,8 @@ type RobotGeoms<TRobot extends string> = RobotResource<TRobot, 'geoms'>;
|
|
|
68
68
|
declare const RobotGeoms: RobotResourceCategory<'geoms'>;
|
|
69
69
|
type RobotKeyframes<TRobot extends string> = RobotResource<TRobot, 'keyframes'>;
|
|
70
70
|
declare const RobotKeyframes: RobotResourceCategory<'keyframes'>;
|
|
71
|
+
type RobotCameras<TRobot extends string> = RobotResource<TRobot, 'cameras'>;
|
|
72
|
+
declare const RobotCameras: RobotResourceCategory<'cameras'>;
|
|
71
73
|
type Actuators = Register extends {
|
|
72
74
|
actuators: infer T extends string;
|
|
73
75
|
} ? T : string;
|
|
@@ -89,6 +91,9 @@ type Geoms = Register extends {
|
|
|
89
91
|
type Keyframes = Register extends {
|
|
90
92
|
keyframes: infer T extends string;
|
|
91
93
|
} ? T : string;
|
|
94
|
+
type Cameras = Register extends {
|
|
95
|
+
cameras: infer T extends string;
|
|
96
|
+
} ? T : string;
|
|
92
97
|
/**
|
|
93
98
|
* A single MuJoCo contact from the WASM module.
|
|
94
99
|
* Accessed via `data.contact.get(i)`.
|
|
@@ -131,6 +136,7 @@ interface MujocoModel {
|
|
|
131
136
|
nflex: number;
|
|
132
137
|
nmesh: number;
|
|
133
138
|
nmat: number;
|
|
139
|
+
ncam?: number;
|
|
134
140
|
names: Int8Array;
|
|
135
141
|
name_bodyadr: Int32Array;
|
|
136
142
|
name_jntadr: Int32Array;
|
|
@@ -140,6 +146,7 @@ interface MujocoModel {
|
|
|
140
146
|
name_keyadr: Int32Array;
|
|
141
147
|
name_sensoradr: Int32Array;
|
|
142
148
|
name_tendonadr: Int32Array;
|
|
149
|
+
name_camadr?: Int32Array;
|
|
143
150
|
body_mass: Float64Array;
|
|
144
151
|
body_parentid: Int32Array;
|
|
145
152
|
body_jntnum: Int32Array;
|
|
@@ -204,6 +211,10 @@ interface MujocoModel {
|
|
|
204
211
|
light_cutoff: Float32Array;
|
|
205
212
|
light_exponent: Float32Array;
|
|
206
213
|
light_intensity: Float32Array;
|
|
214
|
+
cam_bodyid?: Int32Array;
|
|
215
|
+
cam_pos?: Float64Array;
|
|
216
|
+
cam_quat?: Float64Array;
|
|
217
|
+
cam_fovy?: Float64Array;
|
|
207
218
|
ten_wrapadr: Int32Array;
|
|
208
219
|
ten_wrapnum: Int32Array;
|
|
209
220
|
ten_range: Float64Array;
|
|
@@ -240,6 +251,9 @@ interface MujocoData {
|
|
|
240
251
|
qfrc_bias: Float64Array;
|
|
241
252
|
site_xpos: Float64Array;
|
|
242
253
|
site_xmat: Float64Array;
|
|
254
|
+
cam_xpos?: Float64Array;
|
|
255
|
+
cam_xmat?: Float64Array;
|
|
256
|
+
xmat?: Float64Array;
|
|
243
257
|
sensordata: Float64Array;
|
|
244
258
|
ncon: number;
|
|
245
259
|
contact: MujocoContactArray;
|
|
@@ -519,6 +533,14 @@ interface SensorInfo {
|
|
|
519
533
|
dim: number;
|
|
520
534
|
adr: number;
|
|
521
535
|
}
|
|
536
|
+
interface CameraInfo {
|
|
537
|
+
id: number;
|
|
538
|
+
name: string;
|
|
539
|
+
bodyId: number;
|
|
540
|
+
fov: number | null;
|
|
541
|
+
position: [number, number, number] | null;
|
|
542
|
+
quaternion: [number, number, number, number] | null;
|
|
543
|
+
}
|
|
522
544
|
interface ContactInfo {
|
|
523
545
|
geom1: number;
|
|
524
546
|
geom1Name: string;
|
|
@@ -696,6 +718,23 @@ interface PairedSplatEnvironmentConfig {
|
|
|
696
718
|
xmlPath: string;
|
|
697
719
|
};
|
|
698
720
|
}
|
|
721
|
+
declare const SplatEnvironmentReadinessStatus: {
|
|
722
|
+
readonly Disabled: "disabled";
|
|
723
|
+
readonly MissingSplat: "missing-splat";
|
|
724
|
+
readonly MissingCollisionProxy: "missing-collision-proxy";
|
|
725
|
+
readonly UnsupportedFormat: "unsupported-format";
|
|
726
|
+
readonly Ready: "ready";
|
|
727
|
+
};
|
|
728
|
+
type SplatEnvironmentReadinessStatus = (typeof SplatEnvironmentReadinessStatus)[keyof typeof SplatEnvironmentReadinessStatus];
|
|
729
|
+
interface SplatEnvironmentReadiness {
|
|
730
|
+
status: SplatEnvironmentReadinessStatus;
|
|
731
|
+
ready: boolean;
|
|
732
|
+
requiresCollisionProxy: boolean;
|
|
733
|
+
missing: Array<'splat' | 'collisionProxy'>;
|
|
734
|
+
format?: SplatFormat;
|
|
735
|
+
renderer?: SplatRendererKind;
|
|
736
|
+
message: string;
|
|
737
|
+
}
|
|
699
738
|
interface SplatEnvironmentMetadataInput {
|
|
700
739
|
environment?: PairedSplatEnvironmentConfig;
|
|
701
740
|
scenario?: VisualScenarioConfig;
|
|
@@ -708,9 +747,23 @@ interface SplatEnvironmentMetadata {
|
|
|
708
747
|
src?: string;
|
|
709
748
|
format: SplatFormat;
|
|
710
749
|
collisionProxy?: SplatCollisionProxyConfig;
|
|
750
|
+
readiness: SplatEnvironmentReadiness;
|
|
711
751
|
userData: Record<string, unknown>;
|
|
712
752
|
}
|
|
713
753
|
type SplatSceneInput = PairedSplatEnvironmentConfig | VisualScenarioConfig | undefined | null;
|
|
754
|
+
interface SplatSceneConfigInput {
|
|
755
|
+
sceneConfig: SceneConfig;
|
|
756
|
+
scenario?: VisualScenarioConfig;
|
|
757
|
+
environment?: PairedSplatEnvironmentConfig;
|
|
758
|
+
enabled?: boolean;
|
|
759
|
+
renderer?: SplatRendererKind;
|
|
760
|
+
}
|
|
761
|
+
interface SplatSceneConfigState {
|
|
762
|
+
environment: PairedSplatEnvironmentConfig | undefined;
|
|
763
|
+
sceneConfig: SceneConfig;
|
|
764
|
+
enabled: boolean;
|
|
765
|
+
readiness: SplatEnvironmentReadiness;
|
|
766
|
+
}
|
|
714
767
|
interface VisualScenarioConfig {
|
|
715
768
|
id?: string;
|
|
716
769
|
label?: string;
|
|
@@ -826,6 +879,7 @@ interface MujocoSimAPI {
|
|
|
826
879
|
getSites(): SiteInfo[];
|
|
827
880
|
getActuators(): ActuatorInfo[];
|
|
828
881
|
getSensors(): SensorInfo[];
|
|
882
|
+
getCameras(): CameraInfo[];
|
|
829
883
|
getModelOption(): ModelOptions;
|
|
830
884
|
setGravity(g: [number, number, number]): void;
|
|
831
885
|
setTimestep(dt: number): void;
|
|
@@ -841,6 +895,9 @@ interface MujocoSimAPI {
|
|
|
841
895
|
getCanvasSnapshot(width?: number, height?: number, mimeType?: string): string;
|
|
842
896
|
captureFrame(options?: MujocoFrameCaptureOptions): Promise<FrameCaptureResult>;
|
|
843
897
|
captureFrameBlob(options?: MujocoFrameCaptureOptions): Promise<FrameCaptureBlobResult>;
|
|
898
|
+
captureCameraFrame(options?: CameraFrameCaptureOptions): Promise<CameraFrameCaptureResult>;
|
|
899
|
+
captureCameraFrameBlob(options?: CameraFrameCaptureOptions): Promise<CameraFrameCaptureBlobResult>;
|
|
900
|
+
recordCameraSequence(options: CameraFrameSequenceOptions): Promise<CameraFrameSequenceResult>;
|
|
844
901
|
project2DTo3D(x: number, y: number, cameraPos: THREE.Vector3, lookAt: THREE.Vector3): {
|
|
845
902
|
point: THREE.Vector3;
|
|
846
903
|
bodyId: number;
|
|
@@ -880,6 +937,137 @@ interface FrameCaptureAPI {
|
|
|
880
937
|
captureBlob: (options?: FrameCaptureOptions) => Promise<FrameCaptureBlobResult>;
|
|
881
938
|
reset: () => void;
|
|
882
939
|
}
|
|
940
|
+
type CameraFrameCaptureVector3 = THREE.Vector3 | readonly [number, number, number];
|
|
941
|
+
type CameraFrameCaptureQuaternion = THREE.Quaternion | readonly [number, number, number, number];
|
|
942
|
+
interface CameraFrameCaptureOptions {
|
|
943
|
+
/** Existing Three camera to clone before applying pose overrides. */
|
|
944
|
+
camera?: THREE.Camera;
|
|
945
|
+
/** Named MuJoCo `<camera>` to render from when available in the loaded model. */
|
|
946
|
+
cameraName?: Cameras;
|
|
947
|
+
/** Named MuJoCo site to use as the rendered camera pose. Useful for robot-mounted optical frames. */
|
|
948
|
+
siteName?: Sites;
|
|
949
|
+
/** Named MuJoCo body to use as the rendered camera pose. */
|
|
950
|
+
bodyName?: Bodies;
|
|
951
|
+
position?: CameraFrameCaptureVector3;
|
|
952
|
+
lookAt?: CameraFrameCaptureVector3;
|
|
953
|
+
quaternion?: CameraFrameCaptureQuaternion;
|
|
954
|
+
up?: CameraFrameCaptureVector3;
|
|
955
|
+
width?: number;
|
|
956
|
+
height?: number;
|
|
957
|
+
type?: string;
|
|
958
|
+
quality?: number;
|
|
959
|
+
fov?: number;
|
|
960
|
+
near?: number;
|
|
961
|
+
far?: number;
|
|
962
|
+
/** Provenance for the camera pose used by the capture. Usually set by the MuJoCo provider. */
|
|
963
|
+
source?: CameraFrameCaptureSource;
|
|
964
|
+
}
|
|
965
|
+
type CameraFrameCaptureSource = {
|
|
966
|
+
kind: 'mujoco-camera';
|
|
967
|
+
cameraName: Cameras;
|
|
968
|
+
} | {
|
|
969
|
+
kind: 'mujoco-site';
|
|
970
|
+
siteName: Sites;
|
|
971
|
+
} | {
|
|
972
|
+
kind: 'mujoco-body';
|
|
973
|
+
bodyName: Bodies;
|
|
974
|
+
} | {
|
|
975
|
+
kind: 'custom-camera';
|
|
976
|
+
} | {
|
|
977
|
+
kind: 'explicit-pose';
|
|
978
|
+
} | {
|
|
979
|
+
kind: 'fallback-camera';
|
|
980
|
+
};
|
|
981
|
+
interface CameraFrameCaptureResult {
|
|
982
|
+
canvas: HTMLCanvasElement;
|
|
983
|
+
camera: THREE.Camera;
|
|
984
|
+
dataUrl: string;
|
|
985
|
+
type: string;
|
|
986
|
+
width: number;
|
|
987
|
+
height: number;
|
|
988
|
+
source: CameraFrameCaptureSource;
|
|
989
|
+
}
|
|
990
|
+
interface CameraFrameCaptureBlobResult {
|
|
991
|
+
canvas: HTMLCanvasElement;
|
|
992
|
+
camera: THREE.Camera;
|
|
993
|
+
blob: Blob;
|
|
994
|
+
type: string;
|
|
995
|
+
width: number;
|
|
996
|
+
height: number;
|
|
997
|
+
source: CameraFrameCaptureSource;
|
|
998
|
+
}
|
|
999
|
+
interface CameraFrameCaptureAPI {
|
|
1000
|
+
status: FrameCaptureStatus;
|
|
1001
|
+
error: Error | null;
|
|
1002
|
+
isCapturing: boolean;
|
|
1003
|
+
capture: (options?: CameraFrameCaptureOptions) => Promise<CameraFrameCaptureResult>;
|
|
1004
|
+
captureBlob: (options?: CameraFrameCaptureOptions) => Promise<CameraFrameCaptureBlobResult>;
|
|
1005
|
+
reset: () => void;
|
|
1006
|
+
}
|
|
1007
|
+
interface CameraFrameSequenceCamera extends CameraFrameCaptureOptions {
|
|
1008
|
+
key: string;
|
|
1009
|
+
}
|
|
1010
|
+
interface CameraFrameSequenceFrame {
|
|
1011
|
+
frameIndex: number;
|
|
1012
|
+
time: number;
|
|
1013
|
+
cameras: Record<string, CameraFrameCaptureResult>;
|
|
1014
|
+
}
|
|
1015
|
+
interface CameraFrameSequenceCameraSummary {
|
|
1016
|
+
key: string;
|
|
1017
|
+
width: number;
|
|
1018
|
+
height: number;
|
|
1019
|
+
source: CameraFrameCaptureSource;
|
|
1020
|
+
frameCount: number;
|
|
1021
|
+
firstFrameIndex: number | null;
|
|
1022
|
+
lastFrameIndex: number | null;
|
|
1023
|
+
firstTimestamp: number | null;
|
|
1024
|
+
lastTimestamp: number | null;
|
|
1025
|
+
}
|
|
1026
|
+
interface CameraFrameSequenceSampleInput extends PhysicsStepInput {
|
|
1027
|
+
frameIndex: number;
|
|
1028
|
+
time: number;
|
|
1029
|
+
}
|
|
1030
|
+
interface CameraFrameSequenceStepInput extends PhysicsStepInput {
|
|
1031
|
+
frameIndex: number;
|
|
1032
|
+
stepIndex: number;
|
|
1033
|
+
time: number;
|
|
1034
|
+
}
|
|
1035
|
+
interface CameraFrameSequenceOptions {
|
|
1036
|
+
cameras: readonly CameraFrameSequenceCamera[];
|
|
1037
|
+
frames: number;
|
|
1038
|
+
/** Number of MuJoCo steps between captured frames. Use 0 for static camera provenance captures. */
|
|
1039
|
+
stepsPerFrame?: number;
|
|
1040
|
+
reset?: boolean;
|
|
1041
|
+
captureInitialFrame?: boolean;
|
|
1042
|
+
retainFrames?: boolean;
|
|
1043
|
+
/**
|
|
1044
|
+
* Require each recorded stream to resolve from exactly one mounted MuJoCo
|
|
1045
|
+
* camera/site/body selector. Defaults to true because sequence recording is
|
|
1046
|
+
* intended for dataset/policy camera streams.
|
|
1047
|
+
*/
|
|
1048
|
+
requireMountedSources?: boolean;
|
|
1049
|
+
signal?: AbortSignal;
|
|
1050
|
+
/** Called after stepping and before image capture for this frame. Use this to record synchronized state/action rows. */
|
|
1051
|
+
onSample?: (input: CameraFrameSequenceSampleInput) => void | Promise<void>;
|
|
1052
|
+
/** Called before each MuJoCo step inside sequence recording. Use this to apply policy/control actions. */
|
|
1053
|
+
onBeforeStep?: (input: CameraFrameSequenceStepInput) => void | Promise<void>;
|
|
1054
|
+
/** Called after each MuJoCo step inside sequence recording. Use this for step-level telemetry. */
|
|
1055
|
+
onAfterStep?: (input: CameraFrameSequenceStepInput) => void | Promise<void>;
|
|
1056
|
+
onFrame?: (frame: CameraFrameSequenceFrame) => void | Promise<void>;
|
|
1057
|
+
}
|
|
1058
|
+
interface CameraFrameSequenceResult {
|
|
1059
|
+
frames: CameraFrameSequenceFrame[];
|
|
1060
|
+
cameraKeys: string[];
|
|
1061
|
+
cameraSummaries: Record<string, CameraFrameSequenceCameraSummary>;
|
|
1062
|
+
frameCount: number;
|
|
1063
|
+
}
|
|
1064
|
+
interface CameraFrameSequenceRecorderAPI {
|
|
1065
|
+
status: FrameCaptureStatus;
|
|
1066
|
+
error: Error | null;
|
|
1067
|
+
isRecording: boolean;
|
|
1068
|
+
record: (options: CameraFrameSequenceOptions) => Promise<CameraFrameSequenceResult>;
|
|
1069
|
+
reset: () => void;
|
|
1070
|
+
}
|
|
883
1071
|
type MujocoCanvasProps = Omit<CanvasProps, 'onError'> & {
|
|
884
1072
|
config: SceneConfig;
|
|
885
1073
|
/** R3F content rendered while the MuJoCo WASM module is still loading. */
|
|
@@ -938,4 +1126,4 @@ interface JointStateResult {
|
|
|
938
1126
|
velocity: React__default.RefObject<number | Float64Array>;
|
|
939
1127
|
}
|
|
940
1128
|
|
|
941
|
-
export { type
|
|
1129
|
+
export { type Actuators as $, type ActuatedJointInfo as A, type BodyProps as B, type ControlGroupInfo as C, type DragInteractionProps as D, type SplatSceneConfigState as E, type SplatSceneInput as F, type DebugProps as G, type GeomInfo as H, type IkConfig as I, type ContactListenerProps as J, type ActuatorInfo as K, type Sites as L, type MujocoContextValue as M, type SitePositionResult as N, type ObservationConfig as O, type PhysicsStepCallback as P, type Sensors as Q, type ReadyCallbackInput as R, type SceneConfig as S, type TrajectoryPlayerProps as T, type SensorHandle as U, type VisualScenarioEffectsProps as V, type SensorInfo as W, type Joints as X, type JointStateResult as Y, type Bodies as Z, type BodyStateResult as _, type MujocoCanvasProps as a, RobotJoints as a$, type CtrlHandle as a0, type ContactInfo as a1, type KeyboardTeleopConfig as a2, type PolicyConfig as a3, type PolicyVector as a4, type ObservationHandle as a5, type TrajectoryInput as a6, type TrajectoryStateChangeInput as a7, type PlaybackState as a8, type TrajectoryFrame as a9, type Geoms as aA, type IKSolveFn as aB, type IkGizmoDragInput as aC, type IkSolveInput as aD, type JointInfo as aE, type KeyBinding as aF, type Keyframes as aG, type ModelOptions as aH, type MujocoContact as aI, type MujocoContactArray as aJ, type MujocoFrameCaptureOptions as aK, type ObservationLayoutItem as aL, type ObservationOutput as aM, type PhysicsConfig as aN, type PhysicsStepInput as aO, type PolicyActionInput as aP, type PolicyInferenceInput as aQ, type PolicyObservationInput as aR, type RayHit as aS, type Register as aT, type RegisteredRobotMap as aU, type ResetCallbackInput as aV, type ResourceSelector as aW, RobotActuators as aX, RobotBodies as aY, RobotCameras as aZ, RobotGeoms as a_, type FrameCaptureOptions as aa, type FrameCaptureResult as ab, type FrameCaptureBlobResult as ac, type FrameCaptureAPI as ad, type CameraFrameCaptureOptions as ae, type CameraFrameCaptureAPI as af, type CameraFrameSequenceRecorderAPI as ag, type Cameras as ah, type CameraFrameSequenceCamera as ai, type CameraFrameCaptureSource as aj, type CameraFrameSequenceOptions as ak, type CameraFrameSequenceResult as al, type CameraFrameCaptureResult as am, type CameraFrameCaptureBlobResult as an, type BodyInfo as ao, type CameraFrameCaptureQuaternion as ap, type CameraFrameCaptureVector3 as aq, type CameraFrameSequenceCameraSummary as ar, type CameraFrameSequenceFrame as as, type CameraFrameSequenceSampleInput as at, type CameraFrameSequenceStepInput as au, type CameraInfo as av, type ControlJointInfo as aw, type FrameCaptureStatus as ax, type FrameCaptureTarget as ay, type FrameCaptureTargetRef as az, type MujocoSimAPI as b, RobotKeyframes as b0, type RobotResource as b1, RobotResources as b2, RobotSensors as b3, RobotSites as b4, type Robots as b5, type ScenarioCameraConfig as b6, type ScenarioMaterialConfig as b7, type SceneMarker as b8, type SceneObject as b9, type SensorResult as ba, type SiteInfo as bb, type SplatAssetConfig as bc, type SplatScenarioConfig as bd, type StateSnapshot as be, type TrajectoryData as bf, type TrajectoryFrameCallbackInput as bg, type VisualScenarioMaterialFilterInput as bh, type XmlPatch as bi, getContact as bj, registerRobotResources as bk, 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 SplatEnvironmentReadiness as t, type SplatCollisionPrimitive as u, SplatEnvironmentReadinessStatus as v, type ScenarioLightingPreset as w, type SplatEnvironmentMetadataInput as x, type SplatEnvironmentMetadata as y, type SplatSceneConfigInput as z };
|
package/dist/vite.d.ts
CHANGED
|
@@ -32,7 +32,7 @@ interface MujocoRegisterCodegenResult {
|
|
|
32
32
|
files: string[];
|
|
33
33
|
counts: Record<RegisterKey, number>;
|
|
34
34
|
}
|
|
35
|
-
type RegisterKey = 'actuators' | 'sensors' | 'bodies' | 'joints' | 'sites' | 'geoms' | 'keyframes';
|
|
35
|
+
type RegisterKey = 'actuators' | 'sensors' | 'bodies' | 'joints' | 'sites' | 'geoms' | 'keyframes' | 'cameras';
|
|
36
36
|
type ModelInput = string | readonly string[] | Record<string, string>;
|
|
37
37
|
declare function mujocoReact(options: MujocoReactPluginOptions): {
|
|
38
38
|
name: string;
|
package/dist/vite.js
CHANGED
|
@@ -2,7 +2,7 @@ import { mkdir, writeFile, readFile } from 'fs/promises';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
|
|
4
4
|
// src/vite.ts
|
|
5
|
-
var REGISTER_KEYS = ["actuators", "sensors", "bodies", "joints", "sites", "geoms", "keyframes"];
|
|
5
|
+
var REGISTER_KEYS = ["actuators", "sensors", "bodies", "joints", "sites", "geoms", "keyframes", "cameras"];
|
|
6
6
|
var MODEL_EXTENSIONS = /* @__PURE__ */ new Set([".xml", ".mjcf", ".urdf"]);
|
|
7
7
|
function createEmptyNames() {
|
|
8
8
|
return {
|
|
@@ -12,7 +12,8 @@ function createEmptyNames() {
|
|
|
12
12
|
joints: /* @__PURE__ */ new Set(),
|
|
13
13
|
sites: /* @__PURE__ */ new Set(),
|
|
14
14
|
geoms: /* @__PURE__ */ new Set(),
|
|
15
|
-
keyframes: /* @__PURE__ */ new Set()
|
|
15
|
+
keyframes: /* @__PURE__ */ new Set(),
|
|
16
|
+
cameras: /* @__PURE__ */ new Set()
|
|
16
17
|
};
|
|
17
18
|
}
|
|
18
19
|
function mujocoReact(options) {
|
|
@@ -99,6 +100,7 @@ async function scanModel(filePath, root, seen, names) {
|
|
|
99
100
|
collectSimpleTagNames(xml, "joint", names.joints);
|
|
100
101
|
collectSimpleTagNames(xml, "site", names.sites);
|
|
101
102
|
collectSimpleTagNames(xml, "geom", names.geoms);
|
|
103
|
+
collectSimpleTagNames(xml, "camera", names.cameras);
|
|
102
104
|
collectSimpleTagNames(xml, "key", names.keyframes);
|
|
103
105
|
collectSectionNames(xml, "actuator", names.actuators);
|
|
104
106
|
collectSectionNames(xml, "sensor", names.sensors);
|
|
@@ -217,7 +219,8 @@ function renderNamespaceAliases(models) {
|
|
|
217
219
|
joints: "RobotJoints",
|
|
218
220
|
sites: "RobotSites",
|
|
219
221
|
geoms: "RobotGeoms",
|
|
220
|
-
keyframes: "RobotKeyframes"
|
|
222
|
+
keyframes: "RobotKeyframes",
|
|
223
|
+
cameras: "RobotCameras"
|
|
221
224
|
};
|
|
222
225
|
const blocks = REGISTER_KEYS.map((key) => {
|
|
223
226
|
const aliases = models.filter((model) => isIdentifier(model.id)).map((model) => ` export type ${model.id} = RobotResource<'${escapeTs(model.id)}', '${key}'>;`);
|