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]>
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]>
From a UX QA round in the browser against the live API:
- A line click could time out while coverage loaded: the meta-catalogue
speaks HTTP/1.1 only (six connections), and six tiles plus four
searches queued the lookup behind megabyte tiles. Tiles now take
three connections and searches two; a search that timed out is asked
once more.
- Between 30 and ~100 km Paris read as empty: the density grid is ~10 km
a cell. Lines now draw to 60 km (z10), as Mapillary's do; above, dots
grow with the pictures they stand for.
- Esc in the docked viewer collapsed the whole panel instead of clearing
the sequence the panel says it clears (shared photo viewer: KartaView
too). The viewer now offers Esc to the provider first; expanded, the
dialog keeps it.
- A picture whose producer is an email address is credited to the
instance holding it (its `via` host), so Licence Ouverte pictures name
their source.
- Empty states say why: "no Panoramax photos here match the filters"
when the filter hid every line, and nothing to zoom into over empty
sea. Wording follows KartaView's ("photos", "click a line for its
nearest photo").
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Panoramax, the open federated street-level commons, registers beside
Mapillary, Google Street View and KartaView. Its meta-catalogue
(api.panoramax.xyz) is keyless and CORS-open, so it runs in the browser:
- coverage from its vector tiles: sequence lines at z11–14 below 30 km
(longest first under the per-tile cap), and above that the grid layer's
density cells as binned points, not counted as sequences;
- a click on a line opens that sequence's picture nearest the click
(STAC search, any direction), without moving the camera, then any
sequence's if it has none within 50 m; the 360° and since filters go to
the lines and to the API;
- cones from the z15 tiles' pictures layer around the open picture
(~110 bytes a picture, against ~7.5 kB for a STAC item), re-centred when
a picture opens outside them; ‹ › follow the picture's prev/next links;
- the caption names the author (not an account named by an email
address) and the picture's licence (StreetPose `license`), and links to
the picture in the Panoramax viewer; the globe credits Panoramax.
KartaView's viewer becomes the shared photoViewer.js (flat <img>, 360° on
panorama.js, ‹ ›, keyboard, pinch, context loss), driven by a per-provider
PhotoSources table; the request limiter moves to limiter.js. Panoramax shows
the 2,048 px SD derivative and fetches the HD original only when the viewer
is wide enough, once, shrunk while it decodes (never above 8,192 px).
Orange #ff6f00 (Panoramax's own), off by default, share option
0.m.0_0.r.panoramax-1. The MCP panel allows the meta-catalogue and the
biggest instances. Tests: policy, decode, source, viewer, provider, and a
Panoramax fixture in the hermetic browser gate.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Marker and direction (reported on the PR):
- KartaView has its own marker, a purple view cone (Street View's is
blue), not GEV's default pin that Mapillary uses.
- The camera direction (marker, cones, FOLLOW, a panorama's centre) is
the direction of travel to the next photo a few metres on. KartaView's
heading is the device compass: whole drives read 0 (no compass) and
others sit a steady ~110° off. Until the drive loads the compass stands
in (0 = unknown), and the pose is sent again once the course is known.
Remaining P4s from the review of #1121:
- Segment chaining is linear (a per-point cursor) and capped at 20,000
segments a tile and 5,000 points a line: a hostile tile of 60k segments
sharing one point took 1.5 s, now tens of ms.
- Decoded tiles are dropped when KartaView is switched off.
- No network / a refused request says so and is not retried as a timeout;
an unreadable answer says so.
- A docked flat photo skips the 2,560 px download until the viewer grows.
- The panel counts the drive's photos (countActivePhotos), not the thinned
page of cones (2,250, not 217).
- After a GPU reset the viewer redraws the photo itself, so a lookup the
user started is not cancelled; a failure is still reported.
- The gate's keyless page lights KartaView and checks it draws with no key;
the fixture answers the sequence count; the line-click step checks the
camera looks along the drive when the compass says 200°.
- README/CHANGELOG show the share-link form the app writes.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
NYC DOT asks developers who use its camera feed to sign a data-sharing
agreement, and this project does not hold one that covers downstream
installs. The pack now loads only when CCTV_NYC_ENABLED=1; unset, empty
or any other value makes no request to webcams.nyctmc.org (tested).
The NYC credit carries NYC DOT's requested application disclaimer
verbatim, and DATA_SOURCES, README, CHANGELOG, CURRENT-STATE and
.env.example describe the prerequisite.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
P1s from the correctness review, each with a regression test:
- Cones showed the wrong page of a long sequence (cache keyed by
sequence; no re-centre after a close or a same-drive line click):
KartaView always reselects, and re-centres whenever a photo of the
selected sequence opens on another page.
- A 360° photo's first frame was one colour: the canvas was sized while
hidden (1×1). It is shown first, and re-measured every frame.
P2/P3s: a storage timeout or 5xx is not remembered as archived (only
403/404/409/410 are); dense z13 tiles draw up to 1,600 lines (a third of
downtown Detroit was cut); decoded tiles are kept 10 min; a timed-out tile
is asked once more; pages are 250 photos and the newest page request goes
first; a photo far past deleted ones, or unlisted at a page edge, still
finds its neighbours; a step that gets no answer is not the end; a lost
WebGL context redraws the photo, and a failed one is retried on the next
mount; the first flat image comes from the proxy (KartaView's own can be
1.7 MB); fileurl fallbacks must be https storage hosts; oversized answers
are refused; keyboard (Shift+← →, ↑ ↓, + −) and pinch look around a
panorama; focus stays in the viewer when a step button disables. Docs:
share links with 0.m.0, keyless count, CURRENT-STATE matched to the code.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The fixture gate answers api.kartaview.org, cdn.kartaview.org and
*.openstreetcam.org from fixtures (a drive with a 360° photo, stored on
storage2 while the API names storage1) and adds three steps: keyless
coverage with its credit and hidden filters, a line click opening the
nearest photo with cones and ›, and a 360° photo on the panorama without
FIT / FILL. The Street View share-link check reads the switch field instead
of one exact entry, since a chip click records every provider's switch.
README, DATA_SOURCES, CHANGELOG and CURRENT-STATE describe KartaView.
Co-Authored-By: Claude Opus 5.5 <[email protected]>