mujoco-react 8.9.2 → 8.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,32 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as _sparkjsdev_spark from '@sparkjsdev/spark';
3
+ import { l as SplatEnvironmentProps } from './types-FFW7ykBu.js';
4
+ import 'react';
5
+ import '@react-three/fiber';
6
+ import 'three';
7
+
8
+ type SparkModule = typeof _sparkjsdev_spark;
9
+ type SparkSplatMeshInstance = InstanceType<SparkModule['SplatMesh']>;
10
+ type SparkSplatStatus = 'idle' | 'loading' | 'ready' | 'error';
11
+ interface SparkSplatEnvironmentProps extends SplatEnvironmentProps {
12
+ /** Enable Spark LoD handling for large splat assets. Default: true. */
13
+ lod?: boolean | 'quality';
14
+ /**
15
+ * Hide meshes whose names include floor, ground, or plane while the splat is
16
+ * active. This mirrors the common hybrid-rendering setup where MJCF keeps
17
+ * collision geometry but the splat owns the visual environment.
18
+ */
19
+ hideGroundMeshes?: boolean;
20
+ onStatusChange?: (status: SparkSplatStatus) => void;
21
+ onLoad?: (mesh: SparkSplatMeshInstance) => void;
22
+ onError?: (error: Error) => void;
23
+ }
24
+ /**
25
+ * Optional SparkJS-backed Gaussian splat renderer for React Three Fiber scenes.
26
+ *
27
+ * Import from `mujoco-react/spark` and install `@sparkjsdev/spark` in the app
28
+ * that uses it. The core `mujoco-react` entrypoint does not depend on Spark.
29
+ */
30
+ declare function SparkSplatEnvironment({ environment, src, format, collisionProxy, collisionProxyMetadata, showPlaceholder, children, lod, hideGroundMeshes, onStatusChange, onLoad, onError, ...groupProps }: SparkSplatEnvironmentProps): react_jsx_runtime.JSX.Element;
31
+
32
+ export { SparkSplatEnvironment, type SparkSplatEnvironmentProps, type SparkSplatStatus };
package/dist/spark.js ADDED
@@ -0,0 +1,150 @@
1
+ import { useSplatEnvironment, SplatEnvironment } from './chunk-KGFRKPLS.js';
2
+ import { useThree } from '@react-three/fiber';
3
+ import { useRef, useState, useEffect } from 'react';
4
+ import * as THREE from 'three';
5
+ import { jsxs, jsx } from 'react/jsx-runtime';
6
+
7
+ function SparkSplatEnvironment({
8
+ environment,
9
+ src,
10
+ format,
11
+ collisionProxy,
12
+ collisionProxyMetadata,
13
+ showPlaceholder,
14
+ children,
15
+ lod = true,
16
+ hideGroundMeshes = false,
17
+ onStatusChange,
18
+ onLoad,
19
+ onError,
20
+ ...groupProps
21
+ }) {
22
+ const groupRef = useRef(null);
23
+ const sparkRef = useRef(null);
24
+ const meshRef = useRef(null);
25
+ const hiddenMeshesRef = useRef([]);
26
+ const onStatusChangeRef = useRef(onStatusChange);
27
+ const onLoadRef = useRef(onLoad);
28
+ const onErrorRef = useRef(onError);
29
+ const [status, setStatus] = useState("idle");
30
+ const { gl, invalidate } = useThree();
31
+ const metadata = useSplatEnvironment({
32
+ environment,
33
+ src,
34
+ format,
35
+ collisionProxy: collisionProxyMetadata
36
+ });
37
+ useEffect(() => {
38
+ onStatusChangeRef.current = onStatusChange;
39
+ }, [onStatusChange]);
40
+ useEffect(() => {
41
+ onLoadRef.current = onLoad;
42
+ }, [onLoad]);
43
+ useEffect(() => {
44
+ onErrorRef.current = onError;
45
+ }, [onError]);
46
+ useEffect(() => {
47
+ let disposed = false;
48
+ function setLifecycleStatus(nextStatus) {
49
+ setStatus(nextStatus);
50
+ onStatusChangeRef.current?.(nextStatus);
51
+ }
52
+ function restoreHiddenMeshes() {
53
+ for (const mesh of hiddenMeshesRef.current) {
54
+ mesh.visible = true;
55
+ }
56
+ hiddenMeshesRef.current = [];
57
+ }
58
+ async function loadSplat() {
59
+ if (!metadata.src || metadata.format !== "spz") {
60
+ setLifecycleStatus("idle");
61
+ return;
62
+ }
63
+ setLifecycleStatus("loading");
64
+ try {
65
+ const sparkModule = await import('@sparkjsdev/spark');
66
+ if (disposed || !groupRef.current) return;
67
+ const spark = new sparkModule.SparkRenderer({
68
+ renderer: gl,
69
+ onDirty: invalidate
70
+ });
71
+ const mesh = new sparkModule.SplatMesh({
72
+ url: metadata.src,
73
+ lod
74
+ });
75
+ mesh.name = "GaussianSplatMesh";
76
+ groupRef.current.add(spark);
77
+ groupRef.current.add(mesh);
78
+ sparkRef.current = spark;
79
+ meshRef.current = mesh;
80
+ if (hideGroundMeshes && groupRef.current.parent) {
81
+ groupRef.current.parent.traverse((object) => {
82
+ if (!(object instanceof THREE.Mesh) || object === mesh) {
83
+ return;
84
+ }
85
+ const name = object.name.toLowerCase();
86
+ if (name.includes("floor") || name.includes("ground") || name.includes("plane")) {
87
+ object.visible = false;
88
+ hiddenMeshesRef.current.push(object);
89
+ }
90
+ });
91
+ }
92
+ await mesh.initialized;
93
+ if (disposed) return;
94
+ setLifecycleStatus("ready");
95
+ onLoadRef.current?.(mesh);
96
+ invalidate();
97
+ } catch (error) {
98
+ const normalizedError = error instanceof Error ? error : new Error(String(error));
99
+ setLifecycleStatus("error");
100
+ onErrorRef.current?.(normalizedError);
101
+ }
102
+ }
103
+ void loadSplat();
104
+ return () => {
105
+ disposed = true;
106
+ restoreHiddenMeshes();
107
+ if (meshRef.current) {
108
+ groupRef.current?.remove(meshRef.current);
109
+ meshRef.current.dispose?.();
110
+ meshRef.current = null;
111
+ }
112
+ if (sparkRef.current) {
113
+ groupRef.current?.remove(sparkRef.current);
114
+ sparkRef.current.dispose?.();
115
+ sparkRef.current = null;
116
+ }
117
+ };
118
+ }, [
119
+ gl,
120
+ hideGroundMeshes,
121
+ invalidate,
122
+ lod,
123
+ metadata.format,
124
+ metadata.src
125
+ ]);
126
+ return /* @__PURE__ */ jsxs(
127
+ SplatEnvironment,
128
+ {
129
+ ...groupProps,
130
+ environment,
131
+ src: metadata.src,
132
+ format: metadata.format,
133
+ collisionProxyMetadata: metadata.collisionProxy,
134
+ collisionProxy,
135
+ showPlaceholder: showPlaceholder ?? status !== "ready",
136
+ children: [
137
+ /* @__PURE__ */ jsx("group", { ref: groupRef }),
138
+ children
139
+ ]
140
+ }
141
+ );
142
+ }
143
+ /**
144
+ * @license
145
+ * SPDX-License-Identifier: Apache-2.0
146
+ */
147
+
148
+ export { SparkSplatEnvironment };
149
+ //# sourceMappingURL=spark.js.map
150
+ //# sourceMappingURL=spark.js.map
@@ -0,0 +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 { useEffect, useRef, useState } 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']>;\n\nexport type SparkSplatStatus = 'idle' | 'loading' | 'ready' | 'error';\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 * 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 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 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 || metadata.format !== 'spz') {\n setLifecycleStatus('idle');\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 meshRef.current.dispose?.();\n meshRef.current = null;\n }\n\n if (sparkRef.current) {\n groupRef.current?.remove(sparkRef.current);\n sparkRef.current.dispose?.();\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 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"]}