screentinker/Examples/PIP-Weather-Radar/README.md
screentinker 89cbcac2cd
Some checks are pending
CI / Unit tests (node --test) (push) Waiting to run
CI / OpenAPI spec lint (push) Waiting to run
CI / Android unit tests (Kotlin schedule evaluator vectors) (push) Waiting to run
CI / Boot smoke + version check (push) Waiting to run
Add PIP-Weather-Radar example (TV-style live radar overlay) (#133)
* Add PIP-Weather-Radar example (TV-style live radar overlay)

A "cut to radar" PiP recipe: a Leaflet map (vendored locally for the
CSP) with a CARTO dark basemap, an animated RainViewer radar loop, and
live NWS warning polygons drawn and color-coded (tornado/severe-tstorm/
flash-flood/flood) with a pulsing "LIVE RADAR" HUD, count chips, and a
legend. Auto-frames the view to the active warning polygon(s).

Two modes: "always" (radar always up) and "on_warning" (default) which
shows the radar only while a qualifying warning covers the configured
point and clears it when the warnings expire — like a station breaking
in during severe weather.

100% keyless / open data: RainViewer radar, CARTO/OSM basemap, NWS
alerts. Zero Node deps; Leaflet is vendored client-side via
vendor-leaflet.sh (gitignored). Offline test covers the warning gate,
color map, RainViewer tile-URL builder, and overlay-URI round-trip.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(radar): note Leaflet is vendored locally, not committed

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 21:05:19 -05:00

5.2 KiB
Raw Permalink Blame History

PIP-Weather-Radar

A TV-news-style live weather radar PiP overlay for ScreenTinker — a dark county map with animated precipitation radar and live NWS warning polygons drawn on top (tornado = red, severe thunderstorm = yellow, flash flood = teal, flood = green), exactly like a local station's radar.

Its headline trick is mode: "on_warning": it watches the National Weather Service and only "cuts to radar" when a qualifying warning actually covers your area — then it clears itself when the warnings expire or drop. (Or run mode: "always" to keep the radar up permanently, e.g. for an ops/EOC wall.)

 radar.js (Node)                          radar-overlay.html (player iframe)
 ──────────────                           ─────────────────────────────────
 poll NWS for warnings   ── show/clear ─▶  CARTO dark basemap
 at your point                             + animated RainViewer radar loop
 (mode on_warning)                         + live NWS warning polygons + HUD

Everything is keyless and has zero Node dependencies. Map rendering uses Leaflet (MIT), vendored locally.

Data sources & attribution

The overlay shows attribution on-map; please keep it. Sources:

  • Basemap: © OpenStreetMap contributors, © CARTO
  • Radar: RainViewer public weather-maps API
  • Warnings/alerts: US National Weather Service / NOAA (api.weather.gov)

⚠️ Disclaimer: this is an informational visualization, not an official warning system. Radar and alert data can be delayed or incomplete. Do not rely on it for life-safety decisions — follow official NWS alerts and local emergency guidance.

Why it works (CSP)

The overlay is served from your signage server, whose CSP is script-src 'self' — so the map library is vendored (loaded same-origin), not from a CDN. The same CSP allows img-src https: and connect-src https:, so the overlay can pull tiles and fetch() the radar + alert JSON directly (both send Access-Control-Allow-Origin: *). No server change needed.

Files

File Purpose
radar.js Poller/pusher: decides when to show/clear the radar PiP; exports pure helpers
radar-overlay.html / radar-overlay.js The map overlay (served same-origin, external JS per CSP)
vendor-leaflet.sh Downloads leaflet.js + leaflet.css into this dir
config.example.json Copy to config.json and fill in
test.js Offline unit test (npm test)

Setup

Note: Leaflet is not committed to this repo (it's third-party, BSD-2-licensed). The script below downloads it locally — run it once before deploying. Nothing else to install.

  1. Vendor Leaflet (downloads leaflet.js + leaflet.css into this dir):
    ./vendor-leaflet.sh
    
  2. Copy the overlay + Leaflet into your signage server's frontend dir (so they're served same-origin as the player):
    cp radar-overlay.html radar-overlay.js leaflet.js leaflet.css /path/to/screentinker/frontend/
    
  3. Configure:
    cp config.example.json config.json
    # edit: api_base, api_token (st_ token with 'full' scope), overlay_base_url
    #       (https://<server>/radar-overlay.html), device_id, and your area:
    #       area_label, lat, lon, zoom, states (for the alert query), events
    
  4. Run:
    npm start            # or: node radar.js
    

Local quick-start (self-signed dev server)

./vendor-leaflet.sh
cp radar-overlay.html radar-overlay.js leaflet.js leaflet.css ../../frontend/
cp config.example.json config.json
# set in config.json:
#   api_base="https://localhost:3443/"
#   api_token="<your st_ full-scope token>"
#   overlay_base_url="https://localhost:3443/radar-overlay.html"
#   device_id="<your device or group id>"
NODE_TLS_REJECT_UNAUTHORIZED=0 node radar.js

Config

Key Default Notes
mode "on_warning" "on_warning" = show only during qualifying warnings; "always" = always on
lat, lon Map center and the NWS ?point= used to detect warnings
zoom 8 Leaflet zoom; ~8 ≈ a county/metro
area_label Shown in the overlay header
states [] 2-letter codes used to fetch warning polygons (?area=ST). Empty → ?point=
events Tornado/Severe Tstorm/Flash Flood/Flood Warning Which warnings qualify & are drawn
poll_interval_sec 60 How often radar.js checks NWS
position/width/height/border_radius center / 1100×720 / 12 PiP box
noaa_user_agent NWS asks for a contact in the User-Agent

The overlay fetches warnings by states (so the polygons stay visible across the map), while radar.js decides show/clear from the ?point= at your lat/lon. Set lat/lon inside the area you care about and list its states.

Test

npm test    # RESULT: PASS ✅

Covers the warning gate (event/expiry/geometry), the color map, the RainViewer tile-URL builder, and the overlay-URI round-trip. No network.