fix(ui-map): repaint fog as layered overpaint; rename to visibleHyperspace
Tests · UI / test (push) Waiting to run

The Phase 29 fog overlay rendered as a handful of random arc
segments instead of a clean union of holes around LOCAL planets
— Pixi v8's `Graphics.cut()` does not reliably subtract multiple
overlapping circles from a base path.

Replaced the cut-based approach with a layered overpaint: a
fog-tinted rectangle fills the world, then opaque background-
coloured circles are painted on top for every visibility circle.
The natural rendering order unions overlapping circles for free —
no geometry, no `cut()` quirks, one extra fill per circle.

Renamed the toggle from `visibilityFog` to `visibleHyperspace`
across the store, i18n strings, popover, tests, and docs. The
overlay still implements the visual "fog" effect at the renderer
level (FOG_COLOR, setVisibilityFog, getMapFog); the toggle is
named after the player-facing concept it controls — the portion
of the map that is visible (intelligence/scan coverage) — rather
than the obscured part.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ilia Denisov
2026-05-19 23:39:39 +02:00
parent 2f4dc01d54
commit 37580b7699
16 changed files with 86 additions and 65 deletions
+14 -14
View File
@@ -704,31 +704,31 @@ export async function createRenderer(opts: RendererOptions): Promise<RendererHan
},
isPrimitiveHidden: (id) => hiddenIds.has(id),
setVisibilityFog: (circles) => {
if (circles.length === 0) {
for (const g of fogGraphics) {
g.parent?.removeChild(g);
g.destroy();
}
fogGraphics = [];
return;
}
// Recreate the fog Graphics on every call. Pixi v8's
// `Graphics.clear()` exists but reusing the same instance
// with multiple `.cut()` operations across calls can
// accumulate stale path state in our experience; a fresh
// Graphics keeps the contract simple.
// Drop the old fog Graphics first — every flip rebuilds
// from scratch instead of mutating in place, so the
// implementation stays simple and Pixi-v8-residue-free.
for (const g of fogGraphics) {
g.parent?.removeChild(g);
g.destroy();
}
fogGraphics = [];
if (circles.length === 0) return;
// Layered overpaint: a fog-tinted rectangle covers the
// world, then opaque background-coloured circles drawn on
// top reveal the visible-hyperspace area. The natural
// rendering order handles overlapping circles correctly —
// Pixi v8's `Graphics.cut()` produces inconsistent
// results for unions of holes (the previous Phase 29
// implementation hit this), and the overpaint approach
// avoids the geometry calculation entirely.
const bg = theme.background;
for (const copy of copies) {
const g = new Graphics();
g.rect(0, 0, opts.world.width, opts.world.height);
g.fill({ color: FOG_COLOR, alpha: 1 });
for (const c of circles) {
g.circle(c.x, c.y, c.radius);
g.cut();
g.fill({ color: bg, alpha: 1 });
}
// Fog sits below every primitive on the same copy so
// planet glyphs paint on top. `addChildAt(g, 0)` keeps