Image loading (photoViewer.js)
- One AbortController per open: a new open, close or unmount stops the
previous photo's first and sharper downloads (an <img> by src = '').
A collapsed viewer never falls back to the original; Panoramax's flat
fallback is the thumbnail. A superseded open resolves quietly.
- Flat HD tracked as "loading" and "shown" apart: a discarded response no
longer blocks later upgrades, and resizes while it loads ask once.
- No upgrade of the photo still shown while another opens.
- Size limits before decoding: imageSize.js reads JPEG/PNG/WebP/GIF
headers; more than 64 MP or 16,384 px a side is refused undecoded, an
<img> that decodes larger is refused and let go, flat HD needs a known
width of at most 8,192 px, and panoramas always decode with a resize.
Panoramax provider
- Retry-After parsed as seconds or an HTTP date; the browser cannot read
it here, so busy answers back off 5 s doubling to 300 s, reset once
answered.
- Headers timed, then the body by an idle timeout (15 s of silence), so a
slow link still gets its megabyte tiles.
- Cones centre only on the picture shown (onShowing), never on a late
lookup; lookups nobody waits for are aborted (shared, refcounted).
- onReopen: a GPU reset redraws in the viewer, not through the core.
- Cones draw the home z15 tile at once and add neighbours as they arrive;
a neighbour that failed is not counted as drawn.
- Coverage tiles decode in ~8 ms slices (a 2 MB z10 tile over Paris was
one ~85-200 ms task); sorted by measured length without a Map.
- Box search asks for 20, not 100 (the API returns them nearest first).
- looksLikeEmail checks every '@'; creatorOf de-duplicates with a Set.
lineCoverage.js
- A redraw while a swap still builds keeps what is on screen (the swap's
old lines and its ready new ones) and drops only the unready ones.
Tests for each (mutation-checked), two vacuous tests made real, the
cones' pictures lane and readable()'s busy/timeout paths covered; the
fixture's box search is nearest first. Docs: README filters and share
links, CHANGELOG HD wording, CURRENT-STATE.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
CHANGELOG: keep both new [Unreleased] entries (Panoramax, and the
emergency-transponder highlight from #856).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
isoTime returned toISOString() for any finite number, which throws past ±8.64e15 ms, so one bad record (e.g. a bike-share last_reported) failed the whole tool answer. Such timestamps are now null. The voice analyst's result rows had the same conversion and get the same guard.
Co-authored-by: Sameh Khamis <[email protected]>
Share-link integers and Cesium radians were converted before normalizeBox
checked them, so a blank edge still became 0°. Edges are now accepted only as
numbers or non-blank numeric strings, which also refuses [] and {}. Tests cover
all four edges through validateBox, dequantizeBox, boxFromRectangle and
searchHls.
The existing "route that fits" case used 199 steps, which is how the
off-by-one went unnoticed. Folds the docs note into the existing cap sentence
and makes the changelog entry specific.
The review-driven rewrite added a narrower entry but left the original
bullet in place, so the PR carried two entries for one change.
Co-Authored-By: Claude Sonnet 5.5 <[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.
The merge from main replaced the NYC DOT opt-in pack entry instead of
adding the Bing entry above it.
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]>