react-native-image-stitcher 0.5.0 → 0.6.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.
@@ -89,7 +89,6 @@ import {
89
89
  subscribeIncrementalState,
90
90
  type IncrementalState,
91
91
  } from '../stitching/incremental';
92
- import { useIncrementalJSDriver } from '../stitching/useIncrementalJSDriver';
93
92
  import { useFrameProcessorDriver } from '../stitching/useFrameProcessorDriver';
94
93
  import { useIncrementalStitcher } from '../stitching/useIncrementalStitcher';
95
94
  import { useIMUTranslationGate } from '../sensors/useIMUTranslationGate';
@@ -235,6 +234,29 @@ export interface CameraProps {
235
234
  showSettingsButton?: boolean;
236
235
  style?: StyleProp<ViewStyle>;
237
236
 
237
+ /**
238
+ * Which incremental stitcher engine to drive. Default
239
+ * `'batch-keyframe'` — collects accepted JPEGs and runs
240
+ * `cv::Stitcher` once at finalize time. This is the v0.4+
241
+ * production default and what the v0.5 Frame Processor migration
242
+ * exercises.
243
+ *
244
+ * Switch to a live engine (`'firstwins-rectilinear'` or
245
+ * `'hybrid'`) for low-latency in-flight stitching. Live engines
246
+ * exercise the F8.6 pixel-buffer ingest path (skipping the JPEG
247
+ * encode/decode round-trip; ~30–50 ms saved per accept) when the
248
+ * Frame Processor driver is active.
249
+ *
250
+ * See `docs/f8-frame-processor-plan.md` and the v0.5.0
251
+ * CHANGELOG for the trade-offs between batch-keyframe and live
252
+ * engines.
253
+ */
254
+ engine?: 'batch-keyframe'
255
+ | 'hybrid'
256
+ | 'slitscan-rotate' | 'slitscan-both'
257
+ | 'firstwins' | 'firstwins-zoomed' | 'firstwins-rectilinear'
258
+ | 'slitscan';
259
+
238
260
  /**
239
261
  * Optional destination directory for captures. When set, the lib
240
262
  * lands tap-photos at `${outputDir}/photo-${ts}.jpg` and panoramas
@@ -280,37 +302,20 @@ export interface CameraProps {
280
302
  * Introduced for F8 (FrameProcessor port) — see
281
303
  * `docs/f8-frame-processor-plan.md`.
282
304
  *
283
- * As of v0.5 (F8.3) this prop is **deprecated for the standard
284
- * non-AR capture flow**: the SDK now installs its own frame
285
- * processor via `useFrameProcessorDriver` that pipes pixel
286
- * buffers into the incremental stitcher with synthesised pose.
287
- * Setting this prop in the default mode will be IGNORED with a
288
- * one-time console.warn — supplying your own worklet would race
289
- * with the SDK's pixel-buffer feed.
305
+ * The SDK installs its own frame processor via
306
+ * `useFrameProcessorDriver`. Setting this prop is ignored with
307
+ * a one-time `console.warn` supplying a host worklet would
308
+ * race with the SDK's pixel-buffer feed. Either remove the prop
309
+ * or fork the SDK if you genuinely need a custom worklet.
290
310
  *
291
- * Three coexistence rules:
292
- * * Default (modern non-AR): SDK owns the worklet, this prop
293
- * is ignored.
294
- * * `legacyDriver={true}`: SDK uses the old `useIncrementalJSDriver`
295
- * (takeSnapshot path). Honoured for diagnostics or as an
296
- * escape hatch.
297
- * * AR mode: vision-camera Camera isn't mounted, this prop is
298
- * irrelevant.
299
- */
300
- frameProcessor?: ReadonlyFrameProcessor | DrawableFrameProcessor;
301
-
302
- /**
303
- * Opt back into the legacy `useIncrementalJSDriver` for non-AR
304
- * captures (the v0.4 path: `takeSnapshot` → JPEG → cache file →
305
- * `IncrementalStitcher.processFrameAtPath`).
311
+ * AR mode is irrelevant: vision-camera's Camera isn't mounted.
306
312
  *
307
- * Default `false` (use the new `useFrameProcessorDriver`, which
308
- * runs the gate on the camera producer thread at native frame
309
- * rate via a vision-camera Frame Processor plugin). The legacy
310
- * path will be removed in v0.6 — set this only if you hit a
311
- * specific issue with the new driver and need to ship a fix.
313
+ * (v0.5 had a `legacyDriver` escape hatch that routed back to
314
+ * `useIncrementalJSDriver`. That hook + prop were removed in
315
+ * v0.6 per the deprecation timeline announced in the v0.5.0
316
+ * CHANGELOG.)
312
317
  */
313
- legacyDriver?: boolean;
318
+ frameProcessor?: ReadonlyFrameProcessor | DrawableFrameProcessor;
314
319
  }
315
320
 
316
321
 
@@ -586,7 +591,7 @@ export function Camera(props: CameraProps): React.JSX.Element {
586
591
  onFramesDropped,
587
592
  onError,
588
593
  frameProcessor: hostFrameProcessor,
589
- legacyDriver = false,
594
+ engine = 'batch-keyframe',
590
595
  } = props;
591
596
 
592
597
  const insets = useSafeAreaInsets();
@@ -766,63 +771,49 @@ export function Camera(props: CameraProps): React.JSX.Element {
766
771
  },
767
772
  });
768
773
 
769
- // JS-driver for non-AR captures (iOS + Android). In AR mode the
770
- // engine consumes frames from the ARSession stream natively, so this
771
- // hook stays idle.
774
+ // Frame Processor driver for non-AR captures (iOS + Android).
775
+ // In AR mode the engine consumes frames from the ARSession stream
776
+ // natively, so this hook stays idle.
772
777
  //
773
778
  // IMPORTANT: start()/stop() are called imperatively from the hold
774
779
  // handlers below — NOT from a useEffect driven by statusPhase. The
775
780
  // hook returns a fresh object identity on every render, and during
776
781
  // a recording the engine emits IncrementalStateUpdate events that
777
- // cause re-renders multiple times per second. An effect with
778
- // `jsDriver` in its deps would teardown + restart the driver on
779
- // every event, resetting the gyro accumulator (yaw/pitch) to zero
780
- // each cycle and nulling the cameraRef during the brief gap. The
781
- // user-visible symptom was "only the first keyframe is accepted,
782
- // every subsequent snapshot sees pose=(0,0) and is rejected as a
783
- // duplicate of the first". Matching AuditCaptureScreen's proven
784
- // imperative pattern (start on hold-start, stop on hold-end) avoids
785
- // the re-render churn entirely.
786
- const jsDriver = useIncrementalJSDriver();
787
- // F8.3 — vision-camera Frame Processor variant. Always
788
- // instantiated so we don't have conditional hook calls; only one
789
- // of the two drivers actually .start()s per capture. Stop() on
790
- // an idle driver is a no-op.
782
+ // cause re-renders multiple times per second. An effect with the
783
+ // driver in its deps would teardown + restart on every event,
784
+ // resetting the gyro accumulator (yaw/pitch) to zero each cycle.
785
+ // User-visible symptom: "only the first keyframe is accepted, every
786
+ // subsequent ingest sees pose=(0,0) and is rejected as a duplicate".
787
+ // The imperative pattern (start on hold-start, stop on hold-end)
788
+ // avoids the re-render churn entirely.
791
789
  const fpDriver = useFrameProcessorDriver();
792
- // Safety: ensure both drivers are stopped if the component unmounts
793
- // mid-recording. Empty deps so this only fires on unmount.
790
+ // Safety: stop the driver if the component unmounts mid-recording.
794
791
  // eslint-disable-next-line react-hooks/exhaustive-deps
795
- useEffect(() => () => { jsDriver.stop(); fpDriver.stop(); }, []);
796
-
797
- // F8.3 — one-shot deprecation warning when the host supplies their
798
- // own `frameProcessor` while running in the default (Frame
799
- // Processor driver) mode. Two worklets racing on the same
800
- // producer thread would corrupt the engine's workQueue ordering;
801
- // the SDK's own worklet wins and the host's is ignored. Hosts
802
- // that *need* a custom worklet must opt into `legacyDriver={true}`
803
- // (which switches off the SDK's worklet entirely).
792
+ useEffect(() => () => { fpDriver.stop(); }, []);
793
+
794
+ // One-shot deprecation warning when the host supplies their own
795
+ // `frameProcessor` prop. Two worklets racing on the same
796
+ // producer thread would corrupt the engine's workQueue ordering,
797
+ // so the SDK's own worklet wins and the host's is silently
798
+ // ignored. (v0.5 had a `legacyDriver` opt-out for hosts that
799
+ // wanted to route around the SDK driver; that was removed in
800
+ // v0.6 along with `useIncrementalJSDriver`.)
804
801
  const hostFrameProcessorIgnoredWarnedRef = useRef(false);
805
802
  if (
806
803
  hostFrameProcessor != null
807
- && !legacyDriver
808
804
  && !hostFrameProcessorIgnoredWarnedRef.current
809
805
  ) {
810
806
  hostFrameProcessorIgnoredWarnedRef.current = true;
811
807
  // eslint-disable-next-line no-console
812
808
  console.warn(
813
809
  '[react-native-image-stitcher] The `frameProcessor` prop on '
814
- + '<Camera> is ignored when the default driver is active '
815
- + '(legacyDriver=false). Either remove the prop or set '
816
- + 'legacyDriver={true} to opt into the legacy path.',
810
+ + '<Camera> is ignored the SDK installs its own worklet '
811
+ + 'via useFrameProcessorDriver. Remove the prop, or fork '
812
+ + 'the SDK if you genuinely need a custom worklet.',
817
813
  );
818
814
  }
819
- // The Frame Processor worklet actually bound to vision-camera's
820
- // Camera. Resolution order:
821
- // 1. Legacy mode: honor the host's prop (or null).
822
- // 2. Modern mode: SDK driver's worklet, regardless of host's prop.
823
- const effectiveFrameProcessor = legacyDriver
824
- ? (hostFrameProcessor ?? null)
825
- : fpDriver.frameProcessor;
815
+ // The Frame Processor worklet bound to vision-camera's Camera.
816
+ const effectiveFrameProcessor = fpDriver.frameProcessor;
826
817
 
827
818
  // ── Subscribe to engine state for live keyframe thumbs ──────────
828
819
  useEffect(() => {
@@ -879,17 +870,17 @@ export function Camera(props: CameraProps): React.JSX.Element {
879
870
  const accepted = incrementalState?.acceptedCount ?? 0;
880
871
  if (accepted > lastAcceptedCountRef.current) {
881
872
  lastAcceptedCountRef.current = accepted;
882
- // F8.3 review-of-review (M3 revert): originally gated this to
883
- // `legacyDriver` because the Frame Processor driver doesn't
884
- // consult `imuGate` for its own pose synthesis. That ignored a
885
- // load-bearing side effect: `imuGate.resetAnchor()` bounds the
886
- // IIR-integrator drift window per-accept, and
887
- // `imuGate.getTotalAbsMetres()` is read at finalize time
888
- // (Camera.tsx:1097) as `imuTranslationMetres` into the native
873
+ // F8.3 review-of-review (M3 revert): an earlier draft gated
874
+ // this on the pre-v0.6 `legacyDriver` prop because the Frame
875
+ // Processor driver doesn't consult `imuGate` for its own pose
876
+ // synthesis. That ignored a load-bearing side effect:
877
+ // `imuGate.resetAnchor()` bounds the IIR-integrator drift
878
+ // window per-accept, and `imuGate.getTotalAbsMetres()` is read
879
+ // at finalize time as `imuTranslationMetres` into the native
889
880
  // stitchMode auto-resolver (PANORAMA vs SCANS). Without the
890
881
  // per-accept reset, long FP-driver captures let IIR drift
891
- // compound → inflated metres → biased toward SCANS. Keep the
892
- // reset firing for ALL non-AR modes.
882
+ // compound → inflated metres → biased toward SCANS. Now fires
883
+ // for ALL non-AR captures (the only non-AR driver post-v0.6).
893
884
  if (isNonAR) {
894
885
  imuGate.resetAnchor();
895
886
  }
@@ -1020,18 +1011,16 @@ export function Camera(props: CameraProps): React.JSX.Element {
1020
1011
  snapshotEveryNAccepts: 1,
1021
1012
  frameRotationDegrees: orientationRotation,
1022
1013
  captureOrientation: deviceOrientation,
1023
- // F8.3 — non-AR captures pick between the new Frame Processor
1024
- // driver (default) and the legacy JS-snapshot driver (opt-in
1025
- // via `legacyDriver={true}`). AR captures always use the
1026
- // ARSession-driven path.
1027
- frameSourceMode: isNonAR
1028
- ? (legacyDriver ? 'jsDriver' : 'frameProcessor')
1029
- : 'arSession',
1014
+ // Non-AR captures use the Frame Processor driver
1015
+ // (vision-camera producer-thread worklet cv_flow_gate
1016
+ // plugin → IncrementalStitcher.consumeFrame). AR captures
1017
+ // use the ARSession-driven path.
1018
+ frameSourceMode: isNonAR ? 'frameProcessor' : 'arSession',
1030
1019
  composeWidth: 1920,
1031
1020
  composeHeight: 1080,
1032
1021
  canvasWidth: 5000,
1033
1022
  canvasHeight: 5000,
1034
- engine: 'batch-keyframe',
1023
+ engine,
1035
1024
  config: panoramaSettingsToNativeConfig({
1036
1025
  ...settings,
1037
1026
  captureSource: effectiveCaptureSource,
@@ -1042,21 +1031,13 @@ export function Camera(props: CameraProps): React.JSX.Element {
1042
1031
  // matching comment on the per-accept reset useEffect above).
1043
1032
  // Keep firing it on every capture start, not just legacy mode.
1044
1033
  imuGate.resetAnchor();
1045
- // Start the non-AR frame source. AR mode feeds natively from
1046
- // ARSession so both drivers stay idle in that path.
1047
- // * Default: Frame Processor driver worklet runs on the
1048
- // producer thread, plugin calls `consumeFrameFromPlugin`
1049
- // directly. No camera ref needed (vision-camera owns it).
1050
- // * Legacy: JS driver — `takeSnapshot` + `processFrameAtPath`
1051
- // via the cameraRef.
1052
- // Imperative-pattern rationale: see the useIncrementalJSDriver
1053
- // comment above re. why this isn't a useEffect.
1034
+ // Start the Frame Processor driver for non-AR captures. AR
1035
+ // mode feeds natively from ARSession so the driver stays idle.
1036
+ // Imperative pattern (vs useEffect) because the driver's start
1037
+ // resets pose accumulators that should only fire at the
1038
+ // hold-start moment, not on every re-render.
1054
1039
  if (isNonAR) {
1055
- if (legacyDriver) {
1056
- jsDriver.start(visionCameraRef);
1057
- } else {
1058
- fpDriver.start();
1059
- }
1040
+ fpDriver.start();
1060
1041
  }
1061
1042
  } catch (err) {
1062
1043
  setStatusPhase('idle');
@@ -1076,9 +1057,8 @@ export function Camera(props: CameraProps): React.JSX.Element {
1076
1057
  settings,
1077
1058
  effectiveCaptureSource,
1078
1059
  imuGate,
1079
- jsDriver,
1080
1060
  fpDriver,
1081
- legacyDriver,
1061
+ engine,
1082
1062
  onError,
1083
1063
  ]);
1084
1064
 
@@ -1087,10 +1067,7 @@ export function Camera(props: CameraProps): React.JSX.Element {
1087
1067
  setStatusPhase('stitching');
1088
1068
  // Stop pumping new frames before finalizing so the engine isn't
1089
1069
  // racing the final cv::Stitcher pass against late-arriving
1090
- // keyframes. Both stop() calls are no-ops when the
1091
- // corresponding driver wasn't started (AR mode, or the inactive
1092
- // driver in non-AR mode).
1093
- jsDriver.stop();
1070
+ // keyframes. No-op in AR mode (the driver was never started).
1094
1071
  fpDriver.stop();
1095
1072
  try {
1096
1073
  // Compose the panorama output path: host-controlled if
@@ -1168,7 +1145,6 @@ export function Camera(props: CameraProps): React.JSX.Element {
1168
1145
  onFramesDropped,
1169
1146
  onError,
1170
1147
  recordingStartedAt,
1171
- jsDriver,
1172
1148
  fpDriver,
1173
1149
  // F10 Phase 2 review N1 — these four were missing pre-fix. The
1174
1150
  // callback reads `settings.debug` (to gate the stitchToast),
package/src/index.ts CHANGED
@@ -177,14 +177,9 @@ export {
177
177
  } from './stitching/incremental';
178
178
  export type { IncrementalState } from './stitching/incremental';
179
179
  export { useIncrementalStitcher } from './stitching/useIncrementalStitcher';
180
- export { useIncrementalJSDriver } from './stitching/useIncrementalJSDriver';
181
- export type {
182
- UseIncrementalJSDriverOptions,
183
- IncrementalJSDriverHandle,
184
- } from './stitching/useIncrementalJSDriver';
185
- // F8.3 — vision-camera Frame Processor variant of the non-AR
186
- // driver. Preferred over `useIncrementalJSDriver` in v0.5+; the
187
- // JS driver stays exported as a deprecated fallback until v0.6.
180
+ // vision-camera Frame Processor driver for non-AR captures. As
181
+ // of v0.6 the only non-AR driver exported (the legacy
182
+ // `useIncrementalJSDriver` was removed; was deprecated in v0.5).
188
183
  export { useFrameProcessorDriver } from './stitching/useFrameProcessorDriver';
189
184
  export type {
190
185
  UseFrameProcessorDriverOptions,
@@ -200,23 +200,22 @@ export interface IncrementalStartOptions {
200
200
  * bridge.start() requires `RNSARSession.start()` to
201
201
  * have already been called.
202
202
  *
203
- * - 'jsDriver' — engine skips AR-session registration; JS
204
- * feeds frames via `processFrameAtPath`. Use in iOS non-AR
205
- * captures (vision-camera + gyro). No AR session required.
206
- * LEGACY; deprecated in v0.5, removed in v0.6.
207
- *
208
203
  * - 'frameProcessor' (F8.3 iOS / F8.4 Android, v0.5+) — engine
209
204
  * flips on `frameProcessorIngestEnabled` so the vision-camera
210
205
  * Frame Processor plugin (`cv_flow_gate_process_frame`) can
211
206
  * feed pixel data directly into the engine's gate path. iOS
212
207
  * passes the `CVPixelBuffer` straight to `consumeFrame`;
213
- * Android extracts the Y plane to a ByteArray and encodes
214
- * accepted frames to JPEG inline (the platform-specific
215
- * engine-input divergence is tracked as F8.6). Use in non-AR
216
- * captures driven by `useFrameProcessorDriver`. Pairs with
217
- * `Camera`'s default driver mode.
208
+ * Android extracts the Y plane to a ByteArray and (since
209
+ * F8.6, v0.5.1) routes live-engine ingest through
210
+ * `addFramePixelData` without a JPEG round-trip. Use in
211
+ * non-AR captures driven by `useFrameProcessorDriver`. Pairs
212
+ * with `Camera`'s default driver mode.
213
+ *
214
+ * `'jsDriver'` was removed in v0.6 (deprecated in v0.5). Hosts
215
+ * that used it should switch to `useFrameProcessorDriver` (or
216
+ * just let `<Camera>` use its default).
218
217
  */
219
- frameSourceMode?: 'arSession' | 'jsDriver' | 'frameProcessor';
218
+ frameSourceMode?: 'arSession' | 'frameProcessor';
220
219
  /** Compose-resolution width in pixels (default 720 for portrait, 960 for landscape). */
221
220
  composeWidth?: number;
222
221
  /** Compose-resolution height in pixels (default 960 for portrait, 720 for landscape). */
@@ -1,14 +1,15 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  /**
3
3
  * useFrameProcessorDriver — vision-camera Frame Processor + gyro
4
- * driver for the incremental panorama engine. Replaces
5
- * `useIncrementalJSDriver` in non-AR captures.
4
+ * driver for the incremental panorama engine. Sole non-AR driver
5
+ * from v0.6 onward (replaced the deprecated `useIncrementalJSDriver`
6
+ * hook, which was removed in v0.6).
6
7
  *
7
- * Why this exists (vs the JS-driver predecessor)
8
+ * Why this exists (vs the pre-v0.6 JS-driver predecessor)
8
9
  *
9
- * The JS driver takes a JPEG snapshot every ~250 ms and feeds the
10
- * path to `IncrementalStitcher.processFrameAtPath`. That path
11
- * has three costs:
10
+ * The old JS driver took a JPEG snapshot every ~250 ms and fed the
11
+ * path to `IncrementalStitcher.processFrameAtPath` (both removed in
12
+ * v0.6). That path had three costs:
12
13
  *
13
14
  * 1. JPEG encode (`takeSnapshot` ≈ 30–80 ms on iPhone 16 Pro)
14
15
  * 2. Disk write of the JPEG
@@ -303,9 +304,9 @@ export function useFrameProcessorDriver(
303
304
  // y = horizontal pan (yaw, about world-Y)
304
305
  // x = vertical tilt (pitch, about world-X)
305
306
  // z = wrist-twist roll (about world-Z, normal to the screen)
306
- // Signs match the legacy `useIncrementalJSDriver` for x/y; z
307
- // follows the same right-hand-rule convention. If field
308
- // captures show inverted roll, flip the sign on `z * dt` below.
307
+ // Right-hand-rule convention throughout same signs the pre-v0.6
308
+ // `useIncrementalJSDriver` produced. If field captures show
309
+ // inverted roll, flip the sign on `z * dt` below.
309
310
  setUpdateIntervalForType(SensorTypes.gyroscope, gyroIntervalMs);
310
311
  gyroSubRef.current = gyroscope.subscribe({
311
312
  next: ({ x, y, z }) => {
@@ -382,8 +383,8 @@ export function useFrameProcessorDriver(
382
383
  imageWidth: w, imageHeight: h,
383
384
  timestampMs: 0,
384
385
  // 2 == RNSARTrackingState.tracking — we always claim "good
385
- // tracking" because there's no ARKit signal to differentiate
386
- // (matches legacy useIncrementalJSDriver semantics).
386
+ // tracking" because there's no ARKit signal to differentiate.
387
+ // (Same contract as the pre-v0.6 useIncrementalJSDriver.)
387
388
  trackingStateRaw: 2,
388
389
  });
389
390
  // Deps array intentionally minimal: only `plugin` actually
@@ -1,74 +0,0 @@
1
- /**
2
- * useIncrementalJSDriver — vision-camera + gyro frame driver for
3
- * the incremental panorama engine, used in non-AR captures on both
4
- * iOS and Android.
5
- *
6
- * History: previously called `useIncrementalAndroidDriver` because
7
- * it was Android-only. As of 2026-05-17 (Issue #2), the native
8
- * `processFrameAtPath` entry point exists on both platforms and the
9
- * hook drives non-AR on iOS too; renamed 2026-05-19 to reflect
10
- * that.
11
- *
12
- * Why this exists
13
- * In AR captures the engine consumes frames from the ARSession
14
- * stream natively (60 Hz pose + image delivery, zero JS
15
- * involvement once started). In NON-AR captures there is no AR
16
- * session — vision-camera owns the camera — so the engine needs
17
- * another frame source. This hook fills the gap:
18
- *
19
- * - vision-camera keeps the camera viewport
20
- * - `takeSnapshot()` runs at ~250 ms intervals during press-hold
21
- * - `react-native-sensors` gyroscope is integrated to estimate
22
- * cumulative yaw/pitch (drives the FoV-overlap gate)
23
- * - Each snapshot path + integrated pose is fed to
24
- * `IncrementalStitcher.processFrameAtPath()`
25
- *
26
- * Trade-off vs the AR path
27
- * Gyro integration drifts ~1–2° per minute. Acceptable for the
28
- * typical 5–15 s shelf pan; not great for ambitious 360° captures.
29
- * Snapshot rate is ~4 Hz (vs 60 Hz in AR mode). Pose drives
30
- * frame-selection only — the actual image alignment is feature-
31
- * matched + RANSAC-fit, so quality of the panorama itself isn't
32
- * bounded by gyro accuracy.
33
- *
34
- * Lifecycle
35
- * `start({ cameraRef })` enables the loop; `stop()` tears down.
36
- * Both should be called by the host's hold-start / hold-complete
37
- * handlers. Safe to call on either platform; the hook only
38
- * activates inside the start/stop block.
39
- */
40
- import type { Camera } from 'react-native-vision-camera';
41
- export interface UseIncrementalJSDriverOptions {
42
- /**
43
- * Snapshot interval in ms. Default 250 (≈ 4 Hz). Lower = more
44
- * candidate frames + more disk I/O. Don't go below 200 — vision-
45
- * camera's snapshot pipeline can't keep up reliably below that.
46
- */
47
- snapshotIntervalMs?: number;
48
- /**
49
- * Gyro sample rate in ms (~30 Hz default matches the existing
50
- * `PanoramaGuidance` cadence). Used for pose integration only —
51
- * not the snapshot rate.
52
- */
53
- gyroIntervalMs?: number;
54
- /**
55
- * Approximate horizontal FoV of the device camera. Drives the
56
- * overlap-percent calculation in the native engine. Default 65°
57
- * is a reasonable mid-tier smartphone average.
58
- */
59
- fovHorizDegrees?: number;
60
- /**
61
- * Approximate vertical FoV of the device camera. Default 50° for
62
- * typical 4:3 phone cameras. When ARCore-driven path is in use
63
- * the engine receives both FoVs straight from intrinsics; the
64
- * gyro driver is a fallback so the defaults are good enough.
65
- */
66
- fovVertDegrees?: number;
67
- }
68
- export interface IncrementalJSDriverHandle {
69
- start: (cameraRef: React.RefObject<Camera | null>) => void;
70
- stop: () => void;
71
- isRunning: boolean;
72
- }
73
- export declare function useIncrementalJSDriver(options?: UseIncrementalJSDriverOptions): IncrementalJSDriverHandle;
74
- //# sourceMappingURL=useIncrementalJSDriver.d.ts.map