Scope world overlays to each scene attachment

Move the world overlay into scene.services.overlay. Each attachment owns its
sources, collision domains, paint lanes, canvases, observers, timers and
accessible action subscribers. Keep both canvases inside the engine container,
with detection beside the card root so its screen blend still reaches the
scene. Release shared font measurements only after the last host detaches.

Resolve retained layer publications against their attached engine, clear the
outgoing source before releasing its renderer, and reconnect the shell's action
subscription on attachment. Keep destroyed hosts inert and give parked engines
fresh services. Bind annotation rectangles and the existing tracked bridge to
their engine's overlay. The tracked bridge itself remains page-owned.

Preserve Cesium's projection, card placement, arbitration, fades, hit tests,
blend order and render demand. Navara keeps the same shared behaviour. No
user-visible change is intended. Exercise simultaneous hosts, either teardown,
stale handles, reattachment and a retained selected card on the fake and
headless Cesium engines. Update QA reads and package ownership for the service.

No coupling metric falls or grows: renderer lines remain 0 Cesium and 189
Navara; external Cesium import files 3; viewer lines 891; Navara kind checks 1;
engine sniff calls 0; extension reads 3; ground passes 1; SDK loads 3;
ScreenSpaceEventHandler files 4; engine-name lines 32.

Each host now takes the page's overlay ids from the host it replaces and gives
them back to a remaining host when destroyed, and the chrome's static overlay
placeholders are gone. The new hosts had left the ids on those empty
placeholders, so the voice pointer policy, the id selectors and the QA probes
that read #world-overlay-canvas missed the drawn canvas.

Checked in the browser, keyless: the overlay baselines on both engines, CCTV
v2 (58 checks), military names, and the engine, voice, ground-layer and Ghost
Maps switches pass. The transit script fails the same 25 checks as before.
This commit is contained in:
German Khokhlov committed 2026-11-07 19:27:31 +04:00
1 parent 26597ad25c
commit 3814221cbc
62 files changed
+3148 -2655

No files matched your search

+25
View File
@@ -565,6 +565,31 @@ attachment-bound callbacks can capture `renderGovernorFor(engine)` directly.
Destroying the scene clears its holds and makes the captured service inert.
A parked engine gets a fresh service when reattached.
## World overlays
`scene.services.overlay` owns one attachment's world labels and cards. It
keeps its sources, collision domains, paint lanes, canvases, frame listeners,
observers, timers and accessible action subscribers. `init()` installs its
DOM inside `engine.host.container`; the detection blend surface stays beside
the card root so it can blend against the scene.
Publish with `setEntries(sourceId, entries, options)`, `setVisible(sourceId,
visible)` and `clearSource(sourceId)`. Read painted rectangles with
`getPaintRect(sourceId, entryId)` and register custom painters with
`registerPaintLane(laneId, painter, options)`. `subscribeActions(listener)`
provides the accessible mirror; `activateAction(owner, key)` rejects an old
host's actions. The shell reconnects these operations on every attachment.
`worldOverlayFor(engine)` resolves the same service for standalone consumers.
The module helper functions take the engine first. Retained layer models use
`bindOverlayHost` with their attached-engine getter; injected hosts without a
`forEngine` resolver keep their own operations. Publications can buffer before
`init()`. Destruction is terminal, including before initialization; a parked
engine needs fresh scene services. An old paint-lane handle cannot mutate its
replacement. Font measurements are shared until the last live host releases
them. The tracked-readout bridge remains page-owned and publishes into its
attached engine's overlay.
## Render effects
The optional `visualStyles`, `bloom` and `contactSonar` capabilities are