The voice error was matched against the translated key message to decide
whether to show the microphone hint, so switching language brought the hint
back and left the message in the old language. The error now carries a
missing-key flag into the status, which words the message at render time.
A controller test covers the language switch, and CURRENT-STATE.md documents
the keyless voice response.
The decision no longer reports not-entity-context or channel-closed, which
its only caller rules out first, nor pointer-scale-not-useful, which the
crop path already checks and logs. A closed channel returns before any
record, as on main. The crop decision is pointer-crop-eligible, since the
crop checks after it decide whether the pointer is on ground, and a sender
called on a closed channel logs channel-lost.
In a dense downtown view from about 400 m up, the occlusion margin of
max(3 m, 2% of the range) came to 14 to 20 m, so a wall, awning, tree or
lower facade standing 10 to 20 m in front of a street was read as the
road itself: the vehicle's dot was hidden by the scene, but its bracket and
callout were still drawn. Checked against scene.pickPosition in one such
view, 18 of 470 vehicles in frame fell in that band.
The margin now depends on how steeply the camera looks down on the
contact. A point on the line of sight s metres in front of a vehicle
stands s * sin(elevation) above it, so a surface there hides the vehicle
once that rise passes 2 m. The margin stays at least 3 m and at most 2%
of the range, so grazing and street-level views are unchanged. In the
same views no vehicle with the drawn surface within 3 m in front of it
(its own road) is newly hidden.
From the review of the first change:
- A contact back in view after longer than a retest interval is held back
and retested like a new one, instead of being drawn from an answer
given before it left the view. It gets a fresh record, so a test still
in flight from before cannot end the hold-back either.
- The hold-back for a contact's first answer stretches with the retest
pace when a crowded view slows it.
- A batch whose control point failed no longer counts as a first answer.
- An unknown log-depth flag reads as "no depth" rather than as standard
depth, which would have put every surface in front of every contact.
- A shader that fails to build leaves no shader behind and is not built
again on the same context.
The detection overlay only hid a contact behind the Earth's curve, so a
street vehicle behind or under a building, a 3D tile or a hill still had
its bracket and "VEH-nnnn" callout painted over that geometry, while its
own dot was depth-tested and correctly hidden.
A contact a layer marks `depthTested: true` (only Street Traffic does) is
now tested against the depth the scene drew and left out of the overlay
while a drawn surface stands in front of it by more than max(3 m, 2% of
its range). Other layers are untouched: their markers are drawn over the
scene on purpose.
The test runs on the GPU and never waits for it. Each tested contact is
one point drawn inside an occlusion query; the vertex shader looks up the
frame's packed pick depth at the contact's pixel, decodes it and drops the
point when the surface is nearer than the contact's threshold. Query
results are collected on later frames. Reading depth back was measured
and rejected: `scene.pickPosition` per contact costs 0.2 to 1.4 ms each,
and Chromium answers `getBufferSubData` with a round trip to its GPU
process even behind a signalled sync object (1.5 ms on a quiet machine,
15 to 25 ms on a busy one).
- Contacts are retested every 100 to 200 ms, spread across frames, at
most 256 a frame; with more in view the pace stretches so none starves.
- Hiding is immediate. A hidden contact returns 600 ms after its last
"hidden" answer, so one on a silhouette edge does not blink, and a
contact new to the view is held back until its first answer (400 ms at
most), so orbiting does not flash brackets behind buildings.
- A callout whose contact goes behind something is dropped at once, not
carried to the next solve and not faded out on the facade.
- These times run on painted frames, so a hidden tab does not expire them.
- A control point in every batch must draw; if it does not, the batch is
ignored and after three the probe stands down for ten seconds. With no
pick depth (2D, Columbus view, depth picking off) nothing is hidden.
A WebGL 1 context reads depth back synchronously about 8 times a second.
The renderer internals this depends on are read in one function,
`readSceneDepthSource`, with the engine version they were checked against.
- layerStateTokenLedger.test: the retired-token reuse case now offers the
retired token (02) to the newcomer, not News's 00.
- he.json: the catalog's singular imperative, {count} first in the plural,
Wikidata read as one source, and smoother legend and info text.
- layerManifest: News after Shipwrecks, so the prompt-budget comment stays
next to the entries it explains.
- CURRENT-STATE: Prettier-formatted (table column, blank line before a heading).
Main added the News layer at the same places: both layers are kept in the
layer names, panel order (News stays last of Events), standalone sources,
voice manifest, credits, DATA_SOURCES and the CURRENT-STATE table. News took
share-link token 00 first, so Shipwrecks moves to 01 (ledger, registry,
CURRENT-STATE and the token tests). The catalog now has 40 layers and the
share-link registry 38. Shipwreck strings are added to the new Hebrew
catalog; the other catalogs keep both sides' strings.
Removing one source's wrecks on the page split merged records: a wreck both
sources list is one Wikidata record carrying EMODnet facts, so expiring
Wikidata dropped wrecks EMODnet still had, and expiring EMODnet kept its
facts. The page now keeps every shown wreck, marked stale, until the newest
source passes the limit, then clears them all. Adds a source test for the
reported ages and limit.
The page compared the proxy's fetchedAt with its own clock, so a skewed
browser clock cleared or kept wrecks wrongly; a snapshot without a timestamp
never expired; and one old source cleared the other's fresh wrecks. The proxy
now reports each source's age on its own clock and its seven-day limit; the
page turns them into per-source deadlines when the snapshot arrives (seven
days from arrival when no age is given) and, on a failed refresh, removes only
the sources past theirs. A refused short refresh is logged.
CURRENT-STATE said each source is asked at most once a day; a failed source
is retried after 15 minutes. It now also covers refused short refreshes and
the page clearing expired wrecks, and its two shipwreck paragraphs are
rewrapped. The card's comment no longer says the records carry no names.
- The legend counted each era twice, scanning every record eight times per
row refresh; it now counts once.
- Each year picker listed every year from the oldest dated wreck (well over
a thousand entries); it lists the years that have a wreck, plus the chosen
ends.
- Labels fell back to Portuguese and links to Portuguese Wikipedia while the
app ships 11 locales: labels now fall back through the app's languages
after English, and a wreck with no English article links its Wikidata
item, which lists the article in every language.
DATA_SOURCES and CURRENT-STATE said text naming people is dropped. The filter
drops text with a title or role word (Mr, captain, owner, crew, reported by);
a bare name with none of them still passes. The docs and the code comment
now say so.
Air accidents (#1584) is not merged, so comments, the changelog fragment and
CURRENT-STATE no longer explain the shipwrecks markers, card and picker by
it; the row-range test fixture is the shipwrecks row. CURRENT-STATE now says
the markers are one billboard collection and the period is stored swapped.
A refresh with one source down (or Wikidata answering 200 with no results)
was cached as the day's snapshot, replacing the full set; and once the
snapshot was a day old, every request after a failure fetched both sources
again. Each source now keeps its own last good records, served as stale for
up to seven days, and a source that failed is not asked again for 15 minutes,
even when there is no data yet. A Wikidata answer without results, or with no
wreck in it, counts as a failure.
When the whole feed backs off, no poll counts a miss, so the tracked
aircraft read STALE at full brightness while no newer position came in.
It now takes the same stale fade as a missed update, in the flights and
military layers.
Keep World News API results an hour at most and say caching needs its
permission; refund a read that never reached it; match Local by any pin;
assign a disputed area by a point inside it; untitled GDELT stories are
minor; hotspot counts leave out minor reports.
Co-Authored-By: Claude Fable 5.2 <[email protected]>
The route check allowed 200 km off the great circle between the airports, so a
coast-to-coast flight routed a few hundred kilometres around weather lost its
origin and destination (JFK–SFO over Kansas, 384 km south). The tolerance is
now 200 km or 15% of the route's length, whichever is larger: 623 km for
JFK–SFO, and still 200 km for a short hop, so a wrong leg stays hidden.
The trail no longer joins a day of history into one line. It lifts the pen
across a gap of more than 48 minutes, an implied speed over 1,500 kt, or a
report without altitude (a parked aircraft within 0.1 nm for under 3 h stays
joined), and every history point is kept as its own segment. History never
gets an invented altitude. The live end is the path the aircraft was drawn
along, thinned to its shape, so it no longer cuts corners through turns; a
late report trims what was drawn after it. Old segments are frozen in chunks,
so a 2,000-point trail costs about 0.1 ms a frame.
A tracked aircraft that misses an update shows STALE and is dimmed. It keeps
flying on its last speed and heading for five minutes (at most 1,500 kt),
then stops, dimmed, labelled SIGNAL LOST with the time since its last report,
and is kept for ten minutes after that report so the camera keeps its target.
Aircraft on or near known ground hold at their last report instead of
coasting. Military flights follow the same rules.
The catalog source 'NASA FIRMS · LIVE' still led the row; getStats() now
names the source 'NASA FIRMS' for such a snapshot. get_active_fires says
"in the 24 hours to" its end and reports window_end. The end is checked
to be a printable time, cleared under KEY REQUIRED, the test moves next
to the layer, and the changelog and CURRENT-STATE describe it.
Name routeId among the canonical analyst IDs in CURRENT-STATE, say what the
changelog entry changes for users, and drop the comment that repeated the
canonical-field doc.
The earlier main merge replaced `import { interruptGlobeRotation } from
'../cameraVerbs.js'` with the displayText import while keeping the
`interruptGlobeRotation('voice-zoom-intent')` call, so voice zoom actions
threw ReferenceError. The same merge replaced main's Overpass reservation
paragraph in docs/CURRENT-STATE.md; restore it next to the new text.
Conflicts:
- docs/CURRENT-STATE.md: keep main's hidden-tab polling paragraph and the
display-text normalization paragraph.
- scripts/package-boundaries.json: keep main's voice panel and text chat
modules and add src/data/displayText.js.
- src/voice/gevActions.test.mjs: keep main's set_panel_open and partial
analyst card tests and the display-text tests.
Tracking a civil flight asks Planespotters for that aircraft's photo, once
per aircraft, straight from the browser. The CONTEXT panel's CONTACTS view
shows it under the flight's name with the photographer's credit, as a plain
link to the photo's page. Only images on plnspttrs.net and pages on
www.planespotters.net are ever shown or linked. Military aircraft and a
converted TR-3B are never looked up.
Flight lookups (type, route, photo) whose source failed temporarily are
asked again after a 60-second cool-down; an answer, found or not, and a
permanent refusal stay final for the session. A route belongs to the
callsign it was looked up for, so a callsign change drops the old route.
Browser QA scripts that track a flight answer the photo lookup themselves,
so they never call the third party.
With Lines on, every progressive paint of a loading city rebuilt all road
lines: up to three ground-line primitives for as many as 1,500 roads, built
asynchronously. Builds started faster than they finished, and each kept the
set it replaced in the scene until it was ready, so sets piled up.
One set now builds at a time. A rebuild asked for while lines are building
replaces the one waiting, and the newest starts when the build finishes.
Lines replaced by a finished build are removed before the next one starts.
Turning Lines off removes the lines at once and drops the waiting rebuild.
createApplicationTools returns pointer: claim(owner) takes the pointer as
Draw does and returns its lease, or null while another tool holds it;
release(lease) gives it back; isFree() lets the application's own click
handlers yield, as the layers' do. This replaces drawShape, which this
branch added: Draw is as it was.
With readings kept per point, the floor a vehicle gets depends on which point
is probed and where it is read. Transit offered the sampler the first point of
each vehicle's path in a cell, usually its oldest fix there, so a vehicle that
stayed in one cell never had its current spot probed. It now offers the latest
point of the path in each cell, and the newest fix in the vehicle's own cell
(the selected vehicle's history is walked newest first).
The grounded-flight display clamp read the floor at its sticky cell's centre,
which now answers from the reading nearest the centre, not the contact. It
reads at the contact's own position, held inside the sticky cell so boundary
hysteresis still applies.
On the photoreal stack the rendered-mesh floor took one probe at each coarse
cell's centre (0.001 degrees) and kept it for the session. A centre on a roof
passed the +80 m DEM window and lifted every vehicle in the cell to roof height
(a Haymarket bus drew 23.5 m above the street, on the garage roof); a centre in
the river put Red Line trains on the Longfellow Bridge 6-9 m under the deck.
The sampler now probes at the caller's point. A cell with a reading is probed
again only at spots about 17 m apart from earlier ones, eight at most, and a
spot refused only because the cell's DEM prior was cold is tried again later.
The floor keeps each reading that passes the gate at the point it was taken
(two within about 5 m keep the lower; sixteen at most per cell) and answers a
read from the reading nearest the asked point, so a viaduct and the street
beside it in one cell keep their own heights.
- Add the full catalog (2940 entries keyed by the English text; 75 plural
entries carry one/two/other per Intl.PluralRules('he')), reviewed for
meaning, terms, separators and label length.
- Register he: he-IL and he map to it; it joins RTL_LOCALES so <html
dir=rtl> mirrors the chrome through logical properties and rtl.css.
- rtl.css: Noto Sans Hebrew (loaded with the other Google fonts) leads the
mono and sans stacks, tracking released like Arabic, HUDs keep JetBrains
Mono for Latin telemetry.
- same-as-english: instrument codes and HUD readouts stay as printed
(HDG/BRG/CRS/FOV/CRT/NVG/FLIR/CAL/SRC, MW units, Sentinel-2, km/h...).
- docs/translations/he.md: style, plurals and glossary.
- docs: TRANSLATORS.md and CURRENT-STATE.md updated; normalizeLocale test
covers he-IL.
createApplicationTools returns drawShape({ shape, signal }): it opens Draw
for one area or line and resolves with its Polygon or LineString without
placing a mark, or null when draw mode is left, the signal aborts, a newer
request replaces it, the pointer is held elsewhere or the tool goes. The
shape controls cannot change the asked-for shape, and a shape across the
antimeridian is refused as a row's actions refuse it and drawn again. It
also returns pointerFree, so an application's own click handlers yield to a
tool holding the pointer, as the layers' do.