gps-plus-slam-app-framework 1.2.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 (230) hide show
  1. package/dist/{app-selectors-CcZ5UV-8.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 +87 -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 +2 -2
  17. package/dist/ar/image-capture.js +7 -5
  18. package/dist/ar/index.d.ts +30 -19
  19. package/dist/ar/index.js +15 -4
  20. package/dist/ar/occupancy-grid.d.ts +1 -1
  21. package/dist/ar/occupancy-grid.js +29 -2
  22. package/dist/ar/planar-pnp.d.ts +2 -0
  23. package/dist/ar/planar-pnp.js +425 -0
  24. package/dist/ar/qr-debug-view.d.ts +2 -0
  25. package/dist/ar/qr-debug-view.js +89 -0
  26. package/dist/ar/qr-derived-pose.d.ts +2 -0
  27. package/dist/ar/qr-derived-pose.js +114 -0
  28. package/dist/ar/qr-detection-controller.d.ts +2 -0
  29. package/dist/ar/qr-detection-controller.js +2 -0
  30. package/dist/ar/qr-frontend.d.ts +2 -0
  31. package/dist/ar/qr-frontend.js +60 -0
  32. package/dist/ar/qr-pose.d.ts +2 -0
  33. package/dist/ar/qr-pose.js +267 -0
  34. package/dist/ar/qr-size-depth-context.d.ts +3 -0
  35. package/dist/ar/qr-size-depth-context.js +42 -0
  36. package/dist/ar/qr-size-measurer.d.ts +2 -0
  37. package/dist/ar/qr-size-measurer.js +2 -0
  38. package/dist/ar/replay-scene.d.ts +1 -1
  39. package/dist/ar/replay-scene.js +1 -1
  40. package/dist/ar/scene-node-names.d.ts +1 -1
  41. package/dist/ar/webxr-nue-basis.d.ts +1 -1
  42. package/dist/ar/webxr-session.d.ts +4 -4
  43. package/dist/ar/webxr-session.js +2 -2
  44. package/dist/ar/xr-camera-texture.d.ts +1 -1
  45. package/dist/ar/xr-error-handler.d.ts +1 -1
  46. package/dist/ar/xr-frame-loop.d.ts +1 -1
  47. package/dist/ar-Dc72Ksiu.js +382 -0
  48. package/dist/{ar-world-group-alignment-ColHB_5A.d.ts → ar-world-group-alignment-DDLkgNf_.d.ts} +1 -1
  49. package/dist/{camera-blit-capture-D5_mNhla.d.ts → camera-blit-capture-CqWe1G7s.d.ts} +66 -4
  50. package/dist/concurrency-DqAlKX4j.d.ts +50 -0
  51. package/dist/core/index.d.ts +1 -1
  52. package/dist/{create-slam-app-store-qNXQ-tq5.d.ts → create-slam-app-store-Ce2FMKCp.d.ts} +5 -5
  53. package/dist/depth-grid-lookup-vMDrGTk_.d.ts +21 -0
  54. package/dist/{depth-sampler-Bhanfwla.d.ts → depth-sampler-DwfPYzS7.d.ts} +1 -1
  55. package/dist/{depth-unprojection-Y6i_mJuT.d.ts → depth-unprojection-CK3b9htH.d.ts} +1 -1
  56. package/dist/{enable-gps-ar-CapmADVN.d.ts → enable-gps-ar-CjZ1nEdu.d.ts} +4 -4
  57. package/dist/file-system-utils-Bs7lpeVP.d.ts +40 -0
  58. package/dist/{frame-conversions-BfsafGWR.d.ts → frame-conversions-D_Af8Dt3.d.ts} +1 -1
  59. package/dist/{fused-path-DJoVu98b.d.ts → fused-path-C0FHe67t.d.ts} +1 -1
  60. package/dist/geo/h3-proximity.d.ts +2 -2
  61. package/dist/geo/h3-proximity.js +61 -2
  62. package/dist/geo/index.d.ts +2 -2
  63. package/dist/geo/index.js +2 -2
  64. package/dist/{gps-anchor-dYeCvvp5.d.ts → gps-anchor-C6I9NDHA.d.ts} +1 -1
  65. package/dist/{gps-ar-pose-sampler-DVb96iOy.d.ts → gps-ar-pose-sampler-DaHg2aPZ.d.ts} +1 -1
  66. package/dist/{gps-event-coordinator-BDIQde2x.d.ts → gps-event-coordinator-C7hwHyLA.d.ts} +3 -3
  67. package/dist/{gps-event-markers-Dc9FT-q1.d.ts → gps-event-markers-Dd0G2bD0.d.ts} +18 -0
  68. package/dist/{h3-proximity-I1msGPgE.d.ts → h3-proximity-B57C6rYL.d.ts} +39 -1
  69. package/dist/{image-capture-DZ4HFRgS.d.ts → image-capture-C2Feywet.d.ts} +30 -4
  70. package/dist/index-BvLo2poy.d.ts +399 -0
  71. package/dist/{index-KJq2amHF.d.ts → index-m_LneUSi.d.ts} +1 -1
  72. package/dist/index.d.ts +77 -67
  73. package/dist/index.js +18 -9
  74. package/dist/{leaflet-map-overlay-6CJC-E1l.d.ts → leaflet-map-overlay-bnb2U1NQ.d.ts} +1 -1
  75. package/dist/{map-data-CkloBxIl.d.ts → map-data-DdjPiSav.d.ts} +1 -1
  76. package/dist/{map-overlay-draw-krOKwDAq.d.ts → map-overlay-draw-CPVdAsFq.d.ts} +1 -1
  77. package/dist/{null-storage-backend-CxEjZHRW.d.ts → null-storage-backend-CuSdYFsM.d.ts} +2 -2
  78. package/dist/{occupancy-grid-BRNRaPyT.d.ts → occupancy-grid-Bvi2Gw1U.d.ts} +12 -2
  79. package/dist/{opfs-storage-DYm8WHq7.d.ts → opfs-storage-DMtlt57S.d.ts} +25 -6
  80. package/dist/{opfs-storage-backend-CjSAuqg_.d.ts → opfs-storage-backend-CeQAb0SD.d.ts} +3 -3
  81. package/dist/{persistence-middleware-DwyzgfWr.d.ts → persistence-middleware-5eearhSV.d.ts} +1 -1
  82. package/dist/planar-pnp-cjthe7Be.d.ts +67 -0
  83. package/dist/qr-debug-view-B8gTzjMm.d.ts +29 -0
  84. package/dist/qr-derived-pose-DinKE600.d.ts +122 -0
  85. package/dist/qr-detected-slice-Cpv-dg82.d.ts +166 -0
  86. package/dist/qr-detection-controller-B-tLVd-S.js +119 -0
  87. package/dist/qr-detection-controller-Cd2Ih4cC.d.ts +48 -0
  88. package/dist/qr-frontend-DufZp2xS.d.ts +58 -0
  89. package/dist/qr-pose-Bt2reSw7.d.ts +138 -0
  90. package/dist/qr-pose-aggregation-CFlmLm6w.d.ts +90 -0
  91. package/dist/qr-pose-aggregation-DXR9STHs.js +200 -0
  92. package/dist/qr-size-depth-context-onu36E9s.d.ts +13 -0
  93. package/dist/qr-size-measurer-D7739ZpB.d.ts +165 -0
  94. package/dist/qr-size-measurer-DLb33geH.js +596 -0
  95. package/dist/recording-options-D93kksJU.d.ts +369 -0
  96. package/dist/{recording-replayer-BL-x-7k0.d.ts → recording-replayer-CUEK82tM.d.ts} +2 -2
  97. package/dist/recording-slice-B-uCgGoh.d.ts +55 -0
  98. package/dist/{replay-engine-BRqszuQ9.d.ts → replay-engine-BSVd7Zzb.d.ts} +7 -4
  99. package/dist/{replay-scene-Bw58VL6p.d.ts → replay-scene-CPt56pps.d.ts} +3 -3
  100. package/dist/sensors/gps-error-handler.d.ts +1 -1
  101. package/dist/sensors/gps.d.ts +1 -1
  102. package/dist/sensors/index.d.ts +3 -3
  103. package/dist/sensors/permission-checker.d.ts +1 -1
  104. package/dist/sensors/permission-checker.js +1 -1
  105. package/dist/state/app-selectors.d.ts +1 -1
  106. package/dist/state/app-selectors.js +3 -1
  107. package/dist/state/combined-root-state.d.ts +1 -1
  108. package/dist/state/create-slam-app-store.d.ts +1 -1
  109. package/dist/state/gps-ar-pose-sampler.d.ts +3 -3
  110. package/dist/state/gps-event-coordinator.d.ts +1 -1
  111. package/dist/state/index.d.ts +20 -17
  112. package/dist/state/index.js +3 -2
  113. package/dist/state/persistence-middleware.d.ts +1 -1
  114. package/dist/state/qr-detected-slice.d.ts +4 -0
  115. package/dist/state/qr-detected-slice.js +311 -0
  116. package/dist/state/recording-options.d.ts +2 -2
  117. package/dist/state/recording-options.js +128 -4
  118. package/dist/state/recording-replayer.d.ts +2 -2
  119. package/dist/state/recording-slice.d.ts +1 -1
  120. package/dist/state/recording-slice.js +5 -1
  121. package/dist/state/replay-engine.d.ts +1 -1
  122. package/dist/state/replay-engine.js +7 -3
  123. package/dist/state/store-subscribers.d.ts +2 -2
  124. package/dist/state/subscribe-to-selector.d.ts +1 -1
  125. package/dist/state/tracking-quality.d.ts +1 -1
  126. package/dist/state/tracking-slice.d.ts +1 -1
  127. package/dist/{state-BkIfpiyA.js → state-IEw0ZsBu.js} +1 -0
  128. package/dist/storage/file-system-utils.d.ts +2 -2
  129. package/dist/storage/file-system-utils.js +17 -1
  130. package/dist/storage/index.d.ts +9 -9
  131. package/dist/storage/index.js +4 -4
  132. package/dist/storage/null-storage-backend.d.ts +1 -1
  133. package/dist/storage/opfs-storage-backend.d.ts +1 -1
  134. package/dist/storage/opfs-storage-backend.js +3 -3
  135. package/dist/storage/opfs-storage.d.ts +1 -1
  136. package/dist/storage/opfs-storage.js +9 -8
  137. package/dist/storage/storage-backend.d.ts +1 -1
  138. package/dist/storage/zip-coverage-embed.d.ts +2 -0
  139. package/dist/storage/zip-coverage-embed.js +88 -0
  140. package/dist/storage/zip-export.d.ts +2 -2
  141. package/dist/storage/zip-export.js +38 -60
  142. package/dist/storage/zip-reader.d.ts +1 -1
  143. package/dist/storage/zip-reader.js +1 -1
  144. package/dist/{storage-backend-C9HLFtgz.d.ts → storage-backend-CTJHNdMp.d.ts} +1 -1
  145. package/dist/{store-subscribers-rrkLkFTt.d.ts → store-subscribers-BZP81hjh.d.ts} +2 -2
  146. package/dist/{subscribe-to-selector-CP3BKSbF.d.ts → subscribe-to-selector-Bp3sLx8L.d.ts} +1 -1
  147. package/dist/test-utils/browser-mocks.d.ts +7 -1
  148. package/dist/test-utils/browser-mocks.js +6 -0
  149. package/dist/test-utils/zip-round-trip-helpers.d.ts +9 -1
  150. package/dist/test-utils/zip-round-trip-helpers.js +8 -3
  151. package/dist/{tracking-slice-CdK8c-8P.d.ts → tracking-slice-DJZ9qeGg.d.ts} +1 -1
  152. package/dist/types/ar-types.d.ts +1 -1
  153. package/dist/types/geo-types.d.ts +1 -1
  154. package/dist/types/index.d.ts +2 -2
  155. package/dist/utils/concurrency.d.ts +2 -2
  156. package/dist/utils/concurrency.js +66 -2
  157. package/dist/utils/failure-tracker.d.ts +1 -1
  158. package/dist/utils/format-file-size.d.ts +1 -1
  159. package/dist/utils/fused-path.d.ts +1 -1
  160. package/dist/utils/index.d.ts +6 -6
  161. package/dist/utils/list-formatter.d.ts +1 -1
  162. package/dist/utils/logger.d.ts +1 -1
  163. package/dist/visualization/accuracy-circles.d.ts +1 -1
  164. package/dist/visualization/alignment-lerper.d.ts +1 -1
  165. package/dist/visualization/ar-world-group-alignment.d.ts +1 -1
  166. package/dist/visualization/ar-world-group-alignment.js +1 -1
  167. package/dist/visualization/camera-follower.d.ts +1 -1
  168. package/dist/visualization/css3d-renderer-manager.d.ts +1 -1
  169. package/dist/visualization/frame-conversions.d.ts +1 -1
  170. package/dist/visualization/frustum-visibility.d.ts +1 -1
  171. package/dist/visualization/gps-anchor.d.ts +1 -1
  172. package/dist/visualization/gps-compass-cubes.d.ts +1 -1
  173. package/dist/visualization/gps-event-markers.d.ts +1 -1
  174. package/dist/visualization/gps-event-markers.js +40 -5
  175. package/dist/visualization/hit-test-reticle.d.ts +1 -1
  176. package/dist/visualization/hit-test-reticle.js +1 -0
  177. package/dist/visualization/index.d.ts +18 -18
  178. package/dist/visualization/leaflet-map-overlay.d.ts +1 -1
  179. package/dist/visualization/leaflet-map-overlay.js +15 -3
  180. package/dist/visualization/lerp-utils.d.ts +1 -1
  181. package/dist/visualization/map-data.d.ts +1 -1
  182. package/dist/visualization/map-overlay-draw.d.ts +1 -1
  183. package/dist/visualization/map-overlay.d.ts +1 -1
  184. package/dist/visualization/three-dispose.d.ts +1 -1
  185. package/dist/visualization/vis-colors.d.ts +1 -1
  186. package/dist/{webxr-session-QhcSSub5.js → webxr-session-CJF9Nijp.js} +234 -9
  187. package/dist/{webxr-session-DtAG9srK.d.ts → webxr-session-COsOjJwn.d.ts} +76 -8
  188. package/dist/zip-coverage-embed-tFohI2J4.d.ts +41 -0
  189. package/dist/{zip-export-D_5HAvFz.d.ts → zip-export-DDWXInTR.d.ts} +28 -24
  190. package/package.json +2 -2
  191. package/dist/concurrency-CO1FQvs3.d.ts +0 -24
  192. package/dist/file-system-C_eqiEA8.d.ts +0 -114
  193. package/dist/file-system-utils-DyAmcuvX.d.ts +0 -24
  194. package/dist/recording-options-DJBXuMxV.d.ts +0 -182
  195. package/dist/recording-slice-89O07ebs.d.ts +0 -36
  196. package/dist/storage/file-system.d.ts +0 -2
  197. package/dist/storage/file-system.js +0 -289
  198. /package/dist/{accuracy-circles-BpwWAs8G.d.ts → accuracy-circles-Pi2YeCrM.d.ts} +0 -0
  199. /package/dist/{alignment-lerper-Dm9G7JJO.d.ts → alignment-lerper-BUTsQ2yu.d.ts} +0 -0
  200. /package/dist/{ar-types-Dan1MVTi.d.ts → ar-types-BckI1E-O.d.ts} +0 -0
  201. /package/dist/{bresenham3d-CFfd7n6B.d.ts → bresenham3d-ByjcmEgM.d.ts} +0 -0
  202. /package/dist/{camera-follower-C2mwEn7c.d.ts → camera-follower-BTb2Yp12.d.ts} +0 -0
  203. /package/dist/{capability-checker-CQXJHxXg.d.ts → capability-checker-CXqoJYtb.d.ts} +0 -0
  204. /package/dist/{capture-failure-tracker-CUeU3L_M.d.ts → capture-failure-tracker-BL5SoG2a.d.ts} +0 -0
  205. /package/dist/{chromium-camera-access-workaround-Jqbn0apH.d.ts → chromium-camera-access-workaround-BNK189P0.d.ts} +0 -0
  206. /package/dist/{css3d-renderer-manager-ptu_t3B3.d.ts → css3d-renderer-manager-m-ab19vp.d.ts} +0 -0
  207. /package/dist/{failure-tracker-Cn8Fo9D4.d.ts → failure-tracker-Cnc_xWUw.d.ts} +0 -0
  208. /package/dist/{format-file-size-CLCZz3lC.d.ts → format-file-size-BFUWvir1.d.ts} +0 -0
  209. /package/dist/{frame-loop-CMewS8cY.d.ts → frame-loop-BEO9_q3k.d.ts} +0 -0
  210. /package/dist/{frustum-visibility-CmI96ESS.d.ts → frustum-visibility-D_RGmH98.d.ts} +0 -0
  211. /package/dist/{geo-types-SaPnIEUM.d.ts → geo-types-DqiBzPO9.d.ts} +0 -0
  212. /package/dist/{gps-VuezJWK3.d.ts → gps-C5inWeNV.d.ts} +0 -0
  213. /package/dist/{gps-compass-cubes-BM1uGiYV.d.ts → gps-compass-cubes-BExxrWJ-.d.ts} +0 -0
  214. /package/dist/{gps-error-handler-CJl_2MVm.d.ts → gps-error-handler-C2bS69oJ.d.ts} +0 -0
  215. /package/dist/{hit-test-reticle-BEzEybxZ.d.ts → hit-test-reticle-Dqak9hiR.d.ts} +0 -0
  216. /package/dist/{index-CF05QV2m.d.ts → index-eaI1Z1KR.d.ts} +0 -0
  217. /package/dist/{lerp-utils-BpV-0Dtk.d.ts → lerp-utils-kLxMJ2Xj.d.ts} +0 -0
  218. /package/dist/{list-formatter-RRcBe8Vg.d.ts → list-formatter-ct8txwvR.d.ts} +0 -0
  219. /package/dist/{logger-BEHXsnnq.d.ts → logger-CzQrCe6C.d.ts} +0 -0
  220. /package/dist/{map-overlay-bcogY5fK.d.ts → map-overlay-Dci4yvm3.d.ts} +0 -0
  221. /package/dist/{permission-checker-GpAiSCwd.d.ts → permission-checker-CtPtPQRq.d.ts} +0 -0
  222. /package/dist/{scene-node-names-Bu0S66H1.d.ts → scene-node-names-CdNeQjOE.d.ts} +0 -0
  223. /package/dist/{session-disposers-M-oashRH.js → session-disposers-D8wnO-uW.js} +0 -0
  224. /package/dist/{three-dispose-D950t71B.d.ts → three-dispose-BCZkSJp2.d.ts} +0 -0
  225. /package/dist/{vis-colors-D6omC64K.d.ts → vis-colors-BZsSLI4i.d.ts} +0 -0
  226. /package/dist/{webxr-nue-basis-CqKQmZzT.d.ts → webxr-nue-basis-CW1wsbm6.d.ts} +0 -0
  227. /package/dist/{xr-camera-texture-DBwCaKTd.d.ts → xr-camera-texture-BmrP7iNZ.d.ts} +0 -0
  228. /package/dist/{xr-error-handler-C0AQRmxs.d.ts → xr-error-handler-BEjRgZjt.d.ts} +0 -0
  229. /package/dist/{xr-frame-loop-BtYytZJg.d.ts → xr-frame-loop-K8ebdjLw.d.ts} +0 -0
  230. /package/dist/{zip-reader-DSEXt7K6.d.ts → zip-reader-Q2ue6zlC.d.ts} +0 -0
@@ -0,0 +1,382 @@
1
+ import "./ar/camera-blit-capture.js";
2
+ import "./ar/chromium-camera-access-workaround.js";
3
+ import "./ar/capture-failure-tracker.js";
4
+ import "./ar/depth-sampler.js";
5
+ import "./ar/depth-unprojection.js";
6
+ import "./qr-size-measurer-DLb33geH.js";
7
+ import "./ar/qr-size-depth-context.js";
8
+ import { buildObjectPoints, transformPoint } from "./ar/qr-pose.js";
9
+ import "./ar/qr-derived-pose.js";
10
+ import "./ar/webxr-nue-basis.js";
11
+ import "./ar/qr-debug-view.js";
12
+ import { n as createDetectionScheduler } from "./qr-detection-controller-B-tLVd-S.js";
13
+ import "./qr-pose-aggregation-DXR9STHs.js";
14
+ import "./webxr-session-CJF9Nijp.js";
15
+ import "./ar/occupancy-grid.js";
16
+ import "./ar/frame-loop.js";
17
+ import "./ar/xr-frame-loop.js";
18
+ import "./ar/image-capture.js";
19
+ import "./ar/xr-camera-texture.js";
20
+ import "./ar/enable-gps-ar.js";
21
+ import "./ar/replay-scene.js";
22
+ //#region ../src/ar/qr-level.ts
23
+ /** Thrown when a fetched level file fails validation. */
24
+ var QrLevelValidationError = class extends Error {
25
+ constructor(message) {
26
+ super(`qr-level: ${message}`);
27
+ this.name = "QrLevelValidationError";
28
+ }
29
+ };
30
+ function isFiniteNumber(v) {
31
+ return typeof v === "number" && Number.isFinite(v);
32
+ }
33
+ function isRecord(v) {
34
+ return typeof v === "object" && v !== null;
35
+ }
36
+ /**
37
+ * Validate the optional `qr.physicalSizeM`. When present it MUST be a positive
38
+ * number (a `0`/negative authored size is a bug, not a "measure it instead"
39
+ * signal). Returns `undefined` when omitted.
40
+ */
41
+ function parsePhysicalSize(value) {
42
+ if (value === void 0) return void 0;
43
+ if (!isFiniteNumber(value) || value <= 0) throw new QrLevelValidationError("\"qr.physicalSizeM\" must be a positive number when present");
44
+ return value;
45
+ }
46
+ /**
47
+ * Validate the optional `qr.geo`. When present every field is validated (a
48
+ * partial geo is a bug — it would silently place the vote wrong). Returns
49
+ * `undefined` when omitted; heading is normalized into `[0, 360)`.
50
+ */
51
+ function parseGeo(value) {
52
+ if (value === void 0) return void 0;
53
+ if (!isRecord(value)) throw new QrLevelValidationError("\"qr.geo\" must be an object when present");
54
+ const { lat, lon, alt, headingDeg } = value;
55
+ if (!isFiniteNumber(lat) || lat < -90 || lat > 90) throw new QrLevelValidationError("\"qr.geo.lat\" must be a number in [-90, 90]");
56
+ if (!isFiniteNumber(lon) || lon < -180 || lon > 180) throw new QrLevelValidationError("\"qr.geo.lon\" must be a number in [-180, 180]");
57
+ if (!isFiniteNumber(alt)) throw new QrLevelValidationError("\"qr.geo.alt\" must be a finite number");
58
+ if (!isFiniteNumber(headingDeg)) throw new QrLevelValidationError("\"qr.geo.headingDeg\" must be a finite number");
59
+ return {
60
+ lat,
61
+ lon,
62
+ alt,
63
+ headingDeg: (headingDeg % 360 + 360) % 360
64
+ };
65
+ }
66
+ /**
67
+ * Validate an already-parsed value as a {@link QrLevel}. Throws
68
+ * {@link QrLevelValidationError} with a descriptive message on any violation.
69
+ */
70
+ function parseQrLevel(data) {
71
+ if (!isRecord(data)) throw new QrLevelValidationError("level file must be a JSON object");
72
+ if (!isFiniteNumber(data.version)) throw new QrLevelValidationError("missing/invalid \"version\"");
73
+ if (!isRecord(data.qr)) throw new QrLevelValidationError("missing/invalid \"qr\"");
74
+ const physicalSizeM = parsePhysicalSize(data.qr.physicalSizeM);
75
+ const geo = parseGeo(data.qr.geo);
76
+ return {
77
+ version: data.version,
78
+ qr: {
79
+ ...physicalSizeM !== void 0 ? { physicalSizeM } : {},
80
+ ...geo !== void 0 ? { geo } : {}
81
+ },
82
+ content: "content" in data ? data.content : void 0
83
+ };
84
+ }
85
+ /**
86
+ * Fetch and validate a level file from `url`. Rejects with
87
+ * {@link QrLevelValidationError} on a non-OK response, non-JSON body, or a
88
+ * schema violation.
89
+ */
90
+ async function fetchQrLevel(url, options = {}) {
91
+ const fetchImpl = options.fetchImpl ?? globalThis.fetch;
92
+ if (!fetchImpl) throw new QrLevelValidationError("no fetch implementation available");
93
+ let response;
94
+ try {
95
+ response = await fetchImpl(url, { signal: options.signal });
96
+ } catch (err) {
97
+ throw new QrLevelValidationError(`fetch failed for ${url}: ${err instanceof Error ? err.message : String(err)}`);
98
+ }
99
+ if (!response.ok) throw new QrLevelValidationError(`fetch ${url} returned status ${response.status}`);
100
+ let body;
101
+ try {
102
+ body = await response.json();
103
+ } catch {
104
+ throw new QrLevelValidationError(`response for ${url} was not valid JSON`);
105
+ }
106
+ return parseQrLevel(body);
107
+ }
108
+ //#endregion
109
+ //#region ../src/ar/qr-gps-vote.ts
110
+ /** Mean meters per degree of latitude (WGS-84 average). */
111
+ const METERS_PER_DEG_LAT = 111320;
112
+ /**
113
+ * `count` points evenly spaced on a circle of radius `baselineM` in the QR
114
+ * plane (z = 0), starting at local +x. The symmetric ring's centroid is the QR
115
+ * center, so translation stays anchored there while the wide radius stiffens
116
+ * the rotation fit. Non-collinear for `count ≥ 3`.
117
+ */
118
+ function widePlanePoints(baselineM, count) {
119
+ const points = [];
120
+ for (let i = 0; i < count; i++) {
121
+ const theta = 2 * Math.PI * i / count;
122
+ points.push([
123
+ baselineM * Math.cos(theta),
124
+ baselineM * Math.sin(theta),
125
+ 0
126
+ ]);
127
+ }
128
+ return points;
129
+ }
130
+ /**
131
+ * Map a QR-local plane offset (meters; +x right, +y up on the printed face) to
132
+ * an East/North/Up offset, given the QR's compass heading. Vertical-QR
133
+ * convention: +y is world up; +x is horizontal at `headingDeg` (clockwise from
134
+ * North), so east = x·sin(h), north = x·cos(h).
135
+ */
136
+ function localPlaneToEnu(localX, localY, headingDeg) {
137
+ const h = headingDeg * Math.PI / 180;
138
+ return {
139
+ east: localX * Math.sin(h),
140
+ north: localX * Math.cos(h),
141
+ up: localY
142
+ };
143
+ }
144
+ /** Apply an ENU meter offset to a geo pose (equirectangular; exact enough for sub-meter QR corners). */
145
+ function offsetGeo(center, enu) {
146
+ const dLat = enu.north / METERS_PER_DEG_LAT;
147
+ const metersPerDegLon = METERS_PER_DEG_LAT * Math.cos(center.lat * Math.PI / 180);
148
+ const dLon = Math.abs(metersPerDegLon) < 1e-9 ? 0 : enu.east / metersPerDegLon;
149
+ return {
150
+ latitude: center.lat + dLat,
151
+ longitude: center.lon + dLon,
152
+ altitude: center.alt + enu.up
153
+ };
154
+ }
155
+ /**
156
+ * Build the synthetic `recordGpsEvent` payload(s) for one QR detection. Returns
157
+ * 4 corner correspondences by default, or 1 center correspondence when
158
+ * `multiCorrespondence` is false. Each payload pairs the corner's odom position
159
+ * (from the solved pose) with its absolute geo position (from the level file),
160
+ * stamped with the tiny synthetic accuracy.
161
+ *
162
+ * @throws RangeError on a non-positive `sizeM` or `syntheticAccuracyM`.
163
+ */
164
+ function buildQrGpsVotes(input) {
165
+ const { qrPoseWorld, sizeM, qrGeo, syntheticAccuracyM, odomRotation = qrPoseWorld.rotation, multiCorrespondence = true, baselineM, count = 4, timestamp = Date.now(), idPrefix = "qr" } = input;
166
+ if (!(syntheticAccuracyM > 0) || !Number.isFinite(syntheticAccuracyM)) throw new RangeError(`qr-gps-vote: syntheticAccuracyM must be positive, got ${syntheticAccuracyM}`);
167
+ const useWideBaseline = baselineM !== void 0 && Number.isFinite(baselineM) && baselineM > 0;
168
+ if (useWideBaseline && count < 3) throw new RangeError(`qr-gps-vote: wide-baseline count must be >= 3 (collinear otherwise), got ${count}`);
169
+ return (useWideBaseline ? widePlanePoints(baselineM, count) : multiCorrespondence ? buildObjectPoints(sizeM) : [[
170
+ 0,
171
+ 0,
172
+ 0
173
+ ]]).map((local, i) => {
174
+ const odomPosition = transformPoint(local, qrPoseWorld);
175
+ const geo = offsetGeo(qrGeo, localPlaneToEnu(local[0], local[1], qrGeo.headingDeg));
176
+ return {
177
+ odomPosition,
178
+ odomRotation,
179
+ rawGpsPoint: {
180
+ id: `${idPrefix}-${timestamp}-${i}`,
181
+ latitude: geo.latitude,
182
+ longitude: geo.longitude,
183
+ altitude: geo.altitude,
184
+ latLongAccuracy: syntheticAccuracyM,
185
+ timestamp
186
+ }
187
+ };
188
+ });
189
+ }
190
+ //#endregion
191
+ //#region ../src/ar/qr-tracking-controller.ts
192
+ function createQrTrackingController(config) {
193
+ const { frontEnd, solvePose, fetchLevel, dispatchVotes, onDetection, resolveSizeM, resolveStablePose, getCameraPose, getIntrinsics, syntheticAccuracyM, voteBaselineM, voteCount, isPlausible, onStatus, onLocked, onError, minIntervalMs = 150, requiredLockCount = 3, now } = config;
194
+ const timestampNow = now ?? (() => Date.now());
195
+ let status = "idle";
196
+ const levelCache = /* @__PURE__ */ new Map();
197
+ let active = null;
198
+ function setStatus(next) {
199
+ if (status === next) return;
200
+ status = next;
201
+ onStatus?.(next);
202
+ }
203
+ async function ensureLevel(url) {
204
+ const cached = levelCache.get(url);
205
+ if (cached) return cached;
206
+ setStatus("loading-level");
207
+ const level = await fetchLevel(url);
208
+ levelCache.set(url, level);
209
+ return level;
210
+ }
211
+ async function detect(image) {
212
+ if (status === "idle" || status === "error") setStatus("scanning");
213
+ const detection = await frontEnd.detect(image);
214
+ if (!detection) {
215
+ active = null;
216
+ return null;
217
+ }
218
+ const level = await ensureLevel(detection.text);
219
+ const sizeM = level.qr.physicalSizeM ?? resolveSizeM?.(detection.text, level) ?? null;
220
+ if (sizeM === null || !(sizeM > 0) || !Number.isFinite(sizeM)) {
221
+ active = null;
222
+ if (status === "loading-level") setStatus("scanning");
223
+ return null;
224
+ }
225
+ const cameraPose = getCameraPose();
226
+ const intrinsics = getIntrinsics(image);
227
+ if (!cameraPose || !intrinsics) {
228
+ active = null;
229
+ return null;
230
+ }
231
+ const solution = solvePose({
232
+ imagePoints: detection.corners,
233
+ sizeM,
234
+ intrinsics,
235
+ cameraPose
236
+ });
237
+ if (!solution) {
238
+ active = null;
239
+ return null;
240
+ }
241
+ if (isPlausible && !isPlausible(solution, cameraPose)) {
242
+ active = null;
243
+ return null;
244
+ }
245
+ active = {
246
+ level,
247
+ text: detection.text,
248
+ sizeM
249
+ };
250
+ return solution;
251
+ }
252
+ const scheduler = createDetectionScheduler({
253
+ detect,
254
+ minIntervalMs,
255
+ requiredLockCount,
256
+ now,
257
+ onLocked: (solution) => {
258
+ const current = active;
259
+ if (!current) return;
260
+ const { level, text, sizeM } = current;
261
+ onDetection?.({
262
+ text,
263
+ qrPoseWorld: solution.qrPoseWorld,
264
+ qrPoseInCamera: solution.qrPoseInCamera,
265
+ reprojectionErrorPx: solution.reprojectionErrorPx,
266
+ timestamp: timestampNow()
267
+ });
268
+ if (level.qr.geo) {
269
+ const votePose = resolveStablePose ? resolveStablePose(text) : solution.qrPoseWorld;
270
+ if (votePose) dispatchVotes(buildQrGpsVotes({
271
+ qrPoseWorld: votePose,
272
+ sizeM,
273
+ qrGeo: level.qr.geo,
274
+ syntheticAccuracyM,
275
+ ...voteBaselineM !== void 0 ? { baselineM: voteBaselineM } : {},
276
+ ...voteCount !== void 0 ? { count: voteCount } : {}
277
+ }));
278
+ }
279
+ setStatus("tracking");
280
+ onLocked?.(solution, level);
281
+ },
282
+ onMiss: () => {
283
+ if (status === "tracking") setStatus("scanning");
284
+ },
285
+ onError: (err) => {
286
+ active = null;
287
+ setStatus("error");
288
+ onError?.(err);
289
+ }
290
+ });
291
+ return {
292
+ offerFrame(image) {
293
+ scheduler.offerFrame(image);
294
+ },
295
+ get status() {
296
+ return status;
297
+ },
298
+ reset() {
299
+ levelCache.clear();
300
+ active = null;
301
+ setStatus("idle");
302
+ }
303
+ };
304
+ }
305
+ //#endregion
306
+ //#region ../src/ar/qr-occupancy-check.ts
307
+ const DEFAULTS = {
308
+ surfaceToleranceCells: 1.5,
309
+ minObservations: 1,
310
+ rayCorridorCells: 1,
311
+ occlusionMarginCells: 2
312
+ };
313
+ function distance(a, b) {
314
+ return Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2]);
315
+ }
316
+ /**
317
+ * Classify a solved QR center against the occupancy grid.
318
+ *
319
+ * - `no-grid` (ok): the grid has no occupied voxels — nothing to check against.
320
+ * - `floating` (not ok): nearest occupied voxel is farther than the tolerance.
321
+ * - `behind-surface` (not ok): an occupied voxel lies on the camera→QR ray
322
+ * clearly in front of the QR (the QR is inside / beyond geometry).
323
+ * - `plausible` (ok): on a surface with empty space toward the camera.
324
+ *
325
+ * All positions are raw-WebXR/odom space (the same frame as `qrPoseWorld`).
326
+ */
327
+ function checkQrPlausibility(qrCenterWorld, cameraPosWorld, grid, options = {}) {
328
+ const surfaceToleranceCells = options.surfaceToleranceCells ?? DEFAULTS.surfaceToleranceCells;
329
+ const minObservations = options.minObservations ?? DEFAULTS.minObservations;
330
+ const rayCorridorCells = options.rayCorridorCells ?? DEFAULTS.rayCorridorCells;
331
+ const occlusionMarginCells = options.occlusionMarginCells ?? DEFAULTS.occlusionMarginCells;
332
+ const cells = grid.getOccupiedCells(minObservations);
333
+ if (cells.length === 0) return {
334
+ verdict: "no-grid",
335
+ ok: true,
336
+ nearestSurfaceDistanceM: Infinity
337
+ };
338
+ const cellSizeM = grid.cellSizeM;
339
+ const centers = cells.map((c) => grid.getCellCenter(c));
340
+ let nearest = Infinity;
341
+ for (const center of centers) {
342
+ const d = distance(center, qrCenterWorld);
343
+ if (d < nearest) nearest = d;
344
+ }
345
+ if (nearest > surfaceToleranceCells * cellSizeM) return {
346
+ verdict: "floating",
347
+ ok: false,
348
+ nearestSurfaceDistanceM: nearest
349
+ };
350
+ const dir = [
351
+ qrCenterWorld[0] - cameraPosWorld[0],
352
+ qrCenterWorld[1] - cameraPosWorld[1],
353
+ qrCenterWorld[2] - cameraPosWorld[2]
354
+ ];
355
+ const rayLength = Math.hypot(dir[0], dir[1], dir[2]);
356
+ if (rayLength > cellSizeM) {
357
+ const nx = dir[0] / rayLength;
358
+ const ny = dir[1] / rayLength;
359
+ const nz = dir[2] / rayLength;
360
+ const corridor = rayCorridorCells * cellSizeM;
361
+ const tMax = rayLength - occlusionMarginCells * cellSizeM;
362
+ for (const center of centers) {
363
+ const ox = center[0] - cameraPosWorld[0];
364
+ const oy = center[1] - cameraPosWorld[1];
365
+ const oz = center[2] - cameraPosWorld[2];
366
+ const t = ox * nx + oy * ny + oz * nz;
367
+ if (t <= cellSizeM || t >= tMax) continue;
368
+ if (Math.hypot(ox - t * nx, oy - t * ny, oz - t * nz) < corridor) return {
369
+ verdict: "behind-surface",
370
+ ok: false,
371
+ nearestSurfaceDistanceM: nearest
372
+ };
373
+ }
374
+ }
375
+ return {
376
+ verdict: "plausible",
377
+ ok: true,
378
+ nearestSurfaceDistanceM: nearest
379
+ };
380
+ }
381
+ //#endregion
382
+ export { localPlaneToEnu as a, fetchQrLevel as c, buildQrGpsVotes as i, parseQrLevel as l, createQrTrackingController as n, offsetGeo as o, METERS_PER_DEG_LAT as r, QrLevelValidationError as s, checkQrPlausibility as t };
@@ -1,4 +1,4 @@
1
- import { t as SubscribableStore } from "./subscribe-to-selector-CP3BKSbF.js";
1
+ import { t as SubscribableStore } from "./subscribe-to-selector-Bp3sLx8L.js";
2
2
  import * as THREE from "three";
3
3
 
4
4
  //#region ../src/visualization/ar-world-group-alignment.d.ts
@@ -31,6 +31,28 @@ declare function computeCaptureSize(cameraWidth: number, cameraHeight: number, d
31
31
  width: number;
32
32
  height: number;
33
33
  };
34
+ /**
35
+ * Compute blit dimensions that PRESERVE the camera aspect ratio with the
36
+ * **longer edge fixed at `maxEdge`**. Unlike {@link computeCaptureSize} (which
37
+ * divides the native resolution by a user divisor), this fits the frame into a
38
+ * fixed pixel budget, so a 4:3 camera becomes e.g. 512×384 — NOT a stretched
39
+ * 512×512. Used by the QR-detection blit (B2) so the detector sees an
40
+ * undistorted code while the readback cost stays bounded by `maxEdge²`.
41
+ *
42
+ * @param cameraWidth - Native camera width in pixels (from XRCamera)
43
+ * @param cameraHeight - Native camera height in pixels (from XRCamera)
44
+ * @param maxEdge - Target length (px) of the longer output edge.
45
+ * @returns Integer dimensions, longer edge == `maxEdge`, aspect preserved
46
+ * (within rounding), each clamped to ≥ 1. When `maxEdge` itself is invalid
47
+ * (< 1 / NaN / Infinity) the longer edge falls back to
48
+ * `DEFAULT_BLIT_CONFIG.width` (still aspect-preserving). When the camera
49
+ * dimensions are invalid (≤ 0 / NaN / Infinity) the aspect is unknown, so it
50
+ * returns a square at the (possibly defaulted) edge.
51
+ */
52
+ declare function computeAspectFitSize(cameraWidth: number, cameraHeight: number, maxEdge: number): {
53
+ width: number;
54
+ height: number;
55
+ };
34
56
  /**
35
57
  * Captures readable pixel data from WebXR opaque camera textures
36
58
  * using the intermediate render target "blit" technique.
@@ -83,6 +105,29 @@ declare class CameraBlitCapture {
83
105
  width: number;
84
106
  height: number;
85
107
  } | null;
108
+ /**
109
+ * Capture the camera texture as **top-left-origin** RGBA — the orientation
110
+ * QR detection (and `BarcodeDetector`) expects — returning a FRESH copy that
111
+ * is safe to retain beyond the next capture.
112
+ *
113
+ * This is the efficient replacement for the demo's old JPEG round-trip: blit
114
+ * + readback (shared with {@link captureToBlob} / {@link captureToPixels}),
115
+ * then the same vertical flip the JPEG encoder applies, but with no encode →
116
+ * decode. Unlike {@link captureToPixels} (which returns the reusable internal
117
+ * buffer in WebGL bottom-row-first order), this returns an owned,
118
+ * correctly-oriented `Uint8ClampedArray`.
119
+ *
120
+ * IMPORTANT: Must be called within the XR animation frame callback, while the
121
+ * camera texture is valid.
122
+ *
123
+ * @returns `{ data, width, height }` (top-left RGBA), or null on
124
+ * failure/dispose.
125
+ */
126
+ captureToRgba(renderer: THREE.WebGLRenderer, cameraTexture: THREE.Texture): {
127
+ data: Uint8ClampedArray;
128
+ width: number;
129
+ height: number;
130
+ } | null;
86
131
  /**
87
132
  * Check if a pixel buffer is entirely black (all zeros).
88
133
  * Uses sampling for performance (checks BLACK_CHECK_SAMPLE_COUNT evenly-spaced pixels).
@@ -100,13 +145,21 @@ declare class CameraBlitCapture {
100
145
  */
101
146
  private pixelsToJpegBlob;
102
147
  private getFlippedImageData;
148
+ /**
149
+ * Produce a FRESH, top-left-origin RGBA copy of the internal readback buffer.
150
+ * WebGL `readPixels` returns bottom-row-first; this copies (so the internal
151
+ * buffer stays y-flipped for a subsequent capture) and swaps rows. Shared by
152
+ * the JPEG encode path ({@link getFlippedImageData}) and {@link captureToRgba}.
153
+ */
154
+ private flippedPixelCopy;
103
155
  private pixelsToJpegViaOffscreenCanvas;
104
156
  private pixelsToJpegViaCanvas;
105
157
  /**
106
- * Flip ImageData vertically in-place.
107
- * WebGL readPixels returns bottom-row-first; canvas expects top-row-first.
158
+ * Flip an RGBA buffer vertically in-place (row swap).
159
+ * WebGL readPixels returns bottom-row-first; canvas / detectors expect
160
+ * top-row-first.
108
161
  */
109
- private flipImageDataVertically;
162
+ private flipRowsVertically;
110
163
  /**
111
164
  * Resize the render target and pixel buffer to match new dimensions.
112
165
  * Call this when the camera resolution is first known or changes.
@@ -119,10 +172,19 @@ declare class CameraBlitCapture {
119
172
  * @returns true if resources were actually resized
120
173
  */
121
174
  resizeIfNeeded(newWidth: number, newHeight: number): boolean;
175
+ /**
176
+ * Current render-target width in pixels. This is exactly the width of the
177
+ * JPEG produced by {@link captureToBlob} (the encode canvas is sized to the
178
+ * render target), so callers can persist it as the captured image's true
179
+ * pixel width without decoding the blob.
180
+ */
181
+ getWidth(): number;
182
+ /** Current render-target height in pixels. See {@link getWidth}. */
183
+ getHeight(): number;
122
184
  /**
123
185
  * Dispose GPU resources. Call when AR session ends.
124
186
  */
125
187
  dispose(): void;
126
188
  }
127
189
  //#endregion
128
- export { computeCaptureSize as i, CameraBlitCaptureConfig as n, DEFAULT_BLIT_CONFIG as r, CameraBlitCapture as t };
190
+ export { computeCaptureSize as a, computeAspectFitSize as i, CameraBlitCaptureConfig as n, DEFAULT_BLIT_CONFIG as r, CameraBlitCapture as t };
@@ -0,0 +1,50 @@
1
+ //#region ../src/utils/concurrency.d.ts
2
+ /**
3
+ * Concurrency Utilities
4
+ *
5
+ * Provides helpers for limiting the number of concurrent async operations.
6
+ * Used to prevent excessive memory consumption when scanning many files
7
+ * in parallel (e.g., reading zip metadata during scenario discovery).
8
+ */
9
+ /**
10
+ * Map over an array with a concurrency limit on the async mapper function.
11
+ *
12
+ * Behaves like `Promise.all(items.map(fn))` but limits how many mapper
13
+ * invocations run simultaneously. Results are returned in the same order
14
+ * as the input items.
15
+ *
16
+ * @param items - Array of items to process
17
+ * @param limit - Maximum number of concurrent mapper invocations
18
+ * @param mapper - Async function to apply to each item
19
+ * @returns Array of results in the same order as input items
20
+ * @throws Re-throws the first error from any mapper invocation (fail-fast)
21
+ */
22
+ declare function mapWithConcurrencyLimit<T, R>(items: T[], limit: number, mapper: (item: T, index: number) => Promise<R>): Promise<R[]>;
23
+ /**
24
+ * Run an async worker over each item with a concurrency cap, invoking the worker
25
+ * per item as the pool pulls it (rather than collecting results into an array).
26
+ *
27
+ * Unlike {@link mapWithConcurrencyLimit}, this returns no values — the worker is
28
+ * expected to produce its side effect (e.g. emit a streaming callback) itself.
29
+ * This is the shape progressive consumers need: each item is handled and can be
30
+ * reported as soon as it settles, instead of waiting for the whole batch.
31
+ *
32
+ * Completion order is **not** guaranteed (it depends on which worker finishes
33
+ * first). Each item's worker is invoked exactly once unless the run is aborted.
34
+ *
35
+ * When an `AbortSignal` is supplied, workers stop pulling **new** items as soon
36
+ * as the signal is aborted (checked before each pull). Items already in flight
37
+ * run to completion — the File System Access reads underneath cannot be torn
38
+ * mid-read — but no further items are started, so a destroyed consumer stops
39
+ * accumulating work. If the signal is already aborted, no work starts at all.
40
+ *
41
+ * @param items - Items to process
42
+ * @param limit - Maximum number of concurrent worker invocations (`>= 1`)
43
+ * @param worker - Async side-effecting function applied to each item
44
+ * @param signal - Optional abort signal that halts pulling new items
45
+ * @throws RangeError if `limit < 1`
46
+ * @throws Re-throws the first error from any worker invocation (fail-fast)
47
+ */
48
+ declare function forEachWithConcurrencyLimit<T>(items: readonly T[], limit: number, worker: (item: T, index: number) => Promise<void>, signal?: AbortSignal): Promise<void>;
49
+ //#endregion
50
+ export { mapWithConcurrencyLimit as n, forEachWithConcurrencyLimit as t };
@@ -1,2 +1,2 @@
1
- import { a as LibraryRootState, c as RootState, d as calcRelativeCoordsInMeters, f as createGpsSlamStore, g as webxrToNUE, h as validateLicenseKey, i as LatLongAlt, l as Vector3, m as odometryTrackingRestarted, n as GpsPoint, o as Matrix4, p as isIdentityMatrix4, r as LatLong, s as Quaternion, t as ArImageCapture, u as calcGpsCoords } from "../index-CF05QV2m.js";
1
+ import { a as LibraryRootState, c as RootState, d as calcRelativeCoordsInMeters, f as createGpsSlamStore, g as webxrToNUE, h as validateLicenseKey, i as LatLongAlt, l as Vector3, m as odometryTrackingRestarted, n as GpsPoint, o as Matrix4, p as isIdentityMatrix4, r as LatLong, s as Quaternion, t as ArImageCapture, u as calcGpsCoords } from "../index-eaI1Z1KR.js";
2
2
  export { ArImageCapture, GpsPoint, LatLong, LatLongAlt, LibraryRootState, Matrix4, Quaternion, RootState, Vector3, calcGpsCoords, calcRelativeCoordsInMeters, createGpsSlamStore, isIdentityMatrix4, odometryTrackingRestarted, validateLicenseKey, webxrToNUE };
@@ -1,8 +1,8 @@
1
- import { t as ARPose } from "./ar-types-Dan1MVTi.js";
2
- import { a as TrackingSliceState, t as DeviceOrientation } from "./tracking-slice-CdK8c-8P.js";
3
- import { t as RecordingState } from "./recording-slice-89O07ebs.js";
4
- import { n as SessionMetadata } from "./opfs-storage-DYm8WHq7.js";
5
- import { n as StorageBackend } from "./storage-backend-C9HLFtgz.js";
1
+ import { t as ARPose } from "./ar-types-BckI1E-O.js";
2
+ import { a as TrackingSliceState, t as DeviceOrientation } from "./tracking-slice-DJZ9qeGg.js";
3
+ import { t as RecordingState } from "./recording-slice-B-uCgGoh.js";
4
+ import { n as SessionMetadata } from "./opfs-storage-DMtlt57S.js";
5
+ import { n as StorageBackend } from "./storage-backend-CTJHNdMp.js";
6
6
  import { GpsPoint, LatLong, Matrix4, RootState, Vector3 } from "gps-plus-slam-js";
7
7
  import * as _$_reduxjs_toolkit0 from "@reduxjs/toolkit";
8
8
  import { Middleware, Reducer, ReducersMapObject, configureStore } from "@reduxjs/toolkit";
@@ -0,0 +1,21 @@
1
+ import { r as DepthPoint } from "./ar-types-BckI1E-O.js";
2
+
3
+ //#region ../src/ar/depth-grid-lookup.d.ts
4
+ interface DepthGridLookup {
5
+ /**
6
+ * Bilinearly-interpolated depth (m) at a normalized screen point (top-left
7
+ * origin), or `null` when the point is outside the node grid or any of the
8
+ * four surrounding nodes has no valid (finite, positive) depth.
9
+ */
10
+ depthAt(screenX: number, screenY: number): number | null;
11
+ }
12
+ /**
13
+ * Build a bilinear lookup over a depth-sampler grid.
14
+ *
15
+ * @param points - the grid `DepthPoint`s (row-major, `row·g + col`).
16
+ * @param gridSize - points-per-side; inferred as `round(√points.length)` when
17
+ * omitted (the sampler always emits a full `g²` grid).
18
+ */
19
+ declare function createDepthGridLookup(points: readonly DepthPoint[], gridSize?: number): DepthGridLookup;
20
+ //#endregion
21
+ export { createDepthGridLookup as n, DepthGridLookup as t };
@@ -1,4 +1,4 @@
1
- import { a as RgbTuple, i as DepthSample, t as ARPose } from "./ar-types-Dan1MVTi.js";
1
+ import { a as RgbTuple, i as DepthSample, t as ARPose } from "./ar-types-BckI1E-O.js";
2
2
  import { Matrix4 } from "gps-plus-slam-js";
3
3
 
4
4
  //#region ../src/ar/depth-rgb-lookup.d.ts
@@ -1,4 +1,4 @@
1
- import { r as DepthPoint } from "./ar-types-Dan1MVTi.js";
1
+ import { r as DepthPoint } from "./ar-types-BckI1E-O.js";
2
2
  import { Matrix4, Quaternion, Vector3 } from "gps-plus-slam-js";
3
3
 
4
4
  //#region ../src/ar/depth-unprojection.d.ts
@@ -1,7 +1,7 @@
1
- import { t as ArCrashIsolationOptions } from "./recording-options-DJBXuMxV.js";
2
- import { n as RawDeviceOrientation, t as GpsPosition } from "./gps-VuezJWK3.js";
3
- import { n as PermissionStatus } from "./permission-checker-GpAiSCwd.js";
4
- import { t as SessionFeatureOptions } from "./webxr-session-DtAG9srK.js";
1
+ import { t as ArCrashIsolationOptions } from "./recording-options-D93kksJU.js";
2
+ import { n as RawDeviceOrientation, t as GpsPosition } from "./gps-C5inWeNV.js";
3
+ import { n as PermissionStatus } from "./permission-checker-CtPtPQRq.js";
4
+ import { r as SessionFeatureOptions } from "./webxr-session-COsOjJwn.js";
5
5
 
6
6
  //#region ../src/ar/enable-gps-ar.d.ts
7
7
  /**
@@ -0,0 +1,40 @@
1
+ //#region ../src/storage/file-system-utils.d.ts
2
+ /**
3
+ * File System Utilities - Pure Functions
4
+ *
5
+ * These are extracted from file-system.ts so they can be tested
6
+ * without mocking browser APIs.
7
+ */
8
+ /**
9
+ * Format a Date as a timestamp string for folder names
10
+ * @example "2025-02-28_14-30-11utc"
11
+ */
12
+ declare function formatTimestamp(date: Date): string;
13
+ /**
14
+ * Format an action file index as a zero-padded filename
15
+ * @example 42 -> "000042.json"
16
+ */
17
+ declare function formatActionFilename(index: number): string;
18
+ /**
19
+ * Format a frame index as a zero-padded filename
20
+ * @example 42 -> "frame-000042.jpg"
21
+ */
22
+ declare function formatFrameFilename(index: number): string;
23
+ /**
24
+ * Canonical session subdirectory for captured camera images, written by new
25
+ * recordings. Renamed from {@link LEGACY_SESSION_IMAGES_DIR} so an exported ZIP
26
+ * is a textbook COLMAP tree (`images/frame-NNNNNN.jpg` next to `sparse/0/`).
27
+ * Both the OPFS write path and the recorder's persisted `imageFile` value must
28
+ * use THIS constant so a recording stays self-consistent (COLMAP export plan
29
+ * Q5, gps-plus-slam/GpsPlusSlamJs_Docs/docs/2026-06-13-colmap-export-plan.md).
30
+ */
31
+ declare const SESSION_IMAGES_DIR = "images";
32
+ /**
33
+ * The pre-2026-06 session image subdirectory. Recordings made before the
34
+ * {@link SESSION_IMAGES_DIR} rename store frames under `frames/` (in both the
35
+ * on-disk dir and the persisted `imageFile`); readers fall back to this prefix
36
+ * so old recordings still replay.
37
+ */
38
+ declare const LEGACY_SESSION_IMAGES_DIR = "frames";
39
+ //#endregion
40
+ export { formatTimestamp as a, formatFrameFilename as i, SESSION_IMAGES_DIR as n, formatActionFilename as r, LEGACY_SESSION_IMAGES_DIR as t };
@@ -1,4 +1,4 @@
1
- import { i as LatLongAlt, r as LatLong } from "./index-CF05QV2m.js";
1
+ import { i as LatLongAlt, r as LatLong } from "./index-eaI1Z1KR.js";
2
2
  import * as THREE from "three";
3
3
 
4
4
  //#region ../src/visualization/frame-conversions.d.ts
@@ -1,4 +1,4 @@
1
- import { t as GpsCoord } from "./geo-types-SaPnIEUM.js";
1
+ import { t as GpsCoord } from "./geo-types-DqiBzPO9.js";
2
2
  import { LatLong, Matrix4, Vector3, fusedGpsFromOdom } from "gps-plus-slam-js";
3
3
 
4
4
  //#region ../src/utils/fused-path.d.ts
@@ -1,2 +1,2 @@
1
- import { a as gpsToH3, i as findNearbyGeoAnchor, n as KnownGeoAnchor, o as h3CellsMatch, r as approxDistanceMetres, s as isH3Index, t as H3_RESOLUTION } from "../h3-proximity-I1msGPgE.js";
2
- export { H3_RESOLUTION, KnownGeoAnchor, approxDistanceMetres, findNearbyGeoAnchor, gpsToH3, h3CellsMatch, isH3Index };
1
+ import { a as findNearbyGeoAnchor, c as h3CellsMatch, i as clusterCellsByZoom, l as isH3Index, n as KnownGeoAnchor, o as gpsPathToCoverageCells, r as approxDistanceMetres, s as gpsToH3, t as H3_RESOLUTION } from "../h3-proximity-B57C6rYL.js";
2
+ export { H3_RESOLUTION, KnownGeoAnchor, approxDistanceMetres, clusterCellsByZoom, findNearbyGeoAnchor, gpsPathToCoverageCells, gpsToH3, h3CellsMatch, isH3Index };