Skip to content

Architecture Overview

Core design principles

  1. No backend — all computation (geometry, projection, protobuf encoding) runs in the browser
  2. GeoJSON as the canonical editor format — all elements are stored as GeoJSON features in WGS84; ENU conversion only happens at export time
  3. Apollo proto types as the target format — TypeScript interfaces mirror the .proto definitions exactly, making the export layer a straightforward translation
  4. Libraries for everything geometricturf.js for spatial math, proj4 for projection, protobufjs for encoding; no custom geometry code

High-level data flow

User interaction


mapbox-gl-draw
(GeoJSON Feature creation / editing)


Zustand mapStore                    ←── uiStore (draw mode, selection)
(LaneFeature, JunctionFeature, …)

      ├── real-time ──→ MapLibre GL layers
      │                 (boundaries, fills, icons, arrows)

      └── on Export ──→ buildBaseMap()

                              ├── proj4: WGS84 → ENU
                              ├── turf: length, samples, headings
                              ├── turf: overlap detection


                        apollo.hdmap.Map (JS object)

                              ├── protobufjs → base_map.bin
                              ├── buildSimMap() → protobufjs → sim_map.bin
                              └── buildRoutingMap() → protobufjs → routing_map.bin

Layer architecture

┌──────────────────────────────────────────────────────────┐
│  React components (App.tsx)                              │
│  ┌─────────────┐  ┌───────────────┐  ┌───────────────┐  │
│  │  MapEditor  │  │   Toolbar     │  │  Properties   │  │
│  │  (MapLibre) │  │   (uiStore)   │  │  (mapStore)   │  │
│  └──────┬──────┘  └───────────────┘  └───────────────┘  │
│         │                                                │
│  ┌──────▼────────────────────────────────────────────┐  │
│  │  Zustand stores                                   │  │
│  │  mapStore: lanes, junctions, signals, ...         │  │
│  │  uiStore:  drawMode, selectedIds, layerVisibility │  │
│  └──────┬────────────────────────────────────────────┘  │
│         │                                                │
│  ┌──────▼──────────────────────────────────────────┐    │
│  │  geo/  ·  proto/  ·  export/  ·  import/        │    │
│  │  (pure TypeScript utility modules)               │    │
│  └─────────────────────────────────────────────────┘    │
└──────────────────────────────────────────────────────────┘

Module responsibilities

ModuleResponsibility
src/types/TypeScript interfaces mirroring Apollo proto definitions; editor-internal GeoJSON types
src/store/mapStoreSingle source of truth for all map elements; undo/redo history
src/store/uiStoreTransient UI state (draw mode, hover, selection, layer visibility)
src/geo/projectionWGS84 ↔ ENU conversion via proj4
src/geo/laneGeometryLane boundary computation, width sampling, heading
src/geo/overlapCalcSpatial intersection detection → Overlap proto objects
src/proto/loaderDynamic .proto loading from public/proto/ via protobufjs
src/proto/codecEncode/decode apollo.hdmap.Map and apollo.routing.Graph
src/export/buildBaseMapTranslate editor state → full apollo.hdmap.Map proto object
src/export/buildSimMapDownsample a base map for Dreamview
src/export/buildRoutingMapBuild routing topology graph from lane connectivity
src/import/parseBaseMapDecode base_map.bin → restore editor GeoJSON state
src/components/MapEditorMapLibre GL map + draw controls + all rendering layers
src/components/ToolbarDraw mode selection buttons
src/components/PropertiesPanelPer-element attribute editing forms
src/components/*DialogNew project / Export / Import modal dialogs
src/components/StatusBarMode indicator, undo/redo controls

Dependency graph (simplified)

App
 ├── MapEditor
 │    ├── mapStore (read)
 │    ├── uiStore  (read + write)
 │    ├── geo/laneGeometry (boundary computation)
 │    └── maplibre-gl + @mapbox/mapbox-gl-draw

 ├── Toolbar  → uiStore (write drawMode)

 ├── PropertiesPanel → mapStore (write element)

 └── ExportDialog
      ├── mapStore (read all elements)
      ├── geo/projection
      ├── export/buildBaseMap → geo/laneGeometry, geo/overlapCalc
      ├── export/buildSimMap
      ├── export/buildRoutingMap
      └── proto/codec → proto/loader → protobufjs

Proto file strategy

Apollo .proto files are copied verbatim from the Apollo repository to public/proto/ and served as static assets. protobufjs fetches and parses them at runtime using its load() API with a custom resolvePath function that strips Apollo's deep path prefix:

ts
// proto/loader.ts
root.resolvePath = (_origin, target) => {
  const filename = target.split('/').pop()!
  return `/proto/${filename}`
}

This avoids bundling proto definitions at build time and keeps them easy to update independently.

Released under the MIT License.