Commit Graph
1154 Commits
Author SHA1 Message Date
Sameh Khamis d0ef3a902b Drive the visual styles, bloom and sharpen through the effects port
VisualEffects defines each preset on the renderer and keeps its own
records of intensities and parameters, written through to the port, so
crossfades, the anime sky fade, bloom and sharpen behave as before. The
renderer animates the animated styles. Sensor picks read the style
records instead of the renderer's stages. The application renderer now
has the effects port and its capabilities.
2026-11-06 16:32:49 -08:00
Sameh Khamis 9f165e68f3 Move the stub's geodesy into a renderer-neutral src/geo
WGS84, ECEF and geodetic conversions, surface normals and east-north-up
frames, as plain {x, y, z} objects, exported as ./geo. A test checks
them against Cesium over random points and the poles. The stub's maths
re-exports them and keeps only the camera angle conventions.
2026-11-05 13:49:53 -08:00
Sameh Khamis 2fc99e7c19 Define the renderer contract, with a stub renderer and a conformance suite
The renderer contract is what the application asks of a 3D renderer, so a
renderer other than Cesium can draw the same application. It is nine ports
(frame, globe, draw, camera, query, input, effects, credits, quality) plus
the renderer itself, one strict .d.ts per port in src/render/contract/.
PORTS lists every member at run time, and a TypeScript-compiler test fails
when the list and the types disagree on one member. An optional member
exists only with its capability; a required one answers null or empty
without it. Nothing in the application uses the contract yet.

The stub renderer (src/render/stub/) implements every port in memory and
draws nothing. Its camera is a port of the default camera's maths: views,
lookAt, flights with their height arc and easing, rectangle framing on the
geodesic midpoint, the view rectangle with its horizon and pole cases,
changed thresholds, follows, and flights that finish inside the call.

The conformance suite (src/render/conformance/) runs 59 checks against
any renderer through the contract alone, in Node or in a browser page. The
camera checks compare traces recorded from Cesium's own Camera, headless on
a virtual clock (scripts/record-camera-goldens.mjs), to 1 mm, 1e-9 and
1e-3 px. The other checks cover listener rules on every subscription, the
frame loop, draw sets, picks, motion clocks, heights, leases, imagery,
styles, credits and quality knobs. The stub passes all of them but the
model check, which needs a glTF asset.

Reference scenes draw one scene per primitive family, a city and a
calibration path from orbit to the street, from contract calls only and
with no network. /dev/conformance/ draws them on the Cesium scene renderer
(src/render/cesium/sceneRenderer.js), records references through a
dev-server-only, loopback-only endpoint, and compares captures with
pixelmatch's antialias detection plus a solid-pixel count. Measured on
Cesium: every MSAA setting passes, and a dropped 4 px point, a dropped 2 px
line and a 1 px shift of the view fail. visual.js states the limits.

The package exports ./render/contract, ./render/stub and
./render/conformance. Documented in docs/RENDERER-CONTRACT.md,
docs/CODE-BOUNDARIES.md and docs/CURRENT-STATE.md.
2026-11-04 14:21:48 -08:00
Sameh Khamis fb30287898 Draw the last native world labels through the label overlay
The Directions A and B letters and a data pack's media label were the two
Cesium text labels left, kept by an allow-list in noCesiumLabels.test.mjs.
Both now publish entries to the shared world-overlay host, and the
allow-list is gone, so any Cesium label in src is a test failure.

Directions publishes the letters to the directions-markers source; the
markers keep only their points. A clicked endpoint's letter hangs over the
surface that was clicked. One placed without a click stays hidden until its
ground-floor cell resolves, then requests a render, so a still camera shows
it; a cell that settles with no height falls back to the ellipsoid. Each
position is computed once.

A pack resource handle gains label(entry). The application passes its
shared overlay host to SceneDirector through dataPacks.overlayHost; without
one a media pack fails to load rather than drawing a native label. Each
labelled resource takes a source from a pool and returns it on dispose, as
the host never removes a source, so two presentations of one pack never
clear each other's labels and repeat loads add no sources. A label written
after dispose is ignored. The media label is protected, so it always draws
as before.

Live (Denver, keyless globe): a clicked A and a programmatic B both anchor
on their dots over 1.58 km ground. Documented in docs/CURRENT-STATE.md and
docs/DIRECTOR-DATA-PACKS.md.
2026-11-04 12:30:31 -08:00
Sameh Khamis ad8adc85f4 Replace Cesium monkey-patches with hooks and keep internals in one module
The arrival ground guard replaced camera.flyTo, flyToBoundingSphere,
setView, lookAt and cancelFlight with wrappers so a direct caller would stop
it. It now remembers the pose it started on and, before each retry, yields
if a flight is under way or the camera has moved across the ground, down or
around. A straight rise is not a move: Cesium's terrain collision lifts a
buried eye that way as tiles load, which is the case the guard exists for.
This also catches owners the wrappers missed (a pose written directly,
lookAtTransform), and no camera method is replaced.

Recent imagery and weather overwrote provider.requestImage (weather also
provider.credit) to ration tiles. They now state that policy as a hook with
withTileRequestHook(provider, { requestImage, credit }) from
src/render/cesium/tileRequests.js, which hands Cesium a provider delegating
to the original and leaves the original untouched.

Every private Cesium field Core reaches goes through a named helper in
src/render/cesium/internals.js: the main and offscreen pick views and their
command extents, a billboard's collection, a cluster's point collection,
the widget's render-loop latch, the WebGL context and the current camera
flight. internals.test.mjs fails when the installed Cesium stops declaring
one of them, and a source scan fails on private access anywhere else. The
cyber sonar's primitives.update wrap stays until the effects work.

Live (Austin, keyless globe): a buried eye is lifted to 253 m over a 133 m
surface; a setView or flyTo by another caller makes the guard yield; radar
loads its tiles through the hook. Documented in docs/APPLICATION.md and
docs/CURRENT-STATE.md.
2026-11-04 11:15:35 -08:00
Sameh Khamis b51f1bf7c5 Take pointer input through one dispatcher per scene
Every layer and tool bound its own ScreenSpaceEventHandler and picked the
same click again: with the usual layers on, one click ran about 26
scene.pick and 2 drillPick passes (120-215 ms in NYC with 18 layers). Pointer
input now comes in through src/input/dispatcher.js, one handler per scene.
A click is picked lazily and at most once per kind of query, and every
subscriber reads the same ClickEvent (pick, hit, id, ownerId, gesture,
drill, ground). The same click now costs 3 picks and 2 drills, 17-70 ms.

- Ambient onClick subscribers run only while no tool holds the pointer,
  checked once per event; tools subscribe with their lease. Moves and
  releases always reach ambient subscribers, so hover and drags end cleanly.
- Camera input and the viewer's stock select/track clicks are ref-counted
  holds (suspendCamera, suppressStockClicks). The dispatcher owns the
  controller's enableInputs, so a Cesium flight that ends no longer turns
  input back on under a drag or the cockpit.
- The draw tool, imagery box, CCTV gizmo, cockpit, directions and every
  selecting layer use it; bindTrackingClickGesture is gone (the gesture is
  on the event). A source scan forbids new handlers, enableInputs writes and
  stock-click removal outside the dispatcher.
- The sensor-style pick correction transit had now applies to every layer.
- Radio's 8-pick near-miss ring is one 17x17 windowed drill.
- A missed pick passed to pickContact is no longer picked again, and a
  touch tap's contact search shares the click's drill.
- A gizmo drag whose release Cesium never reported ends on the next press
  instead of leaving the camera held.

The dispatcher is exported as ./input with the pointer-lease functions, and
documented in docs/APPLICATION.md.
2026-11-04 08:48:51 -08:00
Sameh Khamis 07c8d7a17c Keep ALPR marker state in a layer store instead of on Cesium entities
The ALPR layer's private per-entity fields (record, clamp, canvas and display
anchors, wedge, native appearance, pick position, shown, surface check) move
from gevAlpr* expandos into alprMarkers, a store made by the new
createEntityStore(). The shared entity records are built on the same factory.
2026-11-03 08:24:33 -08:00
Sameh Khamis 95c0070412 Keep tracked-entity state in Core records instead of on Cesium entities
Flights, military, satellites, installations, local ADS-B and ALPR hung
gevTrackedId, gevDisplayPosition, gevVisualPosition, gevSelectionOrigin and
gevLabelModel on the Cesium entities they draw, and the tracked readout,
follow camera, cockpit, share links and awareness read them back. They now
live in src/data/entityRecords.js, a Core-owned record per entity: layers
write entityRecord(entity), readers use readEntityRecord(entity). Nothing
changes on screen. This is the first slice of the renderer plan's state
mirror (P1).

The module is exported as ./data/entity-records so hosted code can read the
same records, and window.__godsEyeView.entityRecords gives the QA scripts
the same access from the page.
2026-11-03 08:09:00 -08:00
Said Turksever 3afbd0c638 Merge branch 'main' into fix/d-military-positionless-rows 2026-11-03 15:28:59 +00:00
Said Turksever 34906c9abb Merge branch 'main' into codex/overpass-admission-review-fixes 2026-11-03 15:07:08 +00:00
Said Turksever a6d20120a7 Merge upstream main into PR #1435 for integration review 2026-11-03 14:50:23 +00:00
Said Turksever 8e40d2689b Merge branch 'main' into prereq-10-osm-overlays 2026-11-03 14:34:32 +00:00
German Khokhlov c664f8eacb Merge branch 'main' into upstream/terrain-partial-heights 2026-11-03 15:28:20 +04:00
German Khokhlov be53c338c8 Merge branch 'main' into upstream/terrain-partial-heights 2026-11-03 14:59:12 +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 ab8691383b docs(hud): describe the character-only summary cap and trim comments 2026-11-03 14:34:32 +04:00
German Khokhlov 238a3d0634 Merge remote-tracking branch 'origin/main' into fix/hal-722-radio-next-no-autoplay 2026-11-03 14:33:12 +04:00
German Khokhlov 81ffa5b663 Suspend the tuner noise context once a pending resume settles
A dial click shorter than the device start-up let suspend() run on a still-suspended context, so the later resume() left it running with no nodes. Cover paused, connecting and voice-fallback releases in radioNextState tests.
2026-11-03 14:32:55 +04:00
German Khokhlov 33381c5981 Merge remote-tracking branch 'origin/main' into german/hal-623-hud-summary-locale
# Conflicts:
#	src/voice/gevActions.test.mjs
2026-11-03 14:28:10 +04:00
Sameh Khamis b9f3dd649e merge feat/voice-outlines 3ac3499e into the review fixes 2026-11-02 13:14:02 -08:00
manjunath 3ac3499e4a merge main 43a67f9 into feat/voice-outlines 2026-11-03 00:26:40 +05:30
Said Turksever bd7ef69843 Merge branch 'main' into prereq-10-osm-overlays 2026-11-02 17:48:19 +00:00
Said Turksever c35eba1704 Merge main into prereq-10-osm-overlays 2026-11-02 17:27:07 +00:00
Sameh Khamis 64c9f4cfa5 let building words pass only on single-structure results
A building word ending the ask ('… Chapel', '… Library', '… Hall') now
passes the last-word rule only when the result is one a building ask
would accept, so a campus, zoo or district whose name merely starts the
ask (Duke University, Old Town) no longer answers it.
2026-11-02 09:07:31 -08:00
Sameh Khamis c059e12a11 merge main 17daf897 into feat/voice-outlines 2026-11-02 09:06:21 -08:00
Sameh Khamis 0712db9891 address the final review of the voice outline fixes
- A building word ("Burj Khalifa Tower", "Sagrada Familia Church") passes
  the last-word rule on a building-like result; enclosures stay out.
- The anchor chooses only among the best-named outlines, so a worse name
  never wins by containment alone.
- An ask without a quadrant takes only the quadrant of the matching street
  nearest the point; a leading quadrant ("SE Main St") may go unsaid too.
- On an unbuffered tile edge a fragment shows as an edge along the
  boundary, so a whole building touching it at a corner is not cut.
- Drop two orphaned comments and correct the place-name key wording.
2026-11-02 09:03:36 -08:00
Said Turksever f38961ef1e Merge main into the Utilities panel 2026-11-02 17:01:52 +00:00
Said Turksever 672a145254 Keep Contact folded until both Cockpit left panels close, and keep focus in a renamed row
Opening Utilities while Data Layers is open no longer forgets that Contact
was folded for the first, and closing one of them leaves Contact folded
while the other is still open. Enter and Esc in a drawn shape's name keep
focus in the field instead of dropping it to the page. The draw tool's
destroy test now checks it stops following the board, and the Draw gate's
amber-count comment sits on its function again.
2026-11-02 17:01:31 +00:00
Sameh Khamis a61d0f4c2a tighten the remaining voice outline review items
- One place-name key for server and tiles, so "St. Paul" and "Saint Paul"
  agree in Nominatim name checks.
- Tile street names: a lone letter is a direction only beside another name
  word ("E Street" is not "East Street"), and a trailing quadrant ("E St NW")
  may go unsaid in the ask.
- A building cut at the tile edge that is nearer the point than any whole
  one leaves the point instead of a farther neighbour standing in; an edge
  without a tile buffer counts as a cut, so a cut area never answers grounds.
- A batch building install re-judges only results that installed; a late
  timeout during caption conversion keeps the pending point drawn; a failed
  plain recaption keeps the old mark addressable.
- An interrupted Nominatim dispatch is reclaimed by the next lock owner ten
  minutes after the start its marker names; node:sqlite loads on first use
  without its experimental warning.
- PHOTON_URL accepts only https, which the page's connect-src allows.
- Shared OpenFreeMap tiles decode each layer when a consumer first selects
  it; outline selection reuses the shared ring area and simplification, and
  ground probes the shared ring centroid; the grounds word list lives once.
2026-11-02 08:50:05 -08:00
Said Turksever 4ebb287d36 Merge main into the Utilities panel, rebuilt on the Vue panel rail
main moved the panels to Vue views and a one-open-panel rail, and removed
the two templates this branch edited. This merge carries the branch onto
that architecture; it adds no behaviour of its own beyond the port.

- The Utilities panel is a RailPanel in LayerPanelsView with its own rail
  item (handyman). LayerPanel renders the Directions rows into its list with
  LayerRows, and falls back to Data Layers without it.
- Draw leaves DisplayPanel for DrawControls, DrawMarkList and DrawSwatches,
  which render what the draw tool publishes to the display store and call
  its actions, as GeoImport does. drawMarks.js words the rows; the DOM-built
  drawMarkList.js is gone. A row's fly-to is an immediate navigation like
  Import's ('drawing' gets its Cockpit refusal), the name field keeps a
  draft through v-field-value, and the colours are one radio group with a
  single tab stop.
- UiSegmented draws an option's icon, named by its label, for the shape
  buttons.
- The catalogs take main's languages with this branch's strings, Arabic
  included, and the tests follow the views to their new homes.
2026-11-02 16:43:29 +00:00
Sameh Khamis a38a065c5c keep bent streets, enclosed landmarks and same-name outlines honest
A street ribbon that holds neither its ring mean nor the anchor is centred
on the street's nearest point when the street runs within 100 m.

Nominatim outline selection ranks an exact name, then one holding every
asked word, then an overlap, and refuses an overlap whose name lacks the
ask's last word unless that word is in the result's address or type, so
"Central Park Zoo" is no longer Central Park. The server caches every
accepted outline and answers each ask with the one holding its resolved
anchor (sent as alat/alon), read across the antimeridian.

A duplicate mark that fails to clean up no longer tears down the new
outline it duplicates.
2026-11-02 08:37:45 -08:00
Said Turksever fc7ff1055c Split Open Map Overlays into Sea Marks and Ski Pistes layers
Each overlay is now its own Infrastructure row instead of a chip on one
shared row: sea-marks (token 6) and ski-pistes (token 7), both
enabled-only, built by createOsmOverlayLayers() from one descriptor
list. Drops the option group and its share-codec defaults, gives each
layer its own name, voice entry and CURRENT-STATE row, and shifts the
token-ledger fixtures to the next free digit 8.
2026-11-02 16:20:08 +00:00
Sameh Khamis d411802d8c Merge branch 'main' into fix/node-24.22.1-security-release 2026-11-02 08:05:41 -08:00
Said Turksever ce1ad3b95a Merge main into prereq-10-osm-overlays and port Open Map Overlays
Main moved on since this PR opened; the overlay layer is ported to the
current contracts:

- Layer-state token 6 (j belongs to transit; new single-character
  tokens are digits) with a reservation-ledger row, and the option owner
  renamed to the layer id so the compact share codec can encode it.
- Constructed per catalog by createOsmOverlaysLayer() in
  constructCatalog.js; src/standalone/data.js no longer registers layers.
- Drapes through maps/imageryHost.js, so the overlays show on Google 3D
  (tileset imagery) as well as the globe stacks, and follow map-stack
  switches. Imagery layers are created on enable and destroyed on
  disable/destroy.
- Translated chip labels and layer name in every locale, LAYER_NAME_KEYS,
  Infrastructure panel group, voice manifest entry.
- Attribution: OpenSeaMap tiles CC BY-SA 2.0, OpenSnowMap credit as
  required, OSM ODbL credit for both; bulk-download note in DATA_SOURCES.
- CURRENT-STATE row, changelog fragment, share-codec absent defaults,
  updated token-ledger fixtures and voice schema pins.
2026-11-02 15:55:40 +00:00
Sameh Khamis a50a61a0c7 Merge branch 'main' into denis/hal-728-dock-icon-only-wings 2026-11-02 07:45:21 -08:00
Sameh Khamis d646fdbe60 Pin Node 24.22.2, the current 24 LTS patch, keeping 24.22.1 as the security floor 2026-11-02 07:39:02 -08:00
Sameh Khamis 5b76a8a40b Merge branch 'main' into security/cross-site-gate-overpass-military 2026-11-02 07:36:10 -08:00
Sameh Khamis cb6a0e9008 Merge branch 'main' into fix/node-24.22.1-security-release 2026-11-02 07:35:05 -08:00
Sameh Khamis 26f668844e Merge branch 'main' into fix/multipart-cable-feature-ownership 2026-11-02 07:17:56 -08:00
Sameh Khamis 799273b301 Test the installations gate with the Overpass proxy tests, drop the stray PR body, and correct the fragment 2026-11-02 07:17:39 -08:00
Sameh Khamis e9c6f2541f Drop the gap beside the icon-only dock wings, point the state doc at the Vue dock, and credit the author 2026-11-02 07:17:18 -08:00
Sameh Khamis 2c007a4ace Merge branch 'main' into denis/hal-728-dock-icon-only-wings 2026-11-02 07:09:23 -08:00
Sameh Khamis 16756bb790 Align the doctor, state doc and bug template with the 24.22.1 pin, and credit the author 2026-11-02 07:06:14 -08:00
Sameh Khamis 8a23328ed1 Describe multipart cable ownership by behaviour and credit the author's handle 2026-11-02 07:06:11 -08:00
Sameh Khamis 0b5a207049 Merge branch 'main' into fix/node-24.22.1-security-release 2026-11-02 07:02:37 -08:00
Sameh Khamis c1b12a6aa4 Merge branch 'main' into fix/multipart-cable-feature-ownership 2026-11-02 07:00:05 -08:00
Sameh Khamis b17fe2b11c Merge branch 'main' into fix/e-bikeshare-derived-capacity 2026-11-02 06:58:29 -08:00
quanticsoul4772 468d5078e3 Merge branch 'main' into upstream/terrain-partial-heights 2026-11-02 06:50:47 -08:00
German Khokhlov 818d2c8295 fix(hud): keep localized summary words whole and drop padding
- The proxy keeps combining marks, in-word apostrophes and name dots
  (ar vowel signs, fr d'Orléans, ja ・), normalizes to NFC, caps every
  summary in characters and cuts at a word boundary.
- feedState is nullable instead of a `none` token, and the summary has at
  most five words: "exactly five" made the model pad short views with
  "no data" or "unavailable".
- The HUD caches only the model's words and adds the current warning on
  every paint; an RTL locale gets a leading right-to-left mark.
- The echo check also rejects an all-Latin reply in a non-Latin language,
  translated layer ids and, with every feed healthy, the UNAVAILABLE word;
  places are matched by word and one-word layer names are skipped in
  Latin-script locales.
- The warning tag names the worst layers first; a partial analyst card
  shows one partial chip.
2026-11-02 13:44:53 +04:00
German Khokhlov 857b007fb1 Keep the Radio tuning dial silent unless a stream is playing
Releasing the tuning dial always started the chosen station, plus tuning
static, even when nothing was playing. It now follows the Previous/Next
rule: the release plays only if a stream was loading, buffering or playing
when the drag began; otherwise it just selects the station.

The privacy note no longer lists finishing tuning as a way to connect and
now names voice instead, in all locales. Docs, changelog and comments are
tightened to match.
2026-11-02 13:27:55 +04:00