gps-plus-slam-app-framework 1.3.0 → 1.7.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 (247) hide show
  1. package/dist/absolute-orientation-CAEh840t.d.ts +54 -0
  2. package/dist/{app-selectors-B8VQoMDY.d.ts → app-selectors-ikTUQZpe.d.ts} +1 -1
  3. package/dist/ar/bresenham3d.d.ts +1 -1
  4. package/dist/ar/camera-blit-capture.d.ts +2 -2
  5. package/dist/ar/camera-blit-capture.js +74 -9
  6. package/dist/ar/capability-checker.d.ts +1 -1
  7. package/dist/ar/capture-failure-tracker.d.ts +1 -1
  8. package/dist/ar/chromium-camera-access-workaround.d.ts +1 -1
  9. package/dist/ar/depth-grid-lookup.d.ts +2 -0
  10. package/dist/ar/depth-grid-lookup.js +43 -0
  11. package/dist/ar/depth-sampler.d.ts +2 -2
  12. package/dist/ar/depth-sampler.js +2 -4
  13. package/dist/ar/depth-unprojection.d.ts +1 -1
  14. package/dist/ar/enable-gps-ar.d.ts +1 -1
  15. package/dist/ar/enable-gps-ar.js +26 -1
  16. package/dist/ar/frame-loop.d.ts +1 -1
  17. package/dist/ar/image-capture.d.ts +2 -2
  18. package/dist/ar/image-capture.js +1 -154
  19. package/dist/ar/image-quality.d.ts +2 -0
  20. package/dist/ar/image-quality.js +168 -0
  21. package/dist/ar/index.d.ts +31 -19
  22. package/dist/ar/index.js +17 -5
  23. package/dist/ar/occupancy-grid.d.ts +1 -1
  24. package/dist/ar/occupancy-grid.js +29 -2
  25. package/dist/ar/planar-pnp.d.ts +2 -0
  26. package/dist/ar/planar-pnp.js +425 -0
  27. package/dist/ar/qr-debug-view.d.ts +2 -0
  28. package/dist/ar/qr-debug-view.js +89 -0
  29. package/dist/ar/qr-derived-pose.d.ts +2 -0
  30. package/dist/ar/qr-derived-pose.js +114 -0
  31. package/dist/ar/qr-detection-controller.d.ts +2 -0
  32. package/dist/ar/qr-detection-controller.js +2 -0
  33. package/dist/ar/qr-frontend.d.ts +2 -0
  34. package/dist/ar/qr-frontend.js +60 -0
  35. package/dist/ar/qr-pose.d.ts +2 -0
  36. package/dist/ar/qr-pose.js +267 -0
  37. package/dist/ar/qr-size-depth-context.d.ts +3 -0
  38. package/dist/ar/qr-size-depth-context.js +42 -0
  39. package/dist/ar/qr-size-measurer.d.ts +2 -0
  40. package/dist/ar/qr-size-measurer.js +2 -0
  41. package/dist/ar/replay-scene.d.ts +1 -1
  42. package/dist/ar/replay-scene.js +1 -1
  43. package/dist/ar/scene-node-names.d.ts +1 -1
  44. package/dist/ar/webxr-nue-basis.d.ts +1 -1
  45. package/dist/ar/webxr-session.d.ts +4 -4
  46. package/dist/ar/webxr-session.js +2 -2
  47. package/dist/ar/xr-camera-texture.d.ts +1 -1
  48. package/dist/ar/xr-error-handler.d.ts +1 -1
  49. package/dist/ar/xr-frame-loop.d.ts +1 -1
  50. package/dist/ar-MFpFlV7j.js +382 -0
  51. package/dist/{ar-world-group-alignment-C9lwwIyI.d.ts → ar-world-group-alignment-69fgnB39.d.ts} +1 -1
  52. package/dist/{camera-blit-capture-CnxUDbKx.d.ts → camera-blit-capture-NKT9H5-e.d.ts} +57 -4
  53. package/dist/capture-motion-gate-0Yl2NpQG.d.ts +24 -0
  54. package/dist/capture-motion-gate-4EscNZCw.js +94 -0
  55. package/dist/concurrency-By0oOTZt.d.ts +50 -0
  56. package/dist/core/index.d.ts +2 -2
  57. package/dist/core/index.js +2 -2
  58. package/dist/create-slam-app-store-DkCHOpvb.js +149 -0
  59. package/dist/{create-slam-app-store-BljusOua.d.ts → create-slam-app-store-n_VF63D5.d.ts} +50 -40
  60. package/dist/depth-grid-lookup-DQ-IYhO3.d.ts +21 -0
  61. package/dist/{depth-sampler-Bhanfwla.d.ts → depth-sampler-asc8exHt.d.ts} +1 -1
  62. package/dist/{depth-unprojection-Y6i_mJuT.d.ts → depth-unprojection-DjsbJW9L.d.ts} +1 -1
  63. package/dist/{enable-gps-ar-BfUJOgpW.d.ts → enable-gps-ar-DkNhFv4Y.d.ts} +4 -4
  64. package/dist/{frame-conversions-BfsafGWR.d.ts → frame-conversions-DObhj8Wf.d.ts} +1 -1
  65. package/dist/{fused-path-DJoVu98b.d.ts → fused-path-v6eOmLl3.d.ts} +1 -1
  66. package/dist/geo/h3-proximity.d.ts +2 -2
  67. package/dist/geo/h3-proximity.js +61 -2
  68. package/dist/geo/index.d.ts +2 -2
  69. package/dist/geo/index.js +2 -2
  70. package/dist/geodesic-angle-BTldfFgs.js +39 -0
  71. package/dist/{gps-anchor-dYeCvvp5.d.ts → gps-anchor-BeFO2RYa.d.ts} +1 -1
  72. package/dist/{gps-ar-pose-sampler-DVb96iOy.d.ts → gps-ar-pose-sampler-DHMZmYAc.d.ts} +1 -1
  73. package/dist/{gps-event-coordinator-CWIDOk4U.d.ts → gps-event-coordinator-CjWW636x.d.ts} +21 -11
  74. package/dist/{gps-event-markers-Dc9FT-q1.d.ts → gps-event-markers-Cz9RMA2k.d.ts} +18 -0
  75. package/dist/{h3-proximity-I1msGPgE.d.ts → h3-proximity-C-j0pw1j.d.ts} +39 -1
  76. package/dist/image-capture-B2-b6tKK.js +374 -0
  77. package/dist/{image-capture-qAZ5Fh5X.d.ts → image-capture-CNZDrQXG.d.ts} +103 -3
  78. package/dist/image-quality-smCBoFj1.d.ts +158 -0
  79. package/dist/index-BAPokxMb.d.ts +22 -0
  80. package/dist/{index-BYYUdf9v.d.ts → index-BODDUTvD.d.ts} +1 -1
  81. package/dist/index-BneSj4_5.d.ts +399 -0
  82. package/dist/index-_Rhgoqkh.d.ts +2 -0
  83. package/dist/index.d.ts +80 -67
  84. package/dist/index.js +24 -12
  85. package/dist/{leaflet-map-overlay-6CJC-E1l.d.ts → leaflet-map-overlay-CmIyiE8n.d.ts} +1 -1
  86. package/dist/{map-data-CkloBxIl.d.ts → map-data-B4oEehUh.d.ts} +1 -1
  87. package/dist/{map-overlay-draw-krOKwDAq.d.ts → map-overlay-draw-ymz1s7fG.d.ts} +1 -1
  88. package/dist/{null-storage-backend-uKQE8tl7.d.ts → null-storage-backend-B9rtyDfG.d.ts} +2 -2
  89. package/dist/{occupancy-grid-BRNRaPyT.d.ts → occupancy-grid-DnOc-6PU.d.ts} +12 -2
  90. package/dist/{opfs-storage-D5zAn_lx.d.ts → opfs-storage-3VZh-qH6.d.ts} +23 -4
  91. package/dist/{opfs-storage-backend-6aYMUZlJ.d.ts → opfs-storage-backend-JJiUJo-3.d.ts} +3 -3
  92. package/dist/{persistence-middleware-B9ei4Nhx.d.ts → persistence-middleware-DAPTTwB2.d.ts} +1 -1
  93. package/dist/planar-pnp-my9bqULS.d.ts +67 -0
  94. package/dist/qr-debug-view-Brl73HGO.d.ts +29 -0
  95. package/dist/qr-derived-pose-CmxTP2m4.d.ts +122 -0
  96. package/dist/qr-detected-slice-VQssZmQJ.d.ts +166 -0
  97. package/dist/qr-detection-controller-B-tLVd-S.js +119 -0
  98. package/dist/qr-detection-controller-CDurHv8E.d.ts +48 -0
  99. package/dist/qr-frontend--fFX25mV.d.ts +58 -0
  100. package/dist/qr-pose-D2rfu5DA.d.ts +138 -0
  101. package/dist/qr-pose-aggregation-B7tWJq7j.d.ts +90 -0
  102. package/dist/qr-pose-aggregation-DBiaLW0O.js +191 -0
  103. package/dist/qr-size-depth-context-CeAG53fy.d.ts +13 -0
  104. package/dist/qr-size-measurer-DLb33geH.js +596 -0
  105. package/dist/qr-size-measurer-DQdAsid1.d.ts +165 -0
  106. package/dist/recording-options-BPCpMHLK.d.ts +514 -0
  107. package/dist/{recording-replayer-r0DZ9ALp.d.ts → recording-replayer-DQKpAGyQ.d.ts} +2 -2
  108. package/dist/recording-slice-DaxHZvNu.d.ts +55 -0
  109. package/dist/{replay-engine-XpDa0dy1.d.ts → replay-engine-CmKh_4wf.d.ts} +7 -4
  110. package/dist/{replay-scene-Bw58VL6p.d.ts → replay-scene-DBlDrV_x.d.ts} +3 -3
  111. package/dist/sensors/absolute-orientation.d.ts +2 -0
  112. package/dist/sensors/absolute-orientation.js +145 -0
  113. package/dist/sensors/gps-error-handler.d.ts +1 -1
  114. package/dist/sensors/gps.d.ts +1 -1
  115. package/dist/sensors/index.d.ts +5 -4
  116. package/dist/sensors/index.js +2 -1
  117. package/dist/sensors/permission-checker.d.ts +1 -1
  118. package/dist/sensors/permission-checker.js +1 -1
  119. package/dist/state/app-selectors.d.ts +1 -1
  120. package/dist/state/combined-root-state.d.ts +1 -1
  121. package/dist/state/create-slam-app-store.d.ts +1 -1
  122. package/dist/state/create-slam-app-store.js +1 -74
  123. package/dist/state/gps-ar-pose-sampler.d.ts +3 -3
  124. package/dist/state/gps-event-coordinator.d.ts +2 -2
  125. package/dist/state/gps-event-coordinator.js +27 -17
  126. package/dist/state/index.d.ts +20 -17
  127. package/dist/state/index.js +5 -4
  128. package/dist/state/persistence-middleware.d.ts +1 -1
  129. package/dist/state/persistence-middleware.js +30 -19
  130. package/dist/state/qr-detected-slice.d.ts +4 -0
  131. package/dist/state/qr-detected-slice.js +311 -0
  132. package/dist/state/recording-options.d.ts +2 -2
  133. package/dist/state/recording-options.js +273 -7
  134. package/dist/state/recording-replayer.d.ts +2 -2
  135. package/dist/state/recording-replayer.js +1 -1
  136. package/dist/state/recording-slice.d.ts +1 -1
  137. package/dist/state/recording-slice.js +5 -1
  138. package/dist/state/replay-engine.d.ts +1 -1
  139. package/dist/state/replay-engine.js +7 -3
  140. package/dist/state/store-subscribers.d.ts +2 -2
  141. package/dist/state/subscribe-to-selector.d.ts +1 -1
  142. package/dist/state/tracking-quality.d.ts +2 -2
  143. package/dist/state/tracking-quality.js +40 -128
  144. package/dist/state/tracking-slice.d.ts +1 -1
  145. package/dist/{state-BkIfpiyA.js → state-E51QT_-j.js} +2 -1
  146. package/dist/storage/file-system-utils.d.ts +1 -1
  147. package/dist/storage/index.d.ts +9 -9
  148. package/dist/storage/index.js +4 -4
  149. package/dist/storage/null-storage-backend.d.ts +1 -1
  150. package/dist/storage/opfs-storage-backend.d.ts +1 -1
  151. package/dist/storage/opfs-storage-backend.js +3 -3
  152. package/dist/storage/opfs-storage.d.ts +1 -1
  153. package/dist/storage/opfs-storage.js +5 -4
  154. package/dist/storage/storage-backend.d.ts +1 -1
  155. package/dist/storage/zip-coverage-embed.d.ts +2 -0
  156. package/dist/storage/zip-coverage-embed.js +88 -0
  157. package/dist/storage/zip-export.d.ts +2 -2
  158. package/dist/storage/zip-export.js +37 -59
  159. package/dist/storage/zip-reader.d.ts +1 -1
  160. package/dist/{storage-backend-Do6YDpNo.d.ts → storage-backend-BdVLD0dU.d.ts} +1 -1
  161. package/dist/{store-subscribers-0YWyOLvV.d.ts → store-subscribers-CA6AJH_8.d.ts} +2 -2
  162. package/dist/{subscribe-to-selector-CZ6k1NFP.d.ts → subscribe-to-selector-B6EUmQ3I.d.ts} +1 -1
  163. package/dist/test-utils/browser-mocks.d.ts +7 -1
  164. package/dist/test-utils/browser-mocks.js +6 -0
  165. package/dist/test-utils/zip-round-trip-helpers.d.ts +9 -1
  166. package/dist/test-utils/zip-round-trip-helpers.js +5 -1
  167. package/dist/{tracking-slice-CdK8c-8P.d.ts → tracking-slice-BuAZxXZ5.d.ts} +1 -1
  168. package/dist/types/ar-types.d.ts +1 -1
  169. package/dist/types/geo-types.d.ts +1 -1
  170. package/dist/types/index.d.ts +2 -2
  171. package/dist/utils/concurrency.d.ts +2 -2
  172. package/dist/utils/concurrency.js +66 -2
  173. package/dist/utils/failure-tracker.d.ts +1 -1
  174. package/dist/utils/format-file-size.d.ts +1 -1
  175. package/dist/utils/fused-path.d.ts +1 -1
  176. package/dist/utils/index.d.ts +8 -7
  177. package/dist/utils/index.js +2 -1
  178. package/dist/utils/list-formatter.d.ts +1 -1
  179. package/dist/utils/logger.d.ts +1 -1
  180. package/dist/visualization/accuracy-circles.d.ts +1 -1
  181. package/dist/visualization/alignment-lerper.d.ts +1 -1
  182. package/dist/visualization/ar-world-group-alignment.d.ts +1 -1
  183. package/dist/visualization/ar-world-group-alignment.js +1 -1
  184. package/dist/visualization/camera-follower.d.ts +1 -1
  185. package/dist/visualization/css3d-renderer-manager.d.ts +1 -1
  186. package/dist/visualization/frame-conversions.d.ts +1 -1
  187. package/dist/visualization/frustum-visibility.d.ts +1 -1
  188. package/dist/visualization/gps-anchor.d.ts +1 -1
  189. package/dist/visualization/gps-compass-cubes.d.ts +1 -1
  190. package/dist/visualization/gps-event-markers.d.ts +1 -1
  191. package/dist/visualization/gps-event-markers.js +40 -5
  192. package/dist/visualization/hit-test-reticle.d.ts +1 -1
  193. package/dist/visualization/hit-test-reticle.js +1 -0
  194. package/dist/visualization/index.d.ts +18 -18
  195. package/dist/visualization/leaflet-map-overlay.d.ts +1 -1
  196. package/dist/visualization/leaflet-map-overlay.js +15 -3
  197. package/dist/visualization/lerp-utils.d.ts +1 -1
  198. package/dist/visualization/map-data.d.ts +1 -1
  199. package/dist/visualization/map-overlay-draw.d.ts +1 -1
  200. package/dist/visualization/map-overlay.d.ts +1 -1
  201. package/dist/visualization/three-dispose.d.ts +1 -1
  202. package/dist/visualization/vis-colors.d.ts +1 -1
  203. package/dist/{webxr-session-TIaD883f.js → webxr-session-DG-eNfny.js} +244 -11
  204. package/dist/{webxr-session-GjZ2BIpS.d.ts → webxr-session-Do5L6G3B.d.ts} +86 -8
  205. package/dist/zip-coverage-embed-DCAREVmw.d.ts +41 -0
  206. package/dist/{zip-export-G14hkSPG.d.ts → zip-export-ol0S_Ofd.d.ts} +27 -23
  207. package/package.json +2 -2
  208. package/dist/concurrency-CO1FQvs3.d.ts +0 -24
  209. package/dist/file-system-CwXTNHmB.d.ts +0 -114
  210. package/dist/index-CF05QV2m.d.ts +0 -2
  211. package/dist/recording-options-DJBXuMxV.d.ts +0 -182
  212. package/dist/recording-slice-89O07ebs.d.ts +0 -36
  213. package/dist/storage/file-system.d.ts +0 -2
  214. package/dist/storage/file-system.js +0 -289
  215. /package/dist/{accuracy-circles-BpwWAs8G.d.ts → accuracy-circles-BtqOP_v1.d.ts} +0 -0
  216. /package/dist/{alignment-lerper-Dm9G7JJO.d.ts → alignment-lerper-Bil6vbVw.d.ts} +0 -0
  217. /package/dist/{ar-types-Dan1MVTi.d.ts → ar-types-BFX2r1wk.d.ts} +0 -0
  218. /package/dist/{bresenham3d-CFfd7n6B.d.ts → bresenham3d-CU1Gv2W4.d.ts} +0 -0
  219. /package/dist/{camera-follower-C2mwEn7c.d.ts → camera-follower-CqJJ7zRj.d.ts} +0 -0
  220. /package/dist/{capability-checker-CQXJHxXg.d.ts → capability-checker-DUQLg6gq.d.ts} +0 -0
  221. /package/dist/{capture-failure-tracker-CUeU3L_M.d.ts → capture-failure-tracker-gsm8q7yi.d.ts} +0 -0
  222. /package/dist/{chromium-camera-access-workaround-Jqbn0apH.d.ts → chromium-camera-access-workaround-D4K2uwwQ.d.ts} +0 -0
  223. /package/dist/{css3d-renderer-manager-ptu_t3B3.d.ts → css3d-renderer-manager-B3kGNtcn.d.ts} +0 -0
  224. /package/dist/{failure-tracker-Cn8Fo9D4.d.ts → failure-tracker-BO7M7jF_.d.ts} +0 -0
  225. /package/dist/{file-system-utils-CXIoL-DM.d.ts → file-system-utils-DOajnMm-.d.ts} +0 -0
  226. /package/dist/{format-file-size-CLCZz3lC.d.ts → format-file-size-Dc98ulzB.d.ts} +0 -0
  227. /package/dist/{frame-loop-CMewS8cY.d.ts → frame-loop-CpVjQ1dH.d.ts} +0 -0
  228. /package/dist/{frustum-visibility-CmI96ESS.d.ts → frustum-visibility-CeoCZchO.d.ts} +0 -0
  229. /package/dist/{geo-types-SaPnIEUM.d.ts → geo-types-3Ip1NzVR.d.ts} +0 -0
  230. /package/dist/{gps-VuezJWK3.d.ts → gps-BBO3hKfT.d.ts} +0 -0
  231. /package/dist/{gps-compass-cubes-BM1uGiYV.d.ts → gps-compass-cubes-DSN87L8p.d.ts} +0 -0
  232. /package/dist/{gps-error-handler-CJl_2MVm.d.ts → gps-error-handler-BbPsfw-_.d.ts} +0 -0
  233. /package/dist/{hit-test-reticle-BEzEybxZ.d.ts → hit-test-reticle-DV-2TpB9.d.ts} +0 -0
  234. /package/dist/{lerp-utils-BpV-0Dtk.d.ts → lerp-utils-BLmHhkVe.d.ts} +0 -0
  235. /package/dist/{list-formatter-RRcBe8Vg.d.ts → list-formatter-KNMS0ay2.d.ts} +0 -0
  236. /package/dist/{logger-BEHXsnnq.d.ts → logger-CLnPrHiD.d.ts} +0 -0
  237. /package/dist/{map-overlay-bcogY5fK.d.ts → map-overlay-Dh2B97MP.d.ts} +0 -0
  238. /package/dist/{permission-checker-GpAiSCwd.d.ts → permission-checker-CDuI8BwC.d.ts} +0 -0
  239. /package/dist/{scene-node-names-Bu0S66H1.d.ts → scene-node-names-BiShOQDB.d.ts} +0 -0
  240. /package/dist/{session-disposers-M-oashRH.js → session-disposers-zv9OGXPB.js} +0 -0
  241. /package/dist/{three-dispose-D950t71B.d.ts → three-dispose-Bt1k7WKh.d.ts} +0 -0
  242. /package/dist/{vis-colors-D6omC64K.d.ts → vis-colors-Obw2pLqT.d.ts} +0 -0
  243. /package/dist/{webxr-nue-basis-CqKQmZzT.d.ts → webxr-nue-basis-3nfjDJJp.d.ts} +0 -0
  244. /package/dist/{xr-camera-texture-DBwCaKTd.d.ts → xr-camera-texture-Cva1q3Qj.d.ts} +0 -0
  245. /package/dist/{xr-error-handler-C0AQRmxs.d.ts → xr-error-handler-CtvHpjfm.d.ts} +0 -0
  246. /package/dist/{xr-frame-loop-BtYytZJg.d.ts → xr-frame-loop-DIYtRcUa.d.ts} +0 -0
  247. /package/dist/{zip-reader-DSEXt7K6.d.ts → zip-reader-D9iPQwdQ.d.ts} +0 -0
@@ -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-CmIyiE8n.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-BLmHhkVe.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-B4oEehUh.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-ymz1s7fG.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-Dh2B97MP.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-Bt1k7WKh.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-Obw2pLqT.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
- import { DEFAULT_CAPTURE_CONFIG, ImageCaptureManager } from "./ar/image-capture.js";
8
+ import { n as ImageCaptureManager, t as DEFAULT_CAPTURE_CONFIG } from "./image-capture-B2-b6tKK.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-zv9OGXPB.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();
@@ -210,6 +290,14 @@ let onSuspiciousImage = null;
210
290
  */
211
291
  let getScreenRotation = null;
212
292
  /**
293
+ * Off-thread image-quality analyzer (set via {@link setImageQualityAnalyzer}).
294
+ * Device-specific (a Web Worker in the recorder), so it is INJECTED rather than
295
+ * built here. Forwarded to `ImageCaptureManager` as its `analyzeFrame` callback;
296
+ * the manager only invokes it when `config.qualityFilter.enabled`. `null` ⇒ the
297
+ * legacy save-immediately path.
298
+ */
299
+ let imageQualityAnalyzer = null;
300
+ /**
213
301
  * Redux store injected by the host (`setTrackingStore`). When present
214
302
  * together with `onTrackingRestarted`, `onXRFrame` dispatches
215
303
  * `poseReceived`/`poseLost`, the XR reference-space reset listener
@@ -285,6 +373,53 @@ const DEPTH_RGB_BLIT_CONFIG = {
285
373
  height: 192
286
374
  };
287
375
  /**
376
+ * Session-owned blit target for the generic camera-frame RGBA capture
377
+ * (framework-wiring options Part A / B2) — feeds QR detection today, object
378
+ * detection / OpenCV later. Separate from `depthRgbBlit` (256×192) on purpose:
379
+ * CV detection needs more pixels across the target (~1024 long edge) than a
380
+ * colour lookup, but only at the detection cadence, so the {@link CameraFrameSource}
381
+ * throttle keeps the readback off the per-frame path. Created lazily on the
382
+ * first capture, disposed by resetWebXRState(). The longer-edge size is
383
+ * configurable via `startCameraFrameCapture`; the blit preserves the camera
384
+ * aspect (see `acquireCameraFrameRgba`).
385
+ */
386
+ let cameraFrameBlit = null;
387
+ /**
388
+ * Default longer-edge resolution (px) for the camera-frame blit the QR / CV
389
+ * detector sees. The on-device capture-resolution sweep (2026-06-17, via the
390
+ * `?capture=` override) showed **1024** decodes a small / out-of-focus QR
391
+ * markedly better than the prior 512 with no perceptible cadence cost on the
392
+ * test phone; 2048 helped slightly more but risks low-end devices (4096 lagged),
393
+ * so 1024 is the safe default. Raise per-consumer via
394
+ * `startCameraFrameCapture({ captureSize })`.
395
+ *
396
+ * @see GpsPlusSlamJs_Docs/docs/2026-06-17-qr-size-accuracy-and-thin-demo-plan.md (WS-C)
397
+ */
398
+ const DEFAULT_CAMERA_FRAME_CAPTURE_SIZE = 1024;
399
+ /**
400
+ * Longer-edge resolution of the camera-frame blit (px), default
401
+ * {@link DEFAULT_CAMERA_FRAME_CAPTURE_SIZE}. The blit preserves the camera
402
+ * aspect, so the actual target is e.g. 1024×768 for a 4:3 frame — see
403
+ * `computeAspectFitSize` / `acquireCameraFrameRgba`.
404
+ */
405
+ let cameraFrameCaptureSize = DEFAULT_CAMERA_FRAME_CAPTURE_SIZE;
406
+ /**
407
+ * Throttled camera frame source (created in initAR when `onCameraFrame` is
408
+ * set). Blits the camera texture to RGBA at the detection cadence and hands it
409
+ * to `onCameraFrame`. @see camera-frame-source.ts
410
+ *
411
+ * SINGLE consumer by design: one source, one callback, one blit. That covers
412
+ * one CV consumer at a time (QR *or* object detection). To run two live CV
413
+ * consumers **simultaneously** at independent cadences/resolutions, replace this
414
+ * single-callback wiring with a small registry (e.g.
415
+ * `registerCameraFrameConsumer({ intervalMs, captureSize, onFrame })`) holding a
416
+ * `CameraFrameSource` per consumer — the class is already per-instance. See the
417
+ * SCOPE note in `camera-frame-source.ts`.
418
+ */
419
+ let cameraFrameSource = null;
420
+ /** Callback for each throttled camera RGBA frame (set via setCameraFrameCallback). */
421
+ let onCameraFrame = null;
422
+ /**
288
423
  * Latest WebXR camera texture, updated each frame when camera-access is enabled.
289
424
  * Acquired via Three.js's renderer.xr.getCameraTexture() API (ExternalTexture).
290
425
  * @see xr-camera-texture.ts
@@ -333,6 +468,20 @@ function acquireDepthRgbLookup() {
333
468
  return readback ? createRgbLookup(readback.pixels, readback.width, readback.height) : null;
334
469
  }
335
470
  /**
471
+ * Capture the current XR frame as top-left RGBA for CV detection (the
472
+ * `capture` injected into {@link CameraFrameSource}; called at most once per
473
+ * detection interval). Returns null — no frame this tick — when camera access
474
+ * or the texture is unavailable; the lazy blit makes a disposal elsewhere
475
+ * self-healing. Reuses `latestCameraTexture`, exactly like the depth-RGB path.
476
+ */
477
+ function acquireCameraFrameRgba() {
478
+ if (!renderer || !latestCameraTexture) return null;
479
+ const target = computeAspectFitSize(latestCameraWidth, latestCameraHeight, cameraFrameCaptureSize);
480
+ if (!cameraFrameBlit) cameraFrameBlit = new CameraBlitCapture(target);
481
+ else cameraFrameBlit.resizeIfNeeded(target.width, target.height);
482
+ return cameraFrameBlit.captureToRgba(renderer, latestCameraTexture);
483
+ }
484
+ /**
336
485
  * Extract the reset transform from an XRReferenceSpaceEvent-like object.
337
486
  *
338
487
  * Distinguishes three cases per OdometryTrackingRestartedPayload semantics:
@@ -563,6 +712,13 @@ async function initAR(container, isolationOptions = {}, sessionFeatures = {}) {
563
712
  acquireRgbLookup: acquireDepthRgbLookup,
564
713
  onDepthUnavailable: onDepthUnavailable ?? void 0
565
714
  });
715
+ if (onCameraFrame) {
716
+ const deliver = onCameraFrame;
717
+ cameraFrameSource = new CameraFrameSource({
718
+ capture: acquireCameraFrameRgba,
719
+ onCapture: (image) => deliver(image)
720
+ });
721
+ }
566
722
  renderer.setAnimationLoop(onXRFrame);
567
723
  log.info("AR session started");
568
724
  }
@@ -681,6 +837,7 @@ function onXRFrame(time, frame) {
681
837
  const depthInfo = getDepthInfoFromFrame(frame, pose);
682
838
  depthSampler.onFrame(time, depthInfo);
683
839
  }
840
+ if (cameraFrameSource) cameraFrameSource.onFrame(time);
684
841
  if (onFrameCallback) try {
685
842
  onFrameCallback();
686
843
  } catch (error) {
@@ -860,6 +1017,18 @@ function setImageCaptureCallback(onCaptured, screenRotationGetter, onFailed, onS
860
1017
  onSuspiciousImage = onSuspicious ?? null;
861
1018
  }
862
1019
  /**
1020
+ * Inject (or clear) the off-thread image-quality analyzer used by the blur/
1021
+ * blackness drop+retry gate. Pass the recorder's Web Worker-backed analyzer to
1022
+ * enable the gate, or `null` to clear it (legacy save-immediately path). Must be
1023
+ * set BEFORE {@link startImageCapture} for the active recording — the manager
1024
+ * reads it once when constructed. The analyzer only runs when the capture
1025
+ * config's `qualityFilter.enabled` is true, so injecting it is harmless when the
1026
+ * gate is off. Ownership/disposal of the worker is the caller's responsibility.
1027
+ */
1028
+ function setImageQualityAnalyzer(analyzer) {
1029
+ imageQualityAnalyzer = analyzer;
1030
+ }
1031
+ /**
863
1032
  * Start capturing images during recording.
864
1033
  * Must call setImageCaptureCallback first.
865
1034
  *
@@ -887,7 +1056,8 @@ function startImageCapture(config) {
887
1056
  getScreenRotation,
888
1057
  onCaptured: onImageCaptured,
889
1058
  onCaptureFailed: onCaptureFailed ?? void 0,
890
- onSuspiciousImage: onSuspiciousImage ?? void 0
1059
+ onSuspiciousImage: onSuspiciousImage ?? void 0,
1060
+ analyzeFrame: imageQualityAnalyzer ?? void 0
891
1061
  };
892
1062
  const mergedConfig = {
893
1063
  ...DEFAULT_CAPTURE_CONFIG,
@@ -897,7 +1067,8 @@ function startImageCapture(config) {
897
1067
  const currentRenderer = renderer;
898
1068
  const divisor = mergedConfig.resolutionDivisor;
899
1069
  callbacks.captureFrame = async (quality) => {
900
- if (!blitCapture || !latestCameraTexture) {
1070
+ const bc = blitCapture;
1071
+ if (!bc || !latestCameraTexture) {
901
1072
  const canvas = currentRenderer.domElement;
902
1073
  return new Promise((resolve) => {
903
1074
  canvas.toBlob((blob) => resolve(blob ? {
@@ -909,14 +1080,14 @@ function startImageCapture(config) {
909
1080
  }
910
1081
  if (latestCameraWidth > 0 && latestCameraHeight > 0) {
911
1082
  const target = computeCaptureSize(latestCameraWidth, latestCameraHeight, divisor);
912
- blitCapture.resizeIfNeeded(target.width, target.height);
1083
+ bc.resizeIfNeeded(target.width, target.height);
913
1084
  }
914
- const blob = await blitCapture.captureToBlob(currentRenderer, latestCameraTexture, quality);
1085
+ const blob = await bc.captureToBlob(currentRenderer, latestCameraTexture, quality);
915
1086
  if (!blob) return null;
916
1087
  return {
917
1088
  blob,
918
- width: blitCapture.getWidth(),
919
- height: blitCapture.getHeight()
1089
+ width: bc.getWidth(),
1090
+ height: bc.getHeight()
920
1091
  };
921
1092
  };
922
1093
  log.info(`Blit capture pipeline initialized (resolutionDivisor=${divisor})`);
@@ -1033,6 +1204,68 @@ function getDepthSampleCount() {
1033
1204
  return depthSampler?.getSampleCount() ?? 0;
1034
1205
  }
1035
1206
  /**
1207
+ * Set the per-frame camera RGBA callback (B2) — the generic CV frame feed (QR
1208
+ * detection today, object detection / OpenCV later). Call this BEFORE initAR to
1209
+ * enable in-session camera frame capture; `startCameraFrameCapture` then begins
1210
+ * delivering frames.
1211
+ *
1212
+ * The callback receives a **top-left-origin** RGBA image (no JPEG round-trip),
1213
+ * captured at the throttled detection cadence — feed it straight to a
1214
+ * `BarcodeDetector` / OpenCV front-end. Mirrors `setDepthCaptureCallback`.
1215
+ *
1216
+ * @param onFrame - Called with each throttled camera frame, or `null` to clear.
1217
+ */
1218
+ function setCameraFrameCallback(onFrame) {
1219
+ onCameraFrame = onFrame;
1220
+ }
1221
+ /**
1222
+ * Start camera frame capture during an AR session. Must call
1223
+ * setCameraFrameCallback before initAR (the source is created there). No-op if
1224
+ * the source was not initialized (callback not set before initAR).
1225
+ *
1226
+ * The source is the single cadence owner: drive your detection scheduler from
1227
+ * the delivered frames with its own `minIntervalMs: 0` (Option A).
1228
+ *
1229
+ * @param config - optional cadence / blit-resolution overrides.
1230
+ */
1231
+ function startCameraFrameCapture(config) {
1232
+ if (!cameraFrameSource) {
1233
+ log.warn("Cannot start camera frame capture - frame source not initialized");
1234
+ return;
1235
+ }
1236
+ if (typeof config?.captureSize === "number" && Number.isFinite(config.captureSize) && config.captureSize > 0) cameraFrameCaptureSize = Math.floor(config.captureSize);
1237
+ if (config?.intervalMs !== void 0) cameraFrameSource.updateConfig({ intervalMs: config.intervalMs });
1238
+ cameraFrameSource.start();
1239
+ log.info(`Camera frame capture started (interval: ${cameraFrameSource.getConfig().intervalMs}ms, long edge ${cameraFrameCaptureSize}px, aspect-preserved)`);
1240
+ }
1241
+ /**
1242
+ * Stop camera frame capture. Safe to call when not running.
1243
+ */
1244
+ function stopCameraFrameCapture() {
1245
+ if (cameraFrameSource) {
1246
+ const count = cameraFrameSource.getFrameCount();
1247
+ cameraFrameSource.stop();
1248
+ log.info(`Camera frame capture stopped (${count} frames captured)`);
1249
+ }
1250
+ }
1251
+ /**
1252
+ * Get the number of camera frames captured since the last
1253
+ * `startCameraFrameCapture`.
1254
+ */
1255
+ function getCameraFrameCount() {
1256
+ return cameraFrameSource?.getFrameCount() ?? 0;
1257
+ }
1258
+ /**
1259
+ * The current longer-edge resolution (px) of the camera-frame blit — the
1260
+ * {@link DEFAULT_CAMERA_FRAME_CAPTURE_SIZE} default unless overridden via
1261
+ * `startCameraFrameCapture({ captureSize })`. Exposed for diagnostics and to
1262
+ * let tests assert the on-device-tuned default without reaching into module
1263
+ * state.
1264
+ */
1265
+ function getCameraFrameCaptureSize() {
1266
+ return cameraFrameCaptureSize;
1267
+ }
1268
+ /**
1036
1269
  * Set a per-frame callback for custom updates.
1037
1270
  * The callback is invoked every XR frame after pose updates but before render.
1038
1271
  * Useful for updating elements that need to follow the camera smoothly
@@ -1051,4 +1284,4 @@ function getLiveCss3dManager() {
1051
1284
  return css3dManager;
1052
1285
  }
1053
1286
  //#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 };
1287
+ export { setFrameCallback as A, startDepthCapture as B, nueQuaternionToWebXR$1 as C, setCamera as D, setArWorldGroup as E, setTrackingLostCallback as F, CameraFrameSource as G, stopCameraFrameCapture as H, setTrackingRecoveredCallback as I, setTrackingStore as L, setImageQualityAnalyzer as M, setScene as N, setCameraFrameCallback as O, setTrackingCallbacks as P, shouldLogCameraAccessDiagnostic as R, nuePositionToWebXR as S, setArPose as T, stopDepthCapture as U, startImageCapture as V, stopImageCapture 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, startCameraFrameCapture as z };
@@ -1,10 +1,11 @@
1
- import { i as DepthSample, t as ARPose } from "./ar-types-Dan1MVTi.js";
2
- import { i as DepthSamplerConfig } from "./depth-sampler-Bhanfwla.js";
3
- import { t as ArCrashIsolationOptions } from "./recording-options-DJBXuMxV.js";
4
- import { a as ImageCaptureConfig, n as CapturedImage } from "./image-capture-qAZ5Fh5X.js";
5
- import { a as TrackingSliceState, r as ResetTransformData } from "./tracking-slice-CdK8c-8P.js";
6
- import { t as Css3dRendererManager } from "./css3d-renderer-manager-ptu_t3B3.js";
7
- import { r as XRCameraLike } from "./xr-camera-texture-DBwCaKTd.js";
1
+ import { i as DepthSample, t as ARPose } from "./ar-types-BFX2r1wk.js";
2
+ import { i as DepthSamplerConfig } from "./depth-sampler-asc8exHt.js";
3
+ import { t as ArCrashIsolationOptions } from "./recording-options-BPCpMHLK.js";
4
+ import { i as FrameQualityVerdict, n as CapturedImage, o as ImageCaptureConfig, t as CapturedFrame } from "./image-capture-CNZDrQXG.js";
5
+ import { a as TrackingSliceState, r as ResetTransformData } from "./tracking-slice-BuAZxXZ5.js";
6
+ import { o as RgbaImage } from "./qr-frontend--fFX25mV.js";
7
+ import { t as Css3dRendererManager } from "./css3d-renderer-manager-B3kGNtcn.js";
8
+ import { r as XRCameraLike } from "./xr-camera-texture-Cva1q3Qj.js";
8
9
  import * as THREE from "three";
9
10
  import { OdometryTrackingRestartedPayload } from "gps-plus-slam-js";
10
11
 
@@ -68,6 +69,18 @@ declare function shouldLogCameraAccessDiagnostic(pose: XRViewerPose | null, alre
68
69
  * @internal
69
70
  */
70
71
  declare function resetWebXRState(): void;
72
+ /**
73
+ * Default longer-edge resolution (px) for the camera-frame blit the QR / CV
74
+ * detector sees. The on-device capture-resolution sweep (2026-06-17, via the
75
+ * `?capture=` override) showed **1024** decodes a small / out-of-focus QR
76
+ * markedly better than the prior 512 with no perceptible cadence cost on the
77
+ * test phone; 2048 helped slightly more but risks low-end devices (4096 lagged),
78
+ * so 1024 is the safe default. Raise per-consumer via
79
+ * `startCameraFrameCapture({ captureSize })`.
80
+ *
81
+ * @see GpsPlusSlamJs_Docs/docs/2026-06-17-qr-size-accuracy-and-thin-demo-plan.md (WS-C)
82
+ */
83
+ declare const DEFAULT_CAMERA_FRAME_CAPTURE_SIZE = 1024;
71
84
  /**
72
85
  * Extract the reset transform from an XRReferenceSpaceEvent-like object.
73
86
  *
@@ -292,6 +305,16 @@ declare function endARSession(): Promise<void>;
292
305
  * @param onSuspicious - Optional callback for when a captured image appears black/empty
293
306
  */
294
307
  declare function setImageCaptureCallback(onCaptured: (image: CapturedImage) => void, screenRotationGetter: () => number, onFailed?: () => void, onSuspicious?: (blobSize: number, frameIndex: number) => void): void;
308
+ /**
309
+ * Inject (or clear) the off-thread image-quality analyzer used by the blur/
310
+ * blackness drop+retry gate. Pass the recorder's Web Worker-backed analyzer to
311
+ * enable the gate, or `null` to clear it (legacy save-immediately path). Must be
312
+ * set BEFORE {@link startImageCapture} for the active recording — the manager
313
+ * reads it once when constructed. The analyzer only runs when the capture
314
+ * config's `qualityFilter.enabled` is true, so injecting it is harmless when the
315
+ * gate is off. Ownership/disposal of the worker is the caller's responsibility.
316
+ */
317
+ declare function setImageQualityAnalyzer(analyzer: ((frame: CapturedFrame) => Promise<FrameQualityVerdict>) | null): void;
295
318
  /**
296
319
  * Start capturing images during recording.
297
320
  * Must call setImageCaptureCallback first.
@@ -371,6 +394,61 @@ declare function stopDepthCapture(): void;
371
394
  * Get the current depth sample count.
372
395
  */
373
396
  declare function getDepthSampleCount(): number;
397
+ /** Optional tuning for {@link startCameraFrameCapture}. */
398
+ interface CameraFrameCaptureConfig {
399
+ /** Detection cadence (ms between captures). Default 125 (~8 Hz). */
400
+ intervalMs?: number;
401
+ /**
402
+ * Longer-edge resolution (px) of the camera-frame blit. Default
403
+ * {@link DEFAULT_CAMERA_FRAME_CAPTURE_SIZE} (1024). The blit preserves the
404
+ * camera ASPECT with its longer edge at this value (e.g. 1024 → 1024×768 for a
405
+ * 4:3 camera), so the target reaches the detector undistorted. A QR needs ~3–5
406
+ * px per module; the on-device sweep settled on 1024 (512 made small QRs decode
407
+ * only at very close range). Applied before the first capture.
408
+ */
409
+ captureSize?: number;
410
+ }
411
+ /**
412
+ * Set the per-frame camera RGBA callback (B2) — the generic CV frame feed (QR
413
+ * detection today, object detection / OpenCV later). Call this BEFORE initAR to
414
+ * enable in-session camera frame capture; `startCameraFrameCapture` then begins
415
+ * delivering frames.
416
+ *
417
+ * The callback receives a **top-left-origin** RGBA image (no JPEG round-trip),
418
+ * captured at the throttled detection cadence — feed it straight to a
419
+ * `BarcodeDetector` / OpenCV front-end. Mirrors `setDepthCaptureCallback`.
420
+ *
421
+ * @param onFrame - Called with each throttled camera frame, or `null` to clear.
422
+ */
423
+ declare function setCameraFrameCallback(onFrame: ((image: RgbaImage) => void) | null): void;
424
+ /**
425
+ * Start camera frame capture during an AR session. Must call
426
+ * setCameraFrameCallback before initAR (the source is created there). No-op if
427
+ * the source was not initialized (callback not set before initAR).
428
+ *
429
+ * The source is the single cadence owner: drive your detection scheduler from
430
+ * the delivered frames with its own `minIntervalMs: 0` (Option A).
431
+ *
432
+ * @param config - optional cadence / blit-resolution overrides.
433
+ */
434
+ declare function startCameraFrameCapture(config?: CameraFrameCaptureConfig): void;
435
+ /**
436
+ * Stop camera frame capture. Safe to call when not running.
437
+ */
438
+ declare function stopCameraFrameCapture(): void;
439
+ /**
440
+ * Get the number of camera frames captured since the last
441
+ * `startCameraFrameCapture`.
442
+ */
443
+ declare function getCameraFrameCount(): number;
444
+ /**
445
+ * The current longer-edge resolution (px) of the camera-frame blit — the
446
+ * {@link DEFAULT_CAMERA_FRAME_CAPTURE_SIZE} default unless overridden via
447
+ * `startCameraFrameCapture({ captureSize })`. Exposed for diagnostics and to
448
+ * let tests assert the on-device-tuned default without reaching into module
449
+ * state.
450
+ */
451
+ declare function getCameraFrameCaptureSize(): number;
374
452
  /**
375
453
  * Set a per-frame callback for custom updates.
376
454
  * The callback is invoked every XR frame after pose updates but before render.
@@ -386,4 +464,4 @@ declare function setFrameCallback(callback: (() => void) | null): void;
386
464
  */
387
465
  declare function getLiveCss3dManager(): Css3dRendererManager | null;
388
466
  //#endregion
389
- export { setScene as A, resetWebXRState as C, setDepthCaptureCallback as D, setCamera as E, shouldLogCameraAccessDiagnostic as F, startDepthCapture as I, startImageCapture as L, setTrackingLostCallback as M, setTrackingRecoveredCallback as N, setFrameCallback as O, setTrackingStore as P, stopDepthCapture as R, nueQuaternionToWebXR$1 as S, setArWorldGroup as T, getXrCameraFromPose as _, createSceneHierarchy as a, isXRCameraLike as b, extractResetTransformData as c, getCamera as d, getCurrentArPose as f, getScene as g, getLiveCss3dManager as h, buildSessionOptions as i, setTrackingCallbacks as j, setImageCaptureCallback as k, getArPose as l, getImageCaptureFrameCount as m, TrackingSubscribableStore as n, endARSession as o, getDepthSampleCount as p, applyAlignmentMatrix as r, extractPoseFromViewer as s, SessionFeatureOptions as t, getArWorldGroup as u, initAR as v, setArPose as w, nuePositionToWebXR as x, isWebXRSupported as y, stopImageCapture as z };
467
+ export { setCamera as A, setTrackingStore as B, isWebXRSupported as C, resetWebXRState as D, nueQuaternionToWebXR$1 as E, setImageQualityAnalyzer as F, stopCameraFrameCapture as G, startCameraFrameCapture as H, setScene as I, stopDepthCapture as K, setTrackingCallbacks as L, setDepthCaptureCallback as M, setFrameCallback as N, setArPose as O, setImageCaptureCallback as P, setTrackingLostCallback as R, initAR as S, nuePositionToWebXR as T, startDepthCapture as U, shouldLogCameraAccessDiagnostic as V, startImageCapture as W, getDepthSampleCount as _, applyAlignmentMatrix as a, getScene as b, endARSession as c, getArPose as d, getArWorldGroup as f, getCurrentArPose as g, getCameraFrameCount as h, TrackingSubscribableStore as i, setCameraFrameCallback as j, setArWorldGroup as k, extractPoseFromViewer as l, getCameraFrameCaptureSize as m, DEFAULT_CAMERA_FRAME_CAPTURE_SIZE as n, buildSessionOptions as o, getCamera as p, stopImageCapture as q, SessionFeatureOptions as r, createSceneHierarchy as s, CameraFrameCaptureConfig as t, extractResetTransformData as u, getImageCaptureFrameCount as v, isXRCameraLike as w, getXrCameraFromPose as x, getLiveCss3dManager as y, setTrackingRecoveredCallback as z };
@@ -0,0 +1,41 @@
1
+ //#region ../src/storage/zip-coverage-embed.d.ts
2
+ /**
3
+ * Zip Coverage Embed — write a recording's H3 coverage into its `session.json`.
4
+ *
5
+ * The map-centric browser indexes legacy recordings (those predating the
6
+ * `h3Cells` field) by reading their full GPS path — slow, and repeated on every
7
+ * folder open. This primitive lets a one-time "upgrade" embed the derived
8
+ * coverage **inside the recording's own `session.json`**, so the recording
9
+ * indexes instantly on every future open in this app *and any other reader*
10
+ * (the portability the user asked for; O3 — in-zip rewrite).
11
+ *
12
+ * It is a pure transform `(zip, cells, resolution) -> zip`: it reads every entry
13
+ * and re-emits a new zip identical to the input except that `session.json` gains
14
+ * `h3Cells` + `h3Resolution`. It never mutates anything in place — the caller
15
+ * (the RecorderApp backfill) owns the safe write-then-verify-then-overwrite
16
+ * protocol around it.
17
+ *
18
+ * @see ./zip-coverage-embed.ts.md
19
+ * @see GpsPlusSlamJs_Docs/docs/2026-06-14-followup-progressive-map-browser-indexing-and-backfill.md (B3)
20
+ */
21
+ /**
22
+ * Return a new zip blob identical to `zip` except its `session.json` gains
23
+ * `h3Cells` + `h3Resolution`.
24
+ *
25
+ * **Skips (returns the input blob unchanged, by reference) when:**
26
+ * - the zip has no `session.json` (nothing to embed into);
27
+ * - `session.json` is present but unparseable (never write over a broken one);
28
+ * - `session.json` already carries `h3Cells` (idempotent — re-running the
29
+ * upgrade is a no-op, and new recordings are skipped).
30
+ *
31
+ * On any unexpected read/write failure it also returns the input untouched —
32
+ * it never emits a partial zip. Callers can detect a skip via reference
33
+ * equality (`result === zip`).
34
+ *
35
+ * Built on `@zip.js/zip.js` (the same library as the exporter) in store mode, so
36
+ * every non-`session.json` entry is re-emitted with byte-identical uncompressed
37
+ * content.
38
+ */
39
+ declare function embedCoverageInSessionJson(zip: Blob, h3Cells: string[], h3Resolution: number): Promise<Blob>;
40
+ //#endregion
41
+ export { embedCoverageInSessionJson as t };