Lumen/SPIKE-03-MAP-REPRESENTATION.md
Lumen Stage1 c0bfd413ff Stage 1: project foundation (strict TS, lint boundaries B-1..B-7, directory structure, CI, boundary tests)
- dedicated git repo at /home/avi/Projects/Lumen (main)
- TypeScript strict (target ES2022, bundler, exactOptionalPropertyTypes, noUncheckedIndexedAccess)
- ESLint 9 + typescript-eslint strictTypeChecked + eslint-plugin-boundaries for B-1..B-7, no-restricted-globals/syntax for B-1/B-7
- Prettier 3.5
- Structure per IMPLEMENTATION-CONTRACT.md §4 (src/platform/idb|cache|sw, storage, data, sync/{transport,verifier}, domain/{emergency,schedule,map,festival,readiness,clock,favorites}, ui/{components,views,router,render}, app, emergency-baseline, assets, public, content, pipeline, tests, scripts)
- CI: .github/workflows/ci.yml (typecheck + lint + format + test)
- Boundary tests: tests/unit/boundaries.test.ts (4 tests) + scripts/check-boundaries.ts
- No feature code, no PWA/IDB/sync/mesh/accounts per contract Stage 1
2026-08-30 23:25:35 -05:00

7.8 KiB
Raw Permalink Blame History

SPIKE-03 — Map Representation

  • Phase: Architecture Validation
  • Date: 2026-08-30
  • Decision under test: ADR-008 (raster WebP base ≤2 levels + DOM POI overlay + CSS-transform pan/zoom + Facilities list; no online tiles; no GPS).
  • Method: structured evaluation against all candidate representations; decode-memory analysis; headless synthetic benchmark (experiments/exp3-map-bench.html) with strict interpretation limits.

1. Candidates

S1 Single SVG map S2 Raster base + DOM overlay (proposed) S3 Canvas S4 Pre-cached raster tile pyramid S5 Hybrid vector-POI over raster (variant of S2)
Offline completeness Yes Yes Yes Yes Yes
Organizer workflow Needs vector art skills; illustrated maps are raster Art as-is (illustrated PNG/WebP) Same as S2 Same as S2 Same as S2
Low-end pan/zoom Degrades with path count GPU transform of 1 image — cheap, constant Full redraw per frame Tile management code Same as S2
Accessibility Awkward at scale POIs are real buttons; list view first-class Needs parallel text tree Same as S3 Same as S2
Zoom quality Infinite Bounded by 2 levels (venue-scale adequate) Same as S2 Good Same as S2
File size Art-dependent WebP excellent for illustrated art Same + overhead per tile Same
POI interaction DOM/SVG events DOM buttons (48 px targets trivial) Manual hit-testing Same as S3 Same as S2
Search / dynamic filtering Possible Trivial (data-driven markers, class toggles) Manual Manual Trivial
Dark mode Styleable Needs dimming strategy (see §4) Manual Manual Same as S2
Maintainability / update flow Re-export vector Replace image + POI sheet → new package Same as S2 Same Same
Code surface Medium Low Higher Highest Low

2. Benchmark evidence (EXP-3) and its limits

Headless desktop run (see experiments/README.md for caveats): all three mechanically viable variants (S2, S1, S3) measured ≈ 0 ms synchronous JS per animation frame at 100 and 300 POIs.

Interpretation (deliberately conservative): desktop JS cost does not discriminate the candidates. The costs that matter on low-end mobile — GPU compositing of transformed layers, texture upload of large images, decode latency, RAM pressure — are invisible to this benchmark. Therefore EXP-3 confirms only: (a) no candidate has a disqualifying JS-side cost; (b) the DOM-overlay and SVG transform mechanics work as designed. The final choice rests on memory, accessibility, workflow, and robustness reasoning below, with a mandatory device protocol in §7.

3. Memory analysis (the decisive axis on mobile)

Decoded image cost ≈ width × height × 4 bytes (RGBA):

Base image Encoded (WebP, illustrated art) Decoded in RAM
1600×1200 (overview cap) ~0.3–0.7 MB ~7.3 MB
2048×1536 ~0.5–1.2 MB ~12 MB
3072×2304 (detail cap) ~1.5–3.5 MB ~27 MB
4096×3072 (previous cap) ~2.5–6 MB ~48 MB
4096×4096 — ~64 MB

Findings:

  • F-1 (change): ARCH §15.3's "≤ 4096 px per side" cap was chosen for GPU texture limits but is insufficient as a memory constraint. On a 3–4 GB low-end Android, holding a 48–64 MB decoded bitmap alongside the app, list caches, and browser overhead is a jetsam/OOM risk. New caps: overview ≤ 1600 px longest edge; detail ≤ 3072 px longest edge; total decoded map memory ≤ ~35 MB; at most one detail-level image resident (overview is swapped out or downscaled when detail is shown). Some older GPUs cap textures at 2048 px; Chromium tiles oversized textures internally (works, at a cost) — the 3072 cap plus an overview-only fallback mode covers this.
  • F-2: WebP encoded sizes at these dimensions fit the 28 MB asset budget with margin, including per-POI icons.
  • F-3: IDs/object URLs: create object URLs lazily per visible level; revoke on level switch to free decode memory.

4. Criteria-by-criteria results for the chosen representation

  • Initial load: overview WebP (~0.5 MB) + map.json renders the usable map immediately; detail level lazy-loads on zoom-in. CONFIRMED by design.
  • Zoom/pan: single-container CSS transform; markers counter-scaled. Mechanics CONFIRMED viable by EXP-3; fps on device UNVERIFIED (§7).
  • Retina/high-density: base authored at ~2× intended display size; downscale-on-fit keeps quality. INFERRED.
  • Accessibility / screen readers: POIs are real DOM buttons with labels; Facilities list is a first-class, non-visual equivalent (not a fallback). Base image carries descriptive alt. CONFIRMED by design.
  • POI interaction: tap → detail sheet; 48 px targets. CONFIRMED by design.
  • Search: shared search component indexes POI names/categories; results highlight markers + list entries. CONFIRMED by design.
  • Dynamic filtering: category chips toggle marker visibility (data-driven, class/attribute toggles; no re-layout of the base). CONFIRMED by design.
  • Dark mode (F-4, change): festival art is typically day-illustrated. Default: CSS filter: brightness(.72) saturate(.85) on the base image in dark theme + full-brightness markers/labels (cheap, GPU-composited). Optional: organizer-supplied night-variant asset (schema hook: asset role map-base/overview-night). No white flash, no re-download required.
  • Organizer workflow: illustrated art delivered as raster + POI coordinate capture step (tap-tool over the image in pipeline tooling, or surveyed normalized coordinates). Map update = new package version; no app change. INFERRED — needs confirmation with real art (OQ-6, AQ-19).
  • Offline use: all bytes local; no tile service, no GPS. CONFIRMED.

5. When the decision would flip

  • Organizers supply vector art (SVG) of good quality → reconsider S1/S5 (crisp zoom, smaller files) — SPIKE verdict remains valid either way because POI overlay + list view are representation-agnostic.
  • Real art exceeds 3072 px requirement for legibility → tile-split the detail level (2×2), still local; bounded extra complexity (DD-9).
  • Device protocol (§7) shows transform jank on the low-end Android target → fallback: overview-only mode + reduced marker count; canvas remains the escape hatch but is not preemptively adopted.

6. Cross-checks with other decisions

  • ADR-004: assets as Blobs in the slot DB — consistent; object-URL lifecycle managed by MapService (F-3).
  • SPIKE-05: map missing ⇒ PARTIAL with list still available if POI data present — consistent.
  • ADR-012: POI optional lat/lng hook preserved; no GPS in V1 — consistent.

7. Mandatory physical-device protocol (before production)

On the low-end Android target and an iPhone:

  1. Pan/zoom sustained 10 s at 60 Hz intent with 200 POIs → observe fps/frame drops (target ≥ 30 fps).
  2. Detail-level first zoom-in: decode latency and memory peak (performance.memory on Chrome; Instruments on iOS).
  3. Overview→detail→overview cycling: no leaked object URLs/memory growth.
  4. Dark-mode filter visual quality + performance cost.
  5. Screen-reader pass over POI markers and Facilities list (TalkBack, VoiceOver).
  6. Older-GPU device (2048 texture cap) with a 3072 px detail image: renders correctly via Chromium tiling; measure cost; exercise overview-only fallback.

8. Verdict

ACCEPT WITH CHANGES.

Representation stands: raster WebP base (≤2 levels) + DOM POI overlay + CSS-transform pan/zoom + first-class Facilities list, no tiles, no GPS. Changes (to ADR-008): image dimension/memory caps tightened (F-1), object-URL lifecycle rule (F-3), dark-mode treatment (F-4), night-variant asset hook. Condition: device protocol §7 must pass before the map is declared production-ready; fallbacks are predefined.