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/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-C5gTvR7b.js';
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-33CV6HSV.js';
1
+ import { useSplatSceneConfig, useSplatEnvironment, SplatEnvironment } from './chunk-T3GVZJ4F.js';
2
2
  import { useThree } from '@react-three/fiber';
3
- import { useState, useEffect, useCallback, useMemo, useRef } from 'react';
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 PolicyConfig as $, type ActuatedJointInfo as A, type BodyProps as B, type ControlGroupInfo as C, type DragInteractionProps as D, type ActuatorInfo as E, type Sites as F, type GeomInfo as G, type SitePositionResult as H, type IkConfig as I, type Sensors as J, type SensorHandle as K, type SensorInfo as L, type MujocoContextValue as M, type Joints as N, type ObservationConfig as O, type PhysicsStepCallback as P, type JointStateResult as Q, type ReadyCallbackInput as R, type SceneConfig as S, type TrajectoryPlayerProps as T, type Bodies as U, type VisualScenarioEffectsProps as V, type BodyStateResult as W, type Actuators as X, type CtrlHandle as Y, type ContactInfo as Z, type KeyboardTeleopConfig as _, type MujocoCanvasProps as a, type PolicyVector as a0, type ObservationHandle as a1, type TrajectoryInput as a2, type TrajectoryStateChangeInput as a3, type PlaybackState as a4, type TrajectoryFrame as a5, type FrameCaptureOptions as a6, type FrameCaptureResult as a7, type FrameCaptureBlobResult as a8, type FrameCaptureAPI as a9, type ResetCallbackInput as aA, type ResourceSelector as aB, RobotActuators as aC, RobotBodies as aD, RobotGeoms as aE, RobotJoints as aF, RobotKeyframes as aG, type RobotResource as aH, RobotResources as aI, RobotSensors as aJ, RobotSites as aK, type Robots as aL, type ScenarioCameraConfig as aM, type ScenarioMaterialConfig as aN, type SceneMarker as aO, type SceneObject as aP, type SensorResult as aQ, type SiteInfo as aR, type SplatAssetConfig as aS, type SplatScenarioConfig as aT, type StateSnapshot as aU, type TrajectoryData as aV, type TrajectoryFrameCallbackInput as aW, type VisualScenarioMaterialFilterInput as aX, type XmlPatch as aY, getContact as aZ, registerRobotResources as a_, type BodyInfo as aa, type ControlJointInfo as ab, type FrameCaptureStatus as ac, type FrameCaptureTarget as ad, type FrameCaptureTargetRef as ae, type Geoms as af, type IKSolveFn as ag, type IkGizmoDragInput as ah, type IkSolveInput as ai, type JointInfo as aj, type KeyBinding as ak, type Keyframes as al, type ModelOptions as am, type MujocoContact as an, type MujocoContactArray as ao, type MujocoFrameCaptureOptions as ap, type ObservationLayoutItem as aq, type ObservationOutput as ar, type PhysicsConfig as as, type PhysicsStepInput as at, type PolicyActionInput as au, type PolicyInferenceInput as av, type PolicyObservationInput as aw, type RayHit as ax, type Register as ay, type RegisteredRobotMap as az, type MujocoSimAPI as b, type StepCallbackInput as c, type SelectionCallbackInput as d, type MujocoModule as e, type MujocoModel as f, type MujocoData as g, type ControlGroupSelector as h, type ObservationResult as i, type IkContextValue as j, type IkGizmoProps as k, type SceneLightsProps as l, type ScenarioLightingProps as m, type SplatEnvironmentProps as n, type VisualScenarioConfig as o, type SplatRendererKind as p, type PairedSplatEnvironmentConfig as q, type SplatFormat as r, type SplatCollisionProxyConfig as s, type SplatCollisionPrimitive as t, type ScenarioLightingPreset as u, type SplatEnvironmentMetadataInput as v, type SplatEnvironmentMetadata as w, type SplatSceneInput as x, type DebugProps as y, type ContactListenerProps as z };
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}'>;`);