@reactvision/react-viro 2.57.0 → 2.57.3
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 +2 -4
- package/components/AR/ViroARSceneNavigator.tsx +11 -3
- 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 +13 -5
- 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 +1 -1
- package/dist/components/AR/ViroARScene.js +2 -5
- package/dist/components/AR/ViroARSceneNavigator.d.ts +11 -3
- 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 +13 -5
- package/dist/components/ViroObjectDetector.js +13 -5
- 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 +4 -4
- package/dist/index.js +2 -1
- package/dist/plugins/withViroAndroid.js +18 -0
- package/index.ts +4 -3
- 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 +8 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROARSessioniOS.h +14 -3
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROFrontCameraProvider.h +34 -0
- package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROViewAR.h +3 -1
- 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/lib/libViroReact.a +0 -0
- package/package.json +11 -11
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Last-resort cap on how long a step waits for a non-looping PLAY to finish. A
|
|
3
|
+
* clip that fails to load fires onError (released at once); a clip whose native
|
|
4
|
+
* finish/error event is dropped or never arrives would otherwise stall the walk
|
|
5
|
+
* forever, so the manager force-releases the waiter after this many ms.
|
|
6
|
+
* Generous on purpose: it must outlast any realistic single clip so it never
|
|
7
|
+
* cuts one short, only catches a genuine stall.
|
|
8
|
+
*/
|
|
9
|
+
export declare const SOUND_WAIT_BACKSTOP_MS: number;
|
|
10
|
+
/** One actively-playing sound, keyed in the manager by its monotonic playId. */
|
|
11
|
+
export type StudioSoundEntry = {
|
|
12
|
+
playId: number;
|
|
13
|
+
audioAssetId: string;
|
|
14
|
+
url: string;
|
|
15
|
+
position?: [number, number, number];
|
|
16
|
+
volume: number;
|
|
17
|
+
loop: boolean;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Per-scene sound store. PLAY adds an entry under a fresh playId; STOP removes
|
|
21
|
+
* by audio asset id (null = all). The whole <StudioSounds> list re-renders on
|
|
22
|
+
* any change, so subscribers are GLOBAL like StudioVariableStore (not per-key).
|
|
23
|
+
*/
|
|
24
|
+
export declare class StudioSoundManager {
|
|
25
|
+
private sounds;
|
|
26
|
+
private listeners;
|
|
27
|
+
private nextPlayId;
|
|
28
|
+
private finishCallbacks;
|
|
29
|
+
private finishTimers;
|
|
30
|
+
/** Subscribe to any add/remove; returns an unsubscribe fn. */
|
|
31
|
+
subscribe(listener: () => void): () => void;
|
|
32
|
+
getActive(): StudioSoundEntry[];
|
|
33
|
+
/** Pull and invoke the stored completion callback (if any) for a playId. */
|
|
34
|
+
private fire;
|
|
35
|
+
/**
|
|
36
|
+
* Adds a sound and returns its playId. onFinish (when given) resolves a step
|
|
37
|
+
* waiting on a non-looping PLAY; it fires on natural finish or early stop.
|
|
38
|
+
*/
|
|
39
|
+
play(entry: {
|
|
40
|
+
audioAssetId: string;
|
|
41
|
+
url: string;
|
|
42
|
+
position?: [number, number, number];
|
|
43
|
+
volume: number;
|
|
44
|
+
loop: boolean;
|
|
45
|
+
stopOthers: boolean;
|
|
46
|
+
}, onFinish?: () => void): number;
|
|
47
|
+
/** null = stop all sounds; otherwise stop every entry for this audio asset. */
|
|
48
|
+
stop(audioAssetId: string | null): void;
|
|
49
|
+
/** Drop one entry; onFinish calls this for non-looping sounds. */
|
|
50
|
+
remove(playId: number): void;
|
|
51
|
+
reset(): void;
|
|
52
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StudioSoundManager = exports.SOUND_WAIT_BACKSTOP_MS = void 0;
|
|
4
|
+
const utils_1 = require("./utils");
|
|
5
|
+
/**
|
|
6
|
+
* Last-resort cap on how long a step waits for a non-looping PLAY to finish. A
|
|
7
|
+
* clip that fails to load fires onError (released at once); a clip whose native
|
|
8
|
+
* finish/error event is dropped or never arrives would otherwise stall the walk
|
|
9
|
+
* forever, so the manager force-releases the waiter after this many ms.
|
|
10
|
+
* Generous on purpose: it must outlast any realistic single clip so it never
|
|
11
|
+
* cuts one short, only catches a genuine stall.
|
|
12
|
+
*/
|
|
13
|
+
exports.SOUND_WAIT_BACKSTOP_MS = 5 * 60 * 1000;
|
|
14
|
+
/**
|
|
15
|
+
* Per-scene sound store. PLAY adds an entry under a fresh playId; STOP removes
|
|
16
|
+
* by audio asset id (null = all). The whole <StudioSounds> list re-renders on
|
|
17
|
+
* any change, so subscribers are GLOBAL like StudioVariableStore (not per-key).
|
|
18
|
+
*/
|
|
19
|
+
class StudioSoundManager {
|
|
20
|
+
sounds = new Map();
|
|
21
|
+
listeners = new utils_1.GlobalListeners();
|
|
22
|
+
nextPlayId = 1;
|
|
23
|
+
// Per-playId completion callback for a step waiting on a non-looping PLAY.
|
|
24
|
+
// Fired on natural finish (via remove) AND when the sound is cut short by a
|
|
25
|
+
// stop/stopOthers/reset, so a waited-on sound never stalls the walk.
|
|
26
|
+
finishCallbacks = new Map();
|
|
27
|
+
// Backstop timer per waited playId; cleared whenever its callback fires so a
|
|
28
|
+
// sound whose native finish/error event never arrives can't stall the walk.
|
|
29
|
+
finishTimers = new Map();
|
|
30
|
+
/** Subscribe to any add/remove; returns an unsubscribe fn. */
|
|
31
|
+
subscribe(listener) {
|
|
32
|
+
return this.listeners.subscribe(listener);
|
|
33
|
+
}
|
|
34
|
+
getActive() {
|
|
35
|
+
return [...this.sounds.values()];
|
|
36
|
+
}
|
|
37
|
+
/** Pull and invoke the stored completion callback (if any) for a playId. */
|
|
38
|
+
fire(playId) {
|
|
39
|
+
const timer = this.finishTimers.get(playId);
|
|
40
|
+
if (timer !== undefined) {
|
|
41
|
+
clearTimeout(timer);
|
|
42
|
+
this.finishTimers.delete(playId);
|
|
43
|
+
}
|
|
44
|
+
const cb = this.finishCallbacks.get(playId);
|
|
45
|
+
if (!cb)
|
|
46
|
+
return;
|
|
47
|
+
this.finishCallbacks.delete(playId);
|
|
48
|
+
cb();
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Adds a sound and returns its playId. onFinish (when given) resolves a step
|
|
52
|
+
* waiting on a non-looping PLAY; it fires on natural finish or early stop.
|
|
53
|
+
*/
|
|
54
|
+
play(entry, onFinish) {
|
|
55
|
+
// stopOthers clears the live list; fire any pending waiters for the cleared
|
|
56
|
+
// entries so a displaced waited-on sound resolves instead of stalling.
|
|
57
|
+
if (entry.stopOthers) {
|
|
58
|
+
const cleared = [...this.sounds.keys()];
|
|
59
|
+
this.sounds.clear();
|
|
60
|
+
for (const id of cleared)
|
|
61
|
+
this.fire(id);
|
|
62
|
+
}
|
|
63
|
+
const playId = this.nextPlayId++;
|
|
64
|
+
this.sounds.set(playId, {
|
|
65
|
+
playId,
|
|
66
|
+
audioAssetId: entry.audioAssetId,
|
|
67
|
+
url: entry.url,
|
|
68
|
+
position: entry.position,
|
|
69
|
+
volume: entry.volume,
|
|
70
|
+
loop: entry.loop,
|
|
71
|
+
});
|
|
72
|
+
if (onFinish) {
|
|
73
|
+
this.finishCallbacks.set(playId, onFinish);
|
|
74
|
+
// Non-looping waited sound: arm the stall backstop. A looping sound is
|
|
75
|
+
// never awaited, so it gets no timer.
|
|
76
|
+
if (!entry.loop) {
|
|
77
|
+
this.finishTimers.set(playId, setTimeout(() => this.remove(playId), exports.SOUND_WAIT_BACKSTOP_MS));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if ((0, utils_1.isDev)()) {
|
|
81
|
+
console.log(`[Studio] Sound play "${entry.audioAssetId}" (#${playId})`);
|
|
82
|
+
}
|
|
83
|
+
this.listeners.notify();
|
|
84
|
+
return playId;
|
|
85
|
+
}
|
|
86
|
+
/** null = stop all sounds; otherwise stop every entry for this audio asset. */
|
|
87
|
+
stop(audioAssetId) {
|
|
88
|
+
const removed = [];
|
|
89
|
+
for (const [id, e] of this.sounds) {
|
|
90
|
+
if (audioAssetId === null || e.audioAssetId === audioAssetId) {
|
|
91
|
+
this.sounds.delete(id);
|
|
92
|
+
removed.push(id);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
this.listeners.notify();
|
|
96
|
+
// Resolve any waiters cut short by the stop.
|
|
97
|
+
for (const id of removed)
|
|
98
|
+
this.fire(id);
|
|
99
|
+
}
|
|
100
|
+
/** Drop one entry; onFinish calls this for non-looping sounds. */
|
|
101
|
+
remove(playId) {
|
|
102
|
+
if (this.sounds.delete(playId))
|
|
103
|
+
this.listeners.notify();
|
|
104
|
+
// Fire the stored callback whether or not the entry was still present
|
|
105
|
+
// (natural finish path: resolves the waiting step).
|
|
106
|
+
this.fire(playId);
|
|
107
|
+
}
|
|
108
|
+
reset() {
|
|
109
|
+
const pending = [...this.finishCallbacks.keys()];
|
|
110
|
+
this.sounds.clear();
|
|
111
|
+
this.listeners.notify();
|
|
112
|
+
// Belt-and-suspenders: the runtime's generation guard no-ops these after a
|
|
113
|
+
// scene-change cancelAll, but fire so nothing leaks on bare resets.
|
|
114
|
+
for (const id of pending)
|
|
115
|
+
this.fire(id);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
exports.StudioSoundManager = StudioSoundManager;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** True only in a dev build; gates verbose runtime logging in the Studio stores. */
|
|
2
|
+
export declare const isDev: () => boolean;
|
|
3
|
+
/** A set of subscribers notified together (variable + sound stores). */
|
|
4
|
+
export declare class GlobalListeners {
|
|
5
|
+
private listeners;
|
|
6
|
+
subscribe(listener: () => void): () => void;
|
|
7
|
+
notify(): void;
|
|
8
|
+
}
|
|
9
|
+
/** Subscribers partitioned by key; notify(key) wakes only that key's set
|
|
10
|
+
* (the visibility store's per-asset variant). */
|
|
11
|
+
export declare class KeyedListeners {
|
|
12
|
+
private listeners;
|
|
13
|
+
subscribe(key: string, listener: () => void): () => void;
|
|
14
|
+
notify(key: string): void;
|
|
15
|
+
notifyAll(): void;
|
|
16
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Small shared helpers for the Studio runtime domain.
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.KeyedListeners = exports.GlobalListeners = exports.isDev = void 0;
|
|
5
|
+
/** True only in a dev build; gates verbose runtime logging in the Studio stores. */
|
|
6
|
+
const isDev = () => typeof __DEV__ !== "undefined" && __DEV__;
|
|
7
|
+
exports.isDev = isDev;
|
|
8
|
+
/** A set of subscribers notified together (variable + sound stores). */
|
|
9
|
+
class GlobalListeners {
|
|
10
|
+
listeners = new Set();
|
|
11
|
+
subscribe(listener) {
|
|
12
|
+
this.listeners.add(listener);
|
|
13
|
+
return () => {
|
|
14
|
+
this.listeners.delete(listener);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
notify() {
|
|
18
|
+
// Snapshot first: a listener may (un)subscribe during its own callback.
|
|
19
|
+
[...this.listeners].forEach((fn) => fn());
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.GlobalListeners = GlobalListeners;
|
|
23
|
+
/** Subscribers partitioned by key; notify(key) wakes only that key's set
|
|
24
|
+
* (the visibility store's per-asset variant). */
|
|
25
|
+
class KeyedListeners {
|
|
26
|
+
listeners = new Map();
|
|
27
|
+
subscribe(key, listener) {
|
|
28
|
+
let set = this.listeners.get(key);
|
|
29
|
+
if (!set) {
|
|
30
|
+
set = new Set();
|
|
31
|
+
this.listeners.set(key, set);
|
|
32
|
+
}
|
|
33
|
+
set.add(listener);
|
|
34
|
+
return () => {
|
|
35
|
+
set?.delete(listener);
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
notify(key) {
|
|
39
|
+
// Snapshot first: a listener may (un)subscribe during its own callback.
|
|
40
|
+
const set = this.listeners.get(key);
|
|
41
|
+
if (set)
|
|
42
|
+
[...set].forEach((fn) => fn());
|
|
43
|
+
}
|
|
44
|
+
notifyAll() {
|
|
45
|
+
this.listeners.forEach((set) => [...set].forEach((fn) => fn()));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.KeyedListeners = KeyedListeners;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { StudioSceneVariable } from "../types";
|
|
2
|
+
import { StudioVariableValue } from "./expressionEvaluator";
|
|
3
|
+
/**
|
|
4
|
+
* Per-session variable store. One instance is owned by the navigator and
|
|
5
|
+
* survives scene pushes; it resets only when the AR/VR session ends.
|
|
6
|
+
*
|
|
7
|
+
* Identity is by NAME: scenes declaring the same name share one value, and
|
|
8
|
+
* seed() only initialises names not already present (initialize-if-absent),
|
|
9
|
+
* so values carry across scene transitions.
|
|
10
|
+
*/
|
|
11
|
+
export declare class StudioVariableStore {
|
|
12
|
+
private values;
|
|
13
|
+
private listeners;
|
|
14
|
+
get(name: string): StudioVariableValue | undefined;
|
|
15
|
+
/** Subscribe to value changes (set/reset); returns an unsubscribe fn. */
|
|
16
|
+
subscribe(listener: () => void): () => void;
|
|
17
|
+
set(name: string, value: StudioVariableValue): void;
|
|
18
|
+
seed(declarations: StudioSceneVariable[]): void;
|
|
19
|
+
reset(): void;
|
|
20
|
+
snapshot(): Record<string, StudioVariableValue>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StudioVariableStore = void 0;
|
|
4
|
+
const expressionEvaluator_1 = require("./expressionEvaluator");
|
|
5
|
+
const utils_1 = require("./utils");
|
|
6
|
+
/**
|
|
7
|
+
* Per-session variable store. One instance is owned by the navigator and
|
|
8
|
+
* survives scene pushes; it resets only when the AR/VR session ends.
|
|
9
|
+
*
|
|
10
|
+
* Identity is by NAME: scenes declaring the same name share one value, and
|
|
11
|
+
* seed() only initialises names not already present (initialize-if-absent),
|
|
12
|
+
* so values carry across scene transitions.
|
|
13
|
+
*/
|
|
14
|
+
class StudioVariableStore {
|
|
15
|
+
values = new Map();
|
|
16
|
+
listeners = new utils_1.GlobalListeners();
|
|
17
|
+
get(name) {
|
|
18
|
+
return this.values.get(name);
|
|
19
|
+
}
|
|
20
|
+
/** Subscribe to value changes (set/reset); returns an unsubscribe fn. */
|
|
21
|
+
subscribe(listener) {
|
|
22
|
+
return this.listeners.subscribe(listener);
|
|
23
|
+
}
|
|
24
|
+
set(name, value) {
|
|
25
|
+
// Values are primitives; skip the no-op write so unchanged values don't
|
|
26
|
+
// log or wake subscribers.
|
|
27
|
+
if (Object.is(this.values.get(name), value))
|
|
28
|
+
return;
|
|
29
|
+
this.values.set(name, value);
|
|
30
|
+
if ((0, utils_1.isDev)()) {
|
|
31
|
+
console.log(`[Studio] Variable "${name}" =`, value);
|
|
32
|
+
}
|
|
33
|
+
this.listeners.notify();
|
|
34
|
+
}
|
|
35
|
+
seed(declarations) {
|
|
36
|
+
for (const decl of declarations) {
|
|
37
|
+
if (!decl?.name)
|
|
38
|
+
continue;
|
|
39
|
+
if (!(0, expressionEvaluator_1.valueMatchesType)(decl.initial_value, decl.type)) {
|
|
40
|
+
console.warn(`[Studio] Variable "${decl.name}": initial value does not match type ${decl.type}; skipping seed.`);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const existing = this.values.get(decl.name);
|
|
44
|
+
if (existing !== undefined) {
|
|
45
|
+
if (!(0, expressionEvaluator_1.valueMatchesType)(existing, decl.type)) {
|
|
46
|
+
console.warn(`[Studio] Variable "${decl.name}" already holds a ${typeof existing} this session, but this scene declares ${decl.type}; keeping the existing value.`);
|
|
47
|
+
}
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
this.values.set(decl.name, decl.initial_value);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
reset() {
|
|
54
|
+
this.values.clear();
|
|
55
|
+
this.listeners.notify();
|
|
56
|
+
}
|
|
57
|
+
snapshot() {
|
|
58
|
+
const out = {};
|
|
59
|
+
this.values.forEach((value, name) => {
|
|
60
|
+
out[name] = value;
|
|
61
|
+
});
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
exports.StudioVariableStore = StudioVariableStore;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { StudioAnimation, StudioAsset, StudioSceneMeta, ViroAnimationProp } from "../types";
|
|
3
|
+
import { SequenceRuntimeContext } from "./sceneNavigationHandler";
|
|
3
4
|
type SceneNavigator = any;
|
|
4
5
|
export type NodeConfig = {
|
|
5
6
|
position: [number, number, number];
|
|
@@ -16,13 +17,7 @@ export type NodeConfig = {
|
|
|
16
17
|
onClick?: () => void;
|
|
17
18
|
animation?: ViroAnimationProp;
|
|
18
19
|
};
|
|
19
|
-
/**
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
*/
|
|
23
|
-
export declare function createNodeConfig(asset: StudioAsset, sceneNavigator: SceneNavigator | undefined, animations: StudioAnimation[], scene: StudioSceneMeta | null, onAnimationTrigger?: (targetAssetId: string, animKey: string) => void, animationStates?: Record<string, ViroAnimationProp>, onSceneChange?: (sceneId: string, sceneName: string) => void): NodeConfig;
|
|
24
|
-
/**
|
|
25
|
-
* Creates the appropriate Viro component for a StudioAsset.
|
|
26
|
-
*/
|
|
27
|
-
export declare function createNode(asset: StudioAsset, sceneNavigator: SceneNavigator | undefined, animations: StudioAnimation[], scene: StudioSceneMeta | null, onAnimationTrigger?: (targetAssetId: string, animKey: string) => void, animationStates?: Record<string, ViroAnimationProp>, onAssetLoaded?: (id: string) => void, onCollision?: (viroTag: string, collidedPoint: [number, number, number], collidedNormal: [number, number, number]) => void, onSceneChange?: (sceneId: string, sceneName: string) => void): React.ReactElement | null;
|
|
20
|
+
/** Clamps Z to -2 for non-trigger assets to guarantee visibility. */
|
|
21
|
+
export declare function createNodeConfig(asset: StudioAsset, sceneNavigator: SceneNavigator | undefined, animations: StudioAnimation[], scene: StudioSceneMeta | null, onAnimationTrigger?: (targetAssetId: string, animKey: string) => void, animationStates?: Record<string, ViroAnimationProp>, onSceneChange?: (sceneId: string, sceneName: string) => void, runtimeCtx?: SequenceRuntimeContext): NodeConfig;
|
|
22
|
+
export declare function createNode(asset: StudioAsset, sceneNavigator: SceneNavigator | undefined, animations: StudioAnimation[], scene: StudioSceneMeta | null, onAnimationTrigger?: (targetAssetId: string, animKey: string) => void, animationStates?: Record<string, ViroAnimationProp>, onAssetLoaded?: (id: string) => void, onCollision?: (viroTag: string, collidedPoint: [number, number, number], collidedNormal: [number, number, number]) => void, onSceneChange?: (sceneId: string, sceneName: string) => void, runtimeCtx?: SequenceRuntimeContext): React.ReactElement | null;
|
|
28
23
|
export {};
|
|
@@ -42,14 +42,12 @@ const ViroImage_1 = require("../../ViroImage");
|
|
|
42
42
|
const ViroText_1 = require("../../ViroText");
|
|
43
43
|
const ViroVideo_1 = require("../../ViroVideo");
|
|
44
44
|
const sceneNavigationHandler_1 = require("./sceneNavigationHandler");
|
|
45
|
+
const apiRequestHelpers_1 = require("./apiRequestHelpers");
|
|
45
46
|
const materialConfig_1 = require("./materialConfig");
|
|
46
47
|
const dragConfiguration_1 = require("./dragConfiguration");
|
|
47
48
|
const physicsConfig_1 = require("./physicsConfig");
|
|
48
|
-
/**
|
|
49
|
-
|
|
50
|
-
* Clamps Z to -2 for non-trigger assets to guarantee visibility.
|
|
51
|
-
*/
|
|
52
|
-
function createNodeConfig(asset, sceneNavigator, animations, scene, onAnimationTrigger, animationStates, onSceneChange) {
|
|
49
|
+
/** Clamps Z to -2 for non-trigger assets to guarantee visibility. */
|
|
50
|
+
function createNodeConfig(asset, sceneNavigator, animations, scene, onAnimationTrigger, animationStates, onSceneChange, runtimeCtx) {
|
|
53
51
|
const hasTriggerImage = !!asset.trigger_image_url;
|
|
54
52
|
let posZ = asset.position_z ?? -2;
|
|
55
53
|
if (!hasTriggerImage && posZ > -0.5) {
|
|
@@ -89,13 +87,25 @@ function createNodeConfig(asset, sceneNavigator, animations, scene, onAnimationT
|
|
|
89
87
|
dragPlane = dragConfiguration_1.DragConfiguration.getDragPlane(scene?.plane_direction ?? "Horizontal", position);
|
|
90
88
|
}
|
|
91
89
|
const parsedPhysics = (0, physicsConfig_1.parsePhysicsBodyConfig)(asset.physics_config);
|
|
92
|
-
const physicsBody = parsedPhysics
|
|
90
|
+
const physicsBody = parsedPhysics
|
|
91
|
+
? (0, physicsConfig_1.buildViroPhysicsBody)(parsedPhysics)
|
|
92
|
+
: undefined;
|
|
93
93
|
const viroTag = parsedPhysics ? asset.id : undefined;
|
|
94
|
-
const onClick = createOnClickHandler(asset, sceneNavigator, animations, onAnimationTrigger, onSceneChange);
|
|
94
|
+
const onClick = createOnClickHandler(asset, sceneNavigator, animations, onAnimationTrigger, onSceneChange, runtimeCtx);
|
|
95
95
|
const animation = animationStates?.[asset.id];
|
|
96
|
-
return {
|
|
96
|
+
return {
|
|
97
|
+
position,
|
|
98
|
+
rotation,
|
|
99
|
+
scale,
|
|
100
|
+
dragType,
|
|
101
|
+
dragPlane,
|
|
102
|
+
physicsBody,
|
|
103
|
+
viroTag,
|
|
104
|
+
onClick,
|
|
105
|
+
animation,
|
|
106
|
+
};
|
|
97
107
|
}
|
|
98
|
-
function createOnClickHandler(asset, sceneNavigator, animations, onAnimationTrigger, onSceneChange) {
|
|
108
|
+
function createOnClickHandler(asset, sceneNavigator, animations, onAnimationTrigger, onSceneChange, runtimeCtx) {
|
|
99
109
|
const fn = asset.scene_function;
|
|
100
110
|
if (!fn)
|
|
101
111
|
return undefined;
|
|
@@ -111,13 +121,11 @@ function createOnClickHandler(asset, sceneNavigator, animations, onAnimationTrig
|
|
|
111
121
|
console.warn(`[Studio] Asset "${asset.name}" has ANIMATION but no animation data`);
|
|
112
122
|
return undefined;
|
|
113
123
|
}
|
|
114
|
-
return () => (0, sceneNavigationHandler_1.executeFunctionWithRelations)(fn, sceneNavigator, animations, onAnimationTrigger, 0, onSceneChange);
|
|
124
|
+
return () => (0, sceneNavigationHandler_1.executeFunctionWithRelations)(fn, sceneNavigator, animations, onAnimationTrigger, 0, onSceneChange, runtimeCtx);
|
|
115
125
|
}
|
|
116
|
-
/** Resolves asset type from asset_type_name. */
|
|
117
126
|
function resolveType(asset) {
|
|
118
127
|
return asset.asset_type_name ?? null;
|
|
119
128
|
}
|
|
120
|
-
/** Infers 3D model format from file extension. */
|
|
121
129
|
function inferModelType(url) {
|
|
122
130
|
const ext = url.toLowerCase().split(".").pop();
|
|
123
131
|
if (ext === "gltf")
|
|
@@ -143,11 +151,15 @@ function create3DObject(asset, config, onAssetLoaded, onCollision) {
|
|
|
143
151
|
]
|
|
144
152
|
: config.scale;
|
|
145
153
|
const hasMaterialConfig = (0, materialConfig_1.parseMaterialConfig)(asset.material_config) !== null;
|
|
146
|
-
const shaderOverrides = hasMaterialConfig
|
|
154
|
+
const shaderOverrides = hasMaterialConfig
|
|
155
|
+
? [(0, materialConfig_1.studioMaterialName)(asset.id)]
|
|
156
|
+
: undefined;
|
|
147
157
|
return (<Viro3DObject_1.Viro3DObject key={asset.id} source={{ uri: asset.file_url }} position={config.position} rotation={config.rotation} scale={scale} type={modelType} dragType={config.dragType} dragPlane={config.dragPlane} animation={config.animation} onClick={config.onClick} renderingOrder={react_native_1.Platform.OS === "android" ? 1 : 0} onLoadEnd={() => onAssetLoaded?.(asset.id)} onError={(e) => console.error(`[Studio] 3D model "${asset.name}" error:`, e)}
|
|
148
158
|
// Viro derives native canDrag from `onDrag != undefined`; without this prop
|
|
149
159
|
// the drag recognizer is never attached, even when dragType is set.
|
|
150
|
-
{...(config.dragType ? { onDrag: () => { } } : {})} {...(shaderOverrides ? { shaderOverrides } : {})} {...(config.physicsBody
|
|
160
|
+
{...(config.dragType ? { onDrag: () => { } } : {})} {...(shaderOverrides ? { shaderOverrides } : {})} {...(config.physicsBody
|
|
161
|
+
? { physicsBody: config.physicsBody, viroTag: config.viroTag }
|
|
162
|
+
: {})} {...(onCollision ? { onCollision: onCollision } : {})}/>);
|
|
151
163
|
}
|
|
152
164
|
function createImage(asset, config, onAssetLoaded) {
|
|
153
165
|
if (!asset.file_url) {
|
|
@@ -156,13 +168,51 @@ function createImage(asset, config, onAssetLoaded) {
|
|
|
156
168
|
}
|
|
157
169
|
return (<ViroImage_1.ViroImage key={asset.id} source={{ uri: asset.file_url }} position={config.position} rotation={config.rotation} scale={config.scale} dragType={config.dragType} animation={config.animation} onClick={config.onClick} onLoadEnd={() => onAssetLoaded?.(asset.id)} onError={(e) => console.error(`[Studio] Image "${asset.name}" error:`, e)} {...(config.dragType ? { onDrag: () => { } } : {})}/>);
|
|
158
170
|
}
|
|
159
|
-
|
|
160
|
-
|
|
171
|
+
/**
|
|
172
|
+
* TEXT node whose content is a {{variable}} template (the asset name). It
|
|
173
|
+
* re-interpolates and repaints whenever a referenced variable changes (and only
|
|
174
|
+
* subscribes when the template actually has placeholders). Resolution is
|
|
175
|
+
* fail-soft: unknown names stay literal.
|
|
176
|
+
*/
|
|
177
|
+
const VariableText = ({ asset, config, store, visible }) => {
|
|
178
|
+
const template = asset.name ?? "";
|
|
179
|
+
const compute = () => store
|
|
180
|
+
? (0, apiRequestHelpers_1.interpolateDisplayTemplate)(template, (n) => store.get(n))
|
|
181
|
+
: template;
|
|
182
|
+
const [text, setText] = React.useState(compute);
|
|
183
|
+
React.useEffect(() => {
|
|
184
|
+
if (!store || (0, apiRequestHelpers_1.extractPlaceholders)(template).length === 0)
|
|
185
|
+
return;
|
|
186
|
+
// Resync any write that landed between first render and subscribe.
|
|
187
|
+
setText(compute());
|
|
188
|
+
return store.subscribe(() => setText(compute()));
|
|
189
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
190
|
+
}, [store, template]);
|
|
191
|
+
return (<ViroText_1.ViroText text={text} position={config.position} rotation={config.rotation} scale={config.scale} dragType={config.dragType} animation={config.animation} onClick={config.onClick} {...(visible === undefined ? {} : { visible })} style={{
|
|
161
192
|
fontFamily: "Arial",
|
|
162
193
|
fontSize: 20,
|
|
163
194
|
color: "#FFFFFF",
|
|
164
195
|
textAlign: "center",
|
|
165
196
|
}} {...(config.dragType ? { onDrag: () => { } } : {})}/>);
|
|
197
|
+
};
|
|
198
|
+
/**
|
|
199
|
+
* Wraps a created node and drives its `visible` prop from the per-scene
|
|
200
|
+
* visibility store, subscribing to its own asset so a Set Visibility action
|
|
201
|
+
* repaints only this node. Without a store, the node stays visible.
|
|
202
|
+
*/
|
|
203
|
+
const VisibleNode = ({ assetId, store, children }) => {
|
|
204
|
+
const [visible, setVisible] = React.useState(() => store?.isVisible(assetId) ?? true);
|
|
205
|
+
React.useEffect(() => {
|
|
206
|
+
if (!store)
|
|
207
|
+
return;
|
|
208
|
+
// Resync any write that landed between first render and subscribe.
|
|
209
|
+
setVisible(store.isVisible(assetId));
|
|
210
|
+
return store.subscribe(assetId, () => setVisible(store.isVisible(assetId)));
|
|
211
|
+
}, [store, assetId]);
|
|
212
|
+
return React.cloneElement(children, { visible });
|
|
213
|
+
};
|
|
214
|
+
function createText(asset, config, store) {
|
|
215
|
+
return (<VariableText key={asset.id} asset={asset} config={config} store={store}/>);
|
|
166
216
|
}
|
|
167
217
|
function createVideo(asset, config) {
|
|
168
218
|
if (!asset.file_url) {
|
|
@@ -171,23 +221,32 @@ function createVideo(asset, config) {
|
|
|
171
221
|
}
|
|
172
222
|
return (<ViroVideo_1.ViroVideo key={asset.id} source={{ uri: asset.file_url }} position={config.position} rotation={config.rotation} scale={config.scale} dragType={config.dragType} animation={config.animation} onClick={config.onClick} loop={true} muted={false} onError={(e) => console.error(`[Studio] Video "${asset.name}" error:`, e)} {...(config.dragType ? { onDrag: () => { } } : {})}/>);
|
|
173
223
|
}
|
|
174
|
-
|
|
175
|
-
* Creates the appropriate Viro component for a StudioAsset.
|
|
176
|
-
*/
|
|
177
|
-
function createNode(asset, sceneNavigator, animations, scene, onAnimationTrigger, animationStates, onAssetLoaded, onCollision, onSceneChange) {
|
|
224
|
+
function createNode(asset, sceneNavigator, animations, scene, onAnimationTrigger, animationStates, onAssetLoaded, onCollision, onSceneChange, runtimeCtx) {
|
|
178
225
|
const type = resolveType(asset);
|
|
179
|
-
const config = createNodeConfig(asset, sceneNavigator, animations, scene, onAnimationTrigger, animationStates, onSceneChange);
|
|
226
|
+
const config = createNodeConfig(asset, sceneNavigator, animations, scene, onAnimationTrigger, animationStates, onSceneChange, runtimeCtx);
|
|
227
|
+
let node;
|
|
180
228
|
switch (type) {
|
|
181
229
|
case "3D-MODEL":
|
|
182
|
-
|
|
230
|
+
node = create3DObject(asset, config, onAssetLoaded, onCollision);
|
|
231
|
+
break;
|
|
183
232
|
case "IMAGE":
|
|
184
|
-
|
|
233
|
+
node = createImage(asset, config, onAssetLoaded);
|
|
234
|
+
break;
|
|
185
235
|
case "TEXT":
|
|
186
|
-
|
|
236
|
+
node = createText(asset, config, runtimeCtx?.variableStore);
|
|
237
|
+
break;
|
|
187
238
|
case "VIDEO":
|
|
188
|
-
|
|
239
|
+
node = createVideo(asset, config);
|
|
240
|
+
break;
|
|
189
241
|
default:
|
|
190
242
|
console.warn(`[Studio] Unknown asset type "${type}" for "${asset.name}"`);
|
|
191
243
|
return null;
|
|
192
244
|
}
|
|
245
|
+
if (!node)
|
|
246
|
+
return null;
|
|
247
|
+
// Drive show/hide/toggle from the visibility store (Set Visibility actions);
|
|
248
|
+
// seeded from the asset's author-time hidden_on_load default.
|
|
249
|
+
return (<VisibleNode key={asset.id} assetId={asset.id} store={runtimeCtx?.visibilityStore}>
|
|
250
|
+
{node}
|
|
251
|
+
</VisibleNode>);
|
|
193
252
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { StudioAsset } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Per-scene visibility store, keyed by scene asset placement id. Seeded from
|
|
4
|
+
* each asset's author-time `hidden_on_load` default at scene load; Set
|
|
5
|
+
* Visibility actions then flip the live value. Toggle reads the current value
|
|
6
|
+
* here, never the author default.
|
|
7
|
+
*
|
|
8
|
+
* Listeners are per-asset (unlike the global variable store) so a Set
|
|
9
|
+
* Visibility on one object repaints only that node, not the whole scene. Node
|
|
10
|
+
* factories subscribe to their own asset id.
|
|
11
|
+
*/
|
|
12
|
+
export declare class StudioVisibilityStore {
|
|
13
|
+
private visible;
|
|
14
|
+
private listeners;
|
|
15
|
+
/** Current visibility; defaults to visible for assets never seeded/set. */
|
|
16
|
+
isVisible(assetId: string): boolean;
|
|
17
|
+
/** Subscribe to changes for one asset; returns an unsubscribe fn. */
|
|
18
|
+
subscribe(assetId: string, listener: () => void): () => void;
|
|
19
|
+
/** Initialise-if-absent from author-time defaults (idempotent, strict-mode safe). */
|
|
20
|
+
seed(assets: StudioAsset[]): void;
|
|
21
|
+
/**
|
|
22
|
+
* Apply a Set Visibility action. TOGGLE flips the live value; VISIBLE/HIDDEN
|
|
23
|
+
* set it absolutely. No-op writes don't wake subscribers.
|
|
24
|
+
*/
|
|
25
|
+
apply(assetId: string, state: "VISIBLE" | "HIDDEN" | "TOGGLE"): void;
|
|
26
|
+
/**
|
|
27
|
+
* Re-initialise for a new scene: replace all values from author-time
|
|
28
|
+
* defaults, THEN notify every subscribed asset so mounted nodes re-read.
|
|
29
|
+
* Order matters — notifying before re-seeding would briefly surface the
|
|
30
|
+
* visible default for an asset that starts hidden.
|
|
31
|
+
*/
|
|
32
|
+
reseed(assets: StudioAsset[]): void;
|
|
33
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StudioVisibilityStore = void 0;
|
|
4
|
+
const utils_1 = require("./utils");
|
|
5
|
+
/**
|
|
6
|
+
* Per-scene visibility store, keyed by scene asset placement id. Seeded from
|
|
7
|
+
* each asset's author-time `hidden_on_load` default at scene load; Set
|
|
8
|
+
* Visibility actions then flip the live value. Toggle reads the current value
|
|
9
|
+
* here, never the author default.
|
|
10
|
+
*
|
|
11
|
+
* Listeners are per-asset (unlike the global variable store) so a Set
|
|
12
|
+
* Visibility on one object repaints only that node, not the whole scene. Node
|
|
13
|
+
* factories subscribe to their own asset id.
|
|
14
|
+
*/
|
|
15
|
+
class StudioVisibilityStore {
|
|
16
|
+
visible = new Map();
|
|
17
|
+
listeners = new utils_1.KeyedListeners();
|
|
18
|
+
/** Current visibility; defaults to visible for assets never seeded/set. */
|
|
19
|
+
isVisible(assetId) {
|
|
20
|
+
return this.visible.get(assetId) ?? true;
|
|
21
|
+
}
|
|
22
|
+
/** Subscribe to changes for one asset; returns an unsubscribe fn. */
|
|
23
|
+
subscribe(assetId, listener) {
|
|
24
|
+
return this.listeners.subscribe(assetId, listener);
|
|
25
|
+
}
|
|
26
|
+
/** Initialise-if-absent from author-time defaults (idempotent, strict-mode safe). */
|
|
27
|
+
seed(assets) {
|
|
28
|
+
for (const asset of assets) {
|
|
29
|
+
if (!asset?.id)
|
|
30
|
+
continue;
|
|
31
|
+
if (this.visible.has(asset.id))
|
|
32
|
+
continue;
|
|
33
|
+
this.visible.set(asset.id, !asset.hidden_on_load);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Apply a Set Visibility action. TOGGLE flips the live value; VISIBLE/HIDDEN
|
|
38
|
+
* set it absolutely. No-op writes don't wake subscribers.
|
|
39
|
+
*/
|
|
40
|
+
apply(assetId, state) {
|
|
41
|
+
const next = state === "TOGGLE" ? !this.isVisible(assetId) : state === "VISIBLE";
|
|
42
|
+
if (this.visible.get(assetId) === next)
|
|
43
|
+
return;
|
|
44
|
+
this.visible.set(assetId, next);
|
|
45
|
+
if ((0, utils_1.isDev)()) {
|
|
46
|
+
console.log(`[Studio] Visibility "${assetId}" =`, next);
|
|
47
|
+
}
|
|
48
|
+
this.listeners.notify(assetId);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Re-initialise for a new scene: replace all values from author-time
|
|
52
|
+
* defaults, THEN notify every subscribed asset so mounted nodes re-read.
|
|
53
|
+
* Order matters — notifying before re-seeding would briefly surface the
|
|
54
|
+
* visible default for an asset that starts hidden.
|
|
55
|
+
*/
|
|
56
|
+
reseed(assets) {
|
|
57
|
+
this.visible.clear();
|
|
58
|
+
for (const asset of assets) {
|
|
59
|
+
if (!asset?.id)
|
|
60
|
+
continue;
|
|
61
|
+
this.visible.set(asset.id, !asset.hidden_on_load);
|
|
62
|
+
}
|
|
63
|
+
this.listeners.notifyAll();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
exports.StudioVisibilityStore = StudioVisibilityStore;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { StudioARScene } from "./StudioARScene";
|
|
2
2
|
export { StudioSceneNavigator } from "./StudioSceneNavigator";
|
|
3
|
-
export type { StudioAnimation, StudioAsset, StudioCollisionBinding, StudioProjectApiResponse, StudioProjectAsset, StudioProjectMeta, StudioProjectOpeningScene, StudioProjectOverview, StudioProjectSceneSummary, StudioSceneCreatedBy, StudioSceneFunction, StudioSceneMeta, StudioSceneResponse, ViroAnimationProp, } from "./types";
|
|
3
|
+
export type { StudioAnimation, StudioAsset, StudioCollisionBinding, StudioProjectApiResponse, StudioProjectAsset, StudioProjectMeta, StudioProjectOpeningScene, StudioProjectOverview, StudioProjectSceneSummary, StudioSceneCreatedBy, StudioSceneFunction, StudioSceneMeta, StudioSceneResponse, StudioSceneVariable, ViroAnimationProp, } from "./types";
|