gps-plus-slam-app-framework 1.0.6 → 1.0.7

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 (174) hide show
  1. package/LICENSE +4 -4
  2. package/README.md +249 -108
  3. package/dist/accuracy-circles-CsxE_7x1.d.ts +43 -0
  4. package/dist/{app-selectors-CHt7DLuq.d.ts → app-selectors-BeU0_ab8.d.ts} +8 -10
  5. package/dist/ar/camera-blit-capture.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-sampler.d.ts +2 -2
  9. package/dist/ar/frame-loop.d.ts +2 -0
  10. package/dist/ar/frame-loop.js +40 -0
  11. package/dist/ar/image-capture.d.ts +1 -1
  12. package/dist/ar/image-capture.js +1 -1
  13. package/dist/ar/index.d.ts +12 -12
  14. package/dist/ar/index.js +3 -3
  15. package/dist/ar/replay-scene.d.ts +1 -1
  16. package/dist/ar/scene-node-names.d.ts +1 -1
  17. package/dist/ar/webxr-session.d.ts +4 -4
  18. package/dist/ar/webxr-session.js +150 -55
  19. package/dist/ar/xr-camera-texture.d.ts +1 -1
  20. package/dist/ar/xr-error-handler.d.ts +1 -1
  21. package/dist/core/index.d.ts +2 -2
  22. package/dist/core/index.js +2 -2
  23. package/dist/create-slam-app-store-CNsZ3rcX.d.ts +371 -0
  24. package/dist/{depth-sampler-BNCtnEoP.d.ts → depth-sampler-xg8vna6c.d.ts} +1 -1
  25. package/dist/{file-system-DD5TczSO.d.ts → file-system-DTApEv_Q.d.ts} +32 -2
  26. package/dist/frame-loop-QJIxLin0.d.ts +42 -0
  27. package/dist/frustum-visibility-BHnFrSKQ.d.ts +58 -0
  28. package/dist/{fused-path-DtqCSqJh.d.ts → fused-path-CB4DwWOG.d.ts} +1 -1
  29. package/dist/geo/h3-proximity.d.ts +1 -1
  30. package/dist/geo/index.d.ts +1 -1
  31. package/dist/{geo-types-Xx-LVcnw.d.ts → geo-types-CTuF23gG.d.ts} +16 -1
  32. package/dist/{gps-GKc6_Cly.d.ts → gps-DXoQb9Kf.d.ts} +1 -1
  33. package/dist/gps-anchor-CnWY61XK.d.ts +48 -0
  34. package/dist/gps-anchor-DjC_3MoT.js +257 -0
  35. package/dist/{gps-ar-pose-sampler-D_Zso40V.d.ts → gps-ar-pose-sampler-DsM1Kb2N.d.ts} +1 -1
  36. package/dist/{gps-event-coordinator-fwvmVfku.d.ts → gps-event-coordinator-DBx9I1YX.d.ts} +3 -3
  37. package/dist/gps-event-markers-BGr-iLvi.d.ts +103 -0
  38. package/dist/{image-capture-2pKjYUS6.d.ts → image-capture-DZLxHDN9.d.ts} +1 -1
  39. package/dist/index-gzWJMVpo.d.ts +2 -0
  40. package/dist/index-pOjUCKEP.d.ts +24 -0
  41. package/dist/index.d.ts +58 -52
  42. package/dist/index.js +11 -5
  43. package/dist/{leaflet-map-overlay-CQZcnxbc.d.ts → leaflet-map-overlay-Cew7XAoO.d.ts} +22 -11
  44. package/dist/{logger-B81iwxx0.d.ts → logger-C9vugiQb.d.ts} +7 -1
  45. package/dist/map-data-sih4g64v.d.ts +49 -0
  46. package/dist/map-overlay-draw-B3R1c9Xp.d.ts +42 -0
  47. package/dist/{null-storage-backend-C0TiwwzQ.d.ts → null-storage-backend-BKOS7JpL.d.ts} +2 -2
  48. package/dist/{opfs-storage-backend-Gt3rd76D.d.ts → opfs-storage-backend-Cj_7PWoq.d.ts} +2 -2
  49. package/dist/{permission-checker-Cu3nbH1S.d.ts → permission-checker-DPJl_RU6.d.ts} +41 -1
  50. package/dist/persistence-middleware-BkHIqvaA.d.ts +55 -0
  51. package/dist/{recording-replayer-BFhFs7Mc.d.ts → recording-replayer-CmCIIZ02.d.ts} +2 -2
  52. package/dist/{recording-slice-BiktUIWF.d.ts → recording-slice-d6OtCrza.d.ts} +2 -2
  53. package/dist/{replay-engine-B88Va62x.d.ts → replay-engine-BGBRQyXs.d.ts} +1 -1
  54. package/dist/{replay-scene-DtUm6bsr.d.ts → replay-scene-DpAGcAKY.d.ts} +3 -3
  55. package/dist/sensors/gps-error-handler.d.ts +1 -1
  56. package/dist/sensors/gps.d.ts +1 -1
  57. package/dist/sensors/gps.js +2 -2
  58. package/dist/sensors/index.d.ts +3 -3
  59. package/dist/sensors/permission-checker.d.ts +2 -2
  60. package/dist/sensors/permission-checker.js +79 -1
  61. package/dist/state/app-selectors.d.ts +2 -2
  62. package/dist/state/app-selectors.js +33 -3
  63. package/dist/state/combined-root-state.d.ts +2 -0
  64. package/dist/state/combined-root-state.js +1 -0
  65. package/dist/state/create-slam-app-store.d.ts +1 -1
  66. package/dist/state/create-slam-app-store.js +27 -13
  67. package/dist/state/gps-ar-pose-sampler.d.ts +3 -3
  68. package/dist/state/gps-event-coordinator.d.ts +1 -1
  69. package/dist/state/index.d.ts +17 -16
  70. package/dist/state/index.js +6 -4
  71. package/dist/state/persistence-middleware.d.ts +2 -2
  72. package/dist/state/persistence-middleware.js +35 -7
  73. package/dist/state/recording-options.d.ts +1 -1
  74. package/dist/state/recording-replayer.d.ts +2 -2
  75. package/dist/state/recording-slice.d.ts +1 -1
  76. package/dist/state/replay-engine.d.ts +1 -1
  77. package/dist/state/store-subscribers.d.ts +2 -2
  78. package/dist/state/store-subscribers.js +38 -12
  79. package/dist/state/subscribe-to-selector.d.ts +1 -1
  80. package/dist/state/tracking-quality.d.ts +2 -0
  81. package/dist/state/tracking-quality.js +723 -0
  82. package/dist/state/tracking-slice.d.ts +2 -0
  83. package/dist/state/tracking-slice.js +147 -0
  84. package/dist/storage/file-system-utils.d.ts +1 -1
  85. package/dist/storage/file-system.d.ts +2 -2
  86. package/dist/storage/file-system.js +52 -1
  87. package/dist/storage/index.d.ts +8 -8
  88. package/dist/storage/null-storage-backend.d.ts +1 -1
  89. package/dist/storage/opfs-storage-backend.d.ts +1 -1
  90. package/dist/storage/opfs-storage.d.ts +1 -1
  91. package/dist/storage/storage-backend.d.ts +1 -1
  92. package/dist/storage/zip-export.d.ts +1 -1
  93. package/dist/storage/zip-reader.d.ts +1 -1
  94. package/dist/storage/zip-reader.js +8 -4
  95. package/dist/{storage-backend-yVnuWGTr.d.ts → storage-backend-CT0Il_AB.d.ts} +1 -1
  96. package/dist/{store-subscribers-DKKHld49.d.ts → store-subscribers-Dce_CoJF.d.ts} +31 -6
  97. package/dist/{subscribe-to-selector-ghDKYtap.d.ts → subscribe-to-selector-DIHm3BRZ.d.ts} +1 -1
  98. package/dist/test-utils/browser-mocks.d.ts +1 -1
  99. package/dist/test-utils/zip-round-trip-helpers.d.ts +7 -1
  100. package/dist/test-utils/zip-round-trip-helpers.js +2 -1
  101. package/dist/tracking-slice-utCNND8t.d.ts +86 -0
  102. package/dist/types/ar-types.d.ts +1 -1
  103. package/dist/types/geo-types.d.ts +2 -2
  104. package/dist/types/index.d.ts +3 -3
  105. package/dist/utils/concurrency.d.ts +1 -1
  106. package/dist/utils/failure-tracker.d.ts +1 -1
  107. package/dist/utils/format-file-size.d.ts +1 -1
  108. package/dist/utils/fused-path.d.ts +1 -1
  109. package/dist/utils/index.d.ts +6 -6
  110. package/dist/utils/list-formatter.d.ts +1 -1
  111. package/dist/utils/logger.d.ts +1 -1
  112. package/dist/utils/logger.js +68 -8
  113. package/dist/visualization/accuracy-circles.d.ts +2 -0
  114. package/dist/visualization/accuracy-circles.js +57 -0
  115. package/dist/visualization/alignment-lerper.d.ts +1 -1
  116. package/dist/visualization/camera-follower.d.ts +1 -1
  117. package/dist/visualization/css3d-renderer-manager.d.ts +1 -1
  118. package/dist/visualization/frustum-visibility.d.ts +2 -0
  119. package/dist/visualization/frustum-visibility.js +139 -0
  120. package/dist/visualization/gps-anchor.d.ts +2 -0
  121. package/dist/visualization/gps-anchor.js +2 -0
  122. package/dist/visualization/gps-compass-cubes.d.ts +1 -1
  123. package/dist/visualization/gps-event-markers.d.ts +2 -2
  124. package/dist/visualization/gps-event-markers.js +69 -2
  125. package/dist/visualization/index.d.ts +17 -12
  126. package/dist/visualization/index.js +6 -2
  127. package/dist/visualization/leaflet-map-overlay.d.ts +1 -1
  128. package/dist/visualization/leaflet-map-overlay.js +33 -79
  129. package/dist/visualization/lerp-utils.d.ts +1 -1
  130. package/dist/visualization/map-data.d.ts +2 -0
  131. package/dist/visualization/map-data.js +33 -0
  132. package/dist/visualization/map-overlay-draw.d.ts +2 -0
  133. package/dist/visualization/map-overlay-draw.js +107 -0
  134. package/dist/visualization/map-overlay.d.ts +1 -1
  135. package/dist/visualization/three-dispose.d.ts +1 -1
  136. package/dist/visualization/vis-colors.d.ts +1 -1
  137. package/dist/{webxr-session-COlSrXdL.d.ts → webxr-session-DB5cIZnN.d.ts} +53 -12
  138. package/dist/{zip-reader-KgJEXbca.d.ts → zip-reader-D1105idz.d.ts} +5 -0
  139. package/package.json +16 -16
  140. package/dist/ar/tracking-state.d.ts +0 -2
  141. package/dist/ar/tracking-state.js +0 -164
  142. package/dist/combined-root-state-B3SvPNjU.d.ts +0 -6
  143. package/dist/create-slam-app-store-DBm7g2Zd.d.ts +0 -85
  144. package/dist/gps-anchored-mesh-manager-CovAFK4g.d.ts +0 -56
  145. package/dist/gps-event-markers-sVyO9utS.d.ts +0 -67
  146. package/dist/persistence-middleware-z-75iisb.d.ts +0 -31
  147. package/dist/tracking-state-B9QfuZCg.d.ts +0 -101
  148. package/dist/visualization/gps-anchored-mesh-manager.d.ts +0 -2
  149. package/dist/visualization/gps-anchored-mesh-manager.js +0 -128
  150. /package/dist/{alignment-lerper-D9BeDwZX.d.ts → alignment-lerper-L1RbWHQ4.d.ts} +0 -0
  151. /package/dist/{ar-types-B-ORgk6Z.d.ts → ar-types-Ck8LEq8k.d.ts} +0 -0
  152. /package/dist/{camera-blit-capture-DHuyrrxr.d.ts → camera-blit-capture-C1V9I1Z6.d.ts} +0 -0
  153. /package/dist/{camera-follower-BMqPddxx.d.ts → camera-follower-1k8mnw5J.d.ts} +0 -0
  154. /package/dist/{capture-failure-tracker-2Q6oI2uQ.d.ts → capture-failure-tracker-JKb1ST8E.d.ts} +0 -0
  155. /package/dist/{chromium-camera-access-workaround-CU5zSKNr.d.ts → chromium-camera-access-workaround-NvChXsi8.d.ts} +0 -0
  156. /package/dist/{concurrency-p6gB30fT.d.ts → concurrency-CMw8pSaG.d.ts} +0 -0
  157. /package/dist/{css3d-renderer-manager-rgLMVAvd.d.ts → css3d-renderer-manager-CkjCb2HW.d.ts} +0 -0
  158. /package/dist/{failure-tracker-1sQ_Cgyw.d.ts → failure-tracker-DnHXOIRa.d.ts} +0 -0
  159. /package/dist/{file-system-utils-BH8FdyIu.d.ts → file-system-utils-CtKiiw27.d.ts} +0 -0
  160. /package/dist/{format-file-size-onGq0k1Q.d.ts → format-file-size-BTS5H62-.d.ts} +0 -0
  161. /package/dist/{gps-compass-cubes-jRIJMOuh.d.ts → gps-compass-cubes-CsLtFv4B.d.ts} +0 -0
  162. /package/dist/{gps-error-handler-CH1S528z.d.ts → gps-error-handler-Dg3ziRVY.d.ts} +0 -0
  163. /package/dist/{h3-proximity-GwesPTFT.d.ts → h3-proximity-BhfgNbdW.d.ts} +0 -0
  164. /package/dist/{lerp-utils-CZgQlrmu.d.ts → lerp-utils-B8MM8zCR.d.ts} +0 -0
  165. /package/dist/{list-formatter-DKQQVLcl.d.ts → list-formatter-CNqi-E2j.d.ts} +0 -0
  166. /package/dist/{map-overlay-C9ifl_4-.d.ts → map-overlay-DAmreyA3.d.ts} +0 -0
  167. /package/dist/{opfs-storage-Dlq1I_Gb.d.ts → opfs-storage-DOPkzgeT.d.ts} +0 -0
  168. /package/dist/{recording-options-BYUFX8iU.d.ts → recording-options-Dq6IsKAv.d.ts} +0 -0
  169. /package/dist/{scene-node-names-DPsaE2z3.d.ts → scene-node-names-6LBjPmwz.d.ts} +0 -0
  170. /package/dist/{three-dispose-qt_r5wR1.d.ts → three-dispose-C2drkp6f.d.ts} +0 -0
  171. /package/dist/{vis-colors-BKkdTIKb.d.ts → vis-colors-CHQhjal3.d.ts} +0 -0
  172. /package/dist/{xr-camera-texture-BbukNE79.d.ts → xr-camera-texture-BU5YvKAM.d.ts} +0 -0
  173. /package/dist/{xr-error-handler-DTHfmvrl.d.ts → xr-error-handler-CDY5QxGb.d.ts} +0 -0
  174. /package/dist/{zip-export-BjrQPv0X.d.ts → zip-export-QO4iLIi7.d.ts} +0 -0
@@ -1,5 +1,6 @@
1
1
  import { createLogger } from "../utils/logger.js";
2
2
  import { VIS_COLORS } from "./vis-colors.js";
3
+ import { drawMapData } from "./map-overlay-draw.js";
3
4
  import { CSS3DObject } from "three/addons/renderers/CSS3DRenderer.js";
4
5
  import L from "leaflet";
5
6
  //#region ../src/visualization/leaflet-map-overlay.ts
@@ -35,14 +36,9 @@ var LeafletMapOverlay = class {
35
36
  leafletMap = null;
36
37
  tileLayer = null;
37
38
  cssObject = null;
38
- rawGpsPoints = [];
39
- fusedPoints = [];
40
- snapshotPoints = [];
39
+ latestMapData = null;
40
+ trajectoryLayers = [];
41
41
  namedMarkers = [];
42
- userMarker = null;
43
- rawGpsPolyline = null;
44
- fusedPolyline = null;
45
- snapshotPolyline = null;
46
42
  constructor(scene, camera, options = {}) {
47
43
  this.scene = scene;
48
44
  this.camera = camera;
@@ -60,10 +56,7 @@ var LeafletMapOverlay = class {
60
56
  lat,
61
57
  lon
62
58
  };
63
- if (this.leafletMap) {
64
- this.leafletMap.setView([lat, lon], this.zoomLevel);
65
- this.updateUserMarker();
66
- }
59
+ if (this.leafletMap) this.leafletMap.setView([lat, lon], this.zoomLevel);
67
60
  }
68
61
  getGpsPosition() {
69
62
  return this.gpsPosition;
@@ -93,38 +86,22 @@ var LeafletMapOverlay = class {
93
86
  isVisible() {
94
87
  return this.visible;
95
88
  }
96
- addRawGpsPoint(lat, lon) {
97
- this.rawGpsPoints.push([lat, lon]);
98
- if (this.leafletMap) {
99
- if (!this.rawGpsPolyline) this.rawGpsPolyline = L.polyline([], {
100
- color: VIS_COLORS.RAW_GPS.css,
101
- weight: 3,
102
- opacity: .8
103
- }).addTo(this.leafletMap);
104
- this.rawGpsPolyline.addLatLng([lat, lon]);
105
- }
106
- }
107
- addFusedPoint(lat, lon) {
108
- this.fusedPoints.push([lat, lon]);
109
- if (this.leafletMap) {
110
- if (!this.fusedPolyline) this.fusedPolyline = L.polyline([], {
111
- color: VIS_COLORS.FUSED_VIO.css,
112
- weight: 3,
113
- opacity: .8
114
- }).addTo(this.leafletMap);
115
- this.fusedPolyline.addLatLng([lat, lon]);
116
- }
117
- }
118
- addAlignmentSnapshot(lat, lon) {
119
- this.snapshotPoints.push([lat, lon]);
120
- if (this.leafletMap) {
121
- if (!this.snapshotPolyline) this.snapshotPolyline = L.polyline([], {
122
- color: VIS_COLORS.ALIGNMENT_SNAPSHOT.css,
123
- weight: 3,
124
- opacity: .8
125
- }).addTo(this.leafletMap);
126
- this.snapshotPolyline.addLatLng([lat, lon]);
127
- }
89
+ /**
90
+ * Render a full trajectory snapshot.
91
+ *
92
+ * Replaces the previous incremental `addRawGpsPoint` / `addFusedPoint` /
93
+ * `addAlignmentSnapshot` API with a single full-snapshot path: the caller
94
+ * builds a {@link MapData} (via the shared `buildMapData`) from the latest
95
+ * store slices and hands it here. The trajectory layers are redrawn
96
+ * wholesale through the shared {@link drawMapData} routine, so the live map
97
+ * stays pixel-identical to the 2D session-summary map and the fused path
98
+ * recomputes (D2) as the alignment matrix improves.
99
+ *
100
+ * Buffered when the map is not yet shown; applied on `show()`.
101
+ */
102
+ render(data) {
103
+ this.latestMapData = data;
104
+ if (this.leafletMap) this.drawTrajectory();
128
105
  }
129
106
  /** Add a "current" named marker (red). Buffered if map is not yet shown. */
130
107
  addCurrentMarker(lat, lon, name) {
@@ -199,9 +176,8 @@ var LeafletMapOverlay = class {
199
176
  dispose() {
200
177
  this.hide();
201
178
  this.destroyLeafletMap();
202
- this.rawGpsPoints = [];
203
- this.fusedPoints = [];
204
- this.snapshotPoints = [];
179
+ this.latestMapData = null;
180
+ this.trajectoryLayers = [];
205
181
  this.namedMarkers = [];
206
182
  this.cssObject = null;
207
183
  log.info("Leaflet map overlay disposed");
@@ -232,14 +208,8 @@ var LeafletMapOverlay = class {
232
208
  this.tileLayer.addTo(this.leafletMap);
233
209
  }
234
210
  destroyLeafletMap() {
235
- this.userMarker?.remove();
236
- this.userMarker = null;
237
- this.rawGpsPolyline?.remove();
238
- this.rawGpsPolyline = null;
239
- this.fusedPolyline?.remove();
240
- this.fusedPolyline = null;
241
- this.snapshotPolyline?.remove();
242
- this.snapshotPolyline = null;
211
+ for (const layer of this.trajectoryLayers) layer.remove();
212
+ this.trajectoryLayers = [];
243
213
  for (const m of this.namedMarkers) {
244
214
  m.marker?.remove();
245
215
  m.marker = null;
@@ -273,33 +243,17 @@ var LeafletMapOverlay = class {
273
243
  }
274
244
  applyBufferedOverlays() {
275
245
  if (!this.leafletMap) return;
276
- this.updateUserMarker();
277
- if (this.rawGpsPoints.length > 0) this.rawGpsPolyline = L.polyline(this.rawGpsPoints, {
278
- color: VIS_COLORS.RAW_GPS.css,
279
- weight: 3,
280
- opacity: .8
281
- }).addTo(this.leafletMap);
282
- if (this.fusedPoints.length > 0) this.fusedPolyline = L.polyline(this.fusedPoints, {
283
- color: VIS_COLORS.FUSED_VIO.css,
284
- weight: 3,
285
- opacity: .8
286
- }).addTo(this.leafletMap);
287
- if (this.snapshotPoints.length > 0) this.snapshotPolyline = L.polyline(this.snapshotPoints, {
288
- color: VIS_COLORS.ALIGNMENT_SNAPSHOT.css,
289
- weight: 3,
290
- opacity: .8
291
- }).addTo(this.leafletMap);
246
+ this.drawTrajectory();
292
247
  for (const m of this.namedMarkers) if (!m.marker) m.marker = this.createNamedMarker(m.lat, m.lng, m.name, m.isPrior);
293
248
  }
294
- updateUserMarker() {
295
- if (!this.gpsPosition || !this.leafletMap) return;
296
- if (this.userMarker) this.userMarker.setLatLng([this.gpsPosition.lat, this.gpsPosition.lon]);
297
- else this.userMarker = L.marker([this.gpsPosition.lat, this.gpsPosition.lon], { icon: L.divIcon({
298
- className: "",
299
- html: `<div style="background:${VIS_COLORS.USER_POSITION.css};width:14px;height:14px;border-radius:50%;border:3px solid white;box-shadow:0 0 6px rgba(59,130,246,0.6);"></div>`,
300
- iconSize: [14, 14],
301
- iconAnchor: [7, 7]
302
- }) }).addTo(this.leafletMap);
249
+ /**
250
+ * Redraw the trajectory layers from {@link latestMapData} via the shared
251
+ * {@link drawMapData} routine, removing any layers from the previous draw.
252
+ */
253
+ drawTrajectory() {
254
+ if (!this.leafletMap || !this.latestMapData) return;
255
+ for (const layer of this.trajectoryLayers) layer.remove();
256
+ this.trajectoryLayers = drawMapData(this.leafletMap, this.latestMapData, { showUserPosition: true }).layers;
303
257
  }
304
258
  createNamedMarker(lat, lon, name, isPrior) {
305
259
  const color = isPrior ? VIS_COLORS.PRIOR_REF_POINT.css : VIS_COLORS.CURRENT_REF_POINT.css;
@@ -1,2 +1,2 @@
1
- import { n as clampedAlpha, t as DEFAULT_LERP_RATE } from "../lerp-utils-CZgQlrmu.js";
1
+ import { n as clampedAlpha, t as DEFAULT_LERP_RATE } from "../lerp-utils-B8MM8zCR.js";
2
2
  export { DEFAULT_LERP_RATE, clampedAlpha };
@@ -0,0 +1,2 @@
1
+ import { n as MapDataInput, r as buildMapData, t as MapData } from "../map-data-sih4g64v.js";
2
+ export { MapData, MapDataInput, buildMapData };
@@ -0,0 +1,33 @@
1
+ import { computeFusedPath } from "../utils/fused-path.js";
2
+ //#region ../src/visualization/map-data.ts
3
+ /**
4
+ * Build a {@link MapData} snapshot from store-derived inputs.
5
+ *
6
+ * Pure and free of Leaflet/Three dependencies. The fused path is always
7
+ * derived via {@link computeFusedPath} (D2); when the matrix or zero reference
8
+ * is missing it is an empty array.
9
+ *
10
+ * @param input - Optional trajectory slices (see {@link MapDataInput}).
11
+ * @returns A fully-resolved {@link MapData} with all arrays defensively copied.
12
+ */
13
+ function buildMapData(input) {
14
+ const rawGpsPath = input.rawGpsPath ? [...input.rawGpsPath] : [];
15
+ const alignmentSnapshots = input.alignmentSnapshots ? [...input.alignmentSnapshots] : [];
16
+ const fusedPath = computeFusedPath({
17
+ odometryPositions: input.odometryPositions ?? [],
18
+ alignmentMatrix: input.alignmentMatrix ?? null,
19
+ zeroRef: input.zeroRef ?? null
20
+ });
21
+ const lastRaw = rawGpsPath[rawGpsPath.length - 1];
22
+ return {
23
+ userPosition: input.userPosition !== void 0 ? input.userPosition : lastRaw ? {
24
+ lat: lastRaw.lat,
25
+ lng: lastRaw.lng
26
+ } : null,
27
+ rawGpsPath,
28
+ fusedPath,
29
+ alignmentSnapshots
30
+ };
31
+ }
32
+ //#endregion
33
+ export { buildMapData };
@@ -0,0 +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-B3R1c9Xp.js";
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 };
@@ -0,0 +1,107 @@
1
+ import { VIS_COLORS } from "./vis-colors.js";
2
+ import { addAccuracyCircles } from "./accuracy-circles.js";
3
+ import L from "leaflet";
4
+ //#region ../src/visualization/map-overlay-draw.ts
5
+ /**
6
+ * Shared map-overlay-drawing module.
7
+ *
8
+ * `drawMapData` is the SINGLE Leaflet drawing routine rendered by BOTH map
9
+ * consumers — the live/replay 3D overlay (`LeafletMapOverlay`) and the 2D
10
+ * session-summary map (`createSummaryMap`). Centralising the drawing here is
11
+ * Phase 3 of the map-system review and the fix for Findings 1 & 4 of the
12
+ * unified-trajectory-map user feedback: previously each renderer drew the
13
+ * trajectory by hand and the two visibly diverged.
14
+ *
15
+ * It consumes the resolved {@link MapData} produced by `buildMapData` and adds,
16
+ * in this order:
17
+ * 1. per-event accuracy circles for the raw GPS path (drawn first so the
18
+ * polyline stays on top), then the raw GPS polyline;
19
+ * 2. the fused (SLAM+GPS) polyline;
20
+ * 3. the alignment-snapshot polyline;
21
+ * 4. (optional) a user-position marker.
22
+ *
23
+ * SCOPE: this module draws only the genuinely-shared SLAM/GPS trajectory
24
+ * layers. Reference-point markers are a RECORDER concept and are drawn by the
25
+ * recorder-owned `ui/draw-ref-point-markers.ts` helper (called from both the
26
+ * summary map and the live overlay wiring), so the two maps stay identical
27
+ * while the framework remains ref-point-agnostic. See
28
+ * gps-plus-slam/GpsPlusSlamJs_Docs/docs/2026-05-31-unified-trajectory-map-phase3-plan.md
29
+ * § Step 5.
30
+ *
31
+ * The caller owns map creation, tile layer, `fitBounds`, resize handling and
32
+ * fullscreen — this module only draws data layers and reports the accumulated
33
+ * bounds so the caller can frame the view.
34
+ */
35
+ /** Raw GPS polyline + accuracy-circle color (yellow). */
36
+ const RAW_GPS_COLOR = VIS_COLORS.RAW_GPS.css;
37
+ /** Fused SLAM+GPS polyline color (cyan). */
38
+ const FUSED_PATH_COLOR = VIS_COLORS.FUSED_VIO.css;
39
+ /** Alignment-snapshot polyline color (red). */
40
+ const ALIGNMENT_SNAPSHOT_COLOR = VIS_COLORS.ALIGNMENT_SNAPSHOT.css;
41
+ /** User-position marker color (blue). */
42
+ const USER_POSITION_COLOR = VIS_COLORS.USER_POSITION.css;
43
+ /** Polyline weight (px) — matches the recorder's `PATH_POLYLINE_WEIGHT`. */
44
+ const MAP_PATH_POLYLINE_WEIGHT = 3;
45
+ /** Polyline opacity — matches the recorder's `PATH_POLYLINE_OPACITY`. */
46
+ const MAP_PATH_POLYLINE_OPACITY = .8;
47
+ /**
48
+ * Draw a {@link MapData} snapshot onto an existing Leaflet map.
49
+ *
50
+ * @param map - Target map (already created with a tile layer by the caller).
51
+ * @param data - Resolved trajectory data from `buildMapData`.
52
+ * @param options - Optional layer toggles (see {@link DrawMapDataOptions}).
53
+ * @returns The created layers and the bounds spanning every drawn coordinate.
54
+ */
55
+ function drawMapData(map, data, options = {}) {
56
+ const layers = [];
57
+ const bounds = L.latLngBounds([]);
58
+ if (data.rawGpsPath.length > 0) {
59
+ const rawLatLngs = data.rawGpsPath.map((p) => [p.lat, p.lng]);
60
+ const circles = addAccuracyCircles(map, data.rawGpsPath, RAW_GPS_COLOR);
61
+ layers.push(...circles);
62
+ const rawPolyline = L.polyline(rawLatLngs, {
63
+ color: RAW_GPS_COLOR,
64
+ weight: 3,
65
+ opacity: MAP_PATH_POLYLINE_OPACITY
66
+ }).addTo(map);
67
+ layers.push(rawPolyline);
68
+ for (const ll of rawLatLngs) bounds.extend(ll);
69
+ }
70
+ if (data.fusedPath.length > 0) {
71
+ const fusedLatLngs = data.fusedPath.map((p) => [p.lat, p.lng]);
72
+ const fusedPolyline = L.polyline(fusedLatLngs, {
73
+ color: FUSED_PATH_COLOR,
74
+ weight: 3,
75
+ opacity: MAP_PATH_POLYLINE_OPACITY
76
+ }).addTo(map);
77
+ layers.push(fusedPolyline);
78
+ for (const ll of fusedLatLngs) bounds.extend(ll);
79
+ }
80
+ if (data.alignmentSnapshots.length > 0) {
81
+ const snapshotLatLngs = data.alignmentSnapshots.map((p) => [p.lat, p.lng]);
82
+ const snapshotPolyline = L.polyline(snapshotLatLngs, {
83
+ color: ALIGNMENT_SNAPSHOT_COLOR,
84
+ weight: 3,
85
+ opacity: MAP_PATH_POLYLINE_OPACITY
86
+ }).addTo(map);
87
+ layers.push(snapshotPolyline);
88
+ for (const ll of snapshotLatLngs) bounds.extend(ll);
89
+ }
90
+ if (options.showUserPosition && data.userPosition) {
91
+ const icon = L.divIcon({
92
+ className: "map-overlay-user-position",
93
+ html: `<div style="background:${USER_POSITION_COLOR};width:14px;height:14px;border-radius:50%;border:2px solid white;"></div>`,
94
+ iconSize: [18, 18],
95
+ iconAnchor: [9, 9]
96
+ });
97
+ const marker = L.marker([data.userPosition.lat, data.userPosition.lng], { icon }).addTo(map);
98
+ layers.push(marker);
99
+ bounds.extend([data.userPosition.lat, data.userPosition.lng]);
100
+ }
101
+ return {
102
+ layers,
103
+ bounds
104
+ };
105
+ }
106
+ //#endregion
107
+ export { ALIGNMENT_SNAPSHOT_COLOR, 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-C9ifl_4-.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-DAmreyA3.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-qt_r5wR1.js";
1
+ import { n as disposeMeshArray, r as disposeObject3D, t as DisposeOptions } from "../three-dispose-C2drkp6f.js";
2
2
  export { DisposeOptions, disposeMeshArray, disposeObject3D };
@@ -1,2 +1,2 @@
1
- import { t as VIS_COLORS } from "../vis-colors-BKkdTIKb.js";
1
+ import { t as VIS_COLORS } from "../vis-colors-CHQhjal3.js";
2
2
  export { VIS_COLORS };
@@ -1,13 +1,30 @@
1
- import { i as DepthSample, t as ARPose } from "./ar-types-B-ORgk6Z.js";
2
- import { i as ImageCaptureConfig, t as CapturedImage } from "./image-capture-2pKjYUS6.js";
3
- import { t as Css3dRendererManager } from "./css3d-renderer-manager-rgLMVAvd.js";
4
- import { n as ResetTransformData } from "./tracking-state-B9QfuZCg.js";
5
- import { t as ArCrashIsolationOptions } from "./recording-options-BYUFX8iU.js";
6
- import { r as XRCameraLike } from "./xr-camera-texture-BbukNE79.js";
1
+ import { i as DepthSample, t as ARPose } from "./ar-types-Ck8LEq8k.js";
2
+ import { i as ImageCaptureConfig, t as CapturedImage } from "./image-capture-DZLxHDN9.js";
3
+ import { t as Css3dRendererManager } from "./css3d-renderer-manager-CkjCb2HW.js";
4
+ import { a as TrackingSliceState, r as ResetTransformData } from "./tracking-slice-utCNND8t.js";
5
+ import { t as ArCrashIsolationOptions } from "./recording-options-Dq6IsKAv.js";
6
+ import { r as XRCameraLike } from "./xr-camera-texture-BU5YvKAM.js";
7
7
  import * as THREE from "three";
8
8
  import { OdometryTrackingRestartedPayload } from "gps-plus-slam-js";
9
9
 
10
10
  //#region ../src/ar/webxr-session.d.ts
11
+ /**
12
+ * Minimal subscribable-store contract the tracking pipeline needs:
13
+ * dispatch the slice actions, read the slice for the restart payload, and
14
+ * subscribe to phase transitions. Structurally compatible with the full
15
+ * `SlamAppStore` (and any test double) without coupling this module to the
16
+ * factory's exact generics.
17
+ */
18
+ interface TrackingSubscribableStore {
19
+ dispatch: (action: {
20
+ type: string;
21
+ payload?: unknown;
22
+ }) => unknown;
23
+ getState: () => {
24
+ tracking: TrackingSliceState;
25
+ };
26
+ subscribe: (listener: () => void) => () => void;
27
+ }
11
28
  declare function isXRCameraLike(value: unknown): value is XRCameraLike;
12
29
  /**
13
30
  * Extract a validated XRCameraLike from an XRViewerPose.
@@ -114,8 +131,18 @@ declare function isWebXRSupported(): Promise<boolean>;
114
131
  * basisChangeNode is a static scene-graph node that holds the WEBXR_TO_NUE
115
132
  * basis-change matrix permanently (matrixAutoUpdate=false). Moving it here
116
133
  * instead of composing it in applyAlignmentMatrix() keeps arWorldGroup's
117
- * local space as NUE: objects added directly to arWorldGroup can be placed
118
- * at [1,0,0]=North, [0,0,1]=East without any WebXR↔NUE conversion.
134
+ * local space in the **NUE axis convention** (X=North, Y=Up, Z=East), so no
135
+ * WebXR↔NUE swizzle is needed for children.
136
+ *
137
+ * CAUTION — two NUE frames: arWorldGroup's local space is the *AR-odometry*
138
+ * NUE frame, i.e. the **domain** of the alignment matrix, NOT the GPS-world
139
+ * NUE frame of the scene root. Only content authored in AR-odometry
140
+ * coordinates (e.g. the camera subtree) may be placed with raw local values.
141
+ * GPS-world content (a lat/lon → NUE point) is expressed in the scene-root
142
+ * frame and must be pre-multiplied by alignment⁻¹ before being used as a
143
+ * local position under arWorldGroup — see createGpsAnchor and the
144
+ * alignment-frame bug doc
145
+ * (GpsPlusSlamJs_Docs/docs/2026-05-31-gps-anchor-alignment-frame-bug.md).
119
146
  *
120
147
  * - Recording: arpose stays at identity; WebXRManager writes to camera.
121
148
  * - Replay: arpose receives recorded odomPosition/odomRotation;
@@ -225,9 +252,12 @@ declare function nueQuaternionToWebXR$1(nue: readonly number[]): readonly [numbe
225
252
  /**
226
253
  * End the current XR session and clean up all resources.
227
254
  *
228
- * Stops the animation loop, disposes the WebGL renderer, removes the
229
- * canvas from the DOM, and tears down the CSS3D overlay. This is the
230
- * production cleanup path call it when the AR experience is finished.
255
+ * Stops the animation loop, ends the XR session, then delegates the full
256
+ * teardown to {@link resetWebXRState} so every module-level reference is
257
+ * cleared (renderer/scene/camera, image-capture, depth, the tracking-phase
258
+ * subscription, the frame-update registry, diagnostics, blit resources).
259
+ * This is the production cleanup path — call it when the AR experience is
260
+ * finished.
231
261
  */
232
262
  declare function endARSession(): Promise<void>;
233
263
  /**
@@ -255,6 +285,17 @@ declare function stopImageCapture(): void;
255
285
  * Get the current image capture frame count.
256
286
  */
257
287
  declare function getImageCaptureFrameCount(): number;
288
+ /**
289
+ * Inject the Redux store used by the tracking-state slice pipeline.
290
+ *
291
+ * MUST be called before `initAR()` whenever the host also wires tracking
292
+ * callbacks via `setTrackingCallbacks`. Without a store the tracking
293
+ * pipeline silently no-ops.
294
+ *
295
+ * @param store — any store satisfying {@link TrackingSubscribableStore}.
296
+ * `null` clears the binding (useful for teardown in tests).
297
+ */
298
+ declare function setTrackingStore(store: TrackingSubscribableStore | null): void;
258
299
  /**
259
300
  * Set up tracking state callbacks.
260
301
  * Call this BEFORE initAR() to enable tracking restart detection.
@@ -313,4 +354,4 @@ declare function setFrameCallback(callback: (() => void) | null): void;
313
354
  */
314
355
  declare function getLiveCss3dManager(): Css3dRendererManager | null;
315
356
  //#endregion
316
- export { setTrackingLostCallback as A, setArWorldGroup as C, setImageCaptureCallback as D, setFrameCallback as E, stopDepthCapture as F, stopImageCapture as I, shouldLogCameraAccessDiagnostic as M, startDepthCapture as N, setScene as O, startImageCapture 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 };
357
+ export { setTrackingCallbacks as A, setArPose as C, setFrameCallback as D, setDepthCaptureCallback as E, startDepthCapture as F, startImageCapture as I, stopDepthCapture as L, setTrackingRecoveredCallback as M, setTrackingStore as N, setImageCaptureCallback as O, shouldLogCameraAccessDiagnostic as P, stopImageCapture as R, resetWebXRState as S, setCamera as T, initAR as _, endARSession as a, nuePositionToWebXR as b, getArPose as c, getCurrentArPose as d, getDepthSampleCount as f, getXrCameraFromPose as g, getScene as h, createSceneHierarchy as i, setTrackingLostCallback as j, setScene as k, getArWorldGroup as l, getLiveCss3dManager as m, applyAlignmentMatrix as n, extractPoseFromViewer as o, getImageCaptureFrameCount as p, buildSessionOptions as r, extractResetTransformData as s, TrackingSubscribableStore as t, getCamera as u, isWebXRSupported as v, setArWorldGroup as w, nueQuaternionToWebXR$1 as x, isXRCameraLike as y };
@@ -77,6 +77,11 @@ declare function loadSessionMetadataFromBlob(blob: Blob, maxFileSize?: number):
77
77
  interface GpsPathCoord {
78
78
  readonly lat: number;
79
79
  readonly lng: number;
80
+ /**
81
+ * Horizontal accuracy in meters (1σ), if the source GPS event included it.
82
+ * Used by 2D-map previews to draw a per-event accuracy circle.
83
+ */
84
+ readonly accuracy?: number;
80
85
  }
81
86
  /**
82
87
  * Extract GPS coordinates from a recording zip provided as a Blob.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gps-plus-slam-app-framework",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "description": "Reusable AR+GPS app framework layer — WebXR session management, Three.js visualization, GPS sensors, storage abstractions, replay engine, and store wiring for gps-plus-slam-js.",
5
5
  "type": "module",
6
6
  "files": [
@@ -36,7 +36,7 @@
36
36
  "dependencies": {
37
37
  "@reduxjs/toolkit": "^2.11.2",
38
38
  "gl-matrix": "3.4.4",
39
- "gps-plus-slam-js": "^1.0.6"
39
+ "gps-plus-slam-js": "^1.0.7"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "@sentry/browser": ">=10.0.0",
@@ -55,27 +55,27 @@
55
55
  },
56
56
  "devDependencies": {
57
57
  "@eslint/js": "^10.0.1",
58
- "@sentry/browser": "^10.49.0",
58
+ "@sentry/browser": "^10.53.1",
59
59
  "@types/leaflet": "^1.9.21",
60
- "@types/node": "^25.6.0",
61
- "@types/three": "^0.184.0",
62
- "@vitest/coverage-v8": "^4.1.5",
63
- "@vitest/eslint-plugin": "^1.6.16",
60
+ "@types/node": "^25.7.0",
61
+ "@types/three": "^0.184.1",
62
+ "@vitest/coverage-v8": "^4.1.6",
63
+ "@vitest/eslint-plugin": "^1.6.17",
64
64
  "@zip.js/zip.js": "^2.8.26",
65
- "dpdm": "^4.0.1",
66
- "eslint": "^10.2.1",
65
+ "dpdm": "^4.2.0",
66
+ "eslint": "^10.3.0",
67
67
  "eslint-config-prettier": "^10.1.8",
68
- "fast-check": "^4.7.0",
69
- "globals": "^17.5.0",
68
+ "fast-check": "^4.8.0",
69
+ "globals": "^17.6.0",
70
70
  "h3-js": "^4.4.0",
71
- "jsdom": "^29.0.2",
71
+ "jsdom": "^29.1.1",
72
72
  "leaflet": "^1.9.4",
73
73
  "prettier": "^3.8.3",
74
74
  "three": "^0.184.0",
75
- "tsdown": "^0.21.9",
75
+ "tsdown": "^0.22.0",
76
76
  "typescript": "^6.0.3",
77
- "typescript-eslint": "^8.59.0",
78
- "vitest": "^4.1.5"
77
+ "typescript-eslint": "^8.59.3",
78
+ "vitest": "^4.1.6"
79
79
  },
80
80
  "keywords": [
81
81
  "ar",
@@ -105,7 +105,7 @@
105
105
  "verify:pack": "pnpm pack --dry-run",
106
106
  "verify:community-key-lifetime": "node scripts/verify-community-key-lifetime.mjs",
107
107
  "test:unit": "vitest run --coverage --config config/vitest.config.ts",
108
- "typecheck": "tsc -p tsconfig.json --noEmit",
108
+ "typecheck": "tsc -p tsconfig.app.json --noEmit",
109
109
  "typecheck:tests": "tsc -p tsconfig.vitest.json --noEmit",
110
110
  "lint": "eslint . --config config/eslint.config.mjs",
111
111
  "test:watch": "vitest --config config/vitest.config.ts",
@@ -1,2 +0,0 @@
1
- import { a as TrackingStateManager, i as TrackingStateCallbacks, n as ResetTransformData, r as TrackingState, t as DeviceOrientation } from "../tracking-state-B9QfuZCg.js";
2
- export { DeviceOrientation, ResetTransformData, TrackingState, TrackingStateCallbacks, TrackingStateManager };