Commit Graph
1645 Commits
Author SHA1 Message Date
Sameh Khamis 6e655b801d feat(fleet): draw airport ground vehicles by callsign and ground stations as a radio mast
Feeds carry many airport ground vehicles (type ZVEH) and ground stations
(GRND) that were drawn as the generic plane, some at the 10 km airborne
default.

- types.json gains aircraft_callsign rules: a ZVEH callsign starting FIRE is
  a fire truck, PUSH/TUG a pushback tug, DEICER/SQUID/SQB a van, else a car.
  GRND draws a new 11.8 m radio mast (other/radio_mast.glb).
- resolveAircraft and aircraftModelSpec take the callsign; a matched rule
  names the model outright, ahead of the type's class model.
- The layer spec cache keys such types by the rule matched, so it holds at
  most one entry per rule.
- These models (catalog category `other`) draw at their built size, as such
  models already do, and a
  contact with no altitude whose model is one now stands on the ground; the
  feed's own type is kept for such contacts, as no airframe lookup knows it.
- Local ADS-B passes the callsign too.
2026-11-13 21:20:16 -08:00
Sameh Khamis 16d163a886 Merge branch 'main' into denis/cockpit-subject-providers 2026-11-13 18:58:00 -08:00
Sameh Khamis 53cbd55181 Merge branch 'main' into fix/cctv-panel-collapse-on-disable 2026-11-13 18:47:22 -08:00
Sameh Khamis c43bf103d6 Merge branch 'main' into german/map-render-error-state 2026-11-13 18:37:03 -08:00
Sameh Khamis 6c55daf9ac fix(transit): a held vehicle's snapshot height is its drawn marker's while the frame pass places it
Near the ground the marker follows the terrain sampled between two reports,
which a straight blend of the reports' floors misses over uneven ground.
2026-11-13 18:36:42 -08:00
Sameh Khamis 9b46692c64 Suspend only the layers Context isolation is switching off
The session snapshot recorded a user's switch only after the CCTV panel had
already rendered the layer off, so a first switch-off by the user inside
Contacts, or after a partly failed restore, still kept the panel open.
Context controls now hold the layers _clearLayersOutsideContextMode is
switching off while its transitions run; suspendsLayer reads that set, and
the snapshot is no longer consulted.
2026-11-13 18:32:57 -08:00
Sameh Khamis 4bb7b411e9 fix(cockpit): a provider's subject rides where it is drawn, and the documented provider rides a moving train
- A frame with no speedMps gets an exact anchor: an inertial one ran on at
  zero speed and closed at 0.75 m/s, so the camera fell kilometres behind a
  moving train. The docs example now passes speedMps and anchor: 'exact',
  a name for its HUD, and isEntryAllowed for a train bound to its line.
- Transit's snapshot height is the floor where playback draws the vehicle,
  not the newest report's floor uphill, and null while that floor is cold,
  so a view waits for the surface instead of standing on the ellipsoid.
- Rail's direction follows playback once it has placed the train: a report
  that runs back (a reversal, or GPS jitter) no longer turns the view
  while the drawn train still runs forward.
- A frame's id is trimmed as the candidate's is.
- A double-click on the selected vessel no longer enters an application's
  subject that took entry after it.
- The docs import from gods-eye-view/..., the package's name.
2026-11-13 18:23:50 -08:00
Sameh Khamis 9d01f8df77 Show no notice for a lost context on a page that must not reload, and log each render error once
An inline panel that lost its WebGL context showed the panel runtime's own
notice and, over it, an alert dialog with no buttons that it could not act
on. With allowReload false a lost context now clears the notice and shows
none, as the docs already said. keepPanelRendering no longer logs render
errors itself: the render failure notice logs each one. Name the Cesium
private fields finishRaise and reportThrown rely on, and the version they
were checked against.
2026-11-13 18:16:07 -08:00
Said Turksever f29b0b2639 Keep the CCTV panel through Context isolation, and collapse through the panel chrome
Contacts and Space Missions switch CCTV off to isolate themselves and restore
it on the way out: the panel and its share preference now stay as they are for
that round trip, as they do for Clear selected data layers. The controls no
longer read the collapsed class before asking: the panel chrome tells a panel
the accordion folded from one whose saved state is closed.

The camera controls gate asserts the collapse, reopens CCTV from the right
rail before switching it back on, and runs a Contacts entry and exit with the
panel open.
2026-11-13 17:46:43 +00:00
Said Turksever 7f18943ec4 docs: CCTV panel collapse on switch-off, and changelog fragment 2026-11-13 17:27:22 +00:00
Denis Groshev 974023510f fix(rail, transit): a train or vehicle a first-person view holds draws no 3D model either, since the view's eye is inside it; let go, its model draws again
The fleet models (#1714) draw nearby trains and vehicles under the 3D toggle. A
held one now leaves out its model as it does its icon, as the Vessels layer does
for its bridge subject: its model item is hidden, and handing the visual back
to its icon keeps the icon hidden while held. Tests drive each layer with the
real fleet-model layer and a stubbed glTF loader; both fail without the fix.
2026-11-13 16:43:50 +01:00
Denis Groshev 546ac22708 Merge branch 'main' into denis/cockpit-subject-providers 2026-11-13 16:38:13 +01:00
German Khokhlov df41c0affb Shorten the render failure notice's comments and docs
Comments keep only the why: the loop-running flag, the mid-raise events and
the one-time canvas focus. The CURRENT-STATE section lists behaviour and
pitfalls instead of retelling the code, and no longer says every tileset
event is raised outside Scene's error handling.
2026-11-13 19:19:15 +04:00
Sameh Khamis f0b0378b11 docs: fleet models on vessels, transit and rail; no live source names monorail, gondola or funicular; model frame axes 2026-11-13 07:16:25 -08:00
Sameh Khamis 058ed0ffeb docs: the fleet models, and changelog entry 2026-11-13 07:16:25 -08:00
German Khokhlov d42b6fe764 Merge branch 'main' into german/map-render-error-state 2026-11-13 18:47:36 +04:00
Denis Groshev fbc1a9a0ec fix(cockpit): a provider member that throws when read (a getter) leaves that provider out with one warning and keeps the rest; a worded member that starts throwing keeps its last good words; a candidate, frame or HUD view whose getter throws reads as null, so the view ends or keeps its last HUD 2026-11-13 09:22:55 +01:00
Denis Groshev 22f43aab01 refactor(cockpit): a provider words its text with getLocale and onLocaleChange from the ./i18n entry; the ./i18n/locale export, which gave only those two, is removed 2026-11-13 07:39:27 +01:00
Denis Groshev a7d722a1f4 Merge branch 'main' into denis/cockpit-subject-providers 2026-11-13 07:26:22 +01:00
Sameh Khamis 5f96009b67 feat(i18n): an ./i18n entry for an application with its own language choice
startPageLocale, followPageLocale and switchLocale start, follow and switch
the page's language as the standalone application and the globe picker do,
for an application that offers the language elsewhere and passes
localePicker: false. The standalone application uses them.
2026-11-12 22:07:13 -08:00
Sameh Khamis e4832c589c Merge branch 'main' into sameh/vessel-photos 2026-11-12 20:32:03 -08:00
Sameh Khamis a930677c83 Merge branch 'main' into sameh/cctv-globe-plane-clamp 2026-11-12 20:22:04 -08:00
Sameh Khamis 347e77d1f6 feat(vessels): a selected vessel shows its Open Vessel Photos photo and MMSI
Selecting a vessel asks Open Vessel Photos (a free, keyless API) for its
photo by MMSI, once per MMSI. The CONTACTS view shows it under the vessel's
name and MMSI with the photographer, the photo's open licence and a link to
the vessel's page; only images on Open Vessel Photos' own host are shown, and
an answer about another MMSI is no photo. The vessel source exposes the lookup
as getEnrichment({kind: 'photo'}) and fetchOpenVesselPhoto for applications
with their own vessel source.
2026-11-12 20:10:30 -08:00
Sameh Khamis 2445af349d fix(cctv): on a globe map the camera plane ends where the view meets the ground
The activation probe raycast only the photoreal tiles. On a globe map the ray
missed, or ran on through the Earth and met a primitive thousands of
kilometres away, and the monitor plane stood at the camera's full range:
about a kilometre wide and hundreds of metres up. A hit at or beyond the range
now counts as none, and on a globe map the plane also clamps short of the
globe's terrain along the axis, or flat ground at the mount's ground while
that terrain is still loading, whichever is nearer.
2026-11-12 20:10:02 -08:00
Sameh Khamis 6e4df4c287 fix(cctv): a new camera's frame shows the moment it is decoded, without a fade
The preview settled when the image had loaded, so the panel's <img> took the
src while it was still decoding and then faded in over 180 ms: every camera
click lingered on an empty box. The preview now settles once the frame is
decoded (a rejected decode still shows the loaded frame, and a decode that
never settles shows it after one second), and the fade is gone.
2026-11-12 20:10:02 -08:00
Sameh Khamis 16aae73622 Merge branch 'main' into said/shortcuts-ignore-modifier-chords 2026-11-12 18:11:19 -08:00
Sameh Khamis 1d476c87ee fix(location): a POI key held with Cmd, Ctrl or Alt runs no POI
The points-of-interest keys (Q/W/E/R/T while a city is expanded) are a
second bare-key document listener, and it did not look at modifiers
either: Alt+R or a delivered Ctrl+R picked the fourth POI and flew the
camera there. It now leaves Cmd, Ctrl and Alt chords to the browser like
the application shortcuts; Shift still counts as the key. The docs and
the changelog entry say so.
2026-11-12 18:02:41 -08:00
Said Turksever 2c4d865ef9 fix(shortcuts): a shortcut key held with Cmd, Ctrl or Alt runs no shortcut
The application shortcut listener read the key alone, so copying with
Cmd+C or Ctrl+C toggled the CCTV layer and opened the nearest camera,
Cmd+F opened the layers panel and Cmd+1 to 6 changed the visual style.
Chords are now left to the browser. Shift is not a chord, a held key
still repeats, and Escape dismisses search either way.
2026-11-13 01:12:58 +00:00
Said Turksever 1a2589d4ef Port the Data Library Browse dialog to Vue and Pinia
The dialog is now DataLibraryDialog.vue (with DataLibraryCard.vue for each
entry), placed with the Browse button by DataLibraryBrowse.vue in
LayerPanelsView and teleported to the body. It renders what the
gev-data-library store holds and sends clicks and typing to the owner.

src/ui/libraryBrowser.js is now the framework-free owner: it presents the
open state, filters, the rows they show, the stat summary and Remove all
through `publish`, and its controls answer the view. Its text helpers are
what the view renders with t(), so every label follows the locale without
rebuilding anything. Only showModal/close and focus moves stay imperative;
focus returns to Browse also when the browser closes the dialog on Escape
itself.

Component tests mount the view over the real owner (open, filters, Add to
Remove keeping focus, Zoom, Remove all, a language switch, clean view).
2026-11-12 23:01:00 +00:00
Said Turksever 24ccdd4dc3 Fix Data Library share restore, dense tile layers and EPC partition reads
- Share links: the compact /share/<code> format carries the switched-on
  library entries (field 29), so Copy Link keeps them; a share opened in the
  same tab restores them; any share decides what is on, so one with every
  library entry off no longer switches on the recipient's stored entries.
- A tile entry too dense at its minimum zoom (Norway cadastre z14, depth z11)
  is hidden below that scale via minimumTerrainLevel instead of allocating
  millions of tiles when zoomed out.
- EPC partitions keep the full extent for exclusion and the 98 % extent for
  ranking only; the old trimmed-only extents are retired.
- Partition index footers that fail transiently are retried; an incomplete
  index is never cached as complete, a complete prior index is kept, and it
  is rebuilt after five minutes.
- Views that leave touching partitions unread are partial; listing and
  footer bodies are capped and ranges validated.
- The Browse dialog relabels after a language switch.
2026-11-12 22:37:34 +00:00
Said Turksever 871b7f0fcc Remove Data Library entries whose licence or provider links are broken
A link check of every manifest found 404 licence or provider pages for
OpenSeaMap seamarks, EMODnet bathymetry and the PDOK, basemap.at, Geneva
SITG, ICGC Catalunya, Luxembourg and Vlaanderen aerial photos, and no
answer from the SEDAC GPW, Minnesota and Bangor hosts. Drop those 11
entries, renumber the unpublished share-token ledger, point the tests at
remaining entries and regenerate DATA_SOURCES.md.
2026-11-12 17:05:21 +00:00
Denis Groshev 09f3380203 docs(cockpit): a held train stays the copy drawn, the read APIs and their exports are experimental, and leaving a view does not track an earlier aircraft again 2026-11-12 17:02:37 +01:00
Denis Groshev a4f321a9ef fix(cockpit): entry to the built-in views is as before: aircraft, satellite and vessel keep their fixed order whenever each was selected, and an application's subject takes entry only when it was selected after every built-in one present, so without providers nothing changes 2026-11-12 16:58:38 +01:00
Said Turksever db80d82b8d Add the Data Library: live regional datasets, tiles and packs
DATA LAYERS keeps its curated core layers; regional and niche sources
live in the Data Library, opened from Browse data library at the foot
of the panel. Each entry is a JSON manifest in src/library/entries/
pointing at a live upstream (query API, provider-hosted file or tile
endpoint), so nothing is bundled and a self-hosted instance hosts no
data. Sources without CORS go through one allowlisted /api/library
route. Kinds: dataset (GeoJSON, CSV, JSON records, ArcGIS, partitioned
GeoParquet), tiles (XYZ, WMS/ArcGIS bbox export, terrarium relief) and
pack. Selections persist and travel in share links as lib=, separate
from the core layer tokens. Library rows get Zoom and Remove icon
chips that work while the layer is off, rendered through RailChips.
Strings are translated in every locale.
2026-11-12 12:26:45 +00:00
Denis Groshev 4c33552105 fix(cockpit): an application subject's wait for the floor is bounded, a late asynchronous hold is released, and a hold never counts as the user's selection
- A subject with no height at all waits at most
  COCKPIT_GROUND_WAIT_TIMEOUT_MS for the floor, its HUD updating and
  reading ACQUIRING SURFACE; then the view ends and the provider gets its
  subject back (there is no height of its own to fall back to).
- A hold that returns a promise is refused as before and released again
  once it settles, unless that subject is being ridden by then; release
  must tolerate a second call.
- Rail and Transit stamp selectedAtMs only for a user's selection (a click,
  focusTrain or focusVehicle); a deselection clears it, and a train or
  vehicle selected only by a hold reads null.
2026-11-12 12:31:04 +01:00
Denis Groshev 57d87d2bbf fix(cockpit): application subjects follow a change of language, never stand on the ellipsoid, and are guarded on every call; a re-selected subject takes entry again
- Labels, entry face and look may be functions, read again on every use
  and on a locale change; a failing read keeps the last good value.
- A frame with no height keeps the eye's last height, or waits
  (surfaceAcquiring) until the floor is known; heights outside
  -1,000..50,000 m read as null.
- Provider methods are synchronous: a returned promise is refused like a
  throw, and a hold that fails is released.
- A candidate may carry selectedAt; Rail and Transit stamp selectedAtMs
  on every selection, so re-selecting moves a subject to the front.
- A released Transit vehicle leaves the visible set at once.
- docs/CURRENT-STATE.md states the new entry order; docs/APPLICATION.md
  documents cockpit subjects, ./i18n/locale and ./layers/rail/paths.
2026-11-12 11:13:58 +01:00
Denis Groshev f75179eea0 feat(cockpit): an application can add its own cockpit subjects; the Rail and Transit layers expose the read and hold APIs such a subject needs
GEV itself registers no new subject: with no provider, the Cockpit offers
aircraft, satellites and vessels as before, except that the most recently
selected of them now wins entry.

- services.cockpitSubjects: providers ({kind, layerId, entryFace, priority,
  isEntryAllowed, read, hold, release, hud}) are checked once by the
  coordinator; frames and HUD views on every update; a throwing provider
  ends its view or keeps the last HUD.
- Entry: the most recently selected subject wins, across all kinds.
- Camera: a frame may turn the ground clamp off, anchor exactly on the
  subject and update every frame.
- A generic HUD: kicker, title, cards, always-visible source rows, banner,
  a veil with light streaks (off under reduced motion) and a bottom
  progress line whose close ticks merge.
- Text comes from the provider, already in the page's language
  (./i18n/locale: getLocale, onLocaleChange).
- Rail and Transit read and hold APIs (getSelectedTrain/Vehicle,
  getCockpitSubject, setCockpitSubject, focusTrain/Vehicle); a held
  train's marker, card and route line are hidden, and its feed keeps
  polling while held.
- ./layers/rail/paths is exported.
2026-11-12 10:50:26 +01:00
Sameh Khamis a105e819e0 fix(news): an application's picture cards stay at every height
Zoomed out, a hotspot's reports give way to its beacon, and the cards an application draws through pictureCards went with them; they came back only once the camera had stopped after zooming in. The cards now come from every report the close-up view would mark, at any height; the layer's own markers and beacons are unchanged.
2026-11-11 19:43:06 -08:00
Sameh Khamis 2b1784d7ed Merge remote-tracking branch 'upstream/main' into denis/news-world-clock 2026-11-11 15:17:44 -08:00
Sameh Khamis b7015f8819 Merge remote-tracking branch 'upstream/main' into denis/news-world-clock
# Conflicts:
#	docs/CURRENT-STATE.md
#	src/app/constructCatalog.js
2026-11-11 15:03:45 -08:00
Denis Groshev 9b3ca481ce Merge upstream main into denis/rail-layer 2026-11-11 23:23:58 +01:00
Sameh Khamis 99a1e06b61 feat(news): an application may draw the News picture cards itself
createNewsLayer takes a pictureCards(cards, { selectedId }) function; createApplicationCatalog passes it through newsOptions. With it, the layer paints no picture cards of its own and hands the function one card per pictured event on the map, most severe then newest first, with the selected report's id; it hands no cards when the layer turns off.
2026-11-11 13:53:10 -08:00
German Khokhlov 82e2b716bc docs(routes): tighten the outage comments and notes
Shorter comments, changelog and CURRENT-STATE text for the 502 outage
path; the CURRENT-STATE paragraph now also names the 429 exception and
which budget expiry answers busy and which answers 502. Text only.
2026-11-11 21:21:07 +04:00
German Khokhlov a29611ca17 Merge branch 'main' into upstream/route-outage-unavailable 2026-11-11 21:16:50 +04:00
Denis Groshev 13818d0b9f Merge upstream main into denis/rail-layer 2026-11-11 18:02:52 +01:00
Denis Groshev 44d2c0695c feat(news): the News layer reads its time from the world clock
Core's catalog passes worldClock.timeFor('news') as the layer's now, so a host that follows the clock for News can show a past time's reports with their ages, window and counts as they were then. Core does not follow the clock for the layer, so it keeps reading the wall clock.
2026-11-11 18:00:24 +01:00
German Khokhlov 1c08482fa8 Merge branch 'main' into upstream/firms-age-rounding 2026-11-11 20:14:57 +04:00
German Khokhlov 897a74ea27 Merge remote-tracking branch 'origin/main' into german/map-render-error-state
# Conflicts:
#	src/i18n/locales/ar.json
#	src/i18n/locales/de.json
#	src/i18n/locales/es.json
#	src/i18n/locales/fr.json
#	src/i18n/locales/he.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
2026-11-11 19:33:49 +04:00
Denis Groshev 830c080803 feat(rail): add a Rail layer with keyless live trains
Live trains from 30 keyless operator feeds: GPS positions from 29 and
Irish Rail's station reports, shown as the operators publish them. 28
work out of the box; Renfe long and medium distance and KTMB appear once
their pack is built, because their vehicles name no route.

Packs are opt-in (scripts/build-rail-paths.mjs): the operator's own
route lines, stop names, next stops and trip-update delays for live
trains. Nothing downloads when the app starts, no train is placed from a
timetable, and no request carries a deployer's key.
2026-11-11 16:06:22 +01: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