# Phase 0: Architecture Documentation **Date:** 2026-07-27 **Status:** Complete **Deliverable:** Architecture documentation for Makepad map codebase --- ## Executive Summary The Makepad map codebase is a **vector tile renderer** built on the Makepad UI framework. It consists of **14,182 lines of Rust code** across **20+ modules** with a complex architecture that mixes rendering, networking, caching, and data processing concerns. **Key Architectural Issues:** - God objects (NigigMapView with 20+ fields) - Circular dependencies between modules - Massive files (geometry.rs: 1968 lines, style_json.rs: 3242 lines) - Unclear module boundaries - Mixed responsibilities in single modules --- ## 1. High-Level Architecture ### 1.1 System Overview ``` ┌─────────────────────────────────────────────────────────────┐ │ NigigMapView Widget │ │ (view.rs - 1075 lines - GOD OBJECT) │ │ - UI event handling │ │ - State management │ │ - Rendering coordination │ │ - Network requests │ │ - Cache management │ └─────────────────────────────────────────────────────────────┘ │ ┌───────────────────┼───────────────────┐ │ │ │ ▼ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ ViewportState │ │ TileCache │ │ TileScheduler │ │ (viewport.rs) │ │ (cache.rs) │ │ (scheduler.rs) │ │ - Camera state │ │ - LRU cache │ │ - Request mgmt │ │ - Zoom/pan │ │ - Eviction │ │ - Retry logic │ │ - Transforms │ │ - State mgmt │ │ - HTTP client │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ │ └───────────────────┼───────────────────┘ │ ▼ ┌───────────────────────────────┐ │ Rendering Pipeline │ │ - Geometry tessellation │ │ - Label placement │ │ - Style application │ │ - Draw call generation │ └───────────────────────────────┘ │ ┌───────────────────┼───────────────────┐ │ │ │ ▼ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ geometry │ │ label │ │ style │ │ (1968 lines) │ │ (1098 lines) │ │ (496 lines) │ │ - Projections │ │ - Extraction │ │ - Compilation │ │ - Tessellation │ │ - Placement │ │ - Theme mgmt │ │ - Transforms │ │ - Collision │ │ - JSON parse │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ ▼ ┌───────────────────────────────┐ │ Data Processing │ │ - MVT parsing │ │ - Overpass parsing │ │ - Tile decoding │ └───────────────────────────────┘ │ ┌───────────────────┼───────────────────┐ │ │ │ ▼ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ mvt_parser │ │ overpass_parser │ │ tile_decode │ │ (701 lines) │ │ (282 lines) │ │ (361 lines) │ │ - Protobuf │ │ - JSON parse │ │ - Orchestrate │ │ - Geometry │ │ - Transform │ │ - Dispatch │ │ - Validation │ │ - Validate │ │ - Merge │ └─────────────────┘ └─────────────────┘ └─────────────────┘ ``` ### 1.2 Component Responsibilities | Component | File | Lines | Responsibility | Issues | |-----------|------|-------|----------------|--------| | **NigigMapView** | view.rs | 1075 | Main widget, orchestrates everything | **GOD OBJECT** - too many responsibilities | | **ViewportState** | viewport.rs | 538 | Camera state, zoom/pan, coordinate transforms | Reasonable separation | | **TileCache** | cache.rs | 716 | LRU cache, eviction, state management | Good separation, but large | | **TileScheduler** | scheduler.rs | 849 | Request management, retry logic, HTTP | Mixed concerns (networking + scheduling) | | **geometry** | geometry.rs | 1968 | Projections, tessellation, transforms | **MASSIVE** - should be split | | **label** | label.rs | 1098 | Label extraction, placement, collision | Mixed concerns (extraction + placement) | | **style** | style.rs | 496 | Style compilation, theme management | Reasonable | | **style_json** | style_json.rs | 3242 | JSON parsing, validation, compilation | **MASSIVE** - should be split | | **mvt_parser** | mvt_parser.rs | 701 | MVT protobuf parsing | Good separation | | **overpass_parser** | overpass_parser.rs | 282 | Overpass JSON parsing | Good separation | | **tile_decode** | tile_decode.rs | 361 | Orchestrate parsing, dispatch | Thin wrapper | | **renderer** | renderer.rs | 255 | Render graph execution | Reasonable | | **render_graph** | render_graph.rs | 418 | Pass management, execution order | Good separation | | **sprite** | sprite.rs | 433 | Sprite atlas, texture management | Reasonable | | **tile_disk** | tile_disk.rs | 204 | Disk I/O, file management | Good separation | | **tile** | tile.rs | 303 | Tile types, coordinate math | Good separation | | **asset_loader** | asset_loader.rs | 124 | Asset loading, caching | Reasonable | | **tessellation** | tessellation.rs | 595 | Geometry tessellation | Good separation | | **label_state** | label_state.rs | 487 | Label state management | Good separation | --- ## 2. Module Dependency Graph ### 2.1 Dependency Matrix ``` view viewport cache scheduler geometry label style mvt overpass tile_decode renderer render_graph sprite tile_disk tile asset_loader tessellation label_state view.rs - ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ viewport.rs ✗ - ✗ ✗ ✓ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✓ ✗ ✗ ✗ cache.rs ✗ ✗ - ✗ ✓ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✓ ✗ ✗ ✗ scheduler.rs ✗ ✓ ✓ - ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✓ ✗ ✗ ✗ geometry.rs ✗ ✗ ✗ ✗ - ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ label.rs ✗ ✗ ✗ ✗ ✓ - ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✓ ✗ ✗ ✗ style.rs ✗ ✗ ✗ ✗ ✓ ✗ - ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ mvt_parser.rs ✗ ✗ ✗ ✗ ✓ ✓ ✗ - ✗ ✗ ✗ ✗ ✗ ✗ ✓ ✗ ✗ ✗ overpass_parser.rs ✗ ✗ ✗ ✗ ✓ ✓ ✗ ✗ - ✗ ✗ ✗ ✗ ✗ ✓ ✗ ✗ ✗ tile_decode.rs ✗ ✗ ✗ ✗ ✓ ✓ ✓ ✓ ✓ - ✗ ✗ ✗ ✗ ✓ ✗ ✗ ✗ renderer.rs ✗ ✗ ✓ ✗ ✓ ✓ ✓ ✗ ✗ ✗ - ✓ ✗ ✗ ✓ ✗ ✓ ✓ render_graph.rs ✗ ✗ ✓ ✗ ✓ ✓ ✓ ✗ ✗ ✗ ✓ - ✗ ✗ ✓ ✗ ✓ ✓ sprite.rs ✗ ✗ ✗ ✗ ✓ ✗ ✗ ✗ ✗ ✗ ✗ ✗ - ✗ ✓ ✗ ✗ ✗ tile_disk.rs ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ - ✓ ✗ ✗ ✗ tile.rs ✗ ✗ ✗ ✗ ✓ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ - ✗ ✗ ✗ asset_loader.rs ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✓ - ✗ ✗ tessellation.rs ✗ ✗ ✗ ✗ ✓ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✓ ✗ - ✗ label_state.rs ✗ ✗ ✗ ✗ ✓ ✓ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✗ ✓ ✗ ✗ - ``` **Legend:** - ✓ = depends on (imports from) - ✗ = no dependency ### 2.2 Circular Dependencies **CRITICAL ISSUE:** The codebase has **circular dependencies** that make it hard to understand, test, and refactor. #### Circular Dependency 1: view.rs ↔ cache.rs ``` view.rs (NigigMapView) ↓ uses cache.rs (TileCache) ↓ uses tile.rs (TileEntry, TileLoadState) ↓ uses geometry.rs (TileKey, Geometry) ↓ used by view.rs (via DrawMapVector, rendering) ``` **Impact:** Cannot test cache.rs independently of view.rs. #### Circular Dependency 2: scheduler.rs ↔ cache.rs ``` scheduler.rs (TileScheduler) ↓ uses cache.rs (TileCache) ↓ uses tile.rs (TileLoadState) ↓ defines TileAction enum ↓ used by scheduler.rs (schedule() returns Vec) ``` **Impact:** Cannot test scheduler.rs independently of cache.rs. #### Circular Dependency 3: renderer.rs ↔ render_graph.rs ``` renderer.rs (Renderer) ↓ uses render_graph.rs (RenderGraph, RenderPass) ↓ uses cache.rs (TileCache) ↓ used by renderer.rs (via RenderContext) ``` **Impact:** Cannot test renderer.rs independently of render_graph.rs. ### 2.3 Dependency Depth Analysis **Maximum dependency depth:** 7 levels ``` view.rs (level 0) ↓ viewport.rs (level 1) ↓ geometry.rs (level 2) ↓ tile.rs (level 3) ↓ cache.rs (level 4) ↓ scheduler.rs (level 5) ↓ tile_decode.rs (level 6) ↓ mvt_parser.rs (level 7) ``` **Problem:** Deep dependency chains make the codebase hard to understand and test. **Recommendation:** Flatten dependency graph to maximum 3 levels. --- ## 3. Data Flow Diagrams ### 3.1 Tile Loading Data Flow ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ TILE LOADING FLOW │ └─────────────────────────────────────────────────────────────────────────────┘ User Action (pan/zoom) │ ▼ ┌─────────────────┐ │ NigigMapView │ │ handle_event() │ │ - Update │ │ viewport │ │ - Request │ │ redraw │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ NigigMapView │ │ draw_walk() │ │ - Calculate │ │ visible │ │ tiles │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ TileScheduler │ │ schedule() │ │ - Check cache │ │ - Generate │ │ TileActions │ └────────┬────────┘ │ ├─────────────────────────────────────┐ │ │ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ │ LoadLocalBatch │ │ LoadFromNetwork │ │ - Read from │ │ - HTTP GET │ │ mbtiles │ │ - Parse JSON │ └────────┬────────┘ └────────┬────────┘ │ │ └────────────────┬────────────────────┘ │ ▼ ┌───────────────────────┐ │ tile_decode.rs │ │ build_tile_buffers() │ │ - Dispatch to │ │ mvt_parser or │ │ overpass_parser │ └───────────┬───────────┘ │ ┌───────────┴───────────┐ │ │ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ │ mvt_parser │ │ overpass_parser │ │ - Parse MVT │ │ - Parse JSON │ │ - Extract │ │ - Transform │ │ geometry │ │ to tiles │ └────────┬────────┘ └────────┬────────┘ │ │ └───────────┬───────────┘ │ ▼ ┌───────────────────────┐ │ TileBuffers │ │ - fill_vertices │ │ - stroke_vertices │ │ - labels │ │ - pois │ └───────────┬───────────┘ │ ▼ ┌───────────────────────┐ │ TileCache │ │ insert_ready() │ │ - Create Geometry │ │ - Store in cache │ │ - Update state │ └───────────┬───────────┘ │ ▼ ┌───────────────────────┐ │ NigigMapView │ │ draw_walk() │ │ - Fetch from cache │ │ - Render geometry │ └───────────────────────┘ ``` ### 3.2 Rendering Pipeline Data Flow ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ RENDERING PIPELINE FLOW │ └─────────────────────────────────────────────────────────────────────────────┘ ┌─────────────────┐ │ NigigMapView │ │ draw_walk() │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ ViewportState │ │ - Calculate │ │ view_zoom │ │ - Calculate │ │ map_offset │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ TileCache │ │ - Fetch │ │ visible │ │ tiles │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ RenderScratch │ │ - Build draw │ │ tile list │ │ - Sort by │ │ z-order │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ RenderContext │ │ - Prepare │ │ rendering │ │ state │ └────────┬────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ RenderGraph.execute() │ │ Execute passes in z-order: │ │ 1. Background pass │ │ 2. Fill pass (polygons) │ │ 3. Stroke pass (lines) │ │ 4. POI pass (markers) │ │ 5. Label pass (text) │ └────────┬────────────────────────────────────────────────────┘ │ ├─────────────┬─────────────┬─────────────┬─────────────┐ │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Background │ │ Fill │ │ Stroke │ │ POI │ │ Label │ │ Pass │ │ Pass │ │ Pass │ │ Pass │ │ Pass │ │ │ │ │ │ │ │ │ │ │ │ - Draw bg │ │ - Draw │ │ - Draw │ │ - Draw │ │ - Place │ │ color │ │ polygons │ │ lines │ │ markers │ │ labels │ │ │ │ - Apply │ │ - Apply │ │ - Apply │ │ - Collision │ │ │ │ fill │ │ stroke │ │ sprites │ │ detection │ │ │ │ styles │ │ styles │ │ │ │ - Draw text │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ │ │ └─────────────┴─────────────┴─────────────┴─────────────┘ │ ▼ ┌───────────────────────┐ │ Makepad Draw Calls │ │ - GPU rendering │ │ - Framebuffer │ └───────────────────────┘ ``` ### 3.3 Label Placement Data Flow ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ LABEL PLACEMENT FLOW │ └─────────────────────────────────────────────────────────────────────────────┘ ┌─────────────────┐ │ TileBuffers │ │ - labels: │ │ Vec