@reactvision/react-viro 2.54.0 → 2.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/README.md +85 -46
  2. package/android/react_viro/react_viro-release.aar +0 -0
  3. package/android/viro_renderer/viro_renderer-release.aar +0 -0
  4. package/components/AR/ViroARCamera.tsx +5 -0
  5. package/components/AR/ViroARImageMarker.tsx +5 -0
  6. package/components/AR/ViroARObjectMarker.tsx +5 -0
  7. package/components/AR/ViroARPlane.tsx +5 -0
  8. package/components/AR/ViroARPlaneSelector.tsx +5 -0
  9. package/components/AR/ViroARScene.tsx +5 -0
  10. package/components/AR/ViroARSceneNavigator.tsx +54 -0
  11. package/components/Studio/StudioARScene.tsx +368 -0
  12. package/components/Studio/StudioSceneNavigator.tsx +191 -0
  13. package/components/Studio/VRTStudioModule.ts +40 -0
  14. package/components/Studio/domain/animationRegistry.ts +86 -0
  15. package/components/Studio/domain/collisionBindingsRuntime.ts +93 -0
  16. package/components/Studio/domain/collisionPairKey.ts +15 -0
  17. package/components/Studio/domain/dragConfiguration.ts +48 -0
  18. package/components/Studio/domain/materialConfig.ts +276 -0
  19. package/components/Studio/domain/physicsConfig.ts +204 -0
  20. package/components/Studio/domain/sceneNavigationHandler.ts +150 -0
  21. package/components/Studio/domain/studioMaterials.ts +33 -0
  22. package/components/Studio/domain/triggerImageRegistry.ts +64 -0
  23. package/components/Studio/domain/useStudioShaderTimeUniforms.ts +51 -0
  24. package/components/Studio/domain/useStudioShaderViewportUniforms.ts +52 -0
  25. package/components/Studio/domain/viroNodeFactory.tsx +323 -0
  26. package/components/Studio/index.ts +18 -0
  27. package/components/Studio/types.ts +164 -0
  28. package/components/Types/ViroEvents.ts +53 -0
  29. package/components/Utilities/VRModuleOpenXR.ts +50 -0
  30. package/components/Utilities/VRQuestNavigatorBridge.ts +168 -0
  31. package/components/Utilities/ViroPlatform.ts +52 -0
  32. package/components/Utilities/ViroVersion.ts +1 -1
  33. package/components/Utilities/useAnySourceHover.ts +55 -0
  34. package/components/Utilities/useAnySourcePressed.ts +70 -0
  35. package/components/ViroQuestEntryPoint.tsx +79 -0
  36. package/components/ViroVRSceneNavigator.tsx +44 -19
  37. package/components/ViroXRSceneNavigator.tsx +217 -0
  38. package/components/VisionOS/ViroVisionOSModule.ts +93 -0
  39. package/dist/components/AR/ViroARCamera.d.ts +1 -1
  40. package/dist/components/AR/ViroARCamera.js +5 -0
  41. package/dist/components/AR/ViroARImageMarker.d.ts +1 -1
  42. package/dist/components/AR/ViroARImageMarker.js +5 -0
  43. package/dist/components/AR/ViroARObjectMarker.d.ts +1 -1
  44. package/dist/components/AR/ViroARObjectMarker.js +5 -0
  45. package/dist/components/AR/ViroARPlane.d.ts +1 -1
  46. package/dist/components/AR/ViroARPlane.js +5 -0
  47. package/dist/components/AR/ViroARPlaneSelector.d.ts +1 -1
  48. package/dist/components/AR/ViroARPlaneSelector.js +5 -0
  49. package/dist/components/AR/ViroARScene.d.ts +1 -1
  50. package/dist/components/AR/ViroARScene.js +5 -0
  51. package/dist/components/AR/ViroARSceneNavigator.d.ts +13 -0
  52. package/dist/components/AR/ViroARSceneNavigator.js +36 -0
  53. package/dist/components/Studio/StudioARScene.d.ts +15 -0
  54. package/dist/components/Studio/StudioARScene.js +299 -0
  55. package/dist/components/Studio/StudioSceneNavigator.d.ts +31 -0
  56. package/dist/components/Studio/StudioSceneNavigator.js +174 -0
  57. package/dist/components/Studio/VRTStudioModule.d.ts +15 -0
  58. package/dist/components/Studio/VRTStudioModule.js +31 -0
  59. package/dist/components/Studio/domain/animationRegistry.d.ts +11 -0
  60. package/dist/components/Studio/domain/animationRegistry.js +67 -0
  61. package/dist/components/Studio/domain/collisionBindingsRuntime.d.ts +21 -0
  62. package/dist/components/Studio/domain/collisionBindingsRuntime.js +54 -0
  63. package/dist/components/Studio/domain/collisionPairKey.d.ts +8 -0
  64. package/dist/components/Studio/domain/collisionPairKey.js +15 -0
  65. package/dist/components/Studio/domain/dragConfiguration.d.ts +20 -0
  66. package/dist/components/Studio/domain/dragConfiguration.js +37 -0
  67. package/dist/components/Studio/domain/materialConfig.d.ts +56 -0
  68. package/dist/components/Studio/domain/materialConfig.js +239 -0
  69. package/dist/components/Studio/domain/physicsConfig.d.ts +69 -0
  70. package/dist/components/Studio/domain/physicsConfig.js +165 -0
  71. package/dist/components/Studio/domain/sceneNavigationHandler.d.ts +12 -0
  72. package/dist/components/Studio/domain/sceneNavigationHandler.js +112 -0
  73. package/dist/components/Studio/domain/studioMaterials.d.ts +6 -0
  74. package/dist/components/Studio/domain/studioMaterials.js +30 -0
  75. package/dist/components/Studio/domain/triggerImageRegistry.d.ts +13 -0
  76. package/dist/components/Studio/domain/triggerImageRegistry.js +47 -0
  77. package/dist/components/Studio/domain/useStudioShaderTimeUniforms.d.ts +6 -0
  78. package/dist/components/Studio/domain/useStudioShaderTimeUniforms.js +48 -0
  79. package/dist/components/Studio/domain/useStudioShaderViewportUniforms.d.ts +6 -0
  80. package/dist/components/Studio/domain/useStudioShaderViewportUniforms.js +48 -0
  81. package/dist/components/Studio/domain/viroNodeFactory.d.ts +28 -0
  82. package/dist/components/Studio/domain/viroNodeFactory.js +193 -0
  83. package/dist/components/Studio/index.d.ts +3 -0
  84. package/dist/components/Studio/index.js +7 -0
  85. package/dist/components/Studio/types.d.ts +149 -0
  86. package/dist/components/Studio/types.js +4 -0
  87. package/dist/components/Types/ViroEvents.d.ts +49 -1
  88. package/dist/components/Types/ViroEvents.js +1 -0
  89. package/dist/components/Utilities/VRModuleOpenXR.d.ts +32 -0
  90. package/dist/components/Utilities/VRModuleOpenXR.js +44 -0
  91. package/dist/components/Utilities/VRQuestNavigatorBridge.d.ts +85 -0
  92. package/dist/components/Utilities/VRQuestNavigatorBridge.js +124 -0
  93. package/dist/components/Utilities/ViroPlatform.d.ts +10 -0
  94. package/dist/components/Utilities/ViroPlatform.js +43 -0
  95. package/dist/components/Utilities/ViroVersion.d.ts +1 -1
  96. package/dist/components/Utilities/ViroVersion.js +1 -1
  97. package/dist/components/Utilities/useAnySourceHover.d.ts +36 -0
  98. package/dist/components/Utilities/useAnySourceHover.js +48 -0
  99. package/dist/components/Utilities/useAnySourcePressed.d.ts +37 -0
  100. package/dist/components/Utilities/useAnySourcePressed.js +61 -0
  101. package/dist/components/ViroQuestEntryPoint.d.ts +13 -0
  102. package/dist/components/ViroQuestEntryPoint.js +104 -0
  103. package/dist/components/ViroVRSceneNavigator.d.ts +24 -10
  104. package/dist/components/ViroVRSceneNavigator.js +21 -18
  105. package/dist/components/ViroXRSceneNavigator.d.ts +54 -0
  106. package/dist/components/ViroXRSceneNavigator.js +173 -0
  107. package/dist/components/VisionOS/ViroVisionOSModule.d.ts +65 -0
  108. package/dist/components/VisionOS/ViroVisionOSModule.js +91 -0
  109. package/dist/index.d.ts +15 -2
  110. package/dist/index.js +32 -2
  111. package/dist/plugins/withViro.d.ts +17 -1
  112. package/dist/plugins/withViroAndroid.js +312 -7
  113. package/dist/plugins/withViroIos.js +5 -0
  114. package/dist/plugins/withViroVisionOS.d.ts +24 -0
  115. package/dist/plugins/withViroVisionOS.js +265 -0
  116. package/index.ts +58 -0
  117. package/ios/ViroReact.podspec +13 -4
  118. package/ios/dist/ViroRenderer/ViroKit.framework/ARCoreCoreMLSemanticsResources.bundle/Info.plist +0 -0
  119. package/ios/dist/ViroRenderer/ViroKit.framework/ARCoreResources.bundle/Info.plist +0 -0
  120. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROARSession.h +10 -0
  121. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROARSessioniOS.h +4 -0
  122. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROInputControllerBase.h +74 -0
  123. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROInputType.h +11 -3
  124. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VROPlatformUtil.h +13 -0
  125. package/ios/dist/ViroRenderer/ViroKit.framework/Headers/VRORenderer.h +8 -0
  126. package/ios/dist/ViroRenderer/ViroKit.framework/Info.plist +0 -0
  127. package/ios/dist/ViroRenderer/ViroKit.framework/Shaders.dat +1 -1
  128. package/ios/dist/ViroRenderer/ViroKit.framework/ViroKit +0 -0
  129. package/ios/dist/ViroRenderer/ViroKit.podspec +5 -0
  130. package/ios/dist/include/VRTARSceneNavigator.h +3 -0
  131. package/ios/dist/include/VRTStudioModule.h +6 -0
  132. package/ios/dist/lib/libViroReact.a +0 -0
  133. package/package.json +1 -1
@@ -45,6 +45,7 @@ var __importStar = (this && this.__importStar) || (function () {
45
45
  Object.defineProperty(exports, "__esModule", { value: true });
46
46
  exports.ViroARPlaneSelector = void 0;
47
47
  const React = __importStar(require("react"));
48
+ const ViroPlatform_1 = require("../Utilities/ViroPlatform");
48
49
  const ViroMaterials_1 = require("../Material/ViroMaterials");
49
50
  const ViroNode_1 = require("../ViroNode");
50
51
  const ViroQuad_1 = require("../ViroQuad");
@@ -284,6 +285,10 @@ class ViroARPlaneSelector extends React.Component {
284
285
  // Render
285
286
  // ---------------------------------------------------------------------------
286
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
+ }
287
292
  return <ViroNode_1.ViroNode>{this._renderPlanes()}</ViroNode_1.ViroNode>;
288
293
  }
289
294
  _renderPlanes() {
@@ -101,6 +101,6 @@ export declare class ViroARScene extends ViroBase<Props> {
101
101
  up: any[];
102
102
  }>;
103
103
  getCameraPositionAsync: () => Promise<any>;
104
- render(): React.JSX.Element;
104
+ render(): React.JSX.Element | null;
105
105
  }
106
106
  export {};
@@ -52,6 +52,7 @@ 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");
55
56
  const ViroCameraModule = react_native_1.NativeModules.ViroCameraModule;
56
57
  class ViroARScene extends ViroBase_1.ViroBase {
57
58
  onTrackingFirstInitialized = false;
@@ -283,6 +284,10 @@ class ViroARScene extends ViroBase_1.ViroBase {
283
284
  return await ViroCameraModule.getCameraPosition((0, react_native_1.findNodeHandle)(this));
284
285
  };
285
286
  render() {
287
+ if (ViroPlatform_1.isQuest) {
288
+ console.warn("[Viro] ViroARScene is not supported on Quest and will not render. Use ViroScene instead.");
289
+ return null;
290
+ }
286
291
  // Uncomment this line to check for misnamed props
287
292
  //checkMisnamedProps("ViroARScene", this.props);
288
293
  // Since anchorDetectionTypes can be either a string or an array, convert the string to a 1-element array.
@@ -30,6 +30,12 @@ type Props = ViewProps & {
30
30
  scene: () => React.JSX.Element;
31
31
  };
32
32
  initialSceneKey?: string;
33
+ /**
34
+ * Optional fallback rendered when this navigator is mounted on a Meta Quest
35
+ * device (where AR is not supported). When omitted, a default message view
36
+ * is rendered. Pass `null` to render nothing.
37
+ */
38
+ questFallback?: React.ReactNode;
33
39
  autofocus?: boolean;
34
40
  /**
35
41
  * iOS only props! Note: these props may change as the underlying platforms coalesce in features.
@@ -172,6 +178,7 @@ type State = {
172
178
  * ViroARSceneNavigator is used to transition between multiple AR Scenes.
173
179
  */
174
180
  export declare class ViroARSceneNavigator extends React.Component<Props, State> {
181
+ static _questWarningLogged: boolean;
175
182
  _component: ViroNativeRef;
176
183
  constructor(props: Props);
177
184
  componentDidMount(): void;
@@ -499,6 +506,8 @@ export declare class ViroARSceneNavigator extends React.Component<Props, State>
499
506
  _rvUpdateCloudAnchor: (anchorId: string, name: string, description: string, isPublic: boolean) => Promise<any>;
500
507
  _rvDeleteCloudAnchor: (anchorId: string) => Promise<any>;
501
508
  _rvFindNearbyCloudAnchors: (latitude: number, longitude: number, radius: number, limit: number) => Promise<any>;
509
+ _rvGetProject: () => Promise<any>;
510
+ _rvGetScene: (sceneId: string) => Promise<any>;
502
511
  _rvGetSceneAssets: (sceneId: string) => Promise<any>;
503
512
  _rvAttachAssetToCloudAnchor: (anchorId: string, fileUrl: string, fileSize: number, name: string, assetType: string, externalUserId: string) => Promise<any>;
504
513
  _rvRemoveAssetFromCloudAnchor: (anchorId: string, assetId: string) => Promise<any>;
@@ -618,6 +627,8 @@ export declare class ViroARSceneNavigator extends React.Component<Props, State>
618
627
  rvAttachAssetToCloudAnchor: (anchorId: string, fileUrl: string, fileSize: number, name: string, assetType: string, externalUserId: string) => Promise<any>;
619
628
  rvRemoveAssetFromCloudAnchor: (anchorId: string, assetId: string) => Promise<any>;
620
629
  rvTrackCloudAnchorResolution: (anchorId: string, success: boolean, confidence: number, matchCount: number, inlierCount: number, processingTimeMs: number, platform: string, externalUserId: string) => Promise<any>;
630
+ rvGetProject: () => Promise<any>;
631
+ rvGetScene: (sceneId: string) => Promise<any>;
621
632
  rvGetSceneAssets: (sceneId: string) => Promise<any>;
622
633
  rvUploadAsset: (filePath: string, assetType: string, fileName: string, appUserId?: string) => Promise<any>;
623
634
  isSemanticModeSupported: () => Promise<ViroSemanticSupportResult>;
@@ -670,6 +681,8 @@ export declare class ViroARSceneNavigator extends React.Component<Props, State>
670
681
  rvAttachAssetToCloudAnchor: (anchorId: string, fileUrl: string, fileSize: number, name: string, assetType: string, externalUserId: string) => Promise<any>;
671
682
  rvRemoveAssetFromCloudAnchor: (anchorId: string, assetId: string) => Promise<any>;
672
683
  rvTrackCloudAnchorResolution: (anchorId: string, success: boolean, confidence: number, matchCount: number, inlierCount: number, processingTimeMs: number, platform: string, externalUserId: string) => Promise<any>;
684
+ rvGetProject: () => Promise<any>;
685
+ rvGetScene: (sceneId: string) => Promise<any>;
673
686
  rvGetSceneAssets: (sceneId: string) => Promise<any>;
674
687
  rvUploadAsset: (filePath: string, assetType: string, fileName: string, appUserId?: string) => Promise<any>;
675
688
  isSemanticModeSupported: () => Promise<ViroSemanticSupportResult>;
@@ -47,12 +47,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
47
47
  exports.ViroARSceneNavigator = void 0;
48
48
  const React = __importStar(require("react"));
49
49
  const react_native_1 = require("react-native");
50
+ const ViroPlatform_1 = require("../Utilities/ViroPlatform");
50
51
  const ViroARSceneNavigatorModule = react_native_1.NativeModules.VRTARSceneNavigatorModule;
51
52
  let mathRandomOffset = 0;
52
53
  /**
53
54
  * ViroARSceneNavigator is used to transition between multiple AR Scenes.
54
55
  */
55
56
  class ViroARSceneNavigator extends React.Component {
57
+ static _questWarningLogged = false;
56
58
  _component = null;
57
59
  constructor(props) {
58
60
  super(props);
@@ -681,6 +683,12 @@ class ViroARSceneNavigator extends React.Component {
681
683
  _rvFindNearbyCloudAnchors = async (latitude, longitude, radius, limit) => {
682
684
  return await ViroARSceneNavigatorModule.rvFindNearbyCloudAnchors((0, react_native_1.findNodeHandle)(this), latitude, longitude, radius, limit);
683
685
  };
686
+ _rvGetProject = async () => {
687
+ return await ViroARSceneNavigatorModule.rvGetProject((0, react_native_1.findNodeHandle)(this));
688
+ };
689
+ _rvGetScene = async (sceneId) => {
690
+ return await ViroARSceneNavigatorModule.rvGetScene((0, react_native_1.findNodeHandle)(this), sceneId);
691
+ };
684
692
  _rvGetSceneAssets = async (sceneId) => {
685
693
  return await ViroARSceneNavigatorModule.rvGetSceneAssets((0, react_native_1.findNodeHandle)(this), sceneId);
686
694
  };
@@ -904,6 +912,8 @@ class ViroARSceneNavigator extends React.Component {
904
912
  rvAttachAssetToCloudAnchor: this._rvAttachAssetToCloudAnchor,
905
913
  rvRemoveAssetFromCloudAnchor: this._rvRemoveAssetFromCloudAnchor,
906
914
  rvTrackCloudAnchorResolution: this._rvTrackCloudAnchorResolution,
915
+ rvGetProject: this._rvGetProject,
916
+ rvGetScene: this._rvGetScene,
907
917
  rvGetSceneAssets: this._rvGetSceneAssets,
908
918
  // Assets API
909
919
  rvUploadAsset: this._rvUploadAsset,
@@ -963,6 +973,8 @@ class ViroARSceneNavigator extends React.Component {
963
973
  rvAttachAssetToCloudAnchor: this._rvAttachAssetToCloudAnchor,
964
974
  rvRemoveAssetFromCloudAnchor: this._rvRemoveAssetFromCloudAnchor,
965
975
  rvTrackCloudAnchorResolution: this._rvTrackCloudAnchorResolution,
976
+ rvGetProject: this._rvGetProject,
977
+ rvGetScene: this._rvGetScene,
966
978
  rvGetSceneAssets: this._rvGetSceneAssets,
967
979
  // Assets API
968
980
  rvUploadAsset: this._rvUploadAsset,
@@ -982,6 +994,21 @@ class ViroARSceneNavigator extends React.Component {
982
994
  render() {
983
995
  // Uncomment this line to check for misnamed props
984
996
  //checkMisnamedProps("ViroARSceneNavigator", this.props);
997
+ if (ViroPlatform_1.isQuest) {
998
+ if (!ViroARSceneNavigator._questWarningLogged) {
999
+ console.warn("[Viro] ViroARSceneNavigator is not supported on Meta Quest. " +
1000
+ "Use ViroXRSceneNavigator (auto-detects Quest) or ViroVRSceneNavigator instead.");
1001
+ ViroARSceneNavigator._questWarningLogged = true;
1002
+ }
1003
+ if ("questFallback" in this.props) {
1004
+ return <>{this.props.questFallback}</>;
1005
+ }
1006
+ return (<react_native_1.View style={[styles.container, styles.questFallback]}>
1007
+ <react_native_1.Text style={styles.questFallbackText}>
1008
+ AR is not supported on Meta Quest.
1009
+ </react_native_1.Text>
1010
+ </react_native_1.View>);
1011
+ }
985
1012
  const items = this._renderSceneStackItems();
986
1013
  // update the arSceneNavigator with the latest given props on every render
987
1014
  this.arSceneNavigator.viroAppProps = this.props.viroAppProps;
@@ -1010,6 +1037,15 @@ const styles = react_native_1.StyleSheet.create({
1010
1037
  justifyContent: "center",
1011
1038
  alignItems: "center",
1012
1039
  },
1040
+ questFallback: {
1041
+ backgroundColor: "#000",
1042
+ padding: 24,
1043
+ },
1044
+ questFallbackText: {
1045
+ color: "#fff",
1046
+ fontSize: 16,
1047
+ textAlign: "center",
1048
+ },
1013
1049
  });
1014
1050
  const VRTARSceneNavigator = (0, react_native_1.requireNativeComponent)("VRTARSceneNavigator",
1015
1051
  // @ts-ignore
@@ -0,0 +1,15 @@
1
+ import * as React from "react";
2
+ import { StudioSceneResponse } from "./types";
3
+ interface StudioARSceneProps {
4
+ sceneNavigator?: any;
5
+ sceneData: StudioSceneResponse | null;
6
+ onReady?: () => void;
7
+ onError?: (err: Error) => void;
8
+ onSceneChange?: (sceneId: string, sceneName: string) => void;
9
+ }
10
+ /**
11
+ * Outer gate: keeps the hooks-bearing inner component out of the tree until
12
+ * sceneData is available, avoiding a Rules of Hooks violation.
13
+ */
14
+ export declare const StudioARScene: React.FC<StudioARSceneProps>;
15
+ export {};
@@ -0,0 +1,299 @@
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.StudioARScene = void 0;
37
+ const React = __importStar(require("react"));
38
+ const react_1 = require("react");
39
+ const react_native_1 = require("react-native");
40
+ const ViroAmbientLight_1 = require("../ViroAmbientLight");
41
+ const ViroARImageMarker_1 = require("../AR/ViroARImageMarker");
42
+ const ViroARPlane_1 = require("../AR/ViroARPlane");
43
+ const ViroARPlaneSelector_1 = require("../AR/ViroARPlaneSelector");
44
+ const ViroARScene_1 = require("../AR/ViroARScene");
45
+ const ViroScene_1 = require("../ViroScene");
46
+ const ViroText_1 = require("../ViroText");
47
+ const ViroController_1 = require("../ViroController");
48
+ const ViroPlatform_1 = require("../Utilities/ViroPlatform");
49
+ const animationRegistry_1 = require("./domain/animationRegistry");
50
+ const collisionBindingsRuntime_1 = require("./domain/collisionBindingsRuntime");
51
+ const collisionPairKey_1 = require("./domain/collisionPairKey");
52
+ const triggerImageRegistry_1 = require("./domain/triggerImageRegistry");
53
+ const viroNodeFactory_1 = require("./domain/viroNodeFactory");
54
+ const sceneNavigationHandler_1 = require("./domain/sceneNavigationHandler");
55
+ const studioMaterials_1 = require("./domain/studioMaterials");
56
+ const useStudioShaderTimeUniforms_1 = require("./domain/useStudioShaderTimeUniforms");
57
+ const useStudioShaderViewportUniforms_1 = require("./domain/useStudioShaderViewportUniforms");
58
+ const physicsConfig_1 = require("./domain/physicsConfig");
59
+ const ANDROID_MAX_3D_MODELS = 3;
60
+ const IOS_MAX_3D_MODELS = 10;
61
+ /**
62
+ * Outer gate: keeps the hooks-bearing inner component out of the tree until
63
+ * sceneData is available, avoiding a Rules of Hooks violation.
64
+ */
65
+ const StudioARScene = (props) => {
66
+ if (!props.sceneData) {
67
+ return ViroPlatform_1.isQuest ? <ViroScene_1.ViroScene /> : <ViroARScene_1.ViroARScene />;
68
+ }
69
+ return <StudioARSceneInner {...props} sceneData={props.sceneData}/>;
70
+ };
71
+ exports.StudioARScene = StudioARScene;
72
+ const StudioARSceneInner = (props) => {
73
+ const { sceneNavigator, sceneData, onReady, onSceneChange } = props;
74
+ const { scene, assets, animations, collision_bindings, functions } = sceneData;
75
+ // ─── Material registration ────────────────────────────────────────────────
76
+ const materialsRegisteredRef = (0, react_1.useRef)(false);
77
+ if (!materialsRegisteredRef.current) {
78
+ (0, studioMaterials_1.registerStudioMaterialsForAssets)(assets);
79
+ materialsRegisteredRef.current = true;
80
+ }
81
+ (0, useStudioShaderTimeUniforms_1.useStudioShaderTimeUniforms)(assets);
82
+ (0, useStudioShaderViewportUniforms_1.useStudioShaderViewportUniforms)(assets);
83
+ // ─── Animation registration ───────────────────────────────────────────────
84
+ const registeredKeyRef = (0, react_1.useRef)(null);
85
+ const animationsKey = animations.map((a) => a.animation_key).join(",");
86
+ if (animations.length > 0 && registeredKeyRef.current !== animationsKey) {
87
+ registeredKeyRef.current = animationsKey;
88
+ (0, animationRegistry_1.registerSceneAnimations)(animations);
89
+ }
90
+ // ─── Animation runtime state ──────────────────────────────────────────────
91
+ const [animOverrides, setAnimOverrides] = (0, react_1.useState)({});
92
+ const [loadedAssetIds, setLoadedAssetIds] = (0, react_1.useState)({});
93
+ const handleAssetLoaded = (0, react_1.useCallback)((assetId) => {
94
+ setLoadedAssetIds((prev) => prev[assetId] ? prev : { ...prev, [assetId]: true });
95
+ }, []);
96
+ const triggerHandlesRef = (0, react_1.useRef)(new Set());
97
+ (0, react_1.useEffect)(() => {
98
+ return () => {
99
+ triggerHandlesRef.current.forEach((id) => cancelAnimationFrame(id));
100
+ triggerHandlesRef.current.clear();
101
+ };
102
+ }, []);
103
+ const triggerAnimation = (0, react_1.useCallback)((targetAssetId, animationKey) => {
104
+ // Viro's animation prop is edge-triggered on false→true. Force false first,
105
+ // then flip to true on the next frame so a re-trigger of the same key fires.
106
+ setAnimOverrides((prev) => ({ ...prev, [targetAssetId]: { key: animationKey, run: false } }));
107
+ const handle = requestAnimationFrame(() => {
108
+ triggerHandlesRef.current.delete(handle);
109
+ setAnimOverrides((prev) => {
110
+ const current = prev[targetAssetId];
111
+ if (!current || current.key !== animationKey || current.run)
112
+ return prev;
113
+ return { ...prev, [targetAssetId]: { key: animationKey, run: true } };
114
+ });
115
+ });
116
+ triggerHandlesRef.current.add(handle);
117
+ }, []);
118
+ const triggerAnimationRef = (0, react_1.useRef)(triggerAnimation);
119
+ triggerAnimationRef.current = triggerAnimation;
120
+ // ─── Computed animation props per asset ──────────────────────────────────
121
+ const animationStates = (0, react_1.useMemo)(() => {
122
+ const states = {};
123
+ const animsByAsset = new Map();
124
+ for (const anim of animations) {
125
+ const list = animsByAsset.get(anim.target_asset_id) ?? [];
126
+ list.push(anim);
127
+ animsByAsset.set(anim.target_asset_id, list);
128
+ }
129
+ for (const [assetId, anims] of animsByAsset) {
130
+ const override = animOverrides[assetId];
131
+ let activeAnim;
132
+ let run;
133
+ if (override) {
134
+ const triggered = anims.find((a) => a.animation_key === override.key);
135
+ if (!triggered)
136
+ continue;
137
+ activeAnim = triggered;
138
+ run = override.run && !!loadedAssetIds[assetId];
139
+ }
140
+ else {
141
+ activeAnim = anims[0];
142
+ run = false;
143
+ }
144
+ states[assetId] = {
145
+ name: activeAnim.animation_key,
146
+ run,
147
+ loop: activeAnim.loop,
148
+ interruptible: activeAnim.interruptible,
149
+ delay: activeAnim.delay_ms ?? 0,
150
+ onStart: activeAnim.on_start_function
151
+ ? () => (0, sceneNavigationHandler_1.executeOnLoadFunction)(activeAnim.on_start_function, functions, sceneNavigator, animations, (id, key) => triggerAnimationRef.current(id, key))
152
+ : undefined,
153
+ onFinish: activeAnim.on_finish_function
154
+ ? () => (0, sceneNavigationHandler_1.executeOnLoadFunction)(activeAnim.on_finish_function, functions, sceneNavigator, animations, (id, key) => triggerAnimationRef.current(id, key))
155
+ : undefined,
156
+ };
157
+ }
158
+ return states;
159
+ }, [animations, animOverrides, loadedAssetIds, functions, sceneNavigator]);
160
+ // ─── on_load_function ─────────────────────────────────────────────────────
161
+ const onLoadExecutedRef = (0, react_1.useRef)(false);
162
+ (0, react_1.useEffect)(() => {
163
+ if (scene.on_load_function && !onLoadExecutedRef.current) {
164
+ onLoadExecutedRef.current = true;
165
+ (0, sceneNavigationHandler_1.executeOnLoadFunction)(scene.on_load_function, functions, sceneNavigator, animations, (id, key) => triggerAnimationRef.current(id, key), onSceneChange);
166
+ }
167
+ }, [scene.id]);
168
+ // ─── Collision bindings ───────────────────────────────────────────────────
169
+ const bindingsByPairKey = (0, react_1.useMemo)(() => {
170
+ const m = new Map();
171
+ for (const b of collision_bindings) {
172
+ const key = (0, collisionPairKey_1.collisionPairKey)(b.asset_x_id, b.asset_y_id);
173
+ const list = m.get(key) ?? [];
174
+ list.push(b);
175
+ m.set(key, list);
176
+ }
177
+ return m;
178
+ }, [collision_bindings]);
179
+ const collisionAssetIds = (0, react_1.useMemo)(() => {
180
+ const s = new Set();
181
+ for (const b of collision_bindings) {
182
+ s.add(b.asset_x_id);
183
+ s.add(b.asset_y_id);
184
+ }
185
+ return s;
186
+ }, [collision_bindings]);
187
+ const collisionCooldownRef = (0, react_1.useRef)(new Map());
188
+ const getCollisionHandler = (0, react_1.useCallback)((placementId) => {
189
+ if (!collisionAssetIds.has(placementId))
190
+ return undefined;
191
+ return (0, collisionBindingsRuntime_1.createPlacementCollisionHandler)(placementId, bindingsByPairKey, sceneNavigator, animations, collisionCooldownRef, (id, key) => triggerAnimationRef.current(id, key), onSceneChange);
192
+ }, [bindingsByPairKey, collisionAssetIds, sceneNavigator, animations]);
193
+ // ─── Trigger image targets ────────────────────────────────────────────────
194
+ const { planeAssets, imageTriggeredAssets } = (0, react_1.useMemo)(() => {
195
+ const plane = assets.filter((a) => !a.trigger_image_url);
196
+ const imgTriggered = assets.filter((a) => !!a.trigger_image_url);
197
+ return { planeAssets: plane, imageTriggeredAssets: imgTriggered };
198
+ }, [assets]);
199
+ const [urlToTargetName, setUrlToTargetName] = (0, react_1.useState)(() => new Map());
200
+ const prevTargetNamesRef = (0, react_1.useRef)([]);
201
+ (0, react_1.useEffect)(() => {
202
+ if (ViroPlatform_1.isQuest) {
203
+ if (imageTriggeredAssets.length > 0) {
204
+ console.warn("[Studio] Image-triggered assets are not supported on Quest — skipping.");
205
+ }
206
+ return;
207
+ }
208
+ if (imageTriggeredAssets.length === 0) {
209
+ (0, triggerImageRegistry_1.cleanupTriggerImageTargets)(prevTargetNamesRef.current);
210
+ prevTargetNamesRef.current = [];
211
+ setUrlToTargetName(new Map());
212
+ return;
213
+ }
214
+ const map = (0, triggerImageRegistry_1.registerTriggerImageTargets)(imageTriggeredAssets);
215
+ const targetNames = [...map.values()];
216
+ prevTargetNamesRef.current = targetNames;
217
+ setUrlToTargetName(map);
218
+ return () => {
219
+ (0, triggerImageRegistry_1.cleanupTriggerImageTargets)(targetNames);
220
+ prevTargetNamesRef.current = [];
221
+ };
222
+ }, [imageTriggeredAssets]);
223
+ // ─── Ready callback ───────────────────────────────────────────────────────
224
+ (0, react_1.useEffect)(() => { onReady?.(); }, []);
225
+ // ─── Render helpers ───────────────────────────────────────────────────────
226
+ const maxModels = react_native_1.Platform.OS === "android" ? ANDROID_MAX_3D_MODELS : IOS_MAX_3D_MODELS;
227
+ const renderedPlaneAssets = (0, react_1.useMemo)(() => {
228
+ let modelCount = 0;
229
+ return planeAssets
230
+ .map((asset) => {
231
+ if (asset.asset_type_name === "3D-MODEL") {
232
+ modelCount++;
233
+ if (modelCount > maxModels) {
234
+ console.warn(`[Studio] Skipping 3D model "${asset.name}" — ${react_native_1.Platform.OS} limit (${maxModels}) reached`);
235
+ return null;
236
+ }
237
+ }
238
+ return (0, viroNodeFactory_1.createNode)(asset, sceneNavigator, animations, scene, (id, key) => triggerAnimationRef.current(id, key), animationStates, handleAssetLoaded, getCollisionHandler(asset.id), onSceneChange);
239
+ })
240
+ .filter(Boolean);
241
+ }, [planeAssets, sceneNavigator, animations, animationStates, handleAssetLoaded, getCollisionHandler, maxModels, onSceneChange]);
242
+ const renderedImageTriggeredAssets = (0, react_1.useMemo)(() => {
243
+ if (ViroPlatform_1.isQuest)
244
+ return [];
245
+ return imageTriggeredAssets
246
+ .map((asset) => {
247
+ const targetName = urlToTargetName.get(asset.trigger_image_url);
248
+ if (!targetName)
249
+ return null;
250
+ const node = (0, viroNodeFactory_1.createNode)(asset, sceneNavigator, animations, scene, (id, key) => triggerAnimationRef.current(id, key), animationStates, handleAssetLoaded, getCollisionHandler(asset.id), onSceneChange);
251
+ if (!node)
252
+ return null;
253
+ return (<ViroARImageMarker_1.ViroARImageMarker key={asset.id} target={targetName}>
254
+ {node}
255
+ </ViroARImageMarker_1.ViroARImageMarker>);
256
+ })
257
+ .filter(Boolean);
258
+ }, [urlToTargetName, imageTriggeredAssets, sceneNavigator, animations, animationStates, handleAssetLoaded, getCollisionHandler, onSceneChange]);
259
+ // ─── Plane detection (AR only) ────────────────────────────────────────────
260
+ const planeDetectionMode = (scene.plane_detection ?? "NONE").toUpperCase();
261
+ const planeAlignment = (scene.plane_direction ?? "Horizontal");
262
+ const renderAssets = () => {
263
+ if (ViroPlatform_1.isQuest) {
264
+ if (planeDetectionMode !== "NONE") {
265
+ console.warn(`[Studio] Plane detection (${planeDetectionMode}) is not supported on Quest — rendering assets without plane anchor.`);
266
+ }
267
+ return <>{renderedPlaneAssets}</>;
268
+ }
269
+ if (planeDetectionMode === "AUTOMATIC") {
270
+ return (<ViroARPlane_1.ViroARPlane minHeight={0.1} minWidth={0.1} alignment={planeAlignment}>
271
+ {renderedPlaneAssets}
272
+ </ViroARPlane_1.ViroARPlane>);
273
+ }
274
+ if (planeDetectionMode === "MANUAL") {
275
+ return (<ViroARPlaneSelector_1.ViroARPlaneSelector minHeight={0.1} minWidth={0.1} alignment={planeAlignment}>
276
+ {renderedPlaneAssets}
277
+ </ViroARPlaneSelector_1.ViroARPlaneSelector>);
278
+ }
279
+ return <>{renderedPlaneAssets}</>;
280
+ };
281
+ // ─── Physics world ────────────────────────────────────────────────────────
282
+ const physicsWorldConfig = (0, physicsConfig_1.parsePhysicsWorldConfig)(scene.physics_world_config);
283
+ const physicsWorld = physicsWorldConfig?.enabled
284
+ ? (0, physicsConfig_1.buildViroPhysicsWorld)(physicsWorldConfig)
285
+ : undefined;
286
+ const physicsProps = physicsWorld ? { physicsWorld: physicsWorld } : {};
287
+ // ─── Render ───────────────────────────────────────────────────────────────
288
+ const children = (<>
289
+ {ViroPlatform_1.isQuest && <ViroController_1.ViroController controllerVisibility reticleVisibility/>}
290
+ <ViroAmbientLight_1.ViroAmbientLight color="#ffffff" intensity={1000}/>
291
+ {renderAssets()}
292
+ {renderedImageTriggeredAssets}
293
+ {assets.length === 0 && (<ViroText_1.ViroText text="No assets to display" position={[0, 0, -2]} style={{ fontFamily: "Arial", fontSize: 16, color: "#CCCCCC", textAlign: "center" }}/>)}
294
+ </>);
295
+ if (ViroPlatform_1.isQuest) {
296
+ return <ViroScene_1.ViroScene {...physicsProps}>{children}</ViroScene_1.ViroScene>;
297
+ }
298
+ return <ViroARScene_1.ViroARScene {...physicsProps}>{children}</ViroARScene_1.ViroARScene>;
299
+ };
@@ -0,0 +1,31 @@
1
+ import * as React from "react";
2
+ import { ViewStyle } from "react-native";
3
+ interface StudioSceneNavigatorProps {
4
+ /**
5
+ * UUID of a specific scene to load. If omitted, the navigator fetches the
6
+ * project configured in the app manifest and uses its opening scene.
7
+ */
8
+ sceneId?: string;
9
+ worldAlignment?: "Gravity" | "GravityAndHeading" | "Camera";
10
+ autofocus?: boolean;
11
+ style?: ViewStyle;
12
+ onSceneReady?: () => void;
13
+ onError?: (err: Error) => void;
14
+ onSceneChange?: (sceneId: string, sceneName: string) => void;
15
+ onExitViro?: () => void;
16
+ }
17
+ /**
18
+ * Cross-reality Studio scene navigator. Renders a Studio-authored scene on
19
+ * both AR devices (iOS / non-Quest Android) and Meta Quest (VR).
20
+ *
21
+ * Opening-scene resolution order:
22
+ * 1. `sceneId` prop → use it directly
23
+ * 2. Native project (RVProjectId from manifest) → use `opening_scene.id`
24
+ * 3. Fallback → first scene in the project's scene list
25
+ *
26
+ * On Quest, ViroXRSceneNavigator is not rendered until the scene data is
27
+ * ready. This means VRActivity always launches with the actual content scene
28
+ * as its initial scene, avoiding the LoadingVRScene → replace timing race.
29
+ */
30
+ export declare function StudioSceneNavigator({ sceneId, worldAlignment, autofocus, style, onSceneReady, onError, onSceneChange, onExitViro, }: StudioSceneNavigatorProps): React.JSX.Element;
31
+ export {};