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]>
This commit is contained in:
authored and GitHub committed 2026-09-22 17:45:39 -05:00
1 parent f01b6a5d84
commit 0251c74109
180 files changed
+30645 -434

No files matched your search

+11 -6
View File
@@ -25,15 +25,17 @@ const css = readStylesheet(new URL('../style.css', import.meta.url));
function realtimeTools() { return GEV_REALTIME_TOOLS; }
test('Realtime schema exposes the authoritative 28-tool inventory', () => {
test('Realtime schema exposes the authoritative 29-tool inventory', () => {
const tools = realtimeTools();
assert.equal(tools.length, 28);
assert.equal(tools.length, 29);
const names = tools.map((tool) => tool.name);
assert.equal(new Set(names).size, 28, 'tool names are unique');
assert.equal(new Set(names).size, 29, 'tool names are unique');
assert.ok(names.includes('set_context_mode'));
assert.ok(names.includes('control_cockpit'));
assert.ok(names.includes('select_nearest_aircraft'));
assert.ok(names.includes('control_radio'));
assert.ok(names.includes('next_satellite_pass'));
assert.ok(names.includes('next_iss_pass'));
// Every tool closes its parameter object: an open schema lets the model
// invent arguments the runner silently drops.
for (const tool of tools) {
@@ -178,17 +180,20 @@ test('no unchanged Realtime tool definition drifts silently', () => {
'fly_to_location',
'select_nearest_aircraft',
'set_map_stack',
'analyst_query',
'next_iss_pass',
'next_satellite_pass',
]);
const unchanged = realtimeTools()
.filter((tool) => !TOUCHED.has(tool.name))
.sort((a, b) => a.name.localeCompare(b.name));
assert.equal(unchanged.length, 21);
assert.equal(unchanged.length, 19);
const digest = createHash('sha256')
.update(JSON.stringify(unchanged))
.digest('hex')
.slice(0, 16);
// ALPR intentionally extends the two layer enums; retain the complete pin.
assert.equal(digest, '6963175a0c9a76de', 'an unchanged Realtime tool definition drifted');
// Analyst additions and ISS wording correction are explicitly excluded above; all other tool definitions retain their pin.
assert.equal(digest, '7411ea585e534795', 'an unchanged Realtime tool definition drifted');
});
test('Radio volume and mission speed share the Sharpen slider visual language', () => {