Clear cancelled lookup loading over an existing photo, release caller abort listeners on internal retirement, surface embedded errors, and permit embedded photos over the clean globe. Add seven regression cases and update runtime documentation. Preserve the published localization and other review fixes.
Review fixes for #1506.
- Ottawa: use the documented camera list and the city's Traffic Camera
Images API. The pack is skipped with no request unless
OTTAWA_CAMERA_CERTIFICATE is set; the certificate is added only at
fetch time inside the pinned /opendata/ path, and each camera is
fetched at most once a minute through the shared frame cache.
- Québec 511 video is opt-in (CCTV_QUEBEC_VIDEO_ENABLED=1) and loads
only after the viewer presses Play; selection, auto-hop, scenes and
voice no longer contact Québec 511. Credit splits locations (MTQ,
CC BY 4.0) from video (Québec 511). Interrupted play() is no longer
reported as an unavailable source; the per-frame listener runs only
while a Québec camera is selected and the canvas rect is cached.
- Catalog cap: reserved Québec and World slots come only from capacity
above the 4,000 shared slots, so a lower CCTV_MAX_SOURCES thins every
pack instead of starving the existing ones. dev-fresh and
.env.example default to 7,516.
- Throttled frames (World, Ottawa): inside the refresh floor with no
cached frame the proxy serves the placeholder, never Street View; a
failed fetch backs off for a minute; the cache is bounded by bytes.
- MJPEG first-frame extraction runs only for sources registered as
MJPEG (Taiwan Highway Bureau), caps a frame at 2 MB, reads in linear
time, accepts a CRLF preamble and a boundary that already starts with
"--", and ends a part without Content-Length at the next delimiter.
THB hosts are registered in the redirect pin list.
- Tests: World loader policy, Québec loader and opt-in, proxy cooldown
without Street View, Ottawa signing, cap reservations at 7,516, 4,000
and 48, overlay Play gate, refresh, visibility and teardown. Guard
tests check the 4,000 shared slots again.
- Remove the unused standalone Québec preview module and public page.
- Docs: DATA_SOURCES, SECURITY, CURRENT-STATE, CCTV_INTEGRATION, README,
.env.example, changelog fragment renamed to its full scope.
P1: on a phone the Street Level panel sits in the Cameras tab sheet, so the
action and sl= links opened photos nobody could see and still reported
success. A photo that opens, and a link that arms, now open that sheet
(revealPanel). In cockpit, clean view, recording or scene playback the action
stops at a new `view` stage before anything switches or loads.
P2s:
- Mapillary's nearest search asks for 100 photos, the API's most. It cuts
the radius's photos at the limit in no particular order, so 8 left the
distance sort and the imagery filter a few arbitrary photos.
- The MCP globe panel opens a billed photo only for a result issued in the
last five minutes (show_in_gods_eye_view stamps issued_at); a host that
mounts the panel again hands back the old result, which only arms.
- OPEN uses an armed link's point only while the view centre is within 1 km
of it; a user who moved on opens what the view shows.
- show_in_gods_eye_view measures a camera's altitude from the terrain under
it before taking its look-at point, so high cities no longer put the
photos kilometres too far ahead.
- The armed-link toast is translated, and the new view-stage message too,
in all 11 catalogs.
- Tests: a turn superseded during the geocode, flight or map switch changes
nothing; an unknown key state lets a cold sl= link through; a wide tilted
area still opens photos at its centre.
Keeps main's locale catalogs and re-adds this PR's eight Street Level strings; re-pins the Realtime payload digests for main's two new overlay layers, where the unchanged tools match main's pin, so show_street_level is still the whole difference.
show_street_level (voice and typed) flies to a place and opens its nearest
street-level photo from Google Street View, Mapillary, KartaView or
Panoramax; Street View switches to Google 3D first. The view model gains a
street_level field, share links carry sl=<source>,<lat>,<lon>, and
show_in_gods_eye_view can open a photo. A plain sl=google link only arms the
point and waits for OPEN, so it never bills a key without a click.
Embed pages show an open photo in an overlay that Esc closes. On-screen
strings are translated into es, ru, zh-CN and zh-Hant. Covered by unit tests
and three new steps in the Street Level browser suite.
- A zoom during a pivoting tilt now scales the range the tilt holds,
as it already did for orbit, instead of being undone on the next
frame while reporting success. The zoom limits no longer move a view
the wrong way: a zoom in leaves a view closer than 80 m in place, and
a zoom out leaves an orbit beyond 5,000 km where it is.
- A grab, touch or wheel on the map while a voice fly-to is in flight
drops the motion queued behind it. Cesium lands the flight anyway,
so the orbit or tilt would otherwise take the camera back. Chained
fly-tos in one reply keep the earliest snapshot.
- A pivot tilt toward the horizon stops lowering the camera at 150 m
above the pivot and tilts the rest in place, so a close view no
longer ends inside tiles or a hillside.
- pitchDeg is an absolute angle. A direction that contradicts it is
refused, judged from the pitch the swing starts at, and the tool
description says so.
Review follow-up for the sonar pulses.
Bounded repaint: the pulses used to ask for a frame every 80 ms from a
setInterval for as long as a subject was shown, so a parked view
repainted at 12.5 fps indefinitely. They now run for 9 s (three ring
flashes) after a selection or a camera move, fading in and out over
1.2 s, then rest: the ring stands on screen at full strength, the pulse
lines and gradient disc are hidden, echoes stop, and nothing asks for
frames. A moving subject does not wake them, since a flying subject
moves on every refresh. The lifecycle's existing camera pose signature
wakes them.
No beat with the Cyber sonar: the setInterval is replaced by a
postRender-armed setTimeout on CYBER_SONAR_RENDER_INTERVAL_MS, as in
cyberSonarScene. Every drawn frame, whoever asked for it, re-arms the
request 80 ms later, so requests never land inside the detection
lane's 80 ms gate.
Reduced motion mid-session: a change listener on the media query
rebuilds the visual, and the same-subject refresh path rebuilds when
the preference no longer matches. The listener is removed in
clearVisual.
Readable edge: restOpacity goes from 0 to 0.4, so the 250 km ring stays
visible between flashes, in screenshots and for low-vision viewers.
The echo field takes an optional level so echoes rest with the pulses.
CURRENT-STATE and the changelog fragment describe the bounded run and
the dimmed ring.
Tests: render requests stop after the bound and stay stopped for a
minute; a camera move seen by the lifecycle wakes them for another
bounded run; a foreign frame postpones the next request to 80 ms after
it; reduced motion flipped by event and by a later refresh; the ring
never drops below restOpacity; echoes scale with the level; the level
fades in, holds, fades out and keeps its value when woken.
The maintainer workflow asks runtime changes for a changelog.d/<pr>-<slug>.md
fragment and no edit to CHANGELOG.md. The three entries move unchanged, with
their credit, into changelog.d/846-voice-geometry.md.
A ½×–4× slider (log2 axis, 5 % steps, default 1×) under the intensity
filter sets how large far-zoom heat spots are. It scales the grid, not
the blur: 2× is a 1024 × 512 grid with the same one-pixel blur, so each
spot grows exactly and weak lone fires don't fade as they widen. A change
rebuilds only the heatmap. Share links keep it as w.s (percent, 50–400).
The layer row now takes a list of sliders.