Commit Graph
13 Commits
Author SHA1 Message Date
German KhokhlovandClaude Opus 5.5 20f4cf3763 i18n: fix the LGTM review findings and tidy the branch texts
- 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]>
2026-10-16 21:00:28 +04:00
German KhokhlovandClaude Opus 5.5 7fd1dd867f Merge origin/main: Panoramax, bikeshare Norway/Detroit, cloud filter strength, Overpass cache
Conflicts:
- KartaView viewer moved into the shared photoViewer.js on main; its
  labels now take the provider name ("{name} street-level photo") and
  are translated there.
- Weather: main's cloud filter strength slider, with its labels in t().
- Street Level caption: translated creator line plus main's licence.

Panoramax status and error texts are marked like KartaView's, and
"Panoramax answered HTTP {status}" gets a template in the panel and the
layer row. Catalogs: es/ru 2553 messages each, complete.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-16 00:06:45 +04:00
Said TurkseverandClaude Opus 5.5 b645a767c8 Street Level: Panoramax review follow-ups (gekh, #1134)
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]>
2026-10-15 16:55:59 +01:00
Said TurkseverandClaude Opus 5.5 e3bc431f9a fix(street-level): review follow-ups — shares judged against the last draw; refused pictures stay refused
From the maintainer review of #1134 (approve with follow-ups):
- lineCoverage: a share is judged against the cap the tile was last drawn
  with, not against later shares that redrew nothing, so small increases
  add up (a retained tile stayed at 100 points after its share grew to
  116). A rebuild's measuring pass no longer counts as a draw.
- photoViewer: a picture refused for its size (bytes, streamed bytes or
  decoded side) is marked `tooLarge`, and the viewer never loads that file
  again by any path; the flat fallback had retried an oversized SD file
  through an <img>, which has no size limit.
- Regressions for both: cumulative share growth below the threshold, and a
  refused SD panorama that is not fetched again as a flat photo.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-15 16:08:18 +01:00
Meir Michanie 40fb2031bb Merge upstream/main: KartaView provider meets i18n
Upstream's KartaView PR (#1121) extracted the Mapillary coverage engine
into a shared lineCoverage.js and made the panel wording
provider-specific (coverage noun/action, SINCE upload-date note,
highlightsSequence legend gate), again in the regions this branch
localizes.

- mapillary/coverage.js: taken as upstream's thin re-export of the new
  lineCoverage.js; the generic too-high hint stays msg()-marked, now in
  lineCoverage.js where the default lives.
- kartaview/policy.js: coverage hints (tooHigh, noCoverage) marked as
  msg() data so they translate like every other coverage hint; thrown
  error messages stay English, matching the Mapillary precedent.
- presentMeta: KartaView counts streets, and Russian plurals need the
  noun inside the template, so the count line gets its own literal tn
  pair keyed off coverageLabel.noun, falling back to the sequences pair;
  upstream's noun/action data contract is untouched.
- uiState legend: upstream highlightsSequence gate with t('Selected');
  sinceNote localized with a {names} placeholder.
- layer-panels.html: sl-since-note wiring kept, data-i18n hooks kept.
- CHANGELOG: both sides kept. es/ru: 4 new keys each.

npm run i18n complete (953 messages each); npm test 6504/6506 (the one
failure is the pre-existing environmental OPENAI_API_KEY leak in
devFreshDotenv, unrelated); build passes.
2026-10-14 17:33:30 +02:00
Said TurkseverandClaude Opus 5.5 ce3f66a837 fix(street-level): IC8 round 3 — no blink when the point budget is re-shared
The round-3 verification found the shared point budget rebuilding a dense
tile by removing its lines before the new ones were built, so central
Paris vanished for 1–2 s after every pan:
- Tiles redrawn for a new share, or for a selected line the cap had left
  out, go through the swap path: the old lines stay until the new ones
  are ready.
- A share must move by 10% to redraw a tile (a 1.6% change rebuilt it).
- The selected line, admitted past the cap, is not counted against it,
  so its tile no longer redraws on every settle.
- A selection the imagery filter hides is not redrawn for.
- Shares are recomputed when a refresh ends loading without a tile
  finishing.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 15:54:21 +01:00
Said TurkseverandClaude Opus 5.5 da0d370fa3 Merge upstream/main (KartaView #1121 merged) into pr/panoramax
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]>
2026-10-14 15:52:21 +01:00
Said TurkseverandClaude Opus 5.5 3ae367d0dd fix(street-level): Panoramax IC8 round 2 — shared point budget, selected line, cone cache, DP segments
From the round-2 verification (approve with follow-ups), all follow-ups:
- The point budget is shared across the tiles in view once loading
  settles (water-filling): a sparse tile keeps what it has, a dense city
  centre takes the rest instead of drawing thinner than its suburbs. The
  selected sequence is always drawn, and selecting one a cap had left out
  draws it.
- The cones' picture-list cache keeps only finished lists: a re-centre
  while the cones loaded inherited the aborted load's tiles and drew
  none in them.
- Douglas–Peucker measures to the segment, so dead ends and U-turns keep
  their far end.
- Switching Panoramax off lets its decoded tiles and lists go.
- Picture downloads are counted while they stream (a host sending no
  length cannot fill memory before the cap).
- Comments on the via caption and the simplification tolerance match the
  code.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 15:39:10 +01:00
Said TurkseverandClaude Opus 5.5 cf502429a3 fix(street-level): Panoramax IC8 review — line geometry budget, caches, attribution, tests
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]>
2026-10-14 15:24:13 +01:00
Said TurkseverandClaude Opus 5.5 b42ab9bb02 feat(street-level): IMAGERY and SINCE filters for KartaView
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]>
2026-10-14 15:02:14 +01:00
Said TurkseverandClaude Opus 5.5 5526666894 fix(street-level): Panoramax UX QA — connection budget, coverage to 60 km, Esc, attribution
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]>
2026-10-14 14:37:45 +01:00
Said TurkseverandClaude Opus 5.5 bce3044e0c fix(street-level): Panoramax functional QA — nearest lookup, line cap order, hostile data
From an adversarial functional QA round against the live API:
- The nearest lookup missed pictures looking away from the click
  (place_position leaves them out at any tolerance): it now runs a
  bounding-box search beside it and ranks both by distance. A line
  clicked from high up searches its sequence within height / 100
  (50–400 m).
- The per-tile line cap kept the newest sequences, not the longest
  (lineCoverage re-sorted them): providers can now keep their decoded
  order (`keepOrder`).
- A long producer name froze the tab (quadratic email regex): linear
  check. A malformed link escape no longer fails the lookup; null or
  string coordinates no longer land at 0,0.
- A line with no camera type or day stays drawn under the filters.
- A sky click on a line changes nothing (as KartaView), instead of
  selecting a sequence with no cones.
- An unreadable tile reads as such; a failed neighbour z15 tile only
  thins the cones; unknown or refused ids say the picture is gone.
- Shared viewer: the sharp-panorama guard is per open (a late download
  of the previous photo no longer lets a second one start); an HD-only
  360° picture is shrunk or skipped like any original; panorama.js read
  the bitmap size after closing it, so 2:1 power-of-two panoramas
  clamped instead of wrapping.
- Tests for each, and for the gaps mutation testing found (preferred
  point, cone order, no reload within drawn tiles, newest-first gate,
  stale bitmap release, flat upgrade retry).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 13:34:25 +01:00
Said TurkseverandClaude Opus 5.5 cb01014e36 feat(street-level): KartaView as a third, keyless imagery provider
Coverage lines from KartaView's z13-14 JSON tiles (OSM ways with photos,
chained end to start), the photo nearest a clicked line, cones along its
sequence, and a viewer for flat photos and 360° panoramas (a small WebGL
equirectangular renderer, no new dependency) with ‹ › along the sequence.

Mapillary's camera-driven line coverage and sequence cones move to the
provider-neutral core (lineCoverage.js, sequenceCones.js) with the tile
fetch, zoom ladder, colours and pick prefixes injected; Mapillary keeps
thin wrappers and its tests pass unchanged.

KartaView quirks handled: api.kartaview.org (the documented
api.openstreetcam.org serves empty tiles), photo URLs that name storage1
for photos stored elsewhere, and a photo API that answers 429 to more than
about three requests at once (two in flight, retried with backoff).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-13 18:33:14 +01:00