@sceneview-sdk/react-native 4.3.5 → 4.4.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.
package/README.md CHANGED
@@ -91,15 +91,21 @@ import { ARSceneView } from '@sceneview-sdk/react-native';
91
91
 
92
92
  ### Props — SceneView
93
93
 
94
- | Prop | Type | Default | Description |
95
- |------------------|-----------------|---------|------------------------------------------|
96
- | `style` | `ViewStyle` | — | Standard React Native style |
97
- | `environment` | `string` | — | HDR environment asset path |
98
- | `modelNodes` | `ModelNode[]` | `[]` | Models to render |
99
- | `geometryNodes` | `GeometryNode[]`| `[]` | Geometry nodes (forward-compatible) |
100
- | `lightNodes` | `LightNode[]` | `[]` | Light nodes (forward-compatible) |
101
- | `cameraOrbit` | `boolean` | `true` | Enable orbit camera controls |
102
- | `onTap` | `function` | — | Tap callback (event pending) |
94
+ | Prop | Type | Default | Description |
95
+ |---------------------|----------------------|-----------|------------------------------------------|
96
+ | `style` | `ViewStyle` | — | Standard React Native style |
97
+ | `environment` | `string` | — | HDR environment asset path |
98
+ | `modelNodes` | `ModelNode[]` | `[]` | Models to render |
99
+ | `geometryNodes` | `GeometryNode[]` | `[]` | Geometry nodes (forward-compatible) |
100
+ | `lightNodes` | `LightNode[]` | `[]` | Light nodes (forward-compatible) |
101
+ | `cameraOrbit` | `boolean` | `true` | Enable orbit camera controls |
102
+ | `cameraControlMode` | `CameraControlMode` | `'orbit'` | Camera mode (v4.3.0). `'pan'`/`'firstPerson'` are iOS-only |
103
+ | `autoCenterContent` | `boolean` | `true` | Auto-centre content on first frame (v4.3.0, iOS-first) |
104
+ | `onTap` | `function` | — | Tap callback (event pending) |
105
+
106
+ `cameraControlMode` `'pan'` and `'firstPerson'` are iOS-only in v4.3.0; on
107
+ Android they fall back to orbit. `autoCenterContent` is iOS-first — the
108
+ Android side is tracked in issue #1051.
103
109
 
104
110
  ### Props — ARSceneView (extends SceneView)
105
111
 
@@ -122,6 +128,26 @@ interface ModelNode {
122
128
  }
123
129
  ```
124
130
 
131
+ ### AR recording (v4.3.0 — iOS)
132
+
133
+ `ARRecorder` records an AR session to a `.mov` video (iOS via ReplayKit):
134
+
135
+ ```ts
136
+ import { ARRecorder } from '@sceneview-sdk/react-native';
137
+
138
+ const recorder = new ARRecorder();
139
+
140
+ await recorder.start();
141
+ // ... later ...
142
+ const path = await recorder.stop();
143
+ await recorder.saveToPhotoLibrary(path);
144
+ ```
145
+
146
+ `ARRecorder` is iOS-only; on Android every method rejects with an
147
+ `UNSUPPORTED` error (ARCore session recording is tracked in issue #1051).
148
+ Check `ARRecorder.isSupported` before use. The host iOS app must declare
149
+ `NSPhotoLibraryAddUsageDescription` in `Info.plist` for `saveToPhotoLibrary`.
150
+
125
151
  ## Architecture
126
152
 
127
153
  ```
@@ -0,0 +1,46 @@
1
+ package io.github.sceneview.reactnative
2
+
3
+ import com.facebook.react.bridge.Promise
4
+ import com.facebook.react.bridge.ReactApplicationContext
5
+ import com.facebook.react.bridge.ReactContextBaseJavaModule
6
+ import com.facebook.react.bridge.ReactMethod
7
+
8
+ /**
9
+ * React Native bridge for AR session recording (v4.3.0, issue #1053).
10
+ *
11
+ * Exposed to JS as `NativeModules.RNARRecorder`.
12
+ *
13
+ * On iOS this is backed by SceneViewSwift's `ARRecorder` (ReplayKit screen
14
+ * capture). On Android, ARCore's `io.github.sceneview.ar.recording.ARRecorder`
15
+ * records a *replayable session dataset* — a fundamentally different artifact
16
+ * from a video, and one that needs `Session`/`Frame` access the Fabric
17
+ * platform-view bridge does not currently expose.
18
+ *
19
+ * Rather than silently no-op, every method rejects with `UNSUPPORTED` so the
20
+ * JS `ARRecorder` class (which already gates `Platform.OS !== 'ios'`) and any
21
+ * direct caller get an honest, actionable error. The Android bridge is
22
+ * tracked in issue #1051.
23
+ */
24
+ class ARRecorderModule(
25
+ reactContext: ReactApplicationContext,
26
+ ) : ReactContextBaseJavaModule(reactContext) {
27
+
28
+ override fun getName(): String = "RNARRecorder"
29
+
30
+ private fun rejectUnsupported(promise: Promise) {
31
+ promise.reject(
32
+ "UNSUPPORTED",
33
+ "ARRecorder is not supported on Android via the React Native bridge. " +
34
+ "ARCore session recording is tracked in issue #1051.",
35
+ )
36
+ }
37
+
38
+ @ReactMethod
39
+ fun start(promise: Promise) = rejectUnsupported(promise)
40
+
41
+ @ReactMethod
42
+ fun stop(outputPath: String?, promise: Promise) = rejectUnsupported(promise)
43
+
44
+ @ReactMethod
45
+ fun saveToPhotoLibrary(movPath: String, promise: Promise) = rejectUnsupported(promise)
46
+ }
@@ -39,6 +39,19 @@ class SceneViewState {
39
39
  val lightNodes = mutableStateListOf<LightNodeData>()
40
40
  val environmentPath = mutableStateOf<String?>(null)
41
41
  val orbitEnabled = mutableStateOf(true)
42
+
43
+ /**
44
+ * v4.3.0 camera control mode (#1053). Stored for parity with the iOS
45
+ * bridge; Android's `SceneView` composable already orbits by default,
46
+ * so `pan` / `firstPerson` currently fall back to orbit (tracked in #1051).
47
+ */
48
+ val cameraControlMode = mutableStateOf("orbit")
49
+
50
+ /**
51
+ * v4.3.0 content auto-centring (#1053). iOS-first; the Android
52
+ * library-level implementation is tracked in #1051.
53
+ */
54
+ val autoCenterContent = mutableStateOf(true)
42
55
  }
43
56
 
44
57
  /**
@@ -303,6 +316,24 @@ class SceneViewManager : SimpleViewManager<FrameLayout>() {
303
316
  fun setCameraOrbit(view: FrameLayout, enabled: Boolean) {
304
317
  getState(view).orbitEnabled.value = enabled
305
318
  }
319
+
320
+ @ReactProp(name = "cameraControlMode")
321
+ fun setCameraControlMode(view: FrameLayout, mode: String?) {
322
+ // v4.3.0 camera modes (#1053). The Android `SceneView` composable
323
+ // already uses an orbit manipulator by default; `pan` and
324
+ // `firstPerson` are iOS-first additions. Acknowledged here so
325
+ // cross-platform JS code does not crash the prop setter — the
326
+ // per-mode switch for Android is tracked in issue #1051.
327
+ getState(view).cameraControlMode.value = mode ?: "orbit"
328
+ }
329
+
330
+ @ReactProp(name = "autoCenterContent", defaultBoolean = true)
331
+ fun setAutoCenterContent(view: FrameLayout, enabled: Boolean) {
332
+ // v4.3.0 content auto-centring (#1053) is iOS-first; the Android
333
+ // library-level implementation is tracked in issue #1051.
334
+ // Acknowledged so cross-platform JS code does not crash.
335
+ getState(view).autoCenterContent.value = enabled
336
+ }
306
337
  }
307
338
 
308
339
  data class ModelNodeData(
@@ -20,7 +20,9 @@ class SceneViewPackage : ReactPackage {
20
20
 
21
21
  override fun createNativeModules(
22
22
  reactContext: ReactApplicationContext
23
- ): List<NativeModule> = emptyList()
23
+ ): List<NativeModule> = listOf(
24
+ ARRecorderModule(reactContext),
25
+ )
24
26
 
25
27
  override fun createViewManagers(
26
28
  reactContext: ReactApplicationContext
@@ -1,12 +1,16 @@
1
1
  // Objective-C bridge — required by React Native to register view managers.
2
2
 
3
3
  #import <React/RCTViewManager.h>
4
+ #import <React/RCTBridgeModule.h>
4
5
 
5
6
  @interface RCT_EXTERN_MODULE(RNSceneViewManager, RCTViewManager)
6
7
 
7
8
  RCT_EXPORT_VIEW_PROPERTY(environment, NSString)
8
9
  RCT_EXPORT_VIEW_PROPERTY(modelNodes, NSArray)
9
10
  RCT_EXPORT_VIEW_PROPERTY(cameraOrbit, BOOL)
11
+ // v4.3.0 camera + content APIs (issue #1053)
12
+ RCT_EXPORT_VIEW_PROPERTY(cameraControlMode, NSString)
13
+ RCT_EXPORT_VIEW_PROPERTY(autoCenterContent, BOOL)
10
14
  RCT_EXPORT_VIEW_PROPERTY(onTap, RCTDirectEventBlock)
11
15
 
12
16
  @end
@@ -22,3 +26,20 @@ RCT_EXPORT_VIEW_PROPERTY(onTap, RCTDirectEventBlock)
22
26
  RCT_EXPORT_VIEW_PROPERTY(onPlaneDetected, RCTDirectEventBlock)
23
27
 
24
28
  @end
29
+
30
+ // v4.3.0 AR recording native module (issue #1053). ReplayKit-backed,
31
+ // iOS-only — the JS `ARRecorder` class gates non-iOS platforms.
32
+ @interface RCT_EXTERN_MODULE(RNARRecorder, NSObject)
33
+
34
+ RCT_EXTERN_METHOD(start:(RCTPromiseResolveBlock)resolve
35
+ rejecter:(RCTPromiseRejectBlock)reject)
36
+
37
+ RCT_EXTERN_METHOD(stop:(NSString *)outputPath
38
+ resolver:(RCTPromiseResolveBlock)resolve
39
+ rejecter:(RCTPromiseRejectBlock)reject)
40
+
41
+ RCT_EXTERN_METHOD(saveToPhotoLibrary:(NSString *)movPath
42
+ resolver:(RCTPromiseResolveBlock)resolve
43
+ rejecter:(RCTPromiseRejectBlock)reject)
44
+
45
+ @end
@@ -33,12 +33,24 @@ class RNSceneViewManager: RCTViewManager {
33
33
  }
34
34
  }
35
35
 
36
+ /// Maps the wire string sent from JS to a `CameraControlMode` (v4.3.0).
37
+ /// Unknown values fall back to `.orbit`.
38
+ func rnCameraControlMode(_ raw: String?) -> CameraControlMode {
39
+ switch raw {
40
+ case "pan": return .pan
41
+ case "firstPerson": return .firstPerson
42
+ default: return .orbit
43
+ }
44
+ }
45
+
36
46
  /// Observable state model shared between React props and SwiftUI view.
37
47
  @MainActor
38
48
  class RNSceneState: ObservableObject {
39
49
  @Published var models: [RNModelData] = []
40
50
  @Published var environmentPath: String?
41
51
  @Published var cameraOrbit: Bool = true
52
+ @Published var cameraControlMode: CameraControlMode = .orbit
53
+ @Published var autoCenterContent: Bool = true
42
54
  }
43
55
 
44
56
  /// UIView wrapper that hosts a SwiftUI `SceneView` via UIHostingController.
@@ -112,6 +124,25 @@ class RNSceneViewWrapper: UIView {
112
124
  }
113
125
  }
114
126
  }
127
+
128
+ /// Camera interaction mode (v4.3.0, issue #1053).
129
+ @objc var cameraControlMode: String? {
130
+ didSet {
131
+ let mode = rnCameraControlMode(cameraControlMode)
132
+ Task { @MainActor in
133
+ sceneState.cameraControlMode = mode
134
+ }
135
+ }
136
+ }
137
+
138
+ /// Whether to auto-centre scene content (v4.3.0, issue #1053).
139
+ @objc var autoCenterContent: Bool = true {
140
+ didSet {
141
+ Task { @MainActor in
142
+ sceneState.autoCenterContent = autoCenterContent
143
+ }
144
+ }
145
+ }
115
146
  }
116
147
 
117
148
  /// SwiftUI content view rendering SceneViewSwift.SceneView.
@@ -126,6 +157,8 @@ struct RNSceneViewContent: View {
126
157
  .scale(model.scale)
127
158
  }
128
159
  }
160
+ .cameraControls(state.cameraControlMode)
161
+ .autoCenterContent(state.autoCenterContent)
129
162
  }
130
163
  }
131
164
 
@@ -257,3 +290,68 @@ struct RNARSceneViewContent: View {
257
290
  }
258
291
  }
259
292
  }
293
+
294
+ // MARK: - AR Recorder native module (v4.3.0, issue #1053)
295
+
296
+ /// React Native bridge for SceneViewSwift's `ARRecorder` — record-only
297
+ /// AR session capture via ReplayKit. Exposed to JS as `NativeModules.RNARRecorder`.
298
+ ///
299
+ /// iOS-only; the JS `ARRecorder` class guards non-iOS platforms before
300
+ /// calling into this module.
301
+ @objc(RNARRecorder)
302
+ class RNARRecorder: NSObject {
303
+
304
+ /// A single recorder instance shared by the JS `ARRecorder` API —
305
+ /// ReplayKit's `RPScreenRecorder` is itself a process-wide singleton,
306
+ /// so multiple JS instances still drive one underlying recorder.
307
+ @MainActor private lazy var recorder = ARRecorder()
308
+
309
+ override static func requiresMainQueueSetup() -> Bool {
310
+ return true
311
+ }
312
+
313
+ @objc func start(
314
+ _ resolve: @escaping RCTPromiseResolveBlock,
315
+ rejecter reject: @escaping RCTPromiseRejectBlock
316
+ ) {
317
+ Task { @MainActor in
318
+ do {
319
+ try await recorder.startRecording()
320
+ resolve(nil)
321
+ } catch {
322
+ reject("AR_RECORDER_START_FAILED", error.localizedDescription, error)
323
+ }
324
+ }
325
+ }
326
+
327
+ @objc func stop(
328
+ _ outputPath: String?,
329
+ resolver resolve: @escaping RCTPromiseResolveBlock,
330
+ rejecter reject: @escaping RCTPromiseRejectBlock
331
+ ) {
332
+ Task { @MainActor in
333
+ do {
334
+ let outputURL = outputPath.map { URL(fileURLWithPath: $0) }
335
+ let url = try await recorder.stopRecording(outputURL: outputURL)
336
+ resolve(url.path)
337
+ } catch {
338
+ reject("AR_RECORDER_STOP_FAILED", error.localizedDescription, error)
339
+ }
340
+ }
341
+ }
342
+
343
+ @objc func saveToPhotoLibrary(
344
+ _ movPath: String,
345
+ resolver resolve: @escaping RCTPromiseResolveBlock,
346
+ rejecter reject: @escaping RCTPromiseRejectBlock
347
+ ) {
348
+ Task { @MainActor in
349
+ do {
350
+ try await ARRecorder.saveToPhotoLibrary(URL(fileURLWithPath: movPath))
351
+ resolve(nil)
352
+ } catch {
353
+ reject("AR_RECORDER_SAVE_FAILED", error.localizedDescription, error)
354
+ }
355
+ }
356
+ }
357
+ }
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.SceneView = exports.ARSceneView = void 0;
6
+ exports.SceneView = exports.ARSceneView = exports.ARRecorder = void 0;
7
7
  var _react = _interopRequireDefault(require("react"));
8
8
  var _reactNative = require("react-native");
9
9
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -25,6 +25,16 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
25
25
  // Props
26
26
  // ---------------------------------------------------------------------------
27
27
 
28
+ /**
29
+ * Camera interaction mode for a {@link SceneView} (v4.3.0).
30
+ *
31
+ * Platform support:
32
+ * - **iOS**: all three modes are wired through `.cameraControls(_:)`.
33
+ * - **Android**: `'orbit'` is the default; `'pan'` / `'firstPerson'` fall
34
+ * back to orbit (the per-mode switch is an iOS-first v4.3.0 addition —
35
+ * the Android side is tracked in issue #1051).
36
+ */
37
+
28
38
  // ---------------------------------------------------------------------------
29
39
  // Native components (only available on Android and iOS)
30
40
  // ---------------------------------------------------------------------------
@@ -99,5 +109,74 @@ const ARSceneView = props => {
99
109
  }
100
110
  return /*#__PURE__*/_react.default.createElement(NativeARSceneView, props);
101
111
  };
112
+
113
+ // ---------------------------------------------------------------------------
114
+ // AR recording (v4.3.0 — iOS via ReplayKit, see issue #1053)
115
+ // ---------------------------------------------------------------------------
116
+
117
+ /** Native module backing {@link ARRecorder}. Present only on iOS. */
102
118
  exports.ARSceneView = ARSceneView;
119
+ const NativeARRecorder = _reactNative.NativeModules.RNARRecorder;
120
+
121
+ /**
122
+ * Records an AR session to a video file (v4.3.0).
123
+ *
124
+ * iOS port of SceneViewSwift's `ARRecorder` — record-only via ReplayKit,
125
+ * producing a QuickTime `.mov`.
126
+ *
127
+ * ```ts
128
+ * const recorder = new ARRecorder();
129
+ * await recorder.start();
130
+ * // ... later ...
131
+ * const path = await recorder.stop();
132
+ * await recorder.saveToPhotoLibrary(path);
133
+ * ```
134
+ *
135
+ * Platform support:
136
+ * - **iOS**: full support via `RPScreenRecorder`.
137
+ * - **Android**: not yet bridged. ARCore session recording produces a
138
+ * replayable dataset (not a video) and needs deeper `Session`/`Frame`
139
+ * access than the Fabric bridge exposes. Every method rejects with an
140
+ * error on Android until issue #1051 lands the Android side.
141
+ */
142
+ class ARRecorder {
143
+ /** `true` when {@link ARRecorder} is supported on the current platform. */
144
+ static get isSupported() {
145
+ return _reactNative.Platform.OS === 'ios' && NativeARRecorder != null;
146
+ }
147
+ rejectUnsupported() {
148
+ return Promise.reject(new Error('ARRecorder is currently only supported on iOS. Android AR session ' + 'recording is tracked in issue #1051.'));
149
+ }
150
+
151
+ /** Starts an AR session recording. */
152
+ start() {
153
+ if (!ARRecorder.isSupported || !NativeARRecorder) {
154
+ return this.rejectUnsupported();
155
+ }
156
+ return NativeARRecorder.start();
157
+ }
158
+
159
+ /**
160
+ * Stops the in-progress recording and resolves with the path of the
161
+ * written `.mov` file.
162
+ *
163
+ * @param outputPath optional destination path; when omitted the native
164
+ * side picks a temp location.
165
+ */
166
+ stop(outputPath) {
167
+ if (!ARRecorder.isSupported || !NativeARRecorder) {
168
+ return this.rejectUnsupported();
169
+ }
170
+ return NativeARRecorder.stop(outputPath ?? null);
171
+ }
172
+
173
+ /** Saves a recorded `.mov` file to the device's photo library (iOS). */
174
+ saveToPhotoLibrary(movPath) {
175
+ if (!ARRecorder.isSupported || !NativeARRecorder) {
176
+ return this.rejectUnsupported();
177
+ }
178
+ return NativeARRecorder.saveToPhotoLibrary(movPath);
179
+ }
180
+ }
181
+ exports.ARRecorder = ARRecorder;
103
182
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["_react","_interopRequireDefault","require","_reactNative","e","__esModule","default","isNativeAvailable","Platform","OS","NativeSceneView","requireNativeComponent","NativeARSceneView","UnsupportedView","name","createElement","View","style","fallbackStyles","container","Text","text","StyleSheet","create","flex","justifyContent","alignItems","backgroundColor","color","fontSize","SceneView","props","exports","ARSceneView"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;AAQsB,SAAAD,uBAAAG,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAEtB;AACA;AACA;;AAEA;;AAiBA;;AAmBA;;AASA;AACA;AACA;;AAkBA;AACA;AACA;;AAoCA;AACA;AACA;;AAEA,MAAMG,iBAAiB,GAAGC,qBAAQ,CAACC,EAAE,KAAK,SAAS,IAAID,qBAAQ,CAACC,EAAE,KAAK,KAAK;AAE5E,MAAMC,eAAe,GAAGH,iBAAiB,GACrC,IAAAI,mCAAsB,EAAiB,aAAa,CAAC,GACrD,IAAI;AAER,MAAMC,iBAAiB,GAAGL,iBAAiB,GACvC,IAAAI,mCAAsB,EAAmB,eAAe,CAAC,GACzD,IAAI;;AAER;AACA;AACA;;AAEA,MAAME,eAA2C,GAAGA,CAAC;EAAEC;AAAK,CAAC,kBAC3Dd,MAAA,CAAAM,OAAA,CAAAS,aAAA,CAACZ,YAAA,CAAAa,IAAI;EAACC,KAAK,EAAEC,cAAc,CAACC;AAAU,gBACpCnB,MAAA,CAAAM,OAAA,CAAAS,aAAA,CAACZ,YAAA,CAAAiB,IAAI;EAACH,KAAK,EAAEC,cAAc,CAACG;AAAK,GAAEP,IAAI,EAAC,oCAAwC,CAC5E,CACP;AAED,MAAMI,cAAc,GAAGI,uBAAU,CAACC,MAAM,CAAC;EACvCJ,SAAS,EAAE;IACTK,IAAI,EAAE,CAAC;IACPC,cAAc,EAAE,QAAQ;IACxBC,UAAU,EAAE,QAAQ;IACpBC,eAAe,EAAE;EACnB,CAAC;EACDN,IAAI,EAAE;IACJO,KAAK,EAAE,MAAM;IACbC,QAAQ,EAAE;EACZ;AACF,CAAC,CAAC;;AAEF;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMC,SAAmC,GAAIC,KAAK,IAAK;EAC5D,IAAI,CAACrB,eAAe,EAAE;IACpB,oBAAOV,MAAA,CAAAM,OAAA,CAAAS,aAAA,CAACF,eAAe;MAACC,IAAI,EAAC;IAAW,CAAE,CAAC;EAC7C;EACA,oBAAOd,MAAA,CAAAM,OAAA,CAAAS,aAAA,CAACL,eAAe,EAAKqB,KAAQ,CAAC;AACvC,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AATAC,OAAA,CAAAF,SAAA,GAAAA,SAAA;AAUO,MAAMG,WAAuC,GAAIF,KAAK,IAAK;EAChE,IAAI,CAACnB,iBAAiB,EAAE;IACtB,oBAAOZ,MAAA,CAAAM,OAAA,CAAAS,aAAA,CAACF,eAAe;MAACC,IAAI,EAAC;IAAa,CAAE,CAAC;EAC/C;EACA,oBAAOd,MAAA,CAAAM,OAAA,CAAAS,aAAA,CAACH,iBAAiB,EAAKmB,KAAQ,CAAC;AACzC,CAAC;AAACC,OAAA,CAAAC,WAAA,GAAAA,WAAA","ignoreList":[]}
1
+ {"version":3,"names":["_react","_interopRequireDefault","require","_reactNative","e","__esModule","default","isNativeAvailable","Platform","OS","NativeSceneView","requireNativeComponent","NativeARSceneView","UnsupportedView","name","createElement","View","style","fallbackStyles","container","Text","text","StyleSheet","create","flex","justifyContent","alignItems","backgroundColor","color","fontSize","SceneView","props","exports","ARSceneView","NativeARRecorder","NativeModules","RNARRecorder","ARRecorder","isSupported","rejectUnsupported","Promise","reject","Error","start","stop","outputPath","saveToPhotoLibrary","movPath"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { requireNativeComponent, Platform, View, Text, StyleSheet } from 'react-native';
2
+ import { requireNativeComponent, NativeModules, Platform, View, Text, StyleSheet } from 'react-native';
3
3
 
4
4
  // ---------------------------------------------------------------------------
5
5
  // Node type interfaces
@@ -19,6 +19,16 @@ import { requireNativeComponent, Platform, View, Text, StyleSheet } from 'react-
19
19
  // Props
20
20
  // ---------------------------------------------------------------------------
21
21
 
22
+ /**
23
+ * Camera interaction mode for a {@link SceneView} (v4.3.0).
24
+ *
25
+ * Platform support:
26
+ * - **iOS**: all three modes are wired through `.cameraControls(_:)`.
27
+ * - **Android**: `'orbit'` is the default; `'pan'` / `'firstPerson'` fall
28
+ * back to orbit (the per-mode switch is an iOS-first v4.3.0 addition —
29
+ * the Android side is tracked in issue #1051).
30
+ */
31
+
22
32
  // ---------------------------------------------------------------------------
23
33
  // Native components (only available on Android and iOS)
24
34
  // ---------------------------------------------------------------------------
@@ -92,4 +102,73 @@ export const ARSceneView = props => {
92
102
  }
93
103
  return /*#__PURE__*/React.createElement(NativeARSceneView, props);
94
104
  };
105
+
106
+ // ---------------------------------------------------------------------------
107
+ // AR recording (v4.3.0 — iOS via ReplayKit, see issue #1053)
108
+ // ---------------------------------------------------------------------------
109
+
110
+ /** Native module backing {@link ARRecorder}. Present only on iOS. */
111
+
112
+ const NativeARRecorder = NativeModules.RNARRecorder;
113
+
114
+ /**
115
+ * Records an AR session to a video file (v4.3.0).
116
+ *
117
+ * iOS port of SceneViewSwift's `ARRecorder` — record-only via ReplayKit,
118
+ * producing a QuickTime `.mov`.
119
+ *
120
+ * ```ts
121
+ * const recorder = new ARRecorder();
122
+ * await recorder.start();
123
+ * // ... later ...
124
+ * const path = await recorder.stop();
125
+ * await recorder.saveToPhotoLibrary(path);
126
+ * ```
127
+ *
128
+ * Platform support:
129
+ * - **iOS**: full support via `RPScreenRecorder`.
130
+ * - **Android**: not yet bridged. ARCore session recording produces a
131
+ * replayable dataset (not a video) and needs deeper `Session`/`Frame`
132
+ * access than the Fabric bridge exposes. Every method rejects with an
133
+ * error on Android until issue #1051 lands the Android side.
134
+ */
135
+ export class ARRecorder {
136
+ /** `true` when {@link ARRecorder} is supported on the current platform. */
137
+ static get isSupported() {
138
+ return Platform.OS === 'ios' && NativeARRecorder != null;
139
+ }
140
+ rejectUnsupported() {
141
+ return Promise.reject(new Error('ARRecorder is currently only supported on iOS. Android AR session ' + 'recording is tracked in issue #1051.'));
142
+ }
143
+
144
+ /** Starts an AR session recording. */
145
+ start() {
146
+ if (!ARRecorder.isSupported || !NativeARRecorder) {
147
+ return this.rejectUnsupported();
148
+ }
149
+ return NativeARRecorder.start();
150
+ }
151
+
152
+ /**
153
+ * Stops the in-progress recording and resolves with the path of the
154
+ * written `.mov` file.
155
+ *
156
+ * @param outputPath optional destination path; when omitted the native
157
+ * side picks a temp location.
158
+ */
159
+ stop(outputPath) {
160
+ if (!ARRecorder.isSupported || !NativeARRecorder) {
161
+ return this.rejectUnsupported();
162
+ }
163
+ return NativeARRecorder.stop(outputPath ?? null);
164
+ }
165
+
166
+ /** Saves a recorded `.mov` file to the device's photo library (iOS). */
167
+ saveToPhotoLibrary(movPath) {
168
+ if (!ARRecorder.isSupported || !NativeARRecorder) {
169
+ return this.rejectUnsupported();
170
+ }
171
+ return NativeARRecorder.saveToPhotoLibrary(movPath);
172
+ }
173
+ }
95
174
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["React","requireNativeComponent","Platform","View","Text","StyleSheet","isNativeAvailable","OS","NativeSceneView","NativeARSceneView","UnsupportedView","name","createElement","style","fallbackStyles","container","text","create","flex","justifyContent","alignItems","backgroundColor","color","fontSize","SceneView","props","ARSceneView"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AACzB,SACEC,sBAAsB,EACtBC,QAAQ,EAGRC,IAAI,EACJC,IAAI,EACJC,UAAU,QACL,cAAc;;AAErB;AACA;AACA;;AAEA;;AAiBA;;AAmBA;;AASA;AACA;AACA;;AAkBA;AACA;AACA;;AAoCA;AACA;AACA;;AAEA,MAAMC,iBAAiB,GAAGJ,QAAQ,CAACK,EAAE,KAAK,SAAS,IAAIL,QAAQ,CAACK,EAAE,KAAK,KAAK;AAE5E,MAAMC,eAAe,GAAGF,iBAAiB,GACrCL,sBAAsB,CAAiB,aAAa,CAAC,GACrD,IAAI;AAER,MAAMQ,iBAAiB,GAAGH,iBAAiB,GACvCL,sBAAsB,CAAmB,eAAe,CAAC,GACzD,IAAI;;AAER;AACA;AACA;;AAEA,MAAMS,eAA2C,GAAGA,CAAC;EAAEC;AAAK,CAAC,kBAC3DX,KAAA,CAAAY,aAAA,CAACT,IAAI;EAACU,KAAK,EAAEC,cAAc,CAACC;AAAU,gBACpCf,KAAA,CAAAY,aAAA,CAACR,IAAI;EAACS,KAAK,EAAEC,cAAc,CAACE;AAAK,GAAEL,IAAI,EAAC,oCAAwC,CAC5E,CACP;AAED,MAAMG,cAAc,GAAGT,UAAU,CAACY,MAAM,CAAC;EACvCF,SAAS,EAAE;IACTG,IAAI,EAAE,CAAC;IACPC,cAAc,EAAE,QAAQ;IACxBC,UAAU,EAAE,QAAQ;IACpBC,eAAe,EAAE;EACnB,CAAC;EACDL,IAAI,EAAE;IACJM,KAAK,EAAE,MAAM;IACbC,QAAQ,EAAE;EACZ;AACF,CAAC,CAAC;;AAEF;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,SAAmC,GAAIC,KAAK,IAAK;EAC5D,IAAI,CAACjB,eAAe,EAAE;IACpB,oBAAOR,KAAA,CAAAY,aAAA,CAACF,eAAe;MAACC,IAAI,EAAC;IAAW,CAAE,CAAC;EAC7C;EACA,oBAAOX,KAAA,CAAAY,aAAA,CAACJ,eAAe,EAAKiB,KAAQ,CAAC;AACvC,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,WAAuC,GAAID,KAAK,IAAK;EAChE,IAAI,CAAChB,iBAAiB,EAAE;IACtB,oBAAOT,KAAA,CAAAY,aAAA,CAACF,eAAe;MAACC,IAAI,EAAC;IAAa,CAAE,CAAC;EAC/C;EACA,oBAAOX,KAAA,CAAAY,aAAA,CAACH,iBAAiB,EAAKgB,KAAQ,CAAC;AACzC,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["React","requireNativeComponent","NativeModules","Platform","View","Text","StyleSheet","isNativeAvailable","OS","NativeSceneView","NativeARSceneView","UnsupportedView","name","createElement","style","fallbackStyles","container","text","create","flex","justifyContent","alignItems","backgroundColor","color","fontSize","SceneView","props","ARSceneView","NativeARRecorder","RNARRecorder","ARRecorder","isSupported","rejectUnsupported","Promise","reject","Error","start","stop","outputPath","saveToPhotoLibrary","movPath"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
@@ -56,6 +56,16 @@ export interface PlaneDetectedEvent {
56
56
  center: [number, number, number];
57
57
  extent: [number, number];
58
58
  }
59
+ /**
60
+ * Camera interaction mode for a {@link SceneView} (v4.3.0).
61
+ *
62
+ * Platform support:
63
+ * - **iOS**: all three modes are wired through `.cameraControls(_:)`.
64
+ * - **Android**: `'orbit'` is the default; `'pan'` / `'firstPerson'` fall
65
+ * back to orbit (the per-mode switch is an iOS-first v4.3.0 addition —
66
+ * the Android side is tracked in issue #1051).
67
+ */
68
+ export type CameraControlMode = 'orbit' | 'pan' | 'firstPerson';
59
69
  export interface SceneViewProps {
60
70
  style?: ViewStyle;
61
71
  /** HDR environment asset path (e.g. "environments/studio.hdr"). */
@@ -68,6 +78,19 @@ export interface SceneViewProps {
68
78
  lightNodes?: LightNode[];
69
79
  /** Enable default orbit camera controls. Default: true. */
70
80
  cameraOrbit?: boolean;
81
+ /**
82
+ * Camera interaction mode (v4.3.0). Default: `'orbit'`.
83
+ *
84
+ * `'pan'` and `'firstPerson'` are iOS-only; on Android they fall back to
85
+ * orbit. See {@link CameraControlMode}.
86
+ */
87
+ cameraControlMode?: CameraControlMode;
88
+ /**
89
+ * Whether the scene auto-centres its content on the first stable frame
90
+ * (v4.3.0). Default: `true`. iOS-first; the Android side is tracked in
91
+ * issue #1051.
92
+ */
93
+ autoCenterContent?: boolean;
71
94
  /** Called when the user taps inside the scene. */
72
95
  onTap?: (event: NativeSyntheticEvent<TapEvent>) => void;
73
96
  }
@@ -103,4 +126,42 @@ export declare const SceneView: React.FC<SceneViewProps>;
103
126
  * ```
104
127
  */
105
128
  export declare const ARSceneView: React.FC<ARSceneViewProps>;
129
+ /**
130
+ * Records an AR session to a video file (v4.3.0).
131
+ *
132
+ * iOS port of SceneViewSwift's `ARRecorder` — record-only via ReplayKit,
133
+ * producing a QuickTime `.mov`.
134
+ *
135
+ * ```ts
136
+ * const recorder = new ARRecorder();
137
+ * await recorder.start();
138
+ * // ... later ...
139
+ * const path = await recorder.stop();
140
+ * await recorder.saveToPhotoLibrary(path);
141
+ * ```
142
+ *
143
+ * Platform support:
144
+ * - **iOS**: full support via `RPScreenRecorder`.
145
+ * - **Android**: not yet bridged. ARCore session recording produces a
146
+ * replayable dataset (not a video) and needs deeper `Session`/`Frame`
147
+ * access than the Fabric bridge exposes. Every method rejects with an
148
+ * error on Android until issue #1051 lands the Android side.
149
+ */
150
+ export declare class ARRecorder {
151
+ /** `true` when {@link ARRecorder} is supported on the current platform. */
152
+ static get isSupported(): boolean;
153
+ private rejectUnsupported;
154
+ /** Starts an AR session recording. */
155
+ start(): Promise<void>;
156
+ /**
157
+ * Stops the in-progress recording and resolves with the path of the
158
+ * written `.mov` file.
159
+ *
160
+ * @param outputPath optional destination path; when omitted the native
161
+ * side picks a temp location.
162
+ */
163
+ stop(outputPath?: string): Promise<string>;
164
+ /** Saves a recorded `.mov` file to the device's photo library (iOS). */
165
+ saveToPhotoLibrary(movPath: string): Promise<void>;
166
+ }
106
167
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sceneview-sdk/react-native",
3
- "version": "4.3.5",
3
+ "version": "4.4.0",
4
4
  "description": "React Native bindings for SceneView — 3D and AR scenes powered by Filament (Android) and RealityKit (iOS)",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
package/src/index.tsx CHANGED
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import {
3
3
  requireNativeComponent,
4
+ NativeModules,
4
5
  Platform,
5
6
  type ViewStyle,
6
7
  type NativeSyntheticEvent,
@@ -82,6 +83,17 @@ export interface PlaneDetectedEvent {
82
83
  // Props
83
84
  // ---------------------------------------------------------------------------
84
85
 
86
+ /**
87
+ * Camera interaction mode for a {@link SceneView} (v4.3.0).
88
+ *
89
+ * Platform support:
90
+ * - **iOS**: all three modes are wired through `.cameraControls(_:)`.
91
+ * - **Android**: `'orbit'` is the default; `'pan'` / `'firstPerson'` fall
92
+ * back to orbit (the per-mode switch is an iOS-first v4.3.0 addition —
93
+ * the Android side is tracked in issue #1051).
94
+ */
95
+ export type CameraControlMode = 'orbit' | 'pan' | 'firstPerson';
96
+
85
97
  export interface SceneViewProps {
86
98
  style?: ViewStyle;
87
99
 
@@ -98,6 +110,21 @@ export interface SceneViewProps {
98
110
  /** Enable default orbit camera controls. Default: true. */
99
111
  cameraOrbit?: boolean;
100
112
 
113
+ /**
114
+ * Camera interaction mode (v4.3.0). Default: `'orbit'`.
115
+ *
116
+ * `'pan'` and `'firstPerson'` are iOS-only; on Android they fall back to
117
+ * orbit. See {@link CameraControlMode}.
118
+ */
119
+ cameraControlMode?: CameraControlMode;
120
+
121
+ /**
122
+ * Whether the scene auto-centres its content on the first stable frame
123
+ * (v4.3.0). Default: `true`. iOS-first; the Android side is tracked in
124
+ * issue #1051.
125
+ */
126
+ autoCenterContent?: boolean;
127
+
101
128
  /** Called when the user taps inside the scene. */
102
129
  onTap?: (event: NativeSyntheticEvent<TapEvent>) => void;
103
130
  }
@@ -190,3 +217,84 @@ export const ARSceneView: React.FC<ARSceneViewProps> = (props) => {
190
217
  }
191
218
  return <NativeARSceneView {...props} />;
192
219
  };
220
+
221
+ // ---------------------------------------------------------------------------
222
+ // AR recording (v4.3.0 — iOS via ReplayKit, see issue #1053)
223
+ // ---------------------------------------------------------------------------
224
+
225
+ /** Native module backing {@link ARRecorder}. Present only on iOS. */
226
+ interface RNARRecorderModule {
227
+ start(): Promise<void>;
228
+ stop(outputPath?: string | null): Promise<string>;
229
+ saveToPhotoLibrary(movPath: string): Promise<void>;
230
+ }
231
+
232
+ const NativeARRecorder: RNARRecorderModule | undefined =
233
+ NativeModules.RNARRecorder;
234
+
235
+ /**
236
+ * Records an AR session to a video file (v4.3.0).
237
+ *
238
+ * iOS port of SceneViewSwift's `ARRecorder` — record-only via ReplayKit,
239
+ * producing a QuickTime `.mov`.
240
+ *
241
+ * ```ts
242
+ * const recorder = new ARRecorder();
243
+ * await recorder.start();
244
+ * // ... later ...
245
+ * const path = await recorder.stop();
246
+ * await recorder.saveToPhotoLibrary(path);
247
+ * ```
248
+ *
249
+ * Platform support:
250
+ * - **iOS**: full support via `RPScreenRecorder`.
251
+ * - **Android**: not yet bridged. ARCore session recording produces a
252
+ * replayable dataset (not a video) and needs deeper `Session`/`Frame`
253
+ * access than the Fabric bridge exposes. Every method rejects with an
254
+ * error on Android until issue #1051 lands the Android side.
255
+ */
256
+ export class ARRecorder {
257
+ /** `true` when {@link ARRecorder} is supported on the current platform. */
258
+ static get isSupported(): boolean {
259
+ return Platform.OS === 'ios' && NativeARRecorder != null;
260
+ }
261
+
262
+ private rejectUnsupported(): Promise<never> {
263
+ return Promise.reject(
264
+ new Error(
265
+ 'ARRecorder is currently only supported on iOS. Android AR session ' +
266
+ 'recording is tracked in issue #1051.'
267
+ )
268
+ );
269
+ }
270
+
271
+ /** Starts an AR session recording. */
272
+ start(): Promise<void> {
273
+ if (!ARRecorder.isSupported || !NativeARRecorder) {
274
+ return this.rejectUnsupported();
275
+ }
276
+ return NativeARRecorder.start();
277
+ }
278
+
279
+ /**
280
+ * Stops the in-progress recording and resolves with the path of the
281
+ * written `.mov` file.
282
+ *
283
+ * @param outputPath optional destination path; when omitted the native
284
+ * side picks a temp location.
285
+ */
286
+ stop(outputPath?: string): Promise<string> {
287
+ if (!ARRecorder.isSupported || !NativeARRecorder) {
288
+ return this.rejectUnsupported();
289
+ }
290
+ return NativeARRecorder.stop(outputPath ?? null);
291
+ }
292
+
293
+ /** Saves a recorded `.mov` file to the device's photo library (iOS). */
294
+ saveToPhotoLibrary(movPath: string): Promise<void> {
295
+ if (!ARRecorder.isSupported || !NativeARRecorder) {
296
+ return this.rejectUnsupported();
297
+ }
298
+ return NativeARRecorder.saveToPhotoLibrary(movPath);
299
+ }
300
+ }