Move the Cartesian3/Cartographic/Matrix4/Transforms/Ellipsoid/Math calls of
the second batch (cockpit camera, context and controller; camera orientation
controls; application shell; location navigation; the annotation resolver
and engine; voice actions and pointer pick; the scene director; the embed
app) to src/geo. Behaviour is unchanged: same argument order, same `result`
semantics.
Kept on Cesium: out-of-scope classes (HeadingPitchRange, BoundingSphere,
Intersect, EllipsoidalOccluder, EasingFunction, SceneTransforms, JulianDate),
WGS84 where it goes into pickEllipsoid or EllipsoidalOccluder,
Matrix4.IDENTITY handed to lookAtTransform, and the Cartesian2 window
positions that reach scene.pickPosition: Cesium keys its per-frame pick
cache on windowPosition.toString(), which a plain object would collapse to
one "[object Object]" key.
The Contacts-subject harness in gevActions.test stubbed
Cesium.Cartographic.fromCartesian to place its subject; it now builds a real
subject position at the same coordinates with geo.cartesian3.fromDegrees.
The cockpit-controls and scenes package-boundary groups now own the src/geo
files.
Move the Cartesian3/Cartographic/Matrix/Quaternion/Transforms/Math calls of
the first batch (src/data motion, anchor, tracked-camera and icon helpers;
the root camera, locations, HUD, share-link, world-focus, ground-guard,
orbit and cloud modules; services/groundSnap) to src/geo. Behaviour is
unchanged: same argument order, same `result` semantics.
Kept on Cesium: out-of-scope classes (JulianDate, Axis, HeadingPitchRange,
BoundingSphere, Rectangle, EasingFunction, EllipsoidalOccluder with its
WGS84 and seed vector, SceneTransforms) and Matrix4.IDENTITY wherever it is
handed straight to a Cesium camera call (locations.test pins its identity).
synthesizeForwardKinematicsFix now returns a plain position, so the two
snapshot renderers clone it with the static Cesium.Cartesian3.clone instead
of the instance method. The package-boundary groups that reach these
modules now own the src/geo files.
An engine-neutral port of the CesiumJS 1.138 core maths gev uses: angle
maths, the WGS84 ellipsoid and geodetic coordinates, 2D/3D vectors, 3x3/4x4
matrices, quaternions and local east-north-up / heading-pitch-roll frames.
Formulas and operation order match Cesium, so outputs are bit-identical
(golden tests pin the centre, pole, -0 and quaternion branches).
- Values are plain-data instances of module-private constructors (own
enumerable fields only), so geo's hot functions keep their own V8 hidden
classes; matrices are plain column-major arrays Cesium accepts.
- Cesium's debug argument checks are ported with the same conditions, order
and DeveloperError messages, gated on DEBUG (src/geo/debug.js): on in Node
and the dev server, folded away by vite build, as Cesium's Build strips
them. A release-parity test compares DEBUG=false geo with Build/Cesium.
- The import-direction check forbids cesium and @cesium/* in src/geo;
CODE-BOUNDARIES.md and THIRD_PARTY_NOTICES.md document the port.
The test's access stub matched a forward-slash suffix, so on Windows the resolver's backslash path never matched and it fell back to PATH. The stub and the expected value now use the same path.join result. The Windows CI job also runs this test file now.
Co-authored-by: Sameh Khamis <[email protected]>
The horizontal offset multiplied elapsed time by a sine, so flakes swung faster the longer the app ran. It is now the integral of the intended sway velocity, which stays bounded at any session age; Wind still scales the amplitude.
Co-authored-by: Sameh Khamis <[email protected]>
Exclusive presentation hides collapsed right-rail panels with display: none.
Skipping every display: none panel also skipped those, so panels the rail had
auto-collapsed stayed collapsed after the HUD was hidden or left Tactical.
Only panels hidden by other CSS are skipped now. Adds the changelog and
current-state notes.
- Pin finiteCoordinate helper behavior across numeric, non-finite, and string inputs
- Verify recovery stage downrange distance, flight numbers, and coordinates fall back safely to null on non-finite data
- Pin recovery status transitions for LOST and EXPENDABLE stage categories
- Verify payload massKg and amount normalization edge cases for blank, negative, and non-numeric values
- Guard against legacy pack bootstrap during unreadable storage recovery
- Report failed saves honestly across captures, updates, and imports
- Resolve default scene id correctly when advancing past a specific shot
- Count unique scenes executed rather than queued shots in run telemetry
- Return run failure status when playback throws instead of false success
- Pin five regression scenarios in src/scenes/director971.test.mjs
This branch moved twice at once: upstream merged KartaView (#1121, a
third keyless street-level provider sharing a new lineCoverage.js), and
the remote i18n-spanish gained the whole-interface translation work
(1993 catalog entries, translateKnown, data-i18n-runtime, the unmarked-
string detector in npm run i18n) built on the Street View merge.
Integration keeps the remote's mechanisms and re-adds KartaView on top:
- presentMeta: remote's translateHint for coverage hints, plus the
KartaView count line as its own literal tn pair (Russian plurals need
the noun inside the template; keyed off coverageLabel.noun with the
sequences pair as the default).
- uiState: upstream's highlightsSequence legend gate (KartaView's lines
do not highlight) with t('Selected').
- layer-panels.html: remote's data-i18n/data-i18n-runtime hooks plus the
sl-since-note wiring KartaView's upload-date SINCE note needs.
- kartaview viewer: the photo-navigation aria-label and img alt go
through t(), as the remote's unmarked-string detector requires.
- catalogs: remote's 1987-entry base (its refined keys supersede this
branch's earlier Street View wording) plus the KartaView entries:
coverage hints, the upload-date note, the streets count line (with
Russian one/few/many/other forms) and the viewer strings.
npm run i18n: complete, no unmarked strings. npm test: 6520/6522 (the
one failure is the pre-existing environmental OPENAI_API_KEY leak in
devFreshDotenv). Build passes.
Upstream's KartaView PR (#1121) extracted the Mapillary coverage engine
into a shared lineCoverage.js and made the panel wording
provider-specific (coverage noun/action, SINCE upload-date note,
highlightsSequence legend gate), again in the regions this branch
localizes.
- mapillary/coverage.js: taken as upstream's thin re-export of the new
lineCoverage.js; the generic too-high hint stays msg()-marked, now in
lineCoverage.js where the default lives.
- kartaview/policy.js: coverage hints (tooHigh, noCoverage) marked as
msg() data so they translate like every other coverage hint; thrown
error messages stay English, matching the Mapillary precedent.
- presentMeta: KartaView counts streets, and Russian plurals need the
noun inside the template, so the count line gets its own literal tn
pair keyed off coverageLabel.noun, falling back to the sequences pair;
upstream's noun/action data contract is untouched.
- uiState legend: upstream highlightsSequence gate with t('Selected');
sinceNote localized with a {names} placeholder.
- layer-panels.html: sl-since-note wiring kept, data-i18n hooks kept.
- CHANGELOG: both sides kept. es/ru: 4 new keys each.
npm run i18n complete (953 messages each); npm test 6504/6506 (the one
failure is the pre-existing environmental OPENAI_API_KEY leak in
devFreshDotenv, unrelated); build passes.
The selected fire card read "4.9 MW" and "8.389°S 44.162°W" in every
language; it now uses the locale's decimal separator and hemisphere
words ("4,9 МВт", "8,389° ю. ш."). The data labels stay as they were.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The round-3 verification found the shared point budget rebuilding a dense
tile by removing its lines before the new ones were built, so central
Paris vanished for 1–2 s after every pan:
- Tiles redrawn for a new share, or for a selected line the cap had left
out, go through the swap path: the old lines stay until the new ones
are ready.
- A share must move by 10% to redraw a tile (a 1.6% change rebuilt it).
- The selected line, admitted past the cap, is not counted against it,
so its tile no longer redraws on every settle.
- A selection the imagery filter hides is not redrawn for.
- Shares are recomputed when a refresh ends loading without a tile
finishing.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
KartaView's later viewer changes are carried into the shared
photoViewer.js: the camera bearing (`bearingOf`), redrawing the same
photo after a GPU reset through `onReopen`, no pose while a lost context
recovers, the 2,560 px flat version only once the viewer outgrows
1,280 px, `refreshPose`, and one sharper-panorama load at a time with a
second look once it lands. Its tile cache's `keyOf` and `clear` move to
the shared tileCache.js. KartaView gets `onEscape` beside `onReopen`.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A final review of both PDFs found text the earlier checks missed:
- Map cards: fire confidence (high/nominal/low) and age (24h), vessel
types (TOWING, TANKER) and installation classes (BASE, AIRFIELD) showed
in English. They now go through the catalog; the data stays English.
- The wind readout kept "10-14 14:00 UTC" and "29.93°N 97.74°W"; it now
uses the locale's date, decimal separator and hemisphere letters.
- Catalog: one term per concept (label/подпись, basemap/подложка,
PROVIDER CONTROLS, HEARD, zoom in, REGIONAL NEWS), calques and broken
grammar in the scene editor, provider settings and Bhote Koshi notes,
and Spanish wording that read wrong ("restringidas por el proveedor",
"Incluye … no se incluyen", "justo ahora", "Sal").
Co-Authored-By: Claude Opus 5.5 <[email protected]>
From the round-2 verification (approve with follow-ups), all follow-ups:
- The point budget is shared across the tiles in view once loading
settles (water-filling): a sparse tile keeps what it has, a dense city
centre takes the rest instead of drawing thinner than its suburbs. The
selected sequence is always drawn, and selecting one a cap had left out
draws it.
- The cones' picture-list cache keeps only finished lists: a re-centre
while the cones loaded inherited the aborted load's tiles and drew
none in them.
- Douglas–Peucker measures to the segment, so dead ends and U-turns keep
their far end.
- Switching Panoramax off lets its decoded tiles and lists go.
- Picture downloads are counted while they stream (a host sending no
length cannot fill memory before the cap).
- Comments on the via caption and the simplification tolerance match the
code.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Esc moved to the viewer's box (`.sl-viewer-wrap`) in the last commit, but
without one it was a second keydown listener on the root; Esc is now taken
by the root's own handler there. format-scope.json listed
panorama.test.mjs twice, which made the formatter refuse the scope; the
files it skipped are formatted.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
From a five-lens IC8 review (correctness, security, tests with mutation
testing, performance, UX):
- P0: over Paris at 12–60 km the unsimplified z10–z12 lines sent ~2M
points to Cesium's ground-polyline builder (gigabytes of geometry; the
tab hung). decode.js now simplifies lines (Douglas–Peucker, 4 tile
units: 6–10% of the points), and lineCoverage gains an opt-in point
budget (`maxPoints`, 10,000 a tile for Panoramax).
- Decoded coverage tiles are kept (KartaView's tile cache moves to the
shared tileCache.js); a sequence's z15 picture lists are kept and load
on their own connection; cones know their tiles from the start of a
load, so a picture opening meanwhile re-centres them and ‹ › no longer
restarts the load.
- The HD panorama loads only for the expanded viewer (a docked one on a
dense screen asked for 3 MB originals) and is aborted when another
photo opens; picture files over 48 MB or 16,384 px are refused; a
bitmap no renderer took after a context loss is closed.
- A nearest lookup survives one of its two searches failing; only a
timeout is retried; offline reads as unreachable; Retry-After is
capped at five minutes; the search box stays on the map at ±180°;
cones near both edges of a narrow (high-latitude) tile read both.
- Every producer is credited (app and photographer); with none to name,
the caption says "via <instance>" rather than crediting the host.
- Esc anywhere in the docked viewer (toolbar, caption) clears the
sequence before the panel takes it. A filter that hides every density
dot says so; wording aligned ("coverage", "photo").
- Tests for every surviving mutant (Esc consumed, keepOrder and dot-size
wiring, licence in the core, limiter aborts, radius floor, bbox corner,
first-producer-only, byte and size caps), a limiter test, and a gate
fixture that answers box searches and leaves out pictures facing away;
the gate now clicks over the other sequence's pictures, so only the
line click's own-sequence lookup can pass.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
KartaView's server filters by upload date only, so SINCE goes by it
throughout for KartaView: the lines (as before), the photo a click opens
and the cones, the cut-off taken as its UTC day as KartaView's startDate
(passesKartaViewFilter). Providers may declare sinceBasis: 'upload'
(validated); while one is lit the panel shows "KartaView: by upload date"
under the SINCE slider, read out with it. The gate checks the note, and
step 13's picks get 60 s on a loaded machine.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
KartaView filters coverage on its server only in its PNG tiles (its JSON
tiles come back empty with a filter), so a filtered tile's PNG is a mask
over the cached JSON segments: a segment stays when at least half the
points along it lie on drawn pixels. A filter change reloads the lines
(lineCoverage.reload keeps the drawn ones until the new ones are in);
masks are cached per filter and tile, and a filtered tile KartaView is
still drawing (504 or a timeout) is asked again, four tries in all.
The nearest lookup asks the photo API for the projection and date, and
the cones follow the filter like Mapillary's. The gate fixture draws
filtered PNG tiles and adds an older flat-only street; a new gate step
checks 360 and LAST YEAR thin KartaView's lines and ALL brings them back.
Co-Authored-By: Claude Opus 5.5 <[email protected]>