mujoco-react 12.0.0 → 12.1.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 +21 -4
- package/dist/chunk-U2Y2BODT.js +137 -0
- package/dist/chunk-U2Y2BODT.js.map +1 -0
- package/dist/{chunk-7BCIHJMW.js → chunk-XD3AY7XZ.js} +47 -9
- package/dist/chunk-XD3AY7XZ.js.map +1 -0
- package/dist/index.d.ts +10 -15
- package/dist/index.js +1437 -1090
- package/dist/index.js.map +1 -1
- package/dist/onnx.d.ts +1 -1
- package/dist/physics.worker.d.ts +2 -0
- package/dist/physics.worker.js +78 -0
- package/dist/physics.worker.js.map +1 -0
- package/dist/spark.d.ts +1 -1
- package/dist/spark.js +1 -1
- package/dist/{types-BjHt_Urb.d.ts → types-CSi3fIVs.d.ts} +70 -1
- package/dist/vite.d.ts +5 -2
- package/dist/vite.js +6 -2
- package/dist/vite.js.map +1 -1
- package/package.json +5 -2
- package/src/components/CameraView.tsx +9 -7
- package/src/core/MujocoCanvas.tsx +2 -0
- package/src/core/MujocoPhysics.tsx +1 -0
- package/src/core/MujocoSimProvider.tsx +103 -81
- package/src/core/sceneIdentity.ts +15 -0
- package/src/core/stepBudget.ts +18 -0
- package/src/hooks/useCameraStream.ts +14 -17
- package/src/hooks/usePolicy.ts +16 -7
- package/src/index.ts +3 -0
- package/src/physics.worker.ts +13 -0
- package/src/rendering/cameraFrameCapture.ts +33 -7
- package/src/runtime/client.ts +186 -0
- package/src/runtime/engine.ts +93 -0
- package/src/runtime/protocol.ts +59 -0
- package/src/runtime/types.ts +51 -0
- package/src/types.ts +11 -0
- package/src/vite.ts +7 -2
- package/dist/chunk-7BCIHJMW.js.map +0 -1
package/README.md
CHANGED
|
@@ -16,6 +16,19 @@ Composable [React Three Fiber](https://docs.pmnd.rs/react-three-fiber) wrapper a
|
|
|
16
16
|
npm install mujoco-react three @react-three/fiber @react-three/drei
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
## Running policies and simulation workloads
|
|
20
|
+
|
|
21
|
+
Use `const runtime = await api.createRuntime()` after `onReady`, then await
|
|
22
|
+
`runtime.observe()` and `runtime.advance({ steps, controls })`. Physics runs in a
|
|
23
|
+
dedicated worker; commands reject when busy instead of accumulating. The runtime
|
|
24
|
+
supports cancellation, reset, full snapshots, synchronized camera observations,
|
|
25
|
+
and separate physics/capture timing. Use `<CameraView>` for GPU-only previews.
|
|
26
|
+
|
|
27
|
+
The viewer has an 8 ms / 100-step per-frame budget. Equivalent inline scene
|
|
28
|
+
configs preserve the loaded model. See the [simulation runtime guide](https://dadd.mintlify.app/guides/simulation-runtime)
|
|
29
|
+
for ownership, VLA loops, bundling, and performance limits, or try the
|
|
30
|
+
[worker demo](https://mujoco-react-example.pages.dev/?demo=runtime).
|
|
31
|
+
|
|
19
32
|
## Vite Plugin and Type-Safe Names
|
|
20
33
|
|
|
21
34
|
Use the Vite plugin to generate declaration merging for actuator, sensor, body, joint, site, geom, and keyframe names:
|
|
@@ -36,6 +49,10 @@ export default defineConfig({
|
|
|
36
49
|
});
|
|
37
50
|
```
|
|
38
51
|
|
|
52
|
+
The plugin also preserves worker asset URLs in Vite development by excluding
|
|
53
|
+
`mujoco-react` from dependency prebundling. Without it, set
|
|
54
|
+
`optimizeDeps: { exclude: ["mujoco-react"] }` when using the worker runtime.
|
|
55
|
+
|
|
39
56
|
The plugin writes `src/mujoco-register.gen.ts` during dev and build. Commit that generated file. Vite auto-loads it, so app code imports generated values from `mujoco-react`, not from the generated file:
|
|
40
57
|
|
|
41
58
|
```ts
|
|
@@ -1153,8 +1170,8 @@ const frame = await apiRef.current?.captureCameraFrame({
|
|
|
1153
1170
|
```
|
|
1154
1171
|
|
|
1155
1172
|
**Live streams.** `useCameraStream(canvasRef, options)` renders a camera into a
|
|
1156
|
-
DOM `<canvas>`
|
|
1157
|
-
|
|
1173
|
+
DOM `<canvas>` at 10 FPS by default (offscreen render → GPU readback → blit).
|
|
1174
|
+
It avoids PNG encoding but still pays readback and pixel-conversion costs. Call it inside `<MujocoCanvas>`; the
|
|
1158
1175
|
canvas can live anywhere in your DOM:
|
|
1159
1176
|
|
|
1160
1177
|
```tsx
|
|
@@ -1167,8 +1184,8 @@ function WristStream({ canvasRef }) {
|
|
|
1167
1184
|
For a transparent picture-in-picture overlay, use `<CameraView>` (or
|
|
1168
1185
|
`useCameraViewport` to track your own element). It scissors into the main canvas —
|
|
1169
1186
|
cheaper, but it takes over the render loop while mounted (incompatible with
|
|
1170
|
-
postprocessing, occluded by opaque DOM), so
|
|
1171
|
-
|
|
1187
|
+
postprocessing, occluded by opaque DOM), so use `useCameraStream` only when HTML compositing requires a separate canvas.
|
|
1188
|
+
Prefer GPU viewports for live simulation previews:
|
|
1172
1189
|
|
|
1173
1190
|
```tsx
|
|
1174
1191
|
<MujocoCanvas config={config}>
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// src/runtime/engine.ts
|
|
2
|
+
var displayFields = [
|
|
3
|
+
"qpos",
|
|
4
|
+
"qvel",
|
|
5
|
+
"ctrl",
|
|
6
|
+
"act",
|
|
7
|
+
"plastic",
|
|
8
|
+
"sensordata",
|
|
9
|
+
"xpos",
|
|
10
|
+
"xquat",
|
|
11
|
+
"xmat",
|
|
12
|
+
"geom_xpos",
|
|
13
|
+
"geom_xmat",
|
|
14
|
+
"site_xpos",
|
|
15
|
+
"site_xmat",
|
|
16
|
+
"cam_xpos",
|
|
17
|
+
"cam_xmat",
|
|
18
|
+
"flexvert_xpos",
|
|
19
|
+
"ten_length",
|
|
20
|
+
"wrap_xpos",
|
|
21
|
+
"cvel",
|
|
22
|
+
"cfrc_ext",
|
|
23
|
+
"qfrc_applied",
|
|
24
|
+
"xfrc_applied",
|
|
25
|
+
"qfrc_bias",
|
|
26
|
+
"ten_wrapadr",
|
|
27
|
+
"ten_wrapnum"
|
|
28
|
+
];
|
|
29
|
+
var SimulationEngine = class {
|
|
30
|
+
constructor(mj, initial) {
|
|
31
|
+
this.mj = mj;
|
|
32
|
+
this.initial = initial;
|
|
33
|
+
mj.FS.writeFile("/runtime.mjb", initial.model);
|
|
34
|
+
const vfs = new mj.MjVFS();
|
|
35
|
+
try {
|
|
36
|
+
this.model = mj.MjModel.from_binary_path("/runtime.mjb", vfs);
|
|
37
|
+
} finally {
|
|
38
|
+
vfs.delete();
|
|
39
|
+
mj.FS.unlink("/runtime.mjb");
|
|
40
|
+
}
|
|
41
|
+
this.data = new mj.MjData(this.model);
|
|
42
|
+
try {
|
|
43
|
+
this.reset();
|
|
44
|
+
} catch (error) {
|
|
45
|
+
this.dispose();
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
model;
|
|
50
|
+
data;
|
|
51
|
+
reset() {
|
|
52
|
+
this.mj.mj_resetData(this.model, this.data);
|
|
53
|
+
this.restore(this.initial.state);
|
|
54
|
+
}
|
|
55
|
+
restore(state) {
|
|
56
|
+
if (state.signature !== this.mj.mjtState.mjSTATE_INTEGRATION.value || state.values.length !== this.mj.mj_stateSize(this.model, state.signature) || !state.values.every(Number.isFinite)) throw new Error("Invalid runtime snapshot");
|
|
57
|
+
this.mj.mj_setState(this.model, this.data, Array.from(state.values), state.signature);
|
|
58
|
+
this.mj.mj_forward(this.model, this.data);
|
|
59
|
+
}
|
|
60
|
+
setControls(controls) {
|
|
61
|
+
if (controls) {
|
|
62
|
+
if (controls.length !== this.data.ctrl.length || !controls.every(Number.isFinite)) throw new Error("Invalid runtime controls");
|
|
63
|
+
this.data.ctrl.set(controls);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
step() {
|
|
67
|
+
const expected = this.data.time + this.model.opt.timestep;
|
|
68
|
+
this.mj.mj_step(this.model, this.data);
|
|
69
|
+
if (Math.abs(this.data.time - expected) > 1e-7 || !this.data.qpos.every(Number.isFinite)) {
|
|
70
|
+
throw new Error("Physics became unstable or reset unexpectedly");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
save() {
|
|
74
|
+
const signature = this.mj.mjtState.mjSTATE_INTEGRATION.value;
|
|
75
|
+
const buffer = new this.mj.DoubleBuffer(this.mj.mj_stateSize(this.model, signature));
|
|
76
|
+
try {
|
|
77
|
+
this.mj.mj_getState(this.model, this.data, buffer, signature);
|
|
78
|
+
return { signature, values: new Float64Array(buffer.GetView()) };
|
|
79
|
+
} finally {
|
|
80
|
+
buffer.delete();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
snapshot(complete = true) {
|
|
84
|
+
const integration = complete ? this.save() : void 0;
|
|
85
|
+
if (integration) this.mj.mj_forward(this.model, this.data);
|
|
86
|
+
try {
|
|
87
|
+
return {
|
|
88
|
+
time: this.data.time,
|
|
89
|
+
fields: Object.fromEntries(displayFields.map((key) => [key, new Float64Array(this.data[key])])),
|
|
90
|
+
contacts: complete ? this.contacts() : [],
|
|
91
|
+
...integration ? { integration } : {}
|
|
92
|
+
};
|
|
93
|
+
} finally {
|
|
94
|
+
if (integration) this.mj.mj_setState(this.model, this.data, Array.from(integration.values), integration.signature);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
contacts() {
|
|
98
|
+
const result = [], vector = this.data.contact;
|
|
99
|
+
const names = this.model.names, addresses = this.model.name_geomadr;
|
|
100
|
+
const name = (id) => {
|
|
101
|
+
if (id < 0) return "flex";
|
|
102
|
+
const start = addresses[id];
|
|
103
|
+
let end = start;
|
|
104
|
+
while (end < names.length && names[end]) end++;
|
|
105
|
+
return new TextDecoder().decode(names.subarray(start, end));
|
|
106
|
+
};
|
|
107
|
+
try {
|
|
108
|
+
for (let i = 0; i < this.data.ncon; i++) {
|
|
109
|
+
const c = vector.get(i);
|
|
110
|
+
if (!c) continue;
|
|
111
|
+
try {
|
|
112
|
+
result.push({
|
|
113
|
+
geom1: c.geom1,
|
|
114
|
+
geom2: c.geom2,
|
|
115
|
+
geom1Name: name(c.geom1),
|
|
116
|
+
geom2Name: name(c.geom2),
|
|
117
|
+
pos: Array.from(c.pos),
|
|
118
|
+
depth: c.dist
|
|
119
|
+
});
|
|
120
|
+
} finally {
|
|
121
|
+
c.delete();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
} finally {
|
|
125
|
+
vector.delete();
|
|
126
|
+
}
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
129
|
+
dispose() {
|
|
130
|
+
this.data.delete();
|
|
131
|
+
this.model.delete();
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
export { SimulationEngine, displayFields };
|
|
136
|
+
//# sourceMappingURL=chunk-U2Y2BODT.js.map
|
|
137
|
+
//# sourceMappingURL=chunk-U2Y2BODT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime/engine.ts"],"names":[],"mappings":"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","file":"chunk-U2Y2BODT.js","sourcesContent":["import type { MainModule, MjModel, MjData } from '@mujoco/mujoco';\nimport type { ContactInfo } from '../types';\n\nexport const displayFields = ['qpos', 'qvel', 'ctrl', 'act', 'plastic', 'sensordata', 'xpos', 'xquat', 'xmat',\n 'geom_xpos', 'geom_xmat', 'site_xpos', 'site_xmat', 'cam_xpos', 'cam_xmat',\n 'flexvert_xpos', 'ten_length', 'wrap_xpos', 'cvel', 'cfrc_ext', 'qfrc_applied', 'xfrc_applied', 'qfrc_bias', 'ten_wrapadr', 'ten_wrapnum'] as const;\nexport interface EngineState { signature: number; values: Float64Array }\nexport interface EngineInitialization { model: Uint8Array; state: EngineState }\nexport interface DisplayState {\n time: number;\n fields: Record<typeof displayFields[number], Float64Array>;\n contacts: ContactInfo[];\n integration?: EngineState;\n}\nexport class SimulationEngine {\n readonly model: MjModel;\n readonly data: MjData;\n constructor(private mj: MainModule, private initial: EngineInitialization) {\n mj.FS.writeFile('/runtime.mjb', initial.model);\n const vfs = new mj.MjVFS();\n try { this.model = mj.MjModel.from_binary_path('/runtime.mjb', vfs); }\n finally { vfs.delete(); mj.FS.unlink('/runtime.mjb'); }\n this.data = new mj.MjData(this.model);\n try { this.reset(); } catch (error) { this.dispose(); throw error; }\n }\n reset() {\n this.mj.mj_resetData(this.model, this.data);\n this.restore(this.initial.state);\n }\n restore(state: EngineState) {\n if (state.signature !== this.mj.mjtState.mjSTATE_INTEGRATION.value ||\n state.values.length !== this.mj.mj_stateSize(this.model, state.signature) ||\n !state.values.every(Number.isFinite)) throw new Error('Invalid runtime snapshot');\n this.mj.mj_setState(this.model, this.data, Array.from(state.values), state.signature);\n this.mj.mj_forward(this.model, this.data);\n }\n setControls(controls?: Float64Array) {\n if (controls) {\n if (controls.length !== this.data.ctrl.length || !controls.every(Number.isFinite)) throw new Error('Invalid runtime controls');\n this.data.ctrl.set(controls);\n }\n }\n step() {\n const expected = this.data.time + this.model.opt.timestep;\n this.mj.mj_step(this.model, this.data);\n if (Math.abs(this.data.time - expected) > 1e-7 || !this.data.qpos.every(Number.isFinite)) {\n throw new Error('Physics became unstable or reset unexpectedly');\n }\n }\n save(): EngineState {\n const signature = this.mj.mjtState.mjSTATE_INTEGRATION.value;\n const buffer = new this.mj.DoubleBuffer(this.mj.mj_stateSize(this.model, signature));\n try {\n this.mj.mj_getState(this.model, this.data, buffer, signature);\n return { signature, values: new Float64Array(buffer.GetView()) };\n } finally { buffer.delete(); }\n }\n snapshot(complete = true): DisplayState {\n const integration = complete ? this.save() : undefined;\n // mj_step integrates qpos after computing derived fields. Refresh completed\n // observations at their reported time, preserving solver warmstart exactly.\n if (integration) this.mj.mj_forward(this.model, this.data);\n try { return {\n time: this.data.time,\n fields: Object.fromEntries(displayFields.map(key => [key, new Float64Array(this.data[key])])) as DisplayState['fields'],\n contacts: complete ? this.contacts() : [],\n ...(integration ? { integration } : {}),\n }; } finally {\n if (integration) this.mj.mj_setState(this.model, this.data, Array.from(integration.values), integration.signature);\n }\n }\n private contacts(): ContactInfo[] {\n const result: ContactInfo[] = [], vector = this.data.contact;\n const names = this.model.names, addresses = this.model.name_geomadr;\n const name = (id: number) => {\n if (id < 0) return 'flex';\n const start = addresses[id]; let end = start;\n while (end < names.length && names[end]) end++;\n return new TextDecoder().decode(names.subarray(start, end));\n };\n try {\n for (let i = 0; i < this.data.ncon; i++) {\n const c = vector.get(i);\n if (!c) continue;\n try { result.push({ geom1: c.geom1, geom2: c.geom2, geom1Name: name(c.geom1), geom2Name: name(c.geom2),\n pos: Array.from(c.pos) as [number, number, number], depth: c.dist }); }\n finally { c.delete(); }\n }\n } finally { vector.delete(); }\n return result;\n }\n dispose() { this.data.delete(); this.model.delete(); }\n}\n"]}
|
|
@@ -315,8 +315,8 @@ function prepareCaptureCamera(camera, options, fallbackCamera, width, height) {
|
|
|
315
315
|
applyProjectionMatrix(camera, options.projectionMatrix);
|
|
316
316
|
applyCameraPose(camera, options, fallbackCamera);
|
|
317
317
|
}
|
|
318
|
-
function readRenderTargetToCanvas(renderer, target, canvas, context, pixels, imageData, width, height, outputColorSpace, flipX = false) {
|
|
319
|
-
renderer.readRenderTargetPixels(target, 0, 0, width, height, pixels);
|
|
318
|
+
function readRenderTargetToCanvas(renderer, target, canvas, context, pixels, imageData, width, height, outputColorSpace, flipX = false, readback = true) {
|
|
319
|
+
if (readback) renderer.readRenderTargetPixels(target, 0, 0, width, height, pixels);
|
|
320
320
|
const rowBytes = width * 4;
|
|
321
321
|
const encodeSrgb = outputColorSpace === THREE.SRGBColorSpace;
|
|
322
322
|
for (let y = 0; y < height; y += 1) {
|
|
@@ -532,6 +532,15 @@ function createCameraFrameCaptureSession(renderer, scene, fallbackCamera, option
|
|
|
532
532
|
const drawContext = context;
|
|
533
533
|
const pixels = new Uint8Array(width * height * 4);
|
|
534
534
|
const imageData = drawContext.createImageData(width, height);
|
|
535
|
+
let inFlight = false, disposed = false;
|
|
536
|
+
function assertAvailable() {
|
|
537
|
+
if (disposed) throw new Error("Camera capture session is disposed");
|
|
538
|
+
if (inFlight) throw new Error("Camera capture session is busy; await the current capture");
|
|
539
|
+
}
|
|
540
|
+
function releaseResources() {
|
|
541
|
+
target.dispose();
|
|
542
|
+
if (isolatedRenderer && !isolatedRenderer.cached) isolatedRenderer.renderer.dispose();
|
|
543
|
+
}
|
|
535
544
|
function resolveCaptureOptions(nextOptions = {}) {
|
|
536
545
|
const captureOptions = { ...options, ...nextOptions };
|
|
537
546
|
if (shouldUseRenderIsolation(captureOptions) !== shouldUseRenderIsolation(options)) {
|
|
@@ -614,9 +623,11 @@ function createCameraFrameCaptureSession(renderer, scene, fallbackCamera, option
|
|
|
614
623
|
};
|
|
615
624
|
}
|
|
616
625
|
function capture(nextOptions = {}) {
|
|
626
|
+
assertAvailable();
|
|
617
627
|
return renderPreparedCapture(resolveCaptureOptions(nextOptions));
|
|
618
628
|
}
|
|
619
629
|
function capturePixels(nextOptions = {}) {
|
|
630
|
+
assertAvailable();
|
|
620
631
|
const captureOptions = resolveCaptureOptions(nextOptions);
|
|
621
632
|
renderCaptureToTarget(captureOptions, () => {
|
|
622
633
|
sessionRenderer.readRenderTargetPixels(target, 0, 0, width, height, pixels);
|
|
@@ -643,6 +654,16 @@ function createCameraFrameCaptureSession(renderer, scene, fallbackCamera, option
|
|
|
643
654
|
return { ...tensor, camera, source: result.source };
|
|
644
655
|
}
|
|
645
656
|
async function captureAsync(nextOptions = {}) {
|
|
657
|
+
assertAvailable();
|
|
658
|
+
inFlight = true;
|
|
659
|
+
try {
|
|
660
|
+
return await captureAsyncInternal(nextOptions);
|
|
661
|
+
} finally {
|
|
662
|
+
inFlight = false;
|
|
663
|
+
if (disposed) releaseResources();
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
async function captureAsyncInternal(nextOptions = {}) {
|
|
646
667
|
const captureOptions = resolveCaptureOptions(nextOptions);
|
|
647
668
|
runCapturePreRenderHooks(scene);
|
|
648
669
|
scene.updateMatrixWorld(true);
|
|
@@ -707,7 +728,25 @@ function createCameraFrameCaptureSession(renderer, scene, fallbackCamera, option
|
|
|
707
728
|
restoreRendererState(sessionRenderer, previousState);
|
|
708
729
|
}
|
|
709
730
|
}
|
|
710
|
-
|
|
731
|
+
let readback;
|
|
732
|
+
renderCaptureToTarget(captureOptions, () => {
|
|
733
|
+
readback = sessionRenderer.readRenderTargetPixelsAsync(target, 0, 0, width, height, pixels);
|
|
734
|
+
});
|
|
735
|
+
await readback;
|
|
736
|
+
readRenderTargetToCanvas(
|
|
737
|
+
sessionRenderer,
|
|
738
|
+
target,
|
|
739
|
+
canvas,
|
|
740
|
+
drawContext,
|
|
741
|
+
pixels,
|
|
742
|
+
imageData,
|
|
743
|
+
width,
|
|
744
|
+
height,
|
|
745
|
+
sessionRenderer.outputColorSpace,
|
|
746
|
+
captureOptions.flipX ?? false,
|
|
747
|
+
false
|
|
748
|
+
);
|
|
749
|
+
return { canvas, camera, width, height, source: getCameraFrameCaptureSource(captureOptions) };
|
|
711
750
|
}
|
|
712
751
|
return {
|
|
713
752
|
width,
|
|
@@ -756,10 +795,9 @@ function createCameraFrameCaptureSession(renderer, scene, fallbackCamera, option
|
|
|
756
795
|
return { ...result, blob, type };
|
|
757
796
|
},
|
|
758
797
|
dispose() {
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
}
|
|
798
|
+
if (disposed) return;
|
|
799
|
+
disposed = true;
|
|
800
|
+
if (!inFlight) releaseResources();
|
|
763
801
|
}
|
|
764
802
|
};
|
|
765
803
|
}
|
|
@@ -1433,5 +1471,5 @@ function clamp01(value) {
|
|
|
1433
1471
|
*/
|
|
1434
1472
|
|
|
1435
1473
|
export { CAMERA_FRAME_CAPTURE_PRE_RENDER_USER_DATA_KEY, CAMERA_FRAME_CAPTURE_RENDER_USER_DATA_KEY, CAPTURE_EXCLUDE_KEY, ModelActuators, ModelBodies, ModelCameras, ModelGeoms, ModelJoints, ModelKeyframes, ModelResources, ModelSensors, ModelSites, ScenarioLighting, SplatEnvironment, SplatEnvironmentReadinessStatus, VisualScenarioEffects, captureCameraFrame, captureCameraFrameBlob, captureCameraFrameTensor, createCameraFrameCaptureSession, createCaptureCamera, createPairedSplatEnvironment, createSparkSplatViewerUrl, createSplatEnvironmentUserData, createSplatSceneConfig, createVisualScenarioExecutionContext, dataUrlToPolicyImageTensor, getContact, getScenarioBackground, getScenarioCameraPosition, getSplatEnvironmentReadiness, imageDataToPolicyImageTensor, pixelsToPolicyImageTensor, prepareCaptureCamera, registerModelResources, renderCameraFrameToCanvas, useSplatEnvironment, useSplatSceneConfig, useVisualScenarioEffects, useVisualScenarioExecutionContext, withContacts, withSplatEnvironment };
|
|
1436
|
-
//# sourceMappingURL=chunk-
|
|
1437
|
-
//# sourceMappingURL=chunk-
|
|
1474
|
+
//# sourceMappingURL=chunk-XD3AY7XZ.js.map
|
|
1475
|
+
//# sourceMappingURL=chunk-XD3AY7XZ.js.map
|