@reactvision/react-viro 2.57.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.
Files changed (91) hide show
  1. package/android/react_viro/react_viro-release.aar +0 -0
  2. package/android/viro_renderer/viro_renderer-release.aar +0 -0
  3. package/components/AR/ViroARPlane.tsx +1 -4
  4. package/components/AR/ViroARPlaneSelector.tsx +10 -5
  5. package/components/AR/ViroARScene.tsx +2 -4
  6. package/components/Studio/StudioARScene.tsx +243 -48
  7. package/components/Studio/StudioSceneNavigator.tsx +15 -0
  8. package/components/Studio/VRTStudioModule.ts +10 -0
  9. package/components/Studio/domain/StudioSounds.tsx +46 -0
  10. package/components/Studio/domain/apiRequestHelpers.ts +612 -0
  11. package/components/Studio/domain/collisionBindingsRuntime.ts +17 -2
  12. package/components/Studio/domain/defaultApiRequestExecutor.ts +61 -0
  13. package/components/Studio/domain/expressionEvaluator.ts +603 -0
  14. package/components/Studio/domain/sceneNavigationHandler.ts +770 -20
  15. package/components/Studio/domain/soundManager.ts +141 -0
  16. package/components/Studio/domain/utils.ts +50 -0
  17. package/components/Studio/domain/variableStore.ts +74 -0
  18. package/components/Studio/domain/viroNodeFactory.tsx +175 -44
  19. package/components/Studio/domain/visibilityStore.ts +66 -0
  20. package/components/Studio/index.ts +1 -0
  21. package/components/Studio/types.ts +178 -1
  22. package/components/Utilities/VRModuleOpenXR.ts +35 -0
  23. package/components/Utilities/ViroVersion.ts +1 -1
  24. package/components/ViroAnimatedImage.tsx +1 -0
  25. package/components/ViroFlexView.tsx +1 -0
  26. package/components/ViroImage.tsx +1 -0
  27. package/components/ViroObjectDetector.tsx +13 -5
  28. package/components/ViroParticleEmitter.tsx +2 -0
  29. package/components/ViroPolygon.tsx +2 -1
  30. package/components/ViroQuad.tsx +2 -1
  31. package/components/ViroSurface.tsx +1 -0
  32. package/components/ViroVideo.tsx +1 -0
  33. package/components/ViroXRSceneNavigator.tsx +8 -0
  34. package/dist/components/AR/ViroARPlane.d.ts +1 -1
  35. package/dist/components/AR/ViroARPlane.js +1 -5
  36. package/dist/components/AR/ViroARPlaneSelector.d.ts +1 -1
  37. package/dist/components/AR/ViroARPlaneSelector.js +10 -5
  38. package/dist/components/AR/ViroARScene.d.ts +1 -1
  39. package/dist/components/AR/ViroARScene.js +2 -5
  40. package/dist/components/Studio/StudioARScene.d.ts +3 -0
  41. package/dist/components/Studio/StudioARScene.js +142 -15
  42. package/dist/components/Studio/StudioSceneNavigator.js +14 -0
  43. package/dist/components/Studio/VRTStudioModule.d.ts +6 -0
  44. package/dist/components/Studio/VRTStudioModule.js +10 -0
  45. package/dist/components/Studio/domain/StudioSounds.d.ts +11 -0
  46. package/dist/components/Studio/domain/StudioSounds.js +69 -0
  47. package/dist/components/Studio/domain/apiRequestHelpers.d.ts +180 -0
  48. package/dist/components/Studio/domain/apiRequestHelpers.js +496 -0
  49. package/dist/components/Studio/domain/collisionBindingsRuntime.d.ts +3 -1
  50. package/dist/components/Studio/domain/collisionBindingsRuntime.js +4 -3
  51. package/dist/components/Studio/domain/defaultApiRequestExecutor.d.ts +14 -0
  52. package/dist/components/Studio/domain/defaultApiRequestExecutor.js +58 -0
  53. package/dist/components/Studio/domain/expressionEvaluator.d.ts +108 -0
  54. package/dist/components/Studio/domain/expressionEvaluator.js +520 -0
  55. package/dist/components/Studio/domain/sceneNavigationHandler.d.ts +35 -8
  56. package/dist/components/Studio/domain/sceneNavigationHandler.js +564 -22
  57. package/dist/components/Studio/domain/soundManager.d.ts +52 -0
  58. package/dist/components/Studio/domain/soundManager.js +118 -0
  59. package/dist/components/Studio/domain/utils.d.ts +16 -0
  60. package/dist/components/Studio/domain/utils.js +48 -0
  61. package/dist/components/Studio/domain/variableStore.d.ts +21 -0
  62. package/dist/components/Studio/domain/variableStore.js +65 -0
  63. package/dist/components/Studio/domain/viroNodeFactory.d.ts +4 -9
  64. package/dist/components/Studio/domain/viroNodeFactory.js +84 -25
  65. package/dist/components/Studio/domain/visibilityStore.d.ts +33 -0
  66. package/dist/components/Studio/domain/visibilityStore.js +66 -0
  67. package/dist/components/Studio/index.d.ts +1 -1
  68. package/dist/components/Studio/types.d.ts +150 -1
  69. package/dist/components/Utilities/VRModuleOpenXR.d.ts +19 -0
  70. package/dist/components/Utilities/VRModuleOpenXR.js +16 -0
  71. package/dist/components/Utilities/ViroVersion.d.ts +1 -1
  72. package/dist/components/Utilities/ViroVersion.js +1 -1
  73. package/dist/components/ViroAnimatedImage.js +1 -0
  74. package/dist/components/ViroFlexView.js +1 -0
  75. package/dist/components/ViroImage.js +1 -0
  76. package/dist/components/ViroObjectDetector.d.ts +13 -5
  77. package/dist/components/ViroObjectDetector.js +13 -5
  78. package/dist/components/ViroParticleEmitter.js +2 -0
  79. package/dist/components/ViroPolygon.js +1 -0
  80. package/dist/components/ViroQuad.js +1 -0
  81. package/dist/components/ViroSurface.js +1 -0
  82. package/dist/components/ViroVideo.js +1 -0
  83. package/dist/components/ViroXRSceneNavigator.d.ts +8 -0
  84. package/dist/index.d.ts +4 -4
  85. package/dist/index.js +2 -1
  86. package/dist/plugins/withViroAndroid.js +18 -0
  87. package/index.ts +4 -3
  88. package/ios/dist/ViroRenderer/ViroKit.framework/Info.plist +0 -0
  89. package/ios/dist/ViroRenderer/ViroKit.framework/Shaders.dat +1 -1
  90. package/ios/dist/lib/libViroReact.a +0 -0
  91. package/package.json +1 -1
@@ -0,0 +1,66 @@
1
+ import { StudioAsset } from "../types";
2
+ import { KeyedListeners, isDev } from "./utils";
3
+
4
+ /**
5
+ * Per-scene visibility store, keyed by scene asset placement id. Seeded from
6
+ * each asset's author-time `hidden_on_load` default at scene load; Set
7
+ * Visibility actions then flip the live value. Toggle reads the current value
8
+ * here, never the author default.
9
+ *
10
+ * Listeners are per-asset (unlike the global variable store) so a Set
11
+ * Visibility on one object repaints only that node, not the whole scene. Node
12
+ * factories subscribe to their own asset id.
13
+ */
14
+ export class StudioVisibilityStore {
15
+ private visible = new Map<string, boolean>();
16
+ private listeners = new KeyedListeners();
17
+
18
+ /** Current visibility; defaults to visible for assets never seeded/set. */
19
+ isVisible(assetId: string): boolean {
20
+ return this.visible.get(assetId) ?? true;
21
+ }
22
+
23
+ /** Subscribe to changes for one asset; returns an unsubscribe fn. */
24
+ subscribe(assetId: string, listener: () => void): () => void {
25
+ return this.listeners.subscribe(assetId, listener);
26
+ }
27
+
28
+ /** Initialise-if-absent from author-time defaults (idempotent, strict-mode safe). */
29
+ seed(assets: StudioAsset[]): void {
30
+ for (const asset of assets) {
31
+ if (!asset?.id) continue;
32
+ if (this.visible.has(asset.id)) continue;
33
+ this.visible.set(asset.id, !asset.hidden_on_load);
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Apply a Set Visibility action. TOGGLE flips the live value; VISIBLE/HIDDEN
39
+ * set it absolutely. No-op writes don't wake subscribers.
40
+ */
41
+ apply(assetId: string, state: "VISIBLE" | "HIDDEN" | "TOGGLE"): void {
42
+ const next =
43
+ state === "TOGGLE" ? !this.isVisible(assetId) : state === "VISIBLE";
44
+ if (this.visible.get(assetId) === next) return;
45
+ this.visible.set(assetId, next);
46
+ if (isDev()) {
47
+ console.log(`[Studio] Visibility "${assetId}" =`, next);
48
+ }
49
+ this.listeners.notify(assetId);
50
+ }
51
+
52
+ /**
53
+ * Re-initialise for a new scene: replace all values from author-time
54
+ * defaults, THEN notify every subscribed asset so mounted nodes re-read.
55
+ * Order matters — notifying before re-seeding would briefly surface the
56
+ * visible default for an asset that starts hidden.
57
+ */
58
+ reseed(assets: StudioAsset[]): void {
59
+ this.visible.clear();
60
+ for (const asset of assets) {
61
+ if (!asset?.id) continue;
62
+ this.visible.set(asset.id, !asset.hidden_on_load);
63
+ }
64
+ this.listeners.notifyAll();
65
+ }
66
+ }
@@ -14,5 +14,6 @@ export type {
14
14
  StudioSceneFunction,
15
15
  StudioSceneMeta,
16
16
  StudioSceneResponse,
17
+ StudioSceneVariable,
17
18
  ViroAnimationProp,
18
19
  } from "./types";
@@ -24,13 +24,159 @@ export interface StudioProjectMeta {
24
24
  occlusion_mode: "NONE" | "PEOPLEONLY" | "DEPTHBASED";
25
25
  }
26
26
 
27
+ /**
28
+ * One ordered step of a Sequence: an ACTION (runs a function), a WAIT (timed
29
+ * pause), or a STOP (explicit terminal — the run halts here).
30
+ */
31
+ export interface StudioSequenceStep {
32
+ id: string;
33
+ step_order: number;
34
+ step_type: "ACTION" | "WAIT" | "STOP";
35
+ duration_ms: number | null; // set for WAIT
36
+ function_id: string | null; // set for ACTION
37
+ function: StudioSceneFunction | null; // resolved child for ACTION; null for WAIT/STOP
38
+ // false (default) = wait for this step's effect to finish before the next
39
+ // step; true = fire-and-forget. Ignored for instant/terminal kinds.
40
+ advance_immediately: boolean;
41
+ }
42
+
43
+ export interface StudioSequence {
44
+ id: string;
45
+ name: string | null;
46
+ steps: StudioSequenceStep[];
47
+ }
48
+
49
+ /** Scene-level variable declaration. Runtime state lives in StudioVariableStore. */
50
+ export interface StudioSceneVariable {
51
+ id: string;
52
+ name: string;
53
+ type: "BOOLEAN" | "NUMBER" | "STRING";
54
+ initial_value: boolean | number | string;
55
+ }
56
+
57
+ /**
58
+ * One ordered predicate arm of a BRANCH. Variable names/types are joined from
59
+ * project_variables so they follow renames. The arm is an owned, headless
60
+ * sequence run like a nested sequence.
61
+ */
62
+ export interface StudioBranchCondition {
63
+ id: string;
64
+ eval_order: number;
65
+ variable_id: string;
66
+ variable_name: string;
67
+ variable_type: "BOOLEAN" | "NUMBER" | "STRING";
68
+ comparison:
69
+ | "EQUALS"
70
+ | "NOT_EQUALS"
71
+ | "GREATER_THAN"
72
+ | "LESS_THAN"
73
+ | "GREATER_OR_EQUAL"
74
+ | "LESS_OR_EQUAL"
75
+ | "LIKE"
76
+ | "ILIKE";
77
+ compare_literal: boolean | number | string | null;
78
+ compare_variable_id: string | null;
79
+ compare_variable_name: string | null;
80
+ compare_variable_type: "BOOLEAN" | "NUMBER" | "STRING" | null;
81
+ sequence: StudioSequence;
82
+ }
83
+
84
+ /**
85
+ * BRANCH payload. Conditions are evaluated in eval_order (first match wins),
86
+ * falling through to the optional no-match arm. Arms are owned, headless
87
+ * sequences run like nested sequences.
88
+ */
89
+ export interface StudioSceneBranch {
90
+ id: string;
91
+ conditions: StudioBranchCondition[];
92
+ no_match_sequence: StudioSequence | null;
93
+ }
94
+
95
+ /**
96
+ * GROUP payload. Owns N lanes, each an owned headless sequence run like a
97
+ * nested sequence. Lanes run concurrently; the group completes when all lanes
98
+ * complete (barrier join).
99
+ */
100
+ export interface StudioSceneGroup {
101
+ id: string;
102
+ lanes: { lane_order: number; sequence: StudioSequence }[];
103
+ }
104
+
105
+ /** One response->variable binding of an API_REQUEST function. */
106
+ export interface StudioApiRequestBinding {
107
+ id: string;
108
+ source: "BODY" | "STATUS" | "OK" | "ERROR_MESSAGE";
109
+ selector: string | null;
110
+ variable_id: string;
111
+ variable_name: string;
112
+ variable_type: "BOOLEAN" | "NUMBER" | "STRING";
113
+ bind_order: number;
114
+ }
115
+
116
+ /**
117
+ * API_REQUEST payload. The HTTP call executes server-side through the
118
+ * platform egress proxy (the client only ever sends the function id plus
119
+ * current variable values); connection_id is an opaque server-side
120
+ * reference. Arms are owned, headless sequences run like nested sequences.
121
+ */
122
+ export interface StudioSceneApiRequest {
123
+ id: string;
124
+ method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
125
+ url_template: string;
126
+ headers: { key: string; value_template: string }[];
127
+ body_template: string | null;
128
+ timeout_ms: number;
129
+ connection_id: string | null;
130
+ bindings: StudioApiRequestBinding[];
131
+ success_sequence: StudioSequence | null;
132
+ failure_sequence: StudioSequence | null;
133
+ }
134
+
135
+ /** Outcome envelope an API-request executor resolves with. */
136
+ export interface StudioApiRequestOutcome {
137
+ ok: boolean;
138
+ status: number | null;
139
+ body?: unknown;
140
+ error_code?: string | null;
141
+ error_message?: string | null;
142
+ }
143
+
144
+ /**
145
+ * Host-app transport for API_REQUEST functions: StudioGo calls the
146
+ * scene-api-request edge function with the user JWT; production Viro apps
147
+ * call it with their X-API-Key. Must resolve with an outcome (reject only on
148
+ * transport failure).
149
+ */
150
+ export type StudioApiRequestExecutor = (
151
+ functionId: string,
152
+ variables: Record<string, boolean | number | string>,
153
+ ) => Promise<StudioApiRequestOutcome>;
154
+
27
155
  export interface StudioSceneFunction {
28
156
  id: string;
29
157
  scene: string;
30
- function_type: "NAVIGATION" | "ALERT" | "ANIMATION";
158
+ function_type:
159
+ | "NAVIGATION"
160
+ | "ALERT"
161
+ | "ANIMATION"
162
+ | "SEQUENCE"
163
+ | "SET_VARIABLE"
164
+ | "BRANCH"
165
+ | "API_REQUEST"
166
+ | "SET_VISIBILITY"
167
+ | "SOUND"
168
+ | "GROUP";
31
169
  navigation: string | null;
32
170
  alert: string | null;
33
171
  animation: string | null;
172
+ sequence: string | null;
173
+ set_variable: string | null;
174
+ branch: string | null;
175
+ api_request: string | null;
176
+ set_visibility: string | null;
177
+ sound: string | null;
178
+ // Named group_fn because `group` is a reserved SQL keyword.
179
+ group_fn: string | null;
34
180
  scene_navigation: { id: string; navigate_to: string } | null;
35
181
  scene_alert: {
36
182
  id: string;
@@ -44,6 +190,33 @@ export interface StudioSceneFunction {
44
190
  delay_ms: number | null;
45
191
  properties: Record<string, unknown>;
46
192
  } | null;
193
+ scene_sequence: StudioSequence | null;
194
+ /** name/type are joined from the target scene_variables row, so they follow renames. */
195
+ scene_set_variable: {
196
+ id: string;
197
+ variable_id: string;
198
+ name: string;
199
+ type: "BOOLEAN" | "NUMBER" | "STRING";
200
+ expression: string;
201
+ } | null;
202
+ scene_branch: StudioSceneBranch | null;
203
+ scene_api_request: StudioSceneApiRequest | null;
204
+ scene_set_visibility: {
205
+ id: string;
206
+ target_asset_id: string;
207
+ state: "VISIBLE" | "HIDDEN" | "TOGGLE";
208
+ } | null;
209
+ scene_sound: {
210
+ id: string;
211
+ action: "PLAY" | "STOP";
212
+ audio_asset_id: string | null;
213
+ audio_url: string | null;
214
+ target_asset_id: string | null;
215
+ volume: number;
216
+ loop: boolean;
217
+ stop_other_sounds: boolean;
218
+ } | null;
219
+ scene_group: StudioSceneGroup | null;
47
220
  }
48
221
 
49
222
  export interface StudioAsset {
@@ -63,6 +236,8 @@ export interface StudioAsset {
63
236
  latitude: number | null;
64
237
  longitude: number | null;
65
238
  is_draggable: boolean;
239
+ /** Author-time "hidden on start"; the runtime seeds visibility from it. */
240
+ hidden_on_load: boolean | null;
66
241
  trigger_image_url: string | null;
67
242
  trigger_image_orientation: "Up" | "Down" | "Left" | "Right" | null;
68
243
  trigger_image_physical_width_m: number | null;
@@ -149,6 +324,8 @@ export interface StudioSceneResponse {
149
324
  collision_bindings: StudioCollisionBinding[];
150
325
  animations: StudioAnimation[];
151
326
  functions: StudioSceneFunction[];
327
+ /** Absent in responses from backends predating the Variables feature. */
328
+ variables?: StudioSceneVariable[];
152
329
  meta: { request_id: string };
153
330
  }
154
331
 
@@ -15,8 +15,43 @@ export function exitVRScene(): void {
15
15
  export type VRModuleOpenXRType = {
16
16
  recenterTracking?: (viewTag: number) => void;
17
17
  setPassthroughEnabled?: (viewTag: number, enabled: boolean) => void;
18
+ setPassthroughStyle?: (
19
+ viewTag: number,
20
+ opacity: number,
21
+ edgeR: number,
22
+ edgeG: number,
23
+ edgeB: number,
24
+ edgeA: number
25
+ ) => void;
18
26
  };
19
27
 
28
+ /** Options for {@link setPassthroughStyle}. All channels are normalized [0,1]. */
29
+ export type ViroPassthroughStyle = {
30
+ /** Texture opacity factor [0,1]. Default 1 (fully opaque passthrough). */
31
+ opacity?: number;
32
+ /** Edge-highlight colour [r,g,b,a]. Alpha 0 (default) disables the edge effect. */
33
+ edgeColor?: [number, number, number, number];
34
+ };
35
+
36
+ /**
37
+ * Style the Quest passthrough layer (XR_FB_passthrough). No-op off-Quest.
38
+ *
39
+ * ```tsx
40
+ * const viewTag = useVRViewTag();
41
+ * if (viewTag != null) {
42
+ * setPassthroughStyle(viewTag, { opacity: 0.8, edgeColor: [0, 1, 1, 1] });
43
+ * }
44
+ * ```
45
+ */
46
+ export function setPassthroughStyle(
47
+ viewTag: number,
48
+ style: ViroPassthroughStyle
49
+ ): void {
50
+ const opacity = style.opacity ?? 1;
51
+ const [r, g, b, a] = style.edgeColor ?? [0, 0, 0, 0];
52
+ VRModuleOpenXR?.setPassthroughStyle?.(viewTag, opacity, r, g, b, a);
53
+ }
54
+
20
55
  /**
21
56
  * Typed reference to the VRModuleOpenXR native module.
22
57
  * undefined when not running on Meta Quest (no-op calls are safe via optional chaining).
@@ -1 +1 @@
1
- export const VIRO_VERSION = "2.57.0";
1
+ export const VIRO_VERSION = "2.57.2";
@@ -170,6 +170,7 @@ export class ViroAnimatedImage extends ViroBase<Props> {
170
170
  nativeProps.style = [this.props.style];
171
171
  nativeProps.onHoverViro = this._onHover;
172
172
  nativeProps.onClickViro = this._onClickState;
173
+ nativeProps.onClick = undefined;
173
174
  nativeProps.onTouchViro = this._onTouch;
174
175
  nativeProps.onScrollViro = this._onScroll;
175
176
  nativeProps.onSwipeViro = this._onSwipe;
@@ -59,6 +59,7 @@ export class ViroFlexView extends ViroBase<Props> {
59
59
  nativeProps.transformBehaviors = transformBehaviors;
60
60
  nativeProps.onHoverViro = this._onHover;
61
61
  nativeProps.onClickViro = this._onClickState;
62
+ nativeProps.onClick = undefined;
62
63
  nativeProps.onTouchViro = this._onTouch;
63
64
  nativeProps.onScrollViro = this._onScroll;
64
65
  nativeProps.onSwipeViro = this._onSwipe;
@@ -142,6 +142,7 @@ export class ViroImage extends ViroBase<Props> {
142
142
  nativeProps.style = [this.props.style];
143
143
  nativeProps.onHoverViro = this._onHover;
144
144
  nativeProps.onClickViro = this._onClickState;
145
+ nativeProps.onClick = undefined;
145
146
  nativeProps.onTouchViro = this._onTouch;
146
147
  nativeProps.onScrollViro = this._onScroll;
147
148
  nativeProps.onSwipeViro = this._onSwipe;
@@ -146,11 +146,19 @@ const VRTObjectDetectorView = requireNativeComponent<any>("VRTObjectDetectorView
146
146
  /**
147
147
  * ViroObjectDetector — on-device open-vocabulary object detection powered by YOLOE.
148
148
  *
149
- * Runs **only in AR**: it shares the camera feed of the enclosing
150
- * `ViroARSceneNavigator` (no separate camera session, no preview of its own) and
151
- * fires `onDetection` with labels, normalized bounding boxes, and an on-screen
152
- * `screenBoundingBox` (dp) at up to `maxFPS`. Mount it as a child or sibling of a
153
- * `ViroARSceneNavigator`; it renders nothing itself, so give it `width: 0, height: 0`.
149
+ * Runs in AR and on Meta Quest:
150
+ * - **Phone AR**: shares the camera feed of the enclosing `ViroARSceneNavigator`
151
+ * (no separate camera session) and fires `onDetection` with labels, normalized
152
+ * bounding boxes, and an on-screen `screenBoundingBox` (dp) at up to `maxFPS`.
153
+ * - **Meta Quest 3 / 3S** (Horizon OS v74+): when mounted in a Quest MR scene
154
+ * (under `ViroXRSceneNavigator`), it captures the headset camera via the Meta
155
+ * Passthrough Camera API and runs the same YOLOE pipeline. Requires the
156
+ * `horizonos.permission.HEADSET_CAMERA` runtime permission. v1 emits `label` +
157
+ * normalized `boundingBox` only — `screenBoundingBox` and `worldPosition` are
158
+ * not provided on Quest yet (they need camera extrinsics).
159
+ *
160
+ * Mount it as a child or sibling of the scene navigator; it renders nothing itself,
161
+ * so give it `width: 0, height: 0`.
154
162
  *
155
163
  * @example
156
164
  * ```tsx
@@ -261,6 +261,7 @@ export class ViroParticleEmitter extends React.Component<Props, State> {
261
261
  : undefined;
262
262
  // Create native props object.
263
263
  let nativeProps = Object.assign({} as any, this.props);
264
+ nativeProps.onClick = undefined;
264
265
  nativeProps.position = this.state.propsPositionState;
265
266
  nativeProps.onNativeTransformDelegateViro = transformDelegate;
266
267
  nativeProps.hasTransformDelegate =
@@ -344,6 +345,7 @@ export class ViroParticleEmitter extends React.Component<Props, State> {
344
345
  };
345
346
  nativeProps.particleAppearance.rotation = newAppearanceRotMod;
346
347
  }
348
+ nativeProps.onClick = undefined;
347
349
  nativeProps.ref = (component: ViroNativeRef) => {
348
350
  this._component = component;
349
351
  };
@@ -60,7 +60,7 @@ type Props = {
60
60
  * that texture partially over the entire surface.
61
61
  */
62
62
  uvCoordinates?: ViroUVCoordinate;
63
- arShadowReceiver?: boolean
63
+ arShadowReceiver?: boolean;
64
64
  style?: ViroStyle;
65
65
  };
66
66
 
@@ -104,6 +104,7 @@ export class ViroPolygon extends ViroBase<Props> {
104
104
  nativeProps.style = [this.props.style];
105
105
  nativeProps.onHoverViro = this._onHover;
106
106
  nativeProps.onClickViro = this._onClickState;
107
+ nativeProps.onClick = undefined;
107
108
  nativeProps.onTouchViro = this._onTouch;
108
109
  nativeProps.onScrollViro = this._onScroll;
109
110
  nativeProps.onSwipeViro = this._onSwipe;
@@ -18,7 +18,7 @@ import { checkMisnamedProps } from "./Utilities/ViroProps";
18
18
  import { ViroBase } from "./ViroBase";
19
19
 
20
20
  type Props = {
21
- arShadowReceiver?: boolean
21
+ arShadowReceiver?: boolean;
22
22
  uvCoordinates?: ViroUVCoordinate[];
23
23
  };
24
24
 
@@ -62,6 +62,7 @@ export class ViroQuad extends ViroBase<Props> {
62
62
  nativeProps.style = [this.props.style];
63
63
  nativeProps.onHoverViro = this._onHover;
64
64
  nativeProps.onClickViro = this._onClickState;
65
+ nativeProps.onClick = undefined;
65
66
  nativeProps.onTouchViro = this._onTouch;
66
67
  nativeProps.onScrollViro = this._onScroll;
67
68
  nativeProps.onSwipeViro = this._onSwipe;
@@ -65,6 +65,7 @@ export class ViroSurface extends ViroBase<Props> {
65
65
  nativeProps.style = [this.props.style];
66
66
  nativeProps.onHoverViro = this._onHover;
67
67
  nativeProps.onClickViro = this._onClickState;
68
+ nativeProps.onClick = undefined;
68
69
  nativeProps.onTouchViro = this._onTouch;
69
70
  nativeProps.onScrollViro = this._onScroll;
70
71
  nativeProps.onSwipeViro = this._onSwipe;
@@ -131,6 +131,7 @@ export class ViroVideo extends ViroBase<Props> {
131
131
  nativeProps.onUpdateTimeViro = this._onUpdateTime;
132
132
  nativeProps.onHoverViro = this._onHover;
133
133
  nativeProps.onClickViro = this._onClickState;
134
+ nativeProps.onClick = undefined;
134
135
  nativeProps.onTouchViro = this._onTouch;
135
136
  nativeProps.onScrollViro = this._onScroll;
136
137
  nativeProps.onSwipeViro = this._onSwipe;
@@ -59,6 +59,14 @@ type Props = ViewProps & {
59
59
  * On Quest, this scene is forwarded to VRActivity via VRQuestNavigatorBridge
60
60
  * rather than rendered inline, because OpenXR exclusive display requires the
61
61
  * VR intent category on the host Activity.
62
+ *
63
+ * The scene root may be either:
64
+ * - `ViroScene` → fully-virtual VR.
65
+ * - `ViroARScene` → mixed reality: passthrough is enabled automatically and
66
+ * real-time plane detection (XR_EXT_plane_detection, Quest 3 / 3S) drives
67
+ * `onAnchorFound` and `ViroARPlane`, exactly as on phone AR. A single
68
+ * AR-rooted `initialScene` therefore runs on phones (ARCore) and Quest (OpenXR)
69
+ * with no per-platform changes. See docs/QUEST_SETUP.md §7b.
62
70
  */
63
71
  vrInitialScene?: SceneFactory;
64
72
 
@@ -25,6 +25,6 @@ export declare class ViroARPlane extends ViroBase<Props> {
25
25
  _onAnchorFound: (event: NativeSyntheticEvent<ViroARAnchorFoundEvent>) => void;
26
26
  _onAnchorUpdated: (event: NativeSyntheticEvent<ViroARAnchorUpdatedEvent>) => void;
27
27
  _onAnchorRemoved: (_event: NativeSyntheticEvent<ViroARAnchorRemovedEvent>) => void;
28
- render(): React.JSX.Element | null;
28
+ render(): React.JSX.Element;
29
29
  }
30
30
  export {};
@@ -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
- if (ViroPlatform_1.isQuest) {
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 | null;
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
- if (ViroPlatform_1.isQuest) {
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
- writesToDepthBuffer: false,
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
  });
@@ -113,6 +113,6 @@ export declare class ViroARScene extends ViroBase<Props> {
113
113
  up: any[];
114
114
  }>;
115
115
  getCameraPositionAsync: () => Promise<any>;
116
- render(): React.JSX.Element | null;
116
+ render(): React.JSX.Element;
117
117
  }
118
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;
@@ -290,10 +289,8 @@ class ViroARScene extends ViroBase_1.ViroBase {
290
289
  return await ViroCameraModule.getCameraPosition((0, react_native_1.findNodeHandle)(this));
291
290
  };
292
291
  render() {
293
- if (ViroPlatform_1.isQuest) {
294
- console.warn("[Viro] ViroARScene is not supported on Quest and will not render. Use ViroScene instead.");
295
- return null;
296
- }
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.
297
294
  // Uncomment this line to check for misnamed props
298
295
  //checkMisnamedProps("ViroARScene", this.props);
299
296
  // Since anchorDetectionTypes can be either a string or an array, convert the string to a 1-element array.
@@ -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