feat(ui): Phase 29 map visibility toggles
Adds the gear-icon popover on the map view with per-game persistence of every category toggle plus the wrap-mode radio. Hide-by-id and visibility-fog facilities land on the renderer so every flip applies within one frame without a Pixi remount; the wrap-mode toggle keeps its existing remount + camera-preserve path. A new server-side turn force-resets every flag to defaults so a hidden category never makes the player miss the next turn's news. Also fixes the FligthDistance → FlightDistance typo in pkg/calc/race.go (plus the single Go caller); the TS side keeps duplicating the formula until a race-level WASM bridge lands. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+84
-21
@@ -3167,28 +3167,44 @@ Targeted tests:
|
||||
- Playwright e2e: send a message between two seeded players, confirm
|
||||
arrival.
|
||||
|
||||
## Phase 29. Map Toggles
|
||||
## ~~Phase 29. Map Toggles~~
|
||||
|
||||
Status: pending.
|
||||
Status: done.
|
||||
|
||||
Goal: deliver the gear-icon control for hiding categories of map
|
||||
content and switching between torus and no-wrap view modes. All
|
||||
toggleable categories are already rendered by earlier phases; this
|
||||
phase only exposes the controls.
|
||||
content and switching between torus and no-wrap view modes. LOCAL
|
||||
planets stay always-on; every other category gets a toggle that
|
||||
applies within one frame via the renderer's hide-by-id facility.
|
||||
|
||||
Artifacts:
|
||||
|
||||
- `ui/frontend/src/lib/active-view/map-toggles.svelte` gear icon in
|
||||
the map view's corner; popover (desktop) / bottom sheet (mobile)
|
||||
- two sections inside the popover:
|
||||
- object visibility: hyperspace groups, incoming groups, cargo
|
||||
routes, reach / visibility zones, battle and bombing markers
|
||||
- view options: wrap scrolling (torus / no-wrap)
|
||||
- planets are always rendered and not toggleable
|
||||
- `ui/frontend/src/lib/map/reach-zones.ts` implementation of reach /
|
||||
visibility zone overlays, off by default (the only category not yet
|
||||
rendered by earlier phases)
|
||||
- toggle state persists per game in `Cache`
|
||||
- `ui/frontend/src/lib/active-view/map-toggles.svelte` — gear icon
|
||||
in the map view's corner; popover (desktop) / bottom sheet
|
||||
(mobile). Three fieldsets:
|
||||
- **Objects** — hyperspace groups, incoming groups,
|
||||
unidentified groups, cargo routes, battle markers, bombing
|
||||
markers (six independent checkboxes; battle and bombing have
|
||||
their own toggles, not a shared one).
|
||||
- **Planets** — foreign / uninhabited / unidentified kind
|
||||
toggles plus a `unreachablePlanets` switch that, when off,
|
||||
hides planets beyond `FlightDistance(localPlayerDrive)` of
|
||||
every LOCAL planet (torus-aware).
|
||||
- **View** — visibility-fog checkbox + torus / no-wrap radios.
|
||||
- `RendererHandle.setHiddenPrimitiveIds(ids)` —
|
||||
declarative hide set; flips `Graphics.visible` per copy and
|
||||
threads the set into `hitTest` so click-through to deeper
|
||||
primitives is correct.
|
||||
- `RendererHandle.setVisibilityFog(circles)` — fog overlay
|
||||
drawn via Pixi v8 `Graphics.cut()` per torus copy, below
|
||||
primitives in z-order.
|
||||
- `src/map/visibility.ts` — pure helpers (`computeHiddenPlanetNumbers`,
|
||||
`computeHiddenIds`, `computeFogCircles`, `isCategoryVisible`,
|
||||
`fingerprintHiddenPlanets`) consumed by the map view.
|
||||
- `GameStateStore.mapToggles` rune + `setMapToggle` method;
|
||||
single-blob persistence in cache namespace `game-map-toggles`
|
||||
(key `{gameId}`, value `{toggles, lastResetTurn}`).
|
||||
- New-turn reset path inside `setGame` / `advanceToPending`
|
||||
drops user overrides when `lastResetTurn < currentTurn`.
|
||||
|
||||
Dependencies: Phases 9 (no-wrap engine), 11 (planets), 16 (cargo
|
||||
routes), 19 (groups, incoming), 27 (battle markers).
|
||||
@@ -3205,11 +3221,58 @@ Acceptance criteria:
|
||||
|
||||
Targeted tests:
|
||||
|
||||
- Vitest component tests for toggle state persistence;
|
||||
- Vitest unit tests for reach-zone rendering on torus and no-wrap
|
||||
fixtures;
|
||||
- Playwright e2e in desktop and mobile viewports: toggle each
|
||||
category and the wrap scrolling, assert visual change.
|
||||
- `tests/visibility-helpers.test.ts` — unit coverage for the
|
||||
hide-set / fog computation;
|
||||
- `tests/state-binding-cascade.test.ts` — `reportToWorld` emits
|
||||
the `categories` + `planetDependents` maps;
|
||||
- `tests/map-toggles-component.test.ts` — popover lifecycle +
|
||||
store wiring;
|
||||
- `tests/map-toggles-state.test.ts` — single-blob persistence +
|
||||
new-turn reset path against a real fake-IndexedDB cache;
|
||||
- `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.
|
||||
|
||||
Decisions:
|
||||
|
||||
1. **"Reach zones" reinterpreted as `unreachablePlanets` filter.**
|
||||
The original plan listed a "reach / visibility zones" category
|
||||
rendered as concentric circles. The realised stage drops the
|
||||
circle overlay and instead exposes an inverse
|
||||
`unreachablePlanets` toggle that hides planets beyond the
|
||||
player's `FlightDistance`. Reach is already implicit in the
|
||||
reach-aware destination picker (Phase 16+), so the cleaner UX
|
||||
is filtering, not adding extra rings.
|
||||
2. **Visibility fog overlay**. A separate `visibilityFog` toggle
|
||||
draws a slightly lighter fog over the world outside the union
|
||||
of `VisibilityDistance` circles around LOCAL planets. The fog
|
||||
is a renderer-level concept (Pixi `Graphics.cut()`), not a
|
||||
primitive — it never participates in hit-test.
|
||||
3. **Per-kind planet toggles + unidentified-group toggle**. The
|
||||
spec's original "object visibility" list was extended:
|
||||
foreign / uninhabited / unidentified planet kinds and
|
||||
unidentified ship groups each get their own toggle.
|
||||
4. **Battle and bombing markers are independent toggles.** The
|
||||
spec text grouped them as a single line item; on review the
|
||||
player wanted finer control, so each kind gets its own
|
||||
checkbox.
|
||||
5. **Single-blob persistence + new-turn reset.** Toggles persist
|
||||
per game as one JSON blob `{toggles, lastResetTurn}` under
|
||||
`game-map-toggles/{gameId}`. A new server-side turn force-
|
||||
resets every flag to defaults so a hidden category cannot
|
||||
silently swallow the next turn's news. History-mode
|
||||
navigation (`viewTurn`) keeps the shared state.
|
||||
6. **Hide-by-id renderer extension.** The wrap-mode toggle keeps
|
||||
the existing remount + camera-preserve path (it has to —
|
||||
torus copies need different `.visible` flags). Every
|
||||
visibility flip uses the new `setHiddenPrimitiveIds` / hide-
|
||||
aware `hitTest` so it applies within one frame.
|
||||
7. **`pkg/calc/race.go` typo fixed**. The Go-side helper was
|
||||
`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).
|
||||
|
||||
## Phase 30. Calculator Tab
|
||||
|
||||
|
||||
Reference in New Issue
Block a user