gps-plus-slam-app-framework 1.3.0 → 1.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.
Files changed (225) hide show
  1. package/dist/{app-selectors-B8VQoMDY.d.ts → app-selectors-CrOucL00.d.ts} +1 -1
  2. package/dist/ar/bresenham3d.d.ts +1 -1
  3. package/dist/ar/camera-blit-capture.d.ts +2 -2
  4. package/dist/ar/camera-blit-capture.js +74 -9
  5. package/dist/ar/capability-checker.d.ts +1 -1
  6. package/dist/ar/capture-failure-tracker.d.ts +1 -1
  7. package/dist/ar/chromium-camera-access-workaround.d.ts +1 -1
  8. package/dist/ar/depth-grid-lookup.d.ts +2 -0
  9. package/dist/ar/depth-grid-lookup.js +43 -0
  10. package/dist/ar/depth-sampler.d.ts +2 -2
  11. package/dist/ar/depth-sampler.js +2 -4
  12. package/dist/ar/depth-unprojection.d.ts +1 -1
  13. package/dist/ar/enable-gps-ar.d.ts +1 -1
  14. package/dist/ar/enable-gps-ar.js +26 -1
  15. package/dist/ar/frame-loop.d.ts +1 -1
  16. package/dist/ar/image-capture.d.ts +1 -1
  17. package/dist/ar/index.d.ts +30 -19
  18. package/dist/ar/index.js +15 -4
  19. package/dist/ar/occupancy-grid.d.ts +1 -1
  20. package/dist/ar/occupancy-grid.js +29 -2
  21. package/dist/ar/planar-pnp.d.ts +2 -0
  22. package/dist/ar/planar-pnp.js +425 -0
  23. package/dist/ar/qr-debug-view.d.ts +2 -0
  24. package/dist/ar/qr-debug-view.js +89 -0
  25. package/dist/ar/qr-derived-pose.d.ts +2 -0
  26. package/dist/ar/qr-derived-pose.js +114 -0
  27. package/dist/ar/qr-detection-controller.d.ts +2 -0
  28. package/dist/ar/qr-detection-controller.js +2 -0
  29. package/dist/ar/qr-frontend.d.ts +2 -0
  30. package/dist/ar/qr-frontend.js +60 -0
  31. package/dist/ar/qr-pose.d.ts +2 -0
  32. package/dist/ar/qr-pose.js +267 -0
  33. package/dist/ar/qr-size-depth-context.d.ts +3 -0
  34. package/dist/ar/qr-size-depth-context.js +42 -0
  35. package/dist/ar/qr-size-measurer.d.ts +2 -0
  36. package/dist/ar/qr-size-measurer.js +2 -0
  37. package/dist/ar/replay-scene.d.ts +1 -1
  38. package/dist/ar/replay-scene.js +1 -1
  39. package/dist/ar/scene-node-names.d.ts +1 -1
  40. package/dist/ar/webxr-nue-basis.d.ts +1 -1
  41. package/dist/ar/webxr-session.d.ts +4 -4
  42. package/dist/ar/webxr-session.js +2 -2
  43. package/dist/ar/xr-camera-texture.d.ts +1 -1
  44. package/dist/ar/xr-error-handler.d.ts +1 -1
  45. package/dist/ar/xr-frame-loop.d.ts +1 -1
  46. package/dist/ar-Dc72Ksiu.js +382 -0
  47. package/dist/{ar-world-group-alignment-C9lwwIyI.d.ts → ar-world-group-alignment-DDLkgNf_.d.ts} +1 -1
  48. package/dist/{camera-blit-capture-CnxUDbKx.d.ts → camera-blit-capture-CqWe1G7s.d.ts} +57 -4
  49. package/dist/concurrency-DqAlKX4j.d.ts +50 -0
  50. package/dist/core/index.d.ts +1 -1
  51. package/dist/{create-slam-app-store-BljusOua.d.ts → create-slam-app-store-Ce2FMKCp.d.ts} +5 -5
  52. package/dist/depth-grid-lookup-vMDrGTk_.d.ts +21 -0
  53. package/dist/{depth-sampler-Bhanfwla.d.ts → depth-sampler-DwfPYzS7.d.ts} +1 -1
  54. package/dist/{depth-unprojection-Y6i_mJuT.d.ts → depth-unprojection-CK3b9htH.d.ts} +1 -1
  55. package/dist/{enable-gps-ar-BfUJOgpW.d.ts → enable-gps-ar-CjZ1nEdu.d.ts} +4 -4
  56. package/dist/{frame-conversions-BfsafGWR.d.ts → frame-conversions-D_Af8Dt3.d.ts} +1 -1
  57. package/dist/{fused-path-DJoVu98b.d.ts → fused-path-C0FHe67t.d.ts} +1 -1
  58. package/dist/geo/h3-proximity.d.ts +2 -2
  59. package/dist/geo/h3-proximity.js +61 -2
  60. package/dist/geo/index.d.ts +2 -2
  61. package/dist/geo/index.js +2 -2
  62. package/dist/{gps-anchor-dYeCvvp5.d.ts → gps-anchor-C6I9NDHA.d.ts} +1 -1
  63. package/dist/{gps-ar-pose-sampler-DVb96iOy.d.ts → gps-ar-pose-sampler-DaHg2aPZ.d.ts} +1 -1
  64. package/dist/{gps-event-coordinator-CWIDOk4U.d.ts → gps-event-coordinator-C7hwHyLA.d.ts} +3 -3
  65. package/dist/{gps-event-markers-Dc9FT-q1.d.ts → gps-event-markers-Dd0G2bD0.d.ts} +18 -0
  66. package/dist/{h3-proximity-I1msGPgE.d.ts → h3-proximity-B57C6rYL.d.ts} +39 -1
  67. package/dist/{image-capture-qAZ5Fh5X.d.ts → image-capture-C2Feywet.d.ts} +1 -1
  68. package/dist/index-BvLo2poy.d.ts +399 -0
  69. package/dist/{index-BYYUdf9v.d.ts → index-m_LneUSi.d.ts} +1 -1
  70. package/dist/index.d.ts +77 -67
  71. package/dist/index.js +18 -9
  72. package/dist/{leaflet-map-overlay-6CJC-E1l.d.ts → leaflet-map-overlay-bnb2U1NQ.d.ts} +1 -1
  73. package/dist/{map-data-CkloBxIl.d.ts → map-data-DdjPiSav.d.ts} +1 -1
  74. package/dist/{map-overlay-draw-krOKwDAq.d.ts → map-overlay-draw-CPVdAsFq.d.ts} +1 -1
  75. package/dist/{null-storage-backend-uKQE8tl7.d.ts → null-storage-backend-CuSdYFsM.d.ts} +2 -2
  76. package/dist/{occupancy-grid-BRNRaPyT.d.ts → occupancy-grid-Bvi2Gw1U.d.ts} +12 -2
  77. package/dist/{opfs-storage-D5zAn_lx.d.ts → opfs-storage-DMtlt57S.d.ts} +23 -4
  78. package/dist/{opfs-storage-backend-6aYMUZlJ.d.ts → opfs-storage-backend-CeQAb0SD.d.ts} +3 -3
  79. package/dist/{persistence-middleware-B9ei4Nhx.d.ts → persistence-middleware-5eearhSV.d.ts} +1 -1
  80. package/dist/planar-pnp-cjthe7Be.d.ts +67 -0
  81. package/dist/qr-debug-view-B8gTzjMm.d.ts +29 -0
  82. package/dist/qr-derived-pose-DinKE600.d.ts +122 -0
  83. package/dist/qr-detected-slice-Cpv-dg82.d.ts +166 -0
  84. package/dist/qr-detection-controller-B-tLVd-S.js +119 -0
  85. package/dist/qr-detection-controller-Cd2Ih4cC.d.ts +48 -0
  86. package/dist/qr-frontend-DufZp2xS.d.ts +58 -0
  87. package/dist/qr-pose-Bt2reSw7.d.ts +138 -0
  88. package/dist/qr-pose-aggregation-CFlmLm6w.d.ts +90 -0
  89. package/dist/qr-pose-aggregation-DXR9STHs.js +200 -0
  90. package/dist/qr-size-depth-context-onu36E9s.d.ts +13 -0
  91. package/dist/qr-size-measurer-D7739ZpB.d.ts +165 -0
  92. package/dist/qr-size-measurer-DLb33geH.js +596 -0
  93. package/dist/recording-options-D93kksJU.d.ts +369 -0
  94. package/dist/{recording-replayer-r0DZ9ALp.d.ts → recording-replayer-CUEK82tM.d.ts} +2 -2
  95. package/dist/recording-slice-B-uCgGoh.d.ts +55 -0
  96. package/dist/{replay-engine-XpDa0dy1.d.ts → replay-engine-BSVd7Zzb.d.ts} +7 -4
  97. package/dist/{replay-scene-Bw58VL6p.d.ts → replay-scene-CPt56pps.d.ts} +3 -3
  98. package/dist/sensors/gps-error-handler.d.ts +1 -1
  99. package/dist/sensors/gps.d.ts +1 -1
  100. package/dist/sensors/index.d.ts +3 -3
  101. package/dist/sensors/permission-checker.d.ts +1 -1
  102. package/dist/sensors/permission-checker.js +1 -1
  103. package/dist/state/app-selectors.d.ts +1 -1
  104. package/dist/state/combined-root-state.d.ts +1 -1
  105. package/dist/state/create-slam-app-store.d.ts +1 -1
  106. package/dist/state/gps-ar-pose-sampler.d.ts +3 -3
  107. package/dist/state/gps-event-coordinator.d.ts +1 -1
  108. package/dist/state/index.d.ts +20 -17
  109. package/dist/state/index.js +3 -2
  110. package/dist/state/persistence-middleware.d.ts +1 -1
  111. package/dist/state/qr-detected-slice.d.ts +4 -0
  112. package/dist/state/qr-detected-slice.js +311 -0
  113. package/dist/state/recording-options.d.ts +2 -2
  114. package/dist/state/recording-options.js +128 -4
  115. package/dist/state/recording-replayer.d.ts +2 -2
  116. package/dist/state/recording-slice.d.ts +1 -1
  117. package/dist/state/recording-slice.js +5 -1
  118. package/dist/state/replay-engine.d.ts +1 -1
  119. package/dist/state/replay-engine.js +7 -3
  120. package/dist/state/store-subscribers.d.ts +2 -2
  121. package/dist/state/subscribe-to-selector.d.ts +1 -1
  122. package/dist/state/tracking-quality.d.ts +1 -1
  123. package/dist/state/tracking-slice.d.ts +1 -1
  124. package/dist/{state-BkIfpiyA.js → state-IEw0ZsBu.js} +1 -0
  125. package/dist/storage/file-system-utils.d.ts +1 -1
  126. package/dist/storage/index.d.ts +9 -9
  127. package/dist/storage/index.js +4 -4
  128. package/dist/storage/null-storage-backend.d.ts +1 -1
  129. package/dist/storage/opfs-storage-backend.d.ts +1 -1
  130. package/dist/storage/opfs-storage-backend.js +3 -3
  131. package/dist/storage/opfs-storage.d.ts +1 -1
  132. package/dist/storage/opfs-storage.js +5 -4
  133. package/dist/storage/storage-backend.d.ts +1 -1
  134. package/dist/storage/zip-coverage-embed.d.ts +2 -0
  135. package/dist/storage/zip-coverage-embed.js +88 -0
  136. package/dist/storage/zip-export.d.ts +2 -2
  137. package/dist/storage/zip-export.js +37 -59
  138. package/dist/storage/zip-reader.d.ts +1 -1
  139. package/dist/{storage-backend-Do6YDpNo.d.ts → storage-backend-CTJHNdMp.d.ts} +1 -1
  140. package/dist/{store-subscribers-0YWyOLvV.d.ts → store-subscribers-BZP81hjh.d.ts} +2 -2
  141. package/dist/{subscribe-to-selector-CZ6k1NFP.d.ts → subscribe-to-selector-Bp3sLx8L.d.ts} +1 -1
  142. package/dist/test-utils/browser-mocks.d.ts +7 -1
  143. package/dist/test-utils/browser-mocks.js +6 -0
  144. package/dist/test-utils/zip-round-trip-helpers.d.ts +9 -1
  145. package/dist/test-utils/zip-round-trip-helpers.js +5 -1
  146. package/dist/{tracking-slice-CdK8c-8P.d.ts → tracking-slice-DJZ9qeGg.d.ts} +1 -1
  147. package/dist/types/ar-types.d.ts +1 -1
  148. package/dist/types/geo-types.d.ts +1 -1
  149. package/dist/types/index.d.ts +2 -2
  150. package/dist/utils/concurrency.d.ts +2 -2
  151. package/dist/utils/concurrency.js +66 -2
  152. package/dist/utils/failure-tracker.d.ts +1 -1
  153. package/dist/utils/format-file-size.d.ts +1 -1
  154. package/dist/utils/fused-path.d.ts +1 -1
  155. package/dist/utils/index.d.ts +6 -6
  156. package/dist/utils/list-formatter.d.ts +1 -1
  157. package/dist/utils/logger.d.ts +1 -1
  158. package/dist/visualization/accuracy-circles.d.ts +1 -1
  159. package/dist/visualization/alignment-lerper.d.ts +1 -1
  160. package/dist/visualization/ar-world-group-alignment.d.ts +1 -1
  161. package/dist/visualization/ar-world-group-alignment.js +1 -1
  162. package/dist/visualization/camera-follower.d.ts +1 -1
  163. package/dist/visualization/css3d-renderer-manager.d.ts +1 -1
  164. package/dist/visualization/frame-conversions.d.ts +1 -1
  165. package/dist/visualization/frustum-visibility.d.ts +1 -1
  166. package/dist/visualization/gps-anchor.d.ts +1 -1
  167. package/dist/visualization/gps-compass-cubes.d.ts +1 -1
  168. package/dist/visualization/gps-event-markers.d.ts +1 -1
  169. package/dist/visualization/gps-event-markers.js +40 -5
  170. package/dist/visualization/hit-test-reticle.d.ts +1 -1
  171. package/dist/visualization/hit-test-reticle.js +1 -0
  172. package/dist/visualization/index.d.ts +18 -18
  173. package/dist/visualization/leaflet-map-overlay.d.ts +1 -1
  174. package/dist/visualization/leaflet-map-overlay.js +15 -3
  175. package/dist/visualization/lerp-utils.d.ts +1 -1
  176. package/dist/visualization/map-data.d.ts +1 -1
  177. package/dist/visualization/map-overlay-draw.d.ts +1 -1
  178. package/dist/visualization/map-overlay.d.ts +1 -1
  179. package/dist/visualization/three-dispose.d.ts +1 -1
  180. package/dist/visualization/vis-colors.d.ts +1 -1
  181. package/dist/{webxr-session-TIaD883f.js → webxr-session-CJF9Nijp.js} +221 -9
  182. package/dist/{webxr-session-GjZ2BIpS.d.ts → webxr-session-COsOjJwn.d.ts} +76 -8
  183. package/dist/zip-coverage-embed-tFohI2J4.d.ts +41 -0
  184. package/dist/{zip-export-G14hkSPG.d.ts → zip-export-DDWXInTR.d.ts} +27 -23
  185. package/package.json +2 -2
  186. package/dist/concurrency-CO1FQvs3.d.ts +0 -24
  187. package/dist/file-system-CwXTNHmB.d.ts +0 -114
  188. package/dist/recording-options-DJBXuMxV.d.ts +0 -182
  189. package/dist/recording-slice-89O07ebs.d.ts +0 -36
  190. package/dist/storage/file-system.d.ts +0 -2
  191. package/dist/storage/file-system.js +0 -289
  192. /package/dist/{accuracy-circles-BpwWAs8G.d.ts → accuracy-circles-Pi2YeCrM.d.ts} +0 -0
  193. /package/dist/{alignment-lerper-Dm9G7JJO.d.ts → alignment-lerper-BUTsQ2yu.d.ts} +0 -0
  194. /package/dist/{ar-types-Dan1MVTi.d.ts → ar-types-BckI1E-O.d.ts} +0 -0
  195. /package/dist/{bresenham3d-CFfd7n6B.d.ts → bresenham3d-ByjcmEgM.d.ts} +0 -0
  196. /package/dist/{camera-follower-C2mwEn7c.d.ts → camera-follower-BTb2Yp12.d.ts} +0 -0
  197. /package/dist/{capability-checker-CQXJHxXg.d.ts → capability-checker-CXqoJYtb.d.ts} +0 -0
  198. /package/dist/{capture-failure-tracker-CUeU3L_M.d.ts → capture-failure-tracker-BL5SoG2a.d.ts} +0 -0
  199. /package/dist/{chromium-camera-access-workaround-Jqbn0apH.d.ts → chromium-camera-access-workaround-BNK189P0.d.ts} +0 -0
  200. /package/dist/{css3d-renderer-manager-ptu_t3B3.d.ts → css3d-renderer-manager-m-ab19vp.d.ts} +0 -0
  201. /package/dist/{failure-tracker-Cn8Fo9D4.d.ts → failure-tracker-Cnc_xWUw.d.ts} +0 -0
  202. /package/dist/{file-system-utils-CXIoL-DM.d.ts → file-system-utils-Bs7lpeVP.d.ts} +0 -0
  203. /package/dist/{format-file-size-CLCZz3lC.d.ts → format-file-size-BFUWvir1.d.ts} +0 -0
  204. /package/dist/{frame-loop-CMewS8cY.d.ts → frame-loop-BEO9_q3k.d.ts} +0 -0
  205. /package/dist/{frustum-visibility-CmI96ESS.d.ts → frustum-visibility-D_RGmH98.d.ts} +0 -0
  206. /package/dist/{geo-types-SaPnIEUM.d.ts → geo-types-DqiBzPO9.d.ts} +0 -0
  207. /package/dist/{gps-VuezJWK3.d.ts → gps-C5inWeNV.d.ts} +0 -0
  208. /package/dist/{gps-compass-cubes-BM1uGiYV.d.ts → gps-compass-cubes-BExxrWJ-.d.ts} +0 -0
  209. /package/dist/{gps-error-handler-CJl_2MVm.d.ts → gps-error-handler-C2bS69oJ.d.ts} +0 -0
  210. /package/dist/{hit-test-reticle-BEzEybxZ.d.ts → hit-test-reticle-Dqak9hiR.d.ts} +0 -0
  211. /package/dist/{index-CF05QV2m.d.ts → index-eaI1Z1KR.d.ts} +0 -0
  212. /package/dist/{lerp-utils-BpV-0Dtk.d.ts → lerp-utils-kLxMJ2Xj.d.ts} +0 -0
  213. /package/dist/{list-formatter-RRcBe8Vg.d.ts → list-formatter-ct8txwvR.d.ts} +0 -0
  214. /package/dist/{logger-BEHXsnnq.d.ts → logger-CzQrCe6C.d.ts} +0 -0
  215. /package/dist/{map-overlay-bcogY5fK.d.ts → map-overlay-Dci4yvm3.d.ts} +0 -0
  216. /package/dist/{permission-checker-GpAiSCwd.d.ts → permission-checker-CtPtPQRq.d.ts} +0 -0
  217. /package/dist/{scene-node-names-Bu0S66H1.d.ts → scene-node-names-CdNeQjOE.d.ts} +0 -0
  218. /package/dist/{session-disposers-M-oashRH.js → session-disposers-D8wnO-uW.js} +0 -0
  219. /package/dist/{three-dispose-D950t71B.d.ts → three-dispose-BCZkSJp2.d.ts} +0 -0
  220. /package/dist/{vis-colors-D6omC64K.d.ts → vis-colors-BZsSLI4i.d.ts} +0 -0
  221. /package/dist/{webxr-nue-basis-CqKQmZzT.d.ts → webxr-nue-basis-CW1wsbm6.d.ts} +0 -0
  222. /package/dist/{xr-camera-texture-DBwCaKTd.d.ts → xr-camera-texture-BmrP7iNZ.d.ts} +0 -0
  223. /package/dist/{xr-error-handler-C0AQRmxs.d.ts → xr-error-handler-BEjRgZjt.d.ts} +0 -0
  224. /package/dist/{xr-frame-loop-BtYytZJg.d.ts → xr-frame-loop-K8ebdjLw.d.ts} +0 -0
  225. /package/dist/{zip-reader-DSEXt7K6.d.ts → zip-reader-Q2ue6zlC.d.ts} +0 -0
@@ -1,2 +1,2 @@
1
- import { n as createCameraFollower, t as CameraFollower } from "../camera-follower-C2mwEn7c.js";
1
+ import { n as createCameraFollower, t as CameraFollower } from "../camera-follower-BTb2Yp12.js";
2
2
  export { CameraFollower, createCameraFollower };
@@ -1,2 +1,2 @@
1
- import { n as createCss3dRendererManager, t as Css3dRendererManager } from "../css3d-renderer-manager-ptu_t3B3.js";
1
+ import { n as createCss3dRendererManager, t as Css3dRendererManager } from "../css3d-renderer-manager-m-ab19vp.js";
2
2
  export { Css3dRendererManager, createCss3dRendererManager };
@@ -1,2 +1,2 @@
1
- import { n as worldNueToGps, t as nueToArLocal } from "../frame-conversions-BfsafGWR.js";
1
+ import { n as worldNueToGps, t as nueToArLocal } from "../frame-conversions-D_Af8Dt3.js";
2
2
  export { nueToArLocal, worldNueToGps };
@@ -1,2 +1,2 @@
1
- import { i as isSphereInCameraFrustum, n as isObjectInCameraFrustum, r as isPointInCameraFrustum, t as buildCameraFrustum } from "../frustum-visibility-CmI96ESS.js";
1
+ import { i as isSphereInCameraFrustum, n as isObjectInCameraFrustum, r as isPointInCameraFrustum, t as buildCameraFrustum } from "../frustum-visibility-D_RGmH98.js";
2
2
  export { buildCameraFrustum, isObjectInCameraFrustum, isPointInCameraFrustum, isSphereInCameraFrustum };
@@ -1,2 +1,2 @@
1
- import { a as GpsAnchorSamplePoint, i as GpsAnchorPhase, n as GpsAnchorMode, o as createGpsAnchor, r as GpsAnchorOptions, t as GpsAnchor } from "../gps-anchor-dYeCvvp5.js";
1
+ import { a as GpsAnchorSamplePoint, i as GpsAnchorPhase, n as GpsAnchorMode, o as createGpsAnchor, r as GpsAnchorOptions, t as GpsAnchor } from "../gps-anchor-C6I9NDHA.js";
2
2
  export { GpsAnchor, GpsAnchorMode, GpsAnchorOptions, GpsAnchorPhase, GpsAnchorSamplePoint, createGpsAnchor };
@@ -1,2 +1,2 @@
1
- import { i as createGpsCompassCubes, n as COMPASS_CUBE_SIZE, r as GpsCompassCubes, t as COMPASS_CUBE_DISTANCE } from "../gps-compass-cubes-BM1uGiYV.js";
1
+ import { i as createGpsCompassCubes, n as COMPASS_CUBE_SIZE, r as GpsCompassCubes, t as COMPASS_CUBE_DISTANCE } from "../gps-compass-cubes-BExxrWJ-.js";
2
2
  export { COMPASS_CUBE_DISTANCE, COMPASS_CUBE_SIZE, GpsCompassCubes, createGpsCompassCubes };
@@ -1,2 +1,2 @@
1
- import { n as GpsEventVisualizer, r as gpsEventVisualizer, t as GpsEventAccuracy } from "../gps-event-markers-Dc9FT-q1.js";
1
+ import { n as GpsEventVisualizer, r as gpsEventVisualizer, t as GpsEventAccuracy } from "../gps-event-markers-Dd0G2bD0.js";
2
2
  export { GpsEventAccuracy, GpsEventVisualizer, gpsEventVisualizer };
@@ -1,6 +1,6 @@
1
1
  import { createLogger } from "../utils/logger.js";
2
2
  import { disposeMeshArray } from "./three-dispose.js";
3
- import { c as getArWorldGroup, m as getScene } from "../webxr-session-TIaD883f.js";
3
+ import { _ as getScene, l as getArWorldGroup } from "../webxr-session-CJF9Nijp.js";
4
4
  import { VIS_COLORS } from "./vis-colors.js";
5
5
  import * as THREE from "three";
6
6
  //#region ../src/visualization/gps-event-markers.ts
@@ -20,10 +20,20 @@ import * as THREE from "three";
20
20
  * world positions update automatically via Three.js scene-graph propagation.
21
21
  */
22
22
  const log = createLogger("GpsEventVisualizer");
23
- /** Sphere radius in meters (8cm - smaller than reference point markers) */
24
- const GPS_MARKER_RADIUS = .08;
25
- /** Slightly larger radius for alignment snapshots to stand out */
26
- const SNAPSHOT_MARKER_RADIUS = .1;
23
+ /**
24
+ * Sphere radius in meters for the raw-GPS / fused debug markers.
25
+ *
26
+ * Halved 0.08 → 0.04 (D5, 2026-06-16 user feedback): these "different colours"
27
+ * tracking spheres were cluttering the AR scene and hiding the ref-point
28
+ * markers. They now shrink while the ref-point marker spheres grow (×2), so the
29
+ * marker the user cares about stands out. This is a framework-level constant
30
+ * rendered in BOTH live recording and replay, so replays of older recordings
31
+ * also show the smaller debug spheres — intended and accepted (requester
32
+ * decision); a plain constant change is correct (no live-vs-replay flag).
33
+ */
34
+ const GPS_MARKER_RADIUS = .04;
35
+ /** Slightly larger radius for alignment snapshots to stand out (halved 0.1 → 0.05 with the GPS markers, D5). */
36
+ const SNAPSHOT_MARKER_RADIUS = .05;
27
37
  /**
28
38
  * Default opacity for the yellow raw-GPS sphere when it is rendered at the
29
39
  * legacy fixed 8 cm radius (no accuracy passed). Matches the original 30 %
@@ -67,6 +77,14 @@ var GpsEventVisualizer = class {
67
77
  eventCounter = 0;
68
78
  snapshotCounter = 0;
69
79
  /**
80
+ * Whether the debug markers are drawn. Toggled by {@link setVisible} for the
81
+ * recorder's `visualization.gpsAlignmentMarkers` opt-out (Finding B). Applied
82
+ * to every marker at creation so events spawned later by the live
83
+ * store-subscriber inherit the current state instead of popping into view.
84
+ * Default `true` — the markers render exactly as before until opted out.
85
+ */
86
+ markersVisible = true;
87
+ /**
70
88
  * Set the GPS zero reference (origin for coordinate conversion).
71
89
  * Must be called before adding GPS events.
72
90
  *
@@ -167,9 +185,25 @@ var GpsEventVisualizer = class {
167
185
  });
168
186
  const mesh = new THREE.Mesh(geometry, material);
169
187
  mesh.name = `${namePrefix}-${eventId}`;
188
+ mesh.visible = this.markersVisible;
170
189
  return mesh;
171
190
  }
172
191
  /**
192
+ * Show or hide ALL debug markers — raw GPS (yellow), fused (cyan), and
193
+ * alignment-snapshot (red) — and remember the state so markers added later
194
+ * inherit it. Used by the recorder's `visualization.gpsAlignmentMarkers`
195
+ * opt-out, read once at Enter-AR (live only; replay keeps markers visible).
196
+ *
197
+ * This only changes rendering: capture, GPS-event recording, counts, and the
198
+ * snapshot positions read back at session end are all unaffected.
199
+ */
200
+ setVisible(visible) {
201
+ this.markersVisible = visible;
202
+ for (const mesh of this.rawGpsMarkers) mesh.visible = visible;
203
+ for (const mesh of this.fusedMarkers) mesh.visible = visible;
204
+ for (const mesh of this.snapshotMarkers) mesh.visible = visible;
205
+ }
206
+ /**
173
207
  * Clear all markers from the scene and reset state.
174
208
  */
175
209
  clearAll() {
@@ -181,6 +215,7 @@ var GpsEventVisualizer = class {
181
215
  this.zeroRef = null;
182
216
  this.eventCounter = 0;
183
217
  this.snapshotCounter = 0;
218
+ this.markersVisible = true;
184
219
  }
185
220
  /**
186
221
  * Get count of visible markers.
@@ -1,2 +1,2 @@
1
- import { n as createReticleMesh, r as updateReticle, t as HitMatrix } from "../hit-test-reticle-BEzEybxZ.js";
1
+ import { n as createReticleMesh, r as updateReticle, t as HitMatrix } from "../hit-test-reticle-Dqak9hiR.js";
2
2
  export { HitMatrix, createReticleMesh, updateReticle };
@@ -75,6 +75,7 @@ function updateReticle(reticle, matrix) {
75
75
  }
76
76
  hitPoseMatrix.fromArray(matrix);
77
77
  reticle.matrix.multiplyMatrices(WEBXR_TO_NUE, hitPoseMatrix);
78
+ reticle.matrixWorldNeedsUpdate = true;
78
79
  reticle.visible = true;
79
80
  }
80
81
  //#endregion
@@ -1,19 +1,19 @@
1
- import { n as createCss3dRendererManager, t as Css3dRendererManager } from "../css3d-renderer-manager-ptu_t3B3.js";
2
- import { n as createCameraFollower, t as CameraFollower } from "../camera-follower-C2mwEn7c.js";
3
- import { n as createAlignmentLerper, t as AlignmentLerper } from "../alignment-lerper-Dm9G7JJO.js";
4
- import { n as MapDataInput, r as buildMapData, t as MapData } from "../map-data-CkloBxIl.js";
5
- import { n as ArWorldGroupAlignmentOptions, r as enableArWorldGroupAlignment, t as ArWorldGroupAlignmentHandle } from "../ar-world-group-alignment-C9lwwIyI.js";
6
- import { i as createGpsCompassCubes, n as COMPASS_CUBE_SIZE, r as GpsCompassCubes, t as COMPASS_CUBE_DISTANCE } from "../gps-compass-cubes-BM1uGiYV.js";
7
- import { i as isSphereInCameraFrustum, n as isObjectInCameraFrustum, r as isPointInCameraFrustum, t as buildCameraFrustum } from "../frustum-visibility-CmI96ESS.js";
8
- import { n as worldNueToGps, t as nueToArLocal } from "../frame-conversions-BfsafGWR.js";
9
- import { n as createReticleMesh, r as updateReticle, t as HitMatrix } from "../hit-test-reticle-BEzEybxZ.js";
10
- import { a as GpsAnchorSamplePoint, i as GpsAnchorPhase, n as GpsAnchorMode, o as createGpsAnchor, r as GpsAnchorOptions, t as GpsAnchor } from "../gps-anchor-dYeCvvp5.js";
11
- import { n as GpsEventVisualizer, r as gpsEventVisualizer } from "../gps-event-markers-Dc9FT-q1.js";
12
- import { a as DEFAULT_Z_OFFSET, n as DEFAULT_LEAFLET_MAP_SIZE_PX, o as LeafletMapOverlay, r as DEFAULT_WORLD_SIZE, s as LeafletMapOverlayOptions } from "../leaflet-map-overlay-6CJC-E1l.js";
13
- import { n as clampedAlpha, t as DEFAULT_LERP_RATE } from "../lerp-utils-BpV-0Dtk.js";
14
- import { a as addAccuracyCircles, i as AccuracyCircleSample, n as ACCURACY_CIRCLE_STROKE_OPACITY, r as ACCURACY_CIRCLE_WEIGHT, t as ACCURACY_CIRCLE_FILL_OPACITY } from "../accuracy-circles-BpwWAs8G.js";
15
- import { a as MAP_PATH_POLYLINE_OPACITY, c as USER_POSITION_COLOR, i as FUSED_PATH_COLOR, l as drawMapData, n as DrawMapDataOptions, o as MAP_PATH_POLYLINE_WEIGHT, r as DrawnMapData, s as RAW_GPS_COLOR, t as ALIGNMENT_SNAPSHOT_COLOR } from "../map-overlay-draw-krOKwDAq.js";
16
- import { a as MapOverlayOptions, c as tileXYToLatLon, i as MapOverlay, n as DEFAULT_MAP_SIZE, o as TextureLoaderInterface, r as DEFAULT_ZOOM, s as latLonToTileXY, t as DEFAULT_HEIGHT_OFFSET } from "../map-overlay-bcogY5fK.js";
17
- import { n as disposeMeshArray, r as disposeObject3D, t as DisposeOptions } from "../three-dispose-D950t71B.js";
18
- import { t as VIS_COLORS } from "../vis-colors-D6omC64K.js";
1
+ import { n as createCss3dRendererManager, t as Css3dRendererManager } from "../css3d-renderer-manager-m-ab19vp.js";
2
+ import { n as createCameraFollower, t as CameraFollower } from "../camera-follower-BTb2Yp12.js";
3
+ import { n as createAlignmentLerper, t as AlignmentLerper } from "../alignment-lerper-BUTsQ2yu.js";
4
+ import { n as MapDataInput, r as buildMapData, t as MapData } from "../map-data-DdjPiSav.js";
5
+ import { n as ArWorldGroupAlignmentOptions, r as enableArWorldGroupAlignment, t as ArWorldGroupAlignmentHandle } from "../ar-world-group-alignment-DDLkgNf_.js";
6
+ import { i as createGpsCompassCubes, n as COMPASS_CUBE_SIZE, r as GpsCompassCubes, t as COMPASS_CUBE_DISTANCE } from "../gps-compass-cubes-BExxrWJ-.js";
7
+ import { i as isSphereInCameraFrustum, n as isObjectInCameraFrustum, r as isPointInCameraFrustum, t as buildCameraFrustum } from "../frustum-visibility-D_RGmH98.js";
8
+ import { n as worldNueToGps, t as nueToArLocal } from "../frame-conversions-D_Af8Dt3.js";
9
+ import { n as createReticleMesh, r as updateReticle, t as HitMatrix } from "../hit-test-reticle-Dqak9hiR.js";
10
+ import { a as GpsAnchorSamplePoint, i as GpsAnchorPhase, n as GpsAnchorMode, o as createGpsAnchor, r as GpsAnchorOptions, t as GpsAnchor } from "../gps-anchor-C6I9NDHA.js";
11
+ import { n as GpsEventVisualizer, r as gpsEventVisualizer } from "../gps-event-markers-Dd0G2bD0.js";
12
+ import { a as DEFAULT_Z_OFFSET, n as DEFAULT_LEAFLET_MAP_SIZE_PX, o as LeafletMapOverlay, r as DEFAULT_WORLD_SIZE, s as LeafletMapOverlayOptions } from "../leaflet-map-overlay-bnb2U1NQ.js";
13
+ import { n as clampedAlpha, t as DEFAULT_LERP_RATE } from "../lerp-utils-kLxMJ2Xj.js";
14
+ import { a as addAccuracyCircles, i as AccuracyCircleSample, n as ACCURACY_CIRCLE_STROKE_OPACITY, r as ACCURACY_CIRCLE_WEIGHT, t as ACCURACY_CIRCLE_FILL_OPACITY } from "../accuracy-circles-Pi2YeCrM.js";
15
+ import { a as MAP_PATH_POLYLINE_OPACITY, c as USER_POSITION_COLOR, i as FUSED_PATH_COLOR, l as drawMapData, n as DrawMapDataOptions, o as MAP_PATH_POLYLINE_WEIGHT, r as DrawnMapData, s as RAW_GPS_COLOR, t as ALIGNMENT_SNAPSHOT_COLOR } from "../map-overlay-draw-CPVdAsFq.js";
16
+ import { a as MapOverlayOptions, c as tileXYToLatLon, i as MapOverlay, n as DEFAULT_MAP_SIZE, o as TextureLoaderInterface, r as DEFAULT_ZOOM, s as latLonToTileXY, t as DEFAULT_HEIGHT_OFFSET } from "../map-overlay-Dci4yvm3.js";
17
+ import { n as disposeMeshArray, r as disposeObject3D, t as DisposeOptions } from "../three-dispose-BCZkSJp2.js";
18
+ import { t as VIS_COLORS } from "../vis-colors-BZsSLI4i.js";
19
19
  export { ACCURACY_CIRCLE_FILL_OPACITY, ACCURACY_CIRCLE_STROKE_OPACITY, ACCURACY_CIRCLE_WEIGHT, ALIGNMENT_SNAPSHOT_COLOR, type AccuracyCircleSample, type AlignmentLerper, type ArWorldGroupAlignmentHandle, type ArWorldGroupAlignmentOptions, COMPASS_CUBE_DISTANCE, COMPASS_CUBE_SIZE, type CameraFollower, type Css3dRendererManager, DEFAULT_HEIGHT_OFFSET, DEFAULT_LEAFLET_MAP_SIZE_PX, DEFAULT_LERP_RATE, DEFAULT_MAP_SIZE, DEFAULT_WORLD_SIZE, DEFAULT_ZOOM, DEFAULT_Z_OFFSET, type DisposeOptions, type DrawMapDataOptions, type DrawnMapData, FUSED_PATH_COLOR, type GpsAnchor, type GpsAnchorMode, type GpsAnchorOptions, type GpsAnchorPhase, type GpsAnchorSamplePoint, type GpsCompassCubes, GpsEventVisualizer, type HitMatrix, LeafletMapOverlay, type LeafletMapOverlayOptions, MAP_PATH_POLYLINE_OPACITY, MAP_PATH_POLYLINE_WEIGHT, type MapData, type MapDataInput, MapOverlay, type MapOverlayOptions, RAW_GPS_COLOR, type TextureLoaderInterface, USER_POSITION_COLOR, VIS_COLORS, addAccuracyCircles, buildCameraFrustum, buildMapData, clampedAlpha, createAlignmentLerper, createCameraFollower, createCss3dRendererManager, createGpsAnchor, createGpsCompassCubes, createReticleMesh, disposeMeshArray, disposeObject3D, drawMapData, enableArWorldGroupAlignment, gpsEventVisualizer, isObjectInCameraFrustum, isPointInCameraFrustum, isSphereInCameraFrustum, latLonToTileXY, nueToArLocal, tileXYToLatLon, updateReticle, worldNueToGps };
@@ -1,2 +1,2 @@
1
- import { a as DEFAULT_Z_OFFSET, i as DEFAULT_ZOOM, n as DEFAULT_LEAFLET_MAP_SIZE_PX, o as LeafletMapOverlay, r as DEFAULT_WORLD_SIZE, s as LeafletMapOverlayOptions, t as DEFAULT_HEIGHT_OFFSET } from "../leaflet-map-overlay-6CJC-E1l.js";
1
+ import { a as DEFAULT_Z_OFFSET, i as DEFAULT_ZOOM, n as DEFAULT_LEAFLET_MAP_SIZE_PX, o as LeafletMapOverlay, r as DEFAULT_WORLD_SIZE, s as LeafletMapOverlayOptions, t as DEFAULT_HEIGHT_OFFSET } from "../leaflet-map-overlay-bnb2U1NQ.js";
2
2
  export { DEFAULT_HEIGHT_OFFSET, DEFAULT_LEAFLET_MAP_SIZE_PX, DEFAULT_WORLD_SIZE, DEFAULT_ZOOM, DEFAULT_Z_OFFSET, LeafletMapOverlay, LeafletMapOverlayOptions };
@@ -7,6 +7,16 @@ import L from "leaflet";
7
7
  const log = createLogger("LeafletMapOverlay");
8
8
  /** Default pixel size of the Leaflet map container */
9
9
  const DEFAULT_LEAFLET_MAP_SIZE_PX = 600;
10
+ /**
11
+ * Diameter (px) of the ref-point markers on the in-AR minimap.
12
+ *
13
+ * Enlarged 12 → 20 px (F5-A, 2026-06-16 user feedback): the field tester
14
+ * reported the minimap "showed the user but not the marker". The markers WERE
15
+ * rendered — they were just too small to notice on the small CSS3D minimap. A
16
+ * bigger dot plus a thicker white halo and a drop shadow makes them the most
17
+ * prominent feature on the minimap (the user-position marker stays 14 px).
18
+ */
19
+ const REF_POINT_MARKER_SIZE_PX = 20;
10
20
  /** Default world-space size in meters (matches old MapOverlay) */
11
21
  const DEFAULT_WORLD_SIZE = 10;
12
22
  /** Default height offset below camera (negative = below) */
@@ -259,11 +269,13 @@ var LeafletMapOverlay = class {
259
269
  const color = isPrior ? VIS_COLORS.PRIOR_REF_POINT.css : VIS_COLORS.CURRENT_REF_POINT.css;
260
270
  const opacity = isPrior ? "opacity:0.8;" : "";
261
271
  const label = isPrior ? `📌 ${name} (prior)` : name;
272
+ const size = REF_POINT_MARKER_SIZE_PX;
273
+ const anchor = size / 2;
262
274
  return L.marker([lat, lon], { icon: L.divIcon({
263
275
  className: "",
264
- html: `<div style="background:${color};width:12px;height:12px;border-radius:50%;border:2px solid white;${opacity}"></div>`,
265
- iconSize: [12, 12],
266
- iconAnchor: [6, 6]
276
+ html: `<div style="background:${color};width:${size}px;height:${size}px;border-radius:50%;border:3px solid white;box-shadow:0 0 4px rgba(0,0,0,0.7);${opacity}"></div>`,
277
+ iconSize: [size, size],
278
+ iconAnchor: [anchor, anchor]
267
279
  }) }).bindPopup(label).addTo(this.leafletMap);
268
280
  }
269
281
  };
@@ -1,2 +1,2 @@
1
- import { n as clampedAlpha, t as DEFAULT_LERP_RATE } from "../lerp-utils-BpV-0Dtk.js";
1
+ import { n as clampedAlpha, t as DEFAULT_LERP_RATE } from "../lerp-utils-kLxMJ2Xj.js";
2
2
  export { DEFAULT_LERP_RATE, clampedAlpha };
@@ -1,2 +1,2 @@
1
- import { n as MapDataInput, r as buildMapData, t as MapData } from "../map-data-CkloBxIl.js";
1
+ import { n as MapDataInput, r as buildMapData, t as MapData } from "../map-data-DdjPiSav.js";
2
2
  export { MapData, MapDataInput, buildMapData };
@@ -1,2 +1,2 @@
1
- import { a as MAP_PATH_POLYLINE_OPACITY, c as USER_POSITION_COLOR, i as FUSED_PATH_COLOR, l as drawMapData, n as DrawMapDataOptions, o as MAP_PATH_POLYLINE_WEIGHT, r as DrawnMapData, s as RAW_GPS_COLOR, t as ALIGNMENT_SNAPSHOT_COLOR } from "../map-overlay-draw-krOKwDAq.js";
1
+ import { a as MAP_PATH_POLYLINE_OPACITY, c as USER_POSITION_COLOR, i as FUSED_PATH_COLOR, l as drawMapData, n as DrawMapDataOptions, o as MAP_PATH_POLYLINE_WEIGHT, r as DrawnMapData, s as RAW_GPS_COLOR, t as ALIGNMENT_SNAPSHOT_COLOR } from "../map-overlay-draw-CPVdAsFq.js";
2
2
  export { ALIGNMENT_SNAPSHOT_COLOR, DrawMapDataOptions, DrawnMapData, FUSED_PATH_COLOR, MAP_PATH_POLYLINE_OPACITY, MAP_PATH_POLYLINE_WEIGHT, RAW_GPS_COLOR, USER_POSITION_COLOR, drawMapData };
@@ -1,2 +1,2 @@
1
- import { a as MapOverlayOptions, c as tileXYToLatLon, i as MapOverlay, n as DEFAULT_MAP_SIZE, o as TextureLoaderInterface, r as DEFAULT_ZOOM, s as latLonToTileXY, t as DEFAULT_HEIGHT_OFFSET } from "../map-overlay-bcogY5fK.js";
1
+ import { a as MapOverlayOptions, c as tileXYToLatLon, i as MapOverlay, n as DEFAULT_MAP_SIZE, o as TextureLoaderInterface, r as DEFAULT_ZOOM, s as latLonToTileXY, t as DEFAULT_HEIGHT_OFFSET } from "../map-overlay-Dci4yvm3.js";
2
2
  export { DEFAULT_HEIGHT_OFFSET, DEFAULT_MAP_SIZE, DEFAULT_ZOOM, MapOverlay, MapOverlayOptions, TextureLoaderInterface, latLonToTileXY, tileXYToLatLon };
@@ -1,2 +1,2 @@
1
- import { n as disposeMeshArray, r as disposeObject3D, t as DisposeOptions } from "../three-dispose-D950t71B.js";
1
+ import { n as disposeMeshArray, r as disposeObject3D, t as DisposeOptions } from "../three-dispose-BCZkSJp2.js";
2
2
  export { DisposeOptions, disposeMeshArray, disposeObject3D };
@@ -1,2 +1,2 @@
1
- import { t as VIS_COLORS } from "../vis-colors-D6omC64K.js";
1
+ import { t as VIS_COLORS } from "../vis-colors-BZsSLI4i.js";
2
2
  export { VIS_COLORS };
@@ -1,19 +1,92 @@
1
1
  import { createLogger } from "./utils/logger.js";
2
- import { CameraBlitCapture, computeCaptureSize } from "./ar/camera-blit-capture.js";
2
+ import { CameraBlitCapture, computeAspectFitSize, computeCaptureSize } from "./ar/camera-blit-capture.js";
3
3
  import { getLastDeviceOrientation } from "./state/gps-event-coordinator.js";
4
4
  import { DepthSampler, wrapXRDepthInfo } from "./ar/depth-sampler.js";
5
+ import { WEBXR_TO_NUE } from "./ar/webxr-nue-basis.js";
5
6
  import { clearFrameUpdates, runFrameUpdates } from "./ar/frame-loop.js";
6
7
  import { clearXrFrameUpdates, runXrFrameUpdates } from "./ar/xr-frame-loop.js";
7
- import { WEBXR_TO_NUE } from "./ar/webxr-nue-basis.js";
8
8
  import { DEFAULT_CAPTURE_CONFIG, ImageCaptureManager } from "./ar/image-capture.js";
9
9
  import { clearLastRestartedPayload, originReset, poseLost, poseReceived, resetTracking, selectLastRestartedPayload, selectTrackingPhase } from "./state/tracking-slice.js";
10
10
  import { acquireCameraTexture } from "./ar/xr-camera-texture.js";
11
- import { n as runSessionDisposers } from "./session-disposers-M-oashRH.js";
11
+ import { n as runSessionDisposers } from "./session-disposers-D8wnO-uW.js";
12
12
  import { DEFAULT_RECORDING_OPTIONS, validateArCrashIsolationOptions } from "./state/recording-options.js";
13
13
  import { SCENE_NODE } from "./ar/scene-node-names.js";
14
14
  import { createCss3dRendererManager } from "./visualization/css3d-renderer-manager.js";
15
15
  import * as THREE from "three";
16
16
  import { nueQuaternionToWebXR, nueToWebXR } from "gps-plus-slam-js";
17
+ //#region ../src/ar/camera-frame-source.ts
18
+ const DEFAULT_CONFIG = { intervalMs: 125 };
19
+ /**
20
+ * Throttled RGBA capturer. Construct with the injected `capture`/`onCapture`
21
+ * pair, `start()`, then call `onFrame(timestamp)` once per XR frame.
22
+ */
23
+ var CameraFrameSource = class {
24
+ callbacks;
25
+ config;
26
+ running = false;
27
+ captureCount = 0;
28
+ lastCaptureTime = -Infinity;
29
+ constructor(callbacks, config) {
30
+ this.callbacks = callbacks;
31
+ this.config = { ...DEFAULT_CONFIG };
32
+ if (config) this.updateConfig(config);
33
+ }
34
+ /** Begin throttling. Resets the cadence so the first tick captures. */
35
+ start() {
36
+ this.running = true;
37
+ this.captureCount = 0;
38
+ this.lastCaptureTime = -Infinity;
39
+ }
40
+ /** Stop capturing. `onFrame` becomes a no-op until `start()` is called again. */
41
+ stop() {
42
+ this.running = false;
43
+ }
44
+ isRunning() {
45
+ return this.running;
46
+ }
47
+ /** Number of frames successfully captured + delivered since `start()`. */
48
+ getFrameCount() {
49
+ return this.captureCount;
50
+ }
51
+ getConfig() {
52
+ return { ...this.config };
53
+ }
54
+ /**
55
+ * Apply partial config (e.g. the app's detection cadence). Invalid values
56
+ * are ignored defensively — `intervalMs` requires a finite positive number.
57
+ */
58
+ updateConfig(config) {
59
+ if (typeof config.intervalMs === "number" && Number.isFinite(config.intervalMs) && config.intervalMs > 0) this.config.intervalMs = config.intervalMs;
60
+ }
61
+ /**
62
+ * Per-XR-frame tick. Captures + delivers a frame at most once per
63
+ * `intervalMs`; otherwise a cheap no-op so it is safe to call every frame.
64
+ *
65
+ * @param timestamp - monotonic frame time in ms (the XR `time` argument).
66
+ */
67
+ onFrame(timestamp) {
68
+ if (!this.running) return;
69
+ if (timestamp - this.lastCaptureTime < this.config.intervalMs) return;
70
+ const image = this.captureSafely();
71
+ if (!image) return;
72
+ this.lastCaptureTime = timestamp;
73
+ this.captureCount++;
74
+ this.callbacks.onCapture(image);
75
+ }
76
+ /**
77
+ * Run the injected capture, guarded so a blit failure (e.g. GL context loss)
78
+ * can never throw out of the XR frame loop — it degrades to "no frame this
79
+ * tick", exactly like a missing texture.
80
+ */
81
+ captureSafely() {
82
+ try {
83
+ return this.callbacks.capture();
84
+ } catch {
85
+ return null;
86
+ }
87
+ }
88
+ };
89
+ //#endregion
17
90
  //#region ../src/ar/depth-rgb-lookup.ts
18
91
  /**
19
92
  * Build an {@link RgbLookup} over an RGBA readback buffer.
@@ -159,6 +232,13 @@ function resetWebXRState() {
159
232
  depthRgbBlit.dispose();
160
233
  depthRgbBlit = null;
161
234
  }
235
+ cameraFrameSource = null;
236
+ onCameraFrame = null;
237
+ cameraFrameCaptureSize = DEFAULT_CAMERA_FRAME_CAPTURE_SIZE;
238
+ if (cameraFrameBlit) {
239
+ cameraFrameBlit.dispose();
240
+ cameraFrameBlit = null;
241
+ }
162
242
  onFrameCallback = null;
163
243
  if (css3dManager) {
164
244
  css3dManager.dispose();
@@ -285,6 +365,53 @@ const DEPTH_RGB_BLIT_CONFIG = {
285
365
  height: 192
286
366
  };
287
367
  /**
368
+ * Session-owned blit target for the generic camera-frame RGBA capture
369
+ * (framework-wiring options Part A / B2) — feeds QR detection today, object
370
+ * detection / OpenCV later. Separate from `depthRgbBlit` (256×192) on purpose:
371
+ * CV detection needs more pixels across the target (~1024 long edge) than a
372
+ * colour lookup, but only at the detection cadence, so the {@link CameraFrameSource}
373
+ * throttle keeps the readback off the per-frame path. Created lazily on the
374
+ * first capture, disposed by resetWebXRState(). The longer-edge size is
375
+ * configurable via `startCameraFrameCapture`; the blit preserves the camera
376
+ * aspect (see `acquireCameraFrameRgba`).
377
+ */
378
+ let cameraFrameBlit = null;
379
+ /**
380
+ * Default longer-edge resolution (px) for the camera-frame blit the QR / CV
381
+ * detector sees. The on-device capture-resolution sweep (2026-06-17, via the
382
+ * `?capture=` override) showed **1024** decodes a small / out-of-focus QR
383
+ * markedly better than the prior 512 with no perceptible cadence cost on the
384
+ * test phone; 2048 helped slightly more but risks low-end devices (4096 lagged),
385
+ * so 1024 is the safe default. Raise per-consumer via
386
+ * `startCameraFrameCapture({ captureSize })`.
387
+ *
388
+ * @see GpsPlusSlamJs_Docs/docs/2026-06-17-qr-size-accuracy-and-thin-demo-plan.md (WS-C)
389
+ */
390
+ const DEFAULT_CAMERA_FRAME_CAPTURE_SIZE = 1024;
391
+ /**
392
+ * Longer-edge resolution of the camera-frame blit (px), default
393
+ * {@link DEFAULT_CAMERA_FRAME_CAPTURE_SIZE}. The blit preserves the camera
394
+ * aspect, so the actual target is e.g. 1024×768 for a 4:3 frame — see
395
+ * `computeAspectFitSize` / `acquireCameraFrameRgba`.
396
+ */
397
+ let cameraFrameCaptureSize = DEFAULT_CAMERA_FRAME_CAPTURE_SIZE;
398
+ /**
399
+ * Throttled camera frame source (created in initAR when `onCameraFrame` is
400
+ * set). Blits the camera texture to RGBA at the detection cadence and hands it
401
+ * to `onCameraFrame`. @see camera-frame-source.ts
402
+ *
403
+ * SINGLE consumer by design: one source, one callback, one blit. That covers
404
+ * one CV consumer at a time (QR *or* object detection). To run two live CV
405
+ * consumers **simultaneously** at independent cadences/resolutions, replace this
406
+ * single-callback wiring with a small registry (e.g.
407
+ * `registerCameraFrameConsumer({ intervalMs, captureSize, onFrame })`) holding a
408
+ * `CameraFrameSource` per consumer — the class is already per-instance. See the
409
+ * SCOPE note in `camera-frame-source.ts`.
410
+ */
411
+ let cameraFrameSource = null;
412
+ /** Callback for each throttled camera RGBA frame (set via setCameraFrameCallback). */
413
+ let onCameraFrame = null;
414
+ /**
288
415
  * Latest WebXR camera texture, updated each frame when camera-access is enabled.
289
416
  * Acquired via Three.js's renderer.xr.getCameraTexture() API (ExternalTexture).
290
417
  * @see xr-camera-texture.ts
@@ -333,6 +460,20 @@ function acquireDepthRgbLookup() {
333
460
  return readback ? createRgbLookup(readback.pixels, readback.width, readback.height) : null;
334
461
  }
335
462
  /**
463
+ * Capture the current XR frame as top-left RGBA for CV detection (the
464
+ * `capture` injected into {@link CameraFrameSource}; called at most once per
465
+ * detection interval). Returns null — no frame this tick — when camera access
466
+ * or the texture is unavailable; the lazy blit makes a disposal elsewhere
467
+ * self-healing. Reuses `latestCameraTexture`, exactly like the depth-RGB path.
468
+ */
469
+ function acquireCameraFrameRgba() {
470
+ if (!renderer || !latestCameraTexture) return null;
471
+ const target = computeAspectFitSize(latestCameraWidth, latestCameraHeight, cameraFrameCaptureSize);
472
+ if (!cameraFrameBlit) cameraFrameBlit = new CameraBlitCapture(target);
473
+ else cameraFrameBlit.resizeIfNeeded(target.width, target.height);
474
+ return cameraFrameBlit.captureToRgba(renderer, latestCameraTexture);
475
+ }
476
+ /**
336
477
  * Extract the reset transform from an XRReferenceSpaceEvent-like object.
337
478
  *
338
479
  * Distinguishes three cases per OdometryTrackingRestartedPayload semantics:
@@ -563,6 +704,13 @@ async function initAR(container, isolationOptions = {}, sessionFeatures = {}) {
563
704
  acquireRgbLookup: acquireDepthRgbLookup,
564
705
  onDepthUnavailable: onDepthUnavailable ?? void 0
565
706
  });
707
+ if (onCameraFrame) {
708
+ const deliver = onCameraFrame;
709
+ cameraFrameSource = new CameraFrameSource({
710
+ capture: acquireCameraFrameRgba,
711
+ onCapture: (image) => deliver(image)
712
+ });
713
+ }
566
714
  renderer.setAnimationLoop(onXRFrame);
567
715
  log.info("AR session started");
568
716
  }
@@ -681,6 +829,7 @@ function onXRFrame(time, frame) {
681
829
  const depthInfo = getDepthInfoFromFrame(frame, pose);
682
830
  depthSampler.onFrame(time, depthInfo);
683
831
  }
832
+ if (cameraFrameSource) cameraFrameSource.onFrame(time);
684
833
  if (onFrameCallback) try {
685
834
  onFrameCallback();
686
835
  } catch (error) {
@@ -897,7 +1046,8 @@ function startImageCapture(config) {
897
1046
  const currentRenderer = renderer;
898
1047
  const divisor = mergedConfig.resolutionDivisor;
899
1048
  callbacks.captureFrame = async (quality) => {
900
- if (!blitCapture || !latestCameraTexture) {
1049
+ const bc = blitCapture;
1050
+ if (!bc || !latestCameraTexture) {
901
1051
  const canvas = currentRenderer.domElement;
902
1052
  return new Promise((resolve) => {
903
1053
  canvas.toBlob((blob) => resolve(blob ? {
@@ -909,14 +1059,14 @@ function startImageCapture(config) {
909
1059
  }
910
1060
  if (latestCameraWidth > 0 && latestCameraHeight > 0) {
911
1061
  const target = computeCaptureSize(latestCameraWidth, latestCameraHeight, divisor);
912
- blitCapture.resizeIfNeeded(target.width, target.height);
1062
+ bc.resizeIfNeeded(target.width, target.height);
913
1063
  }
914
- const blob = await blitCapture.captureToBlob(currentRenderer, latestCameraTexture, quality);
1064
+ const blob = await bc.captureToBlob(currentRenderer, latestCameraTexture, quality);
915
1065
  if (!blob) return null;
916
1066
  return {
917
1067
  blob,
918
- width: blitCapture.getWidth(),
919
- height: blitCapture.getHeight()
1068
+ width: bc.getWidth(),
1069
+ height: bc.getHeight()
920
1070
  };
921
1071
  };
922
1072
  log.info(`Blit capture pipeline initialized (resolutionDivisor=${divisor})`);
@@ -1033,6 +1183,68 @@ function getDepthSampleCount() {
1033
1183
  return depthSampler?.getSampleCount() ?? 0;
1034
1184
  }
1035
1185
  /**
1186
+ * Set the per-frame camera RGBA callback (B2) — the generic CV frame feed (QR
1187
+ * detection today, object detection / OpenCV later). Call this BEFORE initAR to
1188
+ * enable in-session camera frame capture; `startCameraFrameCapture` then begins
1189
+ * delivering frames.
1190
+ *
1191
+ * The callback receives a **top-left-origin** RGBA image (no JPEG round-trip),
1192
+ * captured at the throttled detection cadence — feed it straight to a
1193
+ * `BarcodeDetector` / OpenCV front-end. Mirrors `setDepthCaptureCallback`.
1194
+ *
1195
+ * @param onFrame - Called with each throttled camera frame, or `null` to clear.
1196
+ */
1197
+ function setCameraFrameCallback(onFrame) {
1198
+ onCameraFrame = onFrame;
1199
+ }
1200
+ /**
1201
+ * Start camera frame capture during an AR session. Must call
1202
+ * setCameraFrameCallback before initAR (the source is created there). No-op if
1203
+ * the source was not initialized (callback not set before initAR).
1204
+ *
1205
+ * The source is the single cadence owner: drive your detection scheduler from
1206
+ * the delivered frames with its own `minIntervalMs: 0` (Option A).
1207
+ *
1208
+ * @param config - optional cadence / blit-resolution overrides.
1209
+ */
1210
+ function startCameraFrameCapture(config) {
1211
+ if (!cameraFrameSource) {
1212
+ log.warn("Cannot start camera frame capture - frame source not initialized");
1213
+ return;
1214
+ }
1215
+ if (typeof config?.captureSize === "number" && Number.isFinite(config.captureSize) && config.captureSize > 0) cameraFrameCaptureSize = Math.floor(config.captureSize);
1216
+ if (config?.intervalMs !== void 0) cameraFrameSource.updateConfig({ intervalMs: config.intervalMs });
1217
+ cameraFrameSource.start();
1218
+ log.info(`Camera frame capture started (interval: ${cameraFrameSource.getConfig().intervalMs}ms, long edge ${cameraFrameCaptureSize}px, aspect-preserved)`);
1219
+ }
1220
+ /**
1221
+ * Stop camera frame capture. Safe to call when not running.
1222
+ */
1223
+ function stopCameraFrameCapture() {
1224
+ if (cameraFrameSource) {
1225
+ const count = cameraFrameSource.getFrameCount();
1226
+ cameraFrameSource.stop();
1227
+ log.info(`Camera frame capture stopped (${count} frames captured)`);
1228
+ }
1229
+ }
1230
+ /**
1231
+ * Get the number of camera frames captured since the last
1232
+ * `startCameraFrameCapture`.
1233
+ */
1234
+ function getCameraFrameCount() {
1235
+ return cameraFrameSource?.getFrameCount() ?? 0;
1236
+ }
1237
+ /**
1238
+ * The current longer-edge resolution (px) of the camera-frame blit — the
1239
+ * {@link DEFAULT_CAMERA_FRAME_CAPTURE_SIZE} default unless overridden via
1240
+ * `startCameraFrameCapture({ captureSize })`. Exposed for diagnostics and to
1241
+ * let tests assert the on-device-tuned default without reaching into module
1242
+ * state.
1243
+ */
1244
+ function getCameraFrameCaptureSize() {
1245
+ return cameraFrameCaptureSize;
1246
+ }
1247
+ /**
1036
1248
  * Set a per-frame callback for custom updates.
1037
1249
  * The callback is invoked every XR frame after pose updates but before render.
1038
1250
  * Useful for updating elements that need to follow the camera smoothly
@@ -1051,4 +1263,4 @@ function getLiveCss3dManager() {
1051
1263
  return css3dManager;
1052
1264
  }
1053
1265
  //#endregion
1054
- export { setTrackingLostCallback as A, setArWorldGroup as C, setImageCaptureCallback as D, setFrameCallback as E, startImageCapture as F, stopDepthCapture as I, stopImageCapture as L, setTrackingStore as M, shouldLogCameraAccessDiagnostic as N, setScene as O, startDepthCapture as P, setArPose as S, setDepthCaptureCallback as T, isWebXRSupported as _, extractPoseFromViewer as a, nueQuaternionToWebXR$1 as b, getArWorldGroup as c, getDepthSampleCount as d, getImageCaptureFrameCount as f, initAR as g, getXrCameraFromPose as h, endARSession as i, setTrackingRecoveredCallback as j, setTrackingCallbacks as k, getCamera as l, getScene as m, buildSessionOptions as n, extractResetTransformData as o, getLiveCss3dManager as p, createSceneHierarchy as r, getArPose as s, applyAlignmentMatrix as t, getCurrentArPose as u, isXRCameraLike as v, setCamera as w, resetWebXRState as x, nuePositionToWebXR as y };
1266
+ export { setFrameCallback as A, startImageCapture as B, nueQuaternionToWebXR$1 as C, setCamera as D, setArWorldGroup as E, setTrackingRecoveredCallback as F, stopDepthCapture as H, setTrackingStore as I, shouldLogCameraAccessDiagnostic as L, setScene as M, setTrackingCallbacks as N, setCameraFrameCallback as O, setTrackingLostCallback as P, startCameraFrameCapture as R, nuePositionToWebXR as S, setArPose as T, stopImageCapture as U, stopCameraFrameCapture as V, CameraFrameSource as W, getScene as _, endARSession as a, isWebXRSupported as b, getArPose as c, getCameraFrameCaptureSize as d, getCameraFrameCount as f, getLiveCss3dManager as g, getImageCaptureFrameCount as h, createSceneHierarchy as i, setImageCaptureCallback as j, setDepthCaptureCallback as k, getArWorldGroup as l, getDepthSampleCount as m, applyAlignmentMatrix as n, extractPoseFromViewer as o, getCurrentArPose as p, buildSessionOptions as r, extractResetTransformData as s, DEFAULT_CAMERA_FRAME_CAPTURE_SIZE as t, getCamera as u, getXrCameraFromPose as v, resetWebXRState as w, isXRCameraLike as x, initAR as y, startDepthCapture as z };