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.
- package/LICENSE +4 -4
- package/README.md +249 -108
- package/dist/accuracy-circles-CsxE_7x1.d.ts +43 -0
- package/dist/{app-selectors-DyMzxCEC.d.ts → app-selectors-BeU0_ab8.d.ts} +14 -15
- package/dist/ar/camera-blit-capture.d.ts +1 -1
- package/dist/ar/capture-failure-tracker.d.ts +1 -1
- package/dist/ar/chromium-camera-access-workaround.d.ts +1 -1
- package/dist/ar/depth-sampler.d.ts +2 -2
- package/dist/ar/depth-sampler.js +1 -1
- package/dist/ar/frame-loop.d.ts +2 -0
- package/dist/ar/frame-loop.js +40 -0
- package/dist/ar/image-capture.d.ts +1 -1
- package/dist/ar/image-capture.js +1 -1
- package/dist/ar/index.d.ts +12 -12
- package/dist/ar/index.js +3 -3
- package/dist/ar/replay-scene.d.ts +1 -1
- package/dist/ar/scene-node-names.d.ts +1 -1
- package/dist/ar/webxr-session.d.ts +4 -4
- package/dist/ar/webxr-session.js +151 -56
- package/dist/ar/xr-camera-texture.d.ts +1 -1
- package/dist/ar/xr-error-handler.d.ts +1 -1
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.js +2 -0
- package/dist/create-slam-app-store-CNsZ3rcX.d.ts +371 -0
- package/dist/{depth-sampler-BNCtnEoP.d.ts → depth-sampler-xg8vna6c.d.ts} +1 -1
- package/dist/file-system-DTApEv_Q.d.ts +114 -0
- package/dist/frame-loop-QJIxLin0.d.ts +42 -0
- package/dist/frustum-visibility-BHnFrSKQ.d.ts +58 -0
- package/dist/{fused-path-DtqCSqJh.d.ts → fused-path-CB4DwWOG.d.ts} +1 -1
- package/dist/geo/h3-proximity.d.ts +2 -0
- package/dist/{ref-points/h3-ref-point.js → geo/h3-proximity.js} +16 -12
- package/dist/geo/index.d.ts +2 -0
- package/dist/geo/index.js +2 -0
- package/dist/{geo-types-Xx-LVcnw.d.ts → geo-types-CTuF23gG.d.ts} +16 -1
- package/dist/{gps-Ddzr2KlX.d.ts → gps-DXoQb9Kf.d.ts} +1 -1
- package/dist/gps-anchor-CnWY61XK.d.ts +48 -0
- package/dist/gps-anchor-DjC_3MoT.js +257 -0
- package/dist/gps-ar-pose-sampler-DsM1Kb2N.d.ts +43 -0
- package/dist/{recording-coordinator-DzflP07_.d.ts → gps-event-coordinator-DBx9I1YX.d.ts} +7 -6
- package/dist/gps-event-markers-BGr-iLvi.d.ts +103 -0
- package/dist/{h3-ref-point-CFhayNSZ.d.ts → h3-proximity-BhfgNbdW.d.ts} +16 -12
- package/dist/{image-capture-2pKjYUS6.d.ts → image-capture-DZLxHDN9.d.ts} +1 -1
- package/dist/index-gzWJMVpo.d.ts +2 -0
- package/dist/index-pOjUCKEP.d.ts +24 -0
- package/dist/index.d.ts +59 -56
- package/dist/index.js +22 -21
- package/dist/{leaflet-map-overlay-CvfQXTye.d.ts → leaflet-map-overlay-Cew7XAoO.d.ts} +32 -17
- package/dist/licensing/index.d.ts +1 -1
- package/dist/licensing/index.js +1 -1
- package/dist/{logger-B81iwxx0.d.ts → logger-C9vugiQb.d.ts} +7 -1
- package/dist/map-data-sih4g64v.d.ts +49 -0
- package/dist/map-overlay-draw-B3R1c9Xp.d.ts +42 -0
- package/dist/{null-storage-backend-CsWvQwN8.d.ts → null-storage-backend-BKOS7JpL.d.ts} +4 -2
- package/dist/{opfs-storage-ChOzF_Wp.d.ts → opfs-storage-DOPkzgeT.d.ts} +54 -51
- package/dist/opfs-storage-backend-Cj_7PWoq.d.ts +13 -0
- package/dist/{permission-checker-jO2ziCWC.d.ts → permission-checker-DPJl_RU6.d.ts} +41 -1
- package/dist/persistence-middleware-BkHIqvaA.d.ts +55 -0
- package/dist/{recording-replayer-oOzPITrd.d.ts → recording-replayer-CmCIIZ02.d.ts} +2 -2
- package/dist/recording-slice-d6OtCrza.d.ts +28 -0
- package/dist/{replay-engine-DuX316ae.d.ts → replay-engine-BGBRQyXs.d.ts} +4 -1
- package/dist/{replay-scene-DtUm6bsr.d.ts → replay-scene-DpAGcAKY.d.ts} +3 -3
- package/dist/sensors/gps-error-handler.d.ts +1 -1
- package/dist/sensors/gps.d.ts +1 -1
- package/dist/sensors/gps.js +2 -2
- package/dist/sensors/index.d.ts +3 -3
- package/dist/sensors/index.js +1 -1
- package/dist/sensors/permission-checker.d.ts +2 -2
- package/dist/sensors/permission-checker.js +79 -1
- package/dist/state/app-selectors.d.ts +2 -2
- package/dist/state/app-selectors.js +33 -3
- package/dist/state/combined-root-state.d.ts +2 -0
- package/dist/state/combined-root-state.js +1 -0
- package/dist/state/create-slam-app-store.d.ts +2 -0
- package/dist/state/create-slam-app-store.js +75 -0
- package/dist/state/gps-ar-pose-sampler.d.ts +4 -0
- package/dist/state/gps-ar-pose-sampler.js +19 -0
- package/dist/state/{recording-coordinator.d.ts → gps-event-coordinator.d.ts} +1 -1
- package/dist/state/{recording-coordinator.js → gps-event-coordinator.js} +3 -4
- package/dist/state/index.d.ts +17 -17
- package/dist/state/index.js +10 -8
- package/dist/state/persistence-middleware.d.ts +2 -2
- package/dist/state/persistence-middleware.js +39 -11
- package/dist/state/recording-options.d.ts +1 -1
- package/dist/state/recording-replayer.d.ts +3 -2
- package/dist/state/recording-replayer.js +2 -2
- package/dist/state/recording-slice.d.ts +2 -0
- package/dist/state/{recorder-slice.js → recording-slice.js} +7 -15
- package/dist/state/replay-engine.d.ts +1 -1
- package/dist/state/replay-engine.js +3 -3
- package/dist/state/store-subscribers.d.ts +2 -2
- package/dist/state/store-subscribers.js +38 -20
- package/dist/state/subscribe-to-selector.d.ts +1 -1
- package/dist/state/tracking-quality.d.ts +2 -0
- package/dist/state/tracking-quality.js +723 -0
- package/dist/state/tracking-slice.d.ts +2 -0
- package/dist/state/tracking-slice.js +147 -0
- package/dist/storage/file-system-utils.d.ts +1 -1
- package/dist/storage/file-system.d.ts +2 -2
- package/dist/storage/file-system.js +154 -94
- package/dist/storage/index.d.ts +9 -11
- package/dist/storage/index.js +5 -7
- package/dist/storage/null-storage-backend.d.ts +1 -1
- package/dist/storage/null-storage-backend.js +7 -0
- package/dist/storage/opfs-storage-backend.d.ts +1 -1
- package/dist/storage/opfs-storage-backend.js +7 -1
- package/dist/storage/opfs-storage.d.ts +2 -2
- package/dist/storage/opfs-storage.js +69 -85
- package/dist/storage/storage-backend.d.ts +2 -2
- package/dist/storage/zip-export.d.ts +2 -2
- package/dist/storage/zip-export.js +55 -62
- package/dist/storage/zip-reader.d.ts +2 -2
- package/dist/storage/zip-reader.js +32 -5
- package/dist/storage-backend-CT0Il_AB.d.ts +28 -0
- package/dist/{store-subscribers-CuoIzB5T.d.ts → store-subscribers-Dce_CoJF.d.ts} +31 -7
- package/dist/{subscribe-to-selector-UTZ0KkAc.d.ts → subscribe-to-selector-DIHm3BRZ.d.ts} +1 -1
- package/dist/test-utils/browser-mocks.d.ts +1 -1
- package/dist/test-utils/zip-round-trip-helpers.d.ts +7 -1
- package/dist/test-utils/zip-round-trip-helpers.js +6 -5
- package/dist/tracking-slice-utCNND8t.d.ts +86 -0
- package/dist/types/ar-types.d.ts +1 -1
- package/dist/types/geo-types.d.ts +2 -2
- package/dist/types/index.d.ts +3 -3
- package/dist/utils/concurrency.d.ts +1 -1
- package/dist/utils/failure-tracker.d.ts +1 -1
- package/dist/utils/format-file-size.d.ts +1 -1
- package/dist/utils/fused-path.d.ts +1 -1
- package/dist/utils/index.d.ts +6 -6
- package/dist/utils/list-formatter.d.ts +1 -1
- package/dist/utils/logger.d.ts +1 -1
- package/dist/utils/logger.js +68 -8
- package/dist/visualization/accuracy-circles.d.ts +2 -0
- package/dist/visualization/accuracy-circles.js +57 -0
- package/dist/visualization/alignment-lerper.d.ts +1 -1
- package/dist/visualization/camera-follower.d.ts +1 -1
- package/dist/visualization/css3d-renderer-manager.d.ts +1 -1
- package/dist/visualization/frustum-visibility.d.ts +2 -0
- package/dist/visualization/frustum-visibility.js +139 -0
- package/dist/visualization/gps-anchor.d.ts +2 -0
- package/dist/visualization/gps-anchor.js +2 -0
- package/dist/visualization/gps-compass-cubes.d.ts +1 -1
- package/dist/visualization/gps-event-markers.d.ts +2 -2
- package/dist/visualization/gps-event-markers.js +69 -2
- package/dist/visualization/index.d.ts +17 -12
- package/dist/visualization/index.js +6 -2
- package/dist/visualization/leaflet-map-overlay.d.ts +1 -1
- package/dist/visualization/leaflet-map-overlay.js +56 -98
- package/dist/visualization/lerp-utils.d.ts +1 -1
- package/dist/visualization/map-data.d.ts +2 -0
- package/dist/visualization/map-data.js +33 -0
- package/dist/visualization/map-overlay-draw.d.ts +2 -0
- package/dist/visualization/map-overlay-draw.js +107 -0
- package/dist/visualization/map-overlay.d.ts +1 -1
- package/dist/visualization/three-dispose.d.ts +1 -1
- package/dist/visualization/vis-colors.d.ts +1 -1
- package/dist/{webxr-session-COlSrXdL.d.ts → webxr-session-DB5cIZnN.d.ts} +53 -12
- package/dist/{zip-export-Rtpi75JJ.d.ts → zip-export-QO4iLIi7.d.ts} +58 -7
- package/dist/{zip-reader-D7pkpX8K.d.ts → zip-reader-D1105idz.d.ts} +38 -1
- package/package.json +29 -18
- package/dist/ar/tracking-state.d.ts +0 -2
- package/dist/ar/tracking-state.js +0 -164
- package/dist/community-license-key-ChZLCJyO.d.ts +0 -21
- package/dist/file-system-BsQgYCU3.d.ts +0 -128
- package/dist/gps-event-markers-DpEy2qRd.d.ts +0 -67
- package/dist/licensing/community-license-key.d.ts +0 -2
- package/dist/licensing/community-license-key.js +0 -21
- package/dist/opfs-storage-backend-CVcmfJHN.d.ts +0 -11
- package/dist/persistence-middleware-DrptY02i.d.ts +0 -31
- package/dist/recorder-slice-fcwAXrsh.d.ts +0 -35
- package/dist/ref-point-importer-B_wn5ABk.d.ts +0 -62
- package/dist/ref-point-loader-Pt1smgHS.d.ts +0 -117
- package/dist/ref-points/h3-ref-point.d.ts +0 -2
- package/dist/ref-points/index.d.ts +0 -2
- package/dist/ref-points/index.js +0 -2
- package/dist/ref-points-slice-tC-Wd6XJ.d.ts +0 -48
- package/dist/reference-points-CFWy8_wj.d.ts +0 -68
- package/dist/routing-slice-BlHTM8eh.d.ts +0 -23
- package/dist/state/recorder-slice.d.ts +0 -2
- package/dist/state/ref-points-slice.d.ts +0 -2
- package/dist/state/ref-points-slice.js +0 -44
- package/dist/state/routing-slice.d.ts +0 -2
- package/dist/state/routing-slice.js +0 -13
- package/dist/state/store.d.ts +0 -9
- package/dist/state/store.js +0 -71
- package/dist/storage/ref-point-importer.d.ts +0 -2
- package/dist/storage/ref-point-importer.js +0 -163
- package/dist/storage/ref-point-loader.d.ts +0 -2
- package/dist/storage/ref-point-loader.js +0 -248
- package/dist/storage/ref-point-recovery.d.ts +0 -28
- package/dist/storage/ref-point-recovery.js +0 -159
- package/dist/storage-backend-BcEItnFr.d.ts +0 -20
- package/dist/store-C7PKOj8S.d.ts +0 -96
- package/dist/tracking-state-B9QfuZCg.d.ts +0 -101
- package/dist/visualization/reference-points.d.ts +0 -2
- package/dist/visualization/reference-points.js +0 -160
- /package/dist/{alignment-lerper-D9BeDwZX.d.ts → alignment-lerper-L1RbWHQ4.d.ts} +0 -0
- /package/dist/{ar-types-B-ORgk6Z.d.ts → ar-types-Ck8LEq8k.d.ts} +0 -0
- /package/dist/{camera-blit-capture-DHuyrrxr.d.ts → camera-blit-capture-C1V9I1Z6.d.ts} +0 -0
- /package/dist/{camera-follower-BMqPddxx.d.ts → camera-follower-1k8mnw5J.d.ts} +0 -0
- /package/dist/{capture-failure-tracker-2Q6oI2uQ.d.ts → capture-failure-tracker-JKb1ST8E.d.ts} +0 -0
- /package/dist/{chromium-camera-access-workaround-CU5zSKNr.d.ts → chromium-camera-access-workaround-NvChXsi8.d.ts} +0 -0
- /package/dist/{concurrency-p6gB30fT.d.ts → concurrency-CMw8pSaG.d.ts} +0 -0
- /package/dist/{css3d-renderer-manager-rgLMVAvd.d.ts → css3d-renderer-manager-CkjCb2HW.d.ts} +0 -0
- /package/dist/{failure-tracker-1sQ_Cgyw.d.ts → failure-tracker-DnHXOIRa.d.ts} +0 -0
- /package/dist/{file-system-utils-5cWO8Xyv.d.ts → file-system-utils-CtKiiw27.d.ts} +0 -0
- /package/dist/{format-file-size-onGq0k1Q.d.ts → format-file-size-BTS5H62-.d.ts} +0 -0
- /package/dist/{gps-compass-cubes-C-6JEnpR.d.ts → gps-compass-cubes-CsLtFv4B.d.ts} +0 -0
- /package/dist/{gps-error-handler-VPuNOuf8.d.ts → gps-error-handler-Dg3ziRVY.d.ts} +0 -0
- /package/dist/{lerp-utils-87NWjUOD.d.ts → lerp-utils-B8MM8zCR.d.ts} +0 -0
- /package/dist/{list-formatter-DKQQVLcl.d.ts → list-formatter-CNqi-E2j.d.ts} +0 -0
- /package/dist/{map-overlay-DuiZuCTx.d.ts → map-overlay-DAmreyA3.d.ts} +0 -0
- /package/dist/{recording-options-BYUFX8iU.d.ts → recording-options-Dq6IsKAv.d.ts} +0 -0
- /package/dist/{scene-node-names-DPsaE2z3.d.ts → scene-node-names-6LBjPmwz.d.ts} +0 -0
- /package/dist/{three-dispose-CCBHjE_a.d.ts → three-dispose-C2drkp6f.d.ts} +0 -0
- /package/dist/{vis-colors-Qi2vlRGt.d.ts → vis-colors-CHQhjal3.d.ts} +0 -0
- /package/dist/{xr-camera-texture-BbukNE79.d.ts → xr-camera-texture-BU5YvKAM.d.ts} +0 -0
- /package/dist/{xr-error-handler-DTHfmvrl.d.ts → xr-error-handler-CDY5QxGb.d.ts} +0 -0
package/LICENSE
CHANGED
|
@@ -181,10 +181,10 @@ APPENDIX: How to apply the Apache License to your work.
|
|
|
181
181
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
182
|
replaced with your own identifying information. (Don't include
|
|
183
183
|
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
-
comment syntax for the file format.
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
188
|
|
|
189
189
|
Copyright 2026 cs-util-com
|
|
190
190
|
|
package/README.md
CHANGED
|
@@ -1,18 +1,45 @@
|
|
|
1
1
|
# GPS+SLAM App Framework
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/gps-plus-slam-app-framework)
|
|
4
|
+
[](https://www.npmjs.com/package/gps-plus-slam-app-framework)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
[](https://nodejs.org/)
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
Reusable building blocks for AR+GPS web apps, built on top of the closed-source [gps-plus-slam-js](https://www.npmjs.com/package/gps-plus-slam-js) alignment core.
|
|
9
|
+
|
|
10
|
+
It is part toolkit, part fusion engine: the toolkit covers the AR + GPS plumbing every app needs anyway, and the fusion engine lifts location accuracy to the point where ideas that previously sat on the "someday, on native" shelf become reachable in a browser:
|
|
11
|
+
|
|
12
|
+
- A **WebXR + Three.js scene** with image and depth capture, replay rendering, and tracking-state monitoring.
|
|
13
|
+
- **GPS, orientation, and permission wiring** ready to plug into the store.
|
|
14
|
+
- **OPFS + ZIP record & replay** with a `StorageBackend` interface you can swap.
|
|
15
|
+
- A **composable Redux store factory** (`createSlamAppStore`) that combines the core library's reducers with your own slices.
|
|
16
|
+
|
|
17
|
+
## Why use GPS+SLAM? (Visual Stability Beyond Raw GPS)
|
|
18
|
+
|
|
19
|
+
Raw GPS is useful for getting near a place, but it still jitters by meters and altitude is usually the hardest channel to trust. Most location-based AR apps work around that with broad proximity zones, floating beacons, or oversized highlights — fine as a fallback, but limiting if you want content that sits exactly on a path, a wall, or a specific spot on the ground.
|
|
20
|
+
|
|
21
|
+
GPS+SLAM fuses GPS observations with the device's AR odometry, so as the user moves the alignment between the AR world and real-world coordinates gets more stable. On top of that, the framework gives you placement helpers for objects that should stay tied to a real location:
|
|
22
|
+
|
|
23
|
+
- **Alignment improves with motion:** Once the user has walked for roughly 15 seconds in representative outdoor conditions, the solver has enough baseline that visible drift drops well below raw GPS. How stable it actually feels still depends on the device, the environment, and how clean the GPS track is — but in our own outdoor tests it consistently held up well enough for content that needs to sit on a specific spot.
|
|
24
|
+
- **VPS-like benefits without a VPS dependency:** Cloud visual-positioning systems can work well, but they usually require network access and a provider-maintained scan of the place where the user stands. GPS+SLAM localizes from the device's own GPS, camera tracking, motion, and orientation sensors, so the same alignment approach works in rural areas, woods, mountains, and private sites that no VPS provider has pre-scanned.
|
|
25
|
+
- **Just a URL, no app install:** The whole experience runs in the mobile browser through WebXR, so end users open a link and are in AR within seconds. There is no app-store gate, no native build per platform, and authors can iterate on the live URL while users keep using the same link.
|
|
26
|
+
- **Heading does not depend only on the compass:** Phone compass data can be noisy, biased, or temporarily wrong enough to make a naive AR overlay rotate in the wrong direction. GPS+SLAM can infer the world heading from how the user actually moves through space, so after the user has walked a few meters the overlay no longer has to trust the device-orientation readings.
|
|
27
|
+
- **Session-local objects stay fixed:** Objects created directly in the AR scene can stay at the same 3D position for the current session, independent of later GPS alignment updates. This is ideal for content the user creates live, such as a 3D trail of the path they walked, temporary markers, or objects they place by hand in the world.
|
|
28
|
+
- **Anchors make placed content shareable:** When an object should also be tied to a GPS coordinate for replay, persistence, or sharing with other users, `createGpsAnchor` bootstraps from median GPS samples, keeps the Three.js object positioned from its GPS target inside `arWorldGroup`, and can defer small corrections until the object is off-screen. Large alignment jumps still force a correction so content does not remain in a stale location.
|
|
29
|
+
- **Use exact paths and POIs, not only blobs:** Proximity zones remain a good UX for letting users enter an experience from any direction, but they do not have to be the only interaction model. The framework is designed for route-following cues, authored POI objects, precise areas of interest, and other content that benefits from being visibly tied to a real-world path or location.
|
|
30
|
+
|
|
31
|
+
Don't take any of this on trust. Because everything runs in the browser, the fastest review is to open one of the example URLs on your own phone, step outside, drop an object, walk around it, and judge for yourself whether the stability holds up for your use case.
|
|
6
32
|
|
|
7
33
|
## Architecture
|
|
8
34
|
|
|
9
35
|
```
|
|
10
36
|
┌──────────────────────────────────────────────────┐
|
|
11
37
|
│ Your App │
|
|
12
|
-
│ (UI, screen flow, app-specific
|
|
38
|
+
│ (UI, screen flow, app-specific reducers) │
|
|
13
39
|
├──────────────────────────────────────────────────┤
|
|
14
40
|
│ gps-plus-slam-app-framework ← this package │
|
|
15
|
-
│ (WebXR, Three.js, sensors, storage, replay
|
|
41
|
+
│ (WebXR, Three.js, sensors, storage, replay, │
|
|
42
|
+
│ composable store factory) │
|
|
16
43
|
├──────────────────────────────────────────────────┤
|
|
17
44
|
│ gps-plus-slam-js (core algorithms) │
|
|
18
45
|
│ (GPS/AR alignment, outlier rejection, GPS math) │
|
|
@@ -24,175 +51,287 @@ The framework never imports from your app. Your app imports from the framework a
|
|
|
24
51
|
## Installation
|
|
25
52
|
|
|
26
53
|
```bash
|
|
27
|
-
|
|
54
|
+
pnpm add gps-plus-slam-app-framework gps-plus-slam-js
|
|
28
55
|
```
|
|
29
56
|
|
|
57
|
+
### Runtime Dependencies
|
|
58
|
+
|
|
59
|
+
These are pulled in automatically — you do not need to install them yourself:
|
|
60
|
+
|
|
61
|
+
- `@reduxjs/toolkit`
|
|
62
|
+
- `gl-matrix`
|
|
63
|
+
- `gps-plus-slam-js`
|
|
64
|
+
|
|
30
65
|
### Peer Dependencies
|
|
31
66
|
|
|
32
|
-
Required:
|
|
67
|
+
Required (install in your app):
|
|
33
68
|
|
|
34
69
|
- `three` (>= 0.170.0)
|
|
35
70
|
- `@zip.js/zip.js` (>= 2.7.0)
|
|
36
71
|
- `h3-js` (>= 4.0.0)
|
|
37
|
-
- `@reduxjs/toolkit` (>= 2.9.0)
|
|
38
72
|
|
|
39
73
|
Optional:
|
|
40
74
|
|
|
41
|
-
- `leaflet` (>= 1.9.0) — only needed if
|
|
42
|
-
- `@sentry/browser` (>= 10.0.0) — only needed
|
|
75
|
+
- `leaflet` (>= 1.9.0) — only needed if you use `LeafletMapOverlay`
|
|
76
|
+
- `@sentry/browser` (>= 10.0.0) — only needed if you wire Sentry error reporting
|
|
43
77
|
|
|
44
78
|
## Quick Start
|
|
45
79
|
|
|
46
80
|
```typescript
|
|
47
|
-
import {
|
|
81
|
+
import { createSlamAppStore } from 'gps-plus-slam-app-framework/state';
|
|
48
82
|
import { initAR } from 'gps-plus-slam-app-framework/ar';
|
|
49
83
|
import { startGpsWatch } from 'gps-plus-slam-app-framework/sensors';
|
|
50
|
-
import {
|
|
51
|
-
import {
|
|
84
|
+
import { NullStorageBackend } from 'gps-plus-slam-app-framework/storage';
|
|
85
|
+
import { recordGpsEvent } from 'gps-plus-slam-app-framework/state';
|
|
52
86
|
|
|
53
|
-
// 1.
|
|
54
|
-
|
|
87
|
+
// 1. Compose the store. NullStorageBackend keeps everything in memory; swap
|
|
88
|
+
// to OpfsStorageBackend when you want durable recording.
|
|
89
|
+
const store = createSlamAppStore({
|
|
90
|
+
storageBackend: new NullStorageBackend(),
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// 2. Start the WebXR AR session.
|
|
94
|
+
await initAR(document.getElementById('app')!);
|
|
55
95
|
|
|
56
|
-
//
|
|
96
|
+
// 3. Wire GPS into the store.
|
|
57
97
|
startGpsWatch(
|
|
58
98
|
(pos) => {
|
|
59
|
-
|
|
99
|
+
store.dispatch(
|
|
100
|
+
recordGpsEvent({
|
|
101
|
+
/* build the payload from `pos` */
|
|
102
|
+
})
|
|
103
|
+
);
|
|
60
104
|
},
|
|
61
105
|
(err) => {
|
|
62
|
-
|
|
106
|
+
console.error('GPS error', err);
|
|
63
107
|
}
|
|
64
108
|
);
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
See [`GpsPlusSlamJs_MinimalExample`](../GpsPlusSlamJs_MinimalExample/) for a complete, runnable smallest-possible consumer (Three.js scene + status panel, no AR, no recording).
|
|
112
|
+
|
|
113
|
+
> **Imports.** Prefer subpath imports (`gps-plus-slam-app-framework/ar`, `…/state`, `…/sensors`, `…/storage`, `…/geo`, `…/visualization`, `…/utils`, `…/types`, `…/licensing`). The root barrel re-exports conflict-free names for convenience.
|
|
114
|
+
|
|
115
|
+
## Composing With Your Own Slices
|
|
116
|
+
|
|
117
|
+
`createSlamAppStore` is the headline composability seam. Your app plugs in its own reducers, middleware, and storage backend without forking the factory:
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import { createSlamAppStore } from 'gps-plus-slam-app-framework/state';
|
|
121
|
+
import { OpfsStorageBackend } from 'gps-plus-slam-app-framework/storage';
|
|
122
|
+
import { myUiReducer } from './state/ui-slice';
|
|
123
|
+
import { myAnalyticsMiddleware } from './state/analytics-middleware';
|
|
124
|
+
|
|
125
|
+
const store = createSlamAppStore({
|
|
126
|
+
storageBackend: new OpfsStorageBackend(),
|
|
127
|
+
extraReducers: { ui: myUiReducer },
|
|
128
|
+
extraMiddleware: [myAnalyticsMiddleware],
|
|
129
|
+
onWriteFailure: (err) => myErrorReporter(err),
|
|
130
|
+
enableDevChecks: import.meta.env.DEV,
|
|
131
|
+
// licenseKey: 'paid-key-here' // omit to use the bundled community key
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
| Option | Purpose |
|
|
136
|
+
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
137
|
+
| `storageBackend` | **Required.** Bridge from Redux actions to durable storage. Use `NullStorageBackend` for tests/replay, `OpfsStorageBackend` for browser recording. |
|
|
138
|
+
| `extraReducers` | Caller-supplied reducers added alongside the framework's built-ins (`gpsData`, `gpsElements`, `arElements`, `recording`). |
|
|
139
|
+
| `extraMiddleware` | Caller-supplied middlewares appended after RTK defaults and the persistence middleware. |
|
|
140
|
+
| `onWriteFailure` | Invoked when the persistence middleware fails to durably write an action. |
|
|
141
|
+
| `enableDevChecks` | Toggle RTK's expensive dev-only Serializable / Immutable checks. Default `true`; set `false` for high-throughput replay. |
|
|
142
|
+
| `licenseKey` | Override the bundled community key with a paid license. Validation always runs. |
|
|
143
|
+
|
|
144
|
+
## Recording & Replay
|
|
145
|
+
|
|
146
|
+
Out of the box the framework lays out durable storage like this when you use `OpfsStorageBackend`:
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
/gps-plus-slam/
|
|
150
|
+
└── sessions/
|
|
151
|
+
└── recording-{timestamp}/
|
|
152
|
+
├── actions/ (one JSON file per recorded Redux action)
|
|
153
|
+
├── frames/ (captured camera/depth frames)
|
|
154
|
+
└── session.json
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Key APIs:
|
|
158
|
+
|
|
159
|
+
- `exportSessionAsZip(sessionHandle, { contributors? })` — bundle a recorded session into a ZIP blob.
|
|
160
|
+
- `replayRecording(store, blob)` — feed a ZIP recording back into a store.
|
|
161
|
+
- `loadActionsFromZip(blob)` / `loadEntriesFromSubdir(blob, subdir)` — read recorded actions or any contributor-defined ZIP subdirectory.
|
|
162
|
+
|
|
163
|
+
### Adding Your Own ZIP Sections (`ZipExportContributor`)
|
|
65
164
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
165
|
+
Apps that need to ship extra data alongside the standard recording (e.g., the recorder app stores `refPoints/` this way) implement a `ZipExportContributor`:
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
import {
|
|
169
|
+
exportSessionAsZip,
|
|
170
|
+
type ZipExportContributor,
|
|
171
|
+
} from 'gps-plus-slam-app-framework/storage';
|
|
172
|
+
|
|
173
|
+
const refPointsContributor: ZipExportContributor = {
|
|
174
|
+
subdir: 'refPoints',
|
|
175
|
+
contribute: async (addFile) => {
|
|
176
|
+
addFile('points.json', JSON.stringify(myRefPoints));
|
|
177
|
+
},
|
|
178
|
+
};
|
|
69
179
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
/* visualization dependencies */
|
|
180
|
+
const blob = await exportSessionAsZip(sessionHandle, {
|
|
181
|
+
contributors: [refPointsContributor],
|
|
73
182
|
});
|
|
74
183
|
```
|
|
75
184
|
|
|
76
|
-
|
|
185
|
+
## Scene-Graph Convention
|
|
186
|
+
|
|
187
|
+
The framework's WebXR scene is laid out so that the **scene root is GPS-aligned (NUE) space**:
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
scene ← GPS-aligned (NUE) space, the scene root
|
|
191
|
+
├── arWorldGroup ← carries the alignment matrix (GPS → AR)
|
|
192
|
+
│ ├── camera ← WebXR XRViewerPose (raw AR pose)
|
|
193
|
+
│ └── ar-content ← anything fixed in AR space
|
|
194
|
+
│ (planes, point clouds, hit-test reticles, …)
|
|
195
|
+
└── ..objects with gps coords.. ← anything anchored to GPS coordinates
|
|
196
|
+
(waypoints, POIs, navigation arrows, …)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
When the alignment solver produces a new matrix, the framework writes it to `arWorldGroup.matrix`. The camera moves with `arWorldGroup`; objects parented directly to `scene` do not.
|
|
200
|
+
|
|
201
|
+
**Three options for placing your own `Object3D`:**
|
|
202
|
+
|
|
203
|
+
1. **Add it to `scene`** (with NUE-meter coordinates from `calcRelativeCoordsInMeters(zeroRef, …)`). The object's world pose stays at the correct latitude/longitude/altitude forever, but every time the alignment matrix is corrected the camera shifts inside `arWorldGroup`, so from the user's AR view the object visually "floats". Cheap and correct, but ugly during corrections — fine for small markers (e.g. ref-point spheres), not great for richer GPS-anchored content.
|
|
204
|
+
2. **Add it to `arWorldGroup`** with a fixed local transform. The object is frozen relative to AR-tracked content and stays visually fixed at the same 3D position for this session. This is a good fit for user-created local content such as a walked path, a temporary marker, a hit-test reticle, or an object the user placed by hand. The tradeoff is that its world / GPS pose drifts every time alignment is corrected, so this mode is not enough when the object must be replayed or shared by GPS coordinate.
|
|
205
|
+
3. **Use `createGpsAnchor` for objects that should stay visually stable at a GPS target.** The anchor owns a single `Object3D` inside `arWorldGroup`, bootstraps from median GPS samples unless `skipBootstrap` is set, and re-derives the object's local pose from the current GPS target and alignment state. In the default `snap-when-offscreen` mode, small corrections are committed while the object is outside the camera frustum, making small alignment corrections hard to notice; larger alignment jumps bypass that gate so the object does not stay in a stale location. Use `snap-every-tick` when correctness is more important than hiding visible position changes.
|
|
206
|
+
|
|
207
|
+
A pure-function `syncGpsAnchoredMeshes` reconciler (option 1, bulk markers) is shipped by the RecorderApp. Use `createGpsAnchor` when a single visible object, route cue, or POI needs the more careful bootstrap and correction policy.
|
|
77
208
|
|
|
78
209
|
## Modules
|
|
79
210
|
|
|
80
211
|
### `ar/` — WebXR & 3D Scene
|
|
81
212
|
|
|
82
|
-
WebXR session lifecycle, Three.js renderer setup, image/depth capture,
|
|
213
|
+
WebXR session lifecycle, Three.js renderer setup, image/depth capture, replay scene management.
|
|
83
214
|
|
|
84
215
|
| Export | Description |
|
|
85
216
|
| -------------------------------------------- | ------------------------------------------------ |
|
|
86
217
|
| `initAR(container)` | Start a WebXR AR session with Three.js rendering |
|
|
87
218
|
| `endARSession()` | End the active XR session |
|
|
88
219
|
| `startImageCapture()` / `stopImageCapture()` | Toggle camera frame capture |
|
|
89
|
-
| `startDepthCapture()` / `stopDepthCapture()` | Toggle depth sampling |
|
|
90
|
-
| `initReplayScene(container)` | Create a 3D replay scene with orbit/FPS controls |
|
|
91
220
|
| `ImageCaptureManager` | Configurable camera frame capture pipeline |
|
|
92
221
|
| `DepthSampler` | Depth buffer sampling with configurable grids |
|
|
93
222
|
| `CameraBlitCapture` | GPU blit-based camera capture |
|
|
94
|
-
| `
|
|
223
|
+
| `initReplayScene(container)` | Create a 3D replay scene with orbit/FPS controls |
|
|
224
|
+
| `applyChromiumProjectionLayerWorkaround` | Workaround for Chromium camera-access edge cases |
|
|
95
225
|
|
|
96
226
|
### `sensors/` — GPS & Permissions
|
|
97
227
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
|
101
|
-
|
|
|
102
|
-
| `
|
|
103
|
-
| `
|
|
104
|
-
| `
|
|
105
|
-
| `
|
|
106
|
-
| `
|
|
107
|
-
| `
|
|
228
|
+
| Export | Description |
|
|
229
|
+
| ----------------------------------- | ----------------------------------------- |
|
|
230
|
+
| `startGpsWatch(onPos, onErr)` | Start watching GPS position |
|
|
231
|
+
| `stopGpsWatch()` | Stop GPS watch |
|
|
232
|
+
| `startOrientationWatch(cb)` | Start device orientation events |
|
|
233
|
+
| `checkAllPermissions()` | Probe camera, GPS, XR permissions |
|
|
234
|
+
| `requestAllPermissions()` | Request all needed permissions |
|
|
235
|
+
| `getGpsErrorMessage(code)` | Human-readable GPS error messages |
|
|
236
|
+
| `createGpsErrorHandler()` | GPS error callback with deduplicated logs |
|
|
237
|
+
| `requestWebXRWithDepthPermission()` | Combined XR + depth permission prompt |
|
|
108
238
|
|
|
109
239
|
### `state/` — Store & Recording
|
|
110
240
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
|
114
|
-
|
|
|
115
|
-
| `
|
|
116
|
-
| `
|
|
117
|
-
| `
|
|
118
|
-
| `
|
|
119
|
-
| `
|
|
120
|
-
| `replayRecording(store, blob)`
|
|
121
|
-
| `
|
|
122
|
-
| `
|
|
123
|
-
| `
|
|
241
|
+
| Export | Description |
|
|
242
|
+
| --------------------------------------------------- | -------------------------------------------------------------- |
|
|
243
|
+
| `createSlamAppStore(options)` | Composable store factory (see options table above). |
|
|
244
|
+
| `recordingReducer` | Recording lifecycle slice (built into the factory). |
|
|
245
|
+
| `startSession()` / `endSession()` | Recording lifecycle actions. |
|
|
246
|
+
| `recordGpsEvent(payload)` | Record a paired AR+GPS observation. |
|
|
247
|
+
| `createGpsPositionHandler(config)` | Factory that adapts `GeolocationPosition` to a store dispatch. |
|
|
248
|
+
| `captureGpsAnchorSample(options)` | Sample a paired AR pose + GPS point for anchoring. |
|
|
249
|
+
| `loadRecordingOptions()` / `saveRecordingOptions()` | Persist user-controlled recording settings. |
|
|
250
|
+
| `replayRecording(store, blob)` | Replay a ZIP recording into a store. |
|
|
251
|
+
| `ReplayEngine` | Lower-level timed action playback with pause/resume/speed. |
|
|
252
|
+
| `createPersistenceMiddleware(options)` | Middleware factory used internally by `createSlamAppStore`. |
|
|
253
|
+
| `wireStoreSubscribers(store, deps)` | Bridge store state → visualization updates. |
|
|
124
254
|
|
|
125
255
|
### `storage/` — OPFS, ZIP, File System
|
|
126
256
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
|
130
|
-
|
|
|
131
|
-
| `
|
|
132
|
-
| `
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
135
|
-
| `
|
|
136
|
-
| `
|
|
137
|
-
| `
|
|
138
|
-
| `
|
|
139
|
-
| `
|
|
257
|
+
| Export | Description |
|
|
258
|
+
| ---------------------------------------------- | ------------------------------------------------------- |
|
|
259
|
+
| `StorageBackend` | Abstract storage interface (implement your own). |
|
|
260
|
+
| `OpfsStorageBackend` | OPFS-based `StorageBackend`. |
|
|
261
|
+
| `NullStorageBackend` | No-op backend for tests and replay. |
|
|
262
|
+
| `initOpfsStorage()` / `initStorage(backend)` | Initialize the file-system layer. |
|
|
263
|
+
| `createSession()` / `listSessions()` | Session lifecycle on disk. |
|
|
264
|
+
| `exportSessionAsZip(handle, { contributors })` | Export a recording session as a ZIP blob. |
|
|
265
|
+
| `ZipExportContributor` | Hook for adding your own ZIP subdirectories on export. |
|
|
266
|
+
| `loadActionsFromZip(blob)` | Parse recorded actions from a ZIP file. |
|
|
267
|
+
| `loadEntriesFromSubdir(blob, subdir)` | Read entries written by a contributor on import/replay. |
|
|
268
|
+
| `loadSessionMetadataFromBlob(blob)` | Read `session.json` from a ZIP. |
|
|
269
|
+
| `loadGpsPathFromBlob(blob)` | Read the recorded GPS path. |
|
|
270
|
+
| `checkStorageQuota()` | Check OPFS quota usage. |
|
|
271
|
+
|
|
272
|
+
### `geo/` — H3 Spatial Indexing
|
|
273
|
+
|
|
274
|
+
H3-based proximity matching for GPS-anchored points (renamed from `ref-points/` in the boundary migration).
|
|
275
|
+
|
|
276
|
+
| Export | Description |
|
|
277
|
+
| -------------------------------- | ------------------------------------------------------------- |
|
|
278
|
+
| `gpsToH3(lat, lon)` | Convert GPS coordinates to an H3 cell index. |
|
|
279
|
+
| `findNearbyGeoAnchor(h3, known)` | Find a known geo-anchored point near an H3 cell. |
|
|
280
|
+
| `h3CellsMatch(a, b)` | Compare two H3 indices. |
|
|
281
|
+
| `approxDistanceMetres(a, b)` | Approximate distance between two `LatLong`s. |
|
|
282
|
+
| `isH3Index(value)` | Type guard for H3 index strings. |
|
|
283
|
+
| `H3_RESOLUTION` | The H3 resolution used (default: 12, ~10 m cells). |
|
|
284
|
+
| `KnownGeoAnchor` (type) | Shape of a known anchor with H3 index, lat/lon, and metadata. |
|
|
140
285
|
|
|
141
286
|
### `visualization/` — Three.js & Maps
|
|
142
287
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
|
146
|
-
|
|
|
147
|
-
| `
|
|
148
|
-
| `
|
|
149
|
-
| `
|
|
150
|
-
| `
|
|
151
|
-
| `
|
|
152
|
-
| `
|
|
153
|
-
| `
|
|
154
|
-
| `
|
|
155
|
-
| `VIS_COLORS` | Consistent color palette for visualizations |
|
|
156
|
-
| `disposeObject3D(obj)` | Safe Three.js object disposal |
|
|
157
|
-
|
|
158
|
-
### `ref-points/` — H3 Spatial Indexing
|
|
159
|
-
|
|
160
|
-
H3-based proximity matching for reference points.
|
|
161
|
-
|
|
162
|
-
| Export | Description |
|
|
163
|
-
| ------------------------------- | ------------------------------------------------ |
|
|
164
|
-
| `gpsToH3(lat, lon)` | Convert GPS coordinates to an H3 cell index |
|
|
165
|
-
| `findNearbyRefPoint(h3, known)` | Find a known reference point near an H3 cell |
|
|
166
|
-
| `H3_RESOLUTION` | The H3 resolution used (default: 12, ~10m cells) |
|
|
288
|
+
| Export | Description |
|
|
289
|
+
| ------------------------------ | ------------------------------------------------------ |
|
|
290
|
+
| `LeafletMapOverlay` | 2D Leaflet map integrated via CSS3D into a 3D scene. |
|
|
291
|
+
| `MapOverlay` | Tile-based 3D map overlay (no Leaflet dependency). |
|
|
292
|
+
| `GpsEventVisualizer` | Three.js spheres for GPS event positions. |
|
|
293
|
+
| `createAlignmentLerper()` | Smooth alignment matrix interpolation. |
|
|
294
|
+
| `createCameraFollower()` | Camera that tracks a moving target. |
|
|
295
|
+
| `createCss3dRendererManager()` | CSS3D renderer for HTML-in-3D overlays. |
|
|
296
|
+
| `createGpsCompassCubes()` | Cardinal direction indicator cubes. |
|
|
297
|
+
| `createGpsAnchor()` | GPS-anchored placement helper for one Three.js object. |
|
|
298
|
+
| `VIS_COLORS` | Consistent color palette for visualizations. |
|
|
299
|
+
| `disposeObject3D(obj)` | Safe Three.js object disposal. |
|
|
167
300
|
|
|
168
301
|
### `utils/` — Logging & Helpers
|
|
169
302
|
|
|
170
|
-
| Export | Description
|
|
171
|
-
| ------------------------------------------- |
|
|
172
|
-
| `createLogger(channel)` |
|
|
173
|
-
| `
|
|
174
|
-
| `
|
|
175
|
-
| `
|
|
176
|
-
| `
|
|
303
|
+
| Export | Description |
|
|
304
|
+
| ------------------------------------------- | ------------------------------------------------- |
|
|
305
|
+
| `createLogger(channel)` | Channeled logger with level control. |
|
|
306
|
+
| `getLogBuffer()` / `subscribeToLogs()` | Inspect or subscribe to the in-memory log ring. |
|
|
307
|
+
| `computeFusedPath(inputs)` | Compute a fused GPS+odometry path. |
|
|
308
|
+
| `createFailureTracker(config)` | Track failure rates with configurable thresholds. |
|
|
309
|
+
| `mapWithConcurrencyLimit(items, fn, limit)` | Async map with bounded concurrency. |
|
|
310
|
+
| `formatFileSize(bytes)` | Human-readable file sizes. |
|
|
311
|
+
| `listFormatter(items)` | Human-friendly comma/and list formatting. |
|
|
177
312
|
|
|
178
313
|
### `types/` — Shared Type Definitions
|
|
179
314
|
|
|
180
|
-
AR and
|
|
315
|
+
AR and geo type definitions (`DepthPoint`, `DepthSample`, `LatLong`, `KnownGeoAnchor`, …) used across modules.
|
|
316
|
+
|
|
317
|
+
### `licensing/` — Bundled Community Key
|
|
318
|
+
|
|
319
|
+
Re-exports `COMMUNITY_LICENSE_KEY` from the core library so that consumers can pass it explicitly if they need to. `createSlamAppStore` already uses it as the default.
|
|
181
320
|
|
|
182
321
|
## Design Principles
|
|
183
322
|
|
|
184
323
|
1. **No global singletons.** Everything is created via factories and passed explicitly.
|
|
185
|
-
2. **Store is the integration point.**
|
|
324
|
+
2. **Store is the integration point.** Modules communicate through Redux state.
|
|
186
325
|
3. **Modules are optional.** Use `initAR` without `LeafletMapOverlay`. No forced coupling.
|
|
187
|
-
4. **Swappable implementations.** The `StorageBackend` interface lets you replace OPFS with IndexedDB or
|
|
326
|
+
4. **Swappable implementations.** The `StorageBackend` interface lets you replace OPFS with IndexedDB or anything else.
|
|
188
327
|
|
|
189
328
|
## Development
|
|
190
329
|
|
|
191
330
|
```bash
|
|
192
331
|
cd GpsPlusSlamJs_AppFramework
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
332
|
+
pnpm install
|
|
333
|
+
pnpm test # format + lint + typecheck + unit tests
|
|
334
|
+
pnpm run build # build with tsdown
|
|
196
335
|
```
|
|
197
336
|
|
|
198
337
|
### Project Structure
|
|
@@ -201,12 +340,13 @@ npm run build # build with tsdown
|
|
|
201
340
|
src/
|
|
202
341
|
├── ar/ # WebXR session, capture, replay scene
|
|
203
342
|
├── sensors/ # GPS, orientation, permissions
|
|
204
|
-
├── state/ #
|
|
205
|
-
├── storage/ # OPFS, ZIP
|
|
206
|
-
├──
|
|
343
|
+
├── state/ # createSlamAppStore, recording, replay, persistence middleware
|
|
344
|
+
├── storage/ # OPFS, ZIP export/import, StorageBackend
|
|
345
|
+
├── geo/ # H3 spatial indexing
|
|
207
346
|
├── visualization/ # Three.js markers, maps, camera helpers
|
|
208
|
-
├── utils/ # Logger, concurrency, formatters
|
|
347
|
+
├── utils/ # Logger, fused-path, concurrency, formatters
|
|
209
348
|
├── types/ # Shared type definitions
|
|
349
|
+
├── licensing/ # Bundled community license key
|
|
210
350
|
└── test-utils/ # Test helpers (browser mocks, ZIP helpers)
|
|
211
351
|
```
|
|
212
352
|
|
|
@@ -214,9 +354,10 @@ src/
|
|
|
214
354
|
|
|
215
355
|
This framework is licensed under **Apache 2.0** — see [LICENSE](LICENSE).
|
|
216
356
|
|
|
217
|
-
> **Note:** This package depends on [gps-plus-slam-js](https://www.npmjs.com/package/gps-plus-slam-js), which is a **closed-source, proprietary** library distributed via npm under a separate license. A community license key is
|
|
357
|
+
> **Note:** This package depends on [gps-plus-slam-js](https://www.npmjs.com/package/gps-plus-slam-js), which is a **closed-source, proprietary** library distributed via npm under a separate license. A community license key is bundled with the framework for frictionless evaluation. See the core library's EULA for usage terms.
|
|
218
358
|
|
|
219
359
|
## See Also
|
|
220
360
|
|
|
221
|
-
- [gps-plus-slam-js](https://www.npmjs.com/package/gps-plus-slam-js) — Core alignment algorithms (closed-source
|
|
222
|
-
- [
|
|
361
|
+
- [gps-plus-slam-js](https://www.npmjs.com/package/gps-plus-slam-js) — Core alignment algorithms (closed-source)
|
|
362
|
+
- [`GpsPlusSlamJs_MinimalExample`](../GpsPlusSlamJs_MinimalExample/) — Smallest possible consumer of this framework
|
|
363
|
+
- [`GpsPlusSlamJs_RecorderApp`](../GpsPlusSlamJs_RecorderApp/) — Full-featured recording app built on this framework
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import L from "leaflet";
|
|
2
|
+
|
|
3
|
+
//#region ../src/visualization/accuracy-circles.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Style for per-event GPS accuracy circles. Radius comes from the GPS event's
|
|
6
|
+
* horizontal accuracy in meters; larger circles mean lower-quality fixes.
|
|
7
|
+
* Filled and stroked with a highly transparent variant of the path color so
|
|
8
|
+
* overlapping circles remain legible without obscuring the basemap or the
|
|
9
|
+
* polyline drawn on top.
|
|
10
|
+
*/
|
|
11
|
+
declare const ACCURACY_CIRCLE_FILL_OPACITY = 0.12;
|
|
12
|
+
declare const ACCURACY_CIRCLE_STROKE_OPACITY = 0.5;
|
|
13
|
+
declare const ACCURACY_CIRCLE_WEIGHT = 1;
|
|
14
|
+
/**
|
|
15
|
+
* Minimal shape required to render an accuracy circle. Intentionally narrower
|
|
16
|
+
* than `RawGpsSample` so any caller with `lat`/`lng` and an optional
|
|
17
|
+
* `accuracy` (meters) can use this helper without coupling to a specific
|
|
18
|
+
* GPS-sample type.
|
|
19
|
+
*/
|
|
20
|
+
interface AccuracyCircleSample {
|
|
21
|
+
readonly lat: number;
|
|
22
|
+
readonly lng: number;
|
|
23
|
+
readonly accuracy?: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Draw one transparent circle per sample whose `accuracy` is a finite
|
|
27
|
+
* positive number. Samples without a usable accuracy value are skipped so
|
|
28
|
+
* pre-accuracy recordings still render their polyline.
|
|
29
|
+
*
|
|
30
|
+
* Circles are added to `map` immediately. The caller is responsible for
|
|
31
|
+
* draw-order: invoke this BEFORE adding the polyline so the line stays
|
|
32
|
+
* visually on top of the circles.
|
|
33
|
+
*
|
|
34
|
+
* @param map - The Leaflet map to add circles to.
|
|
35
|
+
* @param samples - GPS samples to consider; non-positive / non-finite
|
|
36
|
+
* `accuracy` values are silently skipped.
|
|
37
|
+
* @param color - CSS color string used for both stroke and fill.
|
|
38
|
+
* @returns The created `L.Circle` instances, in the order they were added.
|
|
39
|
+
* Callers that track layers for cleanup can append these to their list.
|
|
40
|
+
*/
|
|
41
|
+
declare function addAccuracyCircles(map: L.Map, samples: readonly AccuracyCircleSample[], color: string): L.Circle[];
|
|
42
|
+
//#endregion
|
|
43
|
+
export { addAccuracyCircles as a, AccuracyCircleSample as i, ACCURACY_CIRCLE_STROKE_OPACITY as n, ACCURACY_CIRCLE_WEIGHT as r, ACCURACY_CIRCLE_FILL_OPACITY as t };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import * as _$_reduxjs_toolkit0 from "@reduxjs/toolkit";
|
|
1
|
+
import { L as CombinedRootState, r as SlamAppRootState } from "./create-slam-app-store-CNsZ3rcX.js";
|
|
3
2
|
import * as _$gps_plus_slam_js0 from "gps-plus-slam-js";
|
|
4
|
-
import { GpsPoint, LatLong, Matrix4, Quaternion,
|
|
3
|
+
import { ArImageCapture, GpsPoint, LatLong, Matrix4, Quaternion, Vector3 } from "gps-plus-slam-js";
|
|
4
|
+
import * as _$_reduxjs_toolkit0 from "@reduxjs/toolkit";
|
|
5
5
|
|
|
6
6
|
//#region ../src/state/app-selectors.d.ts
|
|
7
7
|
/** Alignment matrix (4×4), or null if not yet computed. */
|
|
8
|
-
declare const selectAlignmentMatrix: ((state:
|
|
8
|
+
declare const selectAlignmentMatrix: ((state: SlamAppRootState & {}) => Matrix4 | null) & {
|
|
9
9
|
clearCache: () => void;
|
|
10
10
|
resultsCount: () => number;
|
|
11
11
|
resetResultsCount: () => void;
|
|
@@ -27,7 +27,7 @@ declare const selectAlignmentMatrix: ((state: CombinedRootState) => Matrix4 | nu
|
|
|
27
27
|
argsMemoize: typeof _$_reduxjs_toolkit0.weakMapMemoize;
|
|
28
28
|
};
|
|
29
29
|
/** Recorded GPS positions with metadata. */
|
|
30
|
-
declare const selectGpsPositions: ((state:
|
|
30
|
+
declare const selectGpsPositions: ((state: SlamAppRootState & {}) => readonly GpsPoint[]) & {
|
|
31
31
|
clearCache: () => void;
|
|
32
32
|
resultsCount: () => number;
|
|
33
33
|
resetResultsCount: () => void;
|
|
@@ -49,7 +49,7 @@ declare const selectGpsPositions: ((state: CombinedRootState) => readonly GpsPoi
|
|
|
49
49
|
argsMemoize: typeof _$_reduxjs_toolkit0.weakMapMemoize;
|
|
50
50
|
};
|
|
51
51
|
/** Recorded odometry positions (AR-local space). */
|
|
52
|
-
declare const selectOdometryPositions: ((state:
|
|
52
|
+
declare const selectOdometryPositions: ((state: SlamAppRootState & {}) => readonly Vector3[]) & {
|
|
53
53
|
clearCache: () => void;
|
|
54
54
|
resultsCount: () => number;
|
|
55
55
|
resetResultsCount: () => void;
|
|
@@ -71,7 +71,7 @@ declare const selectOdometryPositions: ((state: CombinedRootState) => readonly V
|
|
|
71
71
|
argsMemoize: typeof _$_reduxjs_toolkit0.weakMapMemoize;
|
|
72
72
|
};
|
|
73
73
|
/** Recorded odometry rotations (AR-local space). */
|
|
74
|
-
declare const selectOdometryRotations: ((state:
|
|
74
|
+
declare const selectOdometryRotations: ((state: SlamAppRootState & {}) => readonly Quaternion[]) & {
|
|
75
75
|
clearCache: () => void;
|
|
76
76
|
resultsCount: () => number;
|
|
77
77
|
resetResultsCount: () => void;
|
|
@@ -93,7 +93,7 @@ declare const selectOdometryRotations: ((state: CombinedRootState) => readonly Q
|
|
|
93
93
|
argsMemoize: typeof _$_reduxjs_toolkit0.weakMapMemoize;
|
|
94
94
|
};
|
|
95
95
|
/** GPS zero reference (origin for coordinate conversion), or null. */
|
|
96
|
-
declare const selectZeroReference: ((state:
|
|
96
|
+
declare const selectZeroReference: ((state: SlamAppRootState & {}) => LatLong | null) & {
|
|
97
97
|
clearCache: () => void;
|
|
98
98
|
resultsCount: () => number;
|
|
99
99
|
resetResultsCount: () => void;
|
|
@@ -114,20 +114,19 @@ declare const selectZeroReference: ((state: CombinedRootState) => LatLong | null
|
|
|
114
114
|
memoize: typeof _$_reduxjs_toolkit0.weakMapMemoize;
|
|
115
115
|
argsMemoize: typeof _$_reduxjs_toolkit0.weakMapMemoize;
|
|
116
116
|
};
|
|
117
|
-
|
|
118
|
-
declare const selectReferencePoints: ((state: CombinedRootState) => readonly ReferencePoint[]) & {
|
|
117
|
+
declare const selectFrameTilesInWebXR: ((state: SlamAppRootState & {}) => readonly ArImageCapture[]) & {
|
|
119
118
|
clearCache: () => void;
|
|
120
119
|
resultsCount: () => number;
|
|
121
120
|
resetResultsCount: () => void;
|
|
122
121
|
} & {
|
|
123
|
-
resultFunc: (resultFuncArgs_0:
|
|
124
|
-
memoizedResultFunc: ((resultFuncArgs_0:
|
|
122
|
+
resultFunc: (resultFuncArgs_0: ArImageCapture[] | undefined) => readonly ArImageCapture[];
|
|
123
|
+
memoizedResultFunc: ((resultFuncArgs_0: ArImageCapture[] | undefined) => readonly ArImageCapture[]) & {
|
|
125
124
|
clearCache: () => void;
|
|
126
125
|
resultsCount: () => number;
|
|
127
126
|
resetResultsCount: () => void;
|
|
128
127
|
};
|
|
129
|
-
lastResult: () => readonly
|
|
130
|
-
dependencies: [(state: CombinedRootState) =>
|
|
128
|
+
lastResult: () => readonly ArImageCapture[];
|
|
129
|
+
dependencies: [(state: CombinedRootState) => ArImageCapture[] | undefined];
|
|
131
130
|
recomputations: () => number;
|
|
132
131
|
resetRecomputations: () => void;
|
|
133
132
|
dependencyRecomputations: () => number;
|
|
@@ -137,4 +136,4 @@ declare const selectReferencePoints: ((state: CombinedRootState) => readonly Ref
|
|
|
137
136
|
argsMemoize: typeof _$_reduxjs_toolkit0.weakMapMemoize;
|
|
138
137
|
};
|
|
139
138
|
//#endregion
|
|
140
|
-
export {
|
|
139
|
+
export { selectOdometryRotations as a, selectOdometryPositions as i, selectFrameTilesInWebXR as n, selectZeroReference as o, selectGpsPositions as r, selectAlignmentMatrix as t };
|