docs/map-engine.mdx
Two rendering engines are available, switchable at runtime via Settings or the VITE_MAP_INTERACTION_MODE environment variable (globe or flat). The preference is persisted in localStorage.
3D Globe (globe.gl + Three.js) — a photorealistic 3D Earth with full pitch and rotation:
earth-topo-bathy.jpg), specular water map for ocean reflections, and a starfield night-sky backgrounddebounceFlushMarkers() to prevent Three.js scene graph crashes during high-frequency data refreshpowerPreference: 'high-performance'), disable the logarithmic depth buffer (saves shader overhead), and turn off auto-rotation and camera damping to eliminate continuous render loop wakeups when idle — addressing reports of 1 fps performance on some machinesThe flat map supports multiple tile providers, selectable at runtime via Settings → Map Tile Provider. The selection persists in localStorage.
| Provider | Description | Cost | Default |
|---|---|---|---|
| OpenFreeMap | Free community-hosted OpenStreetMap tiles. Dark and Positron styles. No API key required. | Free | Yes (when VITE_PMTILES_URL is unset) |
| CARTO | CARTO's Dark Matter and Voyager GL styles. No API key required. | Free tier | No |
| PMTiles (self-hosted) | Self-hosted vector tiles via the PMTiles format. Tiles are served as a single .pmtiles archive file over HTTP Range requests — the browser only downloads tiles for the current viewport (~50-200KB per pan/zoom), not the entire file. Requires VITE_PMTILES_URL environment variable. | Self-hosted | Yes (when VITE_PMTILES_URL is set) |
| Auto | Tries PMTiles first, falls back to OpenFreeMap on error (2+ tile load failures or 10s timeout). Only available when VITE_PMTILES_URL is set. | Self-hosted | No |
OSS-friendly defaults: When VITE_PMTILES_URL is not set (the default), only OpenFreeMap and CARTO appear in Settings. PMTiles and Auto options are hidden. This ensures community installations work out of the box with zero configuration and no external tile hosting costs.
Self-hosting PMTiles: To use your own tiles:
go-pmtiles extractVITE_PMTILES_URL=https://your-server.example/planet.pmtiles in .env.localEach tile provider offers different visual themes, selectable via Settings → Map Theme. The theme selection is per-provider — switching providers remembers each provider's last-used theme. Map theme is fully independent of the app theme (Auto/Dark/Light); the app theme only affects UI chrome, while the map theme controls basemap appearance.
| Provider | Available Themes | Default |
|---|---|---|
| PMTiles | Black (deepest dark), Dark, Grayscale, Light, White | Black |
| OpenFreeMap | Dark, Positron (light) | Dark |
| CARTO | Dark Matter, Voyager (light), Positron (light) | Dark Matter |
Sprite mapping: PMTiles themes black, dark, and grayscale use the dark Protomaps sprite sheet; light and white use the light sprite sheet.
Overlay paint adaptation: Country highlight/hover paint colors automatically adapt to the selected map theme (not the app theme), using lower opacity on light themes for visibility.
Fallback behavior: When using PMTiles or Auto mode, if tile loading fails (CORS errors, server downtime, 403s), the map automatically falls back to OpenFreeMap after detecting 2+ errors within 10 seconds. The fallback respects the current map theme's light/dark nature — a light PMTiles theme falls back to OpenFreeMap Positron, not Dark. A console warning is logged when fallback activates.
Flat Map (deck.gl + MapLibre GL JS) — a WebGL-accelerated 2D map with smooth 60fps rendering and thousands of concurrent markers:
GeoJsonLayer, ScatterplotLayer, PathLayer, IconLayer, TextLayer, PolygonLayer, ArcLayer, HeatmapLayer composited in a single render passShared across both engines:
map-layer-definitions.ts) consumed by both renderers — adding a new layer is a single-file operation. Layers are variant-specific: full (29 geopolitical + military + infrastructure), tech (12 startup/cloud/cyber), finance (15 exchange/banking/trade), and happy (5 positive-events/conservation)?view=mena&zoom=4&layers=conflicts,bases)Intl.DateTimeFormat().resolvedOptions().timeZone — no network dependency, no geolocation prompt. On mobile, the browser's Geolocation API is queried (5-second timeout) and the map auto-centers on the user's precise GPS coordinates at zoom level 6. If the URL already contains shared coordinates, the shared view takes precedence and geolocation is skippedMap: prefixed commands to fly to any country or region on either engineCountry boundaries, boundary overrides, and the geocoding service are documented in Maps & Geocoding. All large static files are served from R2 CDN via maps.worldmonitor.app.