mujoco-react 9.2.0 → 9.4.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 +225 -15
- package/dist/{chunk-33CV6HSV.js → chunk-VDSEPZYQ.js} +303 -14
- package/dist/chunk-VDSEPZYQ.js.map +1 -0
- package/dist/index.d.ts +274 -7
- package/dist/index.js +1172 -131
- 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-S8ggQY2n.d.ts → types-BuJ4boaq.d.ts} +160 -5
- package/dist/vite.d.ts +1 -1
- package/dist/vite.js +14 -7
- package/dist/vite.js.map +1 -1
- package/package.json +1 -1
- package/src/components/SplatCollisionProxyPreview.tsx +350 -0
- package/src/components/VisualScenario.tsx +287 -11
- package/src/core/MujocoSimProvider.tsx +374 -30
- package/src/core/SceneLoader.ts +13 -0
- package/src/hooks/useMountedCameraSequenceRecorder.ts +155 -0
- package/src/index.ts +80 -0
- package/src/rendering/cameraFrameCapture.ts +195 -26
- package/src/rendering/cameraFrameSource.ts +747 -0
- package/src/spark.tsx +144 -0
- package/src/types.ts +166 -4
- package/src/vite.ts +14 -6
- 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-BuJ4boaq.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-VDSEPZYQ.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;
|
|
@@ -691,11 +713,28 @@ interface PairedSplatEnvironmentConfig {
|
|
|
691
713
|
description?: string;
|
|
692
714
|
/** Visual-only Gaussian splat asset. */
|
|
693
715
|
splat: SplatAssetConfig;
|
|
694
|
-
/** MJCF/XML contact geometry paired with the visual splat. */
|
|
695
|
-
collisionProxy
|
|
716
|
+
/** Optional MJCF/XML contact geometry paired with the visual splat. */
|
|
717
|
+
collisionProxy?: SplatCollisionProxyConfig & {
|
|
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,61 @@ 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
|
}
|
|
753
|
+
interface ResolvedScenarioCameraConfig {
|
|
754
|
+
jitter: number;
|
|
755
|
+
exposure: number;
|
|
756
|
+
noise: number;
|
|
757
|
+
blur: number;
|
|
758
|
+
}
|
|
759
|
+
interface ResolvedScenarioMaterialConfig {
|
|
760
|
+
randomizeObjectColors: boolean;
|
|
761
|
+
randomizeTableMaterial: boolean;
|
|
762
|
+
roughness?: number;
|
|
763
|
+
metalness?: number;
|
|
764
|
+
}
|
|
765
|
+
interface VisualScenarioExecutionContext {
|
|
766
|
+
scenarioId: string;
|
|
767
|
+
scenarioLabel: string;
|
|
768
|
+
variantId?: string;
|
|
769
|
+
seed: number;
|
|
770
|
+
lighting: ScenarioLightingPreset;
|
|
771
|
+
environment?: string;
|
|
772
|
+
camera: ResolvedScenarioCameraConfig;
|
|
773
|
+
materials: ResolvedScenarioMaterialConfig;
|
|
774
|
+
splatEnabled: boolean;
|
|
775
|
+
splatSrc?: string;
|
|
776
|
+
splatFormat: SplatFormat;
|
|
777
|
+
splatRenderer?: SplatRendererKind;
|
|
778
|
+
collisionProxyXmlPath?: string;
|
|
779
|
+
collisionProxyStatus?: SplatCollisionProxyConfig['status'];
|
|
780
|
+
collisionProxyPrimitives: SplatCollisionPrimitive[];
|
|
781
|
+
readiness: SplatEnvironmentReadiness;
|
|
782
|
+
transformSource: 'visualScenario.camera';
|
|
783
|
+
}
|
|
784
|
+
interface VisualScenarioExecutionContextInput {
|
|
785
|
+
scenario?: VisualScenarioConfig;
|
|
786
|
+
environment?: PairedSplatEnvironmentConfig;
|
|
787
|
+
renderer?: SplatRendererKind;
|
|
788
|
+
variantId?: string;
|
|
789
|
+
enabled?: boolean;
|
|
790
|
+
}
|
|
713
791
|
type SplatSceneInput = PairedSplatEnvironmentConfig | VisualScenarioConfig | undefined | null;
|
|
792
|
+
interface SplatSceneConfigInput {
|
|
793
|
+
sceneConfig: SceneConfig;
|
|
794
|
+
scenario?: VisualScenarioConfig;
|
|
795
|
+
environment?: PairedSplatEnvironmentConfig;
|
|
796
|
+
enabled?: boolean;
|
|
797
|
+
renderer?: SplatRendererKind;
|
|
798
|
+
}
|
|
799
|
+
interface SplatSceneConfigState {
|
|
800
|
+
environment: PairedSplatEnvironmentConfig | undefined;
|
|
801
|
+
sceneConfig: SceneConfig;
|
|
802
|
+
enabled: boolean;
|
|
803
|
+
readiness: SplatEnvironmentReadiness;
|
|
804
|
+
}
|
|
714
805
|
interface VisualScenarioConfig {
|
|
715
806
|
id?: string;
|
|
716
807
|
label?: string;
|
|
@@ -826,6 +917,7 @@ interface MujocoSimAPI {
|
|
|
826
917
|
getSites(): SiteInfo[];
|
|
827
918
|
getActuators(): ActuatorInfo[];
|
|
828
919
|
getSensors(): SensorInfo[];
|
|
920
|
+
getCameras(): CameraInfo[];
|
|
829
921
|
getModelOption(): ModelOptions;
|
|
830
922
|
setGravity(g: [number, number, number]): void;
|
|
831
923
|
setTimestep(dt: number): void;
|
|
@@ -886,7 +978,14 @@ interface FrameCaptureAPI {
|
|
|
886
978
|
type CameraFrameCaptureVector3 = THREE.Vector3 | readonly [number, number, number];
|
|
887
979
|
type CameraFrameCaptureQuaternion = THREE.Quaternion | readonly [number, number, number, number];
|
|
888
980
|
interface CameraFrameCaptureOptions {
|
|
981
|
+
/** Existing Three camera to clone before applying pose overrides. */
|
|
889
982
|
camera?: THREE.Camera;
|
|
983
|
+
/** Named MuJoCo `<camera>` to render from when available in the loaded model. */
|
|
984
|
+
cameraName?: Cameras;
|
|
985
|
+
/** Named MuJoCo site to use as the rendered camera pose. Useful for robot-mounted optical frames. */
|
|
986
|
+
siteName?: Sites;
|
|
987
|
+
/** Named MuJoCo body to use as the rendered camera pose. */
|
|
988
|
+
bodyName?: Bodies;
|
|
890
989
|
position?: CameraFrameCaptureVector3;
|
|
891
990
|
lookAt?: CameraFrameCaptureVector3;
|
|
892
991
|
quaternion?: CameraFrameCaptureQuaternion;
|
|
@@ -898,7 +997,25 @@ interface CameraFrameCaptureOptions {
|
|
|
898
997
|
fov?: number;
|
|
899
998
|
near?: number;
|
|
900
999
|
far?: number;
|
|
901
|
-
|
|
1000
|
+
/** Provenance for the camera pose used by the capture. Usually set by the MuJoCo provider. */
|
|
1001
|
+
source?: CameraFrameCaptureSource;
|
|
1002
|
+
}
|
|
1003
|
+
type CameraFrameCaptureSource = {
|
|
1004
|
+
kind: 'mujoco-camera';
|
|
1005
|
+
cameraName: Cameras;
|
|
1006
|
+
} | {
|
|
1007
|
+
kind: 'mujoco-site';
|
|
1008
|
+
siteName: Sites;
|
|
1009
|
+
} | {
|
|
1010
|
+
kind: 'mujoco-body';
|
|
1011
|
+
bodyName: Bodies;
|
|
1012
|
+
} | {
|
|
1013
|
+
kind: 'custom-camera';
|
|
1014
|
+
} | {
|
|
1015
|
+
kind: 'explicit-pose';
|
|
1016
|
+
} | {
|
|
1017
|
+
kind: 'fallback-camera';
|
|
1018
|
+
};
|
|
902
1019
|
interface CameraFrameCaptureResult {
|
|
903
1020
|
canvas: HTMLCanvasElement;
|
|
904
1021
|
camera: THREE.Camera;
|
|
@@ -906,6 +1023,7 @@ interface CameraFrameCaptureResult {
|
|
|
906
1023
|
type: string;
|
|
907
1024
|
width: number;
|
|
908
1025
|
height: number;
|
|
1026
|
+
source: CameraFrameCaptureSource;
|
|
909
1027
|
}
|
|
910
1028
|
interface CameraFrameCaptureBlobResult {
|
|
911
1029
|
canvas: HTMLCanvasElement;
|
|
@@ -914,6 +1032,7 @@ interface CameraFrameCaptureBlobResult {
|
|
|
914
1032
|
type: string;
|
|
915
1033
|
width: number;
|
|
916
1034
|
height: number;
|
|
1035
|
+
source: CameraFrameCaptureSource;
|
|
917
1036
|
}
|
|
918
1037
|
interface CameraFrameCaptureAPI {
|
|
919
1038
|
status: FrameCaptureStatus;
|
|
@@ -931,17 +1050,53 @@ interface CameraFrameSequenceFrame {
|
|
|
931
1050
|
time: number;
|
|
932
1051
|
cameras: Record<string, CameraFrameCaptureResult>;
|
|
933
1052
|
}
|
|
1053
|
+
interface CameraFrameSequenceCameraSummary {
|
|
1054
|
+
key: string;
|
|
1055
|
+
width: number;
|
|
1056
|
+
height: number;
|
|
1057
|
+
source: CameraFrameCaptureSource;
|
|
1058
|
+
frameCount: number;
|
|
1059
|
+
firstFrameIndex: number | null;
|
|
1060
|
+
lastFrameIndex: number | null;
|
|
1061
|
+
firstTimestamp: number | null;
|
|
1062
|
+
lastTimestamp: number | null;
|
|
1063
|
+
}
|
|
1064
|
+
interface CameraFrameSequenceSampleInput extends PhysicsStepInput {
|
|
1065
|
+
frameIndex: number;
|
|
1066
|
+
time: number;
|
|
1067
|
+
}
|
|
1068
|
+
interface CameraFrameSequenceStepInput extends PhysicsStepInput {
|
|
1069
|
+
frameIndex: number;
|
|
1070
|
+
stepIndex: number;
|
|
1071
|
+
time: number;
|
|
1072
|
+
}
|
|
934
1073
|
interface CameraFrameSequenceOptions {
|
|
935
1074
|
cameras: readonly CameraFrameSequenceCamera[];
|
|
936
1075
|
frames: number;
|
|
1076
|
+
/** Number of MuJoCo steps between captured frames. Use 0 for static camera provenance captures. */
|
|
937
1077
|
stepsPerFrame?: number;
|
|
938
1078
|
reset?: boolean;
|
|
939
1079
|
captureInitialFrame?: boolean;
|
|
1080
|
+
retainFrames?: boolean;
|
|
1081
|
+
/**
|
|
1082
|
+
* Require each recorded stream to resolve from exactly one mounted MuJoCo
|
|
1083
|
+
* camera/site/body selector. Defaults to true because sequence recording is
|
|
1084
|
+
* intended for dataset/policy camera streams.
|
|
1085
|
+
*/
|
|
1086
|
+
requireMountedSources?: boolean;
|
|
1087
|
+
signal?: AbortSignal;
|
|
1088
|
+
/** Called after stepping and before image capture for this frame. Use this to record synchronized state/action rows. */
|
|
1089
|
+
onSample?: (input: CameraFrameSequenceSampleInput) => void | Promise<void>;
|
|
1090
|
+
/** Called before each MuJoCo step inside sequence recording. Use this to apply policy/control actions. */
|
|
1091
|
+
onBeforeStep?: (input: CameraFrameSequenceStepInput) => void | Promise<void>;
|
|
1092
|
+
/** Called after each MuJoCo step inside sequence recording. Use this for step-level telemetry. */
|
|
1093
|
+
onAfterStep?: (input: CameraFrameSequenceStepInput) => void | Promise<void>;
|
|
940
1094
|
onFrame?: (frame: CameraFrameSequenceFrame) => void | Promise<void>;
|
|
941
1095
|
}
|
|
942
1096
|
interface CameraFrameSequenceResult {
|
|
943
1097
|
frames: CameraFrameSequenceFrame[];
|
|
944
1098
|
cameraKeys: string[];
|
|
1099
|
+
cameraSummaries: Record<string, CameraFrameSequenceCameraSummary>;
|
|
945
1100
|
frameCount: number;
|
|
946
1101
|
}
|
|
947
1102
|
interface CameraFrameSequenceRecorderAPI {
|
|
@@ -1009,4 +1164,4 @@ interface JointStateResult {
|
|
|
1009
1164
|
velocity: React__default.RefObject<number | Float64Array>;
|
|
1010
1165
|
}
|
|
1011
1166
|
|
|
1012
|
-
export { type
|
|
1167
|
+
export { type Bodies as $, type ActuatedJointInfo as A, type BodyProps as B, type ControlGroupInfo as C, type DragInteractionProps as D, type ScenarioLightingPreset as E, type SplatEnvironmentMetadataInput as F, type SplatEnvironmentMetadata as G, type SplatSceneInput as H, type IkConfig as I, type DebugProps as J, type GeomInfo as K, type ContactListenerProps as L, type MujocoContextValue as M, type ActuatorInfo as N, type ObservationConfig as O, type PhysicsStepCallback as P, type Sites as Q, type ReadyCallbackInput as R, type SceneConfig as S, type TrajectoryPlayerProps as T, type SitePositionResult as U, type VisualScenarioEffectsProps as V, type Sensors as W, type SensorHandle as X, type SensorInfo as Y, type Joints as Z, type JointStateResult as _, type MujocoCanvasProps as a, RobotActuators as a$, type BodyStateResult as a0, type Actuators as a1, type CtrlHandle as a2, type ContactInfo as a3, type KeyboardTeleopConfig as a4, type PolicyConfig as a5, type PolicyVector as a6, type ObservationHandle as a7, type TrajectoryInput as a8, type TrajectoryStateChangeInput as a9, type FrameCaptureTarget as aA, type FrameCaptureTargetRef as aB, type Geoms as aC, type IKSolveFn as aD, type IkGizmoDragInput as aE, type IkSolveInput as aF, type JointInfo as aG, type KeyBinding as aH, type Keyframes as aI, type ModelOptions as aJ, type MujocoContact as aK, type MujocoContactArray as aL, type MujocoFrameCaptureOptions as aM, type ObservationLayoutItem as aN, type ObservationOutput as aO, type PhysicsConfig as aP, type PhysicsStepInput as aQ, type PolicyActionInput as aR, type PolicyInferenceInput as aS, type PolicyObservationInput as aT, type RayHit as aU, type Register as aV, type RegisteredRobotMap as aW, type ResetCallbackInput as aX, type ResolvedScenarioCameraConfig as aY, type ResolvedScenarioMaterialConfig as aZ, type ResourceSelector as a_, type PlaybackState as aa, type TrajectoryFrame as ab, type FrameCaptureOptions as ac, type FrameCaptureResult as ad, type FrameCaptureBlobResult as ae, type FrameCaptureAPI as af, type CameraFrameCaptureOptions as ag, type CameraFrameCaptureAPI as ah, type CameraFrameSequenceRecorderAPI as ai, type Cameras as aj, type CameraFrameSequenceCamera as ak, type CameraFrameCaptureSource as al, type CameraFrameSequenceOptions as am, type CameraFrameSequenceResult as an, type CameraFrameCaptureResult as ao, type CameraFrameCaptureBlobResult as ap, type BodyInfo as aq, type CameraFrameCaptureQuaternion as ar, type CameraFrameCaptureVector3 as as, type CameraFrameSequenceCameraSummary as at, type CameraFrameSequenceFrame as au, type CameraFrameSequenceSampleInput as av, type CameraFrameSequenceStepInput as aw, type CameraInfo as ax, type ControlJointInfo as ay, type FrameCaptureStatus as az, type MujocoSimAPI as b, RobotBodies as b0, RobotCameras as b1, RobotGeoms as b2, RobotJoints as b3, RobotKeyframes as b4, type RobotResource as b5, RobotResources as b6, RobotSensors as b7, RobotSites as b8, type Robots as b9, type ScenarioCameraConfig as ba, type ScenarioMaterialConfig as bb, type SceneMarker as bc, type SceneObject as bd, type SensorResult as be, type SiteInfo as bf, type SplatAssetConfig as bg, type SplatScenarioConfig as bh, type StateSnapshot as bi, type TrajectoryData as bj, type TrajectoryFrameCallbackInput as bk, type VisualScenarioMaterialFilterInput as bl, type XmlPatch as bm, getContact as bn, registerRobotResources as bo, 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 SplatSceneConfigInput as w, type SplatSceneConfigState as x, type VisualScenarioExecutionContextInput as y, type VisualScenarioExecutionContext 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) {
|
|
@@ -91,7 +92,7 @@ async function generateMujocoRegister(options) {
|
|
|
91
92
|
};
|
|
92
93
|
}
|
|
93
94
|
async function scanModel(filePath, root, seen, names) {
|
|
94
|
-
const normalized = path.
|
|
95
|
+
const normalized = path.resolve(filePath);
|
|
95
96
|
if (seen.has(normalized)) return;
|
|
96
97
|
seen.add(normalized);
|
|
97
98
|
const xml = await readFile(normalized, "utf8");
|
|
@@ -99,12 +100,13 @@ 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);
|
|
105
107
|
for (const includePath of collectIncludePaths(xml)) {
|
|
106
108
|
const next = path.resolve(path.dirname(normalized), includePath);
|
|
107
|
-
if (next
|
|
109
|
+
if (isPathInsideRoot(next, root)) await scanModel(next, root, seen, names);
|
|
108
110
|
}
|
|
109
111
|
}
|
|
110
112
|
function collectSimpleTagNames(xml, tag, target) {
|
|
@@ -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}'>;`);
|
|
@@ -251,7 +254,7 @@ function shouldInjectRegisterImport(id, root, generatedRegister) {
|
|
|
251
254
|
if (file.includes(`${path.sep}node_modules${path.sep}`)) return false;
|
|
252
255
|
const absolute = path.resolve(file);
|
|
253
256
|
if (absolute === generatedRegister) return false;
|
|
254
|
-
return absolute
|
|
257
|
+
return isPathInsideRoot(absolute, root);
|
|
255
258
|
}
|
|
256
259
|
function renderGeneratedImport(id, generatedRegister) {
|
|
257
260
|
const fromDir = path.dirname(stripQuery(id));
|
|
@@ -292,7 +295,11 @@ function shouldRegenerate(file, watchedFiles, models, root) {
|
|
|
292
295
|
if (watchedFiles.includes(absolute)) return true;
|
|
293
296
|
if (!MODEL_EXTENSIONS.has(path.extname(absolute).toLowerCase())) return false;
|
|
294
297
|
const modelDirs = models.map((model) => path.dirname(path.resolve(root, model.file)));
|
|
295
|
-
return modelDirs.some((dir) => absolute
|
|
298
|
+
return modelDirs.some((dir) => isPathInsideRoot(absolute, dir));
|
|
299
|
+
}
|
|
300
|
+
function isPathInsideRoot(filePath, root) {
|
|
301
|
+
const relative = path.relative(path.resolve(root), path.resolve(filePath));
|
|
302
|
+
return relative === "" || relative !== "" && !relative.startsWith("..") && !path.isAbsolute(relative);
|
|
296
303
|
}
|
|
297
304
|
/**
|
|
298
305
|
* @license
|