Skip to content

Phase 5: GPX Export — Hardware Compatibility Specification ​

Status: Implementation Complete Author: CPO/Architect directive, implemented by MAP-EXPERT Epic: Waypoints & Cue Sheets

Context ​

Everything we built (auto-reversals, emoji symbols, orphaned states, smart snapping) lives inside the React sandbox. The moment the user presses [ Download GPX ], we must squeeze this "cosmos" into a file format invented in 2002, readable by dumb bike computers (Garmin Edge, Wahoo ELEMNT, iGPSport, Lezyne).

If a developer naively dumps our smart Cues "as-is," users will curse us — the navigator will hang, won't beep, or flood the screen with garbage.


Rule 1: The Blue Flag Curse (Symbol Mapping) ​

Problem: Our cues use Unicode emoji (âš ī¸, âŦ…ī¸, 💧). In GPX they export as <wpt> with <sym>. But bike computer firmware only recognizes specific text tags. Unknown tags → Garmin renders a giant ugly blue flag/pin covering the map.

Solution: The export function uses the gpxSym field from CUE_SYMBOLS dictionary to map internal symbols to hardware-compatible <sym> values:

Internal SymbolGPX <sym> TagDevice Behavior
Danger<sym>Danger</sym>âš ī¸ Warning triangle
Left<sym>Left</sym>← Turn arrow
Right<sym>Right</sym>→ Turn arrow
Drinking Water<sym>Drinking Water</sym>💧 Water icon
Food<sym>Food</sym>🍴 Restaurant icon
Summit<sym>Summit</sym>â›°ī¸ Peak marker
Information<sym>Information</sym>â„šī¸ Info point

IMPORTANT

CUE_SYMBOLS[symbol].gpxSym is the single source of truth. All export paths MUST use it, never raw emoji strings.


Rule 2: Silent Cues (Coordinate Precision) ​

Problem: In GPX, <wpt> waypoints are programmatically unlinked from <trk> track lines. The navigator just sees a line and a point "somewhere nearby." If a cue is 2m off the track, a Wahoo/Garmin may decide it's on a different road and won't beep when the rider approaches.

Solution: Force Snap at Export Time

When generating GPX, the exporter finds the nearest <trkpt> coordinate on the track geometry for each cue and replaces its lat/lng with the exact track point coordinates. The cue and track point must match pixel-to-pixel in the file.

Cue original: [27.5634, 53.9012]
Nearest trkpt: [27.5635, 53.9013]
Exported <wpt>: lat="53.9013" lon="27.5635"  ← SNAPPED!

Rule 3: Hardware Text Limits (Sanitization) ​

Problem: Our web UI is omnivorous, but handlebar hardware is not.

Solution:

  1. Truncation: <name> text in cue <wpt> MUST be truncated to 20 characters (CUE_TEXT_MAX_LENGTH). Longer text breaks old device UIs.

  2. Emoji Stripping: The exporter runs text through a regex that removes all Unicode emoji. Cheap Chinese bike computer XML parsers may hang on emoji bytes.

typescript
const EMOJI_REGEX = /[\u{1F600}-\u{1F64F}\u{1F300}-\u{1F5FF}\u{1F680}-\u{1F6FF}\u{1F1E0}-\u{1F1FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}\u{FE00}-\u{FE0F}\u{1F900}-\u{1F9FF}\u{200D}\u{20E3}\u{E0020}-\u{E007F}]/gu

Rule 4: Skeleton & Orphan Filter ​

Problem: Internal control points and orphaned cues must not leak into exported files.

Solution:

  1. Control Points (waypoints array) are IGNORED. Only the heavy <trk> geometry (the generated blue line) is exported. The skeleton is internal-only state.

  2. Orphaned Cues (orphaned: true) are EXCLUDED. If a cue drifted away from the route and the user didn't snap it back, it must not confuse the navigator.


Export Pipeline Summary ​

User clicks [Download GPX]
    │
    â–ŧ
1. <trk> — Export route geometry (with <ele> tags for ClimbPro/Summit)
   └── IGNORE control_points (waypoints array)
   └── Apply Smart Thinning (RDP) per quality setting
    │
    â–ŧ
2. <wpt> — Export POIs (user-created points of interest)
   └── EXCLUDE type='generatedAnchor'
    │
    â–ŧ
3. <wpt> — Export Cues (navigation annotations)
   └── EXCLUDE orphaned cues (orphaned === true)
   └── SNAP coordinates to nearest <trkpt>
   └── MAP symbol via CUE_SYMBOLS[sym].gpxSym
   └── SANITIZE text: strip emoji, truncate to 20 chars
   └── Emit <sym> tag for bike computer alerts

Future: TCX Export (Backlog) ​

GPX is universal. But for pro athletes, .TCX (Training Center XML) has a native <CoursePoint> block designed by Garmin specifically for roadbooks and turn-by-turn navigation. Cues exported as TCX work 10x more reliably on sport watches and bike computers than GPX waypoints.

TIP

TCX export is a natural Phase 6 extension. The same sanitization and snapping rules apply.