1. Military callsigns (aircraft.js): callsigns matching CONFIG.aircraft.
militaryPrefixes tint red regardless of altitude band and bump larger. New
"Military filter" HUD row (default off) shows only military aircraft when on;
status "N military of M". Pick overlay shows Military/Civil class.
2. Satellite ground track (satellites.js): selecting a satellite draws its
sub-satellite path (height 0, ±half orbit around now) as a dashed polyline in
the sat's colour; deselect hides it; one track at a time. Recomputed on
demand from the satrec (no upfront precompute of 97 tracks).
3. Shareable URL state (main.js + ui.js): camera / mode / layer toggles / clock
offset serialize to location.hash (replaceState, 1 s cadence, only on change)
and are restored on boot; malformed hashes ignored silently.
4. Screenshot endpoint (serve.py): dev-only POST snap?name= writes a base64 PNG
body to docs/<name>.png (name sanitized to [a-z0-9-], can't escape docs/).
Captured docs/screenshot-data.png + screenshot-photo.png (render() called
synchronously before toDataURL — the preserveDrawingBuffer pitfall).
README rewritten for Wave 2: quakes/fires layer rows (marked REAL), replay,
shared cache, shareable links, ground tracks, military, screenshots, updated
architecture + roadmap.
Verified in browser: 11 military of 6062 + filter; ground track 180 pts on
select / hidden on deselect; URL round-trips camera+mode+layers+clock; both
screenshots written as valid 1280x720 PNGs; subpath audit clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New js/layers/fires.js — fetches EONET open wildfire events directly (ACAO:*),
refreshes every 15 min, rebuilt wholesale (no time dynamics — EONET events are
slow-moving). Uses the latest dated geometry per event; Point coords direct,
Polygon reduced to first-ring centroid. Flame-teardrop billboard (new
lib.flameGlyph, drawn in #ff7a1a with dark outline, shared canvas), aggressive
label translucency so dense California/Australia clusters stay legible, cap 500.
HUD row "Wildfires (NASA EONET)".
PITFALL handled: EONET mislabels Content-Type as application/rss+xml but the
body is JSON — we call res.json() and never gate on the header.
Verified in browser: 500 fires, all finite positions, glyphs render over
North America, zero console errors.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New js/layers/quakes.js — fetches the USGS all_day GeoJSON directly (ACAO:*,
no proxy), refreshes every 5 min regardless of scrub state. Quakes are
time-anchored via availability: in-window quakes appear as the slider crosses
their origin time, older-than-window quakes stay visible the whole window
(intervals clamped to [start, stop]). Magnitude ramps amber→red, size scales
with magnitude, quakes <1h old pulse (age-aware callback), labels only for
M>=4.5. Deduped by feature id across refreshes, capped at 400 (smallest mag
dropped first). HUD row "Earthquakes (USGS)" with count/max-mag status.
Also: serve.py now sends Cache-Control: no-store on all responses (was
proxy-only) so iterative js/css edits always take effect on reload — the
module graph was caching stale copies during dev.
Verified in browser: 223 quakes, 11 labeled, time-anchoring confirmed
(187 visible at -6h → 223 at now), zero console errors.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- CesiumJS viewer (token-free, baseLayer:false), Carto dark + EOX Sentinel-2
- clock spans now +/-6h CLAMPED; built-in timeline/animation = the space-time slider
- HUD: brand, LIVE/SCRUBBED chip, Data/Photo mode toggle, layer rows, credits
- lighting is mode-aware: OFF in Data (high-contrast asset map), ON in Photo
(realistic day/night terminator) — refines SPEC 6.1's global-lighting note
- main.js defines the layer-factory contract + dynamic loader; layers land next
- serve.py now forwards OpenSky X-Rate-Limit-* headers for the aircraft status line
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>