gps-plus-slam-app-framework 1.0.0 → 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 (216) 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-DyMzxCEC.d.ts → app-selectors-BeU0_ab8.d.ts} +14 -15
  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/depth-sampler.js +1 -1
  10. package/dist/ar/frame-loop.d.ts +2 -0
  11. package/dist/ar/frame-loop.js +40 -0
  12. package/dist/ar/image-capture.d.ts +1 -1
  13. package/dist/ar/image-capture.js +1 -1
  14. package/dist/ar/index.d.ts +12 -12
  15. package/dist/ar/index.js +3 -3
  16. package/dist/ar/replay-scene.d.ts +1 -1
  17. package/dist/ar/scene-node-names.d.ts +1 -1
  18. package/dist/ar/webxr-session.d.ts +4 -4
  19. package/dist/ar/webxr-session.js +151 -56
  20. package/dist/ar/xr-camera-texture.d.ts +1 -1
  21. package/dist/ar/xr-error-handler.d.ts +1 -1
  22. package/dist/core/index.d.ts +2 -0
  23. package/dist/core/index.js +2 -0
  24. package/dist/create-slam-app-store-CNsZ3rcX.d.ts +371 -0
  25. package/dist/{depth-sampler-BNCtnEoP.d.ts → depth-sampler-xg8vna6c.d.ts} +1 -1
  26. package/dist/file-system-DTApEv_Q.d.ts +114 -0
  27. package/dist/frame-loop-QJIxLin0.d.ts +42 -0
  28. package/dist/frustum-visibility-BHnFrSKQ.d.ts +58 -0
  29. package/dist/{fused-path-DtqCSqJh.d.ts → fused-path-CB4DwWOG.d.ts} +1 -1
  30. package/dist/geo/h3-proximity.d.ts +2 -0
  31. package/dist/{ref-points/h3-ref-point.js → geo/h3-proximity.js} +16 -12
  32. package/dist/geo/index.d.ts +2 -0
  33. package/dist/geo/index.js +2 -0
  34. package/dist/{geo-types-Xx-LVcnw.d.ts → geo-types-CTuF23gG.d.ts} +16 -1
  35. package/dist/{gps-Ddzr2KlX.d.ts → gps-DXoQb9Kf.d.ts} +1 -1
  36. package/dist/gps-anchor-CnWY61XK.d.ts +48 -0
  37. package/dist/gps-anchor-DjC_3MoT.js +257 -0
  38. package/dist/gps-ar-pose-sampler-DsM1Kb2N.d.ts +43 -0
  39. package/dist/{recording-coordinator-DzflP07_.d.ts → gps-event-coordinator-DBx9I1YX.d.ts} +7 -6
  40. package/dist/gps-event-markers-BGr-iLvi.d.ts +103 -0
  41. package/dist/{h3-ref-point-CFhayNSZ.d.ts → h3-proximity-BhfgNbdW.d.ts} +16 -12
  42. package/dist/{image-capture-2pKjYUS6.d.ts → image-capture-DZLxHDN9.d.ts} +1 -1
  43. package/dist/index-gzWJMVpo.d.ts +2 -0
  44. package/dist/index-pOjUCKEP.d.ts +24 -0
  45. package/dist/index.d.ts +59 -56
  46. package/dist/index.js +22 -21
  47. package/dist/{leaflet-map-overlay-CvfQXTye.d.ts → leaflet-map-overlay-Cew7XAoO.d.ts} +32 -17
  48. package/dist/licensing/index.d.ts +1 -1
  49. package/dist/licensing/index.js +1 -1
  50. package/dist/{logger-B81iwxx0.d.ts → logger-C9vugiQb.d.ts} +7 -1
  51. package/dist/map-data-sih4g64v.d.ts +49 -0
  52. package/dist/map-overlay-draw-B3R1c9Xp.d.ts +42 -0
  53. package/dist/{null-storage-backend-CsWvQwN8.d.ts → null-storage-backend-BKOS7JpL.d.ts} +4 -2
  54. package/dist/{opfs-storage-ChOzF_Wp.d.ts → opfs-storage-DOPkzgeT.d.ts} +54 -51
  55. package/dist/opfs-storage-backend-Cj_7PWoq.d.ts +13 -0
  56. package/dist/{permission-checker-jO2ziCWC.d.ts → permission-checker-DPJl_RU6.d.ts} +41 -1
  57. package/dist/persistence-middleware-BkHIqvaA.d.ts +55 -0
  58. package/dist/{recording-replayer-oOzPITrd.d.ts → recording-replayer-CmCIIZ02.d.ts} +2 -2
  59. package/dist/recording-slice-d6OtCrza.d.ts +28 -0
  60. package/dist/{replay-engine-DuX316ae.d.ts → replay-engine-BGBRQyXs.d.ts} +4 -1
  61. package/dist/{replay-scene-DtUm6bsr.d.ts → replay-scene-DpAGcAKY.d.ts} +3 -3
  62. package/dist/sensors/gps-error-handler.d.ts +1 -1
  63. package/dist/sensors/gps.d.ts +1 -1
  64. package/dist/sensors/gps.js +2 -2
  65. package/dist/sensors/index.d.ts +3 -3
  66. package/dist/sensors/index.js +1 -1
  67. package/dist/sensors/permission-checker.d.ts +2 -2
  68. package/dist/sensors/permission-checker.js +79 -1
  69. package/dist/state/app-selectors.d.ts +2 -2
  70. package/dist/state/app-selectors.js +33 -3
  71. package/dist/state/combined-root-state.d.ts +2 -0
  72. package/dist/state/combined-root-state.js +1 -0
  73. package/dist/state/create-slam-app-store.d.ts +2 -0
  74. package/dist/state/create-slam-app-store.js +75 -0
  75. package/dist/state/gps-ar-pose-sampler.d.ts +4 -0
  76. package/dist/state/gps-ar-pose-sampler.js +19 -0
  77. package/dist/state/{recording-coordinator.d.ts → gps-event-coordinator.d.ts} +1 -1
  78. package/dist/state/{recording-coordinator.js → gps-event-coordinator.js} +3 -4
  79. package/dist/state/index.d.ts +17 -17
  80. package/dist/state/index.js +10 -8
  81. package/dist/state/persistence-middleware.d.ts +2 -2
  82. package/dist/state/persistence-middleware.js +39 -11
  83. package/dist/state/recording-options.d.ts +1 -1
  84. package/dist/state/recording-replayer.d.ts +3 -2
  85. package/dist/state/recording-replayer.js +2 -2
  86. package/dist/state/recording-slice.d.ts +2 -0
  87. package/dist/state/{recorder-slice.js → recording-slice.js} +7 -15
  88. package/dist/state/replay-engine.d.ts +1 -1
  89. package/dist/state/replay-engine.js +3 -3
  90. package/dist/state/store-subscribers.d.ts +2 -2
  91. package/dist/state/store-subscribers.js +38 -20
  92. package/dist/state/subscribe-to-selector.d.ts +1 -1
  93. package/dist/state/tracking-quality.d.ts +2 -0
  94. package/dist/state/tracking-quality.js +723 -0
  95. package/dist/state/tracking-slice.d.ts +2 -0
  96. package/dist/state/tracking-slice.js +147 -0
  97. package/dist/storage/file-system-utils.d.ts +1 -1
  98. package/dist/storage/file-system.d.ts +2 -2
  99. package/dist/storage/file-system.js +154 -94
  100. package/dist/storage/index.d.ts +9 -11
  101. package/dist/storage/index.js +5 -7
  102. package/dist/storage/null-storage-backend.d.ts +1 -1
  103. package/dist/storage/null-storage-backend.js +7 -0
  104. package/dist/storage/opfs-storage-backend.d.ts +1 -1
  105. package/dist/storage/opfs-storage-backend.js +7 -1
  106. package/dist/storage/opfs-storage.d.ts +2 -2
  107. package/dist/storage/opfs-storage.js +69 -85
  108. package/dist/storage/storage-backend.d.ts +2 -2
  109. package/dist/storage/zip-export.d.ts +2 -2
  110. package/dist/storage/zip-export.js +55 -62
  111. package/dist/storage/zip-reader.d.ts +2 -2
  112. package/dist/storage/zip-reader.js +32 -5
  113. package/dist/storage-backend-CT0Il_AB.d.ts +28 -0
  114. package/dist/{store-subscribers-CuoIzB5T.d.ts → store-subscribers-Dce_CoJF.d.ts} +31 -7
  115. package/dist/{subscribe-to-selector-UTZ0KkAc.d.ts → subscribe-to-selector-DIHm3BRZ.d.ts} +1 -1
  116. package/dist/test-utils/browser-mocks.d.ts +1 -1
  117. package/dist/test-utils/zip-round-trip-helpers.d.ts +7 -1
  118. package/dist/test-utils/zip-round-trip-helpers.js +6 -5
  119. package/dist/tracking-slice-utCNND8t.d.ts +86 -0
  120. package/dist/types/ar-types.d.ts +1 -1
  121. package/dist/types/geo-types.d.ts +2 -2
  122. package/dist/types/index.d.ts +3 -3
  123. package/dist/utils/concurrency.d.ts +1 -1
  124. package/dist/utils/failure-tracker.d.ts +1 -1
  125. package/dist/utils/format-file-size.d.ts +1 -1
  126. package/dist/utils/fused-path.d.ts +1 -1
  127. package/dist/utils/index.d.ts +6 -6
  128. package/dist/utils/list-formatter.d.ts +1 -1
  129. package/dist/utils/logger.d.ts +1 -1
  130. package/dist/utils/logger.js +68 -8
  131. package/dist/visualization/accuracy-circles.d.ts +2 -0
  132. package/dist/visualization/accuracy-circles.js +57 -0
  133. package/dist/visualization/alignment-lerper.d.ts +1 -1
  134. package/dist/visualization/camera-follower.d.ts +1 -1
  135. package/dist/visualization/css3d-renderer-manager.d.ts +1 -1
  136. package/dist/visualization/frustum-visibility.d.ts +2 -0
  137. package/dist/visualization/frustum-visibility.js +139 -0
  138. package/dist/visualization/gps-anchor.d.ts +2 -0
  139. package/dist/visualization/gps-anchor.js +2 -0
  140. package/dist/visualization/gps-compass-cubes.d.ts +1 -1
  141. package/dist/visualization/gps-event-markers.d.ts +2 -2
  142. package/dist/visualization/gps-event-markers.js +69 -2
  143. package/dist/visualization/index.d.ts +17 -12
  144. package/dist/visualization/index.js +6 -2
  145. package/dist/visualization/leaflet-map-overlay.d.ts +1 -1
  146. package/dist/visualization/leaflet-map-overlay.js +56 -98
  147. package/dist/visualization/lerp-utils.d.ts +1 -1
  148. package/dist/visualization/map-data.d.ts +2 -0
  149. package/dist/visualization/map-data.js +33 -0
  150. package/dist/visualization/map-overlay-draw.d.ts +2 -0
  151. package/dist/visualization/map-overlay-draw.js +107 -0
  152. package/dist/visualization/map-overlay.d.ts +1 -1
  153. package/dist/visualization/three-dispose.d.ts +1 -1
  154. package/dist/visualization/vis-colors.d.ts +1 -1
  155. package/dist/{webxr-session-COlSrXdL.d.ts → webxr-session-DB5cIZnN.d.ts} +53 -12
  156. package/dist/{zip-export-Rtpi75JJ.d.ts → zip-export-QO4iLIi7.d.ts} +58 -7
  157. package/dist/{zip-reader-D7pkpX8K.d.ts → zip-reader-D1105idz.d.ts} +38 -1
  158. package/package.json +29 -18
  159. package/dist/ar/tracking-state.d.ts +0 -2
  160. package/dist/ar/tracking-state.js +0 -164
  161. package/dist/community-license-key-ChZLCJyO.d.ts +0 -21
  162. package/dist/file-system-BsQgYCU3.d.ts +0 -128
  163. package/dist/gps-event-markers-DpEy2qRd.d.ts +0 -67
  164. package/dist/licensing/community-license-key.d.ts +0 -2
  165. package/dist/licensing/community-license-key.js +0 -21
  166. package/dist/opfs-storage-backend-CVcmfJHN.d.ts +0 -11
  167. package/dist/persistence-middleware-DrptY02i.d.ts +0 -31
  168. package/dist/recorder-slice-fcwAXrsh.d.ts +0 -35
  169. package/dist/ref-point-importer-B_wn5ABk.d.ts +0 -62
  170. package/dist/ref-point-loader-Pt1smgHS.d.ts +0 -117
  171. package/dist/ref-points/h3-ref-point.d.ts +0 -2
  172. package/dist/ref-points/index.d.ts +0 -2
  173. package/dist/ref-points/index.js +0 -2
  174. package/dist/ref-points-slice-tC-Wd6XJ.d.ts +0 -48
  175. package/dist/reference-points-CFWy8_wj.d.ts +0 -68
  176. package/dist/routing-slice-BlHTM8eh.d.ts +0 -23
  177. package/dist/state/recorder-slice.d.ts +0 -2
  178. package/dist/state/ref-points-slice.d.ts +0 -2
  179. package/dist/state/ref-points-slice.js +0 -44
  180. package/dist/state/routing-slice.d.ts +0 -2
  181. package/dist/state/routing-slice.js +0 -13
  182. package/dist/state/store.d.ts +0 -9
  183. package/dist/state/store.js +0 -71
  184. package/dist/storage/ref-point-importer.d.ts +0 -2
  185. package/dist/storage/ref-point-importer.js +0 -163
  186. package/dist/storage/ref-point-loader.d.ts +0 -2
  187. package/dist/storage/ref-point-loader.js +0 -248
  188. package/dist/storage/ref-point-recovery.d.ts +0 -28
  189. package/dist/storage/ref-point-recovery.js +0 -159
  190. package/dist/storage-backend-BcEItnFr.d.ts +0 -20
  191. package/dist/store-C7PKOj8S.d.ts +0 -96
  192. package/dist/tracking-state-B9QfuZCg.d.ts +0 -101
  193. package/dist/visualization/reference-points.d.ts +0 -2
  194. package/dist/visualization/reference-points.js +0 -160
  195. /package/dist/{alignment-lerper-D9BeDwZX.d.ts → alignment-lerper-L1RbWHQ4.d.ts} +0 -0
  196. /package/dist/{ar-types-B-ORgk6Z.d.ts → ar-types-Ck8LEq8k.d.ts} +0 -0
  197. /package/dist/{camera-blit-capture-DHuyrrxr.d.ts → camera-blit-capture-C1V9I1Z6.d.ts} +0 -0
  198. /package/dist/{camera-follower-BMqPddxx.d.ts → camera-follower-1k8mnw5J.d.ts} +0 -0
  199. /package/dist/{capture-failure-tracker-2Q6oI2uQ.d.ts → capture-failure-tracker-JKb1ST8E.d.ts} +0 -0
  200. /package/dist/{chromium-camera-access-workaround-CU5zSKNr.d.ts → chromium-camera-access-workaround-NvChXsi8.d.ts} +0 -0
  201. /package/dist/{concurrency-p6gB30fT.d.ts → concurrency-CMw8pSaG.d.ts} +0 -0
  202. /package/dist/{css3d-renderer-manager-rgLMVAvd.d.ts → css3d-renderer-manager-CkjCb2HW.d.ts} +0 -0
  203. /package/dist/{failure-tracker-1sQ_Cgyw.d.ts → failure-tracker-DnHXOIRa.d.ts} +0 -0
  204. /package/dist/{file-system-utils-5cWO8Xyv.d.ts → file-system-utils-CtKiiw27.d.ts} +0 -0
  205. /package/dist/{format-file-size-onGq0k1Q.d.ts → format-file-size-BTS5H62-.d.ts} +0 -0
  206. /package/dist/{gps-compass-cubes-C-6JEnpR.d.ts → gps-compass-cubes-CsLtFv4B.d.ts} +0 -0
  207. /package/dist/{gps-error-handler-VPuNOuf8.d.ts → gps-error-handler-Dg3ziRVY.d.ts} +0 -0
  208. /package/dist/{lerp-utils-87NWjUOD.d.ts → lerp-utils-B8MM8zCR.d.ts} +0 -0
  209. /package/dist/{list-formatter-DKQQVLcl.d.ts → list-formatter-CNqi-E2j.d.ts} +0 -0
  210. /package/dist/{map-overlay-DuiZuCTx.d.ts → map-overlay-DAmreyA3.d.ts} +0 -0
  211. /package/dist/{recording-options-BYUFX8iU.d.ts → recording-options-Dq6IsKAv.d.ts} +0 -0
  212. /package/dist/{scene-node-names-DPsaE2z3.d.ts → scene-node-names-6LBjPmwz.d.ts} +0 -0
  213. /package/dist/{three-dispose-CCBHjE_a.d.ts → three-dispose-C2drkp6f.d.ts} +0 -0
  214. /package/dist/{vis-colors-Qi2vlRGt.d.ts → vis-colors-CHQhjal3.d.ts} +0 -0
  215. /package/dist/{xr-camera-texture-BbukNE79.d.ts → xr-camera-texture-BU5YvKAM.d.ts} +0 -0
  216. /package/dist/{xr-error-handler-DTHfmvrl.d.ts → xr-error-handler-CDY5QxGb.d.ts} +0 -0
@@ -5,8 +5,12 @@ import { createCameraFollower } from "./camera-follower.js";
5
5
  import { createAlignmentLerper } from "./alignment-lerper.js";
6
6
  import { VIS_COLORS } from "./vis-colors.js";
7
7
  import { COMPASS_CUBE_DISTANCE, COMPASS_CUBE_SIZE, createGpsCompassCubes } from "./gps-compass-cubes.js";
8
+ import { buildMapData } from "./map-data.js";
9
+ import { buildCameraFrustum, isObjectInCameraFrustum, isPointInCameraFrustum, isSphereInCameraFrustum } from "./frustum-visibility.js";
10
+ import { n as nueToArLocal, t as createGpsAnchor } from "../gps-anchor-DjC_3MoT.js";
8
11
  import { GpsEventVisualizer, gpsEventVisualizer } from "./gps-event-markers.js";
12
+ import { ACCURACY_CIRCLE_FILL_OPACITY, ACCURACY_CIRCLE_STROKE_OPACITY, ACCURACY_CIRCLE_WEIGHT, addAccuracyCircles } from "./accuracy-circles.js";
13
+ import { ALIGNMENT_SNAPSHOT_COLOR, FUSED_PATH_COLOR, MAP_PATH_POLYLINE_OPACITY, MAP_PATH_POLYLINE_WEIGHT, RAW_GPS_COLOR, USER_POSITION_COLOR, drawMapData } from "./map-overlay-draw.js";
9
14
  import { DEFAULT_LEAFLET_MAP_SIZE_PX, DEFAULT_WORLD_SIZE, DEFAULT_Z_OFFSET, LeafletMapOverlay } from "./leaflet-map-overlay.js";
10
15
  import { DEFAULT_HEIGHT_OFFSET, DEFAULT_MAP_SIZE, DEFAULT_ZOOM, MapOverlay, latLonToTileXY, tileXYToLatLon } from "./map-overlay.js";
11
- import { RefPointVisualizer, refPointVisualizer } from "./reference-points.js";
12
- export { COMPASS_CUBE_DISTANCE, COMPASS_CUBE_SIZE, DEFAULT_HEIGHT_OFFSET, DEFAULT_LEAFLET_MAP_SIZE_PX, DEFAULT_LERP_RATE, DEFAULT_MAP_SIZE, DEFAULT_WORLD_SIZE, DEFAULT_ZOOM, DEFAULT_Z_OFFSET, GpsEventVisualizer, LeafletMapOverlay, MapOverlay, RefPointVisualizer, VIS_COLORS, clampedAlpha, createAlignmentLerper, createCameraFollower, createCss3dRendererManager, createGpsCompassCubes, disposeMeshArray, disposeObject3D, gpsEventVisualizer, latLonToTileXY, refPointVisualizer, tileXYToLatLon };
16
+ export { ACCURACY_CIRCLE_FILL_OPACITY, ACCURACY_CIRCLE_STROKE_OPACITY, ACCURACY_CIRCLE_WEIGHT, ALIGNMENT_SNAPSHOT_COLOR, COMPASS_CUBE_DISTANCE, COMPASS_CUBE_SIZE, DEFAULT_HEIGHT_OFFSET, DEFAULT_LEAFLET_MAP_SIZE_PX, DEFAULT_LERP_RATE, DEFAULT_MAP_SIZE, DEFAULT_WORLD_SIZE, DEFAULT_ZOOM, DEFAULT_Z_OFFSET, FUSED_PATH_COLOR, GpsEventVisualizer, LeafletMapOverlay, MAP_PATH_POLYLINE_OPACITY, MAP_PATH_POLYLINE_WEIGHT, MapOverlay, RAW_GPS_COLOR, USER_POSITION_COLOR, VIS_COLORS, addAccuracyCircles, buildCameraFrustum, buildMapData, clampedAlpha, createAlignmentLerper, createCameraFollower, createCss3dRendererManager, createGpsAnchor, createGpsCompassCubes, disposeMeshArray, disposeObject3D, drawMapData, gpsEventVisualizer, isObjectInCameraFrustum, isPointInCameraFrustum, isSphereInCameraFrustum, latLonToTileXY, nueToArLocal, tileXYToLatLon };
@@ -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-CvfQXTye.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-Cew7XAoO.js";
2
2
  export { DEFAULT_HEIGHT_OFFSET, DEFAULT_LEAFLET_MAP_SIZE_PX, DEFAULT_WORLD_SIZE, DEFAULT_ZOOM, DEFAULT_Z_OFFSET, LeafletMapOverlay, LeafletMapOverlayOptions };
@@ -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 = [];
41
- refPoints = [];
42
- userMarker = null;
43
- rawGpsPolyline = null;
44
- fusedPolyline = null;
45
- snapshotPolyline = null;
39
+ latestMapData = null;
40
+ trajectoryLayers = [];
41
+ namedMarkers = [];
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,42 +86,27 @@ 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
- addRefPoint(lat, lon, name) {
130
- const marker = this.leafletMap ? this.createRefPointMarker(lat, lon, name, false) : null;
131
- this.refPoints.push({
106
+ /** Add a "current" named marker (red). Buffered if map is not yet shown. */
107
+ addCurrentMarker(lat, lon, name) {
108
+ const marker = this.leafletMap ? this.createNamedMarker(lat, lon, name, false) : null;
109
+ this.namedMarkers.push({
132
110
  lat,
133
111
  lng: lon,
134
112
  name,
@@ -136,9 +114,10 @@ var LeafletMapOverlay = class {
136
114
  marker
137
115
  });
138
116
  }
139
- addPriorRefPoint(lat, lon, name) {
140
- const marker = this.leafletMap ? this.createRefPointMarker(lat, lon, name, true) : null;
141
- this.refPoints.push({
117
+ /** Add a "prior" named marker (green, decorated). Buffered if not shown. */
118
+ addPriorMarker(lat, lon, name) {
119
+ const marker = this.leafletMap ? this.createNamedMarker(lat, lon, name, true) : null;
120
+ this.namedMarkers.push({
142
121
  lat,
143
122
  lng: lon,
144
123
  name,
@@ -146,13 +125,15 @@ var LeafletMapOverlay = class {
146
125
  marker
147
126
  });
148
127
  }
149
- addPriorRefPoints(refPoints) {
150
- for (const rp of refPoints) this.addPriorRefPoint(rp.lat, rp.lon, rp.name);
128
+ /** Bulk add prior markers. */
129
+ addPriorMarkers(markers) {
130
+ for (const m of markers) this.addPriorMarker(m.lat, m.lon, m.name);
151
131
  }
152
- clearPriorRefPoints() {
153
- this.refPoints = this.refPoints.filter((rp) => {
154
- if (rp.isPrior) {
155
- rp.marker?.remove();
132
+ /** Remove all prior markers; current markers are unaffected. */
133
+ clearPriorMarkers() {
134
+ this.namedMarkers = this.namedMarkers.filter((m) => {
135
+ if (m.isPrior) {
136
+ m.marker?.remove();
156
137
  return false;
157
138
  }
158
139
  return true;
@@ -195,10 +176,9 @@ var LeafletMapOverlay = class {
195
176
  dispose() {
196
177
  this.hide();
197
178
  this.destroyLeafletMap();
198
- this.rawGpsPoints = [];
199
- this.fusedPoints = [];
200
- this.snapshotPoints = [];
201
- this.refPoints = [];
179
+ this.latestMapData = null;
180
+ this.trajectoryLayers = [];
181
+ this.namedMarkers = [];
202
182
  this.cssObject = null;
203
183
  log.info("Leaflet map overlay disposed");
204
184
  }
@@ -228,17 +208,11 @@ var LeafletMapOverlay = class {
228
208
  this.tileLayer.addTo(this.leafletMap);
229
209
  }
230
210
  destroyLeafletMap() {
231
- this.userMarker?.remove();
232
- this.userMarker = null;
233
- this.rawGpsPolyline?.remove();
234
- this.rawGpsPolyline = null;
235
- this.fusedPolyline?.remove();
236
- this.fusedPolyline = null;
237
- this.snapshotPolyline?.remove();
238
- this.snapshotPolyline = null;
239
- for (const rp of this.refPoints) {
240
- rp.marker?.remove();
241
- rp.marker = null;
211
+ for (const layer of this.trajectoryLayers) layer.remove();
212
+ this.trajectoryLayers = [];
213
+ for (const m of this.namedMarkers) {
214
+ m.marker?.remove();
215
+ m.marker = null;
242
216
  }
243
217
  if (this.leafletMap) {
244
218
  this.leafletMap.remove();
@@ -269,35 +243,19 @@ var LeafletMapOverlay = class {
269
243
  }
270
244
  applyBufferedOverlays() {
271
245
  if (!this.leafletMap) return;
272
- this.updateUserMarker();
273
- if (this.rawGpsPoints.length > 0) this.rawGpsPolyline = L.polyline(this.rawGpsPoints, {
274
- color: VIS_COLORS.RAW_GPS.css,
275
- weight: 3,
276
- opacity: .8
277
- }).addTo(this.leafletMap);
278
- if (this.fusedPoints.length > 0) this.fusedPolyline = L.polyline(this.fusedPoints, {
279
- color: VIS_COLORS.FUSED_VIO.css,
280
- weight: 3,
281
- opacity: .8
282
- }).addTo(this.leafletMap);
283
- if (this.snapshotPoints.length > 0) this.snapshotPolyline = L.polyline(this.snapshotPoints, {
284
- color: VIS_COLORS.ALIGNMENT_SNAPSHOT.css,
285
- weight: 3,
286
- opacity: .8
287
- }).addTo(this.leafletMap);
288
- for (const rp of this.refPoints) if (!rp.marker) rp.marker = this.createRefPointMarker(rp.lat, rp.lng, rp.name, rp.isPrior);
246
+ this.drawTrajectory();
247
+ for (const m of this.namedMarkers) if (!m.marker) m.marker = this.createNamedMarker(m.lat, m.lng, m.name, m.isPrior);
289
248
  }
290
- updateUserMarker() {
291
- if (!this.gpsPosition || !this.leafletMap) return;
292
- if (this.userMarker) this.userMarker.setLatLng([this.gpsPosition.lat, this.gpsPosition.lon]);
293
- else this.userMarker = L.marker([this.gpsPosition.lat, this.gpsPosition.lon], { icon: L.divIcon({
294
- className: "",
295
- 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>`,
296
- iconSize: [14, 14],
297
- iconAnchor: [7, 7]
298
- }) }).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;
299
257
  }
300
- createRefPointMarker(lat, lon, name, isPrior) {
258
+ createNamedMarker(lat, lon, name, isPrior) {
301
259
  const color = isPrior ? VIS_COLORS.PRIOR_REF_POINT.css : VIS_COLORS.CURRENT_REF_POINT.css;
302
260
  const opacity = isPrior ? "opacity:0.8;" : "";
303
261
  const label = isPrior ? `📌 ${name} (prior)` : name;
@@ -1,2 +1,2 @@
1
- import { n as clampedAlpha, t as DEFAULT_LERP_RATE } from "../lerp-utils-87NWjUOD.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-DuiZuCTx.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-CCBHjE_a.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-Qi2vlRGt.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 };
@@ -28,6 +28,55 @@ interface ZipExportResult {
28
28
  /** Number of files packaged in the ZIP */
29
29
  readonly fileCount: number;
30
30
  }
31
+ /**
32
+ * Helper passed to a {@link ZipExportContributor.contribute} callback for
33
+ * appending blobs to the ZIP under a stable, contributor-owned subdirectory.
34
+ *
35
+ * The framework prepends the contributor's `subdir` to the supplied
36
+ * `relativePath` automatically, so contributors only think in terms of paths
37
+ * relative to their own subdir (e.g. `'42.json'`, not `'refPoints/42.json'`).
38
+ */
39
+ type ZipContributorAddFile = (relativePath: string, blob: Blob) => Promise<void>;
40
+ /**
41
+ * Extension contributor that lets a consumer (typically the recorder)
42
+ * append app-specific files to a session ZIP without forking the
43
+ * framework's ZIP writer.
44
+ *
45
+ * Each contributor declares a top-level subdirectory it owns inside the
46
+ * ZIP (e.g. the recorder uses `refPoints/`). The framework calls
47
+ * {@link contribute} after writing all framework-owned sections.
48
+ *
49
+ * Contributors must:
50
+ * - Only write files under their declared `subdir` (the framework enforces
51
+ * this by routing every `addFile` call through the prefix).
52
+ * - Tolerate an empty source (e.g. a session with no ref points) by
53
+ * returning `0` instead of throwing.
54
+ *
55
+ * @see 2026-05-03-appframework-vs-recorderapp-boundary-analysis.md — Iter 2.
56
+ */
57
+ interface ZipExportContributor {
58
+ /** Top-level subdirectory inside the ZIP (no leading or trailing `/`). */
59
+ readonly subdir: string;
60
+ /**
61
+ * Append files for this contributor. Implementations call `addFile`
62
+ * once per file with a path relative to {@link subdir}.
63
+ *
64
+ * @returns Number of files added so the framework's `fileCount` total
65
+ * stays accurate for download summaries.
66
+ */
67
+ contribute(addFile: ZipContributorAddFile): Promise<number>;
68
+ }
69
+ /**
70
+ * Options for {@link exportSessionAsZip}.
71
+ */
72
+ interface ExportSessionAsZipOptions {
73
+ /**
74
+ * Optional list of {@link ZipExportContributor}s. Each is invoked after
75
+ * framework-owned sections have been written. Order is preserved in the
76
+ * resulting ZIP central directory but has no semantic effect.
77
+ */
78
+ readonly contributors?: readonly ZipExportContributor[];
79
+ }
31
80
  /**
32
81
  * Export a session from OPFS as a ZIP blob.
33
82
  *
@@ -35,16 +84,18 @@ interface ZipExportResult {
35
84
  * - session.json (at root)
36
85
  * - actions/000001.json, actions/000002.json, ...
37
86
  * - frames/frame-000001.jpg, frames/frame-000002.jpg, ...
38
- * - refPoints/{h3}.json (only observations from this session)
87
+ * - refPoints/{h3}.json (only observations from this session, scenario layout only)
39
88
  *
40
89
  * Uses "store" mode (compression level 0) for fast packaging.
41
90
  *
42
- * @param scenarioName - Name of the scenario
43
- * @param sessionName - Name of the session folder
91
+ * Supports both flat and scenario-based layouts:
92
+ * - `exportSessionAsZip(sessionName)` flat layout (sessions/)
93
+ * - `exportSessionAsZip(scenarioName, sessionName)` — scenario layout (scenarios/{name}/)
94
+ *
44
95
  * @returns ZIP export result with blob and file count
45
- * @throws Error if scenario or session not found
96
+ * @throws Error if session not found
46
97
  */
47
- declare function exportSessionAsZip(scenarioName: string, sessionName: string): Promise<ZipExportResult>;
98
+ declare function exportSessionAsZip(scenarioNameOrSessionName: string, sessionName?: string, options?: ExportSessionAsZipOptions): Promise<ZipExportResult>;
48
99
  /**
49
100
  * Sync current OPFS session data to an external file handle.
50
101
  *
@@ -63,7 +114,7 @@ declare function exportSessionAsZip(scenarioName: string, sessionName: string):
63
114
  * @returns ZIP export result with blob and file count
64
115
  * @throws Error if scenario or session not found
65
116
  */
66
- declare function syncToExternalZip(fileHandle: FileSystemFileHandle, scenarioName: string, sessionName: string): Promise<ZipExportResult>;
117
+ declare function syncToExternalZip(fileHandle: FileSystemFileHandle, scenarioName: string, sessionName: string, options?: ExportSessionAsZipOptions): Promise<ZipExportResult>;
67
118
  /**
68
119
  * Trigger a file download in the browser.
69
120
  *
@@ -84,4 +135,4 @@ declare function downloadZip(blob: Blob, filename: string): Promise<void>;
84
135
  */
85
136
  declare function exportAndDownloadSession(scenarioName: string, sessionName: string): Promise<void>;
86
137
  //#endregion
87
- export { syncToExternalZip as a, exportSessionAsZip as i, downloadZip as n, exportAndDownloadSession as r, ZipExportResult as t };
138
+ export { downloadZip as a, syncToExternalZip as c, ZipExportResult as i, ZipContributorAddFile as n, exportAndDownloadSession as o, ZipExportContributor as r, exportSessionAsZip as s, ExportSessionAsZipOptions as t };