feat(ui): F8-12 — map polish (zoom invariance, labels, selection, soft radius) (#55)
* Honest pixel-space sizing for `pointRadiusPx` / `strokeWidthPx`: the renderer divides by the current camera scale on every `viewport.zoomed` so thin lines / small markers stay the same on-screen size at any zoom. * Known-size planets switch to `pointRadiusWorld`, softened against the reference scale by `PLANET_SIZE_ZOOM_ALPHA = 0.33`; unidentified planets pin to a 3-px disc. * New planet label layer renders a two-line `name / #N` legend under each planet (`#N` only for unidentified or when the new `planetNames` toggle is off). Selection now paints an inverse-fill frame around the selected planet's label plus an outline on the disc; the old selection-ring primitive is retired. * Bombing markers swap the separate CirclePrim for a planet-outline overlay (damaged / wiped colour); the report deep-link moves to a "view bombing report" link in the planet inspector. * Docs + tests follow: `renderer.md` reflects the new sizing contract + label / outline layers, vitest covers the sizing math, label formatting, and the new toggle, and the map-toggles e2e adds a persistence case for `planetNames`. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -110,7 +110,7 @@ describe("buildBattleAndBombingMarkers", () => {
|
||||
expect(out.primitives).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("emits one yellow ring per damaged bombing and red per wiped", () => {
|
||||
it("does not emit bombing primitives (F8-12 / #30) — the planet outline is drawn elsewhere", () => {
|
||||
const report = makeReport({
|
||||
planets: [
|
||||
{
|
||||
@@ -163,28 +163,12 @@ describe("buildBattleAndBombingMarkers", () => {
|
||||
attackPower: 1,
|
||||
wiped: false,
|
||||
},
|
||||
{
|
||||
planetNumber: 2,
|
||||
planet: "B",
|
||||
owner: "X",
|
||||
attacker: "Y",
|
||||
production: "MAT",
|
||||
industry: 0,
|
||||
population: 0,
|
||||
colonists: 0,
|
||||
industryStockpile: 0,
|
||||
materialsStockpile: 0,
|
||||
attackPower: 1,
|
||||
wiped: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const out = buildBattleAndBombingMarkers(report);
|
||||
const rings = out.primitives.filter((p) => p.kind === "circle");
|
||||
expect(rings).toHaveLength(2);
|
||||
expect(rings[0].style.strokeColor).toBe(DARK_THEME.bombingDamaged);
|
||||
expect(rings[1].style.strokeColor).toBe(DARK_THEME.bombingWiped);
|
||||
expect(out.primitives.filter((p) => p.kind === "circle")).toHaveLength(0);
|
||||
// `setPlanetOutlines` in the renderer paints the bombing accent.
|
||||
});
|
||||
|
||||
it("paints markers with the supplied palette's colours", () => {
|
||||
@@ -231,11 +215,9 @@ describe("buildBattleAndBombingMarkers", () => {
|
||||
|
||||
const out = buildBattleAndBombingMarkers(report, LIGHT_THEME);
|
||||
const lines = out.primitives.filter((p) => p.kind === "line");
|
||||
const rings = out.primitives.filter((p) => p.kind === "circle");
|
||||
for (const l of lines) {
|
||||
expect(l.style.strokeColor).toBe(LIGHT_THEME.battleMarker);
|
||||
}
|
||||
expect(rings[0].style.strokeColor).toBe(LIGHT_THEME.bombingWiped);
|
||||
// The accents are deliberately distinct between the palettes.
|
||||
expect(LIGHT_THEME.battleMarker).not.toBe(DARK_THEME.battleMarker);
|
||||
expect(LIGHT_THEME.bombingWiped).not.toBe(DARK_THEME.bombingWiped);
|
||||
|
||||
Reference in New Issue
Block a user