@reactvision/react-viro 2.54.0 → 2.55.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 +85 -46
- package/android/react_viro/react_viro-release.aar +0 -0
- package/android/viro_renderer/viro_renderer-release.aar +0 -0
- package/components/AR/ViroARCamera.tsx +5 -0
- package/components/AR/ViroARImageMarker.tsx +5 -0
- package/components/AR/ViroARObjectMarker.tsx +5 -0
- package/components/AR/ViroARPlane.tsx +5 -0
- package/components/AR/ViroARPlaneSelector.tsx +5 -0
- package/components/AR/ViroARScene.tsx +5 -0
- package/components/AR/ViroARSceneNavigator.tsx +54 -0
- package/components/Studio/StudioARScene.tsx +368 -0
- package/components/Studio/StudioSceneNavigator.tsx +191 -0
- package/components/Studio/VRTStudioModule.ts +40 -0
- package/components/Studio/domain/animationRegistry.ts +86 -0
- package/components/Studio/domain/collisionBindingsRuntime.ts +93 -0
- package/components/Studio/domain/collisionPairKey.ts +15 -0
- package/components/Studio/domain/dragConfiguration.ts +48 -0
- package/components/Studio/domain/materialConfig.ts +276 -0
- package/components/Studio/domain/physicsConfig.ts +204 -0
- package/components/Studio/domain/sceneNavigationHandler.ts +150 -0
- package/components/Studio/domain/studioMaterials.ts +33 -0
- package/components/Studio/domain/triggerImageRegistry.ts +64 -0
- package/components/Studio/domain/useStudioShaderTimeUniforms.ts +51 -0
- package/components/Studio/domain/useStudioShaderViewportUniforms.ts +52 -0
- package/components/Studio/domain/viroNodeFactory.tsx +323 -0
- package/components/Studio/index.ts +18 -0
- package/components/Studio/types.ts +164 -0
- package/components/Types/ViroEvents.ts +53 -0
- package/components/Utilities/VRModuleOpenXR.ts +50 -0
- package/components/Utilities/VRQuestNavigatorBridge.ts +168 -0
- package/components/Utilities/ViroPlatform.ts +52 -0
- package/components/Utilities/ViroVersion.ts +1 -1
- package/components/Utilities/useAnySourceHover.ts +55 -0
- package/components/Utilities/useAnySourcePressed.ts +70 -0
- package/components/ViroQuestEntryPoint.tsx +79 -0
- package/components/ViroVRSceneNavigator.tsx +44 -19
- package/components/ViroXRSceneNavigator.tsx +217 -0
- package/components/VisionOS/ViroVisionOSModule.ts +93 -0
- package/dist/components/AR/ViroARCamera.d.ts +1 -1
- package/dist/components/AR/ViroARCamera.js +5 -0
- package/dist/components/AR/ViroARImageMarker.d.ts +1 -1
- package/dist/components/AR/ViroARImageMarker.js +5 -0
- package/dist/components/AR/ViroARObjectMarker.d.ts +1 -1
- package/dist/components/AR/ViroARObjectMarker.js +5 -0
- package/dist/components/AR/ViroARPlane.d.ts +1 -1
- package/dist/components/AR/ViroARPlane.js +5 -0
- package/dist/components/AR/ViroARPlaneSelector.d.ts +1 -1
- package/dist/components/AR/ViroARPlaneSelector.js +5 -0
- package/dist/components/AR/ViroARScene.d.ts +1 -1
- package/dist/components/AR/ViroARScene.js +5 -0
- package/dist/components/AR/ViroARSceneNavigator.d.ts +13 -0
- package/dist/components/AR/ViroARSceneNavigator.js +36 -0
- package/dist/components/Studio/StudioARScene.d.ts +15 -0
- package/dist/components/Studio/StudioARScene.js +299 -0
- package/dist/components/Studio/StudioSceneNavigator.d.ts +31 -0
- package/dist/components/Studio/StudioSceneNavigator.js +174 -0
- package/dist/components/Studio/VRTStudioModule.d.ts +15 -0
- package/dist/components/Studio/VRTStudioModule.js +31 -0
- package/dist/components/Studio/domain/animationRegistry.d.ts +11 -0
- package/dist/components/Studio/domain/animationRegistry.js +67 -0
- package/dist/components/Studio/domain/collisionBindingsRuntime.d.ts +21 -0
- package/dist/components/Studio/domain/collisionBindingsRuntime.js +54 -0
- package/dist/components/Studio/domain/collisionPairKey.d.ts +8 -0
- package/dist/components/Studio/domain/collisionPairKey.js +15 -0
- package/dist/components/Studio/domain/dragConfiguration.d.ts +20 -0
- package/dist/components/Studio/domain/dragConfiguration.js +37 -0
- package/dist/components/Studio/domain/materialConfig.d.ts +56 -0
- package/dist/components/Studio/domain/materialConfig.js +239 -0
- package/dist/components/Studio/domain/physicsConfig.d.ts +69 -0
- package/dist/components/Studio/domain/physicsConfig.js +165 -0
- package/dist/components/Studio/domain/sceneNavigationHandler.d.ts +12 -0
- package/dist/components/Studio/domain/sceneNavigationHandler.js +112 -0
- package/dist/components/Studio/domain/studioMaterials.d.ts +6 -0
- package/dist/components/Studio/domain/studioMaterials.js +30 -0
- package/dist/components/Studio/domain/triggerImageRegistry.d.ts +13 -0
- package/dist/components/Studio/domain/triggerImageRegistry.js +47 -0
- package/dist/components/Studio/domain/useStudioShaderTimeUniforms.d.ts +6 -0
- package/dist/components/Studio/domain/useStudioShaderTimeUniforms.js +48 -0
- package/dist/components/Studio/domain/useStudioShaderViewportUniforms.d.ts +6 -0
- package/dist/components/Studio/domain/useStudioShaderViewportUniforms.js +48 -0
- package/dist/components/Studio/domain/viroNodeFactory.d.ts +28 -0
- package/dist/components/Studio/domain/viroNodeFactory.js +193 -0
- package/dist/components/Studio/index.d.ts +3 -0
- package/dist/components/Studio/index.js +7 -0
- package/dist/components/Studio/types.d.ts +149 -0
- package/dist/components/Studio/types.js +4 -0
- package/dist/components/Types/ViroEvents.d.ts +49 -1
- package/dist/components/Types/ViroEvents.js +1 -0
- package/dist/components/Utilities/VRModuleOpenXR.d.ts +32 -0
- package/dist/components/Utilities/VRModuleOpenXR.js +44 -0
- package/dist/components/Utilities/VRQuestNavigatorBridge.d.ts +85 -0
- package/dist/components/Utilities/VRQuestNavigatorBridge.js +124 -0
- package/dist/components/Utilities/ViroPlatform.d.ts +10 -0
- package/dist/components/Utilities/ViroPlatform.js +43 -0
- package/dist/components/Utilities/ViroVersion.d.ts +1 -1
- package/dist/components/Utilities/ViroVersion.js +1 -1
- package/dist/components/Utilities/useAnySourceHover.d.ts +36 -0
- package/dist/components/Utilities/useAnySourceHover.js +48 -0
- package/dist/components/Utilities/useAnySourcePressed.d.ts +37 -0
- package/dist/components/Utilities/useAnySourcePressed.js +61 -0
- package/dist/components/ViroQuestEntryPoint.d.ts +13 -0
- package/dist/components/ViroQuestEntryPoint.js +104 -0
- package/dist/components/ViroVRSceneNavigator.d.ts +24 -10
- package/dist/components/ViroVRSceneNavigator.js +21 -18
- package/dist/components/ViroXRSceneNavigator.d.ts +54 -0
- package/dist/components/ViroXRSceneNavigator.js +173 -0
- package/dist/components/VisionOS/ViroVisionOSModule.d.ts +65 -0
- package/dist/components/VisionOS/ViroVisionOSModule.js +91 -0
- package/dist/index.d.ts +15 -2
- package/dist/index.js +32 -2
- package/dist/plugins/withViro.d.ts +17 -1
- package/dist/plugins/withViroAndroid.js +312 -7
- package/dist/plugins/withViroIos.js +5 -0
- package/dist/plugins/withViroVisionOS.d.ts +24 -0
- package/dist/plugins/withViroVisionOS.js +265 -0
- package/index.ts +58 -0
- package/ios/ViroReact.podspec +13 -4
- package/ios/dist/ViroRenderer/ViroKit.framework/ARCoreCoreMLSemanticsResources.bundle/Info.plist +0 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/ARCoreResources.bundle/Info.plist +0 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROARSession.h +10 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROARSessioniOS.h +4 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROInputControllerBase.h +74 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROInputType.h +11 -3
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROPlatformUtil.h +13 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VRORenderer.h +8 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Info.plist +0 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Shaders.dat +1 -1
- package/ios/dist/ViroRenderer/ViroKit.framework/ViroKit +0 -0
- package/ios/dist/ViroRenderer/ViroKit.podspec +5 -0
- package/ios/dist/include/VRTARSceneNavigator.h +3 -0
- package/ios/dist/include/VRTStudioModule.h +6 -0
- package/ios/dist/lib/libViroReact.a +0 -0
- package/package.json +1 -1
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Studio material_config parsing and Viro material definition building.
|
|
4
|
+
* Ported from studio-go/domain/materialConfig.ts — no zod dependency.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.materialConfigNeedsTimeUniform = materialConfigNeedsTimeUniform;
|
|
8
|
+
exports.materialConfigNeedsViewportUniforms = materialConfigNeedsViewportUniforms;
|
|
9
|
+
exports.studioMaterialName = studioMaterialName;
|
|
10
|
+
exports.parseMaterialConfig = parseMaterialConfig;
|
|
11
|
+
exports.buildViroMaterialDefinition = buildViroMaterialDefinition;
|
|
12
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
13
|
+
const TEXTURE_KEYS = [
|
|
14
|
+
"diffuseTexture",
|
|
15
|
+
"normalTexture",
|
|
16
|
+
"roughnessTexture",
|
|
17
|
+
"metalnessTexture",
|
|
18
|
+
"ambientOcclusionTexture",
|
|
19
|
+
"specularTexture",
|
|
20
|
+
];
|
|
21
|
+
function textureToViro(uri) {
|
|
22
|
+
if (uri == null || uri === "")
|
|
23
|
+
return undefined;
|
|
24
|
+
return { uri };
|
|
25
|
+
}
|
|
26
|
+
function collectShaderModifierStrings(config) {
|
|
27
|
+
const mods = config.shaderModifiers;
|
|
28
|
+
if (!mods)
|
|
29
|
+
return [];
|
|
30
|
+
const strings = [];
|
|
31
|
+
for (const stage of Object.values(mods)) {
|
|
32
|
+
if (typeof stage === "string") {
|
|
33
|
+
strings.push(stage);
|
|
34
|
+
}
|
|
35
|
+
else if (stage && typeof stage === "object") {
|
|
36
|
+
const s = stage;
|
|
37
|
+
if (typeof s.uniforms === "string")
|
|
38
|
+
strings.push(s.uniforms);
|
|
39
|
+
if (typeof s.body === "string")
|
|
40
|
+
strings.push(s.body);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return strings;
|
|
44
|
+
}
|
|
45
|
+
const TIME_WORD_RE = /\btime\b/i;
|
|
46
|
+
const CAMERA_TEXTURE_RE = /\bcamera_texture\b/;
|
|
47
|
+
const RF_VIEWPORT_RE = /\b_rf_vpw\b|\b_rf_vph\b/;
|
|
48
|
+
function materialConfigNeedsTimeUniform(config) {
|
|
49
|
+
if (config.materialUniforms?.some((u) => u.name === "time"))
|
|
50
|
+
return true;
|
|
51
|
+
return collectShaderModifierStrings(config).some((s) => TIME_WORD_RE.test(s));
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* True if the shader uses _rf_vpw/_rf_vph viewport uniforms.
|
|
55
|
+
* These must be pushed via ViroMaterials.updateShaderUniform on mount and orientation change.
|
|
56
|
+
*/
|
|
57
|
+
function materialConfigNeedsViewportUniforms(config) {
|
|
58
|
+
return collectShaderModifierStrings(config).some((s) => RF_VIEWPORT_RE.test(s));
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Prepends GLSL uniform declarations that the body references but the uniforms block omits.
|
|
62
|
+
* Required when shaders are authored for remote delivery without explicit sampler declarations.
|
|
63
|
+
*/
|
|
64
|
+
function injectMissingGlslDeclarations(uniforms, body) {
|
|
65
|
+
let result = uniforms;
|
|
66
|
+
if (CAMERA_TEXTURE_RE.test(body) && !CAMERA_TEXTURE_RE.test(result)) {
|
|
67
|
+
result =
|
|
68
|
+
"uniform sampler2D camera_texture;\nuniform highp mat4 camera_image_transform;\n" +
|
|
69
|
+
result;
|
|
70
|
+
}
|
|
71
|
+
if (RF_VIEWPORT_RE.test(body) && !/\b_rf_vpw\b/.test(result)) {
|
|
72
|
+
result = "uniform highp float _rf_vpw;\nuniform highp float _rf_vph;\n" + result;
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* iOS only applies `ViroMaterials.updateShaderUniform` to uniforms registered
|
|
78
|
+
* via `materialUniforms`. If a shader references `time` or viewport uniforms in
|
|
79
|
+
* GLSL only, we add the runtime binding here.
|
|
80
|
+
*/
|
|
81
|
+
function mergeMaterialUniformsForViro(config) {
|
|
82
|
+
const list = config.materialUniforms
|
|
83
|
+
? config.materialUniforms.map((u) => ({ name: u.name, type: u.type, value: u.value }))
|
|
84
|
+
: [];
|
|
85
|
+
if (materialConfigNeedsTimeUniform(config) && !list.some((u) => u.name === "time")) {
|
|
86
|
+
list.push({ name: "time", type: "float", value: 0 });
|
|
87
|
+
}
|
|
88
|
+
if (materialConfigNeedsViewportUniforms(config)) {
|
|
89
|
+
if (!list.some((u) => u.name === "_rf_vpw"))
|
|
90
|
+
list.push({ name: "_rf_vpw", type: "float", value: 0 });
|
|
91
|
+
if (!list.some((u) => u.name === "_rf_vph"))
|
|
92
|
+
list.push({ name: "_rf_vph", type: "float", value: 0 });
|
|
93
|
+
}
|
|
94
|
+
return list.length > 0 ? list : undefined;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Studio stores modifiers as `{ uniforms, body }`; Viro works best with a single
|
|
98
|
+
* GLSL string per stage. Stages with advanced fields are kept as structured objects.
|
|
99
|
+
* Camera texture usage is detected from GLSL and auto-flagged so the Viro native
|
|
100
|
+
* layer binds the camera feed even when the DB JSON omits `requiresCameraTexture`.
|
|
101
|
+
*/
|
|
102
|
+
function normalizeShaderModifiersForViro(mods) {
|
|
103
|
+
const out = {};
|
|
104
|
+
for (const [key, stage] of Object.entries(mods)) {
|
|
105
|
+
if (typeof stage === "string") {
|
|
106
|
+
out[key] = stage;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (stage && typeof stage === "object") {
|
|
110
|
+
const s = stage;
|
|
111
|
+
const uniforms = typeof s.uniforms === "string" ? s.uniforms : "";
|
|
112
|
+
const body = typeof s.body === "string" ? s.body : "";
|
|
113
|
+
// Detect camera texture usage in GLSL even when the flag is absent from DB JSON.
|
|
114
|
+
const usesCameraTexture = CAMERA_TEXTURE_RE.test(body) || CAMERA_TEXTURE_RE.test(uniforms);
|
|
115
|
+
const hasAdvanced = s.varyings != null ||
|
|
116
|
+
s.requiresSceneDepth === true ||
|
|
117
|
+
s.requiresCameraTexture === true ||
|
|
118
|
+
usesCameraTexture ||
|
|
119
|
+
s.priority != null;
|
|
120
|
+
if (hasAdvanced) {
|
|
121
|
+
if (usesCameraTexture && s.requiresCameraTexture !== true) {
|
|
122
|
+
// Auto-fix: flag the stage and inject any missing GLSL declarations so the
|
|
123
|
+
// native Viro layer binds camera_texture and the shader compiles cleanly.
|
|
124
|
+
out[key] = {
|
|
125
|
+
...s,
|
|
126
|
+
requiresCameraTexture: true,
|
|
127
|
+
uniforms: injectMissingGlslDeclarations(uniforms, body),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
out[key] = stage;
|
|
132
|
+
}
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
const merged = [uniforms.trim(), body.trim()].filter(Boolean).join("\n");
|
|
136
|
+
out[key] = merged.length > 0 ? merged : stage;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return out;
|
|
140
|
+
}
|
|
141
|
+
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
142
|
+
function studioMaterialName(assetId) {
|
|
143
|
+
return `studio_${assetId}`;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Parses `scene_assets.material_config` JSON. Returns null if missing or invalid.
|
|
147
|
+
*/
|
|
148
|
+
function parseMaterialConfig(raw) {
|
|
149
|
+
if (raw == null || typeof raw !== "object" || Array.isArray(raw))
|
|
150
|
+
return null;
|
|
151
|
+
const r = raw;
|
|
152
|
+
try {
|
|
153
|
+
const config = {
|
|
154
|
+
lightingModel: (["Constant", "Lambert", "Blinn", "Phong", "PBR"].includes(r.lightingModel)
|
|
155
|
+
? r.lightingModel
|
|
156
|
+
: "PBR"),
|
|
157
|
+
};
|
|
158
|
+
if (typeof r.presetName === "string")
|
|
159
|
+
config.presetName = r.presetName;
|
|
160
|
+
if (typeof r.diffuseColor === "string")
|
|
161
|
+
config.diffuseColor = r.diffuseColor;
|
|
162
|
+
if (typeof r.roughness === "number")
|
|
163
|
+
config.roughness = r.roughness;
|
|
164
|
+
if (typeof r.metalness === "number")
|
|
165
|
+
config.metalness = r.metalness;
|
|
166
|
+
if (typeof r.shininess === "number")
|
|
167
|
+
config.shininess = r.shininess;
|
|
168
|
+
if (typeof r.alpha === "number")
|
|
169
|
+
config.alpha = r.alpha;
|
|
170
|
+
if (typeof r.blendMode === "string")
|
|
171
|
+
config.blendMode = r.blendMode;
|
|
172
|
+
if (r.bloomThreshold != null && typeof r.bloomThreshold === "number")
|
|
173
|
+
config.bloomThreshold = r.bloomThreshold;
|
|
174
|
+
if (["Clamp", "Repeat", "Mirror"].includes(r.wrapS))
|
|
175
|
+
config.wrapS = r.wrapS;
|
|
176
|
+
if (["Clamp", "Repeat", "Mirror"].includes(r.wrapT))
|
|
177
|
+
config.wrapT = r.wrapT;
|
|
178
|
+
if (typeof r.transparencyMode === "string")
|
|
179
|
+
config.transparencyMode = r.transparencyMode;
|
|
180
|
+
if (typeof r.cullMode === "string")
|
|
181
|
+
config.cullMode = r.cullMode;
|
|
182
|
+
for (const key of TEXTURE_KEYS) {
|
|
183
|
+
const v = r[key];
|
|
184
|
+
if (typeof v === "string" || v === null)
|
|
185
|
+
config[key] = v;
|
|
186
|
+
}
|
|
187
|
+
if (r.shaderModifiers && typeof r.shaderModifiers === "object" && !Array.isArray(r.shaderModifiers)) {
|
|
188
|
+
config.shaderModifiers = r.shaderModifiers;
|
|
189
|
+
}
|
|
190
|
+
if (Array.isArray(r.materialUniforms)) {
|
|
191
|
+
config.materialUniforms = r.materialUniforms.filter((u) => u && typeof u.name === "string" && typeof u.type === "string");
|
|
192
|
+
}
|
|
193
|
+
return config;
|
|
194
|
+
}
|
|
195
|
+
catch (e) {
|
|
196
|
+
console.warn("[material_config] Failed to parse material_config", e);
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Maps a validated Studio material_config to Viro's `createMaterials` definition shape.
|
|
202
|
+
*/
|
|
203
|
+
function buildViroMaterialDefinition(config) {
|
|
204
|
+
const out = { lightingModel: config.lightingModel };
|
|
205
|
+
if (config.diffuseColor !== undefined)
|
|
206
|
+
out.diffuseColor = config.diffuseColor;
|
|
207
|
+
if (config.roughness !== undefined)
|
|
208
|
+
out.roughness = config.roughness;
|
|
209
|
+
if (config.metalness !== undefined)
|
|
210
|
+
out.metalness = config.metalness;
|
|
211
|
+
if (config.shininess !== undefined)
|
|
212
|
+
out.shininess = config.shininess;
|
|
213
|
+
if (config.alpha !== undefined)
|
|
214
|
+
out.alpha = config.alpha;
|
|
215
|
+
if (config.blendMode !== undefined)
|
|
216
|
+
out.blendMode = config.blendMode;
|
|
217
|
+
if (config.bloomThreshold != undefined)
|
|
218
|
+
out.bloomThreshold = config.bloomThreshold;
|
|
219
|
+
if (config.wrapS !== undefined)
|
|
220
|
+
out.wrapS = config.wrapS;
|
|
221
|
+
if (config.wrapT !== undefined)
|
|
222
|
+
out.wrapT = config.wrapT;
|
|
223
|
+
if (config.transparencyMode !== undefined)
|
|
224
|
+
out.transparencyMode = config.transparencyMode;
|
|
225
|
+
if (config.cullMode !== undefined)
|
|
226
|
+
out.cullMode = config.cullMode;
|
|
227
|
+
for (const key of TEXTURE_KEYS) {
|
|
228
|
+
const mapped = textureToViro(config[key]);
|
|
229
|
+
if (mapped !== undefined)
|
|
230
|
+
out[key] = mapped;
|
|
231
|
+
}
|
|
232
|
+
if (config.shaderModifiers !== undefined) {
|
|
233
|
+
out.shaderModifiers = normalizeShaderModifiersForViro(config.shaderModifiers);
|
|
234
|
+
}
|
|
235
|
+
const mergedUniforms = mergeMaterialUniformsForViro(config);
|
|
236
|
+
if (mergedUniforms !== undefined)
|
|
237
|
+
out.materialUniforms = mergedUniforms;
|
|
238
|
+
return out;
|
|
239
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Studio physics_config and physics_world_config parsing and Viro prop building.
|
|
3
|
+
* Ported from studio-go/domain/physicsConfig.ts — no zod dependency.
|
|
4
|
+
*/
|
|
5
|
+
type Vec3 = [number, number, number];
|
|
6
|
+
type ForceEntry = {
|
|
7
|
+
value: Vec3;
|
|
8
|
+
position?: Vec3;
|
|
9
|
+
};
|
|
10
|
+
type PhysicsShape = {
|
|
11
|
+
type: "Box";
|
|
12
|
+
params: [number, number, number];
|
|
13
|
+
} | {
|
|
14
|
+
type: "Sphere";
|
|
15
|
+
params: [number];
|
|
16
|
+
} | {
|
|
17
|
+
type: "Compound";
|
|
18
|
+
children: Array<{
|
|
19
|
+
type: "Box" | "Sphere";
|
|
20
|
+
params: number[];
|
|
21
|
+
position: Vec3;
|
|
22
|
+
rotation?: Vec3;
|
|
23
|
+
}>;
|
|
24
|
+
};
|
|
25
|
+
export type PhysicsBodyConfig = {
|
|
26
|
+
enabled: boolean;
|
|
27
|
+
type: "Dynamic" | "Kinematic" | "Static";
|
|
28
|
+
mass: number;
|
|
29
|
+
shape?: PhysicsShape;
|
|
30
|
+
restitution?: number;
|
|
31
|
+
friction?: number;
|
|
32
|
+
useGravity?: boolean;
|
|
33
|
+
viroTag?: string;
|
|
34
|
+
force?: ForceEntry | ForceEntry[];
|
|
35
|
+
torque?: Vec3 | Vec3[];
|
|
36
|
+
velocity?: Vec3;
|
|
37
|
+
};
|
|
38
|
+
export type PhysicsWorldConfig = {
|
|
39
|
+
enabled: boolean;
|
|
40
|
+
gravity: Vec3;
|
|
41
|
+
drawBounds: boolean;
|
|
42
|
+
};
|
|
43
|
+
export type BuildViroPhysicsBodyOptions = {
|
|
44
|
+
/** Forces Dynamic body to Kinematic with mass 0 while dragging. */
|
|
45
|
+
kinematicDragOverride?: boolean;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Parses `scene.physics_world_config` JSON. Returns null if missing or invalid.
|
|
49
|
+
*/
|
|
50
|
+
export declare function parsePhysicsWorldConfig(raw: unknown): PhysicsWorldConfig | null;
|
|
51
|
+
/**
|
|
52
|
+
* Parses `asset.physics_config` JSON. Returns null if missing or invalid.
|
|
53
|
+
*/
|
|
54
|
+
export declare function parsePhysicsBodyConfig(raw: unknown): PhysicsBodyConfig | null;
|
|
55
|
+
/** Viro `ViroARScene` physicsWorld prop. */
|
|
56
|
+
export declare function buildViroPhysicsWorld(config: PhysicsWorldConfig): {
|
|
57
|
+
gravity: Vec3;
|
|
58
|
+
drawBounds?: boolean;
|
|
59
|
+
};
|
|
60
|
+
/** Maps validated Studio physics_config to Viro `physicsBody` prop. */
|
|
61
|
+
export declare function buildViroPhysicsBody(config: PhysicsBodyConfig, options?: BuildViroPhysicsBodyOptions): Record<string, unknown>;
|
|
62
|
+
/**
|
|
63
|
+
* Draggable Dynamic bodies need kinematic override during drag so the simulation
|
|
64
|
+
* doesn't fight the gesture.
|
|
65
|
+
*/
|
|
66
|
+
export declare function shouldUseKinematicPhysicsDrag(asset: {
|
|
67
|
+
is_draggable: boolean;
|
|
68
|
+
}, config: PhysicsBodyConfig | null): boolean;
|
|
69
|
+
export {};
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Studio physics_config and physics_world_config parsing and Viro prop building.
|
|
4
|
+
* Ported from studio-go/domain/physicsConfig.ts — no zod dependency.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.parsePhysicsWorldConfig = parsePhysicsWorldConfig;
|
|
8
|
+
exports.parsePhysicsBodyConfig = parsePhysicsBodyConfig;
|
|
9
|
+
exports.buildViroPhysicsWorld = buildViroPhysicsWorld;
|
|
10
|
+
exports.buildViroPhysicsBody = buildViroPhysicsBody;
|
|
11
|
+
exports.shouldUseKinematicPhysicsDrag = shouldUseKinematicPhysicsDrag;
|
|
12
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
13
|
+
function isVec3(v) {
|
|
14
|
+
return Array.isArray(v) && v.length === 3 && v.every((n) => typeof n === "number");
|
|
15
|
+
}
|
|
16
|
+
function parseShape(raw) {
|
|
17
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
18
|
+
return undefined;
|
|
19
|
+
const r = raw;
|
|
20
|
+
if (r.type === "Box" && Array.isArray(r.params) && r.params.length === 3) {
|
|
21
|
+
return { type: "Box", params: r.params };
|
|
22
|
+
}
|
|
23
|
+
if (r.type === "Sphere" && Array.isArray(r.params) && r.params.length >= 1) {
|
|
24
|
+
return { type: "Sphere", params: [r.params[0]] };
|
|
25
|
+
}
|
|
26
|
+
if (r.type === "Compound" && Array.isArray(r.children)) {
|
|
27
|
+
const children = r.children.filter((c) => {
|
|
28
|
+
if (!c || typeof c !== "object")
|
|
29
|
+
return false;
|
|
30
|
+
const ch = c;
|
|
31
|
+
return (ch.type === "Box" || ch.type === "Sphere") && Array.isArray(ch.params) && isVec3(ch.position);
|
|
32
|
+
});
|
|
33
|
+
if (children.length > 0)
|
|
34
|
+
return { type: "Compound", children };
|
|
35
|
+
}
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
function mapShapeToViro(shape) {
|
|
39
|
+
if (shape.type === "Box")
|
|
40
|
+
return { type: "Box", params: [...shape.params] };
|
|
41
|
+
if (shape.type === "Sphere")
|
|
42
|
+
return { type: "Sphere", params: [...shape.params] };
|
|
43
|
+
return {
|
|
44
|
+
type: "Compound",
|
|
45
|
+
params: [],
|
|
46
|
+
children: shape.children.map((c) => {
|
|
47
|
+
const base = { type: c.type, params: [...c.params], position: [...c.position] };
|
|
48
|
+
if (c.rotation)
|
|
49
|
+
base.rotation = [...c.rotation];
|
|
50
|
+
return base;
|
|
51
|
+
}),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function normalizeTorque(torque) {
|
|
55
|
+
if (Array.isArray(torque[0])) {
|
|
56
|
+
return torque.reduce((acc, t) => [acc[0] + t[0], acc[1] + t[1], acc[2] + t[2]], [0, 0, 0]);
|
|
57
|
+
}
|
|
58
|
+
return [...torque];
|
|
59
|
+
}
|
|
60
|
+
function normalizeForce(force) {
|
|
61
|
+
const arr = Array.isArray(force) ? force : [force];
|
|
62
|
+
return arr.map((f) => ({
|
|
63
|
+
value: [...f.value],
|
|
64
|
+
position: f.position != null ? [...f.position] : undefined,
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
68
|
+
/**
|
|
69
|
+
* Parses `scene.physics_world_config` JSON. Returns null if missing or invalid.
|
|
70
|
+
*/
|
|
71
|
+
function parsePhysicsWorldConfig(raw) {
|
|
72
|
+
if (raw == null || typeof raw !== "object" || Array.isArray(raw))
|
|
73
|
+
return null;
|
|
74
|
+
const r = raw;
|
|
75
|
+
try {
|
|
76
|
+
return {
|
|
77
|
+
enabled: typeof r.enabled === "boolean" ? r.enabled : false,
|
|
78
|
+
gravity: isVec3(r.gravity) ? r.gravity : [0, -9.8, 0],
|
|
79
|
+
drawBounds: typeof r.drawBounds === "boolean" ? r.drawBounds : false,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Parses `asset.physics_config` JSON. Returns null if missing or invalid.
|
|
88
|
+
*/
|
|
89
|
+
function parsePhysicsBodyConfig(raw) {
|
|
90
|
+
if (raw == null || typeof raw !== "object" || Array.isArray(raw))
|
|
91
|
+
return null;
|
|
92
|
+
const r = raw;
|
|
93
|
+
try {
|
|
94
|
+
const type = (["Dynamic", "Kinematic", "Static"].includes(r.type)
|
|
95
|
+
? r.type
|
|
96
|
+
: undefined);
|
|
97
|
+
if (!type)
|
|
98
|
+
return null;
|
|
99
|
+
const mass = typeof r.mass === "number" ? r.mass : 0;
|
|
100
|
+
const config = {
|
|
101
|
+
enabled: typeof r.enabled === "boolean" ? r.enabled : true,
|
|
102
|
+
type,
|
|
103
|
+
mass,
|
|
104
|
+
};
|
|
105
|
+
const shape = parseShape(r.shape);
|
|
106
|
+
if (shape)
|
|
107
|
+
config.shape = shape;
|
|
108
|
+
if (typeof r.restitution === "number")
|
|
109
|
+
config.restitution = r.restitution;
|
|
110
|
+
if (typeof r.friction === "number")
|
|
111
|
+
config.friction = r.friction;
|
|
112
|
+
if (typeof r.useGravity === "boolean")
|
|
113
|
+
config.useGravity = r.useGravity;
|
|
114
|
+
if (typeof r.viroTag === "string")
|
|
115
|
+
config.viroTag = r.viroTag;
|
|
116
|
+
if (isVec3(r.velocity))
|
|
117
|
+
config.velocity = r.velocity;
|
|
118
|
+
if (r.torque != null)
|
|
119
|
+
config.torque = r.torque;
|
|
120
|
+
if (r.force != null)
|
|
121
|
+
config.force = r.force;
|
|
122
|
+
return config;
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/** Viro `ViroARScene` physicsWorld prop. */
|
|
129
|
+
function buildViroPhysicsWorld(config) {
|
|
130
|
+
return {
|
|
131
|
+
gravity: [...config.gravity],
|
|
132
|
+
...(config.drawBounds ? { drawBounds: true } : {}),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
/** Maps validated Studio physics_config to Viro `physicsBody` prop. */
|
|
136
|
+
function buildViroPhysicsBody(config, options) {
|
|
137
|
+
const kinematicDrag = options?.kinematicDragOverride === true && config.type === "Dynamic" && config.enabled;
|
|
138
|
+
const type = kinematicDrag ? "Kinematic" : config.type;
|
|
139
|
+
const mass = kinematicDrag ? 0 : config.mass;
|
|
140
|
+
const shape = mapShapeToViro(config.shape ?? { type: "Box", params: [1, 1, 1] });
|
|
141
|
+
const body = { type, mass, shape, enabled: config.enabled };
|
|
142
|
+
if (config.restitution !== undefined)
|
|
143
|
+
body.restitution = config.restitution;
|
|
144
|
+
if (config.friction !== undefined)
|
|
145
|
+
body.friction = config.friction;
|
|
146
|
+
if (config.useGravity !== undefined)
|
|
147
|
+
body.useGravity = kinematicDrag ? false : config.useGravity;
|
|
148
|
+
if (config.velocity !== undefined)
|
|
149
|
+
body.velocity = [...config.velocity];
|
|
150
|
+
if (config.torque !== undefined)
|
|
151
|
+
body.torque = normalizeTorque(config.torque);
|
|
152
|
+
if (config.force !== undefined)
|
|
153
|
+
body.force = normalizeForce(config.force);
|
|
154
|
+
return body;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Draggable Dynamic bodies need kinematic override during drag so the simulation
|
|
158
|
+
* doesn't fight the gesture.
|
|
159
|
+
*/
|
|
160
|
+
function shouldUseKinematicPhysicsDrag(asset, config) {
|
|
161
|
+
return (asset.is_draggable === true &&
|
|
162
|
+
config != null &&
|
|
163
|
+
config.enabled === true &&
|
|
164
|
+
config.type === "Dynamic");
|
|
165
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { StudioAnimation, StudioSceneFunction } from "../types";
|
|
2
|
+
type SceneNavigator = any;
|
|
3
|
+
/**
|
|
4
|
+
* Single dispatcher for all scene function types.
|
|
5
|
+
* Used by onClick, onCollision, and on_load_function triggers.
|
|
6
|
+
*/
|
|
7
|
+
export declare function executeFunctionWithRelations(fn: StudioSceneFunction, sceneNavigator: SceneNavigator | undefined, animations: StudioAnimation[], onAnimationTrigger?: (targetAssetId: string, animationKey: string) => void, depth?: number, onSceneChange?: (sceneId: string, sceneName: string) => void): void;
|
|
8
|
+
/**
|
|
9
|
+
* Executes the scene's on_load_function if set.
|
|
10
|
+
*/
|
|
11
|
+
export declare function executeOnLoadFunction(functionId: string, functions: StudioSceneFunction[], sceneNavigator: SceneNavigator | undefined, animations: StudioAnimation[], onAnimationTrigger?: (targetAssetId: string, animationKey: string) => void, onSceneChange?: (sceneId: string, sceneName: string) => void): void;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.executeFunctionWithRelations = executeFunctionWithRelations;
|
|
4
|
+
exports.executeOnLoadFunction = executeOnLoadFunction;
|
|
5
|
+
const react_native_1 = require("react-native");
|
|
6
|
+
const ViroPlatform_1 = require("../../Utilities/ViroPlatform");
|
|
7
|
+
const VRTStudioModule_1 = require("../VRTStudioModule");
|
|
8
|
+
const ANIMATION_CHAIN_MAX_DEPTH = 10;
|
|
9
|
+
/**
|
|
10
|
+
* Resolves a scene function by ID from a flat list.
|
|
11
|
+
*/
|
|
12
|
+
function resolveById(id, fns) {
|
|
13
|
+
return fns.find((f) => f.id === id);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Looks up target_asset_id for an ANIMATION-type scene function.
|
|
17
|
+
* The inline scene_animation only has the animation UUID — we resolve it
|
|
18
|
+
* from the top-level animations array.
|
|
19
|
+
*/
|
|
20
|
+
function resolveAnimationTargetAssetId(animationId, animations) {
|
|
21
|
+
return animations.find((a) => a.id === animationId)?.target_asset_id;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Single dispatcher for all scene function types.
|
|
25
|
+
* Used by onClick, onCollision, and on_load_function triggers.
|
|
26
|
+
*/
|
|
27
|
+
function executeFunctionWithRelations(fn, sceneNavigator, animations, onAnimationTrigger, depth = 0, onSceneChange) {
|
|
28
|
+
if (depth > ANIMATION_CHAIN_MAX_DEPTH) {
|
|
29
|
+
console.warn(`[Studio] Max animation chain depth (${ANIMATION_CHAIN_MAX_DEPTH}) exceeded for function ${fn.id}.`);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (fn.function_type === "NAVIGATION") {
|
|
33
|
+
const nav = fn.scene_navigation;
|
|
34
|
+
if (!nav?.navigate_to || !sceneNavigator)
|
|
35
|
+
return;
|
|
36
|
+
void navigateToScene(sceneNavigator, nav.navigate_to, animations, onSceneChange);
|
|
37
|
+
}
|
|
38
|
+
else if (fn.function_type === "ALERT") {
|
|
39
|
+
const alrt = fn.scene_alert;
|
|
40
|
+
if (!alrt)
|
|
41
|
+
return;
|
|
42
|
+
if (ViroPlatform_1.isQuest) {
|
|
43
|
+
// Alert.alert shows a 2D panel dialog — invisible in the VR compositor.
|
|
44
|
+
// Log it so it's not silently swallowed; in-scene VR alert UI is a TODO.
|
|
45
|
+
console.warn(`[Studio] Alert (Quest — not shown in VR): "${alrt.alert_title}" — ${alrt.alert_message}`);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
react_native_1.Alert.alert(alrt.alert_title ?? "Alert", alrt.alert_message ?? "", [
|
|
49
|
+
{ text: "OK", style: "default" },
|
|
50
|
+
]);
|
|
51
|
+
}
|
|
52
|
+
else if (fn.function_type === "ANIMATION") {
|
|
53
|
+
const anim = fn.scene_animation;
|
|
54
|
+
if (!anim || !onAnimationTrigger)
|
|
55
|
+
return;
|
|
56
|
+
const animLookupId = fn.animation ?? anim.id;
|
|
57
|
+
const targetAssetId = resolveAnimationTargetAssetId(animLookupId, animations);
|
|
58
|
+
if (!targetAssetId) {
|
|
59
|
+
console.warn(`[Studio] ANIMATION function ${fn.id}: could not resolve target_asset_id for animation ${anim.id}`);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
onAnimationTrigger(targetAssetId, anim.animation_key);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Executes the scene's on_load_function if set.
|
|
67
|
+
*/
|
|
68
|
+
function executeOnLoadFunction(functionId, functions, sceneNavigator, animations, onAnimationTrigger, onSceneChange) {
|
|
69
|
+
const fn = resolveById(functionId, functions);
|
|
70
|
+
if (!fn) {
|
|
71
|
+
console.warn(`[Studio] on_load_function ${functionId} not found.`);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
executeFunctionWithRelations(fn, sceneNavigator, animations, onAnimationTrigger, 0, onSceneChange);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Navigates to a new AR scene by fetching its data via rvGetScene and
|
|
78
|
+
* pushing it onto the ViroARSceneNavigator stack.
|
|
79
|
+
*
|
|
80
|
+
* The sceneNavigator object exposes rvGetScene as a method — no separate
|
|
81
|
+
* API client needed here.
|
|
82
|
+
*/
|
|
83
|
+
async function navigateToScene(sceneNavigator, targetSceneId, currentAnimations, onSceneChange) {
|
|
84
|
+
if (!sceneNavigator) {
|
|
85
|
+
console.error("[Studio] SceneNavigator not available for navigation");
|
|
86
|
+
react_native_1.Alert.alert("Navigation Error", "Unable to navigate to scene");
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
console.log(`[Studio] Navigating to scene: ${targetSceneId}`);
|
|
90
|
+
try {
|
|
91
|
+
const result = await VRTStudioModule_1.VRTStudioModule.rvGetScene(targetSceneId);
|
|
92
|
+
if (!result?.success) {
|
|
93
|
+
throw new Error(result?.error ?? "rvGetScene failed");
|
|
94
|
+
}
|
|
95
|
+
const sceneData = JSON.parse(result.data);
|
|
96
|
+
// Lazy import to avoid circular dependency
|
|
97
|
+
const { StudioARScene } = require("../StudioARScene");
|
|
98
|
+
sceneNavigator.push({
|
|
99
|
+
scene: StudioARScene,
|
|
100
|
+
passProps: {
|
|
101
|
+
sceneData,
|
|
102
|
+
onSceneChange,
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
onSceneChange?.(targetSceneId, sceneData.scene.name ?? targetSceneId);
|
|
106
|
+
console.log(`[Studio] Navigated to scene: ${sceneData.scene.name}`);
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
console.error("[Studio] Error navigating to scene:", error);
|
|
110
|
+
react_native_1.Alert.alert("Navigation Error", "Failed to load scene");
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { StudioAsset } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Registers Viro materials for scene assets that have a valid `material_config`.
|
|
4
|
+
* Call synchronously after fetching assets and before rendering AR nodes.
|
|
5
|
+
*/
|
|
6
|
+
export declare function registerStudioMaterialsForAssets(assets: StudioAsset[]): void;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerStudioMaterialsForAssets = registerStudioMaterialsForAssets;
|
|
4
|
+
const ViroMaterials_1 = require("../../Material/ViroMaterials");
|
|
5
|
+
const materialConfig_1 = require("./materialConfig");
|
|
6
|
+
/**
|
|
7
|
+
* Registers Viro materials for scene assets that have a valid `material_config`.
|
|
8
|
+
* Call synchronously after fetching assets and before rendering AR nodes.
|
|
9
|
+
*/
|
|
10
|
+
function registerStudioMaterialsForAssets(assets) {
|
|
11
|
+
const materials = {};
|
|
12
|
+
for (const asset of assets) {
|
|
13
|
+
if (asset.asset_type_name !== "3D-MODEL")
|
|
14
|
+
continue;
|
|
15
|
+
if (asset.material_config == null)
|
|
16
|
+
continue;
|
|
17
|
+
const config = (0, materialConfig_1.parseMaterialConfig)(asset.material_config);
|
|
18
|
+
if (!config)
|
|
19
|
+
continue;
|
|
20
|
+
materials[(0, materialConfig_1.studioMaterialName)(asset.id)] = (0, materialConfig_1.buildViroMaterialDefinition)(config);
|
|
21
|
+
}
|
|
22
|
+
if (Object.keys(materials).length === 0)
|
|
23
|
+
return;
|
|
24
|
+
try {
|
|
25
|
+
ViroMaterials_1.ViroMaterials.createMaterials(materials);
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
console.error("[studioMaterials] ViroMaterials.createMaterials failed", err);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { StudioAsset } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Registers trigger image targets with ViroReact for image recognition.
|
|
4
|
+
* One target per asset with trigger_image_url.
|
|
5
|
+
* Must be called before rendering ViroARImageMarker components.
|
|
6
|
+
*
|
|
7
|
+
* @returns Map from trigger_image_url → target name for lookup in ViroARImageMarker
|
|
8
|
+
*/
|
|
9
|
+
export declare function registerTriggerImageTargets(assets: StudioAsset[]): Map<string, string>;
|
|
10
|
+
/**
|
|
11
|
+
* Cleans up trigger image targets when the scene unmounts.
|
|
12
|
+
*/
|
|
13
|
+
export declare function cleanupTriggerImageTargets(targetNames: string[]): void;
|