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:
@@ -12,7 +12,11 @@
|
||||
// booting a Pixi `Application`.
|
||||
|
||||
import { torusShortestDelta } from "./math";
|
||||
import { DEFAULT_POINT_RADIUS_PX, type PointPrim, type PrimitiveID } from "./world";
|
||||
import {
|
||||
displayPointRadiusWorld,
|
||||
type PointPrim,
|
||||
type PrimitiveID,
|
||||
} from "./world";
|
||||
|
||||
/**
|
||||
* PickModeOptions configures a pick-mode session. The caller is
|
||||
@@ -110,11 +114,15 @@ export function computePickOverlay(
|
||||
pointPrimitivesById: ReadonlyMap<PrimitiveID, PointPrim>,
|
||||
allPrimitiveIds: Iterable<PrimitiveID>,
|
||||
world: { width: number; height: number } | null = null,
|
||||
cameraScale: number = 1,
|
||||
scaleRef: number = 1,
|
||||
): PickOverlaySpec {
|
||||
const sourcePrim = pointPrimitivesById.get(options.sourcePrimitiveId);
|
||||
const sourceRadius =
|
||||
(sourcePrim?.style.pointRadiusPx ?? DEFAULT_POINT_RADIUS_PX) +
|
||||
ANCHOR_PADDING_WORLD;
|
||||
const sourceVisibleRadius =
|
||||
sourcePrim === undefined
|
||||
? 0
|
||||
: displayPointRadiusWorld(sourcePrim.style, cameraScale, scaleRef);
|
||||
const sourceRadius = sourceVisibleRadius + ANCHOR_PADDING_WORLD;
|
||||
|
||||
const dimmed = new Set<PrimitiveID>();
|
||||
for (const id of allPrimitiveIds) {
|
||||
@@ -160,12 +168,15 @@ export function computePickOverlay(
|
||||
) {
|
||||
const target = pointPrimitivesById.get(hoveredId);
|
||||
if (target !== undefined) {
|
||||
const targetRadius = displayPointRadiusWorld(
|
||||
target.style,
|
||||
cameraScale,
|
||||
scaleRef,
|
||||
);
|
||||
hoverOutline = {
|
||||
x: target.x,
|
||||
y: target.y,
|
||||
radius:
|
||||
(target.style.pointRadiusPx ?? DEFAULT_POINT_RADIUS_PX) +
|
||||
HOVER_PADDING_WORLD,
|
||||
radius: targetRadius + HOVER_PADDING_WORLD,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user