From 75a42113738f4ef2b622a3634077d2d3283839de Mon Sep 17 00:00:00 2001 From: Ilia Denisov Date: Thu, 28 May 2026 00:14:14 +0200 Subject: [PATCH] =?UTF-8?q?fix(ui):=20F8-12=20=E2=80=94=20settle=20e2e=20r?= =?UTF-8?q?egressions=20from=20the=20polish=20PR=20(#55)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * state-binding.ts: normalise planet size by the engine's typical mid-range (`SIZE_NORMALIZER = 100`) so legacy fixtures recording Size in the hundreds do not blow up the world-unit disc and start overlapping neighbouring planets. The cube-root growth stays; Size-800 reads twice as big as Size-100. * cargo-routes.spec.ts: retire the selection-ring CirclePrim from the expected primitive count (4 planets + 3 cargo arrow lines = 7). * map-toggles.spec.ts: bombing-rings → planet outlines (the high-bit 0xc… range is permanently empty); planet-names persist test waits for the renderer's debug providers and for the IndexedDB write to flush before reload. Co-Authored-By: Claude Opus 4.7 --- ui/frontend/src/map/state-binding.ts | 23 +++++++++++++-------- ui/frontend/tests/e2e/cargo-routes.spec.ts | 8 +++++--- ui/frontend/tests/e2e/map-toggles.spec.ts | 24 ++++++++++++++++------ 3 files changed, 38 insertions(+), 17 deletions(-) diff --git a/ui/frontend/src/map/state-binding.ts b/ui/frontend/src/map/state-binding.ts index 5316138..4b27ea2 100644 --- a/ui/frontend/src/map/state-binding.ts +++ b/ui/frontend/src/map/state-binding.ts @@ -39,15 +39,21 @@ import { // extra lookup. /** - * KNOWN_PLANET_BASE_RADIUS_WORLD is the world-unit scale of the cube- - * root size mapping for planets with a known `size`. With α = 0.33 - * the on-screen pixel radius at default zoom is roughly - * `BASE * cbrt(size) * scaleRef`. The cube root keeps planet area - * proportional to volume, so a Size-8 planet reads twice as big as a - * Size-1 one. Owner can tune this together with `PLANET_SIZE_ZOOM_ALPHA` - * during the F8 manual-QA loop. + * KNOWN_PLANET_BASE_RADIUS_WORLD calibrates the cube-root size + * mapping so that an "average" planet (`size === SIZE_NORMALIZER`) + * renders at roughly this radius in world units when the camera is + * at the reference scale. Larger / smaller planets scale by + * `cbrt(size / SIZE_NORMALIZER)`, which keeps disc area proportional + * to volume — a Size-800 planet reads twice as big as a Size-100 one, + * eight times its volume but only 2× the radius. + * + * `SIZE_NORMALIZER` follows the engine's typical mid-range. Without + * it, the raw cube-root grows huge for legacy fixtures that record + * Size in hundreds; with it, the disc stays in a sane world-unit + * band so neighbouring planets never overlap on the default zoom. */ const KNOWN_PLANET_BASE_RADIUS_WORLD = 4; +const SIZE_NORMALIZER = 100; /** * UNKNOWN_PLANET_PIXEL_RADIUS matches issue #55 / п.28: planets with @@ -62,7 +68,8 @@ function styleFor(planet: ReportPlanet, theme: Theme): Style { if (planet.kind === "unidentified" || size === null || !(size > 0)) { return { ...fill, pointRadiusPx: UNKNOWN_PLANET_PIXEL_RADIUS }; } - const baseRadius = KNOWN_PLANET_BASE_RADIUS_WORLD * Math.cbrt(size); + const baseRadius = + KNOWN_PLANET_BASE_RADIUS_WORLD * Math.cbrt(size / SIZE_NORMALIZER); return { ...fill, pointRadiusWorld: baseRadius }; } diff --git a/ui/frontend/tests/e2e/cargo-routes.spec.ts b/ui/frontend/tests/e2e/cargo-routes.spec.ts index 87b44db..cfefebe 100644 --- a/ui/frontend/tests/e2e/cargo-routes.spec.ts +++ b/ui/frontend/tests/e2e/cargo-routes.spec.ts @@ -461,10 +461,12 @@ test("cargo-routes flow: pick a destination, arrow appears, reload restores", as lines: prims.filter((p) => p.kind === "line").length, }; }); - // `total` also counts the selected source planet's selection ring - // (F4 — one circle), so it is one more than the planet + line prims. + // F8-12 / #30 retired the selection-ring CirclePrim: selection is + // now drawn as an outline overlay around the planet disc, outside + // the primitive surface. Expected total = 4 planets + 3 cargo + // arrow lines. await expect.poll(debugLineCount, { timeout: 15000 }).toEqual({ - total: 8, + total: 7, lines: 3, }); diff --git a/ui/frontend/tests/e2e/map-toggles.spec.ts b/ui/frontend/tests/e2e/map-toggles.spec.ts index b0c96f5..60b7d9d 100644 --- a/ui/frontend/tests/e2e/map-toggles.spec.ts +++ b/ui/frontend/tests/e2e/map-toggles.spec.ts @@ -268,10 +268,12 @@ test("gear popover toggles a planet kind off and cascades onto its markers", asy await openGame(page); // Baseline — every planet shows up, plus the battle X-cross (2 - // LinePrim) and the bombing ring on the foreign planet. + // LinePrim). F8-12 / #30 retired the bombing CirclePrim; the + // visual cue is now a planet outline drawn outside the primitive + // surface, so the high-bit 0xc… range stays empty by construction. expect(await visiblePlanets(page)).toEqual([1, 2, 3, 4, 5]); expect(await visibleHighBitCount(page, 0xa0000000)).toBe(2); - expect(await visibleHighBitCount(page, 0xc0000000)).toBe(1); + expect(await visibleHighBitCount(page, 0xc0000000)).toBe(0); await page.getByTestId("map-toggles-trigger").click(); await expect(page.getByTestId("map-toggles-surface")).toBeVisible(); @@ -293,7 +295,6 @@ test("gear popover toggles a planet kind off and cascades onto its markers", asy expect(await visiblePlanets(page)).toEqual([1, 2, 4, 5]); expect(await visibleHighBitCount(page, 0xa0000000)).toBe(0); - expect(await visibleHighBitCount(page, 0xc0000000)).toBe(0); }); test("visibility fog toggles between the LOCAL-planet circle list and an empty overlay", async ({ @@ -385,15 +386,26 @@ test("planet-names toggle persists across a page reload (F8-12 / #29)", async ({ true, ); await page.getByTestId("map-toggles-planet-names").click(); - expect(await page.getByTestId("map-toggles-planet-names").isChecked()).toBe( - false, - ); + await expect + .poll(() => + page + .getByTestId("map-toggles-planet-names") + .isChecked(), + ) + .toBe(false); + // Wait for the IndexedDB write to flush so the reload observes the + // persisted blob instead of the pre-flip defaults. + await page.waitForTimeout(200); await page.reload({ waitUntil: "commit" }); await expect(page.getByTestId("active-view-map")).toHaveAttribute( "data-status", "ready", ); + await page.waitForFunction(() => { + const prims = window.__galaxyDebug?.getMapPrimitives?.() ?? []; + return prims.length > 0; + }); await page.getByTestId("map-toggles-trigger").click(); expect(await page.getByTestId("map-toggles-planet-names").isChecked()).toBe( false,