feat(ui): Phase 30 ship-class calculator with goal-seek and reach circles
Tests · UI / test (push) Successful in 2m14s
Tests · Go / test (push) Successful in 2m25s

Fuse the standalone ship-class designer (Phases 17/18) into a sidebar calculator: live mass/speed/attack/defence/bombing results, a planet build-rate readout, single-target goal-seek, a modernization-cost mode, and auto reach circles on the map for the selected planet.

pkg/calc becomes the single source for the new math (no mirroring): extract BombingPower from the engine model and the per-turn ship-production loop from controller.ProduceShip into pkg/calc (engine now delegates), and add inverse goal-seek solvers in pkg/calc/solve.go. Thin-bridge the combat, planet-build, and solver functions through ui/core/calc + ui/wasm and rebuild core.wasm.

Remove the standalone designer view/route; the ship-classes table and the view/bottom menus open the calculator via a shared request store.

Docs: rewrite ui/PLAN.md Phase 30, adjust Phase 34 (realistic forecast + CAP/COL ownership), add ui/docs/calculator-ux.md, extend calc-bridge.md, fix navigation.md; remove ui/CALCULATOR.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ilia Denisov
2026-05-21 19:52:08 +02:00
parent 00159ddf7c
commit 9ae7b88b89
53 changed files with 3748 additions and 1298 deletions
+118 -56
View File
@@ -1968,7 +1968,11 @@ Decisions baked into Phase 16 (vs. the original stage description):
## ~~Phase 17. Ship Classes — CRUD Without Calc~~
Status: done (local-ci run 20).
Status: done (local-ci run 20). Note: Phase 30 removed the standalone
designer view/route described below and folded ship-class create/view
into the sidebar calculator; the table's row-activate and "new" button
now open the calculator. The table itself and the validator are
unchanged.
Goal: list, view, create, and delete ship classes through a
dedicated table view and a designer view; numeric calculations are
@@ -2037,7 +2041,10 @@ Targeted tests:
## ~~Phase 18. Ship Classes — Calc Bridge~~
Status: done.
Status: done. Note: the live mass/speed/range preview built here moved
into the Phase 30 calculator when the standalone designer was removed;
the `ui/core/calc` ship bridge wrapped here is reused unchanged and
extended by Phase 30 (combat, planet build, solvers).
Goal: wire `pkg/calc/` ship math into the designer for live mass,
speed, range, and cargo capacity previews.
@@ -3314,39 +3321,92 @@ Decisions:
rendered result is verified by a high-contrast screenshot during
development plus the existing fog / render-on-demand e2e.
## Phase 30. Calculator Tab
## Phase 30. Ship Class Calculator
Status: pending.
Goal: ship an independent calculator in the sidebar, callable from any
view, exposing the full set of `pkg/calc/` functions wired through
`Core`.
Goal: replace the standalone Phase 17/18 ship-class designer with a
fused designer + calculator living in the sidebar. It shows the ship
design blocks, live derived results (mass, speed, attack, defence,
bombing), and a planet build-rate readout, and adds single-target
goal-seek — the player pins one result and the model back-solves the
single input it claims. A second mode reuses the design area to price
ship-class modernization. The standalone designer view and route are
removed; the ship-classes table and the view/bottom menus open the
calculator instead.
The original four detached modes (ship / path / modernization /
bombing) were dropped during planning: path is deferred (MVP path is
brute force) and replaced by auto reach circles on the map; bombing is
folded in as a per-ship result; ship and modernization are the two
modes. See `ui/CALCULATOR.md` history (removed) and the interview
decisions baked below.
Goal-seek claim map (one lock at a time): attack → weapons,
defence → shields, empty/loaded speed → drive, empty mass → cargo,
loaded mass → cargo load. Locking one result disables the others'
lock affordances; an unreachable target shows the locked cell in an
error state. Tech levels and the planet MAT are override inputs with a
reset lock; the player tech is the default.
Artifacts:
- `ui/frontend/src/lib/sidebar/calculator-tab.svelte` UI with mode
selector (ship calculator, path calculator, modernization cost,
bombing power) and per-mode forms
- bridge entries in `ui/core/calc/` for any function not already
wrapped by Phase 18
- topic doc `ui/docs/calculator-ux.md` documenting modes,
layouts, and the rule that calculator inputs persist across
navigation
- `pkg/calc/` additions, single-sourced (no mirroring): `BombingPower`
extracted from `game/internal/model/game/group.go`; a pure
`ProduceShipsInTurn` extracted from `controller.ProduceShip` (the
engine now delegates to both); inverse solvers in `pkg/calc/solve.go`
(`WeaponsForAttack`, `DriveForSpeed`, `ShieldsForDefence` by
bisection, `CargoForEmptyMass`, `LoadForFullMass`)
- thin bridges in `ui/core/calc/` (combat, planet build, solvers),
registered in `ui/wasm/main.go`, typed on `Core`
(`platform/core/index.ts` + `wasm.ts`)
- `ui/frontend/src/lib/calculator/calc-model.ts` pure orchestration
(forward results + single-target goal-seek + planet build)
- `ui/frontend/src/lib/calculator/ship-design-area.svelte` reusable
design block (5 blocks + 4 techs, override locks, computed-block
read-only) — earmarked for the future ship-group upgrade flow
- `ui/frontend/src/lib/sidebar/calculator-tab.svelte` shell (mode
selector, name combobox + Create / Delete, the calc and planet areas
inline)
- `ui/frontend/src/map/reach-circles.ts` + `lib/calculator/reach.svelte.ts`
shared store: the calculator publishes the selected planet origin and
loaded speed, the map draws 13 reach circles
- `lib/calculator/load-request.svelte.ts` shared store: the table /
menus ask the layout to open the calculator on a class
- topic doc `ui/docs/calculator-ux.md`; `ui/docs/calc-bridge.md`
extended with the new wired functions
Dependencies: Phase 18.
Dependencies: Phases 17, 18, 19/20 (selection store), 29 (map modes).
Acceptance criteria:
- every calculator mode produces results identical to direct
`pkg/calc/` calls;
- inputs persist across view switches per global state-preservation
rule;
- calculator works in history mode against the snapshot's tech levels.
- every result is byte-identical to direct `pkg/calc/` calls on shared
fixtures (Go parity tests);
- locking one result back-solves its claimed input; a second lock is
disabled; an unreachable target shows the error state;
- Create reuses the existing ship-class command flow and validator;
selecting an existing class loads it as a template;
- inputs persist across view switches per the global state-preservation
rule; the calculator works in history mode against the snapshot's
tech levels;
- selecting an own planet draws the reach circles; clearing the
selection or an invalid design removes them;
- the standalone designer view/route no longer exists.
Targeted tests:
- Vitest snapshot tests per mode on canonical inputs;
- Playwright e2e: switch modes, confirm input persistence.
- Go: `pkg/calc` unit tests + engine parity (`ProduceShip`,
`BombingPower`); `ui/core/calc` bridge parity; solver round-trips;
- Vitest: `calc-model` (forward, goal-seek per claim, infeasible),
`calculator-tab` (results, goal-seek, Create, planet area),
`reach-circles` math;
- Playwright e2e: create / list / delete via the table + calculator,
Create-disabled-while-invalid (`tests/e2e/ship-classes.spec.ts`).
Note: the WASM artefact `ui/frontend/static/core.wasm` must be rebuilt
(`make wasm`, needs TinyGo) for the new bridge functions to be present
at runtime and in the Playwright suite; Vitest injects a fake `Core`
and does not need the rebuild.
## Phase 31. Wails Desktop Wrapper
@@ -3483,54 +3543,56 @@ Targeted tests:
- regression test: bumping the app version invalidates the prior
service worker.
## Phase 34. Multi-Turn Projection — Single-Turn Forecast and Range Circles
## Phase 34. Multi-Turn Projection — Realistic Planet Forecast
Status: pending. Long-term scope deferred but this phase ships real
features.
Goal: ship two concrete projection features (planet next-turn
forecast and ship-designer reach circles) plus the transient
map-overlay back-stack mechanism that the reach-circles feature is
the first user of.
Goal: ship a realistic multi-turn planet projection and surface it in
the planet inspector and in the calculator's planet area. Reach circles
already shipped in Phase 30 (auto-drawn from the calculator's selected
planet); this phase no longer owns them.
The Phase 30 planet area is single-turn (MAT-only): it answers "ships
this turn / turns per ship" at the current or overridden MAT. This phase
makes it realistic and multi-turn by extracting the planet economy into
`pkg/calc` and simulating turns: population growth (`×1.08`), material /
capital / colonist supply, and the capital/colonist unpacking that
mirrors `MakeTurn` steps 09/12/14/15. CAP and COL only affect future
turns (post-production unpacking), so they become meaningful here and
are added to the calculator's planet area as supply inputs alongside
MAT.
Artifacts:
- `ui/frontend/src/lib/projection/` minimal projection engine that
computes one-turn-ahead state for a single planet using `pkg/calc/`
- planet inspector forecast section showing next-turn population,
industry, materials stockpile, and production progress
- `ui/frontend/src/lib/navigation/transient-overlay.ts` push/pop
back-stack mechanism for map overlays driven by other views, with
a back-button affordance on the map that returns to the originating
view with state preserved
- ship-designer `Preview range on map` action that pushes a transient
overlay onto the map showing concentric reach circles for 1, 2, 3,
4 turns from a chosen origin, computed from the in-progress ship
design and the player's current Drive tech via `ui/core/calc/`
- topic doc `ui/docs/multi-turn-projection.md` describing the
long-term vision (multi-turn planning mode, scenario branches) and
the phased path to it
- `pkg/calc/` planet-economy extraction (single-sourced, engine
delegates): `PlanetProduction`, `ProducePopulation`,
`UnpackColonists`, `UnpackCapital`, reusing `ProduceShipsInTurn`; a
multi-turn projector `ProjectPlanetBuild` answering "K ships in M
turns" under guaranteed per-turn supply
- thin bridges in `ui/core/calc/` + `Core` typings
- planet inspector forecast section (next-turn population, industry,
materials, production progress)
- calculator planet area gains CAP and COL supply inputs and switches
its readout to the multi-turn projector
- topic doc `ui/docs/multi-turn-projection.md` (long-term vision:
multi-turn planning mode, scenario branches)
Dependencies: Phases 17, 18.
Dependencies: Phases 17, 18, 30.
Acceptance criteria:
- the planet inspector shows a forecast section with next-turn values
matching `pkg/calc/` outputs;
- the ship-designer `Preview range on map` button transitions to the
map with reach circles drawn from the chosen origin; back returns
to the designer with all in-progress state intact;
- the transient overlay is cleared if the user navigates to any other
view via the header dropdown.
- projector output is byte-identical to running the engine's per-turn
planet update over the same turns (Go parity);
- the planet inspector shows a forecast section matching it;
- the calculator planet area honours MAT / CAP / COL supply and shows
"K ships in M turns" consistent with the projector.
Targeted tests:
- Vitest unit tests for the projection engine on canonical fixtures;
- Vitest unit tests for the transient-overlay push/pop logic and
state preservation;
- Playwright e2e: open a planet inspector, observe one-turn forecast;
open a ship designer, click `Preview range on map`, see reach
circles, click back, return with state intact.
- Go parity tests for each extracted economy formula and the projector;
- Vitest for the calculator planet area with supply inputs;
- Playwright e2e: planet inspector forecast section.
## Phase 35. Polish — Accessibility, Localisation, Error UX