Commit Graph
27 Commits
Author SHA1 Message Date
Sameh Khamis 51637a5e96 Merge branch 'main' into feat/voice-geometry
# Conflicts:
#	SECURITY.md
#	scripts/format-scope.json
#	src/app/constructCatalog.test.mjs
#	src/app/sourceComposition.test.mjs
#	src/firstRunExperience.test.mjs
#	src/i18n/locales/ar.json
#	src/i18n/locales/de.json
#	src/i18n/locales/es.json
#	src/i18n/locales/fr.json
#	src/i18n/locales/it.json
#	src/i18n/locales/ja.json
#	src/i18n/locales/pt.json
#	src/i18n/locales/ru.json
#	src/i18n/locales/uk.json
#	src/i18n/locales/zh-CN.json
#	src/i18n/locales/zh-Hant.json
#	src/voice/actionSchemas.test.mjs
2026-11-03 09:07:16 -08:00
Manjunath ecaddd838b Merge feat/voice-geometry onto main
Both stack parents (#837, #842) are on main, so the voice geometry branch
now builds on main directly. Conflict resolutions keep main's behaviour and
add the geometry work on top: osm_query gating on every provider, restored
admin identity for Nominatim outlines, merged analyst follow-up memory, and
the cancelled Globe View reset instruction ahead of the generic cancellation.
2026-11-03 14:33:34 +05:30
Said Turksever fc7ff1055c Split Open Map Overlays into Sea Marks and Ski Pistes layers
Each overlay is now its own Infrastructure row instead of a chip on one
shared row: sea-marks (token 6) and ski-pistes (token 7), both
enabled-only, built by createOsmOverlayLayers() from one descriptor
list. Drops the option group and its share-codec defaults, gives each
layer its own name, voice entry and CURRENT-STATE row, and shifts the
token-ledger fixtures to the next free digit 8.
2026-11-02 16:20:08 +00:00
Said Turksever ce1ad3b95a Merge main into prereq-10-osm-overlays and port Open Map Overlays
Main moved on since this PR opened; the overlay layer is ported to the
current contracts:

- Layer-state token 6 (j belongs to transit; new single-character
  tokens are digits) with a reservation-ledger row, and the option owner
  renamed to the layer id so the compact share codec can encode it.
- Constructed per catalog by createOsmOverlaysLayer() in
  constructCatalog.js; src/standalone/data.js no longer registers layers.
- Drapes through maps/imageryHost.js, so the overlays show on Google 3D
  (tileset imagery) as well as the globe stacks, and follow map-stack
  switches. Imagery layers are created on enable and destroyed on
  disable/destroy.
- Translated chip labels and layer name in every locale, LAYER_NAME_KEYS,
  Infrastructure panel group, voice manifest entry.
- Attribution: OpenSeaMap tiles CC BY-SA 2.0, OpenSnowMap credit as
  required, OSM ODbL credit for both; bulk-download note in DATA_SOURCES.
- CURRENT-STATE row, changelog fragment, share-codec absent defaults,
  updated token-ledger fixtures and voice schema pins.
2026-11-02 15:55:40 +00:00
Sameh Khamis e1bbbcec5a Let a GNSS integrity source set the layer's evidence window
The catalog now passes the gnss-integrity source's windowMs to the layer.
A missing, non-finite or non-positive value keeps the 30-minute default.
The row text now names the window the layer uses instead of a fixed 30 min.
2026-10-31 14:33:48 -07:00
GPTmadeitandClaude Opus 5.5 1f77d2290c feat: add S2 GhostMaps live intel layer
Adds an "S2 GhostMaps" layer (Events group) that renders S2 Underground's
GhostMaps KMZ exports (Common Intelligence Picture, Kinetic 30d, Border
Crisis, Iran CIP/Kinetic, Yemen FLOT, latest incident drop).

- server/providers/ghostMaps.js: watcher polls the repo's git smart-HTTP
  ref advertisement (default every 15s, GHOSTMAPS_POLL_SECONDS), fetches
  the tree only on a new head, caches commit-pinned files by blob sha and
  pushes catalog updates to browsers over SSE (/api/ghostmaps/events).
- src/layers/ghostMaps: KML reader, ArcGIS popup-table parsing, per-product
  data sources, product chips, horizon-culled pins, report cards.
- Unit tests, QA gate (scripts/qa-ghostmaps.mjs), credits (CC BY-NC-SA 4.0),
  i18n, voice manifest, layer-state token 5.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-20 16:24:53 -04:00
Sameh Khamis 046126eb36 Merge branch 'main' into feat/aqhi
Port to current main: main reserved layer-state token 0 for street-level, so
air-quality takes the next free token, 4 (registry, ledger, and the allocation
tests shift by one). Main moved source contracts into sourceComposition.js, so
air-quality registers its getSnapshot contract there. Package boundaries keep
main's lists plus this branch's air-quality modules and packages.
2026-10-15 12:39:00 -07:00
Mazeyar Moeini Feizabadi 01a8ad7aa7 fix: address GNSS integrity and aircraft emergency review findings 2026-10-14 17:43:13 +02:00
Mazeyar Moeini Feizabadi ec80c89c1e fix: integrate GNSS and emergency features with current main contracts 2026-10-13 17:42:30 +02:00
Leo PechnickiandClaude eefcb338b3 feat(layers): GNSS interference layer from ADS-B NIC/NACp integrity
Bins airborne ADS-B v1/v2 aircraft that report degraded navigation
integrity (NIC < 7, NACp < 8, or readsb's GPS-loss flag) into 0.5 degree
cells over a rolling 30-minute window, coloured with the gpsjam.org
bands. Keyless: reads the capped adsb.lol point snapshot around the view
through /api/gnss-integrity, which returns integrity fields only, caches
60 s per whole-degree anchor, backs off on upstream 429 and serves the
last snapshot on failure. Adds scripts/qa-gnss.mjs.

Built by the Hex project (Crew Leo Agile dev team).

Co-Authored-By: Claude <[email protected]>
2026-10-13 17:19:23 +02:00
Sameh Khamis 5756ae92a8 Make catalog feed configuration optional and explicit 2026-10-09 17:35:38 -07:00
Sameh Khamis 940b277460 Allow optional Street Level provider composition 2026-10-09 17:18:49 -07:00
manjunath22466 b234d7b427 feat(voice): add reusable geometry actions
- turn named places and mapped landmarks into reusable bounded areas
- count loaded records inside resolved, drawn and annotated geometry
- find recent imagery for an area, the view or the pointer snapshot
- keep osm place search behind an operator-configured overpass endpoint
- preserve cancellation, ownership and follow-up memory across every action
- cover geometry, provider lifecycle, cache isolation and voice routing
2026-10-03 10:23:38 +05:30
rileygramlich 8887ca47eb feat(air-quality): add the Air quality layer to the Weather group
Reworks #568 to the shape asked for in review.

Generalized from "AQHI" to a provider-backed Air quality layer, with ECCC's
AQHI as the first registered provider. Readings are carried as
{ provider, scale, value, band } rather than a bare number, because
air-quality indices are not interchangeable: AQHI runs 1-10+ on health risk,
the US AQI runs 0-500 on concentration breakpoints, and Europe's EAQI is a
five-step category. Naming the index a value belongs to is what lets another
network be added without inventing a shared numeric meaning. Coverage is
stated as "Canada only" on the provider, the layer row and the card.

Adds the WEATHER panel readout (readout: true) carrying the band legend and
the worst readings currently in view, with getRowControls/setRowControlsListener
following the wind and cyclone cards. An unresolvable view rectangle degrades
to the worst readings overall rather than to a blank card, and a rectangle
crossing the antimeridian is handled.

update() now takes the earthquakes layer's abort-and-guard shape: it aborts any
in-flight request, passes the signal through to the source, and refuses to
touch the scene when the request was superseded, aborted, or the layer was
disabled while it was outstanding. disable() and destroy() abort too. Tests
cover the late-response, superseded-refresh and disabled-update paths.

Rebased on main: the source is registered in src/sources/reference.js, and the
allocation profile was re-measured against the current worker — median 3,900
B/frame, max 4,114, 85.7 B/candidate, inside the shared 154 ceiling, budgeted
at 5,200 for 26% headroom. The earlier figures no longer held.

Freshness is now judged on the observation time rather than on when the last
response arrived. lastUpdate only says the feed answered; a station that keeps
returning a reading from four hours ago would otherwise be narrated as live by
the HUD and the voice provenance envelope. getStats() reports observedAt and
stale, so layerFeedState() calls the layer stale past two missed hourly
publications, and degraded when a refresh fails over readings that are still
good.

The share-link token is 0, which is what layer-token:next allocates. Taking it
moves the ledger fixtures that had hard-coded 0 as the free digit and 3 as the
one after; those shift to 3 and 4. The pinned equality between the reservation
ledger and LEGACY_LAYER_STATE_TOKENS also had to become "the closed legacy set
plus air-quality", since that set is documented as never growing. Happy to
re-pin this differently if you would rather the fixtures derive the provisional
digits from nextLayerStateToken() so the next layer does not move them again.

The layer and its source are registered as ./layers/air-quality and
./layers/air-quality/source, each with its own boundary group, following the
perimeters pair. check:boundaries requires the package exports and the group
exports to be the same set, so a layer that ships a source needs both.
2026-10-02 15:12:37 -06:00
Said TurkseverandClaude Fable 5.1 9ba6f96d87 Merge upstream/main into pr/mapillary-layer
Upstream took share token '2' for fire perimeters, so Street Level moves to
'3'. mapillary-js joins upstream's optimizeDeps include list instead of
overriding it; catalog and registry tests count the new upstream layers.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-25 17:58:27 +01:00
f913066cf2 feat(fires): MODIS in Active Fires and a Fire Perimeters layer (#737)
Adds MODIS NRT to Active Fires and a keyless Fire Perimeters layer (NIFC WFIGS) with
InciWeb incident links, served through a capped, cached /api/fire-perimeters proxy.

Co-authored-by: Gustavo Beneduzi <[email protected]>
Co-authored-by: James Cooke <[email protected]>
2026-09-23 21:21:52 -05:00
1fc795577a feat(sdr): local receivers — browser RTL-SDR, Local ADS-B layer and decoder feeds (#732)
Adds a Local ADS-B layer fed by your own receivers: a browser WebUSB
RTL-SDR (with FM listening) and local 1090/978 MHz decoder feeds
(LOCAL_RECEIVER_FEEDS, local and private addresses only). Local aircraft
draw in magenta with class, silhouettes, 3D models, trails and a position
sanity filter; the click card names the band and input that heard them.

Builds on Sameh Khamis's SDR prototype and the initial GEV port by
Mazeyar Moeini Feizabadi (#134); the decoder-feed design follows the
notes on #57. Closes #57.

Co-authored-by: Sameh Khamis <[email protected]>
Co-authored-by: Mazeyar Moeini Feizabadi <[email protected]>
2026-09-23 16:00:53 -05:00
Said TurkseverandClaude Fable 5.1 817716f0c1 Merge upstream/main into pr/mapillary-layer
Twenty layers now (weather, wind, cyclones and recent imagery landed
upstream); Street Level sits after Recent Imagery in the right rail and the
Cameras group, and the rail CSS names it beside the other panels.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-23 19:05:59 +01:00
Said TurkseverandClaude Fable 5.1 fa5710bcf2 feat(mapillary): street-level layer core — coverage, sequences, viewer bridge, query engine
Camera-driven Mapillary coverage (z0–5 overview points from orbit, z11–14
ground-clamped sequence lines below 60 km), per-sequence image cones, an
embedded MapillaryJS viewer bridge with a camera-follow mode, sprite icons
for map features, and a query engine that turns a plan into a streamed
z14 tile fan-out. Registers an on-globe CC BY-SA 4.0 credit while enabled.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-09-23 15:44:32 +01:00
Bilawal Sidhuandmanjunath22466 082074a006 feat(layers): Recent Imagery — open satellite imagery for a selected box (#716)
Select a box on the world and browse the last 30 days of open satellite imagery over it, keyless: NASA GIBS Harmonized Landsat Sentinel-2 (30 m) and the VIIRS daily overview (250 m), with a day strip, IMAGE / VS BASEMAP / A / B modes with a swipe divider, PNG export and share links. The before/after swipe from the Nepal scene moves into shared modules so both use it.

Co-authored-by: manjunath22466 <[email protected]>
2026-09-22 20:34:11 -05:00
0251c74109 feat(weather): add globe wind, observed weather and cyclone context (#617)
Wind (NOAA GFS and ECMWF IFS: animated particles, colour field, a reading at map centre), observed weather (NOAA MRMS radar, GOES and NESDIS infrared clouds, lightning density) on one shared history timeline, NHC and CPHC cyclone advisories with tracks and cones, and a WEATHER panel in the right rail. On 3D Tiles the observed products render as raised shells with a sharper window around the view.

Co-authored-by: Gustavo Beneduzi <[email protected]>
Co-authored-by: Daniel Slay <[email protected]>
Co-authored-by: Rehaan Delmotra <[email protected]>
Co-authored-by: Cursor Agent <[email protected]>
2026-09-22 17:45:39 -05:00
Bilawal Sidhu 0bb61f53c6 fix(transit): keep the real silhouettes under sensor presets, make the selected trail visible, put Transit in Movement (#596)
## Changes

Follow-up to #587 after the owner's first look at the merged transit layer on Google 3D tiles.

- **Sensor presets keep the real silhouettes.** Under NVG, thermal (white-hot, black-hot, Ironbow) and noir, vehicles are the same silhouettes as in normal view, filled opaque white with a 2 px dark halo, at the CRT display sizes (26 px fleet, 39 px selected). The solid rounded "signature" bodies are gone.
- **The selected vehicle's trail is visible.** The retained history is now draped onto 3D tiles and terrain (`GroundPolylinePrimitive`, `ClassificationType.BOTH`, the way the traffic heat-lines are drawn), 3 px core over a 5 px dark backing, per-segment age colour, a short draped head clipped to the sprite. Two defects kept it off screen before: Cesium's per-instance attribute getters return copies, so the renderer's show/colour edits were discarded, and a marker did not recover after the camera jumped to it, which hid the trail with it. Trail geometry is now prepared on selection independent of floor resolution and marker visibility; sparse long intervals (rail) keep a bounded marker corridor instead of dropping the interval; classification survives map-source changes.
- **Transit sits in the Movement panel group** between Street Traffic and Bike Share (the panel orders by `PANEL_GROUPS`, not by catalog order; the catalog is moved too).

## How it was verified

- `npm run format:check` (854 files), `npm run check:boundaries`, `npm test` (4,062 passing), `npm run build` clean; tracking regression 109/109 in a real browser on Google 3D tiles.
- Browser harness (`scripts/qa-transit.mjs`), keyed on Google 3D tiles and keyless: keyed 194 pass, with the trail pixel check passing at 300, 600 and 900 m; the remaining keyed failures are the per-frame allocation gate already recorded as a follow-up from #587 (CPU and frame time within budget), four readability lines at threshold edges, and the card-anchor check now counting frames where the selected marker is legitimately off screen; keyless 193 pass with the remaining misses being threshold edges on the thin tram silhouette (centre 0.83–0.88 against 0.85) and one bus ring 0.28 against 0.25 on a pure-white roof.
- New harness checks: `Google 3D selected trail visible at 6 of 8 projected samples` (repeated off/on framebuffer captures at 300/600/900 m, samples outside the sprite footprint, a background-change negative control; fails on main, passes here), a camera-arrival check (select a moving vehicle, `setView` onto it, marker shown and trail body drawn within 2 s), `PANEL_ORDER` pinned, raster tests comparing every sensor raster's mask and aspect ratio to the normal silhouette.
- Direct look on a keyed build: a live CapMetro bus at 30 m/s selected through the layer API draws its draped trail along the highway lane (harness capture `keyed-600m-trail-visible.jpg`).
- Adversarial review by Codex Astra before the last two fix passes (stack-switch classification, marker corridor under the vertex cap, pixel-gate loophole), all three fixed with regressions.

Docs: `docs/CURRENT-STATE.md` and `CHANGELOG.md` updated in this PR. No data-source changes.
2026-09-15 13:26:41 -05:00
manjunath22466 60768ccc0b feat: add Nepal flood incident scene 2026-09-15 19:48:11 +05:30
Bilawal Sidhu 76c20be277 feat(transit): live public-transit vehicles from open GTFS-Realtime feeds (#587)
Supersedes #218 by @spcpza, ported onto the current component layout with fixes from review.

Verified before merge: format, package boundaries, unit suite, build, and the browser tracking suite; a browser harness for the change where one applies; adversarial review applied.

Contributor: @spcpza. His original commit is the base of this branch, and his own re-port onto main (2026-09-15, `5b69011`) was consulted while finishing the height work. That port reads every vehicle's surface from the app's shared ground-floor system (`cachedGroundFloor` / `warmGroundFloor` / `GROUND_FLOOR_LIFT_M`) rather than sampling the scene per layer, keeps a vehicle hidden until its cell answers, warms a bounded batch per poll on a timer instead of per frame, and renders at the ellipsoid above the altitude gate. That is the sounder primitive — one floor system for the app, with the rooftop-versus-street question already settled against a datum-correct DEM prior — and this branch's height work was rebuilt on it, replacing a bespoke cell cache, ground prior and rooftop rule written here. Credit for that direction is his.

Future work (not in this PR), both written up in docs/CURRENT-STATE.md:

- Readable route names. The realtime feeds carry only `route_id`; `route_short_name` / `route_long_name` live in each operator's static GTFS `routes.txt`, and headsigns in `trips.txt`. Doing it properly wants a server-side metadata loader beside the transit proxy with fixed registered static sources, bounded indexes built once and persisted, a slow conditional refresh, and a versioned route dictionary the browser caches. Shipped here: ids are never rewritten, and a cut one carries an ellipsis instead of reading as a typo.
- Below-ground rendering. Subway vehicles are drawn on the surface directly above themselves, because the feeds carry no depth and a train nobody can see is not worth drawing; the card says so plainly. Real treatment wants OSM tunnel geometry per city and a ghosted sprite tethered to the surface. The owner recorded it and left it.

Round four and after (2026-09-15). The owner tested round three under FLIR and NVG, and then asked for the design to be taken further: elegant in performance, beautiful on camera, trails with a cache for public transport, Cesium-native, and a core other moving layers can adopt. Codex Astra reviewed the plan (it confirmed the speed fault: a glide started from the drawn position at receipt time but spanned the gap between report times, so with MBTA reporting every ~10 s against a 15 s poll every second glide ran at 1.5x; it rejected a queued-segment patch), then wrote the design, then implemented it in commit-sized passes with adversarial review between them and real-browser harness runs by the integrator.

What this PR now contains beyond the contributor's original port:

- Delayed playback in a contact-agnostic core (`src/data/contactPlayback.js`): each vehicle keeps a typed, bounded fix history and a display clock that runs at one second per second through it, a feed-derived lag behind real time, holding at its newest fix rather than extrapolating and never sprinting to catch up. Marker, course, motion word, card and trail all read the same displayed sample. The clock has an explicit time-offset and seek API so a rewind is a later feature, not a rewrite; flights and vessels are untouched.
- A selected-vehicle trail (`src/data/contactTrailRenderer.js`, `src/layers/transit/trails.js`): the retained history drawn with batched Cesium primitives, clipped at display time so the head is exactly the sprite, faded by age, in the mode colour (white under sensor presets), on the same surface path as the marker.
- Bounded proxy-side history (`server/providers/transitHistory.js`): fifteen minutes and at most 128 fixes per vehicle with hard byte ceilings, MBTA only for now (opt-in per feed), served by a small endpoint that never fetches upstream, so a selected trail survives a browser reload while the server keeps running.
- Scene work bounded to what is visible and moving, an occluder, cached DETECT candidates, holds on the render loop only while something visible moves.
- Sensor presets: white-hot haloed sprites under NVG/FLIR/noir (black-hot inverts), saturated mode colours under CRT, per-mode bracket tiers in every theme, the selected card keeping its mode colour.
- A discriminating browser harness (`scripts/qa-transit.mjs`) that samples postRender frames, reads the real card anchor, and measures fleet budgets at 800 and 3,000 vehicles.

Not built, recorded as follow-ups: curated route display names (lowest priority per the owner), fleet-wide tails, route snapping, a rewind UI, adoption of the playback core by flights and vessels.

Verified at merge (2026-09-15 morning): unit suite 3,896 passing, build clean, format and boundary gates clean, tracking regression 109/109, browser harness keyless 200 pass / 0 fail (13 sensor checks unexercised because the live view offered fewer than six isolated sprites; every judged sprite passed), keyed on Google 3D tiles 198 pass with the per-frame allocation gate as the only failure. Follow-ups recorded: the keyed build's playback sampler still allocates per frame (CPU and frame time stay within budget; the 3,000-vehicle metro view sits at a 27.6 ms frame interval against a 25 ms budget), the shared detection overlay's per-paint allocation, friendlier route names, fleet-wide tails, a rewind UI, and adopting the playback core for vessels and flights.
Co-authored-by: spcpza <[email protected]>
2026-09-15 05:18:30 -05:00
Bilawal Sidhuandspcpza d78696dc17 feat(directions): keyless A→B directions with turn-by-turn steps and FLY (#564)
Supersedes #219 by @spcpza, ported onto the current component layout with fixes from review.

Verified before merge: format, package boundaries, unit suite, build, and the browser tracking suite; a browser harness for the change where one applies; adversarial review applied.

Co-authored-by: spcpza <[email protected]>
2026-09-14 20:09:41 -05:00
Sameh Khamis ac977bd8bc refactor: own application request operations and surface caches 2026-09-14 14:49:04 -07:00
Sameh Khamis 8160ac5fe4 refactor: construct application layers from supplied sources 2026-09-14 14:20:01 -07:00