Commit Graph
380 Commits
Author SHA1 Message Date
Sameh Khamis 5019bd9e8a feat(kit): render the sliders with UiSlider
UiSlider takes v-model, min, max, step and disabled
over Core's native range input, emits numbers, and with `hold` never
rewrites a focused handle and takes the model back on blur. It is a
functional render function, so the portable style parameter rows use it
too. The Display, Radio, RTL-SDR, Cockpit, mission replay and style
parameter sliders render with it; server-rendered markup keeps their
default values.
2026-11-01 11:27:52 -08:00
Sameh Khamis 7f7e66e793 feat(radio): answer the internet radio controls through the radio store
The Radio panel's and Cockpit's Enable, launcher, station tag,
transport and volume controls call RadioControls through the radio
store instead of DOM listeners. A refused station tag gets the kept tag
back from act(), which now returns what the answering action returned.
The Cockpit's station steps keep rotate: false. The unused element
fields go from the shell.
2026-11-01 11:02:39 -08:00
Sameh Khamis 61d11ce369 feat(radio): answer the RTL-SDR card through the radio store
SdrCard calls LocalSdrControls through radio store actions instead of
DOM listeners, and renders its gain options from the receiver's own
R820T gain steps with page-language labels. The display and radio
stores share one owner list (createOwners): the newest connected owner
with an action answers it.
2026-11-01 10:52:50 -08:00
Sameh Khamis e5fa31d01e feat(controls): render every segmented group with UiSegmented
Street Level's fit and panorama filters and Recent Imagery's mode render
through the kit's UiSegmented, and their owners answer the choice
through the Street Level store (setPano, setRenderMode) and the
readout's onSetMode. The imperative segmentedControl.js adapter and its
test go. UiSegmented moves focus at once on a key, a radio group from
the option holding focus and an arrows group from the selection, and
asks for a change only when the key lands somewhere new.
2026-11-01 10:38:25 -08:00
Sameh Khamis 3c3f8e3e67 feat(display): answer the Display controls through the store with UiSegmented
The Display panel, the dock's style buttons and the clean-view exit call
the display store's actions, and DisplayBindings connects their handlers
to it, replacing the bindDisplayControls listeners. The detection
allocation and 3D model coverage choices render through a new kit
UiSegmented, which takes v-model, options, label,
stacked and disabled, and adds a keyboard policy, item classes and
per-option attributes.

Shell element fields and facade accessors that only the old listeners
read are removed. The package boundaries now own UiSegmented and the
UiPanel kit files, and the format scope drops the deleted test.
2026-11-01 09:56:47 -08:00
Sameh Khamis 0adcd61184 feat(first-run): render the mission launcher from a store
initFirstRunExperience no longer writes the launcher card's classes,
attributes and text, wires its listeners or removes it: it presents the
card's visibility, busy state, status line, copy and scroll fade to the
gev-first-run store and connects the controls the welcome view's choices,
DISMISS and "Don't show this again" call. A refused save hands the tick
back to the view to revert. The launcher still reads the rendered card for
its hit test, keyboard trap, focus and overflow measurement.

The owner-chosen copy moves to src/firstRunCopy.js, shared by both. The
source-text tests give way to component tests, and the first-run mutation
QA follows the new code (67/67 caught).
2026-10-31 22:53:03 -07:00
Sameh Khamis c03b4a7643 feat(hud): render the Intel HUD from a store
IntelHUD no longer builds #intel-hud with innerHTML or writes its readouts
by id: it publishes its readouts, typing summary, REC blink, visibility,
layout variant and style colors through its publish option to the gev-hud
store, and the intel-hud application view renders them. The corners render
from mount so the panel layout controllers register them as obstacles.

The vessel layer presents the selected vessel's readout through
src/hudReadouts.js, which IntelHUD follows, instead of writing into the
HUD. The Cyber sonar state answers a HUD toggle from IntelHUD's visibility
rather than the class the view renders on its next update.
2026-10-31 22:18:50 -07:00
Sameh Khamis b96cc37ab5 feat(awareness): render the Global Context compass from a store
The awareness layer presents the compass ring, heading, cardinal labels and
contact bearing markers through subscribeDirectionOverlay(); the application
shell publishes them to the gev-awareness-direction store and the scene
chrome renders them in the viewer's container.
2026-10-31 22:01:56 -07:00
Sameh Khamis b22e138c55 feat(world-overlay): render the visible map target list from a store
The world overlay presents its focusable mirror of painted cards through
subscribeWorldOverlayActions() and answers activateWorldOverlayAction();
the application shell publishes the list to a store and the scene chrome
renders the buttons and the status, announcing a repeated focus again.
The module stays free of Vue for the portable transit entry, and its
canvases remain painting surfaces.
2026-10-31 21:52:32 -07:00
Sameh Khamis 662f51fdf3 feat(annotations): render the screen-space annotation board from a store
The screen annotation renderer keeps each mark's SVG parts as attribute
records and presents the board to a store after every rendered frame; a
view teleports it to the page and hands back the callout text and mark
groups the renderer measures. The tracked-entity fade is measured once
the frame is in the document, removed marks fade out before they leave,
and the styles it injected move to annotations.css.
2026-10-31 21:39:34 -07:00
Sameh Khamis 265aa605bd feat(celestial-ring): render the full-globe ring from a store
The celestial ring presents its overlay to a store and the scene chrome
renders it in the globe container, handing back the two canvases the
ring paints. The application shell passes the store in so the keyhole
helpers other packages import stay free of Vue. Without its canvases the
ring still tracks whether the globe is framed and turns itself off.
2026-10-31 21:20:27 -07:00
Sameh Khamis fd0d51c450 feat(bhote-koshi): render the reconstruction panel from a store
The Bhote Koshi layer keeps its panel controls as plain records and
presents them to a store; the context rail renders the panel as its last
child and marks itself while it is on. Controls are bound to the enable
that published them, and an unchanged frame is not sent again.
2026-10-31 21:12:08 -07:00
Sameh Khamis 9ea6d7e8aa feat(launches): render the replay vehicle overlay from a store
The launches layer keeps the replay state, projection and wording and
presents the replay vehicle overlay through subscribeReplayOverlay(),
sending nothing for an unchanged frame, so the portable launches entry
stays free of Vue. The application shell publishes each presentation to
the gev-mission-replay store and the scene chrome teleports the vehicle,
orbit dot and callout into the globe container with the same markup,
classes, mode, transform, rotation and sonar opacities. Hiding keeps the
mode, place and text, as before.
2026-10-31 20:53:54 -07:00
Sameh Khamis e0bfa471ac feat(wind): render the inspection marker from a store
createWindInspectionMarker() moves to src/layers/wind/inspectionMarker.js,
so the portable ./tools entry that reads wind/inspection.js stays free of
Vue. It keeps the frame listener and projection and presents where the
inspected point falls to the gev-wind-inspection store after each
rendered frame, publishing nothing for an unchanged frame; the scene
chrome teleports the marker into the wind layer's container with the
same class, inline style, hidden state and position. The application
guide lists everything leaving out the scene chrome now leaves out.
2026-10-31 20:47:19 -07:00
Sameh Khamis 0926cbc105 feat(voice): render the pointer reticle beside the voice control
PointerReticle keeps the turn's timers and tool tracking and presents
where the user pointed to the gev-pointer-reticle store, one entry per
reticle; the command dock teleports each to the body with the same
class, aria-hidden, hidden state, target and position. The voice QA
reads the card and reticle after Vue's flush, and the application guide
says leaving out the command dock leaves out the voice control and its
reticle.
2026-10-31 20:36:39 -07:00
Sameh Khamis f9bf782b9c feat(ui): render the FPS readout in the title bar from the status store
createFrameRateMonitor() keeps the key, frame count and interval and
publishes the readout to the gev-status store; the scene chrome renders
it after the subtitle with the same class, hidden state and title. A
page without the title bar still gets no monitor, and a monitor only
updates or withdraws the readout the store shows.
2026-10-31 20:28:24 -07:00
Sameh Khamis e0abf74308 feat(scenes): render the data-pack attribution cards from a store
The data-pack presentations keep the Cesium resources, object URLs and
pick targets and present each pack's attribution card, with its media
player, to the gev-data-packs store; the DataPacks view teleports one
panel per set of presentations into the viewer's container with the same
markup and inline styles, and stops a removed card's player as it goes.
2026-10-31 20:22:22 -07:00
Sameh Khamis 59e3aaa271 feat(scenes): render the Scene actions panel from a store
The scene interactions owner keeps the pick handler and the interaction
session and presents the panel to the gev-scene-interactions store; the
SceneInteractions view teleports it into the viewer's container with the
same markup and inline styles. Each activation keys its own panel, each
button carries the owner it was rendered for, and only the owner the
store shows may change or remove it.
2026-10-31 20:14:35 -07:00
Sameh Khamis f846aaed4c feat(ui): render the page toast from the status store
ShellFeedback and the scene director show toasts through createToast(),
each on its own timer as before, and the scene chrome renders the toast.
Every show rewrites the text, so a repeated message is announced again.
2026-10-31 19:58:59 -07:00
Sameh Khamis 3c391482f6 feat(ui): render the status chips and their split-flap labels from a store
ShellFeedback publishes the loading status and the road network chip, and
CctvControls the camera grid chip, to the gev-status store; the scene
chrome renders them. SplitFlapText plays the departure-board cascade that
splitFlap.js plans, writing only the label's one text node, and rests when
its owner is destroyed. setSplitFlapText and disposeSplitFlap are gone.
2026-10-31 19:51:39 -07:00
Sameh Khamis 492b719f19 feat(ui): render the imagery split dividers from a store
createImagerySplit keeps the divider's value, drag, keyboard, CSS position
and scene split, and publishes its line to the imagery split store.
ImagerySplitView, in the scene chrome, teleports each line to the body, so
recent imagery and the Bhote Koshi event no longer build divider DOM.
2026-10-31 19:35:27 -07:00
Sameh Khamis 1de4f635ca feat(voice): render the voice control from a presenter
createVoiceControl now returns a presenter instead of building the
control with innerHTML: the session, cost, input, card and panel owners
write its state by part and listen for interactions, and VoiceControl.vue
renders it in the command dock, between the location bar and the visual
presets as before. Focus moves wait for the render; the waveform's bars
publish apart from the control and only when they change; the minutes
field keeps a draft until its owner writes it. Owner tests use a real
presenter on their own store, and view tests render the control.
2026-10-31 19:22:03 -07:00
Sameh Khamis 2ffd7a4afd refactor(ui): remove the action button and status badge builders
The Vue views apply the gev-action-button and gev-status-badge classes
themselves, so the DOM builders have no users left. The docs describe the
views instead.
2026-10-31 18:40:25 -07:00
Sameh Khamis 5bf797ef71 refactor(build): place the views in the page instead of expanding templates
index.html now lists each view's host and the loading screen itself, so
the gev:template expansion plugin, its view list, the loading-screen
template and the ./build/html export are gone. createApplication takes
omitViews for views an application leaves out; their hosts are removed,
and a view an earlier call rendered is unmounted.
2026-10-31 17:52:47 -07:00
Sameh Khamis 6802c9c8b0 feat(ui): render every application template except the loading screen as a Vue view
The scene chrome, cockpit, Display controls, command dock, layer panels,
Context rail, welcome card and Provider Settings move verbatim into
src/ui/views and mount into their hosts before the page is translated and
wired. Each view renders the same elements, attributes and text as its
template; Vue keeps whitespace between elements as one space, and no view
markup sits under a white-space: pre rule.

Template asset URLs stay literal, view files are left out of Prettier so
the markup is not reflowed, and the Node component loader moves to build/
and is exported as build/register-vue for host test runners. Hosts that do
not initialize Core's locale pass localePicker: false instead of editing
the markup.
2026-10-30 17:47:52 -07:00
Sameh Khamis 3d5d3ef014 feat(ui): add a desktop panel rail to each sidebar
Each side stack hosts a Vue rail listing its panels; selecting one opens it
through PanelChrome. The shell owns one Vue runtime and Pinia instance, and a
panel store mirrors each side's panels from the DOM. The rail hides with its
stack, in Cockpit, clean view and recording, and on phones. Panels without a
catalog entry get a generic item, and Data Layers leaves the rail while the
f shortcut hides it.
2026-10-30 16:41:29 -07:00
Sameh Khamis 7307c11c74 feat(ui): add the Vue component kit with UiRail, UiTooltip and UiIcon 2026-10-30 16:11:48 -07:00
Said Turksever 38302a27a4 Merge upstream/main into feat/cctv-a22-autobrennero
Resolve conflicts with the NYC, Toronto, Lithuania, Florida, Taiwan and
Kartverket work on main. The CHANGELOG entry moves to
changelog.d/956-a22-brennero-webcams.md, as main now asks.
2026-10-30 14:50:41 +00:00
Said Turksever a370742e25 Merge remote-tracking branch 'origin/main' into ux/context-panel-cleanup 2026-10-29 16:42:17 +00:00
Said Turksever 97b7307b14 Fix the format gate and the Cyber Context styling, and pin the redesign
CI failed at format:check: the format scope still listed the deleted
panelChrome.radioOwnership test, and panelRails.test.mjs needed Prettier
after its glow list shrank.

The new Context title colour outranked Cyber's red panel titles, and the
collapsed Context launcher came out brighter than its siblings; the rule
now applies only to the expanded panel outside Cyber. Cyber's layout-focus
standby card had relied on the old dashed border and centring, so it
drew a 3px frame with its text off the radar art; it now names its own
1px frame, padding and centring. Cyber also drops the shared segmented
track, which drew a third frame around its already framed mode buttons.

Tests now pin the Context header to its title and collapse control, the
segmented control, 10px type, the missing halo and the scoped title
colour, plus the Cyber standby and track overrides. Each fails on the
previous CSS or markup.

qa-radio enables Radio and starts the first Play from the visible
controls, expanding Context and Radio the way a person must, then puts
the panels back. The Escape test and its mutation describe what they
still protect. CURRENT-STATE no longer describes the removed Radio icon
or compact player.
2026-10-29 12:55:47 +00:00
Said Turksever 39a60b4034 Remove the Snow visual preset
Snow is no longer offered anywhere a style can be chosen: the Visual
Presets tray, keyboard shortcut 7, the Cockpit vision carousel, and the
set_visual_style voice action. The shader and its labels go with it;
weather snowfall and the SNOW weather condition are unaffected.

Share links keep working. Snow's enum code (6) stays reserved, so a
compact or long-form link that names it opens on Normal and drops the
Snow shader parameters without reporting them as unknown. A Scene
Director shot saved with Snow plays on Normal too. Snow's frozen share
defaults matched Normal's apart from those parameters, so no other
setting in an old link changes meaning.

The legacy voice-schema pins restore Snow before hashing, so the
unchanged pins still prove nothing else moved; the complete Realtime
payload digest is re-derived.
2026-10-29 11:20:49 +00:00
Sameh Khamis c1f60cb7e7 Cut the Google requests the HUD summary makes on its own
The HUD builds place context for its AI summary whenever the camera
settles, and each build paid for up to four reverse geocodes plus a Nearby
Places search, even when no OpenAI key was configured to use them.

- Ask GET /api/openai/hud-summary/status once; with no summary configured,
  or after an unconfigured reply, make no place lookups for the page.
- Reverse-geocode at most two points: the view center and one viewport
  point.
- Reuse a lookup until the view center moves a quarter of the visible
  width, the camera's distance to it doubles or halves, or the camera
  crosses a lookup height. The reused points are asked again, so only a
  timeout, failure or empty answer spends.
- Repaint the last AI reply when a small pan leaves the context unchanged.

Cached-only hosts and voice context lookups are unchanged.
2026-10-28 14:59:33 -07:00
Sameh Khamis da02fd8645 feat(share): short /share/<code> links with a compact versioned view format (#1418)
* feat(share): add compact versioned share-view codec

Add a standalone codec for `#s=<base64url>` share links: a version byte
followed by protobuf-style tag-length-value fields. Settings equal to
their default are omitted and refilled from the same table on decode;
unknown fields are skipped by wire type, so new fields never break
older apps. Views are a place (camera) or a thing (an aircraft,
military aircraft, vessel or satellite to follow, with camera offset
and last-known fix); an unknown kind falls back to the camera.

The decoder bounds its input and rejects malformed payloads with a
reason instead of throwing. A converter maps the long form's parsed
state to and from the codec state; the long form is unchanged.

* fix(share): tighten codec decoding after review

Unknown detection mode and allocation names now fall back to their
defaults instead of reaching the lenient long-form migration. Future
panel values and style-parameter tokens are skipped rather than applied
or rejected, and layer options are accepted only under their owner
layer. Wrap longitudes before scaling, normalize negative zero, reuse
the layer-state tracking ID grammar, and align the format doc with the
decoder.

* feat(share): let a host share the link its own way

ShareLinkManager.buildLink() returns the current share link without
copying it, and copyLink() now copies exactly that. The share button
passes the link to an optional services.shareLink(url), which resolves
to 'shared', 'copied', 'cancelled' or false; 'cancelled' shows no toast
and 'shared' shows the new "Link shared" (es, ru, zh-CN). Without the
service the button copies as before.

* feat(share): open and make short /share/<code> links

The share button now makes `<app>/share/<code>` links with the compact
share-view code, and the app opens them at start-up through the same
restore pipeline as long links. Once the app next writes the address, the
share path is replaced (no new history entry) by the app's own address and
the live long-form hash, so a reload follows the live view. A host can pass
the code as `initialShareCode` instead. A code that fails to decode restores
nothing and shows "This share link can't be opened".

The code gains a trailing CRC-8 check byte, so any single mistyped
character is rejected instead of opening a different view. Thing views no
longer store a camera: it is derived from the entity's last-known fix and
the follow offset on a sphere, the entity kind is implied by the id's
field, and the followed entity's layer bit is implied; an aircraft followed
from the app's own camera is a 42-character code. The `#s=` hash form is
gone.

While the camera follows an aircraft, military aircraft or satellite, the
link is a thing view with the camera's offset and the entity's position.
Opening one turns the layer on and follows the entity through the existing
shared-follow restore, then swings the camera round to the shared offset; a
vessel view selects the vessel once the vessel feed has it. If the entity
is not reporting within its window, the view stays at its last-known fix
and says so. The panel and style-parameter tables now come from the codec,
and a host share hook that returns a plain value or throws still gets a
toast.

* fix(share): encode style settings against the style's own look

Settings a style applies when selected (bloom, sharpen, HUD, detection,
celestial ring and the style's shader parameters) now default, per field,
to what that style applies in a fresh session, read from the tables the
app applies (the first-load baseline, the style presets and the shader
defaults). The encoder compares against the view's style and the decoder
fills omitted settings from the decoded style, so a view that keeps its
style's look costs only its camera and style. The previous defaults did not
match a fresh session (sharpen, HUD and detection were off), so every link
paid for them, and a style's own shader parameters were always written.

A test pins the per-style defaults as frozen v1 meanings. A followed
aircraft in Noir is now 44 characters and the real long-link example 39.

* docs: changelog for #1418
2026-10-26 15:31:51 -07:00
Sameh Khamis c533b1994c Merge main and preserve voice panel and GhostMaps schema coverage 2026-10-26 08:52:03 -07:00
Sameh Khamis 074e272356 fix(voice): recover idle timers and retire panel audio observers 2026-10-26 08:42:41 -07:00
Mazeyar Moeini Feizabadi 4da002bd42 Merge current main into S2 GhostMaps and preserve updated import and voice behavior 2026-10-26 16:25:49 +01:00
Mazeyar Moeini Feizabadi 4a18af5426 fix: address GhostMaps resource and source ownership review findings 2026-10-26 16:24:34 +01:00
Bilawal SidhuandBilawal Sidhu a3a19883b4 feat: add Scope controls and conditional HUD text backplates (#1410)
* feat: add scope controls and conditional HUD backplates

* docs: assign scope changelog to PR 1410

* fix: stabilize title backplate and brighten secondary labels

---------

Co-authored-by: Bilawal Sidhu <[email protected]>
2026-10-26 00:24:27 -05:00
Rudy Mizrahi Celekli a15fdd3134 fix(hud): carry rounded DMS seconds into the minutes (#1339)
Carry rounded HUD coordinate seconds into minutes and degrees.

Contribution by @rudycelekli.
2026-10-25 17:59:09 -07:00
Sameh Khamis 2006c035d9 chore: remove four modules nothing in the app uses (#1403)
* chore: remove four modules nothing in the app uses

src/app/sourceSlot.js re-exported src/sources/sourceSlot.js, which every
caller imports directly. src/data/flowTiles.js and src/data/issPass.js were
reached only by their own tests. src/data/localGeojson.js wrapped
localGeojsonCore.js with the app's services, which the catalog already
passes itself. The local GeoJSON layer tests now build layers the way the
catalog does, so they keep covering localGeojsonCore.js; only the test of
the wrapper's own default host goes. Boundary lists, format scope and docs
drop the removed paths.

* docs: changelog for #1403
2026-10-25 17:21:41 -07:00
Said Turksever 60ec1f962b Merge branch 'main' into codex/fix-hidden-tab-polling 2026-10-24 23:51:23 +01:00
manjunath22466 b2fb4a261e feat(camera): add globe rotation (#1225)
Add continuous globe rotation with direction and speed controls, viewport fit checks, camera ownership handoff, and voice refusal guards.
2026-10-23 14:51:42 -07:00
Said Turksever be44f523e0 Merge remote-tracking branch 'origin/main' into fix/1282
# Conflicts:
#	docs/CURRENT-STATE.md
2026-10-23 12:09:26 +01:00
Sameh Khamis 504f9342aa chore: remove unreachable legacy entry modules
Delete three modules that no entry point, package export, test or script
imports:

- src/ui.js, a StyleManager subclass that pre-selected the standalone
  catalog. Application controls are built through src/app/controls.js
  and src/standalone/controls.js.
- src/standalone/ui.js, a bare re-export of StyleManager.
- src/data/localLayers.js, a list of default infrastructure, cable and
  FIRMS layer instances. The catalog builds these layers itself.

With src/ui.js gone, the import-direction check keeps a single
compatibility exception (server/providers/local.js to
server/standalone/key-setup.js), and its test now asserts that a
src/ui.js importing standalone code is rejected. The boundary and
format registries and the docs that named these files are updated.
2026-10-22 18:53:56 -07:00
Said Turksever 5b63bd5f7f Merge branch 'main' into codex/fix-docker-trusted-peers 2026-10-22 22:51:20 +01:00
Mazeyar Moeini Feizabadi d5c49d35e8 Merge latest main into S2 GhostMaps contribution 2026-10-22 02:41:26 +02:00
Sameh Khamis 3e80afe713 Pin camera sources by parsed URL
Camera catalog image URLs were pinned by string prefix, so a URL that only
began with the agency's directory before dot segments or an encoded separator
were resolved still counted as inside it. The pin now parses the URL and
requires the same scheme, the exact host, no credentials, the default port and
a normalized path inside the pinned directory. Redirects on a pinned host must
stay inside the same directory.

Document the response format checks and API response headers alongside the
existing server hardening notes.
2026-10-21 15:07:40 -07:00
German Khokhlov a1a9a36f54 Merge remote-tracking branch 'origin/main' into claude/hal-627-starfield-cb6fa2 2026-10-21 21:39:46 +04:00
Said TurkseverandClaude Opus 5.5 82c722e6af chore(format): keep format-scope in step with main
Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-21 17:40:49 +01:00
Said TurkseverandClaude Opus 5.5 eaf14e2937 Merge branch 'main' into codex/fix-docker-trusted-peers
Resolve scripts/format-scope.json by keeping both sides.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-21 17:39:47 +01:00