fix(ui-map): render-on-demand + drop pan inertia to stop the Safari fog freeze
Tests · UI / test (push) Successful in 1m55s
Tests · UI / test (pull_request) Successful in 2m4s

The Phase 29 visibility fog ("visible hyperspace") froze the whole UI on
large reports in Safari while staying smooth in Firefox. Root cause: the
fog is a layered overpaint (torus mode = 9 world-sized rects + 9xN
near-world-sized opaque circles, ~270 fills for KNNTS041) and Pixi's
continuous auto-render loop re-rasterised all of it every frame, even
while idle. Safari's WebGPU backend cannot sustain that fillrate, so the
main thread/compositor starved and the entire UI froze.

Stage 1 (vector-preserving, no rasterisation):

- Stop Pixi's auto-render loop (app.stop()) and paint on demand via a
  single Ticker.shared flush gated on viewport.dirty (camera) plus an
  internal requestRender() from every content mutation (fog / hide-set /
  extras / wrap mode / resize / pick overlay). An idle map now does zero
  GPU work per frame; plain hover paints nothing.
- Remove the decelerate (drag-inertia) plugin: a released drag stops
  instantly (owner request) and the viewport goes idle immediately.
- Expose RendererHandle.getRenderCount() / getMapRenderCount for
  deterministic e2e assertions.

Tests: new map-toggles e2e specs (idle map does not repaint; released
drag does not coast) green on all four Playwright projects incl. WebKit.
Docs: renderer.md (render-on-demand section; fog section corrected to the
current single-fogLayer model; FPS note) and PLAN.md Phase 29 decision 8.

If Safari pan is still heavy after this, stage 2 will cut the overpaint
itself with an inverse stencil mask of the circle union (kept vector).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ilia Denisov
2026-05-20 16:28:18 +02:00
parent 0da2f4b6fb
commit 51902b995f
7 changed files with 307 additions and 28 deletions
+20 -2
View File
@@ -3235,8 +3235,9 @@ Targeted tests:
- `tests/map-hit-test.test.ts` — `hitTest` honours the
`hiddenIds` parameter;
- `tests/e2e/map-toggles.spec.ts` — cascade, fog, wrap-mode
camera preservation, reload persistence across the four
Playwright projects.
camera preservation, reload persistence, plus render-on-demand
(an idle map does not repaint; a released drag does not coast)
across the four Playwright projects.
Decisions:
@@ -3278,6 +3279,23 @@ Decisions:
`FligthDistance`; the Phase 29 work renamed it to
`FlightDistance` (and the only TS call site duplicates the
formula directly, awaiting a future race-level WASM bridge).
8. **Render-on-demand + no pan inertia (fog perf, stage 1).** The
renderer originally kept Pixi's continuous auto-render loop, so
the visibility fog's layered overpaint re-rasterised every frame
and froze the whole UI on large reports in Safari (Pixi's WebGPU
backend) — even while idle. The renderer now stops the auto-render
loop (`app.stop()`) and paints on demand: a single `Ticker.shared`
flush renders only when `viewport.dirty` (camera moved) or an
internal `requestRender()` fires from a content mutation
(`setVisibilityFog` / `setHiddenPrimitiveIds` /
`setExtraPrimitives` / `applyMode` / `resize` / pick overlay);
plain hover paints nothing. The `decelerate` (drag-inertia) plugin
is removed so a released drag stops instantly and the viewport
goes idle immediately. `RendererHandle.getRenderCount()` (mirrored
on `__galaxyDebug` as `getMapRenderCount`) backs the e2e
assertions. If Safari pan is still heavy after this, stage 2 cuts
the overpaint itself (an inverse stencil mask of the circle union,
kept vector so the map stays crisp at any zoom).
## Phase 30. Calculator Tab