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
@@ -73,6 +73,10 @@ fresh.
GALAXY_CLIENT_CONTEXT_KEY,
GalaxyClientHolder,
} from "$lib/galaxy-client-context.svelte";
import {
CORE_CONTEXT_KEY,
CoreHolder,
} from "$lib/core-context.svelte";
import { session } from "$lib/session-store.svelte";
import { loadStore } from "../../../platform/store/index";
import { loadCore } from "../../../platform/core/index";
@@ -105,6 +109,8 @@ fresh.
setContext(RENDERED_REPORT_CONTEXT_KEY, renderedReport);
const galaxyClient = new GalaxyClientHolder();
setContext(GALAXY_CLIENT_CONTEXT_KEY, galaxyClient);
const coreHolder = new CoreHolder();
setContext(CORE_CONTEXT_KEY, coreHolder);
// `MapPickService` lives at the layout so both the active map
// view (which binds the renderer-side resolver) and the
// inspector subsections (which call `pick(...)`) see the same
@@ -172,6 +178,7 @@ fresh.
const deviceSessionId = session.deviceSessionId;
try {
const [{ cache }, core] = await Promise.all([loadStore(), loadCore()]);
coreHolder.set(core);
const client = new GalaxyClient({
core,
edge: createEdgeGatewayClient(GATEWAY_BASE_URL),