The Next and Previous buttons cycled stations with the layer's default
autoplay, so a first press started buffering a broadcaster stream even
though the panel says audio connects only after Play. Stepping now only
selects until a stream is loading, buffering or playing; once one is,
playback follows the new station so the old broadcaster does not keep
playing under the new label.
The compact Next fallback scenario in qa-radio.mjs started from a stopped
stream and relied on the old behaviour, so it now starts from a playing
station.
Fixes HAL-722
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Ukrainian in the language picker: 2730 strings, four plural forms, Cyrillic
HUD units and the uk style guide. Based on the Ukrainian translation by
@meirm (#312).
Co-authored-by: Meir Michanie <[email protected]>
Co-authored-by: Meir Michanie <[email protected]>
The HUD builds place context for its AI summary whenever the camera
settles, and each build paid for up to four reverse geocodes plus a Nearby
Places search, even when no OpenAI key was configured to use them.
- Ask GET /api/openai/hud-summary/status once; with no summary configured,
or after an unconfigured reply, make no place lookups for the page.
- Reverse-geocode at most two points: the view center and one viewport
point.
- Reuse a lookup until the view center moves a quarter of the visible
width, the camera's distance to it doubles or halves, or the camera
crosses a lookup height. The reused points are asked again, so only a
timeout, failure or empty answer spends.
- Repaint the last AI reply when a small pan leaves the context unchanged.
Cached-only hosts and voice context lookups are unchanged.
- The trailing visibility frame uses the layer's injectable runtime timer and
is cancelled by resetState as well as disable and destroy.
- An empty-feed regular pass records the camera pose, so later in-cadence
frames do not keep scheduling trailing frames.
- New renderGovernor.test.mjs: a parked camera schedules nothing, a stopped
camera gets exactly one trailing frame and no self-wake, a forced pass
requests its frame, destroy cancels the timer.
- The CHANGELOG entry moves to changelog.d/871-vessels-idle-render.md; docs
say the hold also covers vessels dimmed under a live target.
stopScene now supersedes seeks through _bumpSceneSeekGeneration; the
bhoteKoshiLocator Stop test calls stopScene on a plain object, so it
needs the method too. Without it four tests throw at the PR head.
- Superseding a seek aborts only the seek's own layer reconcile, so a
loadShot that is later rejected (shot-not-found) no longer cancels an
in-flight LOAD. Stop still aborts any LOAD.
- A refused seek rolls back to each layer's effective intent, so a manual
toggle still in flight is kept.
- A cancelled seek leaves layers to whatever superseded it, as a cancelled
LOAD does; only refusal rolls back.
- Move the _seekLoadedShot JSDoc back onto its method.
The route proxy also refuses with 'routing busy — too many routes at once'
(429) and 'route proxy error'; both showed in English in every locale.
Mark them in ROUTING_REFUSALS and add es, ru, zh-CN and zh-Hant entries.
errorText is now cleared on a new connection, a mode switch and stop(), so
it never outlives the error it describes. Tests cover the two refusals,
'Routing failed: rate limited' (pattern order) and the stop() reset.