Commit Graph
3537 Commits
Author SHA1 Message Date
German Khokhlov eed8acc3f7 Keep the traffic population and vehicle heights after a globe round trip
The republish after a globe switch ran as a refinement ('Handoff refined'):
it sampled the incoming globe while it still showed coarse tiles and,
being a refinement, never refined again. Keyless Cesium's first terrain
tiles put Austin's streets near -2 200 m, so vehicles stayed there, and
the next globe weighted each road by the camera distance to those
waypoints (1.9 km became 4.1 km), cutting the population from about 620
to 260 until the camera moved.

The handoff is now a completed pass that refines once the incoming
surface has loaded, road density and the coverage radius are measured to
the road's coordinates on the local ground estimate instead of to the
last sampled waypoints, and flow that lands after a publication
re-allocates the retained roads' budgets instead of only recolouring
them.
2026-11-03 16:24:08 +04:00
German Khokhlov f3adccd01a Merge pull request #1456 from quanticsoul4772/upstream/terrain-partial-heights
fix(terrain): keep known heights when a terrain request fails
2026-11-03 16:03:07 +04:00
Manjunath d18fdfa47f Merge branch 'main' into feat/voice-geometry
Picks up the HUD summary locale work (#1488). No conflicts; it changes no
voice prompt or tool description.
2026-11-03 17:31:36 +05:30
Manjunath dfdbb134d5 fix(osm): key cached place searches to the Overpass instance that answered
The /api/osm/features cache key was the query alone, kept for a day, so after
an operator repointed OVERPASS_UPSTREAMS the old instance's answers were still
served. The key now includes the configured-upstream tag, as main's other
Overpass caches check it, so a new instance is always asked.
2026-11-03 17:27:36 +05:30
Manjunath 474cce51eb fix(voice): keep the area in follow-ups on OSM places
osm_query handed its places to the analyst with no presentation, so "which of
those have emergency?" after "hospitals in Kathmandu" was answered as "anywhere
in the loaded data". The handoff now carries the scope the places were found
in ("inside Kathmandu" with its areaId, or "in view"), as an analyst count over
that area would.
2026-11-03 17:27:32 +05:30
Manjunath 451be8e3b7 fix(voice): treat a Zone as retired only in Nepal
Every name ending in "Zone" was kept without a level and refused as a retired
administrative identity. That is right for Nepal, which replaced its zones in
2015, but zones are current units elsewhere: Ethiopia's "Gamo Zone" was
refused. The selector now keeps the verified level unless display_name places
the zone in Nepal or names no country, and the client no longer reads "Zone"
as a retired level when the source verified one.
2026-11-03 17:27:26 +05:30
Manjunath 682427ef1d docs(changelog): move the voice geometry entries to a changelog.d fragment
The maintainer workflow asks runtime changes for a changelog.d/<pr>-<slug>.md
fragment and no edit to CHANGELOG.md. The three entries move unchanged, with
their credit, into changelog.d/846-voice-geometry.md.
2026-11-03 17:27:20 +05:30
Manjunath 4edaf245d0 fix(voice): keep say lines and retry advice in cancelled and failed replies
The cancelled and failed branches ran before the say-line branch, so a
cancelled panel change no longer said "Cockpit exited; the voice panel was
left as you last set it", and AREA_TIMEOUT / OSM_TIMEOUT got "tell the user it
failed" instead of the tool description's "retry once". A cancelled or failed
result with a say line now has it spoken, and those two timeouts are retried
once. Both providers share this instruction.
2026-11-03 17:27:14 +05:30
German Khokhlov 4e950d04e9 Merge remote-tracking branch 'origin/main' into claude/hal-676-gev-fire-intensity-742bd1
# Conflicts:
#	scripts/format-scope.json
#	src/i18n/locales/ar.json
#	src/i18n/locales/de.json
#	src/i18n/locales/fr.json
#	src/i18n/locales/it.json
#	src/i18n/locales/ja.json
#	src/i18n/locales/pt.json
#	src/i18n/locales/zh-Hant.json
#	src/ui/layerPanel.js
2026-11-03 15:36:13 +04:00
German Khokhlov f4879fc24b Keep the Utilities panel's Directions row mounted across a globe switch 2026-11-03 15:36:11 +04:00
German Khokhlov 7f0572cf4c Run upstream's HUD summary and standalone startup tests against the engine-based HUD and application 2026-11-03 15:36:11 +04:00
German Khokhlov 1a1eef0e5c Merge origin/main into german/navara
Conflict resolutions:
- src/main.js: upstream's PHOTON_URL place-search setting is read once at
  module level and passed as geospatial: { endpoints: { photon } } by
  createApplication(), so every engine start of the switch flow gets it; the
  old single top-level createStandaloneApplication() call stays removed.
- src/layers/bikeshare/render/cesium/rendering.js: upstream's
  publishedCapacity fix applied with this branch's
  resolveCapacity(model, capacity, status) signature. The same fix is ported
  to src/layers/bikeshare/render/navara.js (record.publishedCapacity, status
  polls resolve from it), with a Navara regression test; upstream's
  proxyRoute test imports the moved render/cesium/rendering.js.
- src/layers/traffic/flow.js: upstream's nextTask() yield and current()
  check kept before the scene is taken from this branch's
  _trafficScene?.() ?? _viewer?.scene with its missing-scene return.
- scripts/package-boundaries.json, scripts/format-scope.json: union of both
  sides' file lists.
- src/voice/actionSchemas.test.mjs: both history comments kept, payload hash
  recomputed for the merged schemas (Sentinel-2 map stack enum plus the
  shorter layer alias hint).
- src/hudAltitudeDatum.test.mjs: this branch's engine-based IntelHUD
  construction with upstream's placeLabels summary context.
2026-11-03 15:36:06 +04:00
German Khokhlov c664f8eacb Merge branch 'main' into upstream/terrain-partial-heights 2026-11-03 15:28:20 +04:00
German Khokhlov a066a2d1ca Keep history entries untouched by unfinished globe picks and restore each visited entry's layers
A picked engine now lives in the switch until it runs; only then is the
address written, so a pick superseded by Back or one that fails rewrites no
entry. An engine-changing history visit holds the outgoing share link, which
neither restores nor writes the visited entry, and the running engine takes
the address back once the switch settles, restoring any entry visited while
it was held or not yet listening. Handed-off layers keep running where the
incoming address agrees with the outgoing one and follow a visited entry
where it differs. A failed recovery keeps the error on the loading screen
with an engine picker for a retry, and a failing reveal of the new globe no
longer blocks the cover removal or later requests.
2026-11-03 15:24:20 +04:00
German Khokhlov 9cc34e324f Stop scene attachments of Bhote Koshi, GhostMaps, cables and infrastructure waiting once their scene is released 2026-11-03 15:23:21 +04:00
German Khokhlov cf6d04b7db End the data startup wait when the application is torn down during a slow layer attachment 2026-11-03 15:23:21 +04:00
German Khokhlov 7fb11507d5 Bound the wait for layer attachments, park enables and explicit refreshes until the next scene binds 2026-11-03 15:23:20 +04:00
German Khokhlov 39c648094b Merge pull request #1488 from bilawalsidhu/german/hal-623-hud-summary-locale
fix(hud): AI summary in the UI language, canonical feed state, partial aggregation
2026-11-03 15:22:40 +04:00
German Khokhlov 342d960582 fix(traffic): retain line identity across clipping 2026-11-03 15:14:20 +04:00
Manjunath 2ac73519ec Add changelog fragment for voice camera tilt (#1520) 2026-11-03 16:43:01 +05:30
Manjunath 75000cf6a9 Hold a voice orbit, pan or rotate until its fly-to lands
"Fly to Paris and orbit it" reaches the app as two sibling tool calls,
which OpenAI runs at once. With a place that needs a lookup, the orbit
started over the old view and the late flight then replaced it; with a
known place, pan and rotate cancelled the flight already in the air.

Orbit, pan and rotate now wait for a pending voice flight the same way
tilt does: up to 30 s, and not run (saying so) if the flight is
cancelled, finds nothing or times out. Stop and rotate_globe do not
wait. Orbit keeps its own arming for flights the voice runner does not
track.
2026-11-03 16:42:50 +05:30
Manjunath 91a3f787d4 Hold a voice tilt until its fly-to lands
"Fly to London and tilt the camera" reaches the app as two sibling tool
calls, and OpenAI runs them concurrently. The tilt's navigation step
cancelled the flight already in the air, so the camera tilted where it
was; when the place still needed a lookup, the late flight replaced the
tilt and London came out top-down.

The voice runner now tracks its latest flight. A tilt sent while that
flight is still looking up or flying waits for it to land (up to 30 s),
then tilts at the destination. If the flight is cancelled, finds nothing
or times out, the tilt is not run and says so.
2026-11-03 16:42:39 +05:30
Manjunath 69152868e4 Fix voice camera tilt from a top-down view
A voice fly-to frames a city top-down, at pitch -90. The tilt clamp
rejected any step that left the pitch below -89, so the first frame of
"tilt up" stopped the motion and "tilt down" was refused: from the view
voice lands on, no tilt ever moved the camera. A bare "tilt the camera"
also failed because tilt required a direction.

- Clamp tilt only in the direction of travel, so -90 can tilt up.
- Swing the camera about the ground under the crosshair, so the place
  stays centred and the heading is kept. A tracked view still tilts in
  place, and a pivot tilt yields when tracking takes the camera.
- Add an optional move_camera pitchDeg for "tilt 45 degrees"; a tilt
  with neither angle nor direction settles at -45 (oblique view).
- Re-derive the voice tool schema pins for the new argument and wording,
  and keep the Realtime prompt under its 52,000-character budget.
2026-11-03 16:42:18 +05:30
Manjunath 05edae0606 Merge branch 'main' into feat/voice-geometry
Picks up the Radio Next/Previous fix (#1474) and the Codespaces docs
(#1515). The one conflict is the Radio cycle assertion in
gevActions.test.mjs: main's new fallback flag is kept in this branch's
layout.
2026-11-03 16:40:39 +05:30
German Khokhlov 92666fdbaf fix(cyclones): preserve movement in selected voice context 2026-11-03 15:10:20 +04:00
German Khokhlov 65f0467ad8 fix(infrastructure): sample visible ground below the ellipsoid 2026-11-03 15:10:15 +04:00
German Khokhlov fae50c0791 fix(cctv): display colour-neutral Bosch MIC models 2026-11-03 15:08:36 +04:00
German Khokhlov c68f167acb fix(transit): count distinct coverage regions 2026-11-03 15:07:00 +04:00
German Khokhlov 53c114965d Write a machine acceptance report and stop early when no browser or preview is available
qa-all-layer-switches.mjs now checks once that Puppeteer can start Chrome and that the preview answers, and names PUPPETEER_EXECUTABLE_PATH and npx puppeteer browsers install chrome when it cannot. Each run writes <output>/acceptance.json with the commit, dirty files at both ends, Chrome, Node, base URL, times and, per scenario, status, exit code, duration, covered layer ids and the sha256 of its log. It replaces summary.json.
2026-11-03 15:05:37 +04:00
German Khokhlov 65d41b971c Check traffic vehicles one by one against a fixed dark ground after the globe round trip
Live Sentinel-2 imagery is bright at this altitude, so a fixed crop of white two-pixel vehicles changed anywhere from 14 to 300 pixels. The scenario now serves a uniform dark ground tile, waits for the layer to settle with vehicles in view, projects each vehicle to the window and requires 90% of those above the drawn terrain to change the picture where the layer places them; in simulation nothing else may change. Vehicles below the terrain and the population left after the round trip are reported, not asserted.
2026-11-03 15:05:36 +04:00
German Khokhlov 04d626a4b1 fix(datacenters): preserve missing geometry and compare ring topology 2026-11-03 15:02:42 +04:00
Manjunath 20770e52a9 docs(changelog): add the range ring sonar pulses fragment for #1519 2026-11-03 16:31:02 +05:30
Manjunath e80f583e66 feat(awareness): add calm sonar pulses that flash the range ring and echo contacts
Pulses: three dim rings grow from the Global Context subject to the
250 km range ring at constant speed, one every 3 s, each taking 9 s.
Each fades in over its first 8% of travel, then fades as
(1 - travel)^1.5 to about a third of its 60% peak, so it arrives at the
ring dim but visible. They are 3 px in the ring's colours, as polylines
with CallbackProperty positions and colours that share the ring's
centre object, so they follow a moving subject.

Ring: while pulses run, the 250 km ring rests unseen and flashes to full
strength as each pulse reaches it, fading over 1.8 s. Without pulses
(reduced motion, or a scene with no primitives or preRender hook) it
stays on screen as before.

Gradient: behind each pulse a radial band in the same blue fades inward
over 35% of the radius. One flat, translucent, unpickable 250 km disc
draws it with a small Fabric material. A preRender listener writes the
pulse radii and opacities into two vec4 uniforms each frame. The disc
(0.25 degree granularity, ~3.5 ms to build) is rebuilt only after the
subject moves 2 km.

Echoes: as a pulse front crosses a flight, military aircraft or AIS
vessel, the detection overlay draws a second bracket in the pulse blue
around that contact's own bracket, spreading outward as it fades over
1.4 s. Awareness publishes the field (centre, radius, pulse timing,
echo styling) through the new src/awarenessEcho.js. The overlay reads
it, so no layer's icon or colour is touched. Mapped installations have
no detection bracket, so they do not echo.

Rendering cost: pulses never hold continuous rendering. They ask for a
frame every 80 ms, the Cyber sonar's parked cadence, so a parked
Contacts view repaints at ~12.5 fps while a subject is shown. This
changes the "parked Contacts stays quiet" behaviour on purpose.
clearVisual stops the timer and removes the disc, the listener and the
echo field.

awarenessRangeRingPositions can now reuse a result array, and passes the
WGS84 ellipsoid explicitly so a reused Cartesian never lands in the
ellipsoid argument. Tuning lives in AWARENESS_RANGE_PULSE,
AWARENESS_RANGE_ECHO and AWARENESS_RANGE_RING_STYLE. src/awarenessEcho.js
is registered in the awareness-layer, application-components and
application-layer-construction packages.

Tests cover:
- the pulse curve and calm rate;
- the ring flash once per arrival, and the static ring without pulses;
- the 80 ms frame cadence and its stop;
- the partial-scene fallback;
- the gradient disc: unpickable, uniform values, rebuild and cleanup;
- per-frame evaluation, and the echo field following the subject;
- awarenessEcho strength, rim wrap, layer filter and altitude handling;
- the detection renderer's echo-bracket band and outward spread.
2026-11-03 16:30:56 +05:30
Manjunath 8a50705eea docs(changelog): add the range ring visibility fragment for #1518 2026-11-03 16:30:37 +05:30
Manjunath 2a629f0987 fix(awareness): make the 250 km range ring readable on any ground
The Global Context range ring was a Cesium ellipse outline at 1 px in
rgba(98,181,255,0.72). WebGL ignores larger ellipse outline widths, so it
could not be thickened, and it vanished over desert and snow and under the
FLIR, NVG and CRT styles.

Draw it as a polyline instead: a 4 px line with a 2 px Context-blue core
inside a 1 px dark halo on each side (PolylineOutlineMaterialProperty).
The halo gives luminance contrast on light and dark ground, which the
monochrome styles keep. The ring sits at the same 2.5 km height and
follows the subject on the same 250 m threshold. Positions come from a
new awarenessRangeRingPositions helper that stays within 50 m of 250 km.

Style values live in AWARENESS_RANGE_RING_STYLE (awareness/policy.js).
Adds rangeRing.test.mjs (geometry at equator, Sahara, Greenland and the
antimeridian; contrast; entity shape; follow threshold) and a
CURRENT-STATE note.
2026-11-03 16:30:20 +05:30
German Khokhlov be53c338c8 Merge branch 'main' into upstream/terrain-partial-heights 2026-11-03 14:59:12 +04:00
German Khokhlov 3139369673 Add a heatmap spot size slider to the Active Fires row
A ½×–4× slider (log2 axis, 5 % steps, default 1×) under the intensity
filter sets how large far-zoom heat spots are. It scales the grid, not
the blur: 2× is a 1024 × 512 grid with the same one-pixel blur, so each
spot grows exactly and weak lone fires don't fade as they widen. A change
rebuilds only the heatmap. Share links keep it as w.s (percent, 50–400).
The layer row now takes a list of sliders.
2026-11-03 14:56:40 +04:00
German Khokhlov d413362467 Merge branch 'main' into german/hal-623-hud-summary-locale 2026-11-03 14:55:40 +04:00
German Khokhlov b80c54b7f1 Merge pull request #1474 from bilawalsidhu/fix/hal-722-radio-next-no-autoplay
Keep Radio Next and Previous from starting playback before Play (HAL-722)
2026-11-03 14:55:14 +04:00
German Khokhlov 4d2b061e3b Hand the session off on Back/Forward and roll failed globe switches back to the last working engine
The engine switch moves out of main.js into src/standalone/engineSwitch.js: every
engine change in the page hands the session off (layers, Director, Contacts,
directions and satellite cameras), whether it came from the picker or from
history. Each attempt has a generation; a failure rolls back to the last engine
that started, requests made during a switch or recovery are reconciled once it
settles, and a picked engine adds its history entry only after it starts. The
first-frame wait only lifts the cover and never fails a started engine; a
hidden tab does not wait. Nothing starts after pagehide, and a failed recovery
leaves the picker usable.
2026-11-03 14:51:17 +04:00
German Khokhlov 64c5cd25e6 Document which inputs a warm cached renderer keeps from the application that built it 2026-11-03 14:47:36 +04:00
German Khokhlov 64759c552e Release the cockpit cloud WebGL context when its controller is destroyed 2026-11-03 14:47:36 +04:00
German Khokhlov 12cd73bed9 Skip CCTV scene work when its renderer was released during a health refresh 2026-11-03 14:47:35 +04:00
German Khokhlov baabff6acf Stop a Bhote Koshi attachment that resumes after its scene was released 2026-11-03 14:47:35 +04:00
German Khokhlov 2853938df7 Detach every layer from a scene even when one fails, and let in-flight attachments stop first 2026-11-03 14:47:35 +04:00
German Khokhlov dd040b4f87 Let a failed application teardown be retried instead of repeating its rejection 2026-11-03 14:47:35 +04:00
German Khokhlov ac5164b14b Merge remote-tracking branch 'origin/main' into german/hal-623-hud-summary-locale 2026-11-03 14:45:45 +04:00
German Khokhlov 03c168d7c9 refactor(hud): share the warning line and trim the summary helpers
One provenanceLine() builds STATE | text | LAYERS for the HUD and
get_hud_caption. hasWord is one lookaround regex, capAtWord one grapheme
pass. Feed-state helpers are imported from layerSnapshot.js directly, and the
kept-whole sanitizer cases are one table.
2026-11-03 14:45:32 +04:00
German Khokhlov ef5c034dc9 Linearly bin fires so weak heat spots stay round
Dropping each detection whole into its nearest pixel snapped spots by up
to half a pixel and left weak lone fires as squares or plus signs once
thresholded. Share each detection's weight between the four nearest pixel
centres instead (linear binning, Wand 1994): spots sit at the true
position and blur round, at the same build cost.
2026-11-03 14:39:02 +04:00
German Khokhlov 0c190c3a15 Format the layer lifecycle, standalone application and Bhote Koshi event with Prettier 2026-11-03 14:36:31 +04:00