Commit Graph
10 Commits
Author SHA1 Message Date
Denis Groshev e95ae7b80c Keep the news layer inside its day and its memory bounds
From review of the news layer:
- An event's other sides older than 24 hours (or undated) are no longer
  listed, and a report dated more than 15 minutes ahead is outside the
  window, as in the regional brief.
- Picture cards are one canvas per event in a bounded cache (24), repainted
  in place when the age changes, with each card's picture dropped with it;
  the age in the key had made a new canvas every minute.
- The feed list drops reports that leave the window and is capped at 600.
- "In view" is filtered from the reports the layer already holds; it reads
  the feed only with minor news on, once per refresh, never per pan.
- Infinite scroll restarts after a filter change or a failed read.
- The two filter selects stack, so "Significant and above" is not cut off.
- The timeout tests hold the event loop until aborted, so they pass on
  Node 22 as well.
2026-11-06 00:45:25 +01:00
Denis Groshev 138cc77a11 Export the news proxy so a host's local server can mount it
`./server/providers/news` (node) with its own package boundary, so a host composing its own local providers can serve /api/news from GEV_NEWS_ORIGIN as Core's standalone server does.
2026-11-06 00:45:25 +01:00
Denis Groshev 5bb489d1fb Put news on the globe, with a feed panel in the right rail
Events ▸ News draws the last 24 hours of reports from curated hotspots
(Ukraine–Russia, Israel–Gaza–Lebanon, Iran–Hormuz, Yemen–Red Sea, Sudan,
Sahel) and developing situations elsewhere, from any server that answers the
`/api/news` read routes.

- Globe: one marker per merged event, clamped to the ground and culled at the
  horizon; one beacon per hotspot when zoomed out and a pulsing beacon for a
  developing situation; hotspot outlines with disputed areas dotted and
  labelled by who administers and who claims them; picture cards for at most
  ten major or fast-growing events with two or more sources, never
  overlapping, switchable off.
- Panel: hotspot chips, a severity filter (significant and above by default),
  categories, minor news off by default, and a scrolling list of event cards
  with picture, headline, place, sources, age and the sides that reported it.
  "In view" lists what is near the map below 3,000 km once the camera
  settles. A card flies the globe to its event and opens it with a link to
  the publisher. Reduced motion stops the pulse and the flights.
- Core serves no news itself: the local server proxies GEV_NEWS_ORIGIN when it
  is set, and answers 503 unavailable otherwise, so the layer reads "not
  configured" once instead of retrying.
- Share token 9 (enabled-only); voice stays off for this layer.
2026-11-06 00:45:24 +01:00
Denis Groshev 2d9d518946 Add the news report model, markers and source
The pure half of a news layer: validated records for a news server's
`/api/news/hotspots|feed|outline` contract, a presentation model and canvas
markers and picture cards, and a fetch client.

- Colour carries severity only (0 no physical event, 1 minor, 2 significant,
  3 major), never a side; the category is the icon, the rim is attestation
  (confirmed, a claim, one side's own press), size grows with sources and
  markers fade with age.
- Cards say "Reported by {side} sources" and mark official channels; a
  machine-read English headline is labelled as such.
- `createNewsSource` reads same-origin routes with a 15 s timeout, a 4 MiB cap
  and record-by-record validation; `NEWS_API_PATHS` and `newsQueryAllowed`
  let a host proxy exactly what the client sends. A 503 marked unavailable
  means "not configured": no retries.
- Exported as `./layers/news/source`, with its own package boundary.
2026-11-06 00:45:22 +01:00
Denis Groshev dd83812a21 Hold Cockpit regional news to the last 24 hours, and tell its states apart
Regional News showed "REGIONAL NEWS UNAVAILABLE" above populated rows and a
static "RECENT" footer over months-old articles. The status banner kept
`display: grid` when hidden, every non-empty answer carried the unavailable
text, and nothing limited or sorted articles by age.

- One window (regionalNewsWindow.js, 24 h): the local proxy asks Google News
  with `when:1d` and GDELT for 24 h, drops undated, older or future-dated
  articles, sorts newest first, and reports newsWindowHours/newsFetchedAt.
- The Cockpit labels four states: fresh (banner hidden, "LAST 24 H"),
  kept after a failed refresh ("CACHED · REFRESH FAILED"), no news in the
  window, and unavailable. The footer lives in the news state, so it
  survives page and tab changes, and the client drops out-of-window rows.
- `.cockpit-brief-status[hidden]` now hides the banner.
2026-11-06 00:45:19 +01:00
Denis Groshev 459b0e8a71 docs(changelog): add the #1556 fragment 2026-11-04 21:53:06 +01:00
Denis Groshev 219f3e1079 feat(cockpit): enter Cockpit with only the ridden aircraft's layer on
Cockpit entry no longer needs Contacts or both flight feeds: a civilian
aircraft needs Live Flights, a military one Military Flights. Contacts and
every other layer can be turned on or off before or during a session, and
turning off the ridden layer ends it. A Context mode change in flight still
blocks entry.

When the other air feed is off, Live Signals and the Contact card say
FLIGHTS FEED OFF or MILITARY FEED OFF · PARTIAL PICTURE instead of
presenting a partial picture as complete. Voice refuses entry with
subject-layer-off rather than contacts-inactive, and its tool description
says Contacts is not required.

Double-clicking the followed aircraft enters Cockpit through the same gate.
The Cockpit takes the scene's double-click before Cesium's stock handler,
which would otherwise untrack a followed aircraft whose model is a
primitive. The entry also shows under the Intel HUD readout, sharing the
Contacts button's face. A test keeps the classes the Cockpit adds to the
body from matching another element's rule.
2026-11-04 21:53:05 +01:00
Denis Groshev 82f17e694e refactor(cockpit): place the camera from a per-subject eye profile
Split the Cockpit camera update into the aircraft's own front half and a
shared placeCamera that reads the eye's forward and up offsets, pitch and
ground clearance from a profile. The aircraft profile carries the existing
constants, so the aircraft view is unchanged; other subjects can now supply
their own eye.
2026-11-04 17:03:52 +01:00
Denis Groshev ce10a46b7f docs(changelog): add the dock icon-only wings entry 2026-10-28 20:22:01 +01:00
Denis Groshev d8358048ad fix(dock): show only icons on the narrow dock wings so labels stop covering the voice control
At 900px and narrower the Location and Visual Presets wings shrink to
--dock-side-compact (4.25rem), open or closed, but their text labels kept
their full width. Between 721px and 900px, where the desktop dock is still
shown, LOCATION and VISUAL PRESETS spilled over the idle voice control, and
the LOCATION label took taps on the left half of the mic button. The label
clip that existed was scoped to 620px, which the phone shell (720px) always
covers, so it never applied to a visible dock.

In that band the labels are now font-size 0 and lose their chevrons, so
each wing shows only its icon. The label text is unchanged, so the toggles'
"Expand/Collapse ..." aria-label and title, which panelChrome builds from
it, keep the full name. The Cyber HUD layout sets a wider
--dock-side-compact that fits its labels, so it keeps them. The
unreachable 620px clip is removed.

Found in GEV launch-readiness QA (HAL-728).
2026-10-28 20:17:59 +01:00