fix(ui): F8-12 — settle e2e regressions from the polish PR (#55)
* 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 <noreply@anthropic.com>
This commit is contained in:
@@ -39,15 +39,21 @@ import {
|
|||||||
// extra lookup.
|
// extra lookup.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* KNOWN_PLANET_BASE_RADIUS_WORLD is the world-unit scale of the cube-
|
* KNOWN_PLANET_BASE_RADIUS_WORLD calibrates the cube-root size
|
||||||
* root size mapping for planets with a known `size`. With α = 0.33
|
* mapping so that an "average" planet (`size === SIZE_NORMALIZER`)
|
||||||
* the on-screen pixel radius at default zoom is roughly
|
* renders at roughly this radius in world units when the camera is
|
||||||
* `BASE * cbrt(size) * scaleRef`. The cube root keeps planet area
|
* at the reference scale. Larger / smaller planets scale by
|
||||||
* proportional to volume, so a Size-8 planet reads twice as big as a
|
* `cbrt(size / SIZE_NORMALIZER)`, which keeps disc area proportional
|
||||||
* Size-1 one. Owner can tune this together with `PLANET_SIZE_ZOOM_ALPHA`
|
* to volume — a Size-800 planet reads twice as big as a Size-100 one,
|
||||||
* during the F8 manual-QA loop.
|
* 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 KNOWN_PLANET_BASE_RADIUS_WORLD = 4;
|
||||||
|
const SIZE_NORMALIZER = 100;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UNKNOWN_PLANET_PIXEL_RADIUS matches issue #55 / п.28: planets with
|
* 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)) {
|
if (planet.kind === "unidentified" || size === null || !(size > 0)) {
|
||||||
return { ...fill, pointRadiusPx: UNKNOWN_PLANET_PIXEL_RADIUS };
|
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 };
|
return { ...fill, pointRadiusWorld: baseRadius };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -461,10 +461,12 @@ test("cargo-routes flow: pick a destination, arrow appears, reload restores", as
|
|||||||
lines: prims.filter((p) => p.kind === "line").length,
|
lines: prims.filter((p) => p.kind === "line").length,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
// `total` also counts the selected source planet's selection ring
|
// F8-12 / #30 retired the selection-ring CirclePrim: selection is
|
||||||
// (F4 — one circle), so it is one more than the planet + line prims.
|
// 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({
|
await expect.poll(debugLineCount, { timeout: 15000 }).toEqual({
|
||||||
total: 8,
|
total: 7,
|
||||||
lines: 3,
|
lines: 3,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -268,10 +268,12 @@ test("gear popover toggles a planet kind off and cascades onto its markers", asy
|
|||||||
await openGame(page);
|
await openGame(page);
|
||||||
|
|
||||||
// Baseline — every planet shows up, plus the battle X-cross (2
|
// 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 visiblePlanets(page)).toEqual([1, 2, 3, 4, 5]);
|
||||||
expect(await visibleHighBitCount(page, 0xa0000000)).toBe(2);
|
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 page.getByTestId("map-toggles-trigger").click();
|
||||||
await expect(page.getByTestId("map-toggles-surface")).toBeVisible();
|
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 visiblePlanets(page)).toEqual([1, 2, 4, 5]);
|
||||||
expect(await visibleHighBitCount(page, 0xa0000000)).toBe(0);
|
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 ({
|
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,
|
true,
|
||||||
);
|
);
|
||||||
await page.getByTestId("map-toggles-planet-names").click();
|
await page.getByTestId("map-toggles-planet-names").click();
|
||||||
expect(await page.getByTestId("map-toggles-planet-names").isChecked()).toBe(
|
await expect
|
||||||
false,
|
.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 page.reload({ waitUntil: "commit" });
|
||||||
await expect(page.getByTestId("active-view-map")).toHaveAttribute(
|
await expect(page.getByTestId("active-view-map")).toHaveAttribute(
|
||||||
"data-status",
|
"data-status",
|
||||||
"ready",
|
"ready",
|
||||||
);
|
);
|
||||||
|
await page.waitForFunction(() => {
|
||||||
|
const prims = window.__galaxyDebug?.getMapPrimitives?.() ?? [];
|
||||||
|
return prims.length > 0;
|
||||||
|
});
|
||||||
await page.getByTestId("map-toggles-trigger").click();
|
await page.getByTestId("map-toggles-trigger").click();
|
||||||
expect(await page.getByTestId("map-toggles-planet-names").isChecked()).toBe(
|
expect(await page.getByTestId("map-toggles-planet-names").isChecked()).toBe(
|
||||||
false,
|
false,
|
||||||
|
|||||||
Reference in New Issue
Block a user