@reactvision/react-viro 2.56.0 → 2.57.2
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 +8 -0
- package/android/react_viro/react_viro-release.aar +0 -0
- package/android/viro_renderer/viro_renderer-release.aar +0 -0
- package/components/AR/ViroARPlane.tsx +1 -4
- package/components/AR/ViroARPlaneSelector.tsx +10 -5
- package/components/AR/ViroARScene.tsx +19 -4
- package/components/Studio/StudioARScene.tsx +243 -48
- package/components/Studio/StudioSceneNavigator.tsx +15 -0
- package/components/Studio/VRTStudioModule.ts +10 -0
- package/components/Studio/domain/StudioSounds.tsx +46 -0
- package/components/Studio/domain/apiRequestHelpers.ts +612 -0
- package/components/Studio/domain/collisionBindingsRuntime.ts +17 -2
- package/components/Studio/domain/defaultApiRequestExecutor.ts +61 -0
- package/components/Studio/domain/expressionEvaluator.ts +603 -0
- package/components/Studio/domain/sceneNavigationHandler.ts +770 -20
- package/components/Studio/domain/soundManager.ts +141 -0
- package/components/Studio/domain/utils.ts +50 -0
- package/components/Studio/domain/variableStore.ts +74 -0
- package/components/Studio/domain/viroNodeFactory.tsx +175 -44
- package/components/Studio/domain/visibilityStore.ts +66 -0
- package/components/Studio/index.ts +1 -0
- package/components/Studio/types.ts +178 -1
- package/components/Utilities/VRModuleOpenXR.ts +35 -0
- package/components/Utilities/ViroVersion.ts +1 -1
- package/components/ViroAnimatedImage.tsx +1 -0
- package/components/ViroFlexView.tsx +1 -0
- package/components/ViroImage.tsx +1 -0
- package/components/ViroObjectDetector.tsx +230 -0
- package/components/ViroParticleEmitter.tsx +2 -0
- package/components/ViroPolygon.tsx +2 -1
- package/components/ViroQuad.tsx +2 -1
- package/components/ViroSurface.tsx +1 -0
- package/components/ViroVideo.tsx +1 -0
- package/components/ViroXRSceneNavigator.tsx +8 -0
- package/dist/components/AR/ViroARPlane.d.ts +1 -1
- package/dist/components/AR/ViroARPlane.js +1 -5
- package/dist/components/AR/ViroARPlaneSelector.d.ts +1 -1
- package/dist/components/AR/ViroARPlaneSelector.js +10 -5
- package/dist/components/AR/ViroARScene.d.ts +13 -1
- package/dist/components/AR/ViroARScene.js +10 -6
- package/dist/components/Studio/StudioARScene.d.ts +3 -0
- package/dist/components/Studio/StudioARScene.js +142 -15
- package/dist/components/Studio/StudioSceneNavigator.js +14 -0
- package/dist/components/Studio/VRTStudioModule.d.ts +6 -0
- package/dist/components/Studio/VRTStudioModule.js +10 -0
- package/dist/components/Studio/domain/StudioSounds.d.ts +11 -0
- package/dist/components/Studio/domain/StudioSounds.js +69 -0
- package/dist/components/Studio/domain/apiRequestHelpers.d.ts +180 -0
- package/dist/components/Studio/domain/apiRequestHelpers.js +496 -0
- package/dist/components/Studio/domain/collisionBindingsRuntime.d.ts +3 -1
- package/dist/components/Studio/domain/collisionBindingsRuntime.js +4 -3
- package/dist/components/Studio/domain/defaultApiRequestExecutor.d.ts +14 -0
- package/dist/components/Studio/domain/defaultApiRequestExecutor.js +58 -0
- package/dist/components/Studio/domain/expressionEvaluator.d.ts +108 -0
- package/dist/components/Studio/domain/expressionEvaluator.js +520 -0
- package/dist/components/Studio/domain/sceneNavigationHandler.d.ts +35 -8
- package/dist/components/Studio/domain/sceneNavigationHandler.js +564 -22
- package/dist/components/Studio/domain/soundManager.d.ts +52 -0
- package/dist/components/Studio/domain/soundManager.js +118 -0
- package/dist/components/Studio/domain/utils.d.ts +16 -0
- package/dist/components/Studio/domain/utils.js +48 -0
- package/dist/components/Studio/domain/variableStore.d.ts +21 -0
- package/dist/components/Studio/domain/variableStore.js +65 -0
- package/dist/components/Studio/domain/viroNodeFactory.d.ts +4 -9
- package/dist/components/Studio/domain/viroNodeFactory.js +84 -25
- package/dist/components/Studio/domain/visibilityStore.d.ts +33 -0
- package/dist/components/Studio/domain/visibilityStore.js +66 -0
- package/dist/components/Studio/index.d.ts +1 -1
- package/dist/components/Studio/types.d.ts +150 -1
- package/dist/components/Utilities/VRModuleOpenXR.d.ts +19 -0
- package/dist/components/Utilities/VRModuleOpenXR.js +16 -0
- package/dist/components/Utilities/ViroVersion.d.ts +1 -1
- package/dist/components/Utilities/ViroVersion.js +1 -1
- package/dist/components/ViroAnimatedImage.js +1 -0
- package/dist/components/ViroFlexView.js +1 -0
- package/dist/components/ViroImage.js +1 -0
- package/dist/components/ViroObjectDetector.d.ts +146 -0
- package/dist/components/ViroObjectDetector.js +93 -0
- package/dist/components/ViroParticleEmitter.js +2 -0
- package/dist/components/ViroPolygon.js +1 -0
- package/dist/components/ViroQuad.js +1 -0
- package/dist/components/ViroSurface.js +1 -0
- package/dist/components/ViroVideo.js +1 -0
- package/dist/components/ViroXRSceneNavigator.d.ts +8 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +5 -2
- package/dist/plugins/withViro.js +2 -15
- package/dist/plugins/withViroAndroid.js +18 -5
- package/dist/plugins/withViroIos.js +0 -6
- package/index.ts +7 -3
- package/ios/ViroReact.podspec +25 -6
- 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/VROARFrameiOS.h +9 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROARScene.h +14 -1
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROARSceneDelegateiOS.h +8 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROGLTFLoader.h +5 -1
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROMonocularDepthEstimator.h +10 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROObjectDetector.h +134 -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/ViroRendererVisionOS/ViroKit.podspec +27 -0
- package/ios/dist/include/VRTARScene.h +1 -0
- package/ios/dist/lib/libViroReact.a +0 -0
- package/package.json +17 -20
|
@@ -47,7 +47,6 @@ exports.ViroARPlane = void 0;
|
|
|
47
47
|
const ViroBase_1 = require("../ViroBase");
|
|
48
48
|
const React = __importStar(require("react"));
|
|
49
49
|
const react_native_1 = require("react-native");
|
|
50
|
-
const ViroPlatform_1 = require("../Utilities/ViroPlatform");
|
|
51
50
|
/**
|
|
52
51
|
* Container for Viro Components anchored to a detected plane.
|
|
53
52
|
*/
|
|
@@ -68,10 +67,7 @@ class ViroARPlane extends ViroBase_1.ViroBase {
|
|
|
68
67
|
}
|
|
69
68
|
};
|
|
70
69
|
render() {
|
|
71
|
-
|
|
72
|
-
console.warn("[Viro] ViroARPlane is not supported on Quest and will not render.");
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
70
|
+
// Supported on Quest via XR_FB_scene plane anchors (room model). No longer gated.
|
|
75
71
|
// Uncomment this line to check for misnamed props
|
|
76
72
|
//checkMisnamedProps("ViroARPlane", this.props);
|
|
77
73
|
let timeToFuse = undefined;
|
|
@@ -293,7 +293,7 @@ export declare class ViroARPlaneSelector extends React.Component<Props, State> {
|
|
|
293
293
|
*/
|
|
294
294
|
_worldToLocal: (world: [number, number, number], anchorPosition: [number, number, number], rotationDeg: [number, number, number]) => [number, number, number];
|
|
295
295
|
_passesAlignmentFilter: (anchor: ViroAnchor) => boolean;
|
|
296
|
-
render(): React.JSX.Element
|
|
296
|
+
render(): React.JSX.Element;
|
|
297
297
|
_renderPlanes(): React.JSX.Element[];
|
|
298
298
|
}
|
|
299
299
|
export {};
|
|
@@ -285,10 +285,7 @@ class ViroARPlaneSelector extends React.Component {
|
|
|
285
285
|
// Render
|
|
286
286
|
// ---------------------------------------------------------------------------
|
|
287
287
|
render() {
|
|
288
|
-
|
|
289
|
-
console.warn("[Viro] ViroARPlaneSelector is not supported on Quest and will not render.");
|
|
290
|
-
return null;
|
|
291
|
-
}
|
|
288
|
+
// Supported on Quest via XR_FB_scene plane anchors (room model). No longer gated.
|
|
292
289
|
return <ViroNode_1.ViroNode>{this._renderPlanes()}</ViroNode_1.ViroNode>;
|
|
293
290
|
}
|
|
294
291
|
_renderPlanes() {
|
|
@@ -351,6 +348,14 @@ ViroMaterials_1.ViroMaterials.createMaterials({
|
|
|
351
348
|
diffuseColor: "rgba(0, 122, 255, 0.5)",
|
|
352
349
|
blendMode: "Alpha",
|
|
353
350
|
cullMode: "None",
|
|
354
|
-
|
|
351
|
+
// Phone: don't write depth, so overlapping/coplanar overlays blend cleanly.
|
|
352
|
+
// Quest: WRITE depth. On Quest's tiled GPU, many non-depth-writing transparent
|
|
353
|
+
// draws break the second (right) eye's render entirely — the whole eye goes
|
|
354
|
+
// black/garbage. Writing depth avoids that path and renders correctly in both
|
|
355
|
+
// eyes (device-confirmed). The plane overlays don't overlap, so depth-writing
|
|
356
|
+
// has no visible downside here. (Engine-level bug — non-depth-writing
|
|
357
|
+
// transparency at quantity breaking stereo — tracked in virocore
|
|
358
|
+
// VROGeometry::updateSubstrate notes / QUEST_SETUP.md.)
|
|
359
|
+
writesToDepthBuffer: ViroPlatform_1.isQuest,
|
|
355
360
|
},
|
|
356
361
|
});
|
|
@@ -17,6 +17,14 @@ type Props = ViroCommonProps & {
|
|
|
17
17
|
onTrackingUpdated?: (state: ViroTrackingState, reason: ViroTrackingReason) => void;
|
|
18
18
|
onPlatformUpdate?: (platformInfoViro: ViroPlatformInfo) => void;
|
|
19
19
|
onAmbientLightUpdate?: (update: ViroAmbientLightInfo) => void;
|
|
20
|
+
/**
|
|
21
|
+
* Fired once when depth data (LiDAR or monocular depth estimation) first becomes
|
|
22
|
+
* available for the session — i.e. hit tests can now return DepthPoints. Useful for
|
|
23
|
+
* hiding an "initializing depth…" state instead of acting on early, inaccurate
|
|
24
|
+
* feature points. On devices using monocular depth estimation, this can take a few
|
|
25
|
+
* seconds after the AR screen appears while the model warms up.
|
|
26
|
+
*/
|
|
27
|
+
onDepthReady?: () => void;
|
|
20
28
|
/**
|
|
21
29
|
* Describes the acoustic properties of the room around the user
|
|
22
30
|
*/
|
|
@@ -47,6 +55,10 @@ export declare class ViroARScene extends ViroBase<Props> {
|
|
|
47
55
|
* Returns object w/ "intensity" and "color" keys
|
|
48
56
|
*/
|
|
49
57
|
_onAmbientLightUpdate: (event: NativeSyntheticEvent<ViroAmbientLightUpdateEvent>) => void;
|
|
58
|
+
/**
|
|
59
|
+
* Fired once when depth data first becomes available for hit testing.
|
|
60
|
+
*/
|
|
61
|
+
_onDepthReady: (_event: NativeSyntheticEvent<{}>) => void;
|
|
50
62
|
_onAnchorFound: (event: NativeSyntheticEvent<ViroARAnchorFoundEvent>) => void;
|
|
51
63
|
_onAnchorUpdated: (event: NativeSyntheticEvent<ViroARAnchorUpdatedEvent>) => void;
|
|
52
64
|
_onAnchorRemoved: (event: NativeSyntheticEvent<ViroARAnchorRemovedEvent>) => void;
|
|
@@ -101,6 +113,6 @@ export declare class ViroARScene extends ViroBase<Props> {
|
|
|
101
113
|
up: any[];
|
|
102
114
|
}>;
|
|
103
115
|
getCameraPositionAsync: () => Promise<any>;
|
|
104
|
-
render(): React.JSX.Element
|
|
116
|
+
render(): React.JSX.Element;
|
|
105
117
|
}
|
|
106
118
|
export {};
|
|
@@ -52,7 +52,6 @@ const react_native_1 = require("react-native");
|
|
|
52
52
|
const resolveAssetSource_1 = __importDefault(require("react-native/Libraries/Image/resolveAssetSource"));
|
|
53
53
|
const ViroBase_1 = require("../ViroBase");
|
|
54
54
|
const ViroConstants_1 = require("../ViroConstants");
|
|
55
|
-
const ViroPlatform_1 = require("../Utilities/ViroPlatform");
|
|
56
55
|
const ViroCameraModule = react_native_1.NativeModules.ViroCameraModule;
|
|
57
56
|
class ViroARScene extends ViroBase_1.ViroBase {
|
|
58
57
|
onTrackingFirstInitialized = false;
|
|
@@ -176,6 +175,12 @@ class ViroARScene extends ViroBase_1.ViroBase {
|
|
|
176
175
|
this.props.onAmbientLightUpdate &&
|
|
177
176
|
this.props.onAmbientLightUpdate(event.nativeEvent.ambientLightInfo);
|
|
178
177
|
};
|
|
178
|
+
/**
|
|
179
|
+
* Fired once when depth data first becomes available for hit testing.
|
|
180
|
+
*/
|
|
181
|
+
_onDepthReady = (_event) => {
|
|
182
|
+
this.props.onDepthReady && this.props.onDepthReady();
|
|
183
|
+
};
|
|
179
184
|
_onAnchorFound = (event) => {
|
|
180
185
|
// TODO: this is in a different format than the other onAnchorFound methods
|
|
181
186
|
this.props.onAnchorFound &&
|
|
@@ -284,10 +289,8 @@ class ViroARScene extends ViroBase_1.ViroBase {
|
|
|
284
289
|
return await ViroCameraModule.getCameraPosition((0, react_native_1.findNodeHandle)(this));
|
|
285
290
|
};
|
|
286
291
|
render() {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
return null;
|
|
290
|
-
}
|
|
292
|
+
// On Meta Quest, ViroARScene renders as a mixed-reality scene through the
|
|
293
|
+
// OpenXR renderer (passthrough + XR_FB_scene plane anchors). No longer gated.
|
|
291
294
|
// Uncomment this line to check for misnamed props
|
|
292
295
|
//checkMisnamedProps("ViroARScene", this.props);
|
|
293
296
|
// Since anchorDetectionTypes can be either a string or an array, convert the string to a 1-element array.
|
|
@@ -334,7 +337,7 @@ class ViroARScene extends ViroBase_1.ViroBase {
|
|
|
334
337
|
},
|
|
335
338
|
}}>
|
|
336
339
|
<VRTARScene {...this.props} canHover={this.props.onHover != undefined} canClick={this.props.onClick != undefined ||
|
|
337
|
-
this.props.onClickState != undefined} canTouch={this.props.onTouch != undefined} canScroll={this.props.onScroll != undefined} canSwipe={this.props.onSwipe != undefined} canDrag={this.props.onDrag != undefined} canPinch={this.props.onPinch != undefined} canRotate={this.props.onRotate != undefined} canFuse={this.props.onFuse != undefined} canCameraARHitTest={this.props.onCameraARHitTest != undefined} canARPointCloudUpdate={this.props.onARPointCloudUpdate != undefined} canCameraTransformUpdate={this.props.onCameraTransformUpdate != undefined} onHoverViro={this._onHover} onClickViro={this._onClickState} onClick={undefined} onTouchViro={this._onTouch} onScrollViro={this._onScroll} onSwipeViro={this._onSwipe} onDragViro={this._onDrag} onPinchViro={this._onPinch} onRotateViro={this._onRotate} onFuseViro={this._onFuse} onCameraARHitTestViro={this._onCameraARHitTest} onARPointCloudUpdateViro={this._onARPointCloudUpdate} onCameraTransformUpdateViro={this._onCameraTransformUpdate} onPlatformUpdateViro={this._onPlatformUpdate} onTrackingUpdatedViro={this._onTrackingUpdated} onAmbientLightUpdateViro={this._onAmbientLightUpdate} onAnchorFoundViro={this._onAnchorFound} onAnchorUpdatedViro={this._onAnchorUpdated} onAnchorRemovedViro={this._onAnchorRemoved} timeToFuse={timeToFuse} anchorDetectionTypes={anchorDetectionTypes} displayPointCloud={displayPointCloud} pointCloudImage={pointCloudImage} pointCloudScale={pointCloudScale} pointCloudMaxPoints={pointCloudMaxPoints}/>
|
|
340
|
+
this.props.onClickState != undefined} canTouch={this.props.onTouch != undefined} canScroll={this.props.onScroll != undefined} canSwipe={this.props.onSwipe != undefined} canDrag={this.props.onDrag != undefined} canPinch={this.props.onPinch != undefined} canRotate={this.props.onRotate != undefined} canFuse={this.props.onFuse != undefined} canCameraARHitTest={this.props.onCameraARHitTest != undefined} canARPointCloudUpdate={this.props.onARPointCloudUpdate != undefined} canCameraTransformUpdate={this.props.onCameraTransformUpdate != undefined} onHoverViro={this._onHover} onClickViro={this._onClickState} onClick={undefined} onTouchViro={this._onTouch} onScrollViro={this._onScroll} onSwipeViro={this._onSwipe} onDragViro={this._onDrag} onPinchViro={this._onPinch} onRotateViro={this._onRotate} onFuseViro={this._onFuse} onCameraARHitTestViro={this._onCameraARHitTest} onARPointCloudUpdateViro={this._onARPointCloudUpdate} onCameraTransformUpdateViro={this._onCameraTransformUpdate} onPlatformUpdateViro={this._onPlatformUpdate} onTrackingUpdatedViro={this._onTrackingUpdated} onAmbientLightUpdateViro={this._onAmbientLightUpdate} onDepthReadyViro={this._onDepthReady} onAnchorFoundViro={this._onAnchorFound} onAnchorUpdatedViro={this._onAnchorUpdated} onAnchorRemovedViro={this._onAnchorRemoved} timeToFuse={timeToFuse} anchorDetectionTypes={anchorDetectionTypes} displayPointCloud={displayPointCloud} pointCloudImage={pointCloudImage} pointCloudScale={pointCloudScale} pointCloudMaxPoints={pointCloudMaxPoints}/>
|
|
338
341
|
</ViroSceneContext_1.ViroSceneContext.Provider>);
|
|
339
342
|
}
|
|
340
343
|
}
|
|
@@ -368,6 +371,7 @@ ViroARScene, {
|
|
|
368
371
|
onTrackingInitializedViro: true,
|
|
369
372
|
onTrackingUpdatedViro: true,
|
|
370
373
|
onAmbientLightUpdateViro: true,
|
|
374
|
+
onDepthReadyViro: true,
|
|
371
375
|
onAnchorFoundViro: true,
|
|
372
376
|
onAnchorUpdatedViro: true,
|
|
373
377
|
onAnchorRemovedViro: true,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import { StudioVariableStore } from "./domain/variableStore";
|
|
2
3
|
import { StudioSceneResponse } from "./types";
|
|
3
4
|
interface StudioARSceneProps {
|
|
4
5
|
sceneNavigator?: any;
|
|
@@ -6,6 +7,8 @@ interface StudioARSceneProps {
|
|
|
6
7
|
onReady?: () => void;
|
|
7
8
|
onError?: (err: Error) => void;
|
|
8
9
|
onSceneChange?: (sceneId: string, sceneName: string) => void;
|
|
10
|
+
/** Session-scoped store owned by the navigator; survives scene pushes. */
|
|
11
|
+
variableStore?: StudioVariableStore;
|
|
9
12
|
}
|
|
10
13
|
/**
|
|
11
14
|
* Outer gate: keeps the hooks-bearing inner component out of the tree until
|
|
@@ -51,7 +51,12 @@ const collisionBindingsRuntime_1 = require("./domain/collisionBindingsRuntime");
|
|
|
51
51
|
const collisionPairKey_1 = require("./domain/collisionPairKey");
|
|
52
52
|
const triggerImageRegistry_1 = require("./domain/triggerImageRegistry");
|
|
53
53
|
const viroNodeFactory_1 = require("./domain/viroNodeFactory");
|
|
54
|
+
const defaultApiRequestExecutor_1 = require("./domain/defaultApiRequestExecutor");
|
|
54
55
|
const sceneNavigationHandler_1 = require("./domain/sceneNavigationHandler");
|
|
56
|
+
const variableStore_1 = require("./domain/variableStore");
|
|
57
|
+
const visibilityStore_1 = require("./domain/visibilityStore");
|
|
58
|
+
const soundManager_1 = require("./domain/soundManager");
|
|
59
|
+
const StudioSounds_1 = require("./domain/StudioSounds");
|
|
55
60
|
const studioMaterials_1 = require("./domain/studioMaterials");
|
|
56
61
|
const useStudioShaderTimeUniforms_1 = require("./domain/useStudioShaderTimeUniforms");
|
|
57
62
|
const useStudioShaderViewportUniforms_1 = require("./domain/useStudioShaderViewportUniforms");
|
|
@@ -70,8 +75,82 @@ const StudioARScene = (props) => {
|
|
|
70
75
|
};
|
|
71
76
|
exports.StudioARScene = StudioARScene;
|
|
72
77
|
const StudioARSceneInner = (props) => {
|
|
73
|
-
const { sceneNavigator, sceneData, onReady, onSceneChange } = props;
|
|
78
|
+
const { sceneNavigator, sceneData, onReady, onSceneChange, variableStore } = props;
|
|
74
79
|
const { scene, assets, animations, collision_bindings, functions } = sceneData;
|
|
80
|
+
// ─── Sequence scheduler ───────────────────────────────────────────────────
|
|
81
|
+
// One per scene. Drives WAIT steps; cancelled on unmount and on navigation so
|
|
82
|
+
// a pending WAIT never fires into a torn-down or replaced scene.
|
|
83
|
+
const schedulerRef = (0, react_1.useRef)(null);
|
|
84
|
+
if (schedulerRef.current === null) {
|
|
85
|
+
schedulerRef.current = new sceneNavigationHandler_1.SequenceScheduler();
|
|
86
|
+
}
|
|
87
|
+
(0, react_1.useEffect)(() => {
|
|
88
|
+
return () => {
|
|
89
|
+
schedulerRef.current?.dispose();
|
|
90
|
+
schedulerRef.current = null;
|
|
91
|
+
// dispose() bumps the scheduler generation first; reset() then clears any
|
|
92
|
+
// pending sound backstop timers and fires their callbacks, which now
|
|
93
|
+
// no-op via the generation guard so unmount can't advance a waited step.
|
|
94
|
+
soundManagerRef.current?.reset();
|
|
95
|
+
};
|
|
96
|
+
}, []);
|
|
97
|
+
// ─── Variable store ───────────────────────────────────────────────────────
|
|
98
|
+
// Normally passed down by the navigator (session-scoped); hosts mounting this
|
|
99
|
+
// scene directly get a scene-local fallback. Seeding happens here, at instance
|
|
100
|
+
// init, so values exist before any effect dispatches on_load. seed() is
|
|
101
|
+
// initialize-if-absent, hence idempotent and strict-mode safe.
|
|
102
|
+
const variableStoreRef = (0, react_1.useRef)(null);
|
|
103
|
+
if (variableStoreRef.current === null) {
|
|
104
|
+
variableStoreRef.current = variableStore ?? new variableStore_1.StudioVariableStore();
|
|
105
|
+
variableStoreRef.current.seed(sceneData.variables ?? []);
|
|
106
|
+
}
|
|
107
|
+
// ─── Visibility store ─────────────────────────────────────────────────────
|
|
108
|
+
// Scene-scoped (asset placements are per-scene), keyed by asset id. Seeded
|
|
109
|
+
// from each asset's author-time hidden_on_load default; Set Visibility
|
|
110
|
+
// actions flip it at runtime. Re-seeded on scene change so a persisted
|
|
111
|
+
// instance doesn't carry stale visibility across a navigation.
|
|
112
|
+
const visibilityStoreRef = (0, react_1.useRef)(null);
|
|
113
|
+
if (visibilityStoreRef.current === null) {
|
|
114
|
+
visibilityStoreRef.current = new visibilityStore_1.StudioVisibilityStore();
|
|
115
|
+
visibilityStoreRef.current.seed(assets);
|
|
116
|
+
}
|
|
117
|
+
(0, react_1.useEffect)(() => {
|
|
118
|
+
visibilityStoreRef.current?.reseed(assets);
|
|
119
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
120
|
+
}, [scene.id]);
|
|
121
|
+
// ─── Sound manager ────────────────────────────────────────────────────────
|
|
122
|
+
// Per-scene. PLAY/STOP scene-function actions drive it; <StudioSounds> renders
|
|
123
|
+
// the active list. Reset on scene change so sounds don't leak across a
|
|
124
|
+
// navigation (sounds, unlike variables, are not session-scoped).
|
|
125
|
+
const soundManagerRef = (0, react_1.useRef)(null);
|
|
126
|
+
if (soundManagerRef.current === null) {
|
|
127
|
+
soundManagerRef.current = new soundManager_1.StudioSoundManager();
|
|
128
|
+
}
|
|
129
|
+
(0, react_1.useEffect)(() => {
|
|
130
|
+
soundManagerRef.current?.reset();
|
|
131
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
132
|
+
}, [scene.id]);
|
|
133
|
+
// Position for a spatial PLAY: look up the placed target asset (matches the
|
|
134
|
+
// node factory's position derivation, position_z defaulting to -2).
|
|
135
|
+
const getAssetPosition = (0, react_1.useCallback)((assetId) => {
|
|
136
|
+
const a = assets.find((x) => x.id === assetId);
|
|
137
|
+
if (!a)
|
|
138
|
+
return undefined;
|
|
139
|
+
return [a.position_x ?? 0, a.position_y ?? 0, a.position_z ?? -2];
|
|
140
|
+
}, [assets]);
|
|
141
|
+
const runtimeCtx = (0, react_1.useMemo)(() => ({
|
|
142
|
+
scheduler: schedulerRef.current,
|
|
143
|
+
variableStore: variableStoreRef.current,
|
|
144
|
+
apiRequestExecutor: defaultApiRequestExecutor_1.defaultApiRequestExecutor,
|
|
145
|
+
visibilityStore: visibilityStoreRef.current,
|
|
146
|
+
soundManager: soundManagerRef.current,
|
|
147
|
+
getAssetPosition,
|
|
148
|
+
}), [getAssetPosition]);
|
|
149
|
+
// Cancel this scene's pending WAITs before handing off to the next scene.
|
|
150
|
+
const handleSceneChange = (0, react_1.useCallback)((sceneId, sceneName) => {
|
|
151
|
+
schedulerRef.current?.cancelAll();
|
|
152
|
+
onSceneChange?.(sceneId, sceneName);
|
|
153
|
+
}, [onSceneChange]);
|
|
75
154
|
// ─── Material registration ────────────────────────────────────────────────
|
|
76
155
|
const materialsRegisteredRef = (0, react_1.useRef)(false);
|
|
77
156
|
if (!materialsRegisteredRef.current) {
|
|
@@ -103,7 +182,10 @@ const StudioARSceneInner = (props) => {
|
|
|
103
182
|
const triggerAnimation = (0, react_1.useCallback)((targetAssetId, animationKey) => {
|
|
104
183
|
// Viro's animation prop is edge-triggered on false→true. Force false first,
|
|
105
184
|
// then flip to true on the next frame so a re-trigger of the same key fires.
|
|
106
|
-
setAnimOverrides((prev) => ({
|
|
185
|
+
setAnimOverrides((prev) => ({
|
|
186
|
+
...prev,
|
|
187
|
+
[targetAssetId]: { key: animationKey, run: false },
|
|
188
|
+
}));
|
|
107
189
|
const handle = requestAnimationFrame(() => {
|
|
108
190
|
triggerHandlesRef.current.delete(handle);
|
|
109
191
|
setAnimOverrides((prev) => {
|
|
@@ -148,21 +230,29 @@ const StudioARSceneInner = (props) => {
|
|
|
148
230
|
interruptible: activeAnim.interruptible,
|
|
149
231
|
delay: activeAnim.delay_ms ?? 0,
|
|
150
232
|
onStart: activeAnim.on_start_function
|
|
151
|
-
? () => (0, sceneNavigationHandler_1.executeOnLoadFunction)(activeAnim.on_start_function, functions, sceneNavigator, animations, (id, key) => triggerAnimationRef.current(id, key))
|
|
233
|
+
? () => (0, sceneNavigationHandler_1.executeOnLoadFunction)(activeAnim.on_start_function, functions, sceneNavigator, animations, (id, key) => triggerAnimationRef.current(id, key), handleSceneChange, runtimeCtx)
|
|
152
234
|
: undefined,
|
|
153
235
|
onFinish: activeAnim.on_finish_function
|
|
154
|
-
? () => (0, sceneNavigationHandler_1.executeOnLoadFunction)(activeAnim.on_finish_function, functions, sceneNavigator, animations, (id, key) => triggerAnimationRef.current(id, key))
|
|
236
|
+
? () => (0, sceneNavigationHandler_1.executeOnLoadFunction)(activeAnim.on_finish_function, functions, sceneNavigator, animations, (id, key) => triggerAnimationRef.current(id, key), handleSceneChange, runtimeCtx)
|
|
155
237
|
: undefined,
|
|
156
238
|
};
|
|
157
239
|
}
|
|
158
240
|
return states;
|
|
159
|
-
}, [
|
|
241
|
+
}, [
|
|
242
|
+
animations,
|
|
243
|
+
animOverrides,
|
|
244
|
+
loadedAssetIds,
|
|
245
|
+
functions,
|
|
246
|
+
sceneNavigator,
|
|
247
|
+
handleSceneChange,
|
|
248
|
+
runtimeCtx,
|
|
249
|
+
]);
|
|
160
250
|
// ─── on_load_function ─────────────────────────────────────────────────────
|
|
161
251
|
const onLoadExecutedRef = (0, react_1.useRef)(false);
|
|
162
252
|
(0, react_1.useEffect)(() => {
|
|
163
253
|
if (scene.on_load_function && !onLoadExecutedRef.current) {
|
|
164
254
|
onLoadExecutedRef.current = true;
|
|
165
|
-
(0, sceneNavigationHandler_1.executeOnLoadFunction)(scene.on_load_function, functions, sceneNavigator, animations, (id, key) => triggerAnimationRef.current(id, key),
|
|
255
|
+
(0, sceneNavigationHandler_1.executeOnLoadFunction)(scene.on_load_function, functions, sceneNavigator, animations, (id, key) => triggerAnimationRef.current(id, key), handleSceneChange, runtimeCtx);
|
|
166
256
|
}
|
|
167
257
|
}, [scene.id]);
|
|
168
258
|
// ─── Collision bindings ───────────────────────────────────────────────────
|
|
@@ -188,8 +278,15 @@ const StudioARSceneInner = (props) => {
|
|
|
188
278
|
const getCollisionHandler = (0, react_1.useCallback)((placementId) => {
|
|
189
279
|
if (!collisionAssetIds.has(placementId))
|
|
190
280
|
return undefined;
|
|
191
|
-
return (0, collisionBindingsRuntime_1.createPlacementCollisionHandler)(placementId, bindingsByPairKey, sceneNavigator, animations, collisionCooldownRef, (id, key) => triggerAnimationRef.current(id, key),
|
|
192
|
-
}, [
|
|
281
|
+
return (0, collisionBindingsRuntime_1.createPlacementCollisionHandler)(placementId, bindingsByPairKey, sceneNavigator, animations, collisionCooldownRef, (id, key) => triggerAnimationRef.current(id, key), handleSceneChange, runtimeCtx);
|
|
282
|
+
}, [
|
|
283
|
+
bindingsByPairKey,
|
|
284
|
+
collisionAssetIds,
|
|
285
|
+
sceneNavigator,
|
|
286
|
+
animations,
|
|
287
|
+
handleSceneChange,
|
|
288
|
+
runtimeCtx,
|
|
289
|
+
]);
|
|
193
290
|
// ─── Trigger image targets ────────────────────────────────────────────────
|
|
194
291
|
const { planeAssets, imageTriggeredAssets } = (0, react_1.useMemo)(() => {
|
|
195
292
|
const plane = assets.filter((a) => !a.trigger_image_url);
|
|
@@ -221,7 +318,9 @@ const StudioARSceneInner = (props) => {
|
|
|
221
318
|
};
|
|
222
319
|
}, [imageTriggeredAssets]);
|
|
223
320
|
// ─── Ready callback ───────────────────────────────────────────────────────
|
|
224
|
-
(0, react_1.useEffect)(() => {
|
|
321
|
+
(0, react_1.useEffect)(() => {
|
|
322
|
+
onReady?.();
|
|
323
|
+
}, []);
|
|
225
324
|
// ─── Render helpers ───────────────────────────────────────────────────────
|
|
226
325
|
const maxModels = react_native_1.Platform.OS === "android" ? ANDROID_MAX_3D_MODELS : IOS_MAX_3D_MODELS;
|
|
227
326
|
const renderedPlaneAssets = (0, react_1.useMemo)(() => {
|
|
@@ -235,10 +334,20 @@ const StudioARSceneInner = (props) => {
|
|
|
235
334
|
return null;
|
|
236
335
|
}
|
|
237
336
|
}
|
|
238
|
-
return (0, viroNodeFactory_1.createNode)(asset, sceneNavigator, animations, scene, (id, key) => triggerAnimationRef.current(id, key), animationStates, handleAssetLoaded, getCollisionHandler(asset.id),
|
|
337
|
+
return (0, viroNodeFactory_1.createNode)(asset, sceneNavigator, animations, scene, (id, key) => triggerAnimationRef.current(id, key), animationStates, handleAssetLoaded, getCollisionHandler(asset.id), handleSceneChange, runtimeCtx);
|
|
239
338
|
})
|
|
240
339
|
.filter(Boolean);
|
|
241
|
-
}, [
|
|
340
|
+
}, [
|
|
341
|
+
planeAssets,
|
|
342
|
+
sceneNavigator,
|
|
343
|
+
animations,
|
|
344
|
+
animationStates,
|
|
345
|
+
handleAssetLoaded,
|
|
346
|
+
getCollisionHandler,
|
|
347
|
+
maxModels,
|
|
348
|
+
handleSceneChange,
|
|
349
|
+
runtimeCtx,
|
|
350
|
+
]);
|
|
242
351
|
const renderedImageTriggeredAssets = (0, react_1.useMemo)(() => {
|
|
243
352
|
if (ViroPlatform_1.isQuest)
|
|
244
353
|
return [];
|
|
@@ -247,7 +356,7 @@ const StudioARSceneInner = (props) => {
|
|
|
247
356
|
const targetName = urlToTargetName.get(asset.trigger_image_url);
|
|
248
357
|
if (!targetName)
|
|
249
358
|
return null;
|
|
250
|
-
const node = (0, viroNodeFactory_1.createNode)(asset, sceneNavigator, animations, scene, (id, key) => triggerAnimationRef.current(id, key), animationStates, handleAssetLoaded, getCollisionHandler(asset.id),
|
|
359
|
+
const node = (0, viroNodeFactory_1.createNode)(asset, sceneNavigator, animations, scene, (id, key) => triggerAnimationRef.current(id, key), animationStates, handleAssetLoaded, getCollisionHandler(asset.id), handleSceneChange, runtimeCtx);
|
|
251
360
|
if (!node)
|
|
252
361
|
return null;
|
|
253
362
|
return (<ViroARImageMarker_1.ViroARImageMarker key={asset.id} target={targetName}>
|
|
@@ -255,7 +364,17 @@ const StudioARSceneInner = (props) => {
|
|
|
255
364
|
</ViroARImageMarker_1.ViroARImageMarker>);
|
|
256
365
|
})
|
|
257
366
|
.filter(Boolean);
|
|
258
|
-
}, [
|
|
367
|
+
}, [
|
|
368
|
+
urlToTargetName,
|
|
369
|
+
imageTriggeredAssets,
|
|
370
|
+
sceneNavigator,
|
|
371
|
+
animations,
|
|
372
|
+
animationStates,
|
|
373
|
+
handleAssetLoaded,
|
|
374
|
+
getCollisionHandler,
|
|
375
|
+
handleSceneChange,
|
|
376
|
+
runtimeCtx,
|
|
377
|
+
]);
|
|
259
378
|
// ─── Plane detection (AR only) ────────────────────────────────────────────
|
|
260
379
|
const planeDetectionMode = (scene.plane_detection ?? "NONE").toUpperCase();
|
|
261
380
|
const planeAlignment = (scene.plane_direction ?? "Horizontal");
|
|
@@ -283,14 +402,22 @@ const StudioARSceneInner = (props) => {
|
|
|
283
402
|
const physicsWorld = physicsWorldConfig?.enabled
|
|
284
403
|
? (0, physicsConfig_1.buildViroPhysicsWorld)(physicsWorldConfig)
|
|
285
404
|
: undefined;
|
|
286
|
-
const physicsProps = physicsWorld
|
|
405
|
+
const physicsProps = physicsWorld
|
|
406
|
+
? { physicsWorld: physicsWorld }
|
|
407
|
+
: {};
|
|
287
408
|
// ─── Render ───────────────────────────────────────────────────────────────
|
|
288
409
|
const children = (<>
|
|
289
410
|
{ViroPlatform_1.isQuest && <ViroController_1.ViroController controllerVisibility reticleVisibility/>}
|
|
290
411
|
<ViroAmbientLight_1.ViroAmbientLight color="#ffffff" intensity={1000}/>
|
|
291
412
|
{renderAssets()}
|
|
292
413
|
{renderedImageTriggeredAssets}
|
|
293
|
-
|
|
414
|
+
<StudioSounds_1.StudioSounds manager={soundManagerRef.current}/>
|
|
415
|
+
{assets.length === 0 && (<ViroText_1.ViroText text="No assets to display" position={[0, 0, -2]} style={{
|
|
416
|
+
fontFamily: "Arial",
|
|
417
|
+
fontSize: 16,
|
|
418
|
+
color: "#CCCCCC",
|
|
419
|
+
textAlign: "center",
|
|
420
|
+
}}/>)}
|
|
294
421
|
</>);
|
|
295
422
|
if (ViroPlatform_1.isQuest) {
|
|
296
423
|
return <ViroScene_1.ViroScene {...physicsProps}>{children}</ViroScene_1.ViroScene>;
|
|
@@ -43,6 +43,7 @@ const ViroXRSceneNavigator_1 = require("../ViroXRSceneNavigator");
|
|
|
43
43
|
const ViroPlatform_1 = require("../Utilities/ViroPlatform");
|
|
44
44
|
const animationRegistry_1 = require("./domain/animationRegistry");
|
|
45
45
|
const studioMaterials_1 = require("./domain/studioMaterials");
|
|
46
|
+
const variableStore_1 = require("./domain/variableStore");
|
|
46
47
|
const StudioARScene_1 = require("./StudioARScene");
|
|
47
48
|
const VRTStudioModule_1 = require("./VRTStudioModule");
|
|
48
49
|
function LoadingARScene() { return <ViroARScene_1.ViroARScene />; }
|
|
@@ -72,6 +73,18 @@ const styles = react_native_1.StyleSheet.create({
|
|
|
72
73
|
function StudioSceneNavigator({ sceneId, worldAlignment = "Gravity", autofocus = true, style, onSceneReady, onError, onSceneChange, onExitViro, }) {
|
|
73
74
|
const navigatorRef = (0, react_1.useRef)(null);
|
|
74
75
|
const loadedSceneIdRef = (0, react_1.useRef)(null);
|
|
76
|
+
// Session-scoped variable store: outlives every scene push, resets when the
|
|
77
|
+
// navigator (= the AR/VR session) unmounts.
|
|
78
|
+
const variableStoreRef = (0, react_1.useRef)(null);
|
|
79
|
+
if (variableStoreRef.current === null) {
|
|
80
|
+
variableStoreRef.current = new variableStore_1.StudioVariableStore();
|
|
81
|
+
}
|
|
82
|
+
(0, react_1.useEffect)(() => {
|
|
83
|
+
return () => {
|
|
84
|
+
variableStoreRef.current?.reset();
|
|
85
|
+
variableStoreRef.current = null;
|
|
86
|
+
};
|
|
87
|
+
}, []);
|
|
75
88
|
const onSceneReadyRef = (0, react_1.useRef)(onSceneReady);
|
|
76
89
|
const onErrorRef = (0, react_1.useRef)(onError);
|
|
77
90
|
const onSceneChangeRef = (0, react_1.useRef)(onSceneChange);
|
|
@@ -137,6 +150,7 @@ function StudioSceneNavigator({ sceneId, worldAlignment = "Gravity", autofocus =
|
|
|
137
150
|
sceneData,
|
|
138
151
|
onReady: onSceneReadyRef.current,
|
|
139
152
|
onSceneChange: onSceneChangeRef.current,
|
|
153
|
+
variableStore: variableStoreRef.current,
|
|
140
154
|
},
|
|
141
155
|
};
|
|
142
156
|
if (ViroPlatform_1.isQuest) {
|
|
@@ -12,4 +12,10 @@ export declare const VRTStudioModule: {
|
|
|
12
12
|
rvGetProject: () => Promise<StudioModuleResult>;
|
|
13
13
|
/** Returns the configured project ID, or null if not set. */
|
|
14
14
|
rvGetProjectId: () => Promise<string | null>;
|
|
15
|
+
/**
|
|
16
|
+
* POSTs a pre-serialised scene-api-request body ({function_id, variables})
|
|
17
|
+
* to the egress proxy, authenticated with the app's RVApiKey. The resolved
|
|
18
|
+
* `data` is the proxy's outcome envelope JSON.
|
|
19
|
+
*/
|
|
20
|
+
rvStudioApiRequest: (bodyJson: string) => Promise<StudioModuleResult>;
|
|
15
21
|
};
|
|
@@ -28,4 +28,14 @@ exports.VRTStudioModule = {
|
|
|
28
28
|
return Promise.resolve(null);
|
|
29
29
|
return native.rvGetProjectId();
|
|
30
30
|
},
|
|
31
|
+
/**
|
|
32
|
+
* POSTs a pre-serialised scene-api-request body ({function_id, variables})
|
|
33
|
+
* to the egress proxy, authenticated with the app's RVApiKey. The resolved
|
|
34
|
+
* `data` is the proxy's outcome envelope JSON.
|
|
35
|
+
*/
|
|
36
|
+
rvStudioApiRequest: (bodyJson) => {
|
|
37
|
+
if (!native)
|
|
38
|
+
return Promise.resolve(NOT_AVAILABLE);
|
|
39
|
+
return native.rvStudioApiRequest(bodyJson);
|
|
40
|
+
},
|
|
31
41
|
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { StudioSoundManager } from "./soundManager";
|
|
3
|
+
/**
|
|
4
|
+
* Renders every actively-playing sound from the manager, re-painting the whole
|
|
5
|
+
* list on any change (like the reactive variable-text nodes). Non-looping sounds
|
|
6
|
+
* remove themselves on finish; any sound removes itself on error so a clip that
|
|
7
|
+
* fails to load releases a waiting step instead of stalling the sequence.
|
|
8
|
+
*/
|
|
9
|
+
export declare const StudioSounds: React.FC<{
|
|
10
|
+
manager: StudioSoundManager;
|
|
11
|
+
}>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.StudioSounds = void 0;
|
|
37
|
+
const React = __importStar(require("react"));
|
|
38
|
+
const ViroSound_1 = require("../../ViroSound");
|
|
39
|
+
const ViroSpatialSound_1 = require("../../ViroSpatialSound");
|
|
40
|
+
/**
|
|
41
|
+
* Renders every actively-playing sound from the manager, re-painting the whole
|
|
42
|
+
* list on any change (like the reactive variable-text nodes). Non-looping sounds
|
|
43
|
+
* remove themselves on finish; any sound removes itself on error so a clip that
|
|
44
|
+
* fails to load releases a waiting step instead of stalling the sequence.
|
|
45
|
+
*/
|
|
46
|
+
const StudioSounds = ({ manager, }) => {
|
|
47
|
+
const [, force] = React.useReducer((n) => n + 1, 0);
|
|
48
|
+
React.useEffect(() => manager.subscribe(force), [manager]);
|
|
49
|
+
return (<>
|
|
50
|
+
{manager.getActive().map((s) => {
|
|
51
|
+
const shared = {
|
|
52
|
+
source: { uri: s.url },
|
|
53
|
+
volume: s.volume,
|
|
54
|
+
loop: s.loop,
|
|
55
|
+
paused: false,
|
|
56
|
+
onFinish: () => {
|
|
57
|
+
if (!s.loop)
|
|
58
|
+
manager.remove(s.playId);
|
|
59
|
+
},
|
|
60
|
+
onError: (e) => {
|
|
61
|
+
console.warn(`[Studio] Sound failed: ${s.audioAssetId} (#${s.playId})`, e?.nativeEvent?.error);
|
|
62
|
+
manager.remove(s.playId);
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
return s.position ? (<ViroSpatialSound_1.ViroSpatialSound key={s.playId} position={s.position} {...shared}/>) : (<ViroSound_1.ViroSound key={s.playId} {...shared}/>);
|
|
66
|
+
})}
|
|
67
|
+
</>);
|
|
68
|
+
};
|
|
69
|
+
exports.StudioSounds = StudioSounds;
|