Skip to content

Architectural Decision Record: Mapping

Status: Proposed
Date: 2026-07-19
Candidates Evaluated: MapLibre GL JS, PMTiles, OpenFreeMap, OpenMobileMaps


1. Problem Owned

The application requires a GPU-accelerated map renderer capable of displaying vector tiles, overlaying domain-specific layers (streamflow gauges, flood zones, fishing access points, bathymetry), and operating 100% offline on iOS Safari and Android Chrome when the user is in remote areas of Maine with no cell signal.


2. Evaluation Summary

We evaluated four candidate tools. Three form a complete integrated stack. One was immediately disqualified.

OpenMobileMaps — Rejected immediately. OpenMobileMaps is a native C++ SDK with iOS/Android rendering backends. It cannot run in a browser or PWA. With ~214 GitHub stars and low activity, it is also not a viable upstream candidate for any part of the platform. It is removed from further consideration.

The remainder of this ADR addresses the three-tool stack: MapLibre GL JS + PMTiles + OpenFreeMap.


3. How the Three Tools Compose

┌──────────────────────────────────────────────────────────────┐
│  MapLibre GL JS (Rendering Engine)                           │
│  ↓ Requests tiles via pmtiles:// protocol                    │
├──────────────────────────────────────────────────────────────┤
│  PMTiles JS Client (Data Retrieval)                          │
│  ↓ Reads byte ranges from local file                         │
├──────────────────────────────────────────────────────────────┤
│  OPFS (Origin Private File System)                           │
│  ← maine.pmtiles file stored here (20–30 MB estimate)        │
├──────────────────────────────────────────────────────────────┤
│  OpenFreeMap Style JSON (Visual Design Layer)                │
│  ↓ Defines how vector features are rendered                  │
├──────────────────────────────────────────────────────────────┤
│  Bluefly Fishing Layers (Domain Intelligence)                │
│  ← USGS nodes, NWS flood zones, access points, bathymetry   │
└──────────────────────────────────────────────────────────────┘

4. Measured Evidence

Metric MapLibre GL JS PMTiles OpenFreeMap
License BSD-3-Clause BSD-3 / CC0 spec MIT
GitHub Stars ~11,100 ~3,000 ~5,600
Governance Linux Foundation (MapLibre Org) Protomaps (open spec) Single maintainer
Offline Capability Yes — requires SW-cached assets Yes — OPFS byte-range reads Style assets only; tiles require PMTiles
PWA / iOS Safari Yes (WebGL supported iOS 15.2+) Yes (OPFS supported iOS 15.2+) Yes
PWA / Android Chrome Yes Yes Yes
Render approach WebGL / WebGPU Protocol adapter to MapLibre Style JSON
Data independence Yes — data agnostic Yes — format only Yes — can point to any tile source
Online requirement No No Style & glyphs require local bundling

5. Upstream Ownership (Per Tool)

MapLibre GL JS owns: - GPU-accelerated tile rendering pipeline - Vector tile (MVT) parsing - Camera navigation, gesture recognition (pinch, rotate, drag) - Worker thread orchestration for tile processing - Text rendering along paths, label collision detection

PMTiles owns: - Single-file archive format for all map tiles - pmtiles:// protocol registration inside MapLibre - Byte-range fetch logic (reads only the viewport-required bytes from OPFS) - CLI tooling to compile OSM extracts → .pmtiles

OpenFreeMap owns: - Pre-built cartography style sheets (Liberty, Positron, Bright) - Font glyphs and icon sprites - Weekly OSM tile compilation and public CDN hosting (for online use)


6. Ownership Result

Capability Owner
GPU tile rendering pipeline MapLibre GL JS
Touch gesture handling MapLibre GL JS
Tile archive format & byte-range reads PMTiles
Offline tile storage (OPFS management) Bluefly
Tile download + storage quota management Bluefly
Base cartography visual design OpenFreeMap
Font glyphs and sprites (bundled locally) OpenFreeMap (bundled)
Style customization (brand colors, dark mode) Bluefly
Fishing domain overlays (USGS, NWS, access) Bluefly
Elevation / contour overlay Bluefly (USGS DEM → PMTiles)
React component lifecycle management Bluefly
PWA Service Worker cache configuration Bluefly (Serwist)

7. Remaining Bluefly Work

After adopting the full stack, Bluefly owns a clearly bounded set of implementation tasks:

  1. Local Assets Pipeline: Download OpenFreeMap style JSON, glyphs, and sprites into /public/map-assets/. Edit style JSON to reference local paths instead of CDN URLs.
  2. PWA Cache Config (Serwist): Add map asset paths to the Service Worker cache manifest so all fonts, icons, and style assets are available offline.
  3. OPFS Download Orchestration: Implement the UI to download the Maine .pmtiles archive (~20–30 MB) into OPFS, with progress indication and storage quota checks.
  4. Fishing Domain Layers: Build GeoJSON overlays for USGS streamflow gauge nodes, NWS active flood zones, and manually curated fishing access points.
  5. Elevation Overlay: Compile USGS Digital Elevation Model data for Maine into a Terrain-RGB PMTiles set for contour lines and relief shading. This addresses the known gap in OpenStreetMap's rural coverage.
  6. React Integration: Manage the imperative MapLibre instance lifecycle inside React hooks (client-side only, loaded via next/dynamic with ssr: false to prevent hydration errors).

8. Known Gaps in Upstream Data

These are gaps in the OSM-derived data that Bluefly will need to address with domain-specific curation: - Logging roads and forest access tracks — often unmapped or misclassified in OSM for rural Maine - Contour lines / elevation — not included in standard OSM vector tiles; requires a separate USGS DEM compilation - Private fishing access points — by design, never in OSM (ethical constraint)


9. Decision

Adopt: MapLibre GL JS + PMTiles + OpenFreeMap as the complete offline mapping stack. Reject: OpenMobileMaps (native SDK, incompatible with PWA architecture).

The three-tool stack is complementary by design. MapLibre owns the rendering. PMTiles owns the offline storage format. OpenFreeMap owns the base cartography. Together they eliminate every layer of custom map infrastructure. Bluefly's remaining work is limited to domain-specific overlays, OPFS orchestration, and style customization — exactly what should be owned by the domain.


10. Record Frozen

This document is an architectural decision record. The comparison phase is complete. Future mapping work — fishing overlays, elevation tiles, OPFS download UX — is tracked as implementation tasks, not revisions to this ADR.