mujoco-react 8.10.0 → 8.11.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 +65 -28
- package/dist/chunk-SEWQULWO.js +400 -0
- package/dist/chunk-SEWQULWO.js.map +1 -0
- package/dist/index.d.ts +82 -14
- package/dist/index.js +289 -17
- package/dist/index.js.map +1 -1
- package/dist/spark.d.ts +24 -3
- package/dist/spark.js +91 -6
- package/dist/spark.js.map +1 -1
- package/dist/{types-FFW7ykBu.d.ts → types-BmneHLBM.d.ts} +59 -5
- package/package.json +1 -1
- package/src/components/Body.tsx +3 -1
- package/src/components/VisualScenario.tsx +343 -6
- package/src/core/MujocoCanvas.tsx +8 -1
- package/src/core/SceneLoader.ts +182 -3
- package/src/hooks/useFrameCapture.ts +206 -0
- package/src/hooks/usePolicy.ts +12 -8
- package/src/index.ts +25 -0
- package/src/spark.tsx +138 -4
- package/src/types.ts +69 -4
- package/dist/chunk-KGFRKPLS.js +0 -186
- package/dist/chunk-KGFRKPLS.js.map +0 -1
package/dist/chunk-KGFRKPLS.js
DELETED
|
@@ -1,186 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
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"]}
|