Live NEXRAD weather radar with NWS alert overlays — bunko.me/radar
  • HTML 38.6%
  • JavaScript 37.4%
  • Python 23.3%
  • Dockerfile 0.7%
Find a file
bunko 72c5f1c046 Fix mobile OOM crash on zoom (cap live radar layers)
The loop kept all ~13 frame layers alive (background pre-warm) = ~104
tile <img>s rasterized at the device pixel ratio. On a retina phone the
pinch-zoom memory spike exceeded the tab budget and the browser
OOM-reloaded the page.

Keep only the current + next frame layer live (showFrame prunes the
rest); drop the eager 13-layer warm-preload; keepBuffer 1 +
updateWhenZooming:false. Mobile load drops from 13 layers/104 tiles to
2 layers/16 tiles and stays flat through zoom and playback. The tile
proxy cache keeps the loop smooth despite recreating layers per step.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 19:30:59 -05:00
app Fix mobile OOM crash on zoom (cap live radar layers) 2026-06-25 19:30:59 -05:00
.gitignore Add radar: live NEXRAD weather radar with NWS alert overlays 2026-06-25 16:08:08 -05:00
docker-compose.yml Scope radar to a region + IEM scan time/countdown 2026-06-25 16:41:49 -05:00
README.md Scope radar to a region + IEM scan time/countdown 2026-06-25 16:41:49 -05:00

radar

Live weather radar with NWS warning overlays — bunko.me/radar (public).

A fullscreen Leaflet map over a dark CARTO basemap with:

  • Animated radar loop from RainViewer — past frames + nowcast, with a scrubbable timeline, play/pause, speed control, and selectable color schemes.
  • IEM NEXRAD composite (Iowa Environmental Mesonet) as a keyless, higher-resolution live-frame alternate (no animation — single composite, updated every 5 min). Shows the scan's valid time + a live countdown to the next scan, and reloads when a new one lands.
  • NWS warning polygons from api.weather.gov — tornado / severe / flash flood warnings and SPC watches for the configured states, color-coded by event, clickable for details, listed in the side rail (click to fly there).

Scoped to a region (default: Oklahoma + surrounding states) — the map fits and is bounded to it, and alerts are filtered to those states.

  • Place labels rendered above the radar so city names stay readable, opacity control, geolocation, dBZ legend, and PWA install support.

Architecture

FastAPI backend (app/main.py) that caches the two upstream feeds so the browser hits a single origin:

  • GET /api/radar-frames — normalized RainViewer weather-maps.json ({host, frames:[{time, path, kind}]}), 60s TTL.
  • GET /api/rvtile/{z}/{x}/{y}?p=&c= — RainViewer tile proxy with a dedup LRU cache + throttled, backoff-on-429 upstream fetches (RainViewer rate-limits direct browser bursts). RainViewer radar is native to ~z7, so the client caps maxNativeZoom: 7 and upscales above that.
  • GET /api/alerts — NWS active alerts for NWS_AREAS, filtered to features with inline polygons, curated properties, 45s TTL, pagination-capped.
  • GET /api/iem-time — latest IEM n0q scan valid time + interval (30s TTL).
  • GET / — the map UI. GET /health, /manifest.webmanifest, /favicon.svg.

Frontend is vanilla JS + Leaflet (app/static/app.js, app/templates/index.html).

Config (env, see docker-compose.yml)

var default meaning
BASE_PATH /radar path prefix (Caddy strips it)
DEFAULT_LAT/LON/ZOOM Tulsa, z7 fallback view if no REGION_BOUNDS
REGION_BOUNDS 25.5,-109.3,41.2,-88.8 S,W,N,E the map fits + is bounded to (OK + neighbors)
NWS_AREAS OK,KS,MO,AR,TX,NM,CO states to pull NWS alerts for
SITE_NAME Tulsa, OK label in the header
NWS_USER_AGENT contact UA required by api.weather.gov

Deploy

docker compose up -d --build

Routed publicly via the shared Caddy proxy (~/apps/proxy/Caddyfile).

Data sources & credits

RainViewer, Iowa Environmental Mesonet (NEXRAD), NWS / api.weather.gov, CARTO basemaps © OpenStreetMap contributors. Not for life-safety decisions — use official NWS products.