gps-plus-slam-app-framework 1.10.0 → 1.11.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 +14 -14
- package/dist/{absolute-orientation-C_IxDR_j.d.ts → absolute-orientation-Dj1One3y.d.ts} +1 -1
- package/dist/{accuracy-circles-BE7tbvYV.d.ts → accuracy-circles-BHz7yVIL.d.ts} +1 -1
- package/dist/{app-selectors-CV7ggGoo.d.ts → app-selectors-DG0ZqaeI.d.ts} +1 -1
- package/dist/ar/ar-crash-isolation.d.ts +2 -0
- package/dist/ar/ar-crash-isolation.js +40 -0
- package/dist/ar/capability-checker.d.ts +1 -1
- package/dist/ar/capture-motion-gate.d.ts +2 -0
- package/dist/{capture-motion-gate-D1eyGC_o.js → ar/capture-motion-gate.js} +25 -2
- package/dist/ar/chromium-camera-access-workaround.d.ts +1 -1
- package/dist/ar/chromium-camera-access-workaround.js +1 -1
- package/dist/ar/depth-grid-lookup.d.ts +1 -1
- package/dist/ar/depth-occluder.d.ts +1 -1
- package/dist/ar/depth-occluder.js +1 -1
- package/dist/ar/depth-sampler.d.ts +2 -2
- package/dist/ar/depth-unprojection.d.ts +1 -1
- package/dist/ar/enable-gps-ar.d.ts +1 -1
- package/dist/ar/enable-gps-ar.js +2 -2
- package/dist/ar/frame-loop.d.ts +1 -1
- package/dist/ar/image-capture.d.ts +1 -1
- package/dist/ar/image-capture.js +1 -1
- package/dist/ar/image-quality.d.ts +2 -2
- package/dist/ar/image-quality.js +136 -4
- package/dist/ar/index.d.ts +28 -26
- package/dist/ar/index.js +15 -14
- package/dist/ar/occlusion-mesh-worker.d.ts +1 -1
- package/dist/ar/occupancy-grid.d.ts +1 -1
- package/dist/ar/occupancy-grid.js +1 -1
- package/dist/ar/occupancy-mesher.d.ts +1 -1
- package/dist/ar/occupancy-mesher.js +1 -1
- package/dist/ar/qr/index.d.ts +11 -0
- package/dist/ar/qr/index.js +11 -0
- package/dist/ar/{planar-pnp.d.ts → qr/planar-pnp.d.ts} +1 -1
- package/dist/ar/{planar-pnp.js → qr/planar-pnp.js} +1 -1
- package/dist/ar/qr/qr-debug-view.d.ts +2 -0
- package/dist/ar/{qr-debug-view.js → qr/qr-debug-view.js} +2 -2
- package/dist/ar/{qr-derived-pose.d.ts → qr/qr-derived-pose.d.ts} +1 -1
- package/dist/ar/{qr-derived-pose.js → qr/qr-derived-pose.js} +2 -2
- package/dist/ar/{qr-detection-controller.d.ts → qr/qr-detection-controller.d.ts} +1 -1
- package/dist/ar/qr/qr-detection-controller.js +2 -0
- package/dist/ar/{qr-frontend.d.ts → qr/qr-frontend.d.ts} +1 -1
- package/dist/ar/{qr-frontend.js → qr/qr-frontend.js} +1 -1
- package/dist/ar/{qr-pose.d.ts → qr/qr-pose.d.ts} +1 -1
- package/dist/ar/{qr-pose.js → qr/qr-pose.js} +1 -1
- package/dist/ar/qr/qr-size-depth-context.d.ts +3 -0
- package/dist/ar/{qr-size-depth-context.js → qr/qr-size-depth-context.js} +4 -4
- package/dist/ar/{qr-size-measurer.d.ts → qr/qr-size-measurer.d.ts} +1 -1
- package/dist/ar/qr/qr-size-measurer.js +2 -0
- package/dist/ar/replay-scene.d.ts +1 -1
- package/dist/ar/replay-scene.js +15 -13
- package/dist/ar/webxr-session.d.ts +4 -4
- package/dist/ar/webxr-session.js +2 -2
- package/dist/ar/xr-camera-texture.d.ts +1 -1
- package/dist/ar/xr-frame-loop.d.ts +1 -1
- package/dist/ar/xr-frame-loop.js +1 -1
- package/dist/ar-crash-isolation-DlXCGzMf.d.ts +52 -0
- package/dist/{ar-world-group-alignment-B6XiA1cT.d.ts → ar-world-group-alignment-BdS_h8Nf.d.ts} +2 -2
- package/dist/{capability-checker-DEo-ktWI.d.ts → capability-checker-BZ3_x1YL.d.ts} +1 -1
- package/dist/capture-motion-gate-CPwLekNf.d.ts +120 -0
- package/dist/{chromium-camera-access-workaround-DCd8SP2N.d.ts → chromium-camera-access-workaround-BHR4clTE.d.ts} +1 -1
- package/dist/{create-slam-app-store-CH31erpP.d.ts → create-slam-app-store-DFm5K9Ob.d.ts} +13 -4
- package/dist/{create-slam-app-store-DLv5ZwqU.js → create-slam-app-store-oK9bnqyI.js} +8 -6
- package/dist/{depth-grid-lookup-DY6zYTLx.d.ts → depth-grid-lookup-CCuzlqUo.d.ts} +1 -1
- package/dist/{depth-sampler-txG8evgQ.d.ts → depth-sampler-CS2jAFw4.d.ts} +2 -2
- package/dist/{depth-unprojection-JKkeqJrV.d.ts → depth-unprojection-ET3Gwedf.d.ts} +1 -1
- package/dist/{enable-gps-ar-BbNWyqp5.d.ts → enable-gps-ar-D_xEHzh5.d.ts} +10 -5
- package/dist/{file-system-utils-CfLTj5Ra.d.ts → file-system-utils-BHI0rXr9.d.ts} +1 -1
- package/dist/geo/h3-proximity.d.ts +1 -1
- package/dist/geo/h3-proximity.js +1 -1
- package/dist/geo/index.d.ts +1 -1
- package/dist/{geodesic-angle-HXBWiXiI.js → geodesic-angle-CZ_Ow90I.js} +2 -2
- package/dist/{gps-ar-pose-sampler-BOOV0jJk.d.ts → gps-ar-pose-sampler-BuuUuK-D.d.ts} +1 -1
- package/dist/{gps-event-coordinator-03rVh_us.d.ts → gps-event-coordinator-Cruoe5I-.d.ts} +4 -4
- package/dist/{gps-event-markers-BsC2Ynlh.d.ts → gps-event-markers-y2b2aVl6.d.ts} +35 -1
- package/dist/{h3-proximity-pFluGfwL.d.ts → h3-proximity-BaAulrnM.d.ts} +1 -1
- package/dist/{image-capture-Cr_rljeV.d.ts → image-capture-BevgKpoO.d.ts} +6 -6
- package/dist/{image-capture-BUqqsOi3.js → image-capture-C4DwxC10.js} +3 -3
- package/dist/{image-quality-BjBLoTec.d.ts → image-quality--HLuyJ2r.d.ts} +44 -2
- package/dist/{index-C2Bo0buN.d.ts → index-BWVwd9Zw.d.ts} +9 -71
- package/dist/{index-CuHaGY0F.d.ts → index-ClmnNJ6-.d.ts} +1 -1
- package/dist/index-Dxb6ATNK.d.ts +64 -0
- package/dist/index.d.ts +55 -55
- package/dist/index.js +23 -23
- package/dist/{leaflet-map-overlay-BRkUhZMD.js → leaflet-map-overlay-CTcTVmL1.js} +1 -1
- package/dist/{leaflet-map-overlay-QhF199BW.d.ts → leaflet-map-overlay-CksetpTt.d.ts} +1 -1
- package/dist/{map-data-D8sSxpOr.d.ts → map-data-D8cCqpOM.d.ts} +2 -2
- package/dist/{map-data-D3oE8AQP.js → map-data-DkhsYDGM.js} +1 -1
- package/dist/{map-overlay-draw-1E61FLKs.d.ts → map-overlay-draw-Cy-klqoA.d.ts} +1 -1
- package/dist/{median-Bla_W50f.js → median-DDBrZGP0.js} +2 -2
- package/dist/{occlusion-mesh-CZ4i_SW2.d.ts → occlusion-mesh-BWe2PrVi.d.ts} +22 -3
- package/dist/{occupancy-grid-f0I07UxI.d.ts → occupancy-grid-CYBdmMOo.d.ts} +2 -2
- package/dist/{persistence-middleware-CI4Cetnl.d.ts → persistence-middleware-Cun4aF5M.d.ts} +12 -2
- package/dist/{planar-pnp-CPLhg5MX.d.ts → planar-pnp-ByxwDEyM.d.ts} +2 -2
- package/dist/{ar-D-03Kso-.js → qr-CTp5xI83.js} +11 -25
- package/dist/{qr-debug-view-BmbWo06j.d.ts → qr-debug-view-CGlITU09.d.ts} +2 -2
- package/dist/{qr-derived-pose-DEYT85ul.d.ts → qr-derived-pose-DZPxZd9C.d.ts} +3 -3
- package/dist/{qr-detected-slice-CPEkGbxh.d.ts → qr-detected-slice-mfyxD2-M.d.ts} +9 -8
- package/dist/{qr-detection-controller-IcMRpTjV.d.ts → qr-detection-controller-C5NII-vs.d.ts} +4 -4
- package/dist/{qr-detection-controller-bRTJXC6G.js → qr-detection-controller-DXc1yHRf.js} +3 -3
- package/dist/{qr-frontend-61SKPSyU.d.ts → qr-frontend-QzKZSqB-.d.ts} +2 -2
- package/dist/{qr-pose-CCTF1PP0.d.ts → qr-pose-21fRDcFO.d.ts} +1 -1
- package/dist/{qr-pose-aggregation-H-O_Jjz9.js → qr-pose-aggregation-Cp0Mtg_j.js} +4 -4
- package/dist/{qr-pose-aggregation-BL6gfl0s.d.ts → qr-pose-aggregation-mABSN0AW.d.ts} +2 -2
- package/dist/{qr-size-depth-context-DJsYqbqY.d.ts → qr-size-depth-context-CMDv6T29.d.ts} +3 -3
- package/dist/{qr-size-measurer-Bl_i-umk.d.ts → qr-size-measurer-rVFf4AdM.d.ts} +5 -5
- package/dist/{qr-size-measurer-BVOIg-He.js → qr-size-measurer-zZB9S1va.js} +4 -4
- package/dist/{recording-replayer-DyIN13nG.d.ts → recording-replayer-qT2EM1Qs.d.ts} +1 -1
- package/dist/{recording-slice-DziOl7P5.d.ts → recording-slice-DXw5-UvO.d.ts} +10 -5
- package/dist/{replay-engine-DAymjsd1.d.ts → replay-engine-B1H_kLhK.d.ts} +1 -1
- package/dist/{replay-scene-CZdWgcpc.d.ts → replay-scene-BJeO36YT.d.ts} +12 -5
- package/dist/sensors/absolute-orientation.d.ts +1 -1
- package/dist/sensors/absolute-orientation.js +1 -1
- package/dist/sensors/gps.d.ts +1 -1
- package/dist/sensors/index.d.ts +3 -3
- package/dist/sensors/permission-checker.d.ts +1 -1
- package/dist/{session-disposers-BZS-hi8u.js → session-disposers-B7hUN90w.js} +1 -1
- package/dist/state/app-selectors.d.ts +1 -1
- package/dist/state/combined-root-state.d.ts +1 -1
- package/dist/state/create-slam-app-store.d.ts +1 -1
- package/dist/state/create-slam-app-store.js +1 -1
- package/dist/state/gps-ar-pose-sampler.d.ts +2 -2
- package/dist/state/gps-event-coordinator.d.ts +2 -2
- package/dist/state/gps-event-coordinator.js +1 -1
- package/dist/state/index.d.ts +17 -18
- package/dist/state/index.js +4 -5
- package/dist/state/persistence-middleware.d.ts +2 -2
- package/dist/state/persistence-middleware.js +24 -15
- package/dist/state/qr-detected-slice.d.ts +3 -3
- package/dist/state/qr-detected-slice.js +8 -8
- package/dist/state/recording-replayer.d.ts +2 -2
- package/dist/state/recording-replayer.js +1 -1
- package/dist/state/recording-slice.d.ts +1 -1
- package/dist/state/replay-engine.d.ts +1 -1
- package/dist/state/store-subscribers.d.ts +2 -2
- package/dist/state/store-subscribers.js +1 -1
- package/dist/state/subscribe-to-selector.d.ts +1 -1
- package/dist/state/tracking-quality.d.ts +1 -1
- package/dist/state/tracking-quality.js +2 -2
- package/dist/state/tracking-slice.d.ts +1 -1
- package/dist/{state-U45ioVyB.js → state-CDF5LvsO.js} +1 -2
- package/dist/storage/file-system-utils.d.ts +1 -1
- package/dist/storage/file-system-utils.js +1 -1
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/zip-coverage-embed.d.ts +1 -1
- package/dist/storage/zip-coverage-embed.js +1 -1
- package/dist/{store-subscribers-DtwakLrQ.d.ts → store-subscribers-CWHToX6N.d.ts} +2 -2
- package/dist/{subscribe-to-selector-Cgo9JTfS.d.ts → subscribe-to-selector-j-eOYybQ.d.ts} +1 -1
- package/dist/test-utils/browser-mocks.d.ts +1 -1
- package/dist/{tracking-slice-Bt2OEQhA.d.ts → tracking-slice-BAbcZK-Y.d.ts} +3 -2
- package/dist/types/ar-types.d.ts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/visualization/accuracy-circles.d.ts +1 -1
- package/dist/visualization/accuracy-circles.js +1 -1
- package/dist/visualization/alignment-lerper.d.ts +1 -1
- package/dist/visualization/ar-world-group-alignment.d.ts +1 -1
- package/dist/visualization/ar-world-group-alignment.js +2 -2
- package/dist/visualization/camera-follower.d.ts +1 -1
- package/dist/visualization/css3d-renderer-manager.d.ts +1 -1
- package/dist/visualization/gps-anchor.js +2 -2
- package/dist/visualization/gps-event-markers.d.ts +2 -2
- package/dist/visualization/gps-event-markers.js +27 -6
- package/dist/visualization/index.d.ts +13 -14
- package/dist/visualization/index.js +4 -5
- package/dist/visualization/leaflet-map-overlay.d.ts +1 -1
- package/dist/visualization/leaflet-map-overlay.js +1 -1
- package/dist/visualization/map-data.d.ts +1 -1
- package/dist/visualization/map-data.js +1 -1
- package/dist/visualization/map-overlay-draw.d.ts +1 -1
- package/dist/visualization/occluder-mesh-driver.d.ts +1 -1
- package/dist/visualization/occluder-mesh-driver.js +1 -1
- package/dist/visualization/occlusion-mesh.d.ts +2 -2
- package/dist/visualization/occlusion-mesh.js +28 -3
- package/dist/visualization/three-dispose.d.ts +1 -1
- package/dist/visualization/vis-colors.d.ts +1 -1
- package/dist/{webxr-session-CGFZ429B.d.ts → webxr-session-DefwObIu.d.ts} +144 -194
- package/dist/{webxr-session-DWKUsCN9.js → webxr-session-OyR3YbTq.js} +151 -281
- package/dist/{xr-frame-loop-25gM4B0K.d.ts → xr-frame-loop-BiZvgqP7.d.ts} +1 -1
- package/dist/{zip-coverage-embed-BrodRLq0.d.ts → zip-coverage-embed-CyoX7XL7.d.ts} +1 -1
- package/package.json +4 -2
- package/dist/ar/qr-debug-view.d.ts +0 -2
- package/dist/ar/qr-detection-controller.js +0 -2
- package/dist/ar/qr-size-depth-context.d.ts +0 -3
- package/dist/ar/qr-size-measurer.js +0 -2
- package/dist/capture-motion-gate-BmjiWUJv.d.ts +0 -24
- package/dist/map-overlay-0yJOcEVO.d.ts +0 -153
- package/dist/recording-options-Cai9D14V.d.ts +0 -700
- package/dist/state/recording-options.d.ts +0 -2
- package/dist/state/recording-options.js +0 -620
- package/dist/visualization/map-overlay.d.ts +0 -2
- package/dist/visualization/map-overlay.js +0 -241
- /package/dist/{alignment-lerper-B4COh_0p.d.ts → alignment-lerper-DAHicRON.d.ts} +0 -0
- /package/dist/{ar-types-CBafnxhE.d.ts → ar-types-D6PYS4bc.d.ts} +0 -0
- /package/dist/{camera-follower-B6zA3dy9.d.ts → camera-follower-CO_ibF2o.d.ts} +0 -0
- /package/dist/{css3d-renderer-manager-DbrSY7Mh.d.ts → css3d-renderer-manager-CJjHtCMT.d.ts} +0 -0
- /package/dist/{device-orientation-cache-BjEaEAmh.js → device-orientation-cache-j-kLP8he.js} +0 -0
- /package/dist/{frame-loop-7HigCj7m.d.ts → frame-loop-7GBMBu68.d.ts} +0 -0
- /package/dist/{gps-CX5b9g3s.d.ts → gps-CnhYrJCa.d.ts} +0 -0
- /package/dist/{occupancy-mesher-BqnRd10x.d.ts → occupancy-mesher-B4Bv4BTk.d.ts} +0 -0
- /package/dist/{permission-checker-D1C5zvo-.d.ts → permission-checker-B-VtjnBA.d.ts} +0 -0
- /package/dist/{three-dispose-C9mdpSRX.d.ts → three-dispose-C3mnKQR5.d.ts} +0 -0
- /package/dist/{vis-colors-DjStl_tD.d.ts → vis-colors-CoSpbZEO.d.ts} +0 -0
- /package/dist/{xr-camera-texture-C6Z4d7RR.d.ts → xr-camera-texture-q0eIDSRg.d.ts} +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DEFAULT_AR_CRASH_ISOLATION, validateArCrashIsolationOptions } from "./ar/ar-crash-isolation.js";
|
|
1
2
|
import { createLogger } from "./utils/logger.js";
|
|
2
3
|
import { CameraBlitCapture, computeAspectFitSize, computeCaptureSize } from "./ar/camera-blit-capture.js";
|
|
3
4
|
import { applyChromiumProjectionLayerWorkaround } from "./ar/chromium-camera-access-workaround.js";
|
|
@@ -5,12 +6,11 @@ import { DepthSampler, wrapXRDepthInfo } from "./ar/depth-sampler.js";
|
|
|
5
6
|
import { WEBXR_TO_NUE } from "./ar/webxr-nue-basis.js";
|
|
6
7
|
import { clearFrameUpdates, runFrameUpdates } from "./ar/frame-loop.js";
|
|
7
8
|
import { clearXrFrameUpdates, runXrFrameUpdates } from "./ar/xr-frame-loop.js";
|
|
8
|
-
import { n as ImageCaptureManager, t as DEFAULT_CAPTURE_CONFIG } from "./image-capture-
|
|
9
|
+
import { n as ImageCaptureManager, t as DEFAULT_CAPTURE_CONFIG } from "./image-capture-C4DwxC10.js";
|
|
9
10
|
import { clearLastRestartedPayload, originReset, poseLost, poseReceived, resetTracking, selectLastRestartedPayload, selectTrackingPhase } from "./state/tracking-slice.js";
|
|
10
11
|
import { acquireCameraTexture } from "./ar/xr-camera-texture.js";
|
|
11
|
-
import { n as runSessionDisposers } from "./session-disposers-
|
|
12
|
-
import { t as getLastDeviceOrientation } from "./device-orientation-cache-
|
|
13
|
-
import { DEFAULT_RECORDING_OPTIONS, validateArCrashIsolationOptions } from "./state/recording-options.js";
|
|
12
|
+
import { n as runSessionDisposers } from "./session-disposers-B7hUN90w.js";
|
|
13
|
+
import { t as getLastDeviceOrientation } from "./device-orientation-cache-j-kLP8he.js";
|
|
14
14
|
import { SCENE_NODE } from "./ar/scene-node-names.js";
|
|
15
15
|
import { createCss3dRendererManager } from "./visualization/css3d-renderer-manager.js";
|
|
16
16
|
import * as THREE from "three";
|
|
@@ -132,6 +132,7 @@ function createRgbLookup(pixels, width, height) {
|
|
|
132
132
|
* The camera's WORLD transform is the GPS-aligned world pose.
|
|
133
133
|
*/
|
|
134
134
|
const log = createLogger("WebXR");
|
|
135
|
+
/** Runtime guard for `XRView.camera` candidates (finite, positive dimensions). */
|
|
135
136
|
function isXRCameraLike(value) {
|
|
136
137
|
if (typeof value !== "object" || value === null) return false;
|
|
137
138
|
const camera = value;
|
|
@@ -181,6 +182,67 @@ function getXrCameraFromPose(pose) {
|
|
|
181
182
|
function shouldLogCameraAccessDiagnostic(pose, alreadyLogged, captureActive) {
|
|
182
183
|
return pose !== null && !alreadyLogged && captureActive;
|
|
183
184
|
}
|
|
185
|
+
/**
|
|
186
|
+
* Extract the reset transform from an XRReferenceSpaceEvent-like object.
|
|
187
|
+
*
|
|
188
|
+
* Distinguishes three cases per OdometryTrackingRestartedPayload semantics:
|
|
189
|
+
* - Transform property missing (older browsers) → returns `undefined`
|
|
190
|
+
* - Transform property present but null (runtime can't determine delta) → returns `null`
|
|
191
|
+
* - Transform property present with data → returns `ResetTransformData`
|
|
192
|
+
*
|
|
193
|
+
* This is a pure function extracted for testability.
|
|
194
|
+
*
|
|
195
|
+
* @param event - The event object, cast to a record with an optional transform property
|
|
196
|
+
* @returns ResetTransformData, null, or undefined
|
|
197
|
+
*/
|
|
198
|
+
function extractResetTransformData(event) {
|
|
199
|
+
if (!("transform" in event)) return;
|
|
200
|
+
const transform = event.transform;
|
|
201
|
+
if (!transform) return null;
|
|
202
|
+
const pos = transform.position;
|
|
203
|
+
const ori = transform.orientation;
|
|
204
|
+
return {
|
|
205
|
+
position: [
|
|
206
|
+
pos.x,
|
|
207
|
+
pos.y,
|
|
208
|
+
pos.z
|
|
209
|
+
],
|
|
210
|
+
orientation: [
|
|
211
|
+
ori.x,
|
|
212
|
+
ori.y,
|
|
213
|
+
ori.z,
|
|
214
|
+
ori.w
|
|
215
|
+
]
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Extract pose data from an XRViewerPose.
|
|
220
|
+
* Returns null if pose or views are unavailable.
|
|
221
|
+
*
|
|
222
|
+
* This is a pure function extracted for testability.
|
|
223
|
+
*
|
|
224
|
+
* @param pose - The XRViewerPose from frame.getViewerPose()
|
|
225
|
+
* @returns ARPose with position and orientation, or null
|
|
226
|
+
*/
|
|
227
|
+
function extractPoseFromViewer(pose) {
|
|
228
|
+
if (!pose) return null;
|
|
229
|
+
const view = pose.views[0];
|
|
230
|
+
if (!view) return null;
|
|
231
|
+
const { position, orientation } = view.transform;
|
|
232
|
+
return {
|
|
233
|
+
position: {
|
|
234
|
+
x: position.x,
|
|
235
|
+
y: position.y,
|
|
236
|
+
z: position.z
|
|
237
|
+
},
|
|
238
|
+
orientation: {
|
|
239
|
+
x: orientation.x,
|
|
240
|
+
y: orientation.y,
|
|
241
|
+
z: orientation.z,
|
|
242
|
+
w: orientation.w
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
}
|
|
184
246
|
let renderer = null;
|
|
185
247
|
let scene = null;
|
|
186
248
|
let camera = null;
|
|
@@ -207,7 +269,6 @@ function resetWebXRState() {
|
|
|
207
269
|
camera = null;
|
|
208
270
|
xrSession = null;
|
|
209
271
|
arWorldGroup = null;
|
|
210
|
-
arPoseNode = null;
|
|
211
272
|
latestArPose = null;
|
|
212
273
|
lastFrameTime = 0;
|
|
213
274
|
clearFrameUpdates();
|
|
@@ -218,6 +279,7 @@ function resetWebXRState() {
|
|
|
218
279
|
getScreenRotation = null;
|
|
219
280
|
onCaptureFailed = null;
|
|
220
281
|
onSuspiciousImage = null;
|
|
282
|
+
imageQualityAnalyzer = null;
|
|
221
283
|
if (trackingPhaseUnsubscribe) {
|
|
222
284
|
trackingPhaseUnsubscribe();
|
|
223
285
|
trackingPhaseUnsubscribe = null;
|
|
@@ -251,7 +313,7 @@ function resetWebXRState() {
|
|
|
251
313
|
getCameraTextureNullCount = 0;
|
|
252
314
|
latestCameraWidth = 0;
|
|
253
315
|
latestCameraHeight = 0;
|
|
254
|
-
currentArCrashIsolationOptions = { ...
|
|
316
|
+
currentArCrashIsolationOptions = { ...DEFAULT_AR_CRASH_ISOLATION };
|
|
255
317
|
cleanupBlitResources();
|
|
256
318
|
}
|
|
257
319
|
/**
|
|
@@ -261,12 +323,6 @@ function resetWebXRState() {
|
|
|
261
323
|
*/
|
|
262
324
|
let arWorldGroup = null;
|
|
263
325
|
/**
|
|
264
|
-
* The arpose Object3D — intermediate node between arWorldGroup and camera.
|
|
265
|
-
* During recording it stays at identity; during replay it receives recorded
|
|
266
|
-
* odomPosition/odomRotation from the store subscriber.
|
|
267
|
-
*/
|
|
268
|
-
let arPoseNode = null;
|
|
269
|
-
/**
|
|
270
326
|
* Stores the latest raw AR pose from WebXR (updated every frame).
|
|
271
327
|
* This is read by the GPS callback to create paired GPS+AR events.
|
|
272
328
|
*/
|
|
@@ -276,39 +332,39 @@ let latestArPose = null;
|
|
|
276
332
|
*/
|
|
277
333
|
let imageCaptureManager = null;
|
|
278
334
|
/**
|
|
279
|
-
* Callback for when an image is captured (
|
|
335
|
+
* Callback for when an image is captured (initAR `callbacks.imageCapture`)
|
|
280
336
|
*/
|
|
281
337
|
let onImageCaptured = null;
|
|
282
338
|
/**
|
|
283
|
-
* Callback for when image capture fails (
|
|
339
|
+
* Callback for when image capture fails (initAR `callbacks.imageCapture`)
|
|
284
340
|
*/
|
|
285
341
|
let onCaptureFailed = null;
|
|
286
342
|
/**
|
|
287
343
|
* Callback for when a captured image appears suspicious/black
|
|
288
|
-
* (
|
|
344
|
+
* (initAR `callbacks.imageCapture`)
|
|
289
345
|
*/
|
|
290
346
|
let onSuspiciousImage = null;
|
|
291
347
|
/**
|
|
292
|
-
* Screen rotation getter (
|
|
348
|
+
* Screen rotation getter (initAR `callbacks.imageCapture`)
|
|
293
349
|
*/
|
|
294
350
|
let getScreenRotation = null;
|
|
295
351
|
/**
|
|
296
|
-
* Off-thread image-quality analyzer (
|
|
352
|
+
* Off-thread image-quality analyzer (initAR `callbacks.imageCapture.qualityAnalyzer`).
|
|
297
353
|
* Device-specific (a Web Worker in the recorder), so it is INJECTED rather than
|
|
298
354
|
* built here. Forwarded to `ImageCaptureManager` as its `analyzeFrame` callback;
|
|
299
355
|
* the manager only invokes it when `config.qualityFilter.enabled`. `null` ⇒ the
|
|
300
|
-
* legacy save-immediately path.
|
|
356
|
+
* legacy save-immediately path. Per-session: cleared by resetWebXRState() like
|
|
357
|
+
* every other init-time callback (the host re-passes it each session).
|
|
301
358
|
*/
|
|
302
359
|
let imageQualityAnalyzer = null;
|
|
303
360
|
/**
|
|
304
|
-
* Redux store injected by the host (`
|
|
305
|
-
*
|
|
306
|
-
* `poseReceived`/`poseLost`, the XR reference-space
|
|
307
|
-
* dispatches `originReset`, and a
|
|
308
|
-
*
|
|
309
|
-
* `
|
|
310
|
-
*
|
|
311
|
-
* no-ops.
|
|
361
|
+
* Redux store injected by the host (initAR `callbacks.tracking.store`;
|
|
362
|
+
* swapped mid-session via {@link rebindTrackingStore}). When present,
|
|
363
|
+
* `onXRFrame` dispatches `poseReceived`/`poseLost`, the XR reference-space
|
|
364
|
+
* reset listener dispatches `originReset`, and a subscription translates
|
|
365
|
+
* phase transitions back into the host's `onTrackingLost` /
|
|
366
|
+
* `onTrackingRestarted` / `onTrackingRecovered` callbacks. When the store
|
|
367
|
+
* is absent the tracking pipeline simply no-ops.
|
|
312
368
|
*/
|
|
313
369
|
let trackingStore = null;
|
|
314
370
|
/**
|
|
@@ -318,22 +374,22 @@ let trackingStore = null;
|
|
|
318
374
|
*/
|
|
319
375
|
let trackingPhaseUnsubscribe = null;
|
|
320
376
|
/**
|
|
321
|
-
* Callback for when tracking restarts (
|
|
377
|
+
* Callback for when tracking restarts (initAR `callbacks.tracking.onRestarted`)
|
|
322
378
|
*/
|
|
323
379
|
let onTrackingRestarted = null;
|
|
324
380
|
/**
|
|
325
|
-
* Callback for when tracking is lost (
|
|
381
|
+
* Callback for when tracking is lost (initAR `callbacks.tracking.onLost`)
|
|
326
382
|
* Field Test Readiness Issue #3: Provide user feedback when tracking is lost
|
|
327
383
|
*/
|
|
328
384
|
let onTrackingLost = null;
|
|
329
385
|
/**
|
|
330
386
|
* Callback for when tracking recovers seamlessly without origin reset (Case 1).
|
|
331
|
-
*
|
|
387
|
+
* initAR `callbacks.tracking.onRecovered`.
|
|
332
388
|
*/
|
|
333
389
|
let onTrackingRecovered = null;
|
|
334
390
|
/**
|
|
335
391
|
* Host callback fired exactly once whenever the XRSession ends — on BOTH the
|
|
336
|
-
* app-initiated and the system-initiated path (
|
|
392
|
+
* app-initiated and the system-initiated path (initAR `callbacks.onSessionEnd`).
|
|
337
393
|
* Cleared by resetWebXRState() like every other module-level callback.
|
|
338
394
|
*/
|
|
339
395
|
let onSessionEnd = null;
|
|
@@ -350,7 +406,7 @@ let endRequestedByApp = false;
|
|
|
350
406
|
*/
|
|
351
407
|
let depthSampler = null;
|
|
352
408
|
/**
|
|
353
|
-
* Callback for when a depth sample is captured (
|
|
409
|
+
* Callback for when a depth sample is captured (initAR `callbacks.depth`)
|
|
354
410
|
*/
|
|
355
411
|
let onDepthCaptured = null;
|
|
356
412
|
/**
|
|
@@ -410,7 +466,7 @@ let cameraFrameBlit = null;
|
|
|
410
466
|
* so 1024 is the safe default. Raise per-consumer via
|
|
411
467
|
* `startCameraFrameCapture({ captureSize })`.
|
|
412
468
|
*
|
|
413
|
-
* @see GpsPlusSlamJs_Docs/docs/2026-06-17-qr-size-accuracy-and-thin-demo-plan.md (WS-C)
|
|
469
|
+
* @see GpsPlusSlamJs_Docs/docs/2026-06-17-1020-qr-size-accuracy-and-thin-demo-plan.md (WS-C)
|
|
414
470
|
*/
|
|
415
471
|
const DEFAULT_CAMERA_FRAME_CAPTURE_SIZE = 1024;
|
|
416
472
|
/**
|
|
@@ -434,7 +490,7 @@ let cameraFrameCaptureSize = DEFAULT_CAMERA_FRAME_CAPTURE_SIZE;
|
|
|
434
490
|
* SCOPE note in `camera-frame-source.ts`.
|
|
435
491
|
*/
|
|
436
492
|
let cameraFrameSource = null;
|
|
437
|
-
/** Callback for each throttled camera RGBA frame (
|
|
493
|
+
/** Callback for each throttled camera RGBA frame (initAR `callbacks.cameraFrame`). */
|
|
438
494
|
let onCameraFrame = null;
|
|
439
495
|
/**
|
|
440
496
|
* Latest WebXR camera texture, updated each frame when camera-access is enabled.
|
|
@@ -459,7 +515,7 @@ let cameraAccessLoggedOnce = false;
|
|
|
459
515
|
*/
|
|
460
516
|
let getCameraTextureNullCount = 0;
|
|
461
517
|
const GET_CAMERA_TEXTURE_LOG_THRESHOLD = 5;
|
|
462
|
-
let currentArCrashIsolationOptions = { ...
|
|
518
|
+
let currentArCrashIsolationOptions = { ...DEFAULT_AR_CRASH_ISOLATION };
|
|
463
519
|
/**
|
|
464
520
|
* Dispose blit capture resources and clear the cached camera texture.
|
|
465
521
|
* Shared by resetWebXRState() and stopImageCapture() to avoid duplication.
|
|
@@ -499,67 +555,6 @@ function acquireCameraFrameRgba() {
|
|
|
499
555
|
return cameraFrameBlit.captureToRgba(renderer, latestCameraTexture);
|
|
500
556
|
}
|
|
501
557
|
/**
|
|
502
|
-
* Extract the reset transform from an XRReferenceSpaceEvent-like object.
|
|
503
|
-
*
|
|
504
|
-
* Distinguishes three cases per OdometryTrackingRestartedPayload semantics:
|
|
505
|
-
* - Transform property missing (older browsers) → returns `undefined`
|
|
506
|
-
* - Transform property present but null (runtime can't determine delta) → returns `null`
|
|
507
|
-
* - Transform property present with data → returns `ResetTransformData`
|
|
508
|
-
*
|
|
509
|
-
* This is a pure function extracted for testability.
|
|
510
|
-
*
|
|
511
|
-
* @param event - The event object, cast to a record with an optional transform property
|
|
512
|
-
* @returns ResetTransformData, null, or undefined
|
|
513
|
-
*/
|
|
514
|
-
function extractResetTransformData(event) {
|
|
515
|
-
if (!("transform" in event)) return;
|
|
516
|
-
const transform = event.transform;
|
|
517
|
-
if (!transform) return null;
|
|
518
|
-
const pos = transform.position;
|
|
519
|
-
const ori = transform.orientation;
|
|
520
|
-
return {
|
|
521
|
-
position: [
|
|
522
|
-
pos.x,
|
|
523
|
-
pos.y,
|
|
524
|
-
pos.z
|
|
525
|
-
],
|
|
526
|
-
orientation: [
|
|
527
|
-
ori.x,
|
|
528
|
-
ori.y,
|
|
529
|
-
ori.z,
|
|
530
|
-
ori.w
|
|
531
|
-
]
|
|
532
|
-
};
|
|
533
|
-
}
|
|
534
|
-
/**
|
|
535
|
-
* Extract pose data from an XRViewerPose.
|
|
536
|
-
* Returns null if pose or views are unavailable.
|
|
537
|
-
*
|
|
538
|
-
* This is a pure function extracted for testability.
|
|
539
|
-
*
|
|
540
|
-
* @param pose - The XRViewerPose from frame.getViewerPose()
|
|
541
|
-
* @returns ARPose with position and orientation, or null
|
|
542
|
-
*/
|
|
543
|
-
function extractPoseFromViewer(pose) {
|
|
544
|
-
if (!pose) return null;
|
|
545
|
-
const view = pose.views[0];
|
|
546
|
-
if (!view) return null;
|
|
547
|
-
const { position, orientation } = view.transform;
|
|
548
|
-
return {
|
|
549
|
-
position: {
|
|
550
|
-
x: position.x,
|
|
551
|
-
y: position.y,
|
|
552
|
-
z: position.z
|
|
553
|
-
},
|
|
554
|
-
orientation: {
|
|
555
|
-
x: orientation.x,
|
|
556
|
-
y: orientation.y,
|
|
557
|
-
z: orientation.z,
|
|
558
|
-
w: orientation.w
|
|
559
|
-
}
|
|
560
|
-
};
|
|
561
|
-
}
|
|
562
|
-
/**
|
|
563
558
|
* Get the current raw AR pose from the latest XR frame.
|
|
564
559
|
* This is updated every frame and should be called when GPS arrives
|
|
565
560
|
* to get the AR pose at that moment.
|
|
@@ -576,6 +571,12 @@ function getCurrentArPose() {
|
|
|
576
571
|
* Build XR session init options.
|
|
577
572
|
* Extracted as a pure function for testability.
|
|
578
573
|
*
|
|
574
|
+
* Exported for unit testing only (surface-reduction step 3, B-5 precedent):
|
|
575
|
+
* production code reaches this exclusively through {@link initAR}; the export
|
|
576
|
+
* exists so `webxr-session.test.ts` can pin the full session-negotiation
|
|
577
|
+
* matrix (isolation flags × session features) without mocking a renderer and
|
|
578
|
+
* `navigator.xr` for every combination. Not re-exported by the ar/ barrel.
|
|
579
|
+
*
|
|
579
580
|
* @param rootElement - The DOM element for DOM overlay
|
|
580
581
|
* @param isolationOptions - Crash-isolation diagnostic flags (DOM overlay,
|
|
581
582
|
* depth-sensing, camera-access)
|
|
@@ -629,6 +630,10 @@ async function isWebXRSupported() {
|
|
|
629
630
|
* Note: these apply to WebGL content only. The CSS3D minimap is composited by
|
|
630
631
|
* the browser from the camera fov alone — near/far do not clip it (F1 in the
|
|
631
632
|
* same feedback doc).
|
|
633
|
+
*
|
|
634
|
+
* Module-private since surface-reduction step 3 (no consumer outside this
|
|
635
|
+
* file): the values are pinned observably on the constructed camera by the
|
|
636
|
+
* `createSceneHierarchy` frustum test in `webxr-session.test.ts`.
|
|
632
637
|
*/
|
|
633
638
|
const AR_CAMERA_FOV = 70;
|
|
634
639
|
const AR_CAMERA_NEAR = .01;
|
|
@@ -681,7 +686,7 @@ function createSceneHierarchy() {
|
|
|
681
686
|
const newArPose = new THREE.Object3D();
|
|
682
687
|
newArPose.name = "ar-pose";
|
|
683
688
|
newBasisChangeNode.add(newArPose);
|
|
684
|
-
const newCamera = new THREE.PerspectiveCamera(
|
|
689
|
+
const newCamera = new THREE.PerspectiveCamera(AR_CAMERA_FOV, window.innerWidth / window.innerHeight, AR_CAMERA_NEAR, AR_CAMERA_FAR);
|
|
685
690
|
newArPose.add(newCamera);
|
|
686
691
|
const ambientLight = new THREE.AmbientLight(16777215, .5);
|
|
687
692
|
newScene.add(ambientLight);
|
|
@@ -701,10 +706,27 @@ function createSceneHierarchy() {
|
|
|
701
706
|
* @param isolationOptions - Crash-isolation diagnostic flags.
|
|
702
707
|
* @param sessionFeatures - Opt-in standard WebXR features (e.g.
|
|
703
708
|
* `requestHitTest`) forwarded to the session negotiation.
|
|
709
|
+
* @param callbacks - Host callbacks for this session (see
|
|
710
|
+
* {@link ArSessionCallbacks}); unpacked once into module slots that
|
|
711
|
+
* `resetWebXRState()` clears at session end.
|
|
704
712
|
*/
|
|
705
|
-
async function initAR(container, isolationOptions = {}, sessionFeatures = {}) {
|
|
713
|
+
async function initAR(container, isolationOptions = {}, sessionFeatures = {}, callbacks = {}) {
|
|
706
714
|
if (!navigator.xr) throw new Error("WebXR not available");
|
|
707
715
|
if (renderer || xrSession) throw new Error("AR session already initialized — call endARSession() before initAR() again");
|
|
716
|
+
onImageCaptured = callbacks.imageCapture?.onCaptured ?? null;
|
|
717
|
+
getScreenRotation = callbacks.imageCapture?.getScreenRotation ?? null;
|
|
718
|
+
onCaptureFailed = callbacks.imageCapture?.onFailed ?? null;
|
|
719
|
+
onSuspiciousImage = callbacks.imageCapture?.onSuspicious ?? null;
|
|
720
|
+
imageQualityAnalyzer = callbacks.imageCapture?.qualityAnalyzer ?? null;
|
|
721
|
+
trackingStore = callbacks.tracking?.store ?? null;
|
|
722
|
+
onTrackingRestarted = callbacks.tracking?.onRestarted ?? null;
|
|
723
|
+
onTrackingLost = callbacks.tracking?.onLost ?? null;
|
|
724
|
+
onTrackingRecovered = callbacks.tracking?.onRecovered ?? null;
|
|
725
|
+
onDepthCaptured = callbacks.depth?.onCaptured ?? null;
|
|
726
|
+
onDepthUnavailable = callbacks.depth?.onUnavailable ?? null;
|
|
727
|
+
onCameraFrame = callbacks.cameraFrame?.onFrame ?? null;
|
|
728
|
+
onFrameCallback = callbacks.onFrame ?? null;
|
|
729
|
+
onSessionEnd = callbacks.onSessionEnd ?? null;
|
|
708
730
|
currentArCrashIsolationOptions = validateArCrashIsolationOptions(isolationOptions);
|
|
709
731
|
if (currentArCrashIsolationOptions.applyChromiumProjectionLayerWorkaround) applyChromiumProjectionLayerWorkaround();
|
|
710
732
|
renderer = new THREE.WebGLRenderer({
|
|
@@ -719,7 +741,6 @@ async function initAR(container, isolationOptions = {}, sessionFeatures = {}) {
|
|
|
719
741
|
const hierarchy = createSceneHierarchy();
|
|
720
742
|
scene = hierarchy.scene;
|
|
721
743
|
arWorldGroup = hierarchy.arWorldGroup;
|
|
722
|
-
arPoseNode = hierarchy.arpose;
|
|
723
744
|
camera = hierarchy.camera;
|
|
724
745
|
const sessionOptions = buildSessionOptions(container, currentArCrashIsolationOptions, sessionFeatures);
|
|
725
746
|
xrSession = await navigator.xr.requestSession("immersive-ar", sessionOptions);
|
|
@@ -727,8 +748,7 @@ async function initAR(container, isolationOptions = {}, sessionFeatures = {}) {
|
|
|
727
748
|
handleSessionEnded();
|
|
728
749
|
});
|
|
729
750
|
await renderer.xr.setSession(xrSession);
|
|
730
|
-
if (
|
|
731
|
-
if (onTrackingRestarted && trackingStore) {
|
|
751
|
+
if (trackingStore) {
|
|
732
752
|
const store = trackingStore;
|
|
733
753
|
store.dispatch(resetTracking());
|
|
734
754
|
trackingPhaseUnsubscribe = subscribeToTrackingPhase(store);
|
|
@@ -812,11 +832,11 @@ function subscribeToTrackingPhase(store) {
|
|
|
812
832
|
}
|
|
813
833
|
/**
|
|
814
834
|
* Dispatch the per-frame `poseReceived` / `poseLost` action into the
|
|
815
|
-
* tracking slice. No-op when no store is bound
|
|
816
|
-
*
|
|
835
|
+
* tracking slice. No-op when no store is bound (tracking wiring was not
|
|
836
|
+
* requested via initAR `callbacks.tracking`).
|
|
817
837
|
*/
|
|
818
838
|
function updateTrackingState(arPose) {
|
|
819
|
-
if (!trackingStore
|
|
839
|
+
if (!trackingStore) return;
|
|
820
840
|
if (arPose) trackingStore.dispatch(poseReceived({
|
|
821
841
|
pose: arPose,
|
|
822
842
|
sensorOrientation: snapshotDeviceOrientation()
|
|
@@ -920,48 +940,6 @@ function getCamera() {
|
|
|
920
940
|
return camera;
|
|
921
941
|
}
|
|
922
942
|
/**
|
|
923
|
-
* Set the scene externally (for replay mode).
|
|
924
|
-
* Allows non-WebXR code paths to register a scene so that modules
|
|
925
|
-
* calling getScene() receive it.
|
|
926
|
-
* @see docs/2026-02-19-replay-mode.md Risk R1
|
|
927
|
-
*/
|
|
928
|
-
function setScene(s) {
|
|
929
|
-
scene = s;
|
|
930
|
-
}
|
|
931
|
-
/**
|
|
932
|
-
* Set the AR world group externally (for replay mode).
|
|
933
|
-
* Allows non-WebXR code paths to register an arWorldGroup so that
|
|
934
|
-
* applyAlignmentMatrix() and visualizers work correctly.
|
|
935
|
-
* @see docs/2026-02-19-replay-mode.md Risk R1
|
|
936
|
-
*/
|
|
937
|
-
function setArWorldGroup(g) {
|
|
938
|
-
arWorldGroup = g;
|
|
939
|
-
}
|
|
940
|
-
/**
|
|
941
|
-
* Set the camera externally (for replay mode).
|
|
942
|
-
* Allows non-WebXR code paths to register a camera so that modules
|
|
943
|
-
* calling getCamera() receive it.
|
|
944
|
-
* @see docs/2026-02-19-replay-mode.md Risk R1
|
|
945
|
-
*/
|
|
946
|
-
function setCamera(c) {
|
|
947
|
-
camera = c;
|
|
948
|
-
}
|
|
949
|
-
/**
|
|
950
|
-
* Get the arpose Object3D (intermediate node between arWorldGroup and camera).
|
|
951
|
-
* Returns null before scene initialization.
|
|
952
|
-
*/
|
|
953
|
-
function getArPose() {
|
|
954
|
-
return arPoseNode;
|
|
955
|
-
}
|
|
956
|
-
/**
|
|
957
|
-
* Set the arpose Object3D externally (for replay mode).
|
|
958
|
-
* Allows non-WebXR code paths to register an arpose so that
|
|
959
|
-
* store subscribers can update it with recorded odom data.
|
|
960
|
-
*/
|
|
961
|
-
function setArPose(a) {
|
|
962
|
-
arPoseNode = a;
|
|
963
|
-
}
|
|
964
|
-
/**
|
|
965
943
|
* Apply an alignment matrix to the AR world group.
|
|
966
944
|
*
|
|
967
945
|
* The alignment matrix maps odometry positions in NUE space
|
|
@@ -1021,20 +999,6 @@ function nueQuaternionToWebXR$1(nue) {
|
|
|
1021
999
|
return nueQuaternionToWebXR(nue);
|
|
1022
1000
|
}
|
|
1023
1001
|
/**
|
|
1024
|
-
* Register a host callback fired exactly once whenever the XRSession ends —
|
|
1025
|
-
* app-initiated ({@link endARSession}) AND system-initiated (e.g. the Android
|
|
1026
|
-
* back gesture, which ends an immersive session directly and uncancelably).
|
|
1027
|
-
* `info.requestedByApp` discriminates the two. Fired AFTER the full teardown,
|
|
1028
|
-
* so the host can immediately start a fresh session from inside the callback.
|
|
1029
|
-
*
|
|
1030
|
-
* Cleared by resetWebXRState() (i.e. after every session end) like the other
|
|
1031
|
-
* module-level callbacks — re-register before/with each new session.
|
|
1032
|
-
* Pass `null` to unregister. F3, 2026-07-04 user feedback.
|
|
1033
|
-
*/
|
|
1034
|
-
function setSessionEndCallback(cb) {
|
|
1035
|
-
onSessionEnd = cb;
|
|
1036
|
-
}
|
|
1037
|
-
/**
|
|
1038
1002
|
* The ONE teardown for a session that has ended, shared by both trigger
|
|
1039
1003
|
* paths via the XRSession 'end' listener. Before F3 the system-initiated
|
|
1040
1004
|
* path (back gesture) only nulled `xrSession`/`latestArPose`, leaving the
|
|
@@ -1077,41 +1041,14 @@ async function endARSession() {
|
|
|
1077
1041
|
}
|
|
1078
1042
|
}
|
|
1079
1043
|
/**
|
|
1080
|
-
* Set up image capture callbacks.
|
|
1081
|
-
* Call this before starting image capture to wire up the callback handlers.
|
|
1082
|
-
*
|
|
1083
|
-
* @param onCaptured - Called when an image is successfully captured
|
|
1084
|
-
* @param screenRotationGetter - Returns current device screen rotation (0, 90, 180, 270)
|
|
1085
|
-
* @param onFailed - Optional callback for when image capture fails (e.g., low memory)
|
|
1086
|
-
* @param onSuspicious - Optional callback for when a captured image appears black/empty
|
|
1087
|
-
*/
|
|
1088
|
-
function setImageCaptureCallback(onCaptured, screenRotationGetter, onFailed, onSuspicious) {
|
|
1089
|
-
onImageCaptured = onCaptured;
|
|
1090
|
-
getScreenRotation = screenRotationGetter;
|
|
1091
|
-
onCaptureFailed = onFailed ?? null;
|
|
1092
|
-
onSuspiciousImage = onSuspicious ?? null;
|
|
1093
|
-
}
|
|
1094
|
-
/**
|
|
1095
|
-
* Inject (or clear) the off-thread image-quality analyzer used by the blur/
|
|
1096
|
-
* blackness drop+retry gate. Pass the recorder's Web Worker-backed analyzer to
|
|
1097
|
-
* enable the gate, or `null` to clear it (legacy save-immediately path). Must be
|
|
1098
|
-
* set BEFORE {@link startImageCapture} for the active recording — the manager
|
|
1099
|
-
* reads it once when constructed. The analyzer only runs when the capture
|
|
1100
|
-
* config's `qualityFilter.enabled` is true, so injecting it is harmless when the
|
|
1101
|
-
* gate is off. Ownership/disposal of the worker is the caller's responsibility.
|
|
1102
|
-
*/
|
|
1103
|
-
function setImageQualityAnalyzer(analyzer) {
|
|
1104
|
-
imageQualityAnalyzer = analyzer;
|
|
1105
|
-
}
|
|
1106
|
-
/**
|
|
1107
1044
|
* Start capturing images during recording.
|
|
1108
|
-
*
|
|
1045
|
+
* Requires the `imageCapture` callbacks group to have been passed to initAR.
|
|
1109
1046
|
*
|
|
1110
1047
|
* @param config - Optional capture configuration. Accepts the whole user
|
|
1111
1048
|
* image-options section (`intervalMs`, `quality`, `resolutionDivisor`; any
|
|
1112
1049
|
* extra keys such as `enabled` are ignored). Passing the section as one
|
|
1113
1050
|
* object means a newly-added option flows through without editing this seam
|
|
1114
|
-
* — see `2026-06-12-payload-rebuild-field-drop-audit.md` (F3).
|
|
1051
|
+
* — see `2026-06-12-1130-payload-rebuild-field-drop-audit.md` (F3).
|
|
1115
1052
|
*/
|
|
1116
1053
|
function startImageCapture(config) {
|
|
1117
1054
|
if (!renderer) {
|
|
@@ -1188,16 +1125,27 @@ function getImageCaptureFrameCount() {
|
|
|
1188
1125
|
return imageCaptureManager?.getFrameCount() ?? 0;
|
|
1189
1126
|
}
|
|
1190
1127
|
/**
|
|
1191
|
-
*
|
|
1128
|
+
* Re-point the tracking pipeline at a NEW store mid-session.
|
|
1129
|
+
*
|
|
1130
|
+
* This is the ONE mutation that deliberately survived the fold of the
|
|
1131
|
+
* pre-init setters into initAR's `callbacks` (surface-reduction step 1):
|
|
1132
|
+
* it is a genuine RUNTIME need, not init-time wiring — the recorder swaps
|
|
1133
|
+
* its Redux store for every recording started inside a single AR session,
|
|
1134
|
+
* and without re-pointing, every per-frame `poseReceived` dispatch would
|
|
1135
|
+
* keep flowing into the orphaned previous store, pinning the new store's
|
|
1136
|
+
* `tracking.phase` at 'initializing' (Finding #1, 2026-05-23 user
|
|
1137
|
+
* feedback). Everything else about a session's callbacks stays fixed from
|
|
1138
|
+
* `initAR` until `resetWebXRState()`.
|
|
1192
1139
|
*
|
|
1193
|
-
*
|
|
1194
|
-
*
|
|
1195
|
-
*
|
|
1140
|
+
* Matches the old `setTrackingStore` semantics exactly: an active phase
|
|
1141
|
+
* subscription to the previous store is torn down before swapping (the
|
|
1142
|
+
* phase subscription itself is only (re)established inside `initAR`).
|
|
1143
|
+
* No-op pipeline when tracking was not wired at init (the host callbacks
|
|
1144
|
+
* stay whatever `initAR` set).
|
|
1196
1145
|
*
|
|
1197
1146
|
* @param store — any store satisfying {@link TrackingSubscribableStore}.
|
|
1198
|
-
* `null` clears the binding (useful for teardown in tests).
|
|
1199
1147
|
*/
|
|
1200
|
-
function
|
|
1148
|
+
function rebindTrackingStore(store) {
|
|
1201
1149
|
if (trackingPhaseUnsubscribe) {
|
|
1202
1150
|
trackingPhaseUnsubscribe();
|
|
1203
1151
|
trackingPhaseUnsubscribe = null;
|
|
@@ -1205,47 +1153,9 @@ function setTrackingStore(store) {
|
|
|
1205
1153
|
trackingStore = store;
|
|
1206
1154
|
}
|
|
1207
1155
|
/**
|
|
1208
|
-
* Set up tracking state callbacks.
|
|
1209
|
-
* Call this BEFORE initAR() to enable tracking restart detection.
|
|
1210
|
-
*
|
|
1211
|
-
* @param onRestarted - Called when tracking restarts after being lost
|
|
1212
|
-
*/
|
|
1213
|
-
function setTrackingCallbacks(onRestarted) {
|
|
1214
|
-
onTrackingRestarted = onRestarted;
|
|
1215
|
-
}
|
|
1216
|
-
/**
|
|
1217
|
-
* Set a callback for when AR tracking is lost.
|
|
1218
|
-
* Call this BEFORE initAR() to enable tracking loss notifications.
|
|
1219
|
-
* Field Test Readiness Issue #3: Provide user feedback when tracking is lost.
|
|
1220
|
-
*
|
|
1221
|
-
* @param callback - Called when tracking is lost (pose becomes null)
|
|
1222
|
-
*/
|
|
1223
|
-
function setTrackingLostCallback(callback) {
|
|
1224
|
-
onTrackingLost = callback;
|
|
1225
|
-
}
|
|
1226
|
-
/**
|
|
1227
|
-
* Set a callback for when AR tracking recovers seamlessly (Case 1: same coordinate frame).
|
|
1228
|
-
* Call this BEFORE initAR() to enable seamless recovery notifications.
|
|
1229
|
-
*
|
|
1230
|
-
* @param callback - Called when tracking recovers without origin reset
|
|
1231
|
-
*/
|
|
1232
|
-
function setTrackingRecoveredCallback(callback) {
|
|
1233
|
-
onTrackingRecovered = callback;
|
|
1234
|
-
}
|
|
1235
|
-
/**
|
|
1236
|
-
* Set up depth capture callback.
|
|
1237
|
-
* Call this BEFORE initAR() to enable depth sampling.
|
|
1238
|
-
*
|
|
1239
|
-
* @param onCaptured - Called when a depth sample is captured
|
|
1240
|
-
* @param onUnavailable - Called once if depth is unavailable after threshold
|
|
1241
|
-
*/
|
|
1242
|
-
function setDepthCaptureCallback(onCaptured, onUnavailable) {
|
|
1243
|
-
onDepthCaptured = onCaptured;
|
|
1244
|
-
onDepthUnavailable = onUnavailable ?? null;
|
|
1245
|
-
}
|
|
1246
|
-
/**
|
|
1247
1156
|
* Start depth sampling during recording.
|
|
1248
|
-
*
|
|
1157
|
+
* Requires the `depth` callbacks group to have been passed to initAR
|
|
1158
|
+
* (the sampler is created there).
|
|
1249
1159
|
*
|
|
1250
1160
|
* @param config - optional sampler overrides (typically the user's
|
|
1251
1161
|
* `depth.intervalMs`/`depth.gridSize` recording options); applied via
|
|
@@ -1279,24 +1189,12 @@ function getDepthSampleCount() {
|
|
|
1279
1189
|
return depthSampler?.getSampleCount() ?? 0;
|
|
1280
1190
|
}
|
|
1281
1191
|
/**
|
|
1282
|
-
*
|
|
1283
|
-
*
|
|
1284
|
-
*
|
|
1285
|
-
*
|
|
1286
|
-
*
|
|
1287
|
-
*
|
|
1288
|
-
* captured at the throttled detection cadence — feed it straight to a
|
|
1289
|
-
* `BarcodeDetector` / OpenCV front-end. Mirrors `setDepthCaptureCallback`.
|
|
1290
|
-
*
|
|
1291
|
-
* @param onFrame - Called with each throttled camera frame, or `null` to clear.
|
|
1292
|
-
*/
|
|
1293
|
-
function setCameraFrameCallback(onFrame) {
|
|
1294
|
-
onCameraFrame = onFrame;
|
|
1295
|
-
}
|
|
1296
|
-
/**
|
|
1297
|
-
* Start camera frame capture during an AR session. Must call
|
|
1298
|
-
* setCameraFrameCallback before initAR (the source is created there). No-op if
|
|
1299
|
-
* the source was not initialized (callback not set before initAR).
|
|
1192
|
+
* Start camera frame capture during an AR session. Requires the
|
|
1193
|
+
* `cameraFrame` callbacks group to have been passed to initAR (the source is
|
|
1194
|
+
* created there); the callback receives **top-left-origin** RGBA images (no
|
|
1195
|
+
* JPEG round-trip) at the throttled detection cadence — feed them straight to
|
|
1196
|
+
* a `BarcodeDetector` / OpenCV front-end (B2). No-op if the source was not
|
|
1197
|
+
* initialized (group not passed to initAR).
|
|
1300
1198
|
*
|
|
1301
1199
|
* The source is the single cadence owner: drive your detection scheduler from
|
|
1302
1200
|
* the delivered frames with its own `minIntervalMs: 0` (Option A).
|
|
@@ -1330,33 +1228,5 @@ function stopCameraFrameCapture() {
|
|
|
1330
1228
|
function getCameraFrameCount() {
|
|
1331
1229
|
return cameraFrameSource?.getFrameCount() ?? 0;
|
|
1332
1230
|
}
|
|
1333
|
-
/**
|
|
1334
|
-
* The current longer-edge resolution (px) of the camera-frame blit — the
|
|
1335
|
-
* {@link DEFAULT_CAMERA_FRAME_CAPTURE_SIZE} default unless overridden via
|
|
1336
|
-
* `startCameraFrameCapture({ captureSize })`. Exposed for diagnostics and to
|
|
1337
|
-
* let tests assert the on-device-tuned default without reaching into module
|
|
1338
|
-
* state.
|
|
1339
|
-
*/
|
|
1340
|
-
function getCameraFrameCaptureSize() {
|
|
1341
|
-
return cameraFrameCaptureSize;
|
|
1342
|
-
}
|
|
1343
|
-
/**
|
|
1344
|
-
* Set a per-frame callback for custom updates.
|
|
1345
|
-
* The callback is invoked every XR frame after pose updates but before render.
|
|
1346
|
-
* Useful for updating elements that need to follow the camera smoothly
|
|
1347
|
-
* (e.g., map overlay position).
|
|
1348
|
-
*
|
|
1349
|
-
* @param callback - Function to call each frame, or null to clear
|
|
1350
|
-
*/
|
|
1351
|
-
function setFrameCallback(callback) {
|
|
1352
|
-
onFrameCallback = callback;
|
|
1353
|
-
}
|
|
1354
|
-
/**
|
|
1355
|
-
* Get the CSS3D renderer manager for live AR mode.
|
|
1356
|
-
* Returns null if no AR session is active or CSS3D was not created.
|
|
1357
|
-
*/
|
|
1358
|
-
function getLiveCss3dManager() {
|
|
1359
|
-
return css3dManager;
|
|
1360
|
-
}
|
|
1361
1231
|
//#endregion
|
|
1362
|
-
export {
|
|
1232
|
+
export { stopImageCapture as A, resetWebXRState as C, startImageCapture as D, startDepthCapture as E, stopCameraFrameCapture as O, rebindTrackingStore as S, startCameraFrameCapture as T, initAR as _, endARSession as a, nuePositionToWebXR as b, getArWorldGroup as c, getCurrentArPose as d, getDepthInfoFromFrame as f, getXrCameraFromPose as g, getScene as h, createSceneHierarchy as i, CameraFrameSource as j, stopDepthCapture as k, getCamera as l, getImageCaptureFrameCount as m, applyAlignmentMatrix as n, extractPoseFromViewer as o, getDepthSampleCount as p, buildSessionOptions as r, extractResetTransformData as s, DEFAULT_CAMERA_FRAME_CAPTURE_SIZE as t, getCameraFrameCount as u, isWebXRSupported as v, shouldLogCameraAccessDiagnostic as w, nueQuaternionToWebXR$1 as x, isXRCameraLike as y };
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* makes correct use the easy path and stashing the awkward one. Do NOT retain
|
|
18
18
|
* `ctx` or its fields beyond the callback's synchronous execution.
|
|
19
19
|
*
|
|
20
|
-
* See `2026-06-03-threejs-arbutton-minimal-ar-example-user-feedback.md`
|
|
20
|
+
* See `2026-06-03-0553-threejs-arbutton-minimal-ar-example-user-feedback.md`
|
|
21
21
|
* §6.2/§6.3 (option H-A2) for the design rationale.
|
|
22
22
|
*/
|
|
23
23
|
/**
|