gps-plus-slam-app-framework 1.4.0 → 1.8.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 (243) hide show
  1. package/dist/absolute-orientation-BAxc15J6.d.ts +54 -0
  2. package/dist/{accuracy-circles-Pi2YeCrM.d.ts → accuracy-circles-DkWBkF5g.d.ts} +16 -6
  3. package/dist/{app-selectors-CrOucL00.d.ts → app-selectors-JqydaUMN.d.ts} +1 -1
  4. package/dist/ar/bresenham3d.d.ts +1 -1
  5. package/dist/ar/camera-blit-capture.d.ts +1 -1
  6. package/dist/ar/capability-checker.d.ts +1 -1
  7. package/dist/ar/capture-failure-tracker.d.ts +1 -1
  8. package/dist/ar/chromium-camera-access-workaround.d.ts +1 -1
  9. package/dist/ar/depth-grid-lookup.d.ts +1 -1
  10. package/dist/ar/depth-occluder.d.ts +127 -0
  11. package/dist/ar/depth-occluder.js +299 -0
  12. package/dist/ar/depth-sampler.d.ts +2 -2
  13. package/dist/ar/depth-sampler.js +24 -4
  14. package/dist/ar/depth-unprojection.d.ts +1 -1
  15. package/dist/ar/depth-unprojection.js +52 -21
  16. package/dist/ar/enable-gps-ar.d.ts +1 -1
  17. package/dist/ar/enable-gps-ar.js +1 -1
  18. package/dist/ar/frame-loop.d.ts +1 -1
  19. package/dist/ar/frame-loop.js +12 -2
  20. package/dist/ar/image-capture.d.ts +2 -2
  21. package/dist/ar/image-capture.js +1 -154
  22. package/dist/ar/image-quality.d.ts +2 -0
  23. package/dist/ar/image-quality.js +169 -0
  24. package/dist/ar/index.d.ts +32 -30
  25. package/dist/ar/index.js +7 -5
  26. package/dist/ar/occlusion-mesh-worker.d.ts +58 -0
  27. package/dist/ar/occlusion-mesh-worker.js +129 -0
  28. package/dist/ar/occupancy-grid.d.ts +2 -2
  29. package/dist/ar/occupancy-grid.js +287 -31
  30. package/dist/ar/occupancy-mesher.d.ts +2 -0
  31. package/dist/ar/occupancy-mesher.js +638 -0
  32. package/dist/ar/planar-pnp.d.ts +1 -1
  33. package/dist/ar/qr-debug-view.d.ts +1 -1
  34. package/dist/ar/qr-derived-pose.d.ts +1 -1
  35. package/dist/ar/qr-detection-controller.d.ts +1 -1
  36. package/dist/ar/qr-frontend.d.ts +1 -1
  37. package/dist/ar/qr-pose.d.ts +1 -1
  38. package/dist/ar/qr-size-depth-context.d.ts +2 -2
  39. package/dist/ar/qr-size-measurer.d.ts +1 -1
  40. package/dist/ar/replay-scene.d.ts +1 -1
  41. package/dist/ar/replay-scene.js +1 -1
  42. package/dist/ar/scene-node-names.d.ts +1 -1
  43. package/dist/ar/webxr-nue-basis.d.ts +1 -1
  44. package/dist/ar/webxr-session.d.ts +4 -4
  45. package/dist/ar/webxr-session.js +2 -2
  46. package/dist/ar/xr-camera-texture.d.ts +1 -1
  47. package/dist/ar/xr-error-handler.d.ts +1 -1
  48. package/dist/ar/xr-frame-loop.d.ts +1 -1
  49. package/dist/ar/xr-frame-loop.js +12 -2
  50. package/dist/{ar-Dc72Ksiu.js → ar-BqCudtqE.js} +4 -3
  51. package/dist/{ar-world-group-alignment-DDLkgNf_.d.ts → ar-world-group-alignment-BlvGcIAk.d.ts} +1 -1
  52. package/dist/capture-motion-gate-BGoAMkmf.d.ts +24 -0
  53. package/dist/capture-motion-gate-_NdTSwKi.js +106 -0
  54. package/dist/cell-key-DIB4rOTV.js +51 -0
  55. package/dist/core/index.d.ts +2 -2
  56. package/dist/core/index.js +2 -2
  57. package/dist/{create-slam-app-store-Ce2FMKCp.d.ts → create-slam-app-store-D3nzh9Wb.d.ts} +50 -40
  58. package/dist/create-slam-app-store-DXiAnJwR.js +156 -0
  59. package/dist/{depth-grid-lookup-vMDrGTk_.d.ts → depth-grid-lookup-D5atpNZ3.d.ts} +1 -1
  60. package/dist/{depth-sampler-DwfPYzS7.d.ts → depth-sampler-CwObAwEA.d.ts} +33 -1
  61. package/dist/{depth-unprojection-CK3b9htH.d.ts → depth-unprojection-DRdBU90S.d.ts} +1 -1
  62. package/dist/{enable-gps-ar-CjZ1nEdu.d.ts → enable-gps-ar-DvGzBOrp.d.ts} +4 -4
  63. package/dist/{frame-conversions-D_Af8Dt3.d.ts → frame-conversions-C4bnNOEY.d.ts} +1 -1
  64. package/dist/{fused-path-C0FHe67t.d.ts → fused-path-C5pp0PJU.d.ts} +1 -1
  65. package/dist/geo/h3-proximity.d.ts +1 -1
  66. package/dist/geo/index.d.ts +1 -1
  67. package/dist/geodesic-angle-BTldfFgs.js +39 -0
  68. package/dist/{gps-anchor-C6I9NDHA.d.ts → gps-anchor-BjECcYnD.d.ts} +1 -1
  69. package/dist/{gps-ar-pose-sampler-DaHg2aPZ.d.ts → gps-ar-pose-sampler-DEGNk2CI.d.ts} +1 -1
  70. package/dist/{gps-event-coordinator-C7hwHyLA.d.ts → gps-event-coordinator-CHtIkhb7.d.ts} +21 -11
  71. package/dist/{image-capture-C2Feywet.d.ts → image-capture-Bp6Pd4Md.d.ts} +103 -3
  72. package/dist/image-capture-DVcuqMtX.js +374 -0
  73. package/dist/image-quality-BMx2ko9-.d.ts +158 -0
  74. package/dist/index-D4vrgV4b.d.ts +2 -0
  75. package/dist/index-D74JTX4I.d.ts +22 -0
  76. package/dist/{index-m_LneUSi.d.ts → index-DlsOo2IB.d.ts} +1 -1
  77. package/dist/{index-BvLo2poy.d.ts → index-cCQWuYqy.d.ts} +3 -3
  78. package/dist/index.d.ts +82 -77
  79. package/dist/index.js +15 -10
  80. package/dist/{leaflet-map-overlay-bnb2U1NQ.d.ts → leaflet-map-overlay-BOZFW5kT.d.ts} +64 -10
  81. package/dist/leaflet-map-overlay-CBWPvaX9.js +452 -0
  82. package/dist/lerp-utils-Qs8OhumS.d.ts +42 -0
  83. package/dist/map-data-D7rpMC6f.js +120 -0
  84. package/dist/{map-data-DdjPiSav.d.ts → map-data-PNfGKGWx.d.ts} +22 -2
  85. package/dist/{map-overlay-draw-CPVdAsFq.d.ts → map-overlay-draw-DiroaJed.d.ts} +1 -1
  86. package/dist/{null-storage-backend-CuSdYFsM.d.ts → null-storage-backend-B1-jlpin.d.ts} +2 -2
  87. package/dist/occlusion-mesh-b28lRJ6S.d.ts +194 -0
  88. package/dist/occupancy-grid-BV7RhB7I.d.ts +194 -0
  89. package/dist/occupancy-mesher-C2ecWhNp.d.ts +100 -0
  90. package/dist/{opfs-storage-DMtlt57S.d.ts → opfs-storage-CTkxvxN4.d.ts} +5 -0
  91. package/dist/{opfs-storage-backend-CeQAb0SD.d.ts → opfs-storage-backend-D6Z03fML.d.ts} +2 -2
  92. package/dist/{persistence-middleware-5eearhSV.d.ts → persistence-middleware-CG-t08X4.d.ts} +1 -1
  93. package/dist/{planar-pnp-cjthe7Be.d.ts → planar-pnp-D7bc_rLX.d.ts} +1 -1
  94. package/dist/{qr-debug-view-B8gTzjMm.d.ts → qr-debug-view-BJooqbiP.d.ts} +1 -1
  95. package/dist/{qr-derived-pose-DinKE600.d.ts → qr-derived-pose-BwNWn8oV.d.ts} +2 -2
  96. package/dist/{qr-detected-slice-Cpv-dg82.d.ts → qr-detected-slice-TzVb8bij.d.ts} +4 -4
  97. package/dist/{qr-detection-controller-Cd2Ih4cC.d.ts → qr-detection-controller-Bo4XfQTP.d.ts} +3 -3
  98. package/dist/{qr-frontend-DufZp2xS.d.ts → qr-frontend-BPURlh3S.d.ts} +1 -1
  99. package/dist/{qr-pose-aggregation-CFlmLm6w.d.ts → qr-pose-aggregation-CypnmjA-.d.ts} +1 -1
  100. package/dist/{qr-pose-aggregation-DXR9STHs.js → qr-pose-aggregation-DBiaLW0O.js} +1 -10
  101. package/dist/{qr-size-depth-context-onu36E9s.d.ts → qr-size-depth-context-apAOmbrZ.d.ts} +2 -2
  102. package/dist/{qr-size-measurer-D7739ZpB.d.ts → qr-size-measurer-DxiMqRUw.d.ts} +3 -3
  103. package/dist/recording-options-vASCFzc5.d.ts +667 -0
  104. package/dist/{recording-replayer-CUEK82tM.d.ts → recording-replayer-D0V9WkmY.d.ts} +2 -2
  105. package/dist/{recording-slice-B-uCgGoh.d.ts → recording-slice-DTUtSVgd.d.ts} +2 -2
  106. package/dist/{replay-engine-BSVd7Zzb.d.ts → replay-engine-xdrUgWJi.d.ts} +1 -1
  107. package/dist/{replay-scene-CPt56pps.d.ts → replay-scene-zJ8SFDjE.d.ts} +3 -3
  108. package/dist/sensors/absolute-orientation.d.ts +2 -0
  109. package/dist/sensors/absolute-orientation.js +162 -0
  110. package/dist/sensors/gps-error-handler.d.ts +1 -1
  111. package/dist/sensors/gps.d.ts +1 -1
  112. package/dist/sensors/index.d.ts +5 -4
  113. package/dist/sensors/index.js +2 -1
  114. package/dist/sensors/permission-checker.d.ts +1 -1
  115. package/dist/state/app-selectors.d.ts +1 -1
  116. package/dist/state/combined-root-state.d.ts +1 -1
  117. package/dist/state/create-slam-app-store.d.ts +1 -1
  118. package/dist/state/create-slam-app-store.js +1 -74
  119. package/dist/state/gps-ar-pose-sampler.d.ts +3 -3
  120. package/dist/state/gps-event-coordinator.d.ts +2 -2
  121. package/dist/state/gps-event-coordinator.js +27 -17
  122. package/dist/state/index.d.ts +20 -20
  123. package/dist/state/index.js +4 -4
  124. package/dist/state/persistence-middleware.d.ts +1 -1
  125. package/dist/state/persistence-middleware.js +30 -19
  126. package/dist/state/qr-detected-slice.d.ts +3 -3
  127. package/dist/state/qr-detected-slice.js +1 -1
  128. package/dist/state/recording-options.d.ts +2 -2
  129. package/dist/state/recording-options.js +286 -25
  130. package/dist/state/recording-replayer.d.ts +2 -2
  131. package/dist/state/recording-replayer.js +1 -1
  132. package/dist/state/recording-slice.d.ts +1 -1
  133. package/dist/state/replay-engine.d.ts +1 -1
  134. package/dist/state/store-subscribers.d.ts +2 -2
  135. package/dist/state/store-subscribers.js +2 -1
  136. package/dist/state/subscribe-to-selector.d.ts +1 -1
  137. package/dist/state/tracking-quality.d.ts +2 -2
  138. package/dist/state/tracking-quality.js +49 -128
  139. package/dist/state/tracking-slice.d.ts +1 -1
  140. package/dist/{state-IEw0ZsBu.js → state-BeKvn4B-.js} +1 -1
  141. package/dist/storage/file-system-utils.d.ts +1 -1
  142. package/dist/storage/index.d.ts +8 -8
  143. package/dist/storage/null-storage-backend.d.ts +1 -1
  144. package/dist/storage/opfs-storage-backend.d.ts +1 -1
  145. package/dist/storage/opfs-storage.d.ts +1 -1
  146. package/dist/storage/opfs-storage.js +25 -1
  147. package/dist/storage/storage-backend.d.ts +1 -1
  148. package/dist/storage/zip-coverage-embed.d.ts +1 -1
  149. package/dist/storage/zip-export.d.ts +1 -1
  150. package/dist/storage/zip-reader.d.ts +1 -1
  151. package/dist/{storage-backend-CTJHNdMp.d.ts → storage-backend-sEtmM4yW.d.ts} +1 -1
  152. package/dist/{store-subscribers-BZP81hjh.d.ts → store-subscribers-DScA7tdT.d.ts} +2 -2
  153. package/dist/{subscribe-to-selector-Bp3sLx8L.d.ts → subscribe-to-selector-B9ylM5Oh.d.ts} +1 -1
  154. package/dist/test-utils/browser-mocks.d.ts +1 -1
  155. package/dist/test-utils/zip-round-trip-helpers.d.ts +1 -1
  156. package/dist/{tracking-slice-DJZ9qeGg.d.ts → tracking-slice-DMkHlbny.d.ts} +1 -1
  157. package/dist/types/ar-types.d.ts +1 -1
  158. package/dist/types/geo-types.d.ts +1 -1
  159. package/dist/types/index.d.ts +2 -2
  160. package/dist/utils/concurrency.d.ts +1 -1
  161. package/dist/utils/failure-tracker.d.ts +1 -1
  162. package/dist/utils/format-file-size.d.ts +1 -1
  163. package/dist/utils/fused-path.d.ts +1 -1
  164. package/dist/utils/index.d.ts +8 -7
  165. package/dist/utils/index.js +2 -1
  166. package/dist/utils/list-formatter.d.ts +1 -1
  167. package/dist/utils/logger.d.ts +1 -1
  168. package/dist/visualization/accuracy-circles.d.ts +1 -1
  169. package/dist/visualization/accuracy-circles.js +17 -8
  170. package/dist/visualization/alignment-lerper.d.ts +1 -1
  171. package/dist/visualization/ar-world-group-alignment.d.ts +1 -1
  172. package/dist/visualization/ar-world-group-alignment.js +1 -1
  173. package/dist/visualization/camera-follower.d.ts +1 -1
  174. package/dist/visualization/css3d-renderer-manager.d.ts +1 -1
  175. package/dist/visualization/frame-conversions.d.ts +1 -1
  176. package/dist/visualization/frustum-visibility.d.ts +1 -1
  177. package/dist/visualization/gps-anchor.d.ts +1 -1
  178. package/dist/visualization/gps-compass-cubes.d.ts +1 -1
  179. package/dist/visualization/gps-event-markers.d.ts +1 -1
  180. package/dist/visualization/gps-event-markers.js +1 -1
  181. package/dist/visualization/hit-test-reticle.d.ts +1 -1
  182. package/dist/visualization/index.d.ts +20 -19
  183. package/dist/visualization/index.js +4 -3
  184. package/dist/visualization/leaflet-map-overlay.d.ts +1 -1
  185. package/dist/visualization/leaflet-map-overlay.js +1 -282
  186. package/dist/visualization/lerp-utils.d.ts +2 -2
  187. package/dist/visualization/lerp-utils.js +27 -3
  188. package/dist/visualization/map-data.d.ts +1 -1
  189. package/dist/visualization/map-data.js +1 -32
  190. package/dist/visualization/map-overlay-draw.d.ts +1 -1
  191. package/dist/visualization/map-overlay-draw.js +24 -2
  192. package/dist/visualization/map-overlay.d.ts +1 -1
  193. package/dist/visualization/occluder-mesh-driver.d.ts +130 -0
  194. package/dist/visualization/occluder-mesh-driver.js +219 -0
  195. package/dist/visualization/occlusion-mesh.d.ts +2 -0
  196. package/dist/visualization/occlusion-mesh.js +437 -0
  197. package/dist/visualization/three-dispose.d.ts +1 -1
  198. package/dist/visualization/vis-colors.d.ts +1 -1
  199. package/dist/{webxr-session-CJF9Nijp.js → webxr-session-BCP2XK7k.js} +110 -14
  200. package/dist/{webxr-session-COsOjJwn.d.ts → webxr-session-cRG2SYAQ.d.ts} +83 -10
  201. package/package.json +4 -4
  202. package/dist/index-eaI1Z1KR.d.ts +0 -2
  203. package/dist/lerp-utils-kLxMJ2Xj.d.ts +0 -20
  204. package/dist/occupancy-grid-Bvi2Gw1U.d.ts +0 -82
  205. package/dist/recording-options-D93kksJU.d.ts +0 -369
  206. /package/dist/{alignment-lerper-BUTsQ2yu.d.ts → alignment-lerper-gD70k7Fq.d.ts} +0 -0
  207. /package/dist/{ar-types-BckI1E-O.d.ts → ar-types-Cc5yvBwn.d.ts} +0 -0
  208. /package/dist/{bresenham3d-ByjcmEgM.d.ts → bresenham3d-DGc4nIb-.d.ts} +0 -0
  209. /package/dist/{camera-blit-capture-CqWe1G7s.d.ts → camera-blit-capture-BimSdyih.d.ts} +0 -0
  210. /package/dist/{camera-follower-BTb2Yp12.d.ts → camera-follower-DfBm2J5i.d.ts} +0 -0
  211. /package/dist/{capability-checker-CXqoJYtb.d.ts → capability-checker-BTTpygvZ.d.ts} +0 -0
  212. /package/dist/{capture-failure-tracker-BL5SoG2a.d.ts → capture-failure-tracker-_BVfhpxv.d.ts} +0 -0
  213. /package/dist/{chromium-camera-access-workaround-BNK189P0.d.ts → chromium-camera-access-workaround-C6yJLXz9.d.ts} +0 -0
  214. /package/dist/{concurrency-DqAlKX4j.d.ts → concurrency-DPeGBH0X.d.ts} +0 -0
  215. /package/dist/{css3d-renderer-manager-m-ab19vp.d.ts → css3d-renderer-manager-CPpVtvgs.d.ts} +0 -0
  216. /package/dist/{failure-tracker-Cnc_xWUw.d.ts → failure-tracker-CeKf5HIc.d.ts} +0 -0
  217. /package/dist/{file-system-utils-Bs7lpeVP.d.ts → file-system-utils-DueXHxo9.d.ts} +0 -0
  218. /package/dist/{format-file-size-BFUWvir1.d.ts → format-file-size-DxN-EBLc.d.ts} +0 -0
  219. /package/dist/{frame-loop-BEO9_q3k.d.ts → frame-loop-7GBMBu68.d.ts} +0 -0
  220. /package/dist/{frustum-visibility-D_RGmH98.d.ts → frustum-visibility-CokkgS_i.d.ts} +0 -0
  221. /package/dist/{geo-types-DqiBzPO9.d.ts → geo-types-DrGVu8nS.d.ts} +0 -0
  222. /package/dist/{gps-C5inWeNV.d.ts → gps-CDKDQokE.d.ts} +0 -0
  223. /package/dist/{gps-compass-cubes-BExxrWJ-.d.ts → gps-compass-cubes-1mooS3BS.d.ts} +0 -0
  224. /package/dist/{gps-error-handler-C2bS69oJ.d.ts → gps-error-handler-C34GQuTu.d.ts} +0 -0
  225. /package/dist/{gps-event-markers-Dd0G2bD0.d.ts → gps-event-markers-Di2nBzx-.d.ts} +0 -0
  226. /package/dist/{h3-proximity-B57C6rYL.d.ts → h3-proximity-D0GTHQmr.d.ts} +0 -0
  227. /package/dist/{hit-test-reticle-Dqak9hiR.d.ts → hit-test-reticle-CaQbrhbk.d.ts} +0 -0
  228. /package/dist/{list-formatter-ct8txwvR.d.ts → list-formatter-DLFDnS70.d.ts} +0 -0
  229. /package/dist/{logger-CzQrCe6C.d.ts → logger-CqTd5Kpk.d.ts} +0 -0
  230. /package/dist/{map-overlay-Dci4yvm3.d.ts → map-overlay-BCQgvIgU.d.ts} +0 -0
  231. /package/dist/{permission-checker-CtPtPQRq.d.ts → permission-checker-B-VtjnBA.d.ts} +0 -0
  232. /package/dist/{qr-pose-Bt2reSw7.d.ts → qr-pose-y3vaEd6x.d.ts} +0 -0
  233. /package/dist/{scene-node-names-CdNeQjOE.d.ts → scene-node-names-CGb-ylBd.d.ts} +0 -0
  234. /package/dist/{session-disposers-D8wnO-uW.js → session-disposers-BPrMplIC.js} +0 -0
  235. /package/dist/{three-dispose-BCZkSJp2.d.ts → three-dispose-BMOAmPhb.d.ts} +0 -0
  236. /package/dist/{vis-colors-BZsSLI4i.d.ts → vis-colors-C7HI0u9_.d.ts} +0 -0
  237. /package/dist/{webxr-nue-basis-CW1wsbm6.d.ts → webxr-nue-basis-CaCnYxuq.d.ts} +0 -0
  238. /package/dist/{xr-camera-texture-BmrP7iNZ.d.ts → xr-camera-texture-q0eIDSRg.d.ts} +0 -0
  239. /package/dist/{xr-error-handler-BEjRgZjt.d.ts → xr-error-handler-uVGDu9IX.d.ts} +0 -0
  240. /package/dist/{xr-frame-loop-K8ebdjLw.d.ts → xr-frame-loop-DX3JPpAU.d.ts} +0 -0
  241. /package/dist/{zip-coverage-embed-tFohI2J4.d.ts → zip-coverage-embed-ncVbaZAz.d.ts} +0 -0
  242. /package/dist/{zip-export-DDWXInTR.d.ts → zip-export-CtiUnAlJ.d.ts} +0 -0
  243. /package/dist/{zip-reader-Q2ue6zlC.d.ts → zip-reader-CvruaGvD.d.ts} +0 -0
@@ -1,11 +1,11 @@
1
- import { i as DepthSample, t as ARPose } from "./ar-types-BckI1E-O.js";
2
- import { i as DepthSamplerConfig } from "./depth-sampler-DwfPYzS7.js";
3
- import { t as ArCrashIsolationOptions } from "./recording-options-D93kksJU.js";
4
- import { a as ImageCaptureConfig, n as CapturedImage } from "./image-capture-C2Feywet.js";
5
- import { a as TrackingSliceState, r as ResetTransformData } from "./tracking-slice-DJZ9qeGg.js";
6
- import { o as RgbaImage } from "./qr-frontend-DufZp2xS.js";
7
- import { t as Css3dRendererManager } from "./css3d-renderer-manager-m-ab19vp.js";
8
- import { r as XRCameraLike } from "./xr-camera-texture-BmrP7iNZ.js";
1
+ import { i as DepthSample, t as ARPose } from "./ar-types-Cc5yvBwn.js";
2
+ import { i as DepthSamplerConfig, t as DepthInfo } from "./depth-sampler-CwObAwEA.js";
3
+ import { t as ArCrashIsolationOptions } from "./recording-options-vASCFzc5.js";
4
+ import { i as FrameQualityVerdict, n as CapturedImage, o as ImageCaptureConfig, t as CapturedFrame } from "./image-capture-Bp6Pd4Md.js";
5
+ import { a as TrackingSliceState, r as ResetTransformData } from "./tracking-slice-DMkHlbny.js";
6
+ import { o as RgbaImage } from "./qr-frontend-BPURlh3S.js";
7
+ import { t as Css3dRendererManager } from "./css3d-renderer-manager-CPpVtvgs.js";
8
+ import { r as XRCameraLike } from "./xr-camera-texture-q0eIDSRg.js";
9
9
  import * as THREE from "three";
10
10
  import { OdometryTrackingRestartedPayload } from "gps-plus-slam-js";
11
11
 
@@ -69,6 +69,16 @@ declare function shouldLogCameraAccessDiagnostic(pose: XRViewerPose | null, alre
69
69
  * @internal
70
70
  */
71
71
  declare function resetWebXRState(): void;
72
+ /**
73
+ * Info passed to the session-end callback (F3, 2026-07-04 user feedback).
74
+ * `requestedByApp` discriminates the app's own `endARSession()` from a
75
+ * system-initiated end (e.g. the Android back gesture, which ends an
76
+ * immersive XRSession directly — no popstate, no beforeunload, not
77
+ * cancelable).
78
+ */
79
+ interface SessionEndInfo {
80
+ requestedByApp: boolean;
81
+ }
72
82
  /**
73
83
  * Default longer-edge resolution (px) for the camera-frame blit the QR / CV
74
84
  * detector sees. The on-device capture-resolution sweep (2026-06-17, via the
@@ -129,6 +139,18 @@ interface SessionFeatureOptions {
129
139
  * existing recorder/anchor sessions are unaffected.
130
140
  */
131
141
  requestHitTest?: boolean;
142
+ /**
143
+ * Request `depth-sensing` (cpu-optimized) for the **live depth occluder**
144
+ * even when crash-isolation's `enableDepthSensingFeature` is off. Consumer
145
+ * apps (AnchorStarter / MinimalExample) want occlusion without the recorder's
146
+ * depth-capture wiring, so the occluder owns its own session-feature switch.
147
+ * Both flags resolve the **same** cpu-optimized usage — setting both is valid
148
+ * (no conflict, no throw): the grid sampler and the occluder are two consumers
149
+ * of one depth read. Default `false`.
150
+ *
151
+ * @see GpsPlusSlamJs_Docs/docs/2026-06-14-webxr-depth-occlusion-plan.md §6/§8
152
+ */
153
+ requestDepthOcclusion?: boolean;
132
154
  }
133
155
  /**
134
156
  * Build XR session init options.
@@ -138,7 +160,7 @@ interface SessionFeatureOptions {
138
160
  * @param isolationOptions - Crash-isolation diagnostic flags (DOM overlay,
139
161
  * depth-sensing, camera-access)
140
162
  * @param sessionFeatures - Opt-in standard WebXR features that are independent
141
- * of crash isolation (currently `requestHitTest`)
163
+ * of crash isolation (`requestHitTest`, `requestDepthOcclusion`)
142
164
  * @returns XRSessionInit options
143
165
  * @throws Error if rootElement is null
144
166
  */
@@ -147,6 +169,23 @@ declare function buildSessionOptions(rootElement: Element | null, isolationOptio
147
169
  * Check if WebXR immersive-ar is supported
148
170
  */
149
171
  declare function isWebXRSupported(): Promise<boolean>;
172
+ /**
173
+ * AR camera frustum constants — the single source of truth for live AR and
174
+ * replay (both build their camera via {@link createSceneHierarchy}).
175
+ *
176
+ * F2 (2026-07-04 user feedback): far raised 100 → 200 m so objects in the
177
+ * reported 100–200 m range are no longer frustum-culled. The far-plane
178
+ * distance itself is essentially free at this app's object counts; the real
179
+ * constraint is depth precision — far/near = 2×10⁴ is comfortable for a
180
+ * 24-bit depth buffer. Revisit the ratio if AR_CAMERA_NEAR ever shrinks.
181
+ *
182
+ * Note: these apply to WebGL content only. The CSS3D minimap is composited by
183
+ * the browser from the camera fov alone — near/far do not clip it (F1 in the
184
+ * same feedback doc).
185
+ */
186
+ declare const AR_CAMERA_FOV = 70;
187
+ declare const AR_CAMERA_NEAR = 0.01;
188
+ declare const AR_CAMERA_FAR = 200;
150
189
  /**
151
190
  * Create the scene hierarchy with proper AR/GPS frame separation.
152
191
  * This is a pure function for testability.
@@ -196,6 +235,18 @@ declare function createSceneHierarchy(): {
196
235
  * `requestHitTest`) forwarded to the session negotiation.
197
236
  */
198
237
  declare function initAR(container: HTMLElement, isolationOptions?: Partial<ArCrashIsolationOptions>, sessionFeatures?: SessionFeatureOptions): Promise<void>;
238
+ /**
239
+ * Extract depth information from an XR frame. Returns `null` if depth sensing is
240
+ * not available (no pose/view, no `getDepthInformation`, or the call throws).
241
+ *
242
+ * Exported so a consumer can feed the **live depth occluder** from a
243
+ * `registerXrFrameUpdate` callback — the callback has the live `frame` +
244
+ * `referenceSpace`, computes `pose = frame.getViewerPose(referenceSpace)`, and
245
+ * passes both here to obtain the per-frame {@link DepthInfo} (with the widened
246
+ * `data` / `rawValueToMeters` / `normDepthBufferFromNormView` / `projectionMatrix`
247
+ * the occluder needs). The same wrapped depth the sparse grid sampler consumes.
248
+ */
249
+ declare function getDepthInfoFromFrame(frame: XRFrame, pose: XRViewerPose | null): DepthInfo | null;
199
250
  /**
200
251
  * Get the current Three.js scene (for adding objects like map)
201
252
  */
@@ -284,6 +335,18 @@ declare function nuePositionToWebXR(nue: readonly number[]): readonly [number, n
284
335
  * NUE [x, y, z, w] → WebXR [z, y, -x, w]
285
336
  */
286
337
  declare function nueQuaternionToWebXR$1(nue: readonly number[]): readonly [number, number, number, number];
338
+ /**
339
+ * Register a host callback fired exactly once whenever the XRSession ends —
340
+ * app-initiated ({@link endARSession}) AND system-initiated (e.g. the Android
341
+ * back gesture, which ends an immersive session directly and uncancelably).
342
+ * `info.requestedByApp` discriminates the two. Fired AFTER the full teardown,
343
+ * so the host can immediately start a fresh session from inside the callback.
344
+ *
345
+ * Cleared by resetWebXRState() (i.e. after every session end) like the other
346
+ * module-level callbacks — re-register before/with each new session.
347
+ * Pass `null` to unregister. F3, 2026-07-04 user feedback.
348
+ */
349
+ declare function setSessionEndCallback(cb: ((info: SessionEndInfo) => void) | null): void;
287
350
  /**
288
351
  * End the current XR session and clean up all resources.
289
352
  *
@@ -305,6 +368,16 @@ declare function endARSession(): Promise<void>;
305
368
  * @param onSuspicious - Optional callback for when a captured image appears black/empty
306
369
  */
307
370
  declare function setImageCaptureCallback(onCaptured: (image: CapturedImage) => void, screenRotationGetter: () => number, onFailed?: () => void, onSuspicious?: (blobSize: number, frameIndex: number) => void): void;
371
+ /**
372
+ * Inject (or clear) the off-thread image-quality analyzer used by the blur/
373
+ * blackness drop+retry gate. Pass the recorder's Web Worker-backed analyzer to
374
+ * enable the gate, or `null` to clear it (legacy save-immediately path). Must be
375
+ * set BEFORE {@link startImageCapture} for the active recording — the manager
376
+ * reads it once when constructed. The analyzer only runs when the capture
377
+ * config's `qualityFilter.enabled` is true, so injecting it is harmless when the
378
+ * gate is off. Ownership/disposal of the worker is the caller's responsibility.
379
+ */
380
+ declare function setImageQualityAnalyzer(analyzer: ((frame: CapturedFrame) => Promise<FrameQualityVerdict>) | null): void;
308
381
  /**
309
382
  * Start capturing images during recording.
310
383
  * Must call setImageCaptureCallback first.
@@ -454,4 +527,4 @@ declare function setFrameCallback(callback: (() => void) | null): void;
454
527
  */
455
528
  declare function getLiveCss3dManager(): Css3dRendererManager | null;
456
529
  //#endregion
457
- export { setCamera as A, shouldLogCameraAccessDiagnostic as B, isWebXRSupported as C, resetWebXRState as D, nueQuaternionToWebXR$1 as E, setScene as F, stopDepthCapture as G, startDepthCapture as H, setTrackingCallbacks as I, stopImageCapture as K, setTrackingLostCallback as L, setDepthCaptureCallback as M, setFrameCallback as N, setArPose as O, setImageCaptureCallback as P, setTrackingRecoveredCallback as R, initAR as S, nuePositionToWebXR as T, startImageCapture as U, startCameraFrameCapture as V, stopCameraFrameCapture as W, getDepthSampleCount as _, applyAlignmentMatrix as a, getScene as b, endARSession as c, getArPose as d, getArWorldGroup as f, getCurrentArPose as g, getCameraFrameCount as h, TrackingSubscribableStore as i, setCameraFrameCallback as j, setArWorldGroup as k, extractPoseFromViewer as l, getCameraFrameCaptureSize as m, DEFAULT_CAMERA_FRAME_CAPTURE_SIZE as n, buildSessionOptions as o, getCamera as p, SessionFeatureOptions as r, createSceneHierarchy as s, CameraFrameCaptureConfig as t, extractResetTransformData as u, getImageCaptureFrameCount as v, isXRCameraLike as w, getXrCameraFromPose as x, getLiveCss3dManager as y, setTrackingStore as z };
530
+ export { stopImageCapture as $, nuePositionToWebXR as A, setImageQualityAnalyzer as B, getImageCaptureFrameCount as C, initAR as D, getXrCameraFromPose as E, setCamera as F, setTrackingRecoveredCallback as G, setSessionEndCallback as H, setCameraFrameCallback as I, startCameraFrameCapture as J, setTrackingStore as K, setDepthCaptureCallback as L, resetWebXRState as M, setArPose as N, isWebXRSupported as O, setArWorldGroup as P, stopDepthCapture as Q, setFrameCallback as R, getDepthSampleCount as S, getScene as T, setTrackingCallbacks as U, setScene as V, setTrackingLostCallback as W, startImageCapture as X, startDepthCapture as Y, stopCameraFrameCapture as Z, getCamera as _, DEFAULT_CAMERA_FRAME_CAPTURE_SIZE as a, getCurrentArPose as b, TrackingSubscribableStore as c, createSceneHierarchy as d, endARSession as f, getArWorldGroup as g, getArPose as h, CameraFrameCaptureConfig as i, nueQuaternionToWebXR$1 as j, isXRCameraLike as k, applyAlignmentMatrix as l, extractResetTransformData as m, AR_CAMERA_FOV as n, SessionEndInfo as o, extractPoseFromViewer as p, shouldLogCameraAccessDiagnostic as q, AR_CAMERA_NEAR as r, SessionFeatureOptions as s, AR_CAMERA_FAR as t, buildSessionOptions as u, getCameraFrameCaptureSize as v, getLiveCss3dManager as w, getDepthInfoFromFrame as x, getCameraFrameCount as y, setImageCaptureCallback as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gps-plus-slam-app-framework",
3
- "version": "1.4.0",
3
+ "version": "1.8.0",
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.4.0"
39
+ "gps-plus-slam-js": "^1.8.0"
40
40
  },
41
41
  "peerDependencies": {
42
42
  "@sentry/browser": ">=10.0.0",
@@ -104,10 +104,10 @@
104
104
  "build": "tsdown --config config/tsdown.config.ts",
105
105
  "verify:pack": "pnpm pack --dry-run",
106
106
  "verify:community-key-lifetime": "node scripts/verify-community-key-lifetime.mjs",
107
- "test:unit": "vitest run --coverage --config config/vitest.config.ts",
107
+ "test:unit": "node ../scripts/run-vitest-scoped.mjs run --coverage --config=config/vitest.config.ts",
108
108
  "typecheck": "tsc -p tsconfig.app.json --noEmit",
109
109
  "typecheck:tests": "tsc -p tsconfig.vitest.json --noEmit",
110
- "lint": "eslint . --config config/eslint.config.mjs",
110
+ "lint": "eslint . --config config/eslint.config.mjs --max-warnings 37",
111
111
  "test:watch": "vitest --config config/vitest.config.ts",
112
112
  "check:cycles": "dpdm -T --exit-code circular:1 --no-warning --no-tree ./src/index.ts",
113
113
  "setup": "bash ./scripts/setup.sh"
@@ -1,2 +0,0 @@
1
- import { ArImageCapture as ArImageCapture$1, GpsPoint as GpsPoint$1, LatLong as LatLong$1, LatLongAlt, Matrix4 as Matrix4$1, Quaternion as Quaternion$1, RootState as LibraryRootState, RootState as RootState$1, Vector3 as Vector3$1, calcGpsCoords as calcGpsCoords$1, calcRelativeCoordsInMeters, createGpsSlamStore, isIdentityMatrix4, odometryTrackingRestarted, validateLicenseKey as validateLicenseKey$1, webxrToNUE } from "gps-plus-slam-js";
2
- export { LibraryRootState as a, RootState$1 as c, calcRelativeCoordsInMeters as d, createGpsSlamStore as f, webxrToNUE as g, validateLicenseKey$1 as h, LatLongAlt as i, Vector3$1 as l, odometryTrackingRestarted as m, GpsPoint$1 as n, Matrix4$1 as o, isIdentityMatrix4 as p, LatLong$1 as r, Quaternion$1 as s, ArImageCapture$1 as t, calcGpsCoords$1 as u };
@@ -1,20 +0,0 @@
1
- //#region ../src/visualization/lerp-utils.d.ts
2
- /**
3
- * Shared lerp utilities for visualization modules.
4
- *
5
- * Both alignment-lerper and camera-follower need the same smoothing
6
- * rate constant and clamped-alpha formula. Centralised here (R3) to
7
- * keep the two modules in sync.
8
- */
9
- /** Default speed multiplier — ~90 % convergence in ~0.3 s at 60 fps. */
10
- declare const DEFAULT_LERP_RATE = 8;
11
- /**
12
- * Compute a frame-rate-independent lerp/slerp factor clamped to [0, 1].
13
- *
14
- * @param lerpRate Speed multiplier (higher = faster convergence).
15
- * @param dt Delta time in seconds since last frame.
16
- * @returns The interpolation alpha, guaranteed ≤ 1.0.
17
- */
18
- declare function clampedAlpha(lerpRate: number, dt: number): number;
19
- //#endregion
20
- export { clampedAlpha as n, DEFAULT_LERP_RATE as t };
@@ -1,82 +0,0 @@
1
- import { t as GridCell } from "./bresenham3d-ByjcmEgM.js";
2
- import { a as RgbTuple, i as DepthSample } from "./ar-types-BckI1E-O.js";
3
- import { Vector3 } from "gps-plus-slam-js";
4
-
5
- //#region ../src/ar/occupancy-grid.d.ts
6
- interface OccupancyGridOptions {
7
- /** Edge length of a cubic grid cell in meters. Default 0.15 (Unity parity). */
8
- readonly cellSizeM?: number;
9
- /**
10
- * Dominant-axis steps before a ray's endpoint at which free-space
11
- * carving stops, to respect depth noise. Default 2 (Unity parity).
12
- */
13
- readonly carveStopCells?: number;
14
- }
15
- declare class OccupancyGrid {
16
- readonly cellSizeM: number;
17
- readonly carveStopCells: number;
18
- private readonly cells;
19
- constructor(options?: OccupancyGridOptions);
20
- /** Number of occupied cells. */
21
- get size(): number;
22
- /**
23
- * Fold one depth sample into the grid: unproject each point, carve free
24
- * space from the camera cell to the point cell, then count the point's
25
- * cell as occupied. Points that cannot be unprojected (no
26
- * projectionMatrix on old recordings, invalid depth/coords) are skipped.
27
- *
28
- * Carving and incrementing run as two separate passes over the sample's
29
- * points: all rays are carved first, then every endpoint is incremented.
30
- * A single interleaved pass would be order-dependent — a deeper point's
31
- * carve could erase the endpoint a nearer point added earlier in the same
32
- * sample. Splitting the passes makes the result deterministic and lets an
33
- * endpoint observed within a sample survive other rays in that same
34
- * sample. (Deeper-carves-nearer still applies ACROSS samples: a later
35
- * sample's ray carves an earlier sample's endpoint as before.)
36
- *
37
- * @returns the number of points actually added.
38
- */
39
- addSample(sample: DepthSample): number;
40
- /** Occupied cells observed at least `minObservations` times (default 1). */
41
- getOccupiedCells(minObservations?: number): GridCell[];
42
- /** Quantize a raw-WebXR position to its grid cell (round per axis). */
43
- cellForPosition(pos: Vector3): GridCell;
44
- /** Center of a cell in raw WebXR space (round-consistent: cell · cellSizeM). */
45
- getCellCenter(cell: GridCell): Vector3;
46
- /**
47
- * Running-average of the EXACT unprojected surface points observed in this
48
- * cell (raw WebXR space), or null for an unknown cell. Unlike
49
- * {@link getCellCenter} (the geometric 15 cm-lattice center) this hugs the
50
- * real measured surface and noise-averages across viewpoints — used by the
51
- * COLMAP `points3D` export and the debug cubes (follow-up Item A). Being a
52
- * centroid of points that fell in the cell, it always lies within
53
- * `cellSizeM/2` of the cell center per axis.
54
- */
55
- getCellPoint(cell: GridCell): Vector3 | null;
56
- /**
57
- * Running-average color of the cell's colored observations (Iter 8), or
58
- * null when the cell is unknown or was only ever observed without color
59
- * (rgb option off / pre-Iter-8 recordings) — consumers fall back to
60
- * height-based coloring. Channels are rounded and clamped to 0–255.
61
- */
62
- getCellColor(cell: GridCell): RgbTuple | null;
63
- /**
64
- * Walk the grid from `startPos` to `endPos` and return the center of the
65
- * first cell occupied at least `minObservations` times, or null.
66
- * Port of Unity's `TryRaycast` (hook for cursor/floor-detection parity).
67
- */
68
- raycast(startPos: Vector3, endPos: Vector3, minObservations?: number): Vector3 | null;
69
- /** Remove all occupied cells (e.g. on store swap / new session). */
70
- clear(): void;
71
- /**
72
- * Delete occupied cells along the camera→point ray (the space was seen
73
- * through, so it must be free), stopping `carveStopCells` dominant-axis
74
- * steps before the endpoint. The endpoint cell itself is additionally
75
- * protected so a current observation is never erased (relevant for
76
- * carveStopCells = 0 and for the unconditional start-cell visit).
77
- */
78
- private carve;
79
- private increment;
80
- }
81
- //#endregion
82
- export { OccupancyGridOptions as n, OccupancyGrid as t };
@@ -1,369 +0,0 @@
1
- //#region ../src/state/recording-options.d.ts
2
- /**
3
- * Recording Options - User-configurable settings for data capture.
4
- *
5
- * Allows users to disable/configure high-frequency data streams
6
- * (depth sampling, image capture) to improve performance on lower-end devices.
7
- *
8
- * Options persist in localStorage across sessions.
9
- */
10
- /**
11
- * Input type for validateRecordingOptions allowing partial nested objects.
12
- * This allows passing incomplete objects that will be merged with defaults.
13
- */
14
- interface RecordingOptionsInput {
15
- depth?: Partial<DepthCaptureOptions>;
16
- images?: Partial<ImageCaptureOptions>;
17
- arCrashIsolation?: Partial<ArCrashIsolationOptions>;
18
- occupancy?: Partial<OccupancyOptions>;
19
- frameTileDisplay?: Partial<FrameTileDisplayOptions>;
20
- visualization?: Partial<VisualizationOptions>;
21
- qr?: Partial<QrCaptureOptions>;
22
- }
23
- /**
24
- * Diagnostic flags for isolating pre-recording AR startup crashes.
25
- * These gates affect XR session negotiation and frame-loop behavior,
26
- * independently of recording-time image/depth capture.
27
- */
28
- interface ArCrashIsolationOptions {
29
- enableDomOverlay: boolean;
30
- enableCameraAccess: boolean;
31
- enableDepthSensingFeature: boolean;
32
- enableCss3dRenderer: boolean;
33
- enableCameraTextureAcquisition: boolean;
34
- /**
35
- * Apply the Chromium WebXR camera-access tab-crash workaround at app
36
- * bootstrap. The workaround always deletes
37
- * `XRWebGLBinding.prototype.createProjectionLayer` /
38
- * `XRRenderState.prototype.layers` (forcing `XRWebGLLayer`) — required on
39
- * every affected Chrome build observed on-device, including Chrome 150 — and
40
- * additionally persists the `baseLayer` across
41
- * `XRSession.prototype.updateRenderState` only for Chrome builds inside the
42
- * affected window (148.0.7778.12 up to 149.0.7821).
43
- *
44
- * Default `true`. Opt-out is offered because forcing `XRWebGLLayer` may break
45
- * WebXR on unaffected (e.g. Quest) devices.
46
- *
47
- * @see GpsPlusSlamJs_AppFramework/src/ar/chromium-camera-access-workaround.ts
48
- * @see https://github.com/mrdoob/three.js/issues/33404
49
- */
50
- applyChromiumProjectionLayerWorkaround: boolean;
51
- }
52
- /**
53
- * Configuration for depth sampling during recording.
54
- */
55
- interface DepthCaptureOptions {
56
- /** Whether to capture depth samples. Default: true */
57
- enabled: boolean;
58
- /** Interval between samples in milliseconds. Default: 1000 */
59
- intervalMs: number;
60
- /**
61
- * Grid size (N×N points per sample). Default: 16 — dense enough to
62
- * populate the AR-space occupancy grid (2026-06-11 port plan §1).
63
- */
64
- gridSize: number;
65
- /**
66
- * Whether to enrich each depth point with the camera color at its view
67
- * coordinates (RGB voxel coloring, occupancy-grid port plan Iter 8).
68
- * Costs one small GPU blit+readback per sample (~1 Hz); when off, the
69
- * occupancy cubes keep the height-based coloring. Default: true.
70
- */
71
- rgb: boolean;
72
- }
73
- /**
74
- * Configuration for image capture during recording.
75
- */
76
- interface ImageCaptureOptions {
77
- /** Whether to capture images. Default: true */
78
- enabled: boolean;
79
- /** Interval between captures in milliseconds. Default: 2000 */
80
- intervalMs: number;
81
- /** JPEG quality (0.0 - 1.0). Default: 0.7 */
82
- quality: number;
83
- /** Resolution divisor: 1 = full native resolution, 2 = half, 4 = quarter. Default: 1 */
84
- resolutionDivisor: number;
85
- }
86
- /**
87
- * Configuration for the derived AR-space occupancy grid (the voxelization of
88
- * the depth samples, port plan 2026-06-11). These settings do NOT change what
89
- * is recorded — they govern the grid derived from the recorded depth points,
90
- * so they also apply when replaying an existing recording, letting the same
91
- * session be re-quantized at a different resolution.
92
- */
93
- interface OccupancyOptions {
94
- /**
95
- * Voxel edge length in metres. Drives the occupancy-grid quantization, the
96
- * debug cubes, and the COLMAP `points3D` density. Default 0.15 (15 cm, Unity
97
- * parity). Smaller = finer detail but cell count scales as 1/cellSize³, so the
98
- * range is deliberately clamped (see `OCCUPANCY_CONSTRAINTS`). Read once when
99
- * the grid is constructed (Enter-AR / replay load), so a change takes effect
100
- * on the next session rather than mid-session.
101
- */
102
- cellSizeM: number;
103
- }
104
- /**
105
- * Configuration for how captured frame tiles are DISPLAYED in AR (D7-resolution,
106
- * 2026-06-16 RecorderApp user feedback / Q3). This is **distinct from** the
107
- * capture setting `images.resolutionDivisor`: capture quality (the JPEG written
108
- * to the recording) is unchanged — this only downscales the in-AR/replay display
109
- * texture built from each captured frame, cutting per-tile GPU texture memory.
110
- *
111
- * Like {@link OccupancyOptions} it does NOT change what is recorded, so it
112
- * applies to **both live and replay** (the tile texture is decoded in both). A
113
- * partial memory mitigation for the OOM/crash track (the tile *count* still
114
- * grows unbounded — capping/recycling is the separate Track-S fix).
115
- */
116
- interface FrameTileDisplayOptions {
117
- /**
118
- * Display-texture resolution divisor: 1 = full captured resolution, 2 = half
119
- * (each dimension), 4 = quarter, 8 = eighth. Default 2 (half). Higher = less
120
- * GPU memory per tile but a blurrier in-AR preview. Independent of the capture
121
- * `images.resolutionDivisor`.
122
- */
123
- divisor: number;
124
- }
125
- /**
126
- * Visibility toggles for the live AR debug overlays (Finding B / DB-2 of
127
- * 2026-06-14-followup-frame-tile-legacy-aspect-and-live-toggle.md).
128
- *
129
- * These gate **only what is drawn live during recording** — they never change
130
- * what is captured (frame blobs, depth samples, occupancy data, GPS events all
131
- * continue regardless) and they never affect replay (where reviewing the
132
- * captured overlays is the whole point). Read once at Enter-AR: toggling
133
- * mid-session applies on the next Enter-AR, not retroactively.
134
- *
135
- * All four default ON, so adding this group is purely additive — every overlay
136
- * still renders until the operator opts out.
137
- */
138
- interface VisualizationOptions {
139
- /** Live frame-tile planes (`FrameTileVisualizer`). Default: true */
140
- frameTiles: boolean;
141
- /** Voxel depth cubes (`OccupancyCubesVisualizer`). Default: true */
142
- occupancyCubes: boolean;
143
- /** Raw/fused/snapshot GPS+VIO alignment spheres (`GpsEventVisualizer`). Default: true */
144
- gpsAlignmentMarkers: boolean;
145
- /** N/E/S/W compass orientation cubes (`createGpsCompassCubes`). Default: true */
146
- compassCubes: boolean;
147
- }
148
- /**
149
- * Configuration for live QR detection + RAW recording (decision §0 of the
150
- * recorder live-QR follow-up,
151
- * `2026-06-17-followup-recorder-live-qr-next-steps.md`).
152
- *
153
- * OPT-IN (`enabled` defaults to `false`): turning it on adds per-frame RGBA
154
- * capture + a `BarcodeDetector` decode to the session, so it is operator-gated
155
- * exactly like the heavy `depth`/`images` streams — an existing recording pays
156
- * nothing. When on, the producer dispatches one RAW `qrDetected/recordQrDetection`
157
- * action per accepted decode (size + pose are DERIVED on read, never recorded).
158
- */
159
- interface QrCaptureOptions {
160
- /** Whether live QR detection + recording runs. Default: false (opt-in). */
161
- enabled: boolean;
162
- /**
163
- * Capture / detection cadence in ms — the SINGLE cadence owner (the producer
164
- * runs `minIntervalMs: 0`; this throttles the camera-frame source). Default
165
- * 125 (~8 Hz), matching the QR demo's `DETECT_INTERVAL_MS`.
166
- */
167
- intervalMs: number;
168
- /**
169
- * RGBA capture long-edge in px. Larger = more decode range on a small/distant
170
- * QR but a costlier blit + detect. Default 1024 (the on-device sweep settled
171
- * here; 512 only decoded small QRs at very close range).
172
- */
173
- captureSize: number;
174
- }
175
- /**
176
- * User-configurable recording options.
177
- * Persisted to localStorage for cross-session consistency.
178
- */
179
- interface RecordingOptions {
180
- /** Depth sampling configuration */
181
- depth: DepthCaptureOptions;
182
- /** Image capture configuration */
183
- images: ImageCaptureOptions;
184
- /** Diagnostic flags for pre-recording AR crash isolation */
185
- arCrashIsolation: ArCrashIsolationOptions;
186
- /** Derived occupancy-grid configuration (voxel size) */
187
- occupancy: OccupancyOptions;
188
- /** Frame-tile display-texture resolution (live + replay; capture unchanged) */
189
- frameTileDisplay: FrameTileDisplayOptions;
190
- /** Live AR debug-overlay visibility toggles (live-only; replay unaffected) */
191
- visualization: VisualizationOptions;
192
- /** Live QR detection + RAW recording configuration (opt-in) */
193
- qr: QrCaptureOptions;
194
- }
195
- /**
196
- * localStorage key for persisted options.
197
- *
198
- * **Multi-tab caveat:** All tabs/instances sharing the same origin will
199
- * read and write this key. In multi-tab or embedded scenarios, concurrent
200
- * saves can silently overwrite each other. Use a custom `storageKey`
201
- * parameter in `loadRecordingOptions` / `saveRecordingOptions` to isolate
202
- * instances when needed.
203
- */
204
- declare const STORAGE_KEY = "gps-plus-slam-recorder-options";
205
- /** Default recording options (all streams enabled) */
206
- declare const DEFAULT_RECORDING_OPTIONS: RecordingOptions;
207
- /** Validation constraints for depth options */
208
- declare const DEPTH_CONSTRAINTS: {
209
- readonly intervalMs: {
210
- readonly min: 500;
211
- readonly max: 5000;
212
- readonly step: 100;
213
- };
214
- readonly gridSize: {
215
- readonly min: 2;
216
- readonly max: 32;
217
- readonly step: 1;
218
- };
219
- };
220
- /** Validation constraints for image options */
221
- declare const IMAGE_CONSTRAINTS: {
222
- readonly intervalMs: {
223
- readonly min: 1000;
224
- readonly max: 10000;
225
- readonly step: 500;
226
- };
227
- readonly quality: {
228
- readonly min: 0.3;
229
- readonly max: 1;
230
- readonly step: 0.1;
231
- };
232
- readonly resolutionDivisor: {
233
- readonly min: 1;
234
- readonly max: 8;
235
- readonly step: 1;
236
- };
237
- };
238
- /**
239
- * Validation constraints for occupancy options.
240
- *
241
- * `cellSizeM` is clamped to 1–20 cm. The floor exists because cell count (and
242
- * therefore the cube `InstancedMesh`, the grid `Map`, and the COLMAP
243
- * `points3D` row count) scales as 1/cellSize³ — sub-centimetre voxels are both
244
- * a memory/perf cliff on a phone and below the depth sensor's noise floor.
245
- * Step is 1 cm (the settings slider operates in cm).
246
- */
247
- declare const OCCUPANCY_CONSTRAINTS: {
248
- readonly cellSizeM: {
249
- readonly min: 0.01;
250
- readonly max: 0.2;
251
- readonly step: 0.01;
252
- };
253
- };
254
- /**
255
- * Validation constraints for the frame-tile display-resolution divisor.
256
- *
257
- * Clamped to 1–8 (full down to one-eighth per dimension), mirroring the capture
258
- * `IMAGE_CONSTRAINTS.resolutionDivisor` range so the settings slider behaves the
259
- * same. The intended stops are 1, 2, 4, 8 (full / half / quarter / eighth); the
260
- * divisor is rounded to an integer so the resize target dimensions stay clean.
261
- */
262
- declare const FRAME_TILE_DISPLAY_CONSTRAINTS: {
263
- readonly divisor: {
264
- readonly min: 1;
265
- readonly max: 8;
266
- readonly step: 1;
267
- };
268
- };
269
- /**
270
- * Validation constraints for QR-capture options.
271
- *
272
- * `intervalMs` is clamped to 50–1000 ms (20 Hz down to 1 Hz): below ~50 ms the
273
- * detector cannot keep up and frames just queue; above 1 s tracking feels dead.
274
- * `captureSize` is clamped to 256–2048 px: under 256 even a near QR loses its
275
- * modules; over 2048 the blit + decode cost is not worth it on a phone. Both
276
- * back a settings slider so a corrupt stored value can never break capture.
277
- */
278
- declare const QR_CONSTRAINTS: {
279
- readonly intervalMs: {
280
- readonly min: 50;
281
- readonly max: 1000;
282
- readonly step: 25;
283
- };
284
- readonly captureSize: {
285
- readonly min: 256;
286
- readonly max: 2048;
287
- readonly step: 128;
288
- };
289
- };
290
- /**
291
- * Validate and normalize AR crash isolation flags.
292
- * Missing or invalid values fall back to defaults.
293
- */
294
- declare function validateArCrashIsolationOptions(options: Partial<ArCrashIsolationOptions>): ArCrashIsolationOptions;
295
- /**
296
- * Validate and normalize the live debug-overlay visibility toggles.
297
- * Each field is boolean-or-default (same policy as the AR-crash-isolation
298
- * flags): a missing, corrupted, or pre-feature persisted value falls back to
299
- * the ON default so an overlay is never silently disabled by bad input.
300
- */
301
- declare function validateVisualizationOptions(options: Partial<VisualizationOptions>): VisualizationOptions;
302
- /**
303
- * Validate and normalize QR-capture options. `enabled` is boolean-or-default
304
- * (a corrupt/pre-feature value falls back to the OFF default so QR never
305
- * silently turns ON); `intervalMs`/`captureSize` are clamped to
306
- * {@link QR_CONSTRAINTS}, with a `Number.isFinite` guard so a stored `NaN`
307
- * (which is `typeof 'number'` and survives `clamp`) falls back to the default
308
- * rather than breaking the camera-frame source.
309
- */
310
- declare function validateQrOptions(options: Partial<QrCaptureOptions>): QrCaptureOptions;
311
- /**
312
- * Validate and normalize depth options.
313
- * Invalid values are clamped to valid ranges.
314
- */
315
- declare function validateDepthOptions(options: Partial<DepthCaptureOptions>): DepthCaptureOptions;
316
- /**
317
- * Validate and normalize image options.
318
- * Invalid values are clamped to valid ranges.
319
- */
320
- declare function validateImageOptions(options: Partial<ImageCaptureOptions>): ImageCaptureOptions;
321
- /**
322
- * Validate and normalize occupancy options.
323
- * Invalid values are clamped to valid ranges.
324
- *
325
- * Note the explicit `Number.isFinite` guard: `OccupancyGrid` throws a
326
- * `RangeError` on a non-finite cell size, and `clamp(NaN, …)` would otherwise
327
- * pass `NaN` straight through (it is `typeof 'number'`). Falling back to the
328
- * default keeps a corrupted stored value from crashing grid construction.
329
- */
330
- declare function validateOccupancyOptions(options: Partial<OccupancyOptions>): OccupancyOptions;
331
- /**
332
- * Validate and normalize frame-tile display options. `divisor` is clamped to
333
- * {@link FRAME_TILE_DISPLAY_CONSTRAINTS} and rounded to an integer, with a
334
- * `Number.isFinite` guard so a stored `NaN` (which is `typeof 'number'` and
335
- * survives `clamp`) falls back to the default rather than producing a broken
336
- * resize target.
337
- */
338
- declare function validateFrameTileDisplayOptions(options: Partial<FrameTileDisplayOptions>): FrameTileDisplayOptions;
339
- /**
340
- * Validate and normalize a full RecordingOptions object.
341
- * Merges with defaults and clamps invalid values.
342
- */
343
- declare function validateRecordingOptions(options: RecordingOptionsInput): RecordingOptions;
344
- /**
345
- * Load recording options from localStorage.
346
- * Returns defaults if no saved options exist or parsing fails.
347
- * Validates and merges with defaults to handle schema evolution.
348
- * @param storageKey - Optional custom localStorage key (defaults to STORAGE_KEY).
349
- */
350
- declare function loadRecordingOptions(storageKey?: string): RecordingOptions;
351
- /**
352
- * Save recording options to localStorage.
353
- * Options are validated before saving.
354
- * @param storageKey - Optional custom localStorage key (defaults to STORAGE_KEY).
355
- */
356
- declare function saveRecordingOptions(options: RecordingOptions, storageKey?: string): void;
357
- /**
358
- * Reset recording options to defaults.
359
- * Clears localStorage and returns default options.
360
- * @param storageKey - Optional custom localStorage key (defaults to STORAGE_KEY).
361
- */
362
- declare function resetRecordingOptions(storageKey?: string): RecordingOptions;
363
- /**
364
- * Create a deep copy of recording options.
365
- * Useful for creating mutable copies of the frozen defaults.
366
- */
367
- declare function cloneRecordingOptions(options: RecordingOptions): RecordingOptions;
368
- //#endregion
369
- export { validateFrameTileDisplayOptions as C, validateRecordingOptions as D, validateQrOptions as E, validateVisualizationOptions as O, validateDepthOptions as S, validateOccupancyOptions as T, cloneRecordingOptions as _, FRAME_TILE_DISPLAY_CONSTRAINTS as a, saveRecordingOptions as b, ImageCaptureOptions as c, QR_CONSTRAINTS as d, QrCaptureOptions as f, VisualizationOptions as g, STORAGE_KEY as h, DepthCaptureOptions as i, OCCUPANCY_CONSTRAINTS as l, RecordingOptionsInput as m, DEFAULT_RECORDING_OPTIONS as n, FrameTileDisplayOptions as o, RecordingOptions as p, DEPTH_CONSTRAINTS as r, IMAGE_CONSTRAINTS as s, ArCrashIsolationOptions as t, OccupancyOptions as u, loadRecordingOptions as v, validateImageOptions as w, validateArCrashIsolationOptions as x, resetRecordingOptions as y };