@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
@@ -0,0 +1,265 @@
1
+ "use strict";
2
+ /**
3
+ * withViroVisionOS.ts
4
+ *
5
+ * Expo config plugin that adds a visionOS target to your app's Xcode project.
6
+ *
7
+ * What it does:
8
+ * 1. Writes the SwiftUI App entry point (ViroVisionApp.swift) into the target folder
9
+ * 2. Adds a visionOS pod target to the Podfile
10
+ * 3. Creates a visionOS Xcode target in the .pbxproj with correct SDK + build settings
11
+ *
12
+ * Usage in app.json:
13
+ * {
14
+ * "plugins": [
15
+ * ["@reactvision/react-viro", { ... }],
16
+ * "@reactvision/react-viro/plugins/withViroVisionOS"
17
+ * ]
18
+ * }
19
+ *
20
+ * After running `expo prebuild`, run `pod install` in ios/ then build the
21
+ * <AppName>Vision target in Xcode targeting the visionOS simulator.
22
+ */
23
+ var __importDefault = (this && this.__importDefault) || function (mod) {
24
+ return (mod && mod.__esModule) ? mod : { "default": mod };
25
+ };
26
+ Object.defineProperty(exports, "__esModule", { value: true });
27
+ exports.withViroVisionOS = void 0;
28
+ const config_plugins_1 = require("@expo/config-plugins");
29
+ const fs_1 = __importDefault(require("fs"));
30
+ const path_1 = __importDefault(require("path"));
31
+ // ─── Constants ────────────────────────────────────────────────────────────────
32
+ const TARGET_SUFFIX = "Vision";
33
+ const VISIONOS_DEPLOYMENT_TARGET = "1.0";
34
+ const PODFILE_MARKER = "# viro-visionos-target";
35
+ // ─── Swift App entry point template ──────────────────────────────────────────
36
+ function viroVisionAppSwift(targetName, bundleId) {
37
+ return `// ViroVisionApp.swift
38
+ // Auto-generated by @reactvision/react-viro — DO NOT EDIT MANUALLY.
39
+ // Re-generated on every expo prebuild run.
40
+
41
+ import SwiftUI
42
+ import ViroReact
43
+
44
+ @main
45
+ struct ${targetName}App: App {
46
+ /// Current immersion style — driven by ViroVisionOSModule.enterImmersiveSpace(style).
47
+ @State private var immersionStyle: ImmersionStyle = .mixed
48
+
49
+ var body: some Scene {
50
+ // Main 2D window (hosts React Native UI if needed, or acts as launch host).
51
+ WindowGroup {
52
+ ViroVisionLaunchView()
53
+ .viroImmersiveSpaceController()
54
+ }
55
+
56
+ // The Viro immersive rendering space.
57
+ // Opened via ViroVisionOSModule.enterImmersiveSpace() from JavaScript.
58
+ ImmersiveSpace(id: ViroImmersiveSpace.id) {
59
+ ViroImmersiveSpaceView()
60
+ }
61
+ .immersionStyle(selection: $immersionStyle, in: .mixed, .full, .progressive)
62
+ }
63
+ }
64
+
65
+ /// Minimal launch view displayed in the 2D window.
66
+ /// Replace with your own SwiftUI content or a React Native root view.
67
+ struct ViroVisionLaunchView: View {
68
+ @State private var isImmersed = false
69
+
70
+ var body: some View {
71
+ VStack(spacing: 20) {
72
+ Text("ReactVision AR")
73
+ .font(.largeTitle)
74
+ .fontWeight(.bold)
75
+
76
+ Button(isImmersed ? "Exit Immersive Space" : "Enter Immersive Space") {
77
+ Task {
78
+ if isImmersed {
79
+ await ViroImmersiveCoordinator.shared.exit()
80
+ } else {
81
+ await ViroImmersiveCoordinator.shared.enter(styleString: "mixed")
82
+ }
83
+ isImmersed.toggle()
84
+ }
85
+ }
86
+ .buttonStyle(.borderedProminent)
87
+ }
88
+ .padding(40)
89
+ }
90
+ }
91
+ `;
92
+ }
93
+ // ─── 1. Write Swift files ─────────────────────────────────────────────────────
94
+ const withVisionOSSwiftFiles = (config) => {
95
+ return (0, config_plugins_1.withDangerousMod)(config, [
96
+ "ios",
97
+ async (newConfig) => {
98
+ const root = newConfig.modRequest.platformProjectRoot;
99
+ const projectName = newConfig.modRequest.projectName;
100
+ const targetName = `${projectName}${TARGET_SUFFIX}`;
101
+ const bundleId = `${newConfig.ios?.bundleIdentifier ?? "com.example"}.vision`;
102
+ const targetDir = path_1.default.join(root, targetName);
103
+ if (!fs_1.default.existsSync(targetDir)) {
104
+ fs_1.default.mkdirSync(targetDir, { recursive: true });
105
+ }
106
+ // Always overwrite — it's auto-generated.
107
+ fs_1.default.writeFileSync(path_1.default.join(targetDir, "ViroVisionApp.swift"), viroVisionAppSwift(targetName, bundleId), "utf-8");
108
+ return newConfig;
109
+ },
110
+ ]);
111
+ };
112
+ // ─── 2. Podfile target block ──────────────────────────────────────────────────
113
+ const withVisionOSPodfile = (config) => {
114
+ return (0, config_plugins_1.withDangerousMod)(config, [
115
+ "ios",
116
+ async (newConfig) => {
117
+ const root = newConfig.modRequest.platformProjectRoot;
118
+ const projectName = newConfig.modRequest.projectName;
119
+ const targetName = `${projectName}${TARGET_SUFFIX}`;
120
+ const podfilePath = path_1.default.join(root, "Podfile");
121
+ let podfile = fs_1.default.readFileSync(podfilePath, "utf-8");
122
+ // Idempotent — skip if already present.
123
+ if (podfile.includes(PODFILE_MARKER))
124
+ return newConfig;
125
+ const podBlock = [
126
+ "",
127
+ PODFILE_MARKER,
128
+ `# ViroKit (iOS-only) and ViroReact (ObjC) are excluded until ViroKit`,
129
+ `# is compiled for xros SDK (Week 2). The POC uses Metal + CompositorServices directly.`,
130
+ `target '${targetName}' do`,
131
+ `end`,
132
+ "",
133
+ ].join("\n");
134
+ fs_1.default.writeFileSync(podfilePath, podfile + podBlock, "utf-8");
135
+ return newConfig;
136
+ },
137
+ ]);
138
+ };
139
+ // ─── 3. Xcode target ─────────────────────────────────────────────────────────
140
+ const withVisionOSXcodeTarget = (config) => {
141
+ return (0, config_plugins_1.withXcodeProject)(config, (newConfig) => {
142
+ const pbxProject = newConfig.modResults;
143
+ const projectName = newConfig.modRequest.projectName;
144
+ const targetName = `${projectName}${TARGET_SUFFIX}`;
145
+ const bundleId = `${newConfig.ios?.bundleIdentifier ?? "com.example"}.vision`;
146
+ const targetDir = targetName; // relative path inside ios/
147
+ // ── Check for existing target ────────────────────────────────────────────
148
+ const nativeTargets = pbxProject.pbxNativeTargetSection();
149
+ const alreadyExists = Object.values(nativeTargets).some((t) => t &&
150
+ typeof t === "object" &&
151
+ (t.name === targetName || t.name === `"${targetName}"`));
152
+ if (alreadyExists)
153
+ return newConfig;
154
+ // ── Add the target (creates PBX phases + config list) ────────────────────
155
+ const target = pbxProject.addTarget(targetName, "application", targetDir, bundleId);
156
+ if (!target) {
157
+ config_plugins_1.WarningAggregator.addWarningIOS("withViroVisionOS", `Failed to add visionOS target "${targetName}" to Xcode project. ` +
158
+ "Add it manually in Xcode: File → New → Target → visionOS → App.");
159
+ return newConfig;
160
+ }
161
+ // ── Set visionOS build settings on every config for this target ──────────
162
+ const configList = pbxProject.pbxXCBuildConfigurationSection();
163
+ for (const conf of Object.values(configList)) {
164
+ if (!conf || typeof conf !== "object" || !conf.buildSettings)
165
+ continue;
166
+ const name = conf.buildSettings.PRODUCT_NAME;
167
+ if (!name)
168
+ continue;
169
+ const normalized = name.replace(/^"(.*)"$/, "$1");
170
+ if (normalized !== targetName)
171
+ continue;
172
+ const bs = conf.buildSettings;
173
+ // visionOS SDK
174
+ bs.SDKROOT = "xros";
175
+ bs.SUPPORTED_PLATFORMS = '"xros xrsimulator"';
176
+ bs[`"DEPLOYMENT_TARGET[sdk=xros*]"`] = `"${VISIONOS_DEPLOYMENT_TARGET}"`;
177
+ bs.TARGETED_DEVICE_FAMILY = '"7"';
178
+ // Swift
179
+ bs.SWIFT_VERSION = '"5.0"';
180
+ bs.CLANG_ENABLE_MODULES = "YES";
181
+ // Runpath for dynamic frameworks (CocoaPods)
182
+ bs.LD_RUNPATH_SEARCH_PATHS = '"$(inherited) @executable_path/Frameworks"';
183
+ // Embed Swift standard libraries
184
+ bs.ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "YES";
185
+ // App-specific
186
+ bs.PRODUCT_BUNDLE_IDENTIFIER = `"${bundleId}"`;
187
+ bs.INFOPLIST_FILE = `"${targetDir}/Info.plist"`;
188
+ bs.GENERATE_INFOPLIST_FILE = "NO";
189
+ bs.ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon";
190
+ // Don't strip Swift symbols in debug
191
+ if (conf.name === "Debug") {
192
+ bs.SWIFT_OPTIMIZATION_LEVEL = '"-Onone"';
193
+ bs.SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG";
194
+ }
195
+ }
196
+ // ── Write Info.plist for the visionOS target ──────────────────────────────
197
+ // (written during the dangerous mod pass — cannot write files here)
198
+ // Logged as a reminder.
199
+ config_plugins_1.WarningAggregator.addWarningIOS("withViroVisionOS", `visionOS target "${targetName}" added. ` +
200
+ `Run "pod install" in ios/ then build the target in Xcode. ` +
201
+ `An Info.plist will be auto-generated by Xcode for the new target.`);
202
+ return newConfig;
203
+ });
204
+ };
205
+ // ─── 4. Info.plist for visionOS target ───────────────────────────────────────
206
+ const INFOPLIST_CONTENT = `<?xml version="1.0" encoding="UTF-8"?>
207
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
208
+ <plist version="1.0">
209
+ <dict>
210
+ <key>CFBundleDevelopmentRegion</key>
211
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
212
+ <key>CFBundleExecutable</key>
213
+ <string>$(EXECUTABLE_NAME)</string>
214
+ <key>CFBundleIdentifier</key>
215
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
216
+ <key>CFBundleInfoDictionaryVersion</key>
217
+ <string>6.0</string>
218
+ <key>CFBundleName</key>
219
+ <string>$(PRODUCT_NAME)</string>
220
+ <key>CFBundlePackageType</key>
221
+ <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
222
+ <key>CFBundleShortVersionString</key>
223
+ <string>1.0</string>
224
+ <key>CFBundleVersion</key>
225
+ <string>1</string>
226
+ <key>UIApplicationSceneManifest</key>
227
+ <dict>
228
+ <key>UIApplicationSupportsMultipleScenes</key>
229
+ <true/>
230
+ </dict>
231
+ <key>NSHandsTrackingUsageDescription</key>
232
+ <string>Hand tracking is used for interaction in AR experiences.</string>
233
+ </dict>
234
+ </plist>
235
+ `;
236
+ const withVisionOSInfoPlist = (config) => {
237
+ return (0, config_plugins_1.withDangerousMod)(config, [
238
+ "ios",
239
+ async (newConfig) => {
240
+ const root = newConfig.modRequest.platformProjectRoot;
241
+ const projectName = newConfig.modRequest.projectName;
242
+ const targetName = `${projectName}${TARGET_SUFFIX}`;
243
+ const targetDir = path_1.default.join(root, targetName);
244
+ if (!fs_1.default.existsSync(targetDir)) {
245
+ fs_1.default.mkdirSync(targetDir, { recursive: true });
246
+ }
247
+ const plistPath = path_1.default.join(targetDir, "Info.plist");
248
+ if (!fs_1.default.existsSync(plistPath)) {
249
+ fs_1.default.writeFileSync(plistPath, INFOPLIST_CONTENT, "utf-8");
250
+ }
251
+ return newConfig;
252
+ },
253
+ ]);
254
+ };
255
+ // ─── Main export ──────────────────────────────────────────────────────────────
256
+ const withViroVisionOS = (config) => {
257
+ return (0, config_plugins_1.withPlugins)(config, [
258
+ withVisionOSSwiftFiles,
259
+ withVisionOSInfoPlist,
260
+ withVisionOSPodfile,
261
+ withVisionOSXcodeTarget,
262
+ ]);
263
+ };
264
+ exports.withViroVisionOS = withViroVisionOS;
265
+ exports.default = exports.withViroVisionOS;
package/index.ts CHANGED
@@ -4,6 +4,8 @@
4
4
  *
5
5
  */
6
6
  import { ViroAnimations } from "./components/Animation/ViroAnimations";
7
+ import { StudioSceneNavigator, StudioARScene } from "./components/Studio";
8
+ import { ViroVisionOSModule, isVisionOS, enterImmersiveSpace, exitImmersiveSpace } from "./components/VisionOS/ViroVisionOSModule";
7
9
  import { Viro3DObject } from "./components/Viro3DObject";
8
10
  import { Viro360Image } from "./components/Viro360Image";
9
11
  import { Viro360Video } from "./components/Viro360Video";
@@ -59,7 +61,11 @@ import { ViroSpotLight } from "./components/ViroSpotLight";
59
61
  import { ViroText } from "./components/ViroText";
60
62
  import { ViroVideo } from "./components/ViroVideo";
61
63
  import { ViroVRSceneNavigator } from "./components/ViroVRSceneNavigator";
64
+ import { ViroXRSceneNavigator } from "./components/ViroXRSceneNavigator";
62
65
  import { Viro3DSceneNavigator } from "./components/Viro3DSceneNavigator";
66
+ import { hasOpenXRSupport, isQuest } from "./components/Utilities/ViroPlatform";
67
+ import { useAnySourceHover } from "./components/Utilities/useAnySourceHover";
68
+ import { useAnySourcePressed } from "./components/Utilities/useAnySourcePressed";
63
69
  import { ViroTextStyle } from "./components/Styles/ViroTextStyle";
64
70
  import { ViroStyle } from "./components/Styles/ViroStyle";
65
71
  import {
@@ -161,10 +167,25 @@ import {
161
167
  ViroMonocularDepthSupportResult,
162
168
  ViroMonocularDepthModelAvailableResult,
163
169
  ViroMonocularDepthPreferenceResult,
170
+ // Quest / OpenXR Hand Tracking Types
171
+ ViroJoint,
172
+ ViroHandJoints,
173
+ ViroHandPinchEvent,
174
+ ViroHandUpdateEvent,
164
175
  } from "./components/Types/ViroEvents";
165
176
  import { ViroSurface } from "./components/ViroSurface";
166
177
  import { ViroSceneNavigator } from "./components/ViroSceneNavigator";
167
178
  import { VIRO_VERSION } from "./components/Utilities/ViroVersion";
179
+ import { ViroQuestEntryPoint } from "./components/ViroQuestEntryPoint";
180
+ import { VRQuestNavigatorBridge } from "./components/Utilities/VRQuestNavigatorBridge";
181
+ import { VRModuleOpenXR, useVRViewTag, exitVRScene } from "./components/Utilities/VRModuleOpenXR";
182
+ import type { VRModuleOpenXRType } from "./components/Utilities/VRModuleOpenXR";
183
+ import { AppRegistry } from "react-native";
184
+
185
+ // Auto-register the Quest VR entry point. VRActivity launches this component
186
+ // as 'VRQuestScene'. Registering here means apps need no manual setup.
187
+ // Apps that need a custom VR root can re-register after importing this package.
188
+ AppRegistry.registerComponent("VRQuestScene", () => ViroQuestEntryPoint);
168
189
 
169
190
  export {
170
191
  ViroARImageMarker,
@@ -215,8 +236,19 @@ export {
215
236
  ViroText,
216
237
  ViroVideo,
217
238
  ViroVRSceneNavigator,
239
+ ViroXRSceneNavigator,
240
+ ViroQuestEntryPoint,
241
+ // Quest bridge — for custom VR roots and VRModuleOpenXR viewTag access
242
+ VRQuestNavigatorBridge,
243
+ VRModuleOpenXR,
244
+ useVRViewTag,
245
+ exitVRScene,
218
246
  Viro3DSceneNavigator,
219
247
  // Utilities
248
+ hasOpenXRSupport,
249
+ isQuest,
250
+ useAnySourceHover,
251
+ useAnySourcePressed,
220
252
  ViroARTrackingReasonConstants,
221
253
  ViroRecordingErrorConstants,
222
254
  ViroTrackingStateConstants,
@@ -323,4 +355,30 @@ export {
323
355
  ViroMonocularDepthSupportResult,
324
356
  ViroMonocularDepthModelAvailableResult,
325
357
  ViroMonocularDepthPreferenceResult,
358
+ // Quest / OpenXR Hand Tracking Types
359
+ ViroJoint,
360
+ ViroHandJoints,
361
+ ViroHandPinchEvent,
362
+ ViroHandUpdateEvent,
363
+ // Studio Integration
364
+ StudioSceneNavigator,
365
+ StudioARScene,
366
+ // VisionOS
367
+ ViroVisionOSModule,
368
+ isVisionOS,
369
+ enterImmersiveSpace,
370
+ exitImmersiveSpace,
326
371
  };
372
+
373
+ export type { VRModuleOpenXRType };
374
+ export type { ImmersiveSpaceStyle } from "./components/VisionOS/ViroVisionOSModule";
375
+
376
+ export type {
377
+ StudioSceneResponse,
378
+ StudioAsset,
379
+ StudioAnimation,
380
+ StudioCollisionBinding,
381
+ StudioSceneFunction,
382
+ StudioSceneMeta,
383
+ StudioProjectMeta,
384
+ } from "./components/Studio";
@@ -12,10 +12,14 @@ Pod::Spec.new do |s|
12
12
  s.author = 'ReactVision'
13
13
  s.requires_arc = true
14
14
  s.platform = :ios, '12.0'
15
- s.ios.deployment_target = '12.0'
16
-
15
+ s.ios.deployment_target = '12.0'
16
+ s.visionos.deployment_target = '1.0'
17
+
18
+ # visionOS: CompositorServices drives the immersive render loop.
19
+ s.visionos.frameworks = ['Metal', 'MetalKit', 'CompositorServices', 'ARKit']
20
+
17
21
  # Base source files (always included)
18
- source_files_array = ['ViroReact/**/*.{h,m,mm}']
22
+ source_files_array = ['ViroReact/**/*.{h,m,mm,swift}']
19
23
  header_files_array = ['ViroReact/**/*.h']
20
24
 
21
25
  # Include dist files if they exist (for release builds)
@@ -26,7 +30,12 @@ Pod::Spec.new do |s|
26
30
 
27
31
  s.source_files = source_files_array
28
32
  s.public_header_files = header_files_array
29
-
33
+
34
+ # visionOS-only sources: keep them out of the iOS build so consumers running
35
+ # `pod install` for iOS don't pull CompositorServices / VRODriverVisionOS.h
36
+ # into a target where those symbols don't exist.
37
+ s.ios.exclude_files = ['ViroReact/VisionOS/**/*']
38
+
30
39
  if File.exist?(File.join(__dir__, 'dist/lib/libViroReact.a'))
31
40
  s.vendored_libraries = 'dist/lib/libViroReact.a'
32
41
  end
@@ -571,11 +571,21 @@ public:
571
571
  std::function<void(bool success, std::string error)> callback) {
572
572
  if (callback) callback(false, "Not supported");
573
573
  }
574
+ virtual void rvGetScene(
575
+ const std::string& sceneId,
576
+ std::function<void(bool success, std::string jsonData, std::string error)> callback) {
577
+ if (callback) callback(false, "", "Not supported");
578
+ }
574
579
  virtual void rvGetSceneAssets(
575
580
  const std::string& sceneId,
576
581
  std::function<void(bool success, std::string jsonData, std::string error)> callback) {
577
582
  if (callback) callback(false, "", "Not supported");
578
583
  }
584
+ virtual void rvGetProject(
585
+ const std::string& projectId,
586
+ std::function<void(bool success, std::string jsonData, std::string error)> callback) {
587
+ if (callback) callback(false, "", "Not supported");
588
+ }
579
589
 
580
590
  // ========================================================================
581
591
  // ReactVision Geospatial CRUD API
@@ -197,6 +197,10 @@ public:
197
197
  double confidence, int matchCount, int inlierCount, int processingTimeMs,
198
198
  const std::string& platform, const std::string& externalUserId,
199
199
  std::function<void(bool, std::string)> callback) override;
200
+ void rvGetProject(const std::string& projectId,
201
+ std::function<void(bool, std::string, std::string)> callback) override;
202
+ void rvGetScene(const std::string& sceneId,
203
+ std::function<void(bool, std::string, std::string)> callback) override;
200
204
  void rvGetSceneAssets(const std::string& sceneId,
201
205
  std::function<void(bool, std::string, std::string)> callback) override;
202
206
 
@@ -27,6 +27,7 @@
27
27
  #define VROInputControllerBase_h
28
28
 
29
29
  #include <stdio.h>
30
+ #include <map>
30
31
  #include <vector>
31
32
  #include <string>
32
33
  #include <memory>
@@ -180,6 +181,23 @@ protected:
180
181
  */
181
182
  void updateHitNode(const VROCamera &camera, VROVector3f origin, VROVector3f ray);
182
183
 
184
+ /*
185
+ Source-aware hit-node update. Stores the result both in the legacy
186
+ `_hitResult` (so single-pointer subsystems — drag, fuse, pinch, rotate —
187
+ keep working unchanged) and in `_hitResultsBySource[source]` so that
188
+ gaze/click events can resolve against the specific input source that
189
+ produced them. Used by backends with multiple simultaneous pointers
190
+ (e.g. OpenXR with two hands tracked at once).
191
+ */
192
+ void updateHitNode(int source, const VROCamera &camera,
193
+ VROVector3f origin, VROVector3f ray);
194
+
195
+ /*
196
+ Returns the per-source hit result if one was recorded for this source,
197
+ otherwise falls back to the legacy single-source `_hitResult`.
198
+ */
199
+ std::shared_ptr<VROHitTestResult> getHitResultForSource(int source) const;
200
+
183
201
  /*
184
202
  VRODraggedObject encapsulates all the information that needs to be tracked
185
203
  and processed for onDrag events for a given dragged node.
@@ -226,6 +244,12 @@ protected:
226
244
  Last result that was returned from the hit test.
227
245
  */
228
246
  std::shared_ptr<VROHitTestResult> _hitResult;
247
+
248
+ /*
249
+ Per-source hit results, populated by the source-aware updateHitNode
250
+ overload. Empty entry → no per-source override; falls back to `_hitResult`.
251
+ */
252
+ std::map<int, std::shared_ptr<VROHitTestResult>> _hitResultsBySource;
229
253
 
230
254
  /*
231
255
  Last known posiiton of the controller.
@@ -296,11 +320,61 @@ private:
296
320
  */
297
321
  std::shared_ptr<VRONode> _lastClickedNode;
298
322
 
323
+ /*
324
+ Per-source last clicked node — used to detect a "completed" click
325
+ (ClickDown + ClickUp on the same node from the same source) when
326
+ multiple pointers are active simultaneously.
327
+ */
328
+ std::map<int, std::shared_ptr<VRONode>> _lastClickedNodesBySource;
329
+
299
330
  /*
300
331
  Last known that was successfully hovered upon.
301
332
  */
302
333
  std::shared_ptr<VRONode> _lastHoveredNode;
303
334
 
335
+ /*
336
+ Per-source last hovered node, used by the source-aware hover dispatch in
337
+ `processGazeEvent`. An entry's presence is the signal that this source
338
+ has its own hover state; otherwise we fall back to `_lastHoveredNode`.
339
+ */
340
+ std::map<int, std::shared_ptr<VRONode>> _lastHoveredNodesBySource;
341
+
342
+ /*
343
+ Hover hysteresis state, per source.
344
+
345
+ OpenXR controller / hand aim ray-casts naturally jitter — pointing at a
346
+ small target with a controller held by an unsteady hand causes the
347
+ hit-test to alternate between the target node and the surrounding
348
+ background every 1–3 frames. Without hysteresis, every alternation
349
+ produced an `onHover(false)` / `onHover(true)` pair to JS, which
350
+ manifested as a flickering hover state and "the click takes dozens of
351
+ presses to register" — because if the user pulled the trigger on a
352
+ "miss" frame, `onButtonEvent` resolved the click against the background
353
+ instead of the target.
354
+
355
+ The hysteresis works as a grace period: when the hit changes from
356
+ `lastHovered` to a different node, we do NOT immediately fire the
357
+ exit — instead we record the candidate change and the timestamp.
358
+ If, within `kHoverHysteresisMillis`, the hit returns to `lastHovered`,
359
+ the exit is cancelled (no `onHover(false)` ever fires). If the new
360
+ candidate persists past the window, the exit is confirmed and the
361
+ normal enter/exit dispatch happens.
362
+
363
+ The same window is consulted by `onButtonEvent` so that clicks landing
364
+ on a transient miss-frame are still routed to `lastHovered` if the
365
+ pending-exit window is still open. That eliminates the "many presses
366
+ to click" symptom even though the underlying ray-cast still oscillates.
367
+ */
368
+ static constexpr double kHoverHysteresisMillis = 75.0;
369
+ struct HoverPending {
370
+ std::shared_ptr<VRONode> candidateNode; // node the hit currently resolves to
371
+ VROVector3f candidatePos; // hit location at the moment of pending start
372
+ bool candidateBgHit = false; // whether candidate is a background hit
373
+ double startedMillis = -1.0; // wall-clock time when the candidate first appeared
374
+ };
375
+ std::map<int, HoverPending> _hoverPendingBySource;
376
+ HoverPending _hoverPending; // legacy single-source fallback
377
+
304
378
  /*
305
379
  Returns the first node that is able to handle the event action by bubbling it up.
306
380
  If nothing is able to handle the event, nullptr is returned.
@@ -57,9 +57,17 @@ namespace ViroCardBoard{
57
57
 
58
58
  namespace ViroOculus{
59
59
  enum InputSource{
60
- Controller = 1,
61
- TouchPad = 2,
62
- BackButton = 3
60
+ Controller = 1, // right controller primary ray (legacy alias for RightController)
61
+ TouchPad = 2,
62
+ BackButton = 3, // menu (left) and B (right) buttons — navigation / back
63
+ LeftController = 4, // left controller primary ray
64
+ AButton = 5, // right-hand A button
65
+ XButton = 6, // left-hand X button
66
+ YButton = 7, // left-hand Y button
67
+ LeftGrip = 8, // left grip / squeeze
68
+ RightGrip = 9, // right grip / squeeze
69
+ LeftThumbstick = 10, // left thumbstick scroll axis
70
+ RightThumbstick = 11, // right thumbstick scroll axis
63
71
  };
64
72
  }
65
73
  #endif
@@ -53,6 +53,7 @@ enum class VROPlatformType {
53
53
  Unknown,
54
54
  AndroidGVR,
55
55
  AndroidOVR,
56
+ AndroidOpenXR,
56
57
  AndroidARCore,
57
58
  AndroidSceneView,
58
59
  iOSCardboard,
@@ -163,6 +164,18 @@ VROTextureFormat VROPlatformGetBitmapFormat(jobject jbitmap);
163
164
  */
164
165
  void VROPlatformDispatchAsyncRenderer(std::function<void()> fcn);
165
166
 
167
+ /*
168
+ OpenXR / headless-GL renderers that own their own render thread should call
169
+ VROPlatformSetUseDirectRendererQueue(true) during initialisation. All
170
+ subsequent VROPlatformDispatchAsyncRenderer calls will enqueue into a C++
171
+ queue instead of going through the GLSurfaceView Java path.
172
+
173
+ The render thread must call VROPlatformDrainRendererQueue() every frame to
174
+ execute queued work (e.g. setSceneController, texture uploads).
175
+ */
176
+ void VROPlatformSetUseDirectRendererQueue(bool use);
177
+ void VROPlatformDrainRendererQueue();
178
+
166
179
  /*
167
180
  Run the given function on a background thread. The thread can be pooled,
168
181
  or spun up fresh. The caller should make no assumptions.
@@ -282,6 +282,14 @@ public:
282
282
 
283
283
  #pragma mark - Camera
284
284
 
285
+ /*
286
+ Returns true if the render context has been initialized (initRenderer called).
287
+ Safe to call before any scene is set.
288
+ */
289
+ bool hasRenderContext() const {
290
+ return _context != nullptr;
291
+ }
292
+
285
293
  /*
286
294
  Get the camera used in the last frame.
287
295
  */
@@ -1,5 +1,5 @@
1
1
  dependencies: \
2
2
  /Users/dorantes/Documents/ViroWorkspace/virocore/ViroRenderer/Shaders.metal \
3
- /private/var/run/com.apple.security.cryptexd/mnt/com.apple.MobileAsset.MetalToolchain-v17.5.188.0.TTgSDB/Metal.xctoolchain/usr/metal/32023/lib/clang/32023.883/include/metal/module.modulemap \
3
+ /private/var/run/com.apple.security.cryptexd/mnt/com.apple.MobileAsset.MetalToolchain-v17.5.188.0.qU0cxL/Metal.xctoolchain/usr/metal/32023/lib/clang/32023.883/include/metal/module.modulemap \
4
4
  /Users/dorantes/Documents/ViroWorkspace/virocore/ViroRenderer/VROSharedStructures.h \
5
5
  /Users/dorantes/Documents/ViroWorkspace/virocore/ViroRenderer/VRODefines.h
@@ -27,8 +27,13 @@ Pod::Spec.new do |s|
27
27
  s.author = 'ReactVision'
28
28
  s.requires_arc = true
29
29
  s.platform = :ios, '13.0'
30
+ s.visionos.deployment_target = '1.0'
30
31
  s.dependency 'React'
31
32
 
33
+ # visionOS requires CompositorServices for the immersive render loop.
34
+ # Metal and MetalKit are available on both iOS and visionOS.
35
+ s.visionos.frameworks = ['Metal', 'MetalKit', 'CompositorServices', 'ARKit']
36
+
32
37
  # ARCore frameworks and Firebase dependencies are weak-linked via post_install hook
33
38
  # This prevents linker errors when ARCore pods are not installed
34
39
  # The following frameworks are weakly linked when ARCore is enabled:
@@ -208,6 +208,9 @@ typedef void (^GeospatialAnchorCompletionHandler)(BOOL success,
208
208
  radius:(double)radius
209
209
  limit:(int)limit
210
210
  completionHandler:(void (^)(BOOL success, NSArray *anchors, NSString *error))completionHandler;
211
+ - (void)rvGetProject:(void (^)(BOOL success, NSString *data, NSString *error))completionHandler;
212
+ - (void)rvGetScene:(NSString *)sceneId
213
+ completionHandler:(void (^)(BOOL success, NSString *data, NSString *error))completionHandler;
211
214
  - (void)rvGetSceneAssets:(NSString *)sceneId
212
215
  completionHandler:(void (^)(BOOL success, NSArray *assets, NSString *error))completionHandler;
213
216
  - (void)rvAttachAssetToCloudAnchor:(NSString *)anchorId
@@ -0,0 +1,6 @@
1
+ #import <React/RCTBridgeModule.h>
2
+ #import <React/RCTBridge.h>
3
+
4
+ @interface VRTStudioModule : NSObject <RCTBridgeModule>
5
+
6
+ @end
Binary file
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "main": "dist/index.js",
4
4
  "module": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
- "version": "2.54.0",
6
+ "version": "2.55.0",
7
7
  "license": "MIT",
8
8
  "publishConfig": {
9
9
  "registry": "https://registry.npmjs.org/"