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.
- package/README.md +44 -0
- package/dist/chunk-KGFRKPLS.js +186 -0
- package/dist/chunk-KGFRKPLS.js.map +1 -0
- package/dist/index.d.ts +37 -735
- package/dist/index.js +41 -19
- package/dist/index.js.map +1 -1
- package/dist/spark.d.ts +32 -0
- package/dist/spark.js +150 -0
- package/dist/spark.js.map +1 -0
- package/dist/types-FFW7ykBu.d.ts +817 -0
- package/dist/vite.d.ts +9 -0
- package/dist/vite.js +4 -0
- package/dist/vite.js.map +1 -1
- package/package.json +15 -2
- package/src/components/VisualScenario.tsx +229 -0
- package/src/hooks/useSceneLights.ts +49 -18
- package/src/index.ts +23 -0
- package/src/spark.tsx +202 -0
- package/src/types.ts +92 -1
- package/src/vite.ts +8 -0
package/README.md
CHANGED
|
@@ -141,6 +141,50 @@ Use it as a child of `<MujocoCanvas>`:
|
|
|
141
141
|
</MujocoCanvas>
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
+
## Gaussian Splat Environments
|
|
145
|
+
|
|
146
|
+
Gaussian splats are visual context; MuJoCo XML remains the source of physics, contacts, and task fixtures. Pair each splat asset with collision proxy metadata so scene variants, rollouts, and datasets preserve both sides of the environment.
|
|
147
|
+
|
|
148
|
+
Use the renderer-agnostic boundary from the main package:
|
|
149
|
+
|
|
150
|
+
```tsx
|
|
151
|
+
import { SplatEnvironment } from "mujoco-react";
|
|
152
|
+
|
|
153
|
+
<SplatEnvironment
|
|
154
|
+
src="/models/lab/scene.spz"
|
|
155
|
+
format="spz"
|
|
156
|
+
collisionProxyMetadata={{
|
|
157
|
+
xmlPath: "/models/lab/collision.xml",
|
|
158
|
+
status: "validated",
|
|
159
|
+
primitives: ["plane", "box"],
|
|
160
|
+
}}
|
|
161
|
+
/>;
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
For first-class Spark rendering, install Spark and import the optional adapter:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
npm install @sparkjsdev/spark
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
```tsx
|
|
171
|
+
import { SparkSplatEnvironment } from "mujoco-react/spark";
|
|
172
|
+
|
|
173
|
+
<MujocoCanvas config={sceneConfig} gl={{ preserveDrawingBuffer: true }}>
|
|
174
|
+
<SparkSplatEnvironment
|
|
175
|
+
src="/models/lab/scene.spz"
|
|
176
|
+
format="spz"
|
|
177
|
+
collisionProxyMetadata={{
|
|
178
|
+
xmlPath: "/models/lab/collision.xml",
|
|
179
|
+
status: "validated",
|
|
180
|
+
primitives: ["plane", "box"],
|
|
181
|
+
}}
|
|
182
|
+
hideGroundMeshes
|
|
183
|
+
onStatusChange={(status) => console.log(status)}
|
|
184
|
+
/>
|
|
185
|
+
</MujocoCanvas>;
|
|
186
|
+
```
|
|
187
|
+
|
|
144
188
|
## Write Controllers
|
|
145
189
|
|
|
146
190
|
```tsx
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import * as THREE from 'three';
|
|
3
|
+
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
// src/components/VisualScenario.tsx
|
|
6
|
+
var DEFAULT_BACKGROUND = "#181a1f";
|
|
7
|
+
function ScenarioLighting({
|
|
8
|
+
preset = "studio",
|
|
9
|
+
castShadow = true,
|
|
10
|
+
intensity = 1
|
|
11
|
+
}) {
|
|
12
|
+
if (preset === "warehouse") {
|
|
13
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
14
|
+
/* @__PURE__ */ jsx("ambientLight", { intensity: 0.18 * intensity }),
|
|
15
|
+
/* @__PURE__ */ jsx(
|
|
16
|
+
"directionalLight",
|
|
17
|
+
{
|
|
18
|
+
position: [3.5, -2, 5],
|
|
19
|
+
intensity: 2.2 * intensity,
|
|
20
|
+
castShadow
|
|
21
|
+
}
|
|
22
|
+
),
|
|
23
|
+
/* @__PURE__ */ jsx("directionalLight", { position: [-2, 1.5, 2.5], intensity: 0.25 * intensity })
|
|
24
|
+
] });
|
|
25
|
+
}
|
|
26
|
+
if (preset === "low-light") {
|
|
27
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
28
|
+
/* @__PURE__ */ jsx("ambientLight", { intensity: 0.08 * intensity }),
|
|
29
|
+
/* @__PURE__ */ jsx(
|
|
30
|
+
"directionalLight",
|
|
31
|
+
{
|
|
32
|
+
position: [2, -2, 3],
|
|
33
|
+
intensity: 0.75 * intensity,
|
|
34
|
+
castShadow
|
|
35
|
+
}
|
|
36
|
+
),
|
|
37
|
+
/* @__PURE__ */ jsx("pointLight", { position: [-0.5, -0.8, 1.3], intensity: 0.6 * intensity })
|
|
38
|
+
] });
|
|
39
|
+
}
|
|
40
|
+
if (preset === "splat") {
|
|
41
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
42
|
+
/* @__PURE__ */ jsx("ambientLight", { intensity: 0.42 * intensity }),
|
|
43
|
+
/* @__PURE__ */ jsx(
|
|
44
|
+
"directionalLight",
|
|
45
|
+
{
|
|
46
|
+
position: [1.8, -2.4, 3.5],
|
|
47
|
+
intensity: 1.2 * intensity,
|
|
48
|
+
castShadow
|
|
49
|
+
}
|
|
50
|
+
),
|
|
51
|
+
/* @__PURE__ */ jsx("pointLight", { position: [0.4, 0.2, 1.4], intensity: 0.35 * intensity })
|
|
52
|
+
] });
|
|
53
|
+
}
|
|
54
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
55
|
+
/* @__PURE__ */ jsx("ambientLight", { intensity: 0.35 * intensity }),
|
|
56
|
+
/* @__PURE__ */ jsx(
|
|
57
|
+
"directionalLight",
|
|
58
|
+
{
|
|
59
|
+
position: [2.5, -3, 4],
|
|
60
|
+
intensity: 1.6 * intensity,
|
|
61
|
+
castShadow
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
] });
|
|
65
|
+
}
|
|
66
|
+
function getScenarioBackground(preset, fallback = DEFAULT_BACKGROUND) {
|
|
67
|
+
if (preset === "warehouse") return "#20242b";
|
|
68
|
+
if (preset === "low-light") return "#0f1115";
|
|
69
|
+
if (preset === "splat") return "#1b1f24";
|
|
70
|
+
return fallback;
|
|
71
|
+
}
|
|
72
|
+
function getScenarioCameraPosition(basePosition, scenario) {
|
|
73
|
+
const [x, y, z] = basePosition;
|
|
74
|
+
const jitter = scenario?.camera?.jitter ?? 0;
|
|
75
|
+
return [
|
|
76
|
+
Number((x + jitter * 0.6).toFixed(3)),
|
|
77
|
+
Number((y - jitter * 0.4).toFixed(3)),
|
|
78
|
+
Number((z + jitter * 0.25).toFixed(3))
|
|
79
|
+
];
|
|
80
|
+
}
|
|
81
|
+
function SplatEnvironment({
|
|
82
|
+
environment,
|
|
83
|
+
src,
|
|
84
|
+
format,
|
|
85
|
+
collisionProxy,
|
|
86
|
+
collisionProxyMetadata,
|
|
87
|
+
children,
|
|
88
|
+
showPlaceholder = true,
|
|
89
|
+
...groupProps
|
|
90
|
+
}) {
|
|
91
|
+
const metadata = useSplatEnvironment({
|
|
92
|
+
environment,
|
|
93
|
+
src,
|
|
94
|
+
format,
|
|
95
|
+
collisionProxy: collisionProxyMetadata
|
|
96
|
+
});
|
|
97
|
+
const existingUserData = typeof groupProps.userData === "object" && groupProps.userData !== null ? groupProps.userData : {};
|
|
98
|
+
return /* @__PURE__ */ jsxs(
|
|
99
|
+
"group",
|
|
100
|
+
{
|
|
101
|
+
...groupProps,
|
|
102
|
+
userData: {
|
|
103
|
+
...existingUserData,
|
|
104
|
+
...metadata.userData
|
|
105
|
+
},
|
|
106
|
+
children: [
|
|
107
|
+
children,
|
|
108
|
+
children || !showPlaceholder ? null : /* @__PURE__ */ jsx(SplatPlaceholder, {}),
|
|
109
|
+
collisionProxy
|
|
110
|
+
]
|
|
111
|
+
}
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
function useSplatEnvironment({
|
|
115
|
+
environment,
|
|
116
|
+
src,
|
|
117
|
+
format,
|
|
118
|
+
collisionProxy
|
|
119
|
+
}) {
|
|
120
|
+
const resolvedSrc = src ?? environment?.splat.src;
|
|
121
|
+
const resolvedFormat = format ?? environment?.splat.format ?? "spz";
|
|
122
|
+
const resolvedCollisionProxy = collisionProxy ?? environment?.collisionProxy;
|
|
123
|
+
return useMemo(
|
|
124
|
+
() => ({
|
|
125
|
+
src: resolvedSrc,
|
|
126
|
+
format: resolvedFormat,
|
|
127
|
+
collisionProxy: resolvedCollisionProxy,
|
|
128
|
+
userData: createSplatEnvironmentUserData({
|
|
129
|
+
environment,
|
|
130
|
+
src: resolvedSrc,
|
|
131
|
+
format: resolvedFormat,
|
|
132
|
+
collisionProxy: resolvedCollisionProxy
|
|
133
|
+
})
|
|
134
|
+
}),
|
|
135
|
+
[environment, resolvedSrc, resolvedFormat, resolvedCollisionProxy]
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
function createSplatEnvironmentUserData({
|
|
139
|
+
environment,
|
|
140
|
+
src,
|
|
141
|
+
format = "spz",
|
|
142
|
+
collisionProxy
|
|
143
|
+
}) {
|
|
144
|
+
return {
|
|
145
|
+
role: "splat-environment",
|
|
146
|
+
environmentId: environment?.id,
|
|
147
|
+
environmentLabel: environment?.label,
|
|
148
|
+
splatSrc: src,
|
|
149
|
+
splatFormat: format,
|
|
150
|
+
splatRenderer: environment?.splat.renderer,
|
|
151
|
+
collisionProxyStatus: collisionProxy?.status ?? "missing",
|
|
152
|
+
collisionProxyXmlPath: collisionProxy?.xmlPath,
|
|
153
|
+
collisionProxyPrimitives: collisionProxy?.primitives ?? []
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function createSparkSplatViewerUrl({
|
|
157
|
+
viewerUrl,
|
|
158
|
+
splatSrc
|
|
159
|
+
}) {
|
|
160
|
+
const url = new URL(viewerUrl, "http://mujoco-react.local");
|
|
161
|
+
url.searchParams.set("splat", splatSrc);
|
|
162
|
+
return viewerUrl.startsWith("http") ? url.toString() : `${url.pathname}${url.search}`;
|
|
163
|
+
}
|
|
164
|
+
function SplatPlaceholder() {
|
|
165
|
+
return /* @__PURE__ */ jsx("group", { children: /* @__PURE__ */ jsxs("mesh", { position: [0, 0, 1.2], children: [
|
|
166
|
+
/* @__PURE__ */ jsx("boxGeometry", { args: [2.4, 2.4, 2.4] }),
|
|
167
|
+
/* @__PURE__ */ jsx(
|
|
168
|
+
"meshBasicMaterial",
|
|
169
|
+
{
|
|
170
|
+
color: "#8b8b8b",
|
|
171
|
+
transparent: true,
|
|
172
|
+
opacity: 0.06,
|
|
173
|
+
wireframe: true,
|
|
174
|
+
side: THREE.DoubleSide
|
|
175
|
+
}
|
|
176
|
+
)
|
|
177
|
+
] }) });
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* @license
|
|
181
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
182
|
+
*/
|
|
183
|
+
|
|
184
|
+
export { ScenarioLighting, SplatEnvironment, createSparkSplatViewerUrl, createSplatEnvironmentUserData, getScenarioBackground, getScenarioCameraPosition, useSplatEnvironment };
|
|
185
|
+
//# sourceMappingURL=chunk-KGFRKPLS.js.map
|
|
186
|
+
//# sourceMappingURL=chunk-KGFRKPLS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/VisualScenario.tsx"],"names":[],"mappings":"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","file":"chunk-KGFRKPLS.js","sourcesContent":["/**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { ThreeElements } from '@react-three/fiber';\nimport type { ReactNode } from 'react';\nimport { useMemo } from 'react';\nimport * as THREE from 'three';\nimport type {\n PairedSplatEnvironmentConfig,\n SplatCollisionProxyConfig,\n SplatEnvironmentMetadata,\n SplatEnvironmentMetadataInput,\n SplatFormat,\n ScenarioLightingPreset,\n ScenarioLightingProps,\n SplatEnvironmentProps,\n VisualScenarioConfig,\n} from '../types';\n\nconst DEFAULT_BACKGROUND = '#181a1f';\n\nexport function ScenarioLighting({\n preset = 'studio',\n castShadow = true,\n intensity = 1,\n}: ScenarioLightingProps) {\n if (preset === 'warehouse') {\n return (\n <>\n <ambientLight intensity={0.18 * intensity} />\n <directionalLight\n position={[3.5, -2, 5]}\n intensity={2.2 * intensity}\n castShadow={castShadow}\n />\n <directionalLight position={[-2, 1.5, 2.5]} intensity={0.25 * intensity} />\n </>\n );\n }\n\n if (preset === 'low-light') {\n return (\n <>\n <ambientLight intensity={0.08 * intensity} />\n <directionalLight\n position={[2, -2, 3]}\n intensity={0.75 * intensity}\n castShadow={castShadow}\n />\n <pointLight position={[-0.5, -0.8, 1.3]} intensity={0.6 * intensity} />\n </>\n );\n }\n\n if (preset === 'splat') {\n return (\n <>\n <ambientLight intensity={0.42 * intensity} />\n <directionalLight\n position={[1.8, -2.4, 3.5]}\n intensity={1.2 * intensity}\n castShadow={castShadow}\n />\n <pointLight position={[0.4, 0.2, 1.4]} intensity={0.35 * intensity} />\n </>\n );\n }\n\n return (\n <>\n <ambientLight intensity={0.35 * intensity} />\n <directionalLight\n position={[2.5, -3, 4]}\n intensity={1.6 * intensity}\n castShadow={castShadow}\n />\n </>\n );\n}\n\nexport function getScenarioBackground(\n preset: ScenarioLightingPreset | undefined,\n fallback = DEFAULT_BACKGROUND\n) {\n if (preset === 'warehouse') return '#20242b';\n if (preset === 'low-light') return '#0f1115';\n if (preset === 'splat') return '#1b1f24';\n return fallback;\n}\n\nexport function getScenarioCameraPosition(\n basePosition: readonly [number, number, number],\n scenario?: Pick<VisualScenarioConfig, 'camera'>\n): [number, number, number] {\n const [x, y, z] = basePosition;\n const jitter = scenario?.camera?.jitter ?? 0;\n\n return [\n Number((x + jitter * 0.6).toFixed(3)),\n Number((y - jitter * 0.4).toFixed(3)),\n Number((z + jitter * 0.25).toFixed(3)),\n ];\n}\n\n/**\n * Renderer-agnostic Gaussian splat environment boundary.\n *\n * This component intentionally does not import a specific 3DGS renderer. Pass a\n * Spark/GaussianSplats3D object as `children` once the app chooses a renderer,\n * and pass MuJoCo/MJCF collision proxy visuals via `collisionProxy`.\n */\nexport function SplatEnvironment({\n environment,\n src,\n format,\n collisionProxy,\n collisionProxyMetadata,\n children,\n showPlaceholder = true,\n ...groupProps\n}: SplatEnvironmentProps) {\n const metadata = useSplatEnvironment({\n environment,\n src,\n format,\n collisionProxy: collisionProxyMetadata,\n });\n const existingUserData =\n typeof groupProps.userData === 'object' && groupProps.userData !== null\n ? groupProps.userData\n : {};\n\n return (\n <group\n {...groupProps}\n userData={{\n ...existingUserData,\n ...metadata.userData,\n }}\n >\n {children}\n {children || !showPlaceholder ? null : <SplatPlaceholder />}\n {collisionProxy}\n </group>\n );\n}\n\nexport function useSplatEnvironment({\n environment,\n src,\n format,\n collisionProxy,\n}: SplatEnvironmentMetadataInput): SplatEnvironmentMetadata {\n const resolvedSrc = src ?? environment?.splat.src;\n const resolvedFormat = format ?? environment?.splat.format ?? 'spz';\n const resolvedCollisionProxy = collisionProxy ?? environment?.collisionProxy;\n\n return useMemo(\n () => ({\n src: resolvedSrc,\n format: resolvedFormat,\n collisionProxy: resolvedCollisionProxy,\n userData: createSplatEnvironmentUserData({\n environment,\n src: resolvedSrc,\n format: resolvedFormat,\n collisionProxy: resolvedCollisionProxy,\n }),\n }),\n [environment, resolvedSrc, resolvedFormat, resolvedCollisionProxy]\n );\n}\n\nexport function createSplatEnvironmentUserData({\n environment,\n src,\n format = 'spz',\n collisionProxy,\n}: {\n environment?: PairedSplatEnvironmentConfig;\n src?: string;\n format?: SplatFormat;\n collisionProxy?: SplatCollisionProxyConfig;\n}) {\n return {\n role: 'splat-environment',\n environmentId: environment?.id,\n environmentLabel: environment?.label,\n splatSrc: src,\n splatFormat: format,\n splatRenderer: environment?.splat.renderer,\n collisionProxyStatus: collisionProxy?.status ?? 'missing',\n collisionProxyXmlPath: collisionProxy?.xmlPath,\n collisionProxyPrimitives: collisionProxy?.primitives ?? [],\n };\n}\n\nexport function createSparkSplatViewerUrl({\n viewerUrl,\n splatSrc,\n}: {\n viewerUrl: string;\n splatSrc: string;\n}) {\n const url = new URL(viewerUrl, 'http://mujoco-react.local');\n url.searchParams.set('splat', splatSrc);\n return viewerUrl.startsWith('http') ? url.toString() : `${url.pathname}${url.search}`;\n}\n\nfunction SplatPlaceholder() {\n return (\n <group>\n <mesh position={[0, 0, 1.2]}>\n <boxGeometry args={[2.4, 2.4, 2.4]} />\n <meshBasicMaterial\n color=\"#8b8b8b\"\n transparent\n opacity={0.06}\n wireframe\n side={THREE.DoubleSide}\n />\n </mesh>\n </group>\n );\n}\n\nexport type SplatCollisionProxy = ReactNode | ThreeElements['group'];\n"]}
|