- Google 3D: the OPEN button re-measures a ground whose tiles are still
loading (a few times, a second apart) and on a map change, not only
after the next camera move.
- Mapillary: two mounts on one host during the first download share one
build instead of leaking a second WebGL viewer.
- Retired floating-panel keys (v8 panelPos, panelFloatHintShown) are
dropped from localStorage; dead inline-position resets, the drag JSDoc
and the dead qa-ui-disposal observer branch are gone.
- Docs: z ladder, panel chrome, position storage and the fixture gate's
actual coverage; changelog fragment for #974 (old .gev-cache/mapillary
can be deleted).
- ru/es: the layer is named as everywhere else in the UI.
- Fixtures and test fakes: unused exports removed; a fake credit removal
of an absent credit no longer drops another one; the tile test reset
frees upstream slots.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Main gained three imagery providers (Google Street View, KartaView,
Panoramax), shared line-coverage, cone and photo-viewer modules, one source
lit at a time and the translated interface. Their shared modules still
carried what this branch removes, so the merge ports them onto it:
- lineCoverage.js is this branch's coverage.js made provider-neutral
(draped lines near the ground only, the selection drawn over them, key
and rate-limit blocking); sequenceCones.js is sequences.js the same way.
Mapillary, KartaView and Panoramax all build on them; Mapillary moves
back to providers/mapillary/ beside the others.
- No ground casting, mesh sampling, surface modes, FOLLOW, legend, prewarm,
orbit overview points (Panoramax's density dots included), stale-tile
swaps or water-filled point budget come back.
- Kept from main because the new providers need them: requiresMapStack and
attachMapStackController (Street View on Google 3D only), ground clicks,
openNearest with an optional provider nearestImage, openImage {frame},
reportError, the view-cone marker (now an SVG glyph), filters /
coverageLabel / sinceBasis, OPEN STREET VIEW, keyAlternatives and i18n.
- photoViewer.js treats the viewer as expanded when its wrap is full screen
or the iPhone popover, as EXPAND now is.
- The fixture browser gate keeps its 8 steps and adds one each for
KartaView and Panoramax; catalogs, docs, boundaries and format scope
follow.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Fixes the 51 P0–P2 findings from the full review of the i18n branch and
the issues found while checking every new string on screen in ru and es.
- Translate errors and statuses that still reached ru/es in English:
feed and tile errors, provider statuses, the ALPR chip, the traffic
mode chip, voice plan step labels, fire feed values, receiver bands,
scene save reasons and the Cesium attribution link.
- Show preset city names in the UI language (src/ui/placeNames.js);
data and everything sent to the model stay English.
- Share layer names between the layer panel, HUD and voice card
(src/ui/layerNames.js).
- Keep long ru/es strings whole: voice card error lines, analyst
titles, the voice tier status, the Nepal evidence button, the ALPR
retry chip. English layout is unchanged.
- Ask before a language switch drops unsaved work.
- Catalog fixes: glossary terms (пуск, пресет), gender agreement and
consistent "peticiones" in es, fewer calques in both languages.
- Fix English text that was itself wrong (e.g. "Exit cockpit to fly to
a weather", raw tool ids in voice plan steps).
Catalogs: es/ru 2535 messages each, complete.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Mark every UI string the unmarked-text check reported (534) plus text it
cannot see (helpers, joined labels, runtime-built panels), and translate
the result to Spanish and Russian: 1,679 messages each.
- Kept on purpose, with the reason where the text lives: provider and
product names, place and camera names, codes and units, dB values, the HUD
terminal readouts, demo shot titles that saved projects look up by title,
and text for AI tools and the voice model.
- Modules shared with the server or AI tools stay free of the i18n import
(local msg); the wind reading and voice session stay English and are
translated where the page shows them.
- npm test now runs the unmarked-text check.
- Fixes on the way: a duplicated radio privacy paragraph, the contact panel
toggle saying Expand while open, the CSS filter mistaking & for CSS.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Replace the semantic keys with the English source text, so code reads as the
UI does and English needs no catalog: t('Save keys'), tn(count, one, other)
for plurals, msg() for text stored in data, and bare data-i18n* markup that
translates the element's own English. Other languages are one flat JSON each.
- Simplify src/i18n: drop namespaces, the configurable locale pair
(GEV_DEFAULT_LOCALE / GEV_SECONDARY_LOCALE) and its build defines. Locale
comes from ?lang=, the stored choice, then browser languages.
- Add scripts/i18n.mjs (npm run i18n): extracts every message from t/tn/msg
and markup, and fails on missing, unused, placeholder-mismatched or
wrongly-shaped plural entries. npm test runs it via catalog.test.mjs.
- Add Russian (src/i18n/locales/ru.json, 833 messages), started from the
community catalog in #312 and reviewed against the current English.
- Fix data-i18n placed on parents that would wipe their children (cockpit
LEVEL and local weather cells, first-run EXPLORE MANUALLY tile), and a
doubled degree sign in the TRACK ACQUIRED signal.
- Rewrite docs/TRANSLATORS.md for the new workflow; drop sections the earlier
merge resurrected in docs/CURRENT-STATE.md.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
No markup carries a drag handle, so nothing called it: panel position
controls keep only collapsed state and the layout-reset notice.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
PR #768 bundled a portable-panel windowing system with the Street Level
layer. Remove it so CCTV and Street Level are ordinary docked right-rail
panels again, as on main before the merge.
Removed:
- header drag to float, 8-way edge/corner resize, double-press snap-back,
dockOnCollapse, command-dock clearance, float hint toast, floating z floor,
persisted floating geometry and ResizeObserver re-clamping
(panelPositionControls.js restored to its pre-#768 version)
- src/ui/panelResize.js and its tests, panelDock.test.mjs
- onPanelResized/dockPanel wiring in PanelChrome, the application shell and
StreetLevelControls (EXPAND/SHRINK no longer docks)
- :not(.panel-floating) guards and .panel-floating/.panel-portable/resize CSS
- qa:panel-resize, qa-panel-resize.mjs, qa-panelDrag.mjs, their tests, the
CI "Portable panel gate" step, QA_FAIL_ON_RETRY, and the Street Level
gate's float/resize/dock steps
- floating-panel docs in README, CHANGELOG, CURRENT-STATE, KNOWN-ISSUES
Kept: the Street Level panel as a docked rail panel (share/cockpit/rail
lists, layout controller, rail and Cyber CSS, EXPAND viewer), and the
independent right-rail alignment fix (settledLeftRailTop, 9dde7b4).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- A floating portable panel saved its measured box, so dragging a
collapsed window stored its 50 px header strip and a reload clamped it
to the minimum. It now saves the inline size the user chose. A unit
test and a collapse -> drag -> reload -> expand step in the panel gate
pin it.
- Coverage awaits the tile fetch and the one-time terrain table load
together, so a tile that fails before the table loads is reported at
once instead of surfacing as an unhandled rejection.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Trim the doc text this PR adds (README, CHANGELOG, CURRENT-STATE,
KNOWN-ISSUES, SECURITY, DATA_SOURCES, .env.example, the CI job comment),
drop code comments that restate the code, cut design-note JSDoc to a line
or two, and drop review tags from test names. Comments only; no code
changes.
Also: README key count (seven keys, two metered), CURRENT-STATE's gate
paragraph (CI runs a production build with a dummy token), the stacked
doc above meshBoxInRange and the orphaned inMeshRange line in
coverage.js, and a duplicate ALPR row in DATA_SOURCES that a merge had
brought back.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A duplicate scan of every module the PR adds (repeated 4-line blocks,
normalised) after gekh's dedup round left these:
- glyphs.js: the cone, ring and position glyphs share cachedGlyph(), wedge(),
ring() and dot(). Checked with a recording canvas: all 20 draw calls keep
the same path and fill/stroke state, so the glyphs are pixel-identical.
- panelPositionControls.js: one placeAt() for the three places that pin a
panel's top-left corner as a fixed window.
- tiles.js: one warn() for the three background-failure logs.
- Tests: src/testSupport/streetLevelFakes.mjs holds the provider snapshot
(uiState + presentation tests), the stand-in provider (core + controls
tests) and one real-ray pinhole camera (view + coverage tests, which had
each written their own). The coverage line-of-sight test still fails when
refresh() stops passing its focus.
- qa-street-level.mjs: one waitForCoverage() for the five copies of the
"on, drawn, settled, not key-gated" wait.
No behaviour change: unit 5862 pass, fixture gate 16/16, panel gate 5/5.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
From gekh's review of #768, each with a test that fails before:
- P2: a floating panel whose content grows (CCTV expanded, a photo opened)
is pulled back on-screen: every portable panel is observed and re-clamped,
not only on window resize.
- P2: a floating header can never land under #command-dock or the voice
pill (the rail's stacking context paints below them): clamping keeps the
header clear of their rects on drag, restore and every re-clamp.
- A live window resize shrinks a floating window wider or taller than the
viewport; Cyber's accordion no longer collapses docked panels when a
floating one opens.
- The three pointer gestures share one helper (threshold, mouse/pen only,
cancel reverts), and the header-drag threshold now has a test.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
From the IC8 review of #768 (P2s), each with a test that fails before:
- Switching the layer off and on during the first photo download no longer
leaves the viewer stuck on "not mounted": an outdated mount only unmounts
an adapter nobody else holds and subscribes poses only once current, and
the MapillaryJS adapter never builds a viewer after it was unmounted.
- Hover picks at most every 120 ms (the CCTV convention), not while the
camera moves or a button is held, and not after the layer went off.
- Esc shrinks the expanded viewer wherever focus is (document capture), so
the map keeps its selection, and Tab from outside returns into it.
Closing a photo moves focus to the panel instead of dropping it on body.
- Portable panels lift only after a mouse or pen moves past the drag
threshold: a click on a docked panel's edge or a touch swipe on its
header no longer turns it into a floating window, and pointercancel
saves nothing and puts the panel back.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
P0
- tileMath: lonToTileX(180) wrapped to column 0, so a whole-world view at
z1 loaded only the western column; 180 is now the last column.
- coverage.loadTile: a superseded request (after a retire or clear) still
deleted the newer request's pending entry and loading count in `finally`,
letting a duplicate load attach lines that nothing could remove. Only the
request that still owns the key attaches its tile or settles the key.
P1
- view/tileMath: a view across the date line read as a ~358 deg box and
loaded tiles on the far side of the globe. visibleBbox now returns
west > east for such views and tilesForBbox splits them at +/-180;
viewCentre averages across the line.
- decode: the parts of a multi-line sequence were joined into one line,
drawing straight segments over capture gaps. Each part is now its own
line (`parts`); later parts carry `~n` in their pick id, and picking or
recolouring any part acts on the whole sequence.
- viewerHost: a prewarmed MapillaryJS viewer was never destroyed, leaking
its WebGL context. Prewarmed adapters are tracked and released on
unmount, at once when the layer went off mid-load, and per provider when
only that provider is switched off.
- nearestImage took the first record the API returned; it now takes the
closest one that passes the filter.
P2
- groundCast: the cache was cleared after a request counted its corners,
dropping ones it relied on; it is now cleared first.
- streetLevelControls: the viewer was resized on every render (every frame
while a panorama is dragged); the ResizeObserver handles size changes and
the viewer is resized once when it opens. The legend now rebuilds when its
entries change, not only their count.
- panelPositionControls: the portable-panel paths this PR added called the
CCTV viewport sync directly; they go through onPanelResized, which the
shell routes to CCTV. The "Compose camera panel controls" JSDoc is back on
_initCctvPanel.
New tests: zoom-1 columns, date-line tiles and bbox, multi-part decode and
part pick ids, nearest image, prewarmed viewer release, and the cache
ordering (fails on the old order).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Route every application-owned presentation string through the i18n
core: t() call sites across the app/layers/ui/data/voice surfaces,
data-i18n* attributes in the src/ui/templates/*.html markup (applied at
boot by applyDocumentTranslations from src/standalone/application.js),
and the dock locale selector (runtime-rendered from the offered pair —
a single EN button while only English ships).
Rebased onto current main, where the extraction follows the module
splits: the shell wiring now lands in the owner modules
(panelChrome, visualSettings, locationNavigation, shareRestoration,
shellFeedback, applicationShell) and the voice status corpus in the
realtime* modules; scene status lives in director.js +
playbackAdapter.js.
Modules shared with the node runtime (loadingFeedback,
installationFeedback, regionalModel, keySetupCore, vessels ingestion)
stay environment-neutral English and localize at their browser render
sites (chip maps in shellFeedback/installations controls, the weather
table in cockpitBriefing, keySetupRequirementEnvVars compositions), so
the package-boundary graph stays clean; the browser boundary groups
now own the i18n modules they reach (scripts/package-boundaries.json).
A floating window restored after a reload had no z-index, and the z ladder
renumbered from 101, so the docked DISPLAY panel (#pp-toggles, z 110) painted
over it. The ladder now starts at 111 (PANEL_Z_FLOATING_FLOOR), a restored
window is promoted like a lifted one, docking drops the promotion, and
floating panels get a CSS floor of 111. Tests fail on the old code.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- The rail's startup move of panels into #right-context-rail cleared every
panel's inline position, so a window restored as floating dropped back to
its rail place after a reload. Floating panels now keep their geometry.
- A header double-click never snapped a floating panel back in a real
browser: the drag handler's pointerdown preventDefault() suppresses the
mouse events a native dblclick is built from. Two presses within 400 ms and
6 px (no drag between) are now detected in pointerdown itself.
- Portable specs can ask to dock when collapsed (dockOnCollapse), and
PanelChrome exposes dockPanel(). Street Level opts in as a portable panel
(min 320 x 280) with dockOnCollapse.
- qa-panel-resize: the panel reader returns right/bottom (s/e handle points
were NaN), counts only visible rail panels like the rail does, parks the
window clear of the voice dock before the resize loop, and names the
element under the pointer when an assertion fails.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A drag spec can now be `portable`: dragging the panel by its header lifts
it out of the right rail into a fixed window, resizable from all four
edges and corners, that remembers its place and size under the existing
godsEyeView.v8.panelPos.<id> key ({ left, top, width?, height?, floating })
and snaps back on a header double-click. Only CCTV opts in here; the rail
skips .panel-floating panels when measuring and allocating, and its
placement rules in layers.css are guarded so no !important is needed.
PanelPositionControls gains an optional onPanelResized hook, threaded
through PanelChrome to a no-op on the application shell.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Wind (NOAA GFS and ECMWF IFS: animated particles, colour field, a reading at map centre), observed weather (NOAA MRMS radar, GOES and NESDIS infrared clouds, lightning density) on one shared history timeline, NHC and CPHC cyclone advisories with tracks and cones, and a WEATHER panel in the right rail. On 3D Tiles the observed products render as raised shells with a sharper window around the view.
Co-authored-by: Gustavo Beneduzi <[email protected]>
Co-authored-by: Daniel Slay <[email protected]>
Co-authored-by: Rehaan Delmotra <[email protected]>
Co-authored-by: Cursor Agent <[email protected]>