@mappedin/blue-dot 6.15.0-beta.0 → 6.17.0-beta.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.
@@ -1,10 +1,7 @@
1
1
  import { Coordinate, Floor, MapView, Model } from "@mappedin/mappedin-js";
2
2
 
3
- //#region ../packages/common/browser.d.ts
4
-
5
- type BrowserPermissionState = PermissionState | 'unavailable';
6
- //#endregion
7
3
  //#region ../../node_modules/.pnpm/type-fest@5.4.2/node_modules/type-fest/source/primitive.d.ts
4
+
8
5
  /**
9
6
  Matches any [primitive value](https://developer.mozilla.org/en-US/docs/Glossary/Primitive).
10
7
 
@@ -872,25 +869,6 @@ Same as `ReadonlyDeep`, but accepts only `object`s as inputs. Internal helper fo
872
869
  */
873
870
  type _ReadonlyObjectDeep<ObjectType extends object> = { readonly [KeyType in keyof ObjectType]: ReadonlyDeep<ObjectType[KeyType]> };
874
871
  //#endregion
875
- //#region ../packages/common/extensions.d.ts
876
- interface MapViewExtension<T> {
877
- enable(options?: PartialDeep<T>): void;
878
- disable(): void;
879
- get isEnabled(): boolean;
880
- destroy(): void;
881
- }
882
- //#endregion
883
- //#region src/status/types.d.ts
884
- type BlueDotStatus = 'hidden' | 'active' | 'inactive' | 'disabled';
885
- type BlueDotAction = 'timeout' | 'error' | 'position-update' | 'enable' | 'disable' | 'initialize';
886
- //#endregion
887
- //#region src/follow/types.d.ts
888
- type FollowMode = /** Camera position follows the Blue Dot's position. */
889
- 'position-only'
890
- /** Camera position follows the Blue Dot's position. Camera bearing matches the Blue Dot's heading. */ | 'position-and-heading'
891
- /** Camera position follows the Blue Dot's position. Camera bearing is calculated based on the Navigation path. */ | 'position-and-path-direction'
892
- /** Disables follow mode */ | false;
893
- //#endregion
894
872
  //#region src/sensors/types.d.ts
895
873
  /**
896
874
  * Built-in sensor IDs
@@ -1028,7 +1006,34 @@ type SensorEventPayloads = {
1028
1006
  };
1029
1007
  };
1030
1008
  //#endregion
1009
+ //#region src/fusion/anchor-state.d.ts
1010
+ /**
1011
+ * Anchor state in the fusion engine's hybrid anchor behavior model.
1012
+ *
1013
+ * - `'none'`: No anchor active; GPS measurements accepted, PDR ignored
1014
+ * - `'anchor-only'`: Anchor active and in exclusive period; GPS rejected, PDR accepted
1015
+ * - `'transition'`: Anchor active but past exclusive period; GPS accepted with increasing weight
1016
+ */
1017
+ type AnchorState = 'none' | 'anchor-only' | 'transition';
1018
+ //#endregion
1031
1019
  //#region src/fusion/types.d.ts
1020
+ type FusionEventPayloads = {
1021
+ 'fused-position': {
1022
+ position: FusedPosition;
1023
+ };
1024
+ 'heading-update': {
1025
+ heading: number;
1026
+ };
1027
+ 'anchor-set': {
1028
+ anchor: PositionAnchor;
1029
+ };
1030
+ 'anchor-expired': {
1031
+ anchor: PositionAnchor;
1032
+ };
1033
+ error: {
1034
+ error: Error | GeolocationPositionError;
1035
+ };
1036
+ };
1032
1037
  type PositionMetadata = {
1033
1038
  /** Confidence score 0-1 (0 = no confidence, 1 = 100% certain) */
1034
1039
  confidence: number;
@@ -1109,6 +1114,29 @@ interface RelativePositionUpdate {
1109
1114
  /** Confidence score 0-1 */
1110
1115
  confidence: number;
1111
1116
  }
1117
+ /**
1118
+ * Configuration for the multi-sensor EKF fusion engine.
1119
+ */
1120
+ interface FusionEngineConfig {
1121
+ /**
1122
+ * Duration in ms where anchor is exclusive (GPS rejected).
1123
+ * @default 5000 (5 seconds)
1124
+ */
1125
+ anchorOnlyPeriodMs: number;
1126
+ /**
1127
+ * Half-life for state uncertainty growth in milliseconds.
1128
+ * The state uncertainty doubles every halfLifeMs when no measurements arrive.
1129
+ * Lower values = faster decay of old position estimates.
1130
+ * @default 10000 (10 seconds)
1131
+ */
1132
+ halfLifeMs: number;
1133
+ /**
1134
+ * Maximum age of position updates to consider in milliseconds.
1135
+ * Updates older than this cause filter reset.
1136
+ * @default 5000 (5 seconds)
1137
+ */
1138
+ maxAgeMs: number;
1139
+ }
1112
1140
  /**
1113
1141
  * Position anchor from a calibration source (VPS, AI Localizer).
1114
1142
  * Anchors represent absolute ground truth positions that other sensors
@@ -1137,6 +1165,28 @@ interface PositionAnchor {
1137
1165
  confidence?: number;
1138
1166
  }
1139
1167
  //#endregion
1168
+ //#region ../packages/common/browser.d.ts
1169
+ type BrowserPermissionState = PermissionState | 'unavailable';
1170
+ //#endregion
1171
+ //#region ../packages/common/extensions.d.ts
1172
+ interface MapViewExtension<T> {
1173
+ enable(options?: PartialDeep<T>): void;
1174
+ disable(): void;
1175
+ get isEnabled(): boolean;
1176
+ destroy(): void;
1177
+ }
1178
+ //#endregion
1179
+ //#region src/status/types.d.ts
1180
+ type BlueDotStatus = 'hidden' | 'active' | 'inactive' | 'disabled';
1181
+ type BlueDotAction = 'timeout' | 'error' | 'position-update' | 'enable' | 'disable' | 'initialize';
1182
+ //#endregion
1183
+ //#region src/follow/types.d.ts
1184
+ type FollowMode = /** Camera position follows the Blue Dot's position. */
1185
+ 'position-only'
1186
+ /** Camera position follows the Blue Dot's position. Camera bearing matches the Blue Dot's heading. */ | 'position-and-heading'
1187
+ /** Camera position follows the Blue Dot's position. Camera bearing is calculated based on the Navigation path. */ | 'position-and-path-direction'
1188
+ /** Disables follow mode */ | false;
1189
+ //#endregion
1140
1190
  //#region src/types.d.ts
1141
1191
  type FollowCameraOptions = {
1142
1192
  /**
@@ -1922,6 +1972,329 @@ declare class SensorRegistry extends PubSub<SensorEventPayloads> {
1922
1972
  destroy(): void;
1923
1973
  }
1924
1974
  //#endregion
1975
+ //#region src/fusion/algorithms/types.d.ts
1976
+ /**
1977
+ * Interface for heading fusion algorithms.
1978
+ * Combines compass, gyroscope, and GPS heading for stable heading estimation.
1979
+ */
1980
+ interface HeadingFusionAlgorithm {
1981
+ /**
1982
+ * Update with compass heading (absolute but noisy).
1983
+ * @param heading Compass heading in degrees [0, 360)
1984
+ * @param timestamp Update timestamp in milliseconds
1985
+ */
1986
+ updateCompass(heading: number, timestamp: number): void;
1987
+ /**
1988
+ * Update with gyroscope angular velocity (smooth relative changes).
1989
+ * @param angularVelocity Angular velocity in deg/s around vertical axis
1990
+ * @param timestamp Update timestamp in milliseconds
1991
+ */
1992
+ updateGyro(angularVelocity: number, timestamp: number): void;
1993
+ /**
1994
+ * Correct heading with GPS ground truth when moving.
1995
+ * @param gpsHeading GPS heading in degrees [0, 360)
1996
+ * @param speed Current speed in m/s
1997
+ */
1998
+ correctWithGps(gpsHeading: number, speed: number): void;
1999
+ /**
2000
+ * Get the current fused heading.
2001
+ * @returns Fused heading in degrees [0, 360), or null if not initialized
2002
+ */
2003
+ getHeading(): number | null;
2004
+ /**
2005
+ * Reset the algorithm state.
2006
+ */
2007
+ reset(): void;
2008
+ }
2009
+ //#endregion
2010
+ //#region src/fusion/algorithms/heading-filter.d.ts
2011
+ /**
2012
+ * Configuration options for the heading fusion filter.
2013
+ */
2014
+ interface HeadingFilterConfig {
2015
+ /** Complementary filter alpha (0-1). Higher = more gyro weight. */
2016
+ complementaryAlpha: number;
2017
+ /** Minimum angular velocity to integrate (deg/s). */
2018
+ gyroNoiseThreshold: number;
2019
+ /** Maximum heading error before snapping to compass (degrees). */
2020
+ maxHeadingError: number;
2021
+ /** Enable magnetic disturbance detection. */
2022
+ magneticGatingEnabled: boolean;
2023
+ /** Minimum heading delta to emit updates (degrees). */
2024
+ deltaThreshold: number;
2025
+ }
2026
+ /**
2027
+ * Complementary filter for heading fusion.
2028
+ * Combines compass (absolute but noisy), gyroscope (smooth relative changes),
2029
+ * and GPS heading (ground truth when moving) to produce stable heading.
2030
+ *
2031
+ * The filter works by:
2032
+ * 1. Short-term: Integrate gyroscope angular velocity for smooth rotations
2033
+ * 2. Long-term: Slowly blend toward compass to prevent gyroscope drift
2034
+ * 3. Correction: When GPS heading is valid (moving fast enough), use as ground truth
2035
+ *
2036
+ * @example
2037
+ * ```ts
2038
+ * const filter = new HeadingFusionFilter();
2039
+ *
2040
+ * // Update with compass reading
2041
+ * filter.updateCompass(45, Date.now());
2042
+ *
2043
+ * // Update with gyroscope angular velocity
2044
+ * filter.updateGyro(5.0, Date.now()); // 5 deg/s rotation
2045
+ *
2046
+ * // Correct with GPS when moving
2047
+ * filter.correctWithGps(47, 1.5); // heading 47°, speed 1.5 m/s
2048
+ *
2049
+ * // Get fused heading
2050
+ * const heading = filter.getHeading(); // ~46°
2051
+ * ```
2052
+ */
2053
+ declare class HeadingFusionFilter implements HeadingFusionAlgorithm {
2054
+ #private;
2055
+ /**
2056
+ * Update the filter with a compass heading reading.
2057
+ * The compass provides absolute heading but is susceptible to magnetic interference.
2058
+ * @param heading Compass heading in degrees [0, 360)
2059
+ * @param timestamp Update timestamp in milliseconds
2060
+ */
2061
+ updateCompass(heading: number, _timestamp: number): void;
2062
+ /**
2063
+ * Update the filter with gyroscope angular velocity.
2064
+ * The gyroscope provides smooth relative heading changes immune to magnetic fields.
2065
+ * @param angularVelocity Angular velocity around vertical axis in deg/s
2066
+ * @param timestamp Update timestamp in milliseconds
2067
+ */
2068
+ updateGyro(angularVelocity: number, timestamp: number): void;
2069
+ /**
2070
+ * Correct the heading with GPS when available.
2071
+ * GPS heading is only considered when moving fast enough and with sufficient confidence.
2072
+ * @param gpsHeading GPS heading in degrees [0, 360)
2073
+ * @param speed Current speed in m/s
2074
+ * @param confidence GPS confidence (0-1), affects how much GPS heading influences result
2075
+ */
2076
+ correctWithGps(gpsHeading: number, speed: number, confidence?: number): void;
2077
+ /**
2078
+ * Configure the filter parameters at runtime.
2079
+ * @param config Partial configuration to apply
2080
+ */
2081
+ configure(config: Partial<HeadingFilterConfig>): void;
2082
+ /**
2083
+ * Get current configuration values.
2084
+ */
2085
+ getConfig(): HeadingFilterConfig;
2086
+ /**
2087
+ * Check if magnetic disturbance is currently detected.
2088
+ */
2089
+ isMagneticDisturbanceActive(): boolean;
2090
+ /**
2091
+ * Get the current fused heading.
2092
+ * @returns Fused heading in degrees [0, 360), or null if not initialized
2093
+ */
2094
+ getHeading(): number | null;
2095
+ /**
2096
+ * Check if the filter has been initialized with at least one compass reading.
2097
+ * @returns True if filter is initialized
2098
+ */
2099
+ isInitialized(): boolean;
2100
+ /**
2101
+ * Get the last compass heading received.
2102
+ * @returns Last compass heading in degrees, or null if none received
2103
+ */
2104
+ getLastCompassHeading(): number | null;
2105
+ /**
2106
+ * Reset the filter state.
2107
+ * Call on floor changes or when heading should be re-initialized.
2108
+ */
2109
+ reset(): void;
2110
+ }
2111
+ //#endregion
2112
+ //#region src/fusion/algorithms/multi-sensor-ekf.d.ts
2113
+ /**
2114
+ * Configuration options for the Multi-Sensor EKF.
2115
+ */
2116
+ interface MultiSensorEKFOptions {
2117
+ /**
2118
+ * Half-life for uncertainty growth in milliseconds.
2119
+ * The state uncertainty doubles every halfLifeMs when no measurements arrive.
2120
+ * Lower values = faster decay of old estimates.
2121
+ * @default 10000 (10 seconds)
2122
+ */
2123
+ halfLifeMs: number;
2124
+ }
2125
+ /**
2126
+ * Multi-sensor Extended Kalman Filter for position fusion.
2127
+ *
2128
+ * Combines position measurements from multiple sources (GPS, VPS, anchors) and
2129
+ * displacement measurements from PDR using a constant-velocity motion model.
2130
+ *
2131
+ * Key features:
2132
+ * - All methods take explicit timestamps (no Date.now() inside)
2133
+ * - Confidence-weighted fusion via measurement noise parameter
2134
+ * - Half-life decay of old estimates via process noise scaling
2135
+ * - Supports both absolute position and relative displacement updates
2136
+ *
2137
+ * State vector: [latitude, longitude, velocity_lat, velocity_lon]
2138
+ *
2139
+ * @example
2140
+ * ```ts
2141
+ * const ekf = new MultiSensorEKF({ halfLifeMs: 10000 });
2142
+ *
2143
+ * // Initialize with first position
2144
+ * ekf.updatePosition(43.123, -79.456, 0.0001, 0);
2145
+ *
2146
+ * // Predict forward
2147
+ * ekf.predict(1000);
2148
+ *
2149
+ * // Update with new GPS measurement (low confidence = high noise)
2150
+ * ekf.updatePosition(43.124, -79.455, 0.001, 1000);
2151
+ *
2152
+ * // Get fused position
2153
+ * const pos = ekf.getPosition(); // { latitude: ~43.1235, longitude: ~-79.4555 }
2154
+ * ```
2155
+ */
2156
+ declare class MultiSensorEKF {
2157
+ #private;
2158
+ constructor(options?: Partial<MultiSensorEKFOptions>);
2159
+ /**
2160
+ * Predict step: project state forward to the given timestamp.
2161
+ * Increases uncertainty based on elapsed time and half-life configuration.
2162
+ *
2163
+ * @param timestampMs - Current timestamp in milliseconds
2164
+ */
2165
+ predict(timestampMs: number): void;
2166
+ /**
2167
+ * Update state with a position measurement (GPS, VPS, anchor).
2168
+ *
2169
+ * @param latitude - Measured latitude in degrees
2170
+ * @param longitude - Measured longitude in degrees
2171
+ * @param measurementNoise - Measurement noise variance (higher = less trust)
2172
+ * @param timestampMs - Measurement timestamp in milliseconds
2173
+ */
2174
+ updatePosition(latitude: number, longitude: number, measurementNoise: number, timestampMs: number): void;
2175
+ /**
2176
+ * Update state with an odometry measurement (PDR displacement).
2177
+ *
2178
+ * Unlike position updates, odometry provides relative displacement rather than
2179
+ * absolute position. The displacement is added directly to the state.
2180
+ *
2181
+ * @param dx - Displacement east in meters (positive = east)
2182
+ * @param dy - Displacement north in meters (positive = north)
2183
+ * @param measurementNoise - Measurement noise variance (higher = less trust)
2184
+ * @param timestampMs - Measurement timestamp in milliseconds
2185
+ */
2186
+ updateOdometry(dx: number, dy: number, measurementNoise: number, timestampMs: number): void;
2187
+ /**
2188
+ * Get the current position estimate.
2189
+ * @returns Position or null if filter not initialized
2190
+ */
2191
+ getPosition(): {
2192
+ latitude: number;
2193
+ longitude: number;
2194
+ } | null;
2195
+ /**
2196
+ * Get the current velocity estimate.
2197
+ * @returns Velocity in degrees per second, or null if filter not initialized
2198
+ */
2199
+ getVelocity(): {
2200
+ vLat: number;
2201
+ vLon: number;
2202
+ } | null;
2203
+ /**
2204
+ * Get the current position uncertainty (trace of position covariance).
2205
+ * Higher values indicate less certainty in the position estimate.
2206
+ * @returns Uncertainty value, or Infinity if filter not initialized
2207
+ */
2208
+ getUncertainty(): number;
2209
+ /**
2210
+ * Get the last update timestamp.
2211
+ * @returns Timestamp in ms, or null if filter not initialized
2212
+ */
2213
+ getLastTimestamp(): number | null;
2214
+ /**
2215
+ * Check if the filter has been initialized with at least one measurement.
2216
+ */
2217
+ isInitialized(): boolean;
2218
+ /**
2219
+ * Reset the filter state.
2220
+ * Call on floor changes, large position jumps, or time gaps.
2221
+ */
2222
+ reset(): void;
2223
+ }
2224
+ //#endregion
2225
+ //#region src/fusion/fusion-engine.d.ts
2226
+ /**
2227
+ * Multi-sensor fusion engine that combines position updates from multiple sources.
2228
+ *
2229
+ * Uses an Extended Kalman Filter (EKF) for position fusion with:
2230
+ * - Confidence-weighted measurements (high confidence = more influence)
2231
+ * - Half-life decay of old estimates (uncertainty grows over time)
2232
+ * - Hybrid anchor behavior (anchor-only period, then transition to GPS)
2233
+ *
2234
+ * Heading fusion uses a separate complementary filter combining compass and gyroscope.
2235
+ */
2236
+ declare class FusionEngine extends PubSub<FusionEventPayloads> {
2237
+ #private;
2238
+ constructor(registry: SensorRegistry, config?: Partial<FusionEngineConfig>);
2239
+ /**
2240
+ * Get the current fusion configuration.
2241
+ */
2242
+ get config(): Readonly<FusionEngineConfig>;
2243
+ /**
2244
+ * Get the current anchor state.
2245
+ * @param nowMs - Current timestamp (defaults to Date.now())
2246
+ */
2247
+ getAnchorState(nowMs?: number): AnchorState;
2248
+ /**
2249
+ * Get the current position anchor if one is set and not expired.
2250
+ */
2251
+ get anchor(): Readonly<PositionAnchor> | undefined;
2252
+ /**
2253
+ * Get the current accumulated displacement from the anchor in meters.
2254
+ * Returns (0, 0) if no anchor is set or no movement has occurred.
2255
+ */
2256
+ get displacement(): Readonly<DisplacementVector>;
2257
+ /**
2258
+ * Set an absolute position anchor from a calibration source (VPS, AI Localizer).
2259
+ * When an anchor is active, it provides the absolute position and other sensors
2260
+ * can provide relative updates from this reference point.
2261
+ *
2262
+ * @param anchor - The position anchor to set
2263
+ * @param configOverride - Optional config overrides for this anchor (e.g., anchorOnlyPeriodMs)
2264
+ */
2265
+ setAnchor(anchor: PositionAnchor, configOverride?: Partial<Pick<FusionEngineConfig, 'anchorOnlyPeriodMs'>>): void;
2266
+ /**
2267
+ * Clear the current position anchor and accumulated displacement.
2268
+ */
2269
+ clearAnchor(): void;
2270
+ /**
2271
+ * Reset the EKF state.
2272
+ * Call on floor changes or large position jumps.
2273
+ */
2274
+ resetEKF(): void;
2275
+ /**
2276
+ * Reset the heading fusion filter state.
2277
+ * Call on floor changes or when heading should be re-initialized.
2278
+ */
2279
+ resetHeadingFilter(): void;
2280
+ /**
2281
+ * Get the heading fusion filter for configuration.
2282
+ * @internal Used by debug tools for runtime tuning.
2283
+ */
2284
+ get headingFilter(): HeadingFusionFilter;
2285
+ /**
2286
+ * Get the multi-sensor EKF for inspection.
2287
+ * @internal Used by debug tools for runtime inspection.
2288
+ */
2289
+ get ekf(): MultiSensorEKF;
2290
+ /**
2291
+ * Get the last fused position.
2292
+ * @returns The last fused position, or undefined if none available
2293
+ */
2294
+ getLastPosition(): FusedPosition | undefined;
2295
+ destroy(): void;
2296
+ }
2297
+ //#endregion
1925
2298
  //#region src/blue-dot.d.ts
1926
2299
  /**
1927
2300
  * Show a Blue Dot indicating the device's position on the map.
@@ -1954,6 +2327,21 @@ declare class BlueDot implements MapViewExtension<BlueDotState> {
1954
2327
  constructor(mapView: MapView);
1955
2328
  /** Sensors API */
1956
2329
  get Sensors(): SensorRegistry;
2330
+ /**
2331
+ * Fusion engine API.
2332
+ * @internal Used by debug tools for runtime tuning and inspection.
2333
+ */
2334
+ get Fusion(): FusionEngine;
2335
+ /**
2336
+ * Get the current position anchor if one is set and not expired.
2337
+ * Anchors provide absolute ground truth positions from calibration sources (VPS, AI Localizer).
2338
+ */
2339
+ get anchor(): Readonly<PositionAnchor> | undefined;
2340
+ /**
2341
+ * Get the current accumulated displacement from the anchor in meters.
2342
+ * Returns { dx: 0, dy: 0 } if no anchor is set or no movement has occurred.
2343
+ */
2344
+ get displacement(): Readonly<DisplacementVector>;
1957
2345
  /**
1958
2346
  * Get the Model for the BlueDot core element.
1959
2347
  */
@@ -1 +1 @@
1
- import{a as n,b as u,f}from"../chunk-O22D2X2S.js";u();u();import{useCallback as c,useState as p}from"react";import{useMap as D,useMapViewExtension as m}from"@mappedin/react-sdk";function B(){let[,t]=p({});return c(()=>t({}),[])}n(B,"useForceUpdate");function l(){let{mapView:t}=D(),o=B(),{register:r}=m("blue-dot",{onRegister:n(()=>{let e=new f(t);return e.on("position-update",o),e.on("status-change",o),e.on("follow-change",o),e.on("error",o),e},"onRegister"),onDeregister:n(e=>{e.off("position-update",o),e.off("status-change",o),e.off("follow-change",o),e.off("error",o),e.destroy()},"onDeregister")}),s=r();if(!s)throw new Error("BlueDot failed to initialize.");return s}n(l,"useBlueDot");u();import{useCallback as d,useEffect as E,useRef as g}from"react";function w(t,o){let r=l(),s=g(o);s.current=o;let e=d(i=>{s.current(i)},[]);E(()=>{if(r!=null)return r.on(t,e),()=>{r!=null&&r.off(t,e)}},[r,t,e])}n(w,"useBlueDotEvent");export{l as useBlueDot,w as useBlueDotEvent};
1
+ import{d as f}from"../chunk-BRRC7V4T.js";import{c as n,m as u}from"../chunk-UVQMTLHL.js";u();u();import{useCallback as c,useState as p}from"react";import{useMap as D,useMapViewExtension as m}from"@mappedin/react-sdk";function B(){let[,t]=p({});return c(()=>t({}),[])}n(B,"useForceUpdate");function l(){let{mapView:t}=D(),o=B(),{register:r}=m("blue-dot",{onRegister:n(()=>{let e=new f(t);return e.on("position-update",o),e.on("status-change",o),e.on("follow-change",o),e.on("error",o),e},"onRegister"),onDeregister:n(e=>{e.off("position-update",o),e.off("status-change",o),e.off("follow-change",o),e.off("error",o),e.destroy()},"onDeregister")}),s=r();if(!s)throw new Error("BlueDot failed to initialize.");return s}n(l,"useBlueDot");u();import{useCallback as d,useEffect as E,useRef as g}from"react";function w(t,o){let r=l(),s=g(o);s.current=o;let e=d(i=>{s.current(i)},[]);E(()=>{if(r!=null)return r.on(t,e),()=>{r!=null&&r.off(t,e)}},[r,t,e])}n(w,"useBlueDotEvent");export{l as useBlueDot,w as useBlueDotEvent};
@@ -7,6 +7,7 @@ import type { ReadonlyDeep } from 'type-fest';
7
7
  import { FollowMode } from './follow/types';
8
8
  import { BlueDotStatus } from './status/types';
9
9
  import { SensorRegistry } from './sensors/sensor-registry';
10
+ import { FusionEngine } from './fusion/fusion-engine';
10
11
  import type { ManualPositionOptions } from './sensors/manual/manual-sensor';
11
12
  /**
12
13
  * Show a Blue Dot indicating the device's position on the map.
@@ -39,6 +40,21 @@ export declare class BlueDot implements MapViewExtension<BlueDotState> {
39
40
  constructor(mapView: MapView);
40
41
  /** Sensors API */
41
42
  get Sensors(): SensorRegistry;
43
+ /**
44
+ * Fusion engine API.
45
+ * @internal Used by debug tools for runtime tuning and inspection.
46
+ */
47
+ get Fusion(): FusionEngine;
48
+ /**
49
+ * Get the current position anchor if one is set and not expired.
50
+ * Anchors provide absolute ground truth positions from calibration sources (VPS, AI Localizer).
51
+ */
52
+ get anchor(): Readonly<import('./fusion/types').PositionAnchor> | undefined;
53
+ /**
54
+ * Get the current accumulated displacement from the anchor in meters.
55
+ * Returns { dx: 0, dy: 0 } if no anchor is set or no movement has occurred.
56
+ */
57
+ get displacement(): Readonly<import('./fusion/types').DisplacementVector>;
42
58
  /**
43
59
  * Get the Model for the BlueDot core element.
44
60
  */