Commit Graph
3692 Commits
Author SHA1 Message Date
German Khokhlov 1c08482fa8 Merge branch 'main' into upstream/firms-age-rounding 2026-11-11 20:14:57 +04:00
German Khokhlov 98b642869e Merge pull request #1113 from asturksever/pr/street-level-show-action
feat(street-level): "show me X on Street View" — assistant action, view field and share link
2026-11-11 19:13:30 +04:00
German Khokhlov 71797427d6 Street Level: a posted view whose camera was taken stands down whole again
Applying the rest of a posted view after the camera was taken during its
terrain wait still let it change the camera: stop_tracking dropped a follow
the user had just started, and annotate_map framed the view's marks. A
camera taken during the wait now ends the view again, as before. The 2 s
terrain timeout and the per-view catch on the queue stay.
2026-11-11 19:01:58 +04:00
German Khokhlov 0ebc09079d Street Level: polar look-at, a bounded terrain wait, takeovers during the flight
- The look-at longitude wraps fully, so a tilted camera at a pole gives a
  point on the globe. The strict off-globe check on street_level is undone:
  points are clamped again, as before.
- A posted view that fails is answered, and the views behind it still apply.
- A posted view waits at most 2 s for the terrain under its camera, then
  keeps its own estimate.
- A camera taken during that wait stays where it is: the rest of the view
  applies, and only its photos stand down.
- show_street_level keeps a search or a press on the globe made during its
  own flight: it adopts only its own navigation stamps on landing, and a
  gesture is never forgiven.
2026-11-11 18:02:15 +04:00
Said Turksever ae66d07575 i18n(sv): the PR's 27 Street Level strings
Main added a Swedish catalog in #1630, so the catalog test failed on the
strings this PR adds. They use the catalog's terms (Gatunivå, nyckel,
bilder på gatunivå, vyns mitt).
2026-11-11 12:16:58 +00:00
Said Turksever 43893697aa Merge upstream main into pr/street-level-show-action 2026-11-11 12:15:18 +00:00
German Khokhlov 4fd36c44e0 Street Level: a replacement keeps its own state, and a posted view stands down
- Releasing a held viewer frees the old source's adapter without resetting
  the panel, so a replacement's error, outcome and armed OPEN survive; a
  cross-source replacement drops the old photo's details and marker.
- The action holds the open photo only for its own switch-off: a source
  switched by hand during the load stops it and reports cancelled.
- A posted view waiting on terrain watches the camera and stands down after a
  navigation or a globe press; a flat or straight-down camera asks no terrain.
- An arming link opens the panel without persisting the layout, and a posted
  view's street-level step runs as programmatic.
- An off-globe street_level point throws TypeError.
- zh-Hant uses the file's wording for the new strings; README and
  CURRENT-STATE count 35 tools.
2026-11-11 16:05:26 +04:00
German Khokhlov 14db73f201 Merge pull request #1630 from Kajjan7610/sv-locale
i18n: add Swedish (sv)
2026-11-11 14:37:04 +04:00
German Khokhlov 45d9ff1d86 Merge branch 'main' into sv-locale
Translate the 148 strings main added since (mostly the News layer) and
prune the 5 it no longer uses; keep both Hebrew and Swedish in the
language lists.
2026-11-11 13:59:40 +04:00
German Khokhlov 45a33b54df Street Level: docs for the OPEN exception, panel freshness and what stops a request
- SECURITY.md: OPEN also takes the link's point when the screen centre
  cannot be picked at all.
- TOOLS.md: the panel's own link opens Street View only for a result issued
  in the last five minutes; an older one only arms.
- Changelog: the hiding modes stop a request, collapsing the panel does not;
  failure cards are in the interface language.
- CURRENT-STATE: a posted view without a point grounds its look-at too.
2026-11-11 13:46:35 +04:00
German Khokhlov f612fc2180 Street Level: a posted view without a photo point grounds its look-at too
show_in_gods_eye_view measured a view's altitude from the terrain before
taking the point the camera looks at; a view posted straight into the
embedded app used the ellipsoid altitude, so a camera over high ground
opened photos kilometres ahead. groundedLookAt moves to the view module,
and the embedded app uses it with the app's terrain heights for a posted
street_level that names no point.
2026-11-11 13:46:10 +04:00
German Khokhlov a8970c1f18 Street Level: a geocoder that throws fails show_street_level at its location stage
A provider that threw while geocoding (offline, an upstream down) escaped
the action as a bare error. show_street_level now reports it as its
location stage ("Could not arrive at …", the cause in detail), and nothing
is switched or looked up; fly_to_location itself is unchanged.
2026-11-11 13:46:10 +04:00
German Khokhlov 8334262109 Street Level: the action's failure cards in the interface language
The voice card showed English for show_street_level failures the catalog
did not know: a missing key, a map or source that could not be switched on,
the layer, invalid coordinates, an imagery fallback and the filter clause.
They now translate like the other action errors (exact messages and
patterns in speech.js), in all twelve languages; the spoken line stays
English, and the filter clause names the filters as their chips do.
2026-11-11 13:46:10 +04:00
German Khokhlov e91e5a9da9 i18n(sv): apply the second translation review
- The cloud brightness key is a filter, not a brightness scale.
- Counted lines without a plural form read "label: count", so 1 agrees.
- Fire confidence is «tillförlitlighet», not «säkerhet».
- Agreement with «flöde» and «luftfartyg»; course on the tracking line is
  «FÄRDRIKTNING», which fits both aircraft and ships.
- Wildlife is «Artobservationer», since the layer also shows plants and fungi.
- Bridge readouts are nouns (BLICK, ÖGONHÖJD), cockpit key hints share one
  verb form, tool names in pointer messages are quoted, and «jfr» replaces
  «jmf.»; the guide's example follows.
- Smaller wording and consistency fixes across the catalog.
2026-11-11 13:37:26 +04:00
Said Turksever e0fedc13dd Street Level: a link whose source has no working key says why 2026-11-11 09:21:06 +00:00
Said Turksever 5b7e917f94 Street Level: Hebrew strings for the show_street_level action 2026-11-11 08:55:55 +00:00
Said Turksever f878efe22d Merge commit '0ceee8df40b97c6c693e86a4443794cd4ed1ff35' into HEAD 2026-11-11 08:54:28 +00:00
Sameh Khamis 0ceee8df40 Merge pull request #1666 from bilawalsidhu/sameh/gdelt-tie-order
fix(news): Conflicts reports of the same time come in a fixed order
2026-11-10 22:49:55 -08:00
Sameh Khamis bc786f8c55 fix(news): Conflicts reports of the same time come in a fixed order
GDELT exports are read in parallel, so two reports with the same time
arrived in whichever order their exports finished, and the feed test that
pages through them failed now and then. Same-time reports now order by
most mentions, then by id.
2026-11-10 22:40:15 -08:00
Sameh Khamis 9bca228340 Merge pull request #1665 from bilawalsidhu/sameh/weather-frame-source
feat(weather): a host can supply decoded frames to the weather layers
2026-11-10 22:04:58 -08:00
Sameh Khamis aa5c0fb5e3 docs(changelog): weather frame source (#1665) 2026-11-10 21:54:27 -08:00
Sameh Khamis e18353f769 feat(weather): a host can supply decoded frames to the weather layers
A weather feed may also be a frame source. With an optional
getFrameImage({ product, time, size, bbox, signal }) the layers take
whole-extent images, detail windows and the global mosaic from it; with an
optional getFrameTile({ product, time, z, x, y, size, signal }) regional
tiles and their prefetch come from it, null being a transparent tile. Pixels
may be an ImageBitmap, ImageData, canvas or VideoFrame of exactly the
requested size; the layer draws them once and closes them. Cancellation
reaches the source, and a feed without these methods reads the image and
tile routes as before.
2026-11-10 21:54:08 -08:00
Sameh Khamis aff5ce7f17 Merge pull request #1663 from bilawalsidhu/sameh/news-test-shared-time
test(news): briefing stories share one published time
2026-11-10 21:29:18 -08:00
Sameh Khamis b226fa820a test(news): briefing stories share one published time, so their order never depends on a clock tick 2026-11-10 21:19:33 -08:00
Sameh Khamis 1fb0fdad71 Merge pull request #1662 from bilawalsidhu/sameh/contacts-follow-world-clock
feat(live): flights, military and vessels follow the world clock; vessels keyed by source id; share a selected vessel
2026-11-10 18:35:44 -08:00
Sameh Khamis c45d9cfb03 Merge branch 'main' into sameh/contacts-follow-world-clock 2026-11-10 18:26:22 -08:00
Sameh Khamis cb414a1671 Merge pull request #1661 from bilawalsidhu/sameh/gemini-error-locale
fix(voice): Gemini voice messages follow a language change
2026-11-10 18:20:57 -08:00
Sameh Khamis 5826420a27 chore(changelog): name the contacts fragment for #1662 2026-11-10 18:17:52 -08:00
Sameh Khamis cbbf55cacd feat(vessels): key vessels by their source's stable id, and share a selected vessel
AIS Vessels are keyed by the id their live source gives, with the MMSI as an
attribute: an MMSI can be shared, spoofed or reused, so two vessels with one
MMSI are now two vessels. Looking a vessel up or selecting it by MMSI still
finds it.

A share link made while a vessel is selected opens that vessel. A UUID vessel
id travels as 16 bytes in a new thing field (13). A shared thing that is not
reporting now says so in a sentence per kind, with its id (ICAO, NORAD, MMSI
or vessel UUID) on a second line.
2026-11-10 18:12:53 -08:00
Sameh Khamis 57ff81f723 feat(live): flights, military and vessels follow the world clock when their source declares a timeline
A live source may now declare a timeline: it can answer a snapshot at a
given time (source.timeline = { coverage(), stepMs, subscribe? }, read by
readSnapshotTimeline). While such a layer is on it follows the world clock
and registers the coverage. At the live edge it polls exactly as before;
away from it the layer asks for getSnapshot({ ...query, atMs }) at the step
at or before the clock time and shows that snapshot instead of polling.

src/time/snapshotTimeline.js owns the following: a seek, time going
backwards or leaving live replaces every contact with the snapshot at the
new time (play waits on it, for at most 8 s); playing on keeps one
snapshot ahead and gates play on it, applying those snapshots as polls so
contacts move smoothly; outside coverage the layer is empty; back at live
it is cleared and polls at once. One load at a time, and a load the
source drops for a newer one is not a failure.

While following, aircraft are drawn at the clock time with no render
delay, records and absences are judged at the clock, track requests carry
atMs, and vessels move between fixes along the great circle. The world
clock counts jumps (seeks and returns to live) in getState().

A source with no timeline never follows the clock, and every layer stays
live, unchanged.
2026-11-10 18:12:53 -08:00
Sameh Khamis 874f83ba48 fix(voice): messages worded before reaching the status also follow a language change (#1661)
The radio and push-to-talk helpers shared by both voice providers now pass
English catalog text, and the OpenAI controller words its detail when shown,
like the Gemini session. A token failure without a server message carries
its status as sourceParams, so it is worded again with the number. The docs
say sourceDetail is the message as given, catalog text when it is the app's
own.
2026-11-10 18:11:07 -08:00
Sameh Khamis 44dd6d48a8 Changelog fragment for #1661 2026-11-10 18:05:04 -08:00
Sameh Khamis b1c5de0ed1 fix(voice): Gemini voice messages follow a language change
The Gemini session translated each status and error message once, when it
happened, so after a language change the voice control kept showing it in
the old language. The state event now also carries the English catalog text
as sourceDetail, and the control words it when shown. The local server's
known token errors stay catalog text until then instead of being translated
on arrival.
2026-11-10 18:04:52 -08:00
Sameh Khamis 962f7293c6 Merge pull request #1660 from bilawalsidhu/sameh/gemini-keyless-mic-hint
fix(voice): keyless Gemini voice drops the microphone hint
2026-11-10 17:20:20 -08:00
Sameh Khamis fdbff75e1e Format the keyless Gemini voice tests (#1660) 2026-11-10 17:10:45 -08:00
Sameh Khamis 0118e17ea6 Changelog fragment for #1660 2026-11-10 17:07:01 -08:00
Sameh Khamis b89f81b729 fix(voice): keyless Gemini voice drops the microphone hint
The Gemini token route now answers a missing key with code API_KEY_MISSING,
the session carries it to the error state as missingKey, and the voice
control hides "Check microphone permission" for that error, as it already
does for OpenAI. The OpenAI controller sends the same flag, so the shared
control and the controller agree whichever updates last.
2026-11-10 17:06:50 -08:00
Sameh Khamis 9560a6dcd1 Merge pull request #1599 from bilawalsidhu/fix/keyless-voice-key-hint
fix(voice): keyless mic says where to add the OpenAI key
2026-11-10 16:22:58 -08:00
Sameh Khamis f86b8954f6 fix(voice): a missing-key error keeps its wording and hides the microphone hint after a language change (#1599)
The voice error was matched against the translated key message to decide
whether to show the microphone hint, so switching language brought the hint
back and left the message in the old language. The error now carries a
missing-key flag into the status, which words the message at render time.
A controller test covers the language switch, and CURRENT-STATE.md documents
the keyless voice response.
2026-11-10 16:11:30 -08:00
Said Turksever 0687e0e3da Changelog: 1599 fragment 2026-11-10 16:11:17 -08:00
Said Turksever c03a54de40 Tests: pin the API_KEY_MISSING code on the keyless voice token response 2026-11-10 16:11:17 -08:00
Said Turksever 09d02b6e7a Keyless voice: say where to add the OpenAI key instead of blaming the microphone 2026-11-10 16:11:17 -08:00
Sameh Khamis 775e9df120 Merge pull request #835 from kvnloo/feat/viewport-context-decision-upstream
feat(voice): reason-code viewport context escalation
2026-11-10 16:04:54 -08:00
Sameh Khamis 49edc31879 Merge branch 'main' into feat/viewport-context-decision-upstream 2026-11-10 15:54:49 -08:00
Sameh Khamis 4442243749 Merge pull request #1659 from bilawalsidhu/sameh/detection-occlusion
Hide street-vehicle brackets and labels behind buildings and terrain
2026-11-10 15:45:56 -08:00
Sameh Khamis 100369f9af Merge remote-tracking branch 'origin/main' into feat/viewport-context-decision-upstream 2026-11-10 15:44:17 -08:00
Sameh Khamis 9234c1b3d2 fix(voice): drop viewport decision codes the caller can never log, name the crop decision eligible (#835)
The decision no longer reports not-entity-context or channel-closed, which
its only caller rules out first, nor pointer-scale-not-useful, which the
crop path already checks and logs. A closed channel returns before any
record, as on main. The crop decision is pointer-crop-eligible, since the
crop checks after it decide whether the pointer is on ground, and a sender
called on a closed channel logs channel-lost.
2026-11-10 15:44:17 -08:00
Sameh Khamis 85f42f6cd8 Changelog fragment for #1659 2026-11-10 15:28:44 -08:00
Sameh Khamis 076d264982 Hide street vehicles behind low walls and trees seen from above
In a dense downtown view from about 400 m up, the occlusion margin of
max(3 m, 2% of the range) came to 14 to 20 m, so a wall, awning, tree or
lower facade standing 10 to 20 m in front of a street was read as the
road itself: the vehicle's dot was hidden by the scene, but its bracket and
callout were still drawn. Checked against scene.pickPosition in one such
view, 18 of 470 vehicles in frame fell in that band.

The margin now depends on how steeply the camera looks down on the
contact. A point on the line of sight s metres in front of a vehicle
stands s * sin(elevation) above it, so a surface there hides the vehicle
once that rise passes 2 m. The margin stays at least 3 m and at most 2%
of the range, so grazing and street-level views are unchanged. In the
same views no vehicle with the drawn surface within 3 m in front of it
(its own road) is newly hidden.

From the review of the first change:

- A contact back in view after longer than a retest interval is held back
  and retested like a new one, instead of being drawn from an answer
  given before it left the view. It gets a fresh record, so a test still
  in flight from before cannot end the hold-back either.
- The hold-back for a contact's first answer stretches with the retest
  pace when a crowded view slows it.
- A batch whose control point failed no longer counts as a first answer.
- An unknown log-depth flag reads as "no depth" rather than as standard
  depth, which would have put every surface in front of every contact.
- A shader that fails to build leaves no shader behind and is not built
  again on the same context.
2026-11-10 15:08:26 -08:00
Sameh Khamis 630e1b1998 Hide street-vehicle brackets and labels behind buildings and terrain
The detection overlay only hid a contact behind the Earth's curve, so a
street vehicle behind or under a building, a 3D tile or a hill still had
its bracket and "VEH-nnnn" callout painted over that geometry, while its
own dot was depth-tested and correctly hidden.

A contact a layer marks `depthTested: true` (only Street Traffic does) is
now tested against the depth the scene drew and left out of the overlay
while a drawn surface stands in front of it by more than max(3 m, 2% of
its range). Other layers are untouched: their markers are drawn over the
scene on purpose.

The test runs on the GPU and never waits for it. Each tested contact is
one point drawn inside an occlusion query; the vertex shader looks up the
frame's packed pick depth at the contact's pixel, decodes it and drops the
point when the surface is nearer than the contact's threshold. Query
results are collected on later frames. Reading depth back was measured
and rejected: `scene.pickPosition` per contact costs 0.2 to 1.4 ms each,
and Chromium answers `getBufferSubData` with a round trip to its GPU
process even behind a signalled sync object (1.5 ms on a quiet machine,
15 to 25 ms on a busy one).

- Contacts are retested every 100 to 200 ms, spread across frames, at
  most 256 a frame; with more in view the pace stretches so none starves.
- Hiding is immediate. A hidden contact returns 600 ms after its last
  "hidden" answer, so one on a silhouette edge does not blink, and a
  contact new to the view is held back until its first answer (400 ms at
  most), so orbiting does not flash brackets behind buildings.
- A callout whose contact goes behind something is dropped at once, not
  carried to the next solve and not faded out on the facade.
- These times run on painted frames, so a hidden tab does not expire them.
- A control point in every batch must draw; if it does not, the batch is
  ignored and after three the probe stands down for ten seconds. With no
  pick depth (2D, Columbus view, depth picking off) nothing is hidden.
  A WebGL 1 context reads depth back synchronously about 8 times a second.

The renderer internals this depends on are read in one function,
`readSceneDepthSource`, with the engine version they were checked against.
2026-11-10 15:08:26 -08:00