mujoco-react 12.1.1 → 12.2.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 +200 -180
- package/dist/{chunk-XD3AY7XZ.js → chunk-SP72GTOD.js} +192 -92
- package/dist/chunk-SP72GTOD.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +25 -3
- package/dist/index.js.map +1 -1
- package/dist/onnx.d.ts +1 -1
- package/dist/spark.d.ts +1 -1
- package/dist/spark.js +25 -16
- package/dist/spark.js.map +1 -1
- package/dist/{types-CSi3fIVs.d.ts → types-CF-BZXtW.d.ts} +32 -1
- package/package.json +2 -2
- package/src/core/MujocoSimProvider.tsx +9 -1
- package/src/hooks/useCameraFrameCapture.ts +17 -0
- package/src/hooks/useCameraStream.ts +1 -1
- package/src/index.ts +2 -0
- package/src/rendering/cameraFrameCapture.ts +141 -68
- package/src/rendering/metricDepth.ts +56 -0
- package/src/spark.tsx +24 -15
- package/src/types.ts +9 -0
- package/dist/chunk-XD3AY7XZ.js.map +0 -1
package/dist/onnx.d.ts
CHANGED
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 { S as SplatEnvironmentProps, a as PairedSplatEnvironmentConfig, b as SceneConfig, c as SplatEnvironmentReadiness, V as VisualScenarioConfig } from './types-
|
|
3
|
+
import { S as SplatEnvironmentProps, a as PairedSplatEnvironmentConfig, b as SceneConfig, c as SplatEnvironmentReadiness, V as VisualScenarioConfig } from './types-CF-BZXtW.js';
|
|
4
4
|
import 'react';
|
|
5
5
|
import '@react-three/fiber';
|
|
6
6
|
import 'three';
|
package/dist/spark.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useSplatSceneConfig, useSplatEnvironment, SplatEnvironment, CAMERA_FRAME_CAPTURE_RENDER_USER_DATA_KEY } from './chunk-
|
|
1
|
+
import { useSplatSceneConfig, useSplatEnvironment, SplatEnvironment, CAMERA_FRAME_CAPTURE_RENDER_USER_DATA_KEY } from './chunk-SP72GTOD.js';
|
|
2
2
|
import { useThree } from '@react-three/fiber';
|
|
3
3
|
import { useMemo, useState, useEffect, useCallback, useRef } from 'react';
|
|
4
4
|
import * as THREE from 'three';
|
|
@@ -182,7 +182,7 @@ function SparkSplatEnvironment({
|
|
|
182
182
|
}) {
|
|
183
183
|
const groupRef = useRef(null);
|
|
184
184
|
const sparkRef = useRef(null);
|
|
185
|
-
const captureSparkRef = useRef(
|
|
185
|
+
const captureSparkRef = useRef(/* @__PURE__ */ new Map());
|
|
186
186
|
const meshRef = useRef(null);
|
|
187
187
|
const hiddenMeshesRef = useRef([]);
|
|
188
188
|
const onStatusChangeRef = useRef(onStatusChange);
|
|
@@ -238,8 +238,10 @@ function SparkSplatEnvironment({
|
|
|
238
238
|
hiddenMeshesRef.current = [];
|
|
239
239
|
}
|
|
240
240
|
function disposeCaptureSpark() {
|
|
241
|
-
|
|
242
|
-
|
|
241
|
+
for (const capture of captureSparkRef.current.values()) {
|
|
242
|
+
safelyDisposeSparkResource(capture.renderer);
|
|
243
|
+
}
|
|
244
|
+
captureSparkRef.current.clear();
|
|
243
245
|
}
|
|
244
246
|
async function loadSplat() {
|
|
245
247
|
if (!metadata.src) {
|
|
@@ -264,21 +266,28 @@ function SparkSplatEnvironment({
|
|
|
264
266
|
...resolvedRenderTuning
|
|
265
267
|
});
|
|
266
268
|
spark.userData[CAMERA_FRAME_CAPTURE_RENDER_USER_DATA_KEY] = async ({
|
|
269
|
+
withCaptureState,
|
|
270
|
+
renderMode,
|
|
267
271
|
scene,
|
|
268
272
|
camera,
|
|
269
273
|
width,
|
|
270
274
|
height
|
|
271
275
|
}) => {
|
|
272
|
-
let captureSpark = captureSparkRef.current;
|
|
276
|
+
let captureSpark = captureSparkRef.current.get(renderMode);
|
|
273
277
|
if (!captureSpark || captureSpark.width !== width || captureSpark.height !== height) {
|
|
274
|
-
|
|
278
|
+
safelyDisposeSparkResource(captureSpark?.renderer);
|
|
275
279
|
captureSpark = {
|
|
276
280
|
renderer: new sparkModule.SparkRenderer({
|
|
277
281
|
renderer: gl,
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
+
// Preview uses Spark's change detection and background sorting;
|
|
283
|
+
// forced update() regenerates even an unchanged static scene.
|
|
284
|
+
autoUpdate: renderMode === "preview",
|
|
285
|
+
preUpdate: false,
|
|
286
|
+
...renderMode === "preview" ? resolvedRenderTuning : {
|
|
287
|
+
lodSplatScale: resolvedCaptureTuning.lodSplatScale,
|
|
288
|
+
lodRenderScale: resolvedCaptureTuning.lodRenderScale,
|
|
289
|
+
minSortIntervalMs: resolvedCaptureTuning.minSortIntervalMs
|
|
290
|
+
},
|
|
282
291
|
target: {
|
|
283
292
|
width,
|
|
284
293
|
height
|
|
@@ -287,7 +296,7 @@ function SparkSplatEnvironment({
|
|
|
287
296
|
width,
|
|
288
297
|
height
|
|
289
298
|
};
|
|
290
|
-
captureSparkRef.current
|
|
299
|
+
captureSparkRef.current.set(renderMode, captureSpark);
|
|
291
300
|
}
|
|
292
301
|
const captureRenderer = captureSpark.renderer;
|
|
293
302
|
const maxWarmupFrames = Math.max(
|
|
@@ -297,11 +306,11 @@ function SparkSplatEnvironment({
|
|
|
297
306
|
let pixels;
|
|
298
307
|
for (let attempt = 0; attempt < maxWarmupFrames; attempt += 1) {
|
|
299
308
|
captureRenderer.renderSize.set(width, height);
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
309
|
+
if (renderMode === "snapshot") {
|
|
310
|
+
await captureRenderer.update({ scene, camera });
|
|
311
|
+
}
|
|
312
|
+
withCaptureState(() => captureRenderer.renderTarget({ scene, camera }));
|
|
313
|
+
pixels = await captureRenderer.readTarget();
|
|
305
314
|
if (captureRenderer.activeSplats > 0 && !isMostlyBlankCapture(pixels, resolvedCaptureTuning)) {
|
|
306
315
|
break;
|
|
307
316
|
}
|
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 useSplatSceneConfig,\n} from './components/VisualScenario';\nimport {\n CAMERA_FRAME_CAPTURE_RENDER_USER_DATA_KEY,\n} from './rendering/cameraFrameCapture';\nimport type {\n CameraFrameCaptureRenderInput,\n CameraFrameCaptureRenderResult,\n} from './rendering/cameraFrameCapture';\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 SparkCaptureRenderer = {\n renderer: SparkRendererInstance;\n width: number;\n height: number;\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 SparkSplatRenderTuning {\n /** Scale Spark's LoD splat budget for the live viewport. */\n lodSplatScale?: number;\n /** Minimum rendered LoD splat size. Higher values trade detail for speed. */\n lodRenderScale?: number;\n /** Minimum delay between Spark sort passes for the live viewport. */\n minSortIntervalMs?: number;\n}\n\nexport interface SparkSplatCaptureTuning extends SparkSplatRenderTuning {\n /** Maximum animation frames to wait for first-capture Spark warm-up. Default: 4. */\n maxWarmupFrames?: number;\n /** Number of pixels sampled when deciding whether a capture is blank. Default: 512. */\n blankSampleCount?: number;\n /** Alpha threshold used by the blank-capture detector. Default: 8. */\n blankAlphaThreshold?: number;\n /** Minimum visible sampled-pixel ratio before retrying capture. Default: 0.02. */\n blankVisibleRatio?: number;\n /** Minimum average sampled RGB sum before retrying capture. Default: 3. */\n blankAverageColor?: number;\n}\n\ntype ResolvedSparkSplatCaptureTuning = Required<\n Pick<\n SparkSplatCaptureTuning,\n | 'maxWarmupFrames'\n | 'blankSampleCount'\n | 'blankAlphaThreshold'\n | 'blankVisibleRatio'\n | 'blankAverageColor'\n >\n> &\n SparkSplatRenderTuning;\n\nfunction getDefaultLiveRenderTuning(\n lod: SparkSplatEnvironmentProps['lod']\n): SparkSplatRenderTuning {\n return {\n lodSplatScale: lod === false ? undefined : lod === 'quality' ? 1 : 0.6,\n lodRenderScale: lod === false || lod === 'quality' ? undefined : 1.2,\n minSortIntervalMs: lod === false ? 0 : lod === 'quality' ? 32 : 80,\n };\n}\n\nfunction getDefaultCaptureTuning(\n lod: SparkSplatEnvironmentProps['lod']\n): ResolvedSparkSplatCaptureTuning {\n return {\n lodSplatScale: lod === false ? undefined : lod === 'quality' ? 1.25 : 1.15,\n lodRenderScale: lod === false ? undefined : 0.6,\n minSortIntervalMs: 0,\n maxWarmupFrames: 4,\n blankSampleCount: 512,\n blankAlphaThreshold: 8,\n blankVisibleRatio: 0.02,\n blankAverageColor: 3,\n };\n}\n\nfunction resolveRenderTuning(\n defaults: SparkSplatRenderTuning,\n tuning: SparkSplatRenderTuning | undefined\n): SparkSplatRenderTuning {\n return {\n lodSplatScale: tuning?.lodSplatScale ?? defaults.lodSplatScale,\n lodRenderScale: tuning?.lodRenderScale ?? defaults.lodRenderScale,\n minSortIntervalMs: tuning?.minSortIntervalMs ?? defaults.minSortIntervalMs,\n };\n}\n\nfunction resolveCaptureTuning(\n lod: SparkSplatEnvironmentProps['lod'],\n tuning: SparkSplatCaptureTuning | undefined\n): ResolvedSparkSplatCaptureTuning {\n const defaults = getDefaultCaptureTuning(lod);\n return {\n ...resolveRenderTuning(defaults, tuning),\n maxWarmupFrames: tuning?.maxWarmupFrames ?? defaults.maxWarmupFrames,\n blankSampleCount: tuning?.blankSampleCount ?? defaults.blankSampleCount,\n blankAlphaThreshold:\n tuning?.blankAlphaThreshold ?? defaults.blankAlphaThreshold,\n blankVisibleRatio: tuning?.blankVisibleRatio ?? defaults.blankVisibleRatio,\n blankAverageColor: tuning?.blankAverageColor ?? defaults.blankAverageColor,\n };\n}\n\nfunction waitForNextAnimationFrame() {\n return new Promise<void>((resolve) => {\n requestAnimationFrame(() => resolve());\n });\n}\n\nfunction isMostlyBlankCapture(\n pixels: Uint8Array,\n tuning: ResolvedSparkSplatCaptureTuning\n) {\n const sampleCount = Math.max(1, Math.floor(tuning.blankSampleCount));\n const stride = Math.max(4, Math.floor(pixels.length / sampleCount / 4) * 4);\n let sampled = 0;\n let visible = 0;\n let colorTotal = 0;\n\n for (let i = 0; i < pixels.length; i += stride) {\n const alpha = pixels[i + 3];\n const color = pixels[i] + pixels[i + 1] + pixels[i + 2];\n sampled += 1;\n if (alpha > tuning.blankAlphaThreshold) visible += 1;\n colorTotal += color;\n }\n\n if (sampled === 0) return true;\n return (\n visible / sampled < tuning.blankVisibleRatio ||\n colorTotal / sampled < tuning.blankAverageColor\n );\n}\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 /** Tune Spark's live viewport renderer. Defaults favor interactive FPS. */\n renderTuning?: SparkSplatRenderTuning;\n /** Tune Spark camera-frame capture. Defaults favor sharper snapshots. */\n captureTuning?: SparkSplatCaptureTuning;\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 renderTuning,\n captureTuning,\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 captureSparkRef = useRef<SparkCaptureRenderer | 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 onStatusChangeRef.current = onStatusChange;\n onLoadRef.current = onLoad;\n onErrorRef.current = onError;\n\n const metadata = useSplatEnvironment({\n environment,\n scenario,\n renderer,\n src,\n format,\n collisionProxy: collisionProxyMetadata,\n });\n const resolvedRenderTuning = useMemo(\n () => resolveRenderTuning(getDefaultLiveRenderTuning(lod), renderTuning),\n [\n lod,\n renderTuning?.lodRenderScale,\n renderTuning?.lodSplatScale,\n renderTuning?.minSortIntervalMs,\n ]\n );\n const resolvedCaptureTuning = useMemo(\n () => resolveCaptureTuning(lod, captureTuning),\n [\n captureTuning?.blankAlphaThreshold,\n captureTuning?.blankAverageColor,\n captureTuning?.blankSampleCount,\n captureTuning?.blankVisibleRatio,\n captureTuning?.lodRenderScale,\n captureTuning?.lodSplatScale,\n captureTuning?.maxWarmupFrames,\n captureTuning?.minSortIntervalMs,\n lod,\n ]\n );\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 function disposeCaptureSpark() {\n safelyDisposeSparkResource(captureSparkRef.current?.renderer);\n captureSparkRef.current = null;\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 ...resolvedRenderTuning,\n });\n spark.userData[CAMERA_FRAME_CAPTURE_RENDER_USER_DATA_KEY] = async ({\n scene,\n camera,\n width,\n height,\n }: CameraFrameCaptureRenderInput): Promise<CameraFrameCaptureRenderResult> => {\n let captureSpark = captureSparkRef.current;\n if (\n !captureSpark ||\n captureSpark.width !== width ||\n captureSpark.height !== height\n ) {\n disposeCaptureSpark();\n captureSpark = {\n renderer: new sparkModule.SparkRenderer({\n renderer: gl,\n autoUpdate: false,\n lodSplatScale: resolvedCaptureTuning.lodSplatScale,\n lodRenderScale: resolvedCaptureTuning.lodRenderScale,\n minSortIntervalMs: resolvedCaptureTuning.minSortIntervalMs,\n target: {\n width,\n height,\n },\n }),\n width,\n height,\n };\n captureSparkRef.current = captureSpark;\n }\n\n const captureRenderer = captureSpark.renderer;\n const maxWarmupFrames = Math.max(\n 1,\n Math.floor(resolvedCaptureTuning.maxWarmupFrames)\n );\n let pixels: Uint8Array | undefined;\n for (let attempt = 0; attempt < maxWarmupFrames; attempt += 1) {\n captureRenderer.renderSize.set(width, height);\n await captureRenderer.update({ scene, camera });\n pixels = await captureRenderer.renderReadTarget({\n scene,\n camera,\n });\n if (\n captureRenderer.activeSplats > 0 &&\n !isMostlyBlankCapture(pixels, resolvedCaptureTuning)\n ) {\n break;\n }\n if (attempt < maxWarmupFrames - 1) {\n await waitForNextAnimationFrame();\n }\n }\n if (!pixels) {\n throw new Error('Spark camera frame capture did not produce pixels.');\n }\n return { pixels, width, height, flipY: true };\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 disposeCaptureSpark();\n };\n }, [\n gl,\n hideGroundMeshes,\n invalidate,\n lod,\n metadata.format,\n metadata.src,\n resolvedCaptureTuning.blankAlphaThreshold,\n resolvedCaptureTuning.blankAverageColor,\n resolvedCaptureTuning.blankSampleCount,\n resolvedCaptureTuning.blankVisibleRatio,\n resolvedCaptureTuning.lodRenderScale,\n resolvedCaptureTuning.lodSplatScale,\n resolvedCaptureTuning.maxWarmupFrames,\n resolvedCaptureTuning.minSortIntervalMs,\n resolvedRenderTuning.lodRenderScale,\n resolvedRenderTuning.lodSplatScale,\n resolvedRenderTuning.minSortIntervalMs,\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(\n resource: SparkDisposable | null | undefined\n) {\n if (!resource) return;\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"]}
|
|
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 {\n CAMERA_FRAME_CAPTURE_RENDER_USER_DATA_KEY,\n} from './rendering/cameraFrameCapture';\nimport type {\n CameraFrameCaptureRenderInput,\n CameraFrameCaptureRenderResult,\n} from './rendering/cameraFrameCapture';\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 SparkCaptureRenderer = {\n renderer: SparkRendererInstance;\n width: number;\n height: number;\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 SparkSplatRenderTuning {\n /** Scale Spark's LoD splat budget for the live viewport. */\n lodSplatScale?: number;\n /** Minimum rendered LoD splat size. Higher values trade detail for speed. */\n lodRenderScale?: number;\n /** Minimum delay between Spark sort passes for the live viewport. */\n minSortIntervalMs?: number;\n}\n\nexport interface SparkSplatCaptureTuning extends SparkSplatRenderTuning {\n /** Maximum animation frames to wait for first-capture Spark warm-up. Default: 4. */\n maxWarmupFrames?: number;\n /** Number of pixels sampled when deciding whether a capture is blank. Default: 512. */\n blankSampleCount?: number;\n /** Alpha threshold used by the blank-capture detector. Default: 8. */\n blankAlphaThreshold?: number;\n /** Minimum visible sampled-pixel ratio before retrying capture. Default: 0.02. */\n blankVisibleRatio?: number;\n /** Minimum average sampled RGB sum before retrying capture. Default: 3. */\n blankAverageColor?: number;\n}\n\ntype ResolvedSparkSplatCaptureTuning = Required<\n Pick<\n SparkSplatCaptureTuning,\n | 'maxWarmupFrames'\n | 'blankSampleCount'\n | 'blankAlphaThreshold'\n | 'blankVisibleRatio'\n | 'blankAverageColor'\n >\n> &\n SparkSplatRenderTuning;\n\nfunction getDefaultLiveRenderTuning(\n lod: SparkSplatEnvironmentProps['lod']\n): SparkSplatRenderTuning {\n return {\n lodSplatScale: lod === false ? undefined : lod === 'quality' ? 1 : 0.6,\n lodRenderScale: lod === false || lod === 'quality' ? undefined : 1.2,\n minSortIntervalMs: lod === false ? 0 : lod === 'quality' ? 32 : 80,\n };\n}\n\nfunction getDefaultCaptureTuning(\n lod: SparkSplatEnvironmentProps['lod']\n): ResolvedSparkSplatCaptureTuning {\n return {\n lodSplatScale: lod === false ? undefined : lod === 'quality' ? 1.25 : 1.15,\n lodRenderScale: lod === false ? undefined : 0.6,\n minSortIntervalMs: 0,\n maxWarmupFrames: 4,\n blankSampleCount: 512,\n blankAlphaThreshold: 8,\n blankVisibleRatio: 0.02,\n blankAverageColor: 3,\n };\n}\n\nfunction resolveRenderTuning(\n defaults: SparkSplatRenderTuning,\n tuning: SparkSplatRenderTuning | undefined\n): SparkSplatRenderTuning {\n return {\n lodSplatScale: tuning?.lodSplatScale ?? defaults.lodSplatScale,\n lodRenderScale: tuning?.lodRenderScale ?? defaults.lodRenderScale,\n minSortIntervalMs: tuning?.minSortIntervalMs ?? defaults.minSortIntervalMs,\n };\n}\n\nfunction resolveCaptureTuning(\n lod: SparkSplatEnvironmentProps['lod'],\n tuning: SparkSplatCaptureTuning | undefined\n): ResolvedSparkSplatCaptureTuning {\n const defaults = getDefaultCaptureTuning(lod);\n return {\n ...resolveRenderTuning(defaults, tuning),\n maxWarmupFrames: tuning?.maxWarmupFrames ?? defaults.maxWarmupFrames,\n blankSampleCount: tuning?.blankSampleCount ?? defaults.blankSampleCount,\n blankAlphaThreshold:\n tuning?.blankAlphaThreshold ?? defaults.blankAlphaThreshold,\n blankVisibleRatio: tuning?.blankVisibleRatio ?? defaults.blankVisibleRatio,\n blankAverageColor: tuning?.blankAverageColor ?? defaults.blankAverageColor,\n };\n}\n\nfunction waitForNextAnimationFrame() {\n return new Promise<void>((resolve) => {\n requestAnimationFrame(() => resolve());\n });\n}\n\nfunction isMostlyBlankCapture(\n pixels: Uint8Array,\n tuning: ResolvedSparkSplatCaptureTuning\n) {\n const sampleCount = Math.max(1, Math.floor(tuning.blankSampleCount));\n const stride = Math.max(4, Math.floor(pixels.length / sampleCount / 4) * 4);\n let sampled = 0;\n let visible = 0;\n let colorTotal = 0;\n\n for (let i = 0; i < pixels.length; i += stride) {\n const alpha = pixels[i + 3];\n const color = pixels[i] + pixels[i + 1] + pixels[i + 2];\n sampled += 1;\n if (alpha > tuning.blankAlphaThreshold) visible += 1;\n colorTotal += color;\n }\n\n if (sampled === 0) return true;\n return (\n visible / sampled < tuning.blankVisibleRatio ||\n colorTotal / sampled < tuning.blankAverageColor\n );\n}\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 /** Tune Spark's live viewport renderer. Defaults favor interactive FPS. */\n renderTuning?: SparkSplatRenderTuning;\n /** Tune Spark camera-frame capture. Defaults favor sharper snapshots. */\n captureTuning?: SparkSplatCaptureTuning;\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 renderTuning,\n captureTuning,\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 captureSparkRef = useRef(new Map<'snapshot' | 'preview', SparkCaptureRenderer>());\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 onStatusChangeRef.current = onStatusChange;\n onLoadRef.current = onLoad;\n onErrorRef.current = onError;\n\n const metadata = useSplatEnvironment({\n environment,\n scenario,\n renderer,\n src,\n format,\n collisionProxy: collisionProxyMetadata,\n });\n const resolvedRenderTuning = useMemo(\n () => resolveRenderTuning(getDefaultLiveRenderTuning(lod), renderTuning),\n [\n lod,\n renderTuning?.lodRenderScale,\n renderTuning?.lodSplatScale,\n renderTuning?.minSortIntervalMs,\n ]\n );\n const resolvedCaptureTuning = useMemo(\n () => resolveCaptureTuning(lod, captureTuning),\n [\n captureTuning?.blankAlphaThreshold,\n captureTuning?.blankAverageColor,\n captureTuning?.blankSampleCount,\n captureTuning?.blankVisibleRatio,\n captureTuning?.lodRenderScale,\n captureTuning?.lodSplatScale,\n captureTuning?.maxWarmupFrames,\n captureTuning?.minSortIntervalMs,\n lod,\n ]\n );\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 function disposeCaptureSpark() {\n for (const capture of captureSparkRef.current.values()) {\n safelyDisposeSparkResource(capture.renderer);\n }\n captureSparkRef.current.clear();\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 ...resolvedRenderTuning,\n });\n spark.userData[CAMERA_FRAME_CAPTURE_RENDER_USER_DATA_KEY] = async ({\n withCaptureState,\n renderMode,\n scene,\n camera,\n width,\n height,\n }: CameraFrameCaptureRenderInput): Promise<CameraFrameCaptureRenderResult> => {\n let captureSpark = captureSparkRef.current.get(renderMode);\n if (\n !captureSpark ||\n captureSpark.width !== width ||\n captureSpark.height !== height\n ) {\n safelyDisposeSparkResource(captureSpark?.renderer);\n captureSpark = {\n renderer: new sparkModule.SparkRenderer({\n renderer: gl,\n // Preview uses Spark's change detection and background sorting;\n // forced update() regenerates even an unchanged static scene.\n autoUpdate: renderMode === 'preview',\n preUpdate: false,\n ...(renderMode === 'preview' ? resolvedRenderTuning : {\n lodSplatScale: resolvedCaptureTuning.lodSplatScale,\n lodRenderScale: resolvedCaptureTuning.lodRenderScale,\n minSortIntervalMs: resolvedCaptureTuning.minSortIntervalMs,\n }),\n target: {\n width,\n height,\n },\n }),\n width,\n height,\n };\n captureSparkRef.current.set(renderMode, captureSpark);\n }\n\n const captureRenderer = captureSpark.renderer;\n const maxWarmupFrames = Math.max(\n 1,\n Math.floor(resolvedCaptureTuning.maxWarmupFrames)\n );\n let pixels: Uint8Array | undefined;\n for (let attempt = 0; attempt < maxWarmupFrames; attempt += 1) {\n captureRenderer.renderSize.set(width, height);\n if (renderMode === 'snapshot') {\n await captureRenderer.update({ scene, camera });\n }\n withCaptureState(() => captureRenderer.renderTarget({ scene, camera }));\n pixels = await captureRenderer.readTarget();\n if (\n captureRenderer.activeSplats > 0 &&\n !isMostlyBlankCapture(pixels, resolvedCaptureTuning)\n ) {\n break;\n }\n if (attempt < maxWarmupFrames - 1) {\n await waitForNextAnimationFrame();\n }\n }\n if (!pixels) {\n throw new Error('Spark camera frame capture did not produce pixels.');\n }\n return { pixels, width, height, flipY: true };\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 disposeCaptureSpark();\n };\n }, [\n gl,\n hideGroundMeshes,\n invalidate,\n lod,\n metadata.format,\n metadata.src,\n resolvedCaptureTuning.blankAlphaThreshold,\n resolvedCaptureTuning.blankAverageColor,\n resolvedCaptureTuning.blankSampleCount,\n resolvedCaptureTuning.blankVisibleRatio,\n resolvedCaptureTuning.lodRenderScale,\n resolvedCaptureTuning.lodSplatScale,\n resolvedCaptureTuning.maxWarmupFrames,\n resolvedCaptureTuning.minSortIntervalMs,\n resolvedRenderTuning.lodRenderScale,\n resolvedRenderTuning.lodSplatScale,\n resolvedRenderTuning.minSortIntervalMs,\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(\n resource: SparkDisposable | null | undefined\n) {\n if (!resource) return;\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"]}
|
|
@@ -124,6 +124,25 @@ interface CameraFramePixelsResult {
|
|
|
124
124
|
height: number;
|
|
125
125
|
source: CameraFrameCaptureSource;
|
|
126
126
|
}
|
|
127
|
+
/** An owned, aligned RGB-D observation from one render. Scene units must be meters. */
|
|
128
|
+
interface CameraRGBDResult {
|
|
129
|
+
/** Interleaved sRGB bytes (RGB), row-major, top-left origin. */
|
|
130
|
+
rgb: Uint8Array;
|
|
131
|
+
/** Positive camera-axis distance (-view Z) in meters, not Euclidean range.
|
|
132
|
+
* Background / no depth-writing surface is +Infinity. Same pixel order as rgb. */
|
|
133
|
+
depth: Float32Array;
|
|
134
|
+
width: number;
|
|
135
|
+
height: number;
|
|
136
|
+
source: CameraFrameCaptureSource;
|
|
137
|
+
origin: 'top-left';
|
|
138
|
+
depthUnits: 'meters';
|
|
139
|
+
depthConvention: 'camera-z';
|
|
140
|
+
/** Horizontal mirroring applied to both arrays. Undo before unprojecting. */
|
|
141
|
+
flipX: boolean;
|
|
142
|
+
/** Owned column-major matrices. Camera coordinates: +X right, +Y up, -Z forward. */
|
|
143
|
+
projectionMatrix: number[];
|
|
144
|
+
cameraWorldMatrix: number[];
|
|
145
|
+
}
|
|
127
146
|
interface CameraFrameTensorResult extends PolicyImageTensorResult {
|
|
128
147
|
camera: THREE.Camera;
|
|
129
148
|
source: CameraFrameCaptureSource;
|
|
@@ -156,6 +175,8 @@ interface CameraFrameCaptureSession {
|
|
|
156
175
|
capturePixels(options?: CameraFrameCaptureOptions): CameraFramePixelsResult;
|
|
157
176
|
/** Render straight into a normalized policy image tensor (no canvas/PNG encode). */
|
|
158
177
|
captureTensor(options?: CameraFrameCaptureTensorOptions): CameraFrameTensorResult;
|
|
178
|
+
/** Synchronous RGB + metric depth from one render. Returned arrays are owned. */
|
|
179
|
+
captureRGBD(options?: CameraFrameCaptureOptions): CameraRGBDResult;
|
|
159
180
|
dispose(): void;
|
|
160
181
|
}
|
|
161
182
|
declare const CAMERA_FRAME_CAPTURE_RENDER_USER_DATA_KEY = "mujocoReactCameraFrameCaptureRender";
|
|
@@ -178,6 +199,8 @@ declare function captureCameraFrameBlob(renderer: THREE.WebGLRenderer, scene: TH
|
|
|
178
199
|
* `session.captureTensor()` so the render target and buffers are reused.
|
|
179
200
|
*/
|
|
180
201
|
declare function captureCameraFrameTensor(renderer: THREE.WebGLRenderer, scene: THREE.Scene, fallbackCamera: THREE.Camera, options?: CameraFrameCaptureTensorOptions): CameraFrameTensorResult;
|
|
202
|
+
/** One-shot aligned RGB-D observation. Use a session for repeated observations. */
|
|
203
|
+
declare function captureCameraRGBD(renderer: THREE.WebGLRenderer, scene: THREE.Scene, fallbackCamera: THREE.Camera, options?: CameraFrameCaptureOptions): CameraRGBDResult;
|
|
181
204
|
|
|
182
205
|
/**
|
|
183
206
|
* @license
|
|
@@ -1401,6 +1424,8 @@ interface MujocoSimAPI {
|
|
|
1401
1424
|
captureFrameBlob(options?: MujocoFrameCaptureOptions): Promise<FrameCaptureBlobResult>;
|
|
1402
1425
|
captureCameraFrame(options?: CameraFrameCaptureOptions): Promise<CameraFrameCaptureResult>;
|
|
1403
1426
|
captureCameraFrameBlob(options?: CameraFrameCaptureOptions): Promise<CameraFrameCaptureBlobResult>;
|
|
1427
|
+
/** Aligned sRGB + camera-axis depth in meters from one render. */
|
|
1428
|
+
captureCameraRGBD(options?: CameraFrameCaptureOptions): CameraRGBDResult;
|
|
1404
1429
|
/** Capture a camera frame straight into a policy image tensor (no canvas/PNG encode). */
|
|
1405
1430
|
captureCameraFrameTensor(options?: CameraFrameCaptureTensorOptions): CameraFrameTensorResult;
|
|
1406
1431
|
/**
|
|
@@ -1501,6 +1526,11 @@ interface CameraFrameRenderIsolationOptions {
|
|
|
1501
1526
|
cache?: boolean;
|
|
1502
1527
|
}
|
|
1503
1528
|
interface CameraFrameCaptureOptions {
|
|
1529
|
+
/** Snapshot (default) waits for splat preparation. Preview reuses the latest
|
|
1530
|
+
* sorted splats while updating in the background for responsive live motion.
|
|
1531
|
+
* useCameraStream defaults to preview; policy/dataset captures stay snapshot.
|
|
1532
|
+
*/
|
|
1533
|
+
renderMode?: 'snapshot' | 'preview';
|
|
1504
1534
|
/** Existing Three camera to clone before applying pose overrides. */
|
|
1505
1535
|
camera?: THREE.Camera;
|
|
1506
1536
|
/** Named MuJoCo `<camera>` to render from when available in the loaded model. */
|
|
@@ -1616,6 +1646,7 @@ interface CameraFrameCaptureAPI {
|
|
|
1616
1646
|
isCapturing: boolean;
|
|
1617
1647
|
capture: (options?: CameraFrameCaptureOptions) => Promise<CameraFrameCaptureResult>;
|
|
1618
1648
|
captureBlob: (options?: CameraFrameCaptureOptions) => Promise<CameraFrameCaptureBlobResult>;
|
|
1649
|
+
captureRGBD: (options?: CameraFrameCaptureOptions) => Promise<CameraRGBDResult>;
|
|
1619
1650
|
reset: () => void;
|
|
1620
1651
|
}
|
|
1621
1652
|
interface CameraFrameSequenceCamera extends CameraFrameCaptureOptions {
|
|
@@ -1782,4 +1813,4 @@ interface ArrayJointStateResult {
|
|
|
1782
1813
|
velocity: React__default.RefObject<Float64Array>;
|
|
1783
1814
|
}
|
|
1784
1815
|
|
|
1785
|
-
export { type SensorHandle as $, type ActuatedJointInfo as A, type BodyProps as B, type ControlGroupInfo as C, type DragInteractionProps as D, type SplatSceneConfigState as E, type VisualScenarioExecutionContextInput as F, type VisualScenarioExecutionContext as G, type ScenarioLightingPreset as H, type IkConfig as I, type SplatEnvironmentMetadataInput as J, type SplatEnvironmentMetadata as K, type SplatSceneInput as L, type MujocoContextValue as M, type CameraFrameCaptureOptions as N, type ObservationConfig as O, type PolicyActionChunk as P, type DebugProps as Q, type ReadyCallbackInput as R, type SplatEnvironmentProps as S, type GeomInfo as T, type ContactListenerProps as U, type VisualScenarioConfig as V, type TrajectoryPlayerProps as W, type ActuatorInfo as X, type Sites as Y, type SitePositionResult as Z, type Sensors as _, type PairedSplatEnvironmentConfig as a, type
|
|
1816
|
+
export { type SensorHandle as $, type ActuatedJointInfo as A, type BodyProps as B, type ControlGroupInfo as C, type DragInteractionProps as D, type SplatSceneConfigState as E, type VisualScenarioExecutionContextInput as F, type VisualScenarioExecutionContext as G, type ScenarioLightingPreset as H, type IkConfig as I, type SplatEnvironmentMetadataInput as J, type SplatEnvironmentMetadata as K, type SplatSceneInput as L, type MujocoContextValue as M, type CameraFrameCaptureOptions as N, type ObservationConfig as O, type PolicyActionChunk as P, type DebugProps as Q, type ReadyCallbackInput as R, type SplatEnvironmentProps as S, type GeomInfo as T, type ContactListenerProps as U, type VisualScenarioConfig as V, type TrajectoryPlayerProps as W, type ActuatorInfo as X, type Sites as Y, type SitePositionResult as Z, type Sensors as _, type PairedSplatEnvironmentConfig as a, type CameraRGBDResult as a$, type SensorInfo as a0, type Joints as a1, type ScalarJointStateResult as a2, type ArrayJointStateResult as a3, type JointStateOptions as a4, type JointStateResult as a5, type Bodies as a6, type BodyStateResult as a7, type Geoms as a8, type Actuators as a9, type PolicyCameraFrameCaptureResult as aA, type FrameCaptureStatus as aB, type PolicyCameraFrameCaptureAPI as aC, type CameraFrameCaptureTensorOptions as aD, type CameraFrameTensorResult as aE, type CameraFrameSequenceRecorderAPI as aF, type ImagePointCoordinateSpace as aG, type ImagePointProjectionOptions as aH, type ImagePointProjectionResult as aI, type PolicyVector as aJ, type ActuatorControlValue as aK, type AdvanceOptions as aL, type BodyInfo as aM, CAMERA_FRAME_CAPTURE_PRE_RENDER_USER_DATA_KEY as aN, CAMERA_FRAME_CAPTURE_RENDER_USER_DATA_KEY as aO, CAPTURE_EXCLUDE_KEY as aP, type CameraFrameCaptureBlobResult as aQ, type CameraFrameCaptureQuaternion as aR, type CameraFrameCaptureResult as aS, type CameraFrameCaptureSession as aT, type CameraFrameCaptureVector3 as aU, type CameraFramePixelsResult as aV, type CameraFrameSequenceCameraSummary as aW, type CameraFrameSequenceFrame as aX, type CameraFrameSequenceSampleInput as aY, type CameraFrameSequenceStepInput as aZ, type CameraInfo as a_, type CtrlHandle as aa, type ContactInfo as ab, type KeyboardTeleopConfig as ac, type KeyboardIkTargetConfig as ad, type PolicyConfig as ae, type PolicyAPI as af, type RemotePolicyConfig as ag, type RemotePolicyAPI as ah, type ObservationHandle as ai, type ObservationOutput as aj, type TrajectoryInput as ak, type TrajectoryStateChangeInput as al, type PlaybackState as am, type TrajectoryFrame as an, type FrameCaptureOptions as ao, type FrameCaptureResult as ap, type FrameCaptureBlobResult as aq, type FrameCaptureAPI as ar, type CameraFrameCaptureAPI as as, type Cameras as at, type CameraFrameSequenceCamera as au, type CameraFrameCaptureSource as av, type CameraFrameSequenceOptions as aw, type CameraFrameSequenceResult as ax, type PolicyCameraFrameStream as ay, type PolicyCameraFrameCaptureOptions as az, type SceneConfig as b, type SimulationRuntime as b$, type ControlJointInfo as b0, type DebugVirtualCamera as b1, type FrameCaptureTarget as b2, type FrameCaptureTargetRef as b3, type IKSolveFn as b4, type IkGizmoDragInput as b5, type IkSolveInput as b6, type JointInfo as b7, type JointStateKind as b8, type KeyBinding as b9, type PolicyImageTensorRange as bA, type PolicyImageTensorResult as bB, type PolicyImageTensorSourceOrigin as bC, type PolicyInferenceInput as bD, type PolicyInferenceOutput as bE, type PolicyInferenceResult as bF, type PolicyObservationInput as bG, type RayHit as bH, type Register as bI, type RegisteredModelMap as bJ, type RemotePolicyRequestInfo as bK, type RemotePolicyRequestInput as bL, type RemotePolicyResponseInfo as bM, type RemotePolicyStatus as bN, type ResetCallbackInput as bO, type ResolvedScenarioCameraConfig as bP, type ResolvedScenarioMaterialConfig as bQ, type ResourceSelector as bR, type RuntimeMetrics as bS, type RuntimeOptions as bT, type RuntimeSnapshot as bU, type RuntimeState as bV, type ScenarioCameraConfig as bW, type ScenarioMaterialConfig as bX, type SceneMarker as bY, type SceneObject as bZ, type SensorResult as b_, type KeyboardIkTargetAction as ba, type KeyboardIkTargetBinding as bb, type Keyframes as bc, ModelActuators as bd, ModelBodies as be, ModelCameras as bf, ModelGeoms as bg, ModelJoints as bh, ModelKeyframes as bi, type ModelOptions as bj, type ModelResource as bk, ModelResources as bl, ModelSensors as bm, ModelSites as bn, type Models as bo, type MujocoContact as bp, type MujocoContactArray as bq, type MujocoFrameCaptureOptions as br, type ObservationLayoutItem as bs, type PhysicsConfig as bt, type PhysicsPerformance as bu, type PhysicsStepInput as bv, type PolicyActionInput as bw, type PolicyImageTensorLayout as bx, type PolicyImageTensorOptions as by, type PolicyImageTensorPixelOptions as bz, type SplatEnvironmentReadiness as c, type SiteInfo as c0, type SplatAssetConfig as c1, type SplatScenarioConfig as c2, type StateSnapshot as c3, type TrajectoryData as c4, type TrajectoryFrameCallbackInput as c5, type VisualScenarioMaterialFilterInput as c6, type WorkerPort as c7, type XmlPatch as c8, captureCameraFrame as c9, captureCameraFrameBlob as ca, captureCameraFrameTensor as cb, captureCameraRGBD as cc, createCameraFrameCaptureSession as cd, dataUrlToPolicyImageTensor as ce, getContact as cf, imageDataToPolicyImageTensor as cg, pixelsToPolicyImageTensor as ch, registerModelResources as ci, renderCameraFrameToCanvas as cj, type MujocoCanvasProps as d, type MujocoSimAPI as e, type StepCallbackInput as f, type SelectionCallbackInput as g, type MujocoIntegrator as h, type MujocoModule as i, type MujocoRenderOptions as j, type PhysicsStepCallback as k, type MujocoModel as l, type MujocoData as m, type ControlGroupSelector as n, type ObservationResult as o, type IkContextValue as p, type IkGizmoProps as q, type SceneLightsProps as r, type ScenarioLightingProps as s, type VisualScenarioEffectsProps as t, type SplatRendererKind as u, type SplatFormat as v, type SplatCollisionProxyConfig as w, type SplatCollisionPrimitive as x, SplatEnvironmentReadinessStatus as y, type SplatSceneConfigInput as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mujoco-react",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.2.0",
|
|
4
4
|
"description": "Composable React Three Fiber building blocks for MuJoCo WASM simulations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"build": "tsup",
|
|
67
67
|
"dev": "tsup --watch",
|
|
68
68
|
"typecheck": "tsc --noEmit",
|
|
69
|
-
"test:runtime": "tsup --config tests/tsup.config.ts && node --test .test-dist/runtime.js .test-dist/simulation-runtime.js"
|
|
69
|
+
"test:runtime": "tsup --config tests/tsup.config.ts && node --test .test-dist/runtime.js .test-dist/simulation-runtime.js .test-dist/camera-capture.js"
|
|
70
70
|
},
|
|
71
71
|
"peerDependencies": {
|
|
72
72
|
"@react-three/drei": ">=9",
|
|
@@ -67,6 +67,7 @@ import {
|
|
|
67
67
|
import {
|
|
68
68
|
captureCameraFrame,
|
|
69
69
|
captureCameraFrameBlob,
|
|
70
|
+
captureCameraRGBD,
|
|
70
71
|
createCameraFrameCaptureSession,
|
|
71
72
|
type CameraFrameCaptureTensorOptions,
|
|
72
73
|
} from '../rendering/cameraFrameCapture';
|
|
@@ -1583,6 +1584,12 @@ export function MujocoSimProvider({
|
|
|
1583
1584
|
[camera, gl, resolveCameraCaptureOptions, scene]
|
|
1584
1585
|
);
|
|
1585
1586
|
|
|
1587
|
+
const captureCameraRGBDApi = useCallback(
|
|
1588
|
+
(options: CameraFrameCaptureOptions = {}) =>
|
|
1589
|
+
captureCameraRGBD(gl, scene, camera, resolveCameraCaptureOptions(options)),
|
|
1590
|
+
[camera, gl, resolveCameraCaptureOptions, scene]
|
|
1591
|
+
);
|
|
1592
|
+
|
|
1586
1593
|
const createCameraFrameCaptureSessionApi = useCallback(
|
|
1587
1594
|
(options: CameraFrameCaptureOptions = {}) =>
|
|
1588
1595
|
createCameraFrameCaptureSession(
|
|
@@ -1950,6 +1957,7 @@ export function MujocoSimProvider({
|
|
|
1950
1957
|
captureCameraFrame: captureCameraFrameApi,
|
|
1951
1958
|
captureCameraFrameBlob: captureCameraFrameBlobApi,
|
|
1952
1959
|
captureCameraFrameTensor: captureCameraFrameTensorApi,
|
|
1960
|
+
captureCameraRGBD: captureCameraRGBDApi,
|
|
1953
1961
|
createCameraFrameCaptureSession: createCameraFrameCaptureSessionApi,
|
|
1954
1962
|
resolveCameraCaptureOptions,
|
|
1955
1963
|
recordCameraSequence: recordCameraSequenceApi,
|
|
@@ -1973,7 +1981,7 @@ export function MujocoSimProvider({
|
|
|
1973
1981
|
loadFromFilesApi, addBodyApi, removeBodyApi, recompileApi,
|
|
1974
1982
|
getCanvas, getCanvasSnapshot, captureFrameApi, captureFrameBlobApi,
|
|
1975
1983
|
captureCameraFrameApi, captureCameraFrameBlobApi,
|
|
1976
|
-
captureCameraFrameTensorApi, createCameraFrameCaptureSessionApi,
|
|
1984
|
+
captureCameraFrameTensorApi, captureCameraRGBDApi, createCameraFrameCaptureSessionApi,
|
|
1977
1985
|
resolveCameraCaptureOptions,
|
|
1978
1986
|
recordCameraSequenceApi,
|
|
1979
1987
|
project2DTo3D,
|
|
@@ -83,12 +83,29 @@ export function useCameraFrameCapture(
|
|
|
83
83
|
[defaultOptions, mujoco.api]
|
|
84
84
|
);
|
|
85
85
|
|
|
86
|
+
async function captureRGBD(options: CameraFrameCaptureOptions = {}) {
|
|
87
|
+
setStatus('capturing');
|
|
88
|
+
setError(null);
|
|
89
|
+
try {
|
|
90
|
+
if (!mujoco.api) throw new Error('MuJoCo scene is not ready for camera frame capture.');
|
|
91
|
+
const result = mujoco.api.captureCameraRGBD({ ...defaultOptions, ...options });
|
|
92
|
+
setStatus('captured');
|
|
93
|
+
return result;
|
|
94
|
+
} catch (nextError) {
|
|
95
|
+
const error = nextError instanceof Error ? nextError : new Error('Unable to capture RGB-D.');
|
|
96
|
+
setError(error);
|
|
97
|
+
setStatus('error');
|
|
98
|
+
throw error;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
86
102
|
return {
|
|
87
103
|
status,
|
|
88
104
|
error,
|
|
89
105
|
isCapturing: status === 'capturing',
|
|
90
106
|
capture,
|
|
91
107
|
captureBlob,
|
|
108
|
+
captureRGBD,
|
|
92
109
|
reset,
|
|
93
110
|
};
|
|
94
111
|
}
|
|
@@ -88,7 +88,7 @@ export function useCameraStream(
|
|
|
88
88
|
|
|
89
89
|
inFlightRef.current = true;
|
|
90
90
|
session
|
|
91
|
-
.captureAsync(api.resolveCameraCaptureOptions(opts))
|
|
91
|
+
.captureAsync(api.resolveCameraCaptureOptions({ ...opts, renderMode: opts.renderMode ?? 'preview' }))
|
|
92
92
|
.then((frame) => {
|
|
93
93
|
const canvas = canvasRef.current;
|
|
94
94
|
if (!mountedRef.current || !canvas) return;
|
package/src/index.ts
CHANGED
|
@@ -172,6 +172,7 @@ export {
|
|
|
172
172
|
captureCameraFrame,
|
|
173
173
|
captureCameraFrameBlob,
|
|
174
174
|
captureCameraFrameTensor,
|
|
175
|
+
captureCameraRGBD,
|
|
175
176
|
createCameraFrameCaptureSession,
|
|
176
177
|
renderCameraFrameToCanvas,
|
|
177
178
|
} from './rendering/cameraFrameCapture';
|
|
@@ -179,6 +180,7 @@ export type {
|
|
|
179
180
|
CameraFrameCaptureSession,
|
|
180
181
|
CameraFrameCaptureTensorOptions,
|
|
181
182
|
CameraFramePixelsResult,
|
|
183
|
+
CameraRGBDResult,
|
|
182
184
|
CameraFrameTensorResult,
|
|
183
185
|
} from './rendering/cameraFrameCapture';
|
|
184
186
|
export {
|