Commit Graph
416 Commits
Author SHA1 Message Date
Daniel Slay 71aa889133 cctv: live-video panel card — canvas painted from the active camera's video element, 16:9 wrap, gated against the still-image path 2026-09-14 20:00:38 +00:00
Daniel Slay e02492cfc2 cctv: HLS strategies as server/providers/cctv/stream.js (Node puller for .m3u8, ffmpeg remuxer for RTMP) with sub-path media dispatch in the provider; hls.js client dependency 2026-09-14 20:00:38 +00:00
Sameh Khamis fb8f9e1c49 refactor: expose portable FIRMS CSV helpers 2026-09-14 12:58:57 -07:00
Gustavo Beneduzi 8db53063a9 fix(wind): scope grid ids and URLs to the model
The grid id and URL omitted the model, so two models sharing a cycle produced
the same `/api/wind/grid/<id>.bin`. Because the grid route defaults to `gfs`,
an IFS grid request resolved against the GFS cache: when both cycles matched it
silently served the GFS field as IFS, and when they differed it 404'd and the
client parsed the error body as float data.

Include the model in both the id and the URL, and reject a resampled grid that
contains non-finite values instead of caching it. Verified against live data:
the IFS grid now decodes to 65,160 finite values (u -20.2..27.6 m/s) and renders
a field distinct from GFS.
2026-09-14 14:32:22 -03:00
Gustavo Beneduzi a2d38391e6 merge: wind overlay visibility fixes from feat/wind-gfs 2026-09-14 14:03:11 -03:00
Gustavo Beneduzi b7033d86c2 fix(wind): make the particle overlay actually visible
Live browser QA of the Wind layer surfaced several rendering defects that
unit tests with fakes did not catch:

- The trail fade used a translucent black fill (source-over), which raises
  alpha instead of erasing; combined with additive strokes the overlay
  saturated into a solid white disk. Fade with destination-out instead, and
  draw strokes with normal blending.
- Particles were seeded uniformly over the whole globe, so at regional zoom
  almost none fell on screen. Seed inside the camera's visible rectangle.
- A non-finite particle position (polar divide-by-zero) reached Cesium,
  which threw and aborted the entire frame before any stroke. Guard finite
  coordinates per particle and per projection.
- Exaggerate advection in proportion to camera height, so the same visual
  speed is legible at street level and at hemispheric zoom.
- Brighter colour ramp (the old ramp started near-invisible dark grey) and a
  defensive frame try/catch so one bad frame cannot kill the loop.

Verified: the wind field/colour/particle model renders the real GFS 06z field
correctly in an offline render, and the wind unit tests pass (8/8).
2026-09-14 14:02:48 -03:00
Gustavo Beneduzi bb18e39b7d feat(wind): add ECMWF IFS as a second wind model
Add ECMWF IFS 10 m wind alongside NOAA GFS, selectable at runtime.

The /api/wind proxy becomes a model dispatcher: `?model=gfs|ifs` (default gfs,
unknown → 400), cached per model+cycle+grid. IFS reads the keyless ECMWF Open
Data JSON Lines `.index` (note: `<stem>.index`, not `<grib2>.index`), byte-range
fetches only the `10u`/`10v` messages, decodes them with the same ecCodes WASM
path, and resamples with the existing grid code (ECMWF grids start at lo1=180;
the resampler already wraps columns).

The client layer gains a `model` parameter (setParams/getParams) with a
generation guard so a model switch aborts and refetches exactly once. Registered
as an enabled+options layer with a `model` enum.

Validated end-to-end against the real 2026-09-14 06z IFS cycle on Node 25
(180x91 grid at 2°, 131,040-byte payload, plausible mean |u|/|v|), and GFS
still passes the same check.

Attribution: contains modified Copernicus/ECMWF IFS forecast data, licensed
under CC BY 4.0. Verified: npm test (3412 pass, 0 fail), check:boundaries.
2026-09-14 13:04:35 -03:00
Gustavo Beneduzi deb34ebe35 feat(wind): add keyless NOAA GFS wind layer with animated particles
Add a Wind layer animating the global 10 m wind field from NOAA GFS.

The /api/wind proxy selects the latest available 0.25° cycle, reads its .idx
inventory, byte-range fetches only the UGRD/VGRD 10 m GRIB2 messages (~1 MB
each instead of the whole ~500 MB file), decodes them with ecCodes (WASM),
resamples to a compact grid (1° default), and serves a manifest plus a Float32
U/V payload cached per cycle for an hour (single-flight, last-good on failure).

The client renders nullschool-style particles in a canvas overlay: bilinear
field sampling with longitude wrap, per-frame advection, Cesium camera
projection, and globe-occlusion culling via EllipsoidalOccluder.

Validated end-to-end against the real 2026-09-14 06z cycle on Node 25
(180x91 grid at 2°, 131,040-byte payload, plausible mean |u|/|v|). The WASM
decoder requires Node >=24, which the repo already requires.

Registered as `wind` (token k) with attribution and docs. Verified: npm test
(3412 pass, 0 fail), npm run check:boundaries.
2026-09-14 12:59:18 -03:00
Sameh Khamis 191edb7c5e Merge pull request #456 from bilawalsidhu/refactor/tool-project-root
refactor(tools): support an explicit project directory
2026-09-14 07:40:10 -07:00
Sameh Khamis 6d5478ffa9 refactor(tools): support an explicit project directory 2026-09-14 07:35:38 -07:00
Sameh Khamis 844c25212c Merge pull request #449 from bilawalsidhu/refactor/shared-application-components
refactor(app): compose shared components and configurable services
2026-09-13 22:45:37 -07:00
Sameh Khamis 97d70317bb test(launcher): resolve installed dependencies through the module graph 2026-09-13 22:42:27 -07:00
Sameh Khamis a67bc60a29 refactor(app): share application components and request services 2026-09-13 22:41:11 -07:00
Sameh Khamis a0a0128a59 Merge pull request #448 from bilawalsidhu/refactor/voice-backend-services
Separate voice controls and configurable Realtime connections
2026-09-13 22:04:34 -07:00
Sameh Khamis c488a18df1 fix: scope voice response parsing to its backend lifetime 2026-09-13 22:00:14 -07:00
Sameh Khamis 1a1cbadf5b refactor: separate voice controls and configurable Realtime connections 2026-09-13 21:54:51 -07:00
Sameh Khamis 0ba00f4662 Merge pull request #447 from bilawalsidhu/refactor/geospatial-services
Compose configurable geocoding, place search and route services
2026-09-13 21:39:04 -07:00
Sameh Khamis 8b36c28b06 refactor: compose configurable geocoding and route services 2026-09-13 21:23:13 -07:00
Sameh Khamis 3b91feffdc Merge pull request #434 from bilawalsidhu/refactor/alpr-camera-source
feat: add mapped ALPR cameras through a reusable source interface
2026-09-13 20:46:52 -07:00
Sameh Khamis bcba7c5c01 fix: use globe terrain when framing an ALPR camera 2026-09-13 20:42:48 -07:00
Sameh Khamis fe1aa3b6f6 fix: clarify nearby ALPR counts and help locate cameras 2026-09-13 20:35:38 -07:00
Sameh Khamis 7068ee7dc7 Merge current main into ALPR camera candidate 2026-09-13 20:08:54 -07:00
Sameh Khamis 9547658dc7 fix: keep ALPR camera markers stable during rotation 2026-09-13 20:04:38 -07:00
Bilawal Sidhu 41c416e329 docs(cctv): describe the ground-height data plainly (#443)
Follow-up to #433.
2026-09-13 21:54:29 -05:00
12790b36c6 feat(cctv): seven camera packs, semantic labels, terrain-clear monitor planes (#433)
Seven contributed CCTV camera packs (Ontario 511, Fintraffic Finland, DriveBC, TxDOT Texas, Estonia Tallinn + Tarktee, Warendorf, Live Traffic NSW) on a fair per-pack catalog cap; semantic camera labels; monitor planes lifted clear of the terrain from a precomputed, bundled ground-height dataset. Default catalog 800 → 3,446 cameras. Full context in PR #433.

Co-authored-by: sendmebits <[email protected]>
Co-authored-by: avocadoAgent <[email protected]>
Co-authored-by: Alex Harvey <[email protected]>
Co-authored-by: Jason Meredith <[email protected]>
Co-authored-by: Daniel Smith <[email protected]>
Co-authored-by: Vladimir Sobolev <[email protected]>
Co-authored-by: Matthias Schneider <[email protected]>
Co-authored-by: Cyber Knight <[email protected]>
Co-authored-by: NovaSoft Australia <[email protected]>
2026-09-13 21:48:33 -05:00
Sameh Khamis 277cd45154 test(tracking): keep the synthetic floor above refreshed contact altitude 2026-09-13 19:39:00 -07:00
Sameh Khamis 211eb70eed Merge remote-tracking branch 'origin/main' into refactor/alpr-camera-source
# Conflicts:
#	package.json
#	scripts/format-scope.json
#	scripts/package-boundaries.json
2026-09-13 19:21:57 -07:00
Sameh Khamis 0272635f25 Merge pull request #440 from bilawalsidhu/refactor/map-source-components
refactor(maps): separate source factories and scene coordination
2026-09-13 19:21:03 -07:00
Sameh Khamis 8024813792 fix(maps): settle failed recovery and update registry QA 2026-09-13 19:01:23 -07:00
Sameh Khamis 06c73bca98 fix(maps): defer 3D attachment until the selection is current 2026-09-13 18:59:29 -07:00
Sameh Khamis e59282dc9c refactor(maps): separate source factories and scene coordination 2026-09-13 18:59:29 -07:00
Sameh Khamis 561a781099 Merge pull request #439 from bilawalsidhu/refactor/bundled-layer-components
refactor(geography): separate cable sources and bundled lookups
2026-09-13 18:50:27 -07:00
Sameh Khamis 3ce5d2e454 refactor(geography): separate cable sources and bundled lookup modules 2026-09-13 18:36:33 -07:00
Sameh Khamis 2213c42200 Merge pull request #437 from bilawalsidhu/test/radio-hud-layout-settle
test(radio): stabilize layout and tuner drag fixtures
2026-09-13 18:35:55 -07:00
Sameh Khamis 2808fc1707 test(radio): settle HUD geometry and expose the tuner drag target 2026-09-13 18:25:38 -07:00
Sameh Khamis cc5d4f7040 Merge pull request #435 from bilawalsidhu/refactor/radio-layer-components
refactor(radio): separate directory, rendering and playback components
2026-09-13 17:53:53 -07:00
Sameh Khamis 0feaab0a72 refactor(alpr): accept normalized camera snapshots and source attribution 2026-09-13 17:33:48 -07:00
Sameh Khamis 1180274081 test(radio): settle both lanes in the paused Cockpit fixture 2026-09-13 17:28:35 -07:00
Sameh Khamis 3b1e75171a refactor(radio): expose shared country normalization 2026-09-13 17:28:35 -07:00
Sameh Khamis 41b3cc1705 refactor(radio): separate directory and playback components 2026-09-13 17:28:35 -07:00
Tom-NeverwinterandBilawal Sidhu 4374c0fa60 feat: add mapped ALPR cameras with bounded source loading
Adapt the ALPR camera contribution to reusable layer components, retaining source attribution, bounded queries, selection and voice controls.

Co-authored-by: Bilawal Sidhu <[email protected]>
2026-09-13 17:21:42 -07:00
Sameh Khamis ba7fda74d7 Merge pull request #430 from bilawalsidhu/fix/geojson-release
fix(layers): release bundled GeoJSON entities on toggle-off instead of hiding them
2026-09-13 16:39:34 -07:00
Sameh Khamis 9f0159343e docs: describe infrastructure disable and rebuild lifecycle 2026-09-13 16:26:08 -07:00
Sameh Khamis 3aaa2afd48 Merge remote-tracking branch 'origin/main' into fix/geojson-release-intake 2026-09-13 16:26:08 -07:00
Sameh Khamis 3ca81fb4fb Merge pull request #432 from bilawalsidhu/refactor/camera-layer-components
refactor(cctv): separate camera source and scene components
2026-09-13 15:28:21 -07:00
Bilawal Sidhu 499e1168a7 fix(layers): release bundled GeoJSON entities on toggle-off instead of hiding them
Toggling datacenters, dams, or submarine cables off only set `show = false`
on their data sources. Cesium's DataSourceDisplay still walks every
visualizer of a hidden source each frame, and the ~11.5k hidden entities
(hundreds of MB) stayed resident, so the whole scene rendered ~2x slower
for the rest of the session after a single on/off round trip (owner field
test 2026-09-13).

disable() now removes the data sources from the viewer and drops the built
records; the parsed dataset (NDJSON features / TeleGeography JSON) is cached
so enable() rebuilds without a refetch or re-parse. A disable that lands
while a load is in flight releases the finished build instead of parking it
hidden. destroy() clears the cache.

Measured with a headful Chrome harness (flights+military+satellites on,
camera rotating, 250-frame windows), before -> after:
- entities resident after OFF: 11,537 -> 0
- DataSourceDisplay.update per frame after OFF: 1.09 ms -> 0.02 ms
- scene.render per frame after OFF: 13.9 ms (control 6.6 ms) -> 5.2 ms
  (fresh baseline 5.0 ms in the same run)
- JS heap 30 s after OFF: 1.6 GB and climbing -> 342 MB after GC

Tests: the GeoJSON lifecycle and cables suites assert disable leaves zero
sources/contexts and re-enable rebuilds with fetch called once.
2026-09-13 17:08:23 -05:00
Sameh Khamis 519bc6c362 refactor(cctv): separate camera source and scene components 2026-09-13 15:02:32 -07:00
Sameh Khamis ca5f5fff93 Merge pull request #429 from bilawalsidhu/feat/frame-rate-shortcut
feat(ui): add a backtick FPS toggle beneath the logo
2026-09-13 15:01:19 -07:00
Sameh Khamis bf6c401e27 feat(ui): toggle rendered frame rate with backtick 2026-09-13 14:51:24 -07:00
Sameh Khamis 53dc685c8d Merge pull request #428 from bilawalsidhu/fix/traffic-city-navigation
fix(traffic): recover loading after city navigation
2026-09-13 14:50:55 -07:00