gps-plus-slam-app-framework 1.0.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 (200) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +222 -0
  3. package/dist/alignment-lerper-D9BeDwZX.d.ts +29 -0
  4. package/dist/app-selectors-DyMzxCEC.d.ts +140 -0
  5. package/dist/ar/camera-blit-capture.d.ts +2 -0
  6. package/dist/ar/camera-blit-capture.js +253 -0
  7. package/dist/ar/capture-failure-tracker.d.ts +2 -0
  8. package/dist/ar/capture-failure-tracker.js +45 -0
  9. package/dist/ar/chromium-camera-access-workaround.d.ts +2 -0
  10. package/dist/ar/chromium-camera-access-workaround.js +32 -0
  11. package/dist/ar/depth-sampler.d.ts +3 -0
  12. package/dist/ar/depth-sampler.js +147 -0
  13. package/dist/ar/image-capture.d.ts +2 -0
  14. package/dist/ar/image-capture.js +152 -0
  15. package/dist/ar/index.d.ts +12 -0
  16. package/dist/ar/index.js +12 -0
  17. package/dist/ar/replay-scene.d.ts +2 -0
  18. package/dist/ar/replay-scene.js +325 -0
  19. package/dist/ar/scene-node-names.d.ts +2 -0
  20. package/dist/ar/scene-node-names.js +16 -0
  21. package/dist/ar/tracking-state.d.ts +2 -0
  22. package/dist/ar/tracking-state.js +164 -0
  23. package/dist/ar/webxr-session.d.ts +4 -0
  24. package/dist/ar/webxr-session.js +890 -0
  25. package/dist/ar/xr-camera-texture.d.ts +2 -0
  26. package/dist/ar/xr-camera-texture.js +39 -0
  27. package/dist/ar/xr-error-handler.d.ts +2 -0
  28. package/dist/ar/xr-error-handler.js +37 -0
  29. package/dist/ar-types-B-ORgk6Z.d.ts +82 -0
  30. package/dist/camera-blit-capture-DHuyrrxr.d.ts +108 -0
  31. package/dist/camera-follower-BMqPddxx.d.ts +29 -0
  32. package/dist/capture-failure-tracker-2Q6oI2uQ.d.ts +52 -0
  33. package/dist/chromium-camera-access-workaround-CU5zSKNr.d.ts +61 -0
  34. package/dist/community-license-key-ChZLCJyO.d.ts +21 -0
  35. package/dist/concurrency-p6gB30fT.d.ts +24 -0
  36. package/dist/css3d-renderer-manager-rgLMVAvd.d.ts +23 -0
  37. package/dist/depth-sampler-BNCtnEoP.d.ts +108 -0
  38. package/dist/failure-tracker-1sQ_Cgyw.d.ts +49 -0
  39. package/dist/file-system-BsQgYCU3.d.ts +128 -0
  40. package/dist/file-system-utils-5cWO8Xyv.d.ts +24 -0
  41. package/dist/format-file-size-onGq0k1Q.d.ts +24 -0
  42. package/dist/fused-path-DtqCSqJh.d.ts +25 -0
  43. package/dist/geo-types-Xx-LVcnw.d.ts +29 -0
  44. package/dist/gps-Ddzr2KlX.d.ts +54 -0
  45. package/dist/gps-compass-cubes-C-6JEnpR.d.ts +22 -0
  46. package/dist/gps-error-handler-VPuNOuf8.d.ts +40 -0
  47. package/dist/gps-event-markers-DpEy2qRd.d.ts +67 -0
  48. package/dist/h3-ref-point-CFhayNSZ.d.ts +59 -0
  49. package/dist/image-capture-2pKjYUS6.d.ts +130 -0
  50. package/dist/index.d.ts +56 -0
  51. package/dist/index.js +61 -0
  52. package/dist/leaflet-map-overlay-CvfQXTye.d.ts +114 -0
  53. package/dist/lerp-utils-87NWjUOD.d.ts +20 -0
  54. package/dist/licensing/community-license-key.d.ts +2 -0
  55. package/dist/licensing/community-license-key.js +21 -0
  56. package/dist/licensing/index.d.ts +2 -0
  57. package/dist/licensing/index.js +2 -0
  58. package/dist/list-formatter-DKQQVLcl.d.ts +14 -0
  59. package/dist/logger-B81iwxx0.d.ts +74 -0
  60. package/dist/map-overlay-DuiZuCTx.d.ts +153 -0
  61. package/dist/null-storage-backend-CsWvQwN8.d.ts +11 -0
  62. package/dist/opfs-storage-ChOzF_Wp.d.ts +181 -0
  63. package/dist/opfs-storage-backend-CVcmfJHN.d.ts +11 -0
  64. package/dist/permission-checker-jO2ziCWC.d.ts +146 -0
  65. package/dist/persistence-middleware-DrptY02i.d.ts +31 -0
  66. package/dist/recorder-slice-fcwAXrsh.d.ts +35 -0
  67. package/dist/recording-coordinator-DzflP07_.d.ts +81 -0
  68. package/dist/recording-options-BYUFX8iU.d.ts +166 -0
  69. package/dist/recording-replayer-oOzPITrd.d.ts +32 -0
  70. package/dist/ref-point-importer-B_wn5ABk.d.ts +62 -0
  71. package/dist/ref-point-loader-Pt1smgHS.d.ts +117 -0
  72. package/dist/ref-points/h3-ref-point.d.ts +2 -0
  73. package/dist/ref-points/h3-ref-point.js +74 -0
  74. package/dist/ref-points/index.d.ts +2 -0
  75. package/dist/ref-points/index.js +2 -0
  76. package/dist/ref-points-slice-tC-Wd6XJ.d.ts +48 -0
  77. package/dist/reference-points-CFWy8_wj.d.ts +68 -0
  78. package/dist/replay-engine-DuX316ae.d.ts +103 -0
  79. package/dist/replay-scene-DtUm6bsr.d.ts +109 -0
  80. package/dist/routing-slice-BlHTM8eh.d.ts +23 -0
  81. package/dist/scene-node-names-DPsaE2z3.d.ts +14 -0
  82. package/dist/sensors/gps-error-handler.d.ts +2 -0
  83. package/dist/sensors/gps-error-handler.js +53 -0
  84. package/dist/sensors/gps.d.ts +2 -0
  85. package/dist/sensors/gps.js +93 -0
  86. package/dist/sensors/index.d.ts +4 -0
  87. package/dist/sensors/index.js +4 -0
  88. package/dist/sensors/permission-checker.d.ts +2 -0
  89. package/dist/sensors/permission-checker.js +397 -0
  90. package/dist/state/app-selectors.d.ts +2 -0
  91. package/dist/state/app-selectors.js +35 -0
  92. package/dist/state/index.d.ts +17 -0
  93. package/dist/state/index.js +13 -0
  94. package/dist/state/persistence-middleware.d.ts +2 -0
  95. package/dist/state/persistence-middleware.js +71 -0
  96. package/dist/state/recorder-slice.d.ts +2 -0
  97. package/dist/state/recorder-slice.js +47 -0
  98. package/dist/state/recording-coordinator.d.ts +2 -0
  99. package/dist/state/recording-coordinator.js +150 -0
  100. package/dist/state/recording-options.d.ts +2 -0
  101. package/dist/state/recording-options.js +192 -0
  102. package/dist/state/recording-replayer.d.ts +2 -0
  103. package/dist/state/recording-replayer.js +39 -0
  104. package/dist/state/ref-points-slice.d.ts +2 -0
  105. package/dist/state/ref-points-slice.js +44 -0
  106. package/dist/state/replay-engine.d.ts +2 -0
  107. package/dist/state/replay-engine.js +230 -0
  108. package/dist/state/routing-slice.d.ts +2 -0
  109. package/dist/state/routing-slice.js +13 -0
  110. package/dist/state/store-subscribers.d.ts +3 -0
  111. package/dist/state/store-subscribers.js +97 -0
  112. package/dist/state/store.d.ts +9 -0
  113. package/dist/state/store.js +71 -0
  114. package/dist/state/subscribe-to-selector.d.ts +2 -0
  115. package/dist/state/subscribe-to-selector.js +26 -0
  116. package/dist/storage/file-system-utils.d.ts +2 -0
  117. package/dist/storage/file-system-utils.js +31 -0
  118. package/dist/storage/file-system.d.ts +2 -0
  119. package/dist/storage/file-system.js +229 -0
  120. package/dist/storage/index.d.ts +11 -0
  121. package/dist/storage/index.js +10 -0
  122. package/dist/storage/null-storage-backend.d.ts +2 -0
  123. package/dist/storage/null-storage-backend.js +8 -0
  124. package/dist/storage/opfs-storage-backend.d.ts +2 -0
  125. package/dist/storage/opfs-storage-backend.js +15 -0
  126. package/dist/storage/opfs-storage.d.ts +2 -0
  127. package/dist/storage/opfs-storage.js +242 -0
  128. package/dist/storage/ref-point-importer.d.ts +2 -0
  129. package/dist/storage/ref-point-importer.js +163 -0
  130. package/dist/storage/ref-point-loader.d.ts +2 -0
  131. package/dist/storage/ref-point-loader.js +248 -0
  132. package/dist/storage/ref-point-recovery.d.ts +28 -0
  133. package/dist/storage/ref-point-recovery.js +159 -0
  134. package/dist/storage/storage-backend.d.ts +2 -0
  135. package/dist/storage/storage-backend.js +1 -0
  136. package/dist/storage/zip-export.d.ts +2 -0
  137. package/dist/storage/zip-export.js +214 -0
  138. package/dist/storage/zip-reader.d.ts +2 -0
  139. package/dist/storage/zip-reader.js +190 -0
  140. package/dist/storage-backend-BcEItnFr.d.ts +20 -0
  141. package/dist/store-C7PKOj8S.d.ts +96 -0
  142. package/dist/store-subscribers-CuoIzB5T.d.ts +77 -0
  143. package/dist/subscribe-to-selector-UTZ0KkAc.d.ts +26 -0
  144. package/dist/test-utils/browser-mocks.d.ts +294 -0
  145. package/dist/test-utils/browser-mocks.js +568 -0
  146. package/dist/test-utils/zip-round-trip-helpers.d.ts +60 -0
  147. package/dist/test-utils/zip-round-trip-helpers.js +207 -0
  148. package/dist/three-dispose-CCBHjE_a.d.ts +30 -0
  149. package/dist/tracking-state-B9QfuZCg.d.ts +101 -0
  150. package/dist/types/ar-types.d.ts +2 -0
  151. package/dist/types/ar-types.js +1 -0
  152. package/dist/types/geo-types.d.ts +2 -0
  153. package/dist/types/geo-types.js +1 -0
  154. package/dist/types/index.d.ts +3 -0
  155. package/dist/types/index.js +1 -0
  156. package/dist/utils/concurrency.d.ts +2 -0
  157. package/dist/utils/concurrency.js +40 -0
  158. package/dist/utils/failure-tracker.d.ts +2 -0
  159. package/dist/utils/failure-tracker.js +48 -0
  160. package/dist/utils/format-file-size.d.ts +2 -0
  161. package/dist/utils/format-file-size.js +41 -0
  162. package/dist/utils/fused-path.d.ts +2 -0
  163. package/dist/utils/fused-path.js +44 -0
  164. package/dist/utils/index.d.ts +7 -0
  165. package/dist/utils/index.js +7 -0
  166. package/dist/utils/list-formatter.d.ts +2 -0
  167. package/dist/utils/list-formatter.js +17 -0
  168. package/dist/utils/logger.d.ts +2 -0
  169. package/dist/utils/logger.js +226 -0
  170. package/dist/vis-colors-Qi2vlRGt.d.ts +63 -0
  171. package/dist/visualization/alignment-lerper.d.ts +2 -0
  172. package/dist/visualization/alignment-lerper.js +68 -0
  173. package/dist/visualization/camera-follower.d.ts +2 -0
  174. package/dist/visualization/camera-follower.js +51 -0
  175. package/dist/visualization/css3d-renderer-manager.d.ts +2 -0
  176. package/dist/visualization/css3d-renderer-manager.js +41 -0
  177. package/dist/visualization/gps-compass-cubes.d.ts +2 -0
  178. package/dist/visualization/gps-compass-cubes.js +129 -0
  179. package/dist/visualization/gps-event-markers.d.ts +2 -0
  180. package/dist/visualization/gps-event-markers.js +159 -0
  181. package/dist/visualization/index.d.ts +12 -0
  182. package/dist/visualization/index.js +12 -0
  183. package/dist/visualization/leaflet-map-overlay.d.ts +2 -0
  184. package/dist/visualization/leaflet-map-overlay.js +313 -0
  185. package/dist/visualization/lerp-utils.d.ts +2 -0
  186. package/dist/visualization/lerp-utils.js +22 -0
  187. package/dist/visualization/map-overlay.d.ts +2 -0
  188. package/dist/visualization/map-overlay.js +241 -0
  189. package/dist/visualization/reference-points.d.ts +2 -0
  190. package/dist/visualization/reference-points.js +160 -0
  191. package/dist/visualization/three-dispose.d.ts +2 -0
  192. package/dist/visualization/three-dispose.js +55 -0
  193. package/dist/visualization/vis-colors.d.ts +2 -0
  194. package/dist/visualization/vis-colors.js +74 -0
  195. package/dist/webxr-session-COlSrXdL.d.ts +316 -0
  196. package/dist/xr-camera-texture-BbukNE79.d.ts +53 -0
  197. package/dist/xr-error-handler-DTHfmvrl.d.ts +24 -0
  198. package/dist/zip-export-Rtpi75JJ.d.ts +87 -0
  199. package/dist/zip-reader-D7pkpX8K.d.ts +97 -0
  200. package/package.json +104 -0
@@ -0,0 +1,226 @@
1
+ import * as Sentry from "@sentry/browser";
2
+ //#region ../src/utils/logger.ts
3
+ /**
4
+ * Configurable Logger Utility
5
+ *
6
+ * Provides a simple logging API with configurable log levels.
7
+ * This allows disabling verbose logging in production while keeping
8
+ * it available for development and debugging.
9
+ *
10
+ * Also maintains an in-memory ring buffer of recent log entries
11
+ * for display in the expandable log panel UI.
12
+ *
13
+ * Sentry Integration:
14
+ * - All log levels add Sentry breadcrumbs for debugging context
15
+ * - log.error() with Error objects automatically reports to Sentry
16
+ */
17
+ /**
18
+ * Log levels in order of verbosity (lower = more verbose)
19
+ */
20
+ let LogLevel = /* @__PURE__ */ function(LogLevel) {
21
+ LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG";
22
+ LogLevel[LogLevel["INFO"] = 1] = "INFO";
23
+ LogLevel[LogLevel["WARN"] = 2] = "WARN";
24
+ LogLevel[LogLevel["ERROR"] = 3] = "ERROR";
25
+ LogLevel[LogLevel["SILENT"] = 4] = "SILENT";
26
+ return LogLevel;
27
+ }({});
28
+ /**
29
+ * Global log level - controls what gets logged across all loggers
30
+ */
31
+ let globalLogLevel = 0;
32
+ /**
33
+ * Maximum number of log entries to keep in the ring buffer
34
+ */
35
+ const LOG_BUFFER_MAX_SIZE = 100;
36
+ /**
37
+ * In-memory ring buffer of recent log entries
38
+ */
39
+ let logBuffer = [];
40
+ let subscribers = [];
41
+ /**
42
+ * Serialize an Error instance to an object capturing name, message, stack,
43
+ * and any enumerable properties.
44
+ */
45
+ function serializeError(error) {
46
+ const result = {
47
+ name: error.name,
48
+ message: error.message,
49
+ stack: error.stack
50
+ };
51
+ for (const key of Object.keys(error)) result[key] = error[key];
52
+ return result;
53
+ }
54
+ /**
55
+ * Safely stringify an object, handling circular references.
56
+ * Uses a WeakSet to track seen objects and replaces cycles with a placeholder.
57
+ */
58
+ function safeStringify(value) {
59
+ const seen = /* @__PURE__ */ new WeakSet();
60
+ const replacer = (_key, val) => {
61
+ if (typeof val === "bigint") return val.toString();
62
+ if (val !== null && typeof val === "object") {
63
+ if (seen.has(val)) return "[Circular]";
64
+ seen.add(val);
65
+ }
66
+ return val;
67
+ };
68
+ try {
69
+ return JSON.stringify(value, replacer);
70
+ } catch {
71
+ return "[Unserializable]";
72
+ }
73
+ }
74
+ /**
75
+ * Serialize a single argument to a string for the log buffer.
76
+ * Special-cases Error instances and handles circular/complex objects safely.
77
+ */
78
+ function serializeArg(arg) {
79
+ if (arg === null) return "null";
80
+ if (arg === void 0) return "undefined";
81
+ if (typeof arg === "string") return arg;
82
+ if (typeof arg === "number" || typeof arg === "boolean") return String(arg);
83
+ if (typeof arg === "bigint") return arg.toString();
84
+ if (typeof arg === "symbol") return arg.toString();
85
+ if (typeof arg === "function") return arg.name ? `[Function: ${arg.name}]` : "[Function]";
86
+ if (arg instanceof Error) return safeStringify(serializeError(arg));
87
+ return safeStringify(arg);
88
+ }
89
+ /**
90
+ * Add an entry to the log buffer and notify subscribers
91
+ */
92
+ function addToBuffer(level, tag, args) {
93
+ const message = args.map((arg) => serializeArg(arg)).join(" ");
94
+ const entry = {
95
+ timestamp: Date.now(),
96
+ level,
97
+ tag,
98
+ message
99
+ };
100
+ logBuffer.push(entry);
101
+ if (logBuffer.length > LOG_BUFFER_MAX_SIZE) logBuffer.shift();
102
+ for (const subscriber of subscribers) try {
103
+ subscriber(entry);
104
+ } catch (err) {
105
+ console.error("[Logger] Subscriber threw an error:", err);
106
+ }
107
+ }
108
+ /**
109
+ * Get a copy of the current log buffer
110
+ * @returns Array of log entries (copy to prevent external mutation)
111
+ */
112
+ function getLogBuffer() {
113
+ return [...logBuffer];
114
+ }
115
+ /**
116
+ * Clear all entries from the log buffer
117
+ */
118
+ function clearLogBuffer() {
119
+ logBuffer = [];
120
+ }
121
+ /**
122
+ * Subscribe to new log entries
123
+ * @param callback - Function called when a new log entry is added
124
+ * @returns Unsubscribe function
125
+ */
126
+ function subscribeToLogs(callback) {
127
+ subscribers.push(callback);
128
+ return () => {
129
+ subscribers = subscribers.filter((sub) => sub !== callback);
130
+ };
131
+ }
132
+ /**
133
+ * Set the global log level
134
+ * @param level - The minimum level to log
135
+ */
136
+ function setGlobalLogLevel(level) {
137
+ globalLogLevel = level;
138
+ }
139
+ /**
140
+ * Get the current global log level
141
+ */
142
+ function getGlobalLogLevel() {
143
+ return globalLogLevel;
144
+ }
145
+ /**
146
+ * Create a logger with a specific tag prefix
147
+ * @param tag - The tag to prefix all log messages with (e.g., 'GPS', 'Storage')
148
+ * @returns A logger object with debug, info, warn, error methods
149
+ *
150
+ * @example
151
+ * ```typescript
152
+ * const log = createLogger('GPS');
153
+ * log.info('Watch started'); // [GPS] Watch started
154
+ * log.error('Error:', err); // [GPS] Error: <error details>
155
+ * ```
156
+ */
157
+ /**
158
+ * Map LogLevel to Sentry breadcrumb severity.
159
+ * Sentry uses 'warning' (not 'warn') for the warning level.
160
+ */
161
+ function toSentryLevel(level) {
162
+ switch (level) {
163
+ case 0: return "debug";
164
+ case 1: return "info";
165
+ case 2: return "warning";
166
+ case 3: return "error";
167
+ default: return "info";
168
+ }
169
+ }
170
+ /**
171
+ * Add a Sentry breadcrumb for debugging context.
172
+ * Breadcrumbs are attached to future exceptions, helping trace what happened before an error.
173
+ */
174
+ function addSentryBreadcrumb(level, tag, args) {
175
+ const message = `[${tag}] ${args.map((arg) => serializeArg(arg)).join(" ")}`;
176
+ Sentry.addBreadcrumb({
177
+ category: "log",
178
+ level: toSentryLevel(level),
179
+ message
180
+ });
181
+ }
182
+ /**
183
+ * Report a warning to Sentry as a standalone message.
184
+ * Called for log.warn() so warnings are independently visible in the
185
+ * Sentry dashboard, not only as breadcrumbs attached to later exceptions.
186
+ */
187
+ function reportWarningToSentry(tag, args) {
188
+ const message = `[${tag}] ${args.map((arg) => serializeArg(arg)).join(" ")}`;
189
+ Sentry.captureMessage(message, "warning");
190
+ }
191
+ /**
192
+ * Report Error objects to Sentry.
193
+ * Only called for log.error() - other levels just add breadcrumbs.
194
+ */
195
+ function reportErrorsToSentry(args) {
196
+ for (const arg of args) if (arg instanceof Error) Sentry.captureException(arg);
197
+ }
198
+ function createLogger(tag) {
199
+ const prefix = `[${tag}]`;
200
+ return {
201
+ debug: (...args) => {
202
+ addToBuffer(0, tag, args);
203
+ addSentryBreadcrumb(0, tag, args);
204
+ if (globalLogLevel <= 0) console.log(prefix, ...args);
205
+ },
206
+ info: (...args) => {
207
+ addToBuffer(1, tag, args);
208
+ addSentryBreadcrumb(1, tag, args);
209
+ if (globalLogLevel <= 1) console.log(prefix, ...args);
210
+ },
211
+ warn: (...args) => {
212
+ addToBuffer(2, tag, args);
213
+ addSentryBreadcrumb(2, tag, args);
214
+ reportWarningToSentry(tag, args);
215
+ if (globalLogLevel <= 2) console.warn(prefix, ...args);
216
+ },
217
+ error: (...args) => {
218
+ addToBuffer(3, tag, args);
219
+ addSentryBreadcrumb(3, tag, args);
220
+ reportErrorsToSentry(args);
221
+ if (globalLogLevel <= 3) console.error(prefix, ...args);
222
+ }
223
+ };
224
+ }
225
+ //#endregion
226
+ export { LogLevel, clearLogBuffer, createLogger, getGlobalLogLevel, getLogBuffer, setGlobalLogLevel, subscribeToLogs };
@@ -0,0 +1,63 @@
1
+ //#region ../src/visualization/vis-colors.d.ts
2
+ /**
3
+ * Centralized Visualization Color Palette
4
+ *
5
+ * Single source of truth for all semantic colors used across the app's
6
+ * visualization layers (Three.js 3D scene and Leaflet 2D summary map).
7
+ *
8
+ * Each entry provides both hex (number, for Three.js) and css (string,
9
+ * for Leaflet/CSS) formats. Some entries intentionally use different 3D/2D
10
+ * shades — see inline comments.
11
+ *
12
+ * Tailwind classes in index.html (e.g., bg-yellow-400) cannot be dynamically
13
+ * generated and must be kept in sync manually — search for "vis-colors" in
14
+ * the HTML legend to find them.
15
+ */
16
+ declare const VIS_COLORS: {
17
+ /** Raw GPS marker — yellow */readonly RAW_GPS: {
18
+ readonly hex: 16776960;
19
+ readonly css: "#ffff00";
20
+ }; /** Fused VIO marker — cyan */
21
+ readonly FUSED_VIO: {
22
+ readonly hex: 65535;
23
+ readonly css: "#00ffff";
24
+ }; /** Alignment snapshot marker — red */
25
+ readonly ALIGNMENT_SNAPSHOT: {
26
+ readonly hex: 16711680;
27
+ readonly css: "#ff0000";
28
+ }; /** Prior reference point — green */
29
+ readonly PRIOR_REF_POINT: {
30
+ readonly hex: 65280;
31
+ readonly css: "#00ff00";
32
+ }; /** Current reference point — bright red in 3D, lighter red (#ff6b6b) in 2D for map visibility */
33
+ readonly CURRENT_REF_POINT: {
34
+ readonly hex: 16711680;
35
+ readonly css: "#ff6b6b";
36
+ }; /** Compass north indicator — red */
37
+ readonly COMPASS_NORTH: {
38
+ readonly hex: 16711680;
39
+ readonly css: "#ff0000";
40
+ }; /** Compass east indicator — blue */
41
+ readonly COMPASS_EAST: {
42
+ readonly hex: 255;
43
+ readonly css: "#0000ff";
44
+ }; /** Compass south indicator — dark red */
45
+ readonly COMPASS_SOUTH: {
46
+ readonly hex: 8930372;
47
+ readonly css: "#884444";
48
+ }; /** Compass west indicator — dark blue */
49
+ readonly COMPASS_WEST: {
50
+ readonly hex: 4473992;
51
+ readonly css: "#444488";
52
+ }; /** Compass up indicator — green */
53
+ readonly COMPASS_UP: {
54
+ readonly hex: 65280;
55
+ readonly css: "#00ff00";
56
+ }; /** User GPS position marker — blue */
57
+ readonly USER_POSITION: {
58
+ readonly hex: 3900150;
59
+ readonly css: "#3b82f6";
60
+ };
61
+ };
62
+ //#endregion
63
+ export { VIS_COLORS as t };
@@ -0,0 +1,2 @@
1
+ import { n as createAlignmentLerper, t as AlignmentLerper } from "../alignment-lerper-D9BeDwZX.js";
2
+ export { AlignmentLerper, createAlignmentLerper };
@@ -0,0 +1,68 @@
1
+ import { clampedAlpha } from "./lerp-utils.js";
2
+ import * as THREE from "three";
3
+ //#region ../src/visualization/alignment-lerper.ts
4
+ /**
5
+ * Alignment Lerper Module
6
+ *
7
+ * Smoothly interpolates arWorldGroup.matrix toward a target alignment
8
+ * matrix each frame, eliminating visual jumps when the alignment solver
9
+ * produces a new alignment (~1 Hz).
10
+ *
11
+ * Pattern: decompose → lerp position / slerp quaternion → compose.
12
+ * Same lerpRate convention as camera-follower.ts (default 8 → ~90%
13
+ * convergence in ~0.3 s at 60 fps).
14
+ *
15
+ * The first target is applied instantly (no animation from identity).
16
+ *
17
+ * @see docs/2026-03-21-user-feedback.md Issue 4
18
+ */
19
+ const _currentPos = new THREE.Vector3();
20
+ const _currentQuat = new THREE.Quaternion();
21
+ const _currentScale = new THREE.Vector3();
22
+ new THREE.Vector3();
23
+ new THREE.Quaternion();
24
+ new THREE.Vector3();
25
+ /**
26
+ * Create an AlignmentLerper that drives arWorldGroup.matrix smoothly.
27
+ *
28
+ * @param arWorldGroup The group whose matrix is interpolated.
29
+ * @param lerpRate Lerp speed multiplier (default 8).
30
+ */
31
+ function createAlignmentLerper(arWorldGroup, lerpRate = 8) {
32
+ let hasTarget = false;
33
+ let isFirstTarget = true;
34
+ const storedTargetPos = new THREE.Vector3();
35
+ const storedTargetQuat = new THREE.Quaternion();
36
+ const storedTargetScale = new THREE.Vector3(1, 1, 1);
37
+ const _matrix = new THREE.Matrix4();
38
+ return {
39
+ setTarget(matrix) {
40
+ _matrix.fromArray(matrix);
41
+ _matrix.decompose(storedTargetPos, storedTargetQuat, storedTargetScale);
42
+ hasTarget = true;
43
+ },
44
+ update(dt) {
45
+ if (!hasTarget) return;
46
+ if (isFirstTarget) {
47
+ _matrix.compose(storedTargetPos, storedTargetQuat, storedTargetScale);
48
+ arWorldGroup.matrix.copy(_matrix);
49
+ arWorldGroup.matrixAutoUpdate = false;
50
+ arWorldGroup.updateMatrixWorld(true);
51
+ isFirstTarget = false;
52
+ return;
53
+ }
54
+ arWorldGroup.matrix.decompose(_currentPos, _currentQuat, _currentScale);
55
+ const alpha = clampedAlpha(lerpRate, dt);
56
+ _currentPos.lerp(storedTargetPos, alpha);
57
+ _currentQuat.slerp(storedTargetQuat, alpha);
58
+ _currentScale.lerp(storedTargetScale, alpha);
59
+ _matrix.compose(_currentPos, _currentQuat, _currentScale);
60
+ arWorldGroup.matrix.copy(_matrix);
61
+ arWorldGroup.matrixAutoUpdate = false;
62
+ arWorldGroup.updateMatrixWorld(true);
63
+ },
64
+ dispose() {}
65
+ };
66
+ }
67
+ //#endregion
68
+ export { createAlignmentLerper };
@@ -0,0 +1,2 @@
1
+ import { n as createCameraFollower, t as CameraFollower } from "../camera-follower-BMqPddxx.js";
2
+ export { CameraFollower, createCameraFollower };
@@ -0,0 +1,51 @@
1
+ import { SCENE_NODE } from "../ar/scene-node-names.js";
2
+ import { clampedAlpha } from "./lerp-utils.js";
3
+ import * as THREE from "three";
4
+ //#region ../src/visualization/camera-follower.ts
5
+ /**
6
+ * Camera Follower Module
7
+ *
8
+ * Creates an Object3D that tracks the camera's world position
9
+ * every frame via lerp, while keeping its own rotation at identity
10
+ * (GPS-world-aligned).
11
+ *
12
+ * The follower is placed at the scene root (outside arWorldGroup)
13
+ * so its world rotation stays identity regardless of the alignment
14
+ * matrix applied to arWorldGroup. This ensures compass cubes and
15
+ * the map mesh point to true N/E/S/W in the NUE GPS frame.
16
+ *
17
+ * Children of the follower (map mesh, compass cubes) stay
18
+ * flat / world-oriented regardless of camera rotation or
19
+ * orbit / FPS controls.
20
+ *
21
+ * @see docs/2026-03-12-user-feedback.md Issue 8
22
+ */
23
+ const _worldPos = new THREE.Vector3();
24
+ /**
25
+ * Create a CameraFollower and attach it as a child of the given parent.
26
+ *
27
+ * The parent should be the scene root (not arWorldGroup) so that the
28
+ * follower's world rotation stays identity — ensuring compass directions
29
+ * align with the NUE GPS frame regardless of alignment matrix changes.
30
+ *
31
+ * @param parent Parent node — should be the scene root.
32
+ * @param lerpRate Lerp speed multiplier (default 8).
33
+ */
34
+ function createCameraFollower(parent, lerpRate = 8) {
35
+ const node = new THREE.Object3D();
36
+ node.name = SCENE_NODE.CAMERA_FOLLOWER;
37
+ parent.add(node);
38
+ return {
39
+ object3D: node,
40
+ update(camera, dt) {
41
+ camera.getWorldPosition(_worldPos);
42
+ const alpha = clampedAlpha(lerpRate, dt);
43
+ node.position.lerp(_worldPos, alpha);
44
+ },
45
+ dispose() {
46
+ if (node.parent) node.parent.remove(node);
47
+ }
48
+ };
49
+ }
50
+ //#endregion
51
+ export { createCameraFollower };
@@ -0,0 +1,2 @@
1
+ import { n as createCss3dRendererManager, t as Css3dRendererManager } from "../css3d-renderer-manager-rgLMVAvd.js";
2
+ export { Css3dRendererManager, createCss3dRendererManager };
@@ -0,0 +1,41 @@
1
+ import { CSS3DRenderer } from "three/addons/renderers/CSS3DRenderer.js";
2
+ //#region ../src/visualization/css3d-renderer-manager.ts
3
+ /**
4
+ * Create and configure a CSS3DRenderer overlay for the given container.
5
+ *
6
+ * The CSS3D layer is positioned absolutely over the container with
7
+ * `pointer-events: none` so it does not intercept clicks intended
8
+ * for the WebGL canvas underneath.
9
+ *
10
+ * **Requirement:** The `container` element must have `position: relative`,
11
+ * `absolute`, `fixed`, or `sticky`. If the container is `position: static`
12
+ * (the CSS default), the overlay will float to the nearest positioned
13
+ * ancestor instead of aligning with the container.
14
+ */
15
+ function createCss3dRendererManager(container, width, height) {
16
+ const cssRenderer = new CSS3DRenderer();
17
+ cssRenderer.setSize(width, height);
18
+ const el = cssRenderer.domElement;
19
+ el.style.position = "absolute";
20
+ el.style.top = "0px";
21
+ el.style.left = "0px";
22
+ el.style.pointerEvents = "none";
23
+ container.appendChild(el);
24
+ let disposed = false;
25
+ return {
26
+ render(scene, camera) {
27
+ if (disposed) return;
28
+ cssRenderer.render(scene, camera);
29
+ },
30
+ setSize(w, h) {
31
+ cssRenderer.setSize(w, h);
32
+ },
33
+ dispose() {
34
+ if (disposed) return;
35
+ disposed = true;
36
+ if (el.parentElement) el.parentElement.removeChild(el);
37
+ }
38
+ };
39
+ }
40
+ //#endregion
41
+ export { createCss3dRendererManager };
@@ -0,0 +1,2 @@
1
+ import { i as createGpsCompassCubes, n as COMPASS_CUBE_SIZE, r as GpsCompassCubes, t as COMPASS_CUBE_DISTANCE } from "../gps-compass-cubes-C-6JEnpR.js";
2
+ export { COMPASS_CUBE_DISTANCE, COMPASS_CUBE_SIZE, GpsCompassCubes, createGpsCompassCubes };
@@ -0,0 +1,129 @@
1
+ import { disposeObject3D } from "./three-dispose.js";
2
+ import { VIS_COLORS } from "./vis-colors.js";
3
+ import * as THREE from "three";
4
+ //#region ../src/visualization/gps-compass-cubes.ts
5
+ /**
6
+ * GPS Compass Cubes Module
7
+ *
8
+ * Creates colored cubes at ±1 m along each axis with text labels
9
+ * (N, E, S, W) to visualize GPS/NUE orientation in the 3D scene.
10
+ *
11
+ * NUE convention: X = North, Y = Up, Z = East.
12
+ *
13
+ * Designed to be added as children of a CameraFollower so they
14
+ * stay near the camera but always GPS-world-aligned.
15
+ *
16
+ * @see docs/2026-03-12-user-feedback.md Issue 8
17
+ */
18
+ /** Side length of each compass cube in metres. */
19
+ const COMPASS_CUBE_SIZE = .1;
20
+ /** Distance from origin to each compass cube in metres. */
21
+ const COMPASS_CUBE_DISTANCE = 1;
22
+ const CUBE_SPECS = [
23
+ {
24
+ name: "compass-north",
25
+ color: VIS_COLORS.COMPASS_NORTH.hex,
26
+ position: [
27
+ 1,
28
+ 0,
29
+ 0
30
+ ],
31
+ label: "N"
32
+ },
33
+ {
34
+ name: "compass-east",
35
+ color: VIS_COLORS.COMPASS_EAST.hex,
36
+ position: [
37
+ 0,
38
+ 0,
39
+ 1
40
+ ],
41
+ label: "E"
42
+ },
43
+ {
44
+ name: "compass-south",
45
+ color: VIS_COLORS.COMPASS_SOUTH.hex,
46
+ position: [
47
+ -1,
48
+ 0,
49
+ 0
50
+ ],
51
+ label: "S"
52
+ },
53
+ {
54
+ name: "compass-west",
55
+ color: VIS_COLORS.COMPASS_WEST.hex,
56
+ position: [
57
+ 0,
58
+ 0,
59
+ -1
60
+ ],
61
+ label: "W"
62
+ },
63
+ {
64
+ name: "compass-up",
65
+ color: VIS_COLORS.COMPASS_UP.hex,
66
+ position: [
67
+ 0,
68
+ 1,
69
+ 0
70
+ ]
71
+ }
72
+ ];
73
+ /**
74
+ * Create a text sprite from a canvas texture.
75
+ * Uses a 64×64 canvas with centered white text on transparent background.
76
+ */
77
+ function createTextSprite(text) {
78
+ const canvas = document.createElement("canvas");
79
+ canvas.width = 64;
80
+ canvas.height = 64;
81
+ const ctx = canvas.getContext("2d");
82
+ if (ctx) {
83
+ ctx.clearRect(0, 0, 64, 64);
84
+ ctx.fillStyle = "#ffffff";
85
+ ctx.font = "bold 48px sans-serif";
86
+ ctx.textAlign = "center";
87
+ ctx.textBaseline = "middle";
88
+ ctx.fillText(text, 32, 32);
89
+ }
90
+ const texture = new THREE.CanvasTexture(canvas);
91
+ const material = new THREE.SpriteMaterial({
92
+ map: texture,
93
+ depthTest: false
94
+ });
95
+ const sprite = new THREE.Sprite(material);
96
+ sprite.name = `label-${text}`;
97
+ sprite.position.set(0, COMPASS_CUBE_SIZE * 1.5, 0);
98
+ sprite.scale.set(.4, .4, .4);
99
+ return sprite;
100
+ }
101
+ /**
102
+ * Create compass cubes and attach them to a parent Object3D.
103
+ *
104
+ * @param parent The Object3D to anchor the compass group to
105
+ * (typically the CameraFollower).
106
+ */
107
+ function createGpsCompassCubes(parent) {
108
+ const group = new THREE.Group();
109
+ group.name = "gps-compass-cubes";
110
+ const geometry = new THREE.BoxGeometry(COMPASS_CUBE_SIZE, COMPASS_CUBE_SIZE, COMPASS_CUBE_SIZE);
111
+ for (const spec of CUBE_SPECS) {
112
+ const material = new THREE.MeshBasicMaterial({ color: spec.color });
113
+ const mesh = new THREE.Mesh(geometry, material);
114
+ mesh.name = spec.name;
115
+ mesh.position.set(...spec.position);
116
+ if (spec.label) mesh.add(createTextSprite(spec.label));
117
+ group.add(mesh);
118
+ }
119
+ parent.add(group);
120
+ return {
121
+ group,
122
+ dispose() {
123
+ if (group.parent) group.parent.remove(group);
124
+ disposeObject3D(group);
125
+ }
126
+ };
127
+ }
128
+ //#endregion
129
+ export { COMPASS_CUBE_DISTANCE, COMPASS_CUBE_SIZE, createGpsCompassCubes };
@@ -0,0 +1,2 @@
1
+ import { n as gpsEventVisualizer, t as GpsEventVisualizer } from "../gps-event-markers-DpEy2qRd.js";
2
+ export { GpsEventVisualizer, gpsEventVisualizer };