destroy() now expires every retry attempt in flight, clearing its deadline
timer and aborting its signal at once rather than when the attempt settles,
and leaves no retry marked as running.
A successful terrain retry overwrote the cached fallback without releasing
it. The replaced fallback is now disposed as soon as the real terrain takes
its place on screen, or, when it stayed installed behind a 3D tileset, once
the next globe activation replaces it.
An Esri or keyless terrain attempt that never settled kept the single-flight
retry open forever, so neither provider was retried again. Each attempt now
counts as failed after 60 seconds and the retry backs off as usual; its
signal is aborted, and a provider that lands after the deadline is released
rather than installed or cached.
CURRENT-STATE now says only the construction fallback to OSM is retried, not
the switch made after repeated Esri tile failures.
An activation that re-showed a fallback while a retry was in flight armed a
second timer, so two retries could run at once and land out of order, leaving
the cache and the screen on different providers. Retries now run one at a
time; a request made meanwhile re-arms once the current one ends, and a
result that is obsolete or no longer wanted is disposed.
Imagery and terrain retries are now handled as each settles, so a stalled
terrain attempt no longer keeps recovered imagery off screen, or the reverse.
- i18n scanner: lastError sink, no false sinks on defaults and ternaries
- shared src/i18n/marker.js for modules that only mark strings
- wind field messages move to wind/fields.js; CITY_POIS imports from cityPois.js
- drop review IDs, change history and stale references from comments and docs
Co-Authored-By: Claude Opus 5.5 <[email protected]>
In the keyless setup a single transient failure while loading the default
map layers locked in the degraded fallback until reload.
_getImageryProvider cached the construction-fallback resolution (OSM) under
the Esri stack id, so every later "Esri Satellite" selection showed OSM.
createKeylessTerrain turns any Re:Earth failure into a flat
EllipsoidTerrainProvider; the controller cached it and set _terrainMode to
'keyless', so a boot-time network blip left the globe flat.
Fallbacks are still cached and shown at once, and no switch waits on a
retry. One controller timer now retries the real provider behind whichever
fallback is on screen (Esri's OSM stand-in, or flat terrain on a shown
globe), starting at 30 seconds and doubling to a 10-minute cap while it
keeps failing. A failed retry leaves the cached fallback and the installed
terrain untouched. A success replaces the cache entry and applies it live:
terrain is installed in place with a render request (or, behind a 3D
tileset, picked up by the next globe activation), and Esri is reselected
automatically, after any in-flight switch settles. A switch that read the
flat fallback re-reads the terrain cache before installing, and destroy()
cancels the timer and releases a provider built after it.
A listener could destroy the controller and re-subscribe one still pending in
the snapshot, which then ran. Delivery now stops at destruction and a destroyed
controller takes no listeners. Adds ordering tests for adds, duplicates and
re-adds during delivery, and moves the current-state note after the section
intro.
- Satellite class in analyst records and voice payloads stays English
("STATION", "COMMS"), so voice filters on the class work in every
language; cards and the legend still show the translated label.
- Layer source names (OSM routing, ALPR sources) stay English in layer
state; the layer row translates them.
- New translateKnown(): catalog text when there is an entry, the given text
otherwise, with no warning. The layer row uses it for loading labels and
errors, Recent Imagery for its notices.
- Mark the remaining Recent Imagery and wind messages.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
- The Space Missions cancellation failure toast read "[object Object]" in
every language: the options object was passed as the message. The English
message is the second argument again, the translation the third.
- Header text is translated before panel chrome builds its collapse labels,
so the dock and display toggles no longer read "Expand VISUAL PRESETS" in
another language.
- The voice "show data layers" result keeps the English layer name
(row data-layer-name), not the translated row text.
- The Google 3D unavailable reason is translated in full.
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]>
Without a browser key, the app asks its server for a short-lived Google
access token (GET /api/google/tiles-token, answering accessToken and
expiresAt) and loads Photorealistic 3D Tiles directly with it as a
header. A tile refused for an expired token gets a renewed one and is
retried once. A server that does not offer tokens changes nothing: the
app continues through ion or the keyless globe as before.
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).
Traffic roads come from OpenFreeMap vector tiles, or TomTom flow tiles with a
key (Hybrid by default). Military areas use OpenFreeMap polygons with a bundled
worldwide name index; wide views show named points. ALPR reads an hourly
OpenStreetMap extract. Cockpit place context and country, state and US county
outlines use bundled Natural Earth and US Census data. Overpass is used only
when an operator configures their own endpoint.
Also: camera arrivals no longer land below ground, keyless terrain retries on
429, bounded relation geometry for configured Overpass, one shared
OpenStreetMap credit, and separate tile and API transports for embedders.
Co-authored-by: theGaryLarson <[email protected]>
Co-authored-by: Milan Khanal <[email protected]>
Select a box on the world and browse the last 30 days of open satellite imagery over it, keyless: NASA GIBS Harmonized Landsat Sentinel-2 (30 m) and the VIIRS daily overview (250 m), with a day strip, IMAGE / VS BASEMAP / A / B modes with a swipe divider, PNG export and share links. The before/after swipe from the Nepal scene moves into shared modules so both use it.
Co-authored-by: manjunath22466 <[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]>