ui/phase-18: ship-class calc bridge with live designer preview

Wires pkg/calc/ship.go into the WASM Core boundary as seven thin
wrappers (DriveEffective, EmptyMass, WeaponsBlockMass, FullMass,
Speed, CargoCapacity, CarryingMass). The ship-class designer reads
Core through a new CORE_CONTEXT_KEY populated by the in-game layout
and renders a five-row preview pane (mass, full-load mass, max
speed, range at full load, cargo capacity) that updates reactively
on every form edit and on the player's localPlayer{Drive,Weapons,
Shields,Cargo} tech levels — three of which are now decoded from
the report's Player block alongside the existing localPlayerDrive.

CarryingMass is the seventh wrapper added to the original six-function
list so that "full-load mass" composes through pkg/calc/ functions
without putting math in TypeScript.
This commit is contained in:
Ilia Denisov
2026-05-09 23:14:40 +02:00
parent 721fa2172d
commit e4dc0ce029
25 changed files with 1056 additions and 64 deletions
+42 -21
View File
@@ -2012,28 +2012,44 @@ Targeted tests:
class, list it, delete it; rejected-submit kept; field-validation
kept (Save disabled with localised tooltip).
## Phase 18. Ship Classes — Calc Bridge
## ~~Phase 18. Ship Classes — Calc Bridge~~
Status: pending.
Status: done.
Goal: wire `pkg/calc/` ship math into the designer for live mass,
speed, range, and cargo capacity previews.
Artifacts:
- `ui/core/calc/ship.go` thin Go bridge wrapping `pkg/calc/.FullMass`,
`EmptyMass`, `Speed`, `CargoCapacity`, `WeaponsBlockMass`,
`DriveEffective` in JSON-marshallable signatures, exported through
the `Core` API
- `ui/frontend/src/platform/core/index.ts` extends `Core` interface
with the new calc methods
- live-updating preview pane in the ship-class designer showing mass,
full-load mass, max speed, range, and cargo capacity at the player's
current tech levels
- audit step recorded in `ui/docs/calc-bridge.md`: every wired
function listed against its `pkg/calc/` source
- if any required `pkg/calc/` function is missing, this phase raises a
blocker and the function is added to `pkg/calc/` first (owner-led)
- `ui/core/calc/ship.go` thin Go bridge wrapping seven functions
from `pkg/calc/ship.go` — `DriveEffective`, `EmptyMass`,
`WeaponsBlockMass`, `FullMass`, `Speed`, `CargoCapacity`,
`CarryingMass` — each as a one-line passthrough; the seventh
function (`CarryingMass`) was added during stage implementation
to let the preview compose `full-load mass` from `CargoCapacity`
without injecting math into TS;
- `ui/wasm/main.go` registers the seven wrappers under
`globalThis.galaxyCore`; `ui/frontend/src/platform/core/index.ts`
extends `Core` with the matching typed methods (`emptyMass` and
`weaponsBlockMass` return `number | null`, mirroring the Go
`(_, false)` validator path);
- `ui/frontend/src/api/game-state.ts` extends `GameReport` with
`localPlayerWeapons`, `localPlayerShields`, `localPlayerCargo`
alongside the existing `localPlayerDrive`. The decoder reads
all four from the `Player` row in the report's player block.
Phases 19-21 reuse these fields without re-extending the report;
- `ui/frontend/src/lib/core-context.svelte.ts` exposes a
`CoreHolder` through `CORE_CONTEXT_KEY`. The in-game layout
(`routes/games/[id]/+layout.svelte`) populates the holder after
`loadCore()` resolves, so the designer reads `Core` from context
without re-booting WASM;
- live-updating preview pane in the ship-class designer showing
empty mass, full-load mass, max speed (at empty), range at full
load, and cargo capacity per ship at the player's current tech
levels; the pane only renders when the form passes validation
*and* `Core` is ready;
- audit step recorded in `ui/docs/calc-bridge.md`: live surface
table lists every wired function against its `pkg/calc/` source.
Dependencies: Phases 5 (Core skeleton), 17.
@@ -2047,11 +2063,14 @@ Acceptance criteria:
Targeted tests:
- Go parity tests in `ui/core/calc/` against `pkg/calc/` outputs on
shared fixtures;
- Vitest snapshot tests for the preview pane on canonical inputs;
- Playwright e2e: edit a ship class, observe preview updates and
submit, confirm server-side mass matches.
- Go parity tests in `ui/core/calc/ship_test.go` against `pkg/calc/`
outputs on shared fixtures, plus a composition test that exercises
the exact preview pipeline (empty → cargo capacity → carrying mass
→ full-load mass → speed at empty + at full);
- Vitest coverage in `ui/frontend/tests/designer-ship-class.test.ts`
asserts preview hidden until validation passes, hidden when no
`Core` is available, renders five rows with computed values once
the form is valid, and reactively refreshes on subsequent edits.
## Phase 19. Inspector — Ship Group (Read-Only)
@@ -2112,7 +2131,9 @@ Artifacts:
`SendGroup`, `LoadCargo`, `UnloadCargo`, `Modernize`, `Dismantle`,
`TransferToRace`, `AssignToFleet` command variants
- `Send` action picks destination through a planet picker filtered by
the group's reach (uses `pkg/calc/` reach function via Core)
the group's reach (uses `pkg/calc/` reach function via Core; the
player's tech levels are already on `GameReport.localPlayer*` from
Phase 18, no extra plumbing needed)
- `Modernize` cost preview using `pkg/calc/` formula via Core
- confirmation dialog for `Dismantle` over a foreign planet with
colonists onboard (special-case from [`rules.txt`](../game/rules.txt): colonists die)