ui/phase-9: PixiJS map renderer with torus and no-wrap modes
Stand up the vector map renderer in ui/frontend/src/map/ on top of PixiJS v8 + pixi-viewport@^6. Torus mode renders nine container copies for seamless wrap; no-wrap mode pins the camera at world bounds and centres on an axis when the viewport exceeds the world along that axis. Hit-test is a brute-force pass with deterministic [-priority, distSq, kindOrder, id] ordering and torus-shortest distance, validated by hand-built unit cases. The development playground at /__debug/map exposes a window debug surface for the Playwright spec, which forces WebGPU on chromium-desktop, WebGL on webkit-desktop, and accepts the auto-picked backend on mobile projects. Algorithm spec lives in ui/docs/renderer.md, which also pins the new deprecation status of galaxy/client (the entire Fyne client module, including client/world). client/world/README.md and the Phase 9 stub in ui/PLAN.md gain matching deprecation banners. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
// Fixture data for the map renderer playground and visual checks.
|
||||
//
|
||||
// sampleWorld() returns a 1000-primitive deterministic world built
|
||||
// with a small linear-congruential RNG so the layout is reproducible
|
||||
// across runs and across machines. The mix of primitive kinds
|
||||
// exercises all draw paths: many points (planets), several stroked
|
||||
// circles (orbits), several filled circles (zones), and a handful of
|
||||
// lines (routes).
|
||||
|
||||
import {
|
||||
type CirclePrim,
|
||||
type LinePrim,
|
||||
type PointPrim,
|
||||
type Primitive,
|
||||
World,
|
||||
} from "./world";
|
||||
|
||||
const WORLD_W = 4000;
|
||||
const WORLD_H = 4000;
|
||||
|
||||
// Tiny deterministic RNG so fixtures stay byte-identical regardless
|
||||
// of host platform. Seed values picked to give a visually pleasant
|
||||
// distribution; not cryptographically meaningful.
|
||||
function lcg(seed: number): () => number {
|
||||
let s = seed >>> 0;
|
||||
return () => {
|
||||
s = (Math.imul(s, 1664525) + 1013904223) >>> 0;
|
||||
return s / 0x1_0000_0000;
|
||||
};
|
||||
}
|
||||
|
||||
// sampleWorld constructs the playground world. The result is stable
|
||||
// across calls — it allocates fresh arrays but the data is identical.
|
||||
export function sampleWorld(): World {
|
||||
const rand = lcg(0x5eed1234);
|
||||
const primitives: Primitive[] = [];
|
||||
let nextId = 0;
|
||||
|
||||
// 950 stars (points).
|
||||
for (let i = 0; i < 950; i++) {
|
||||
const star: PointPrim = {
|
||||
kind: "point",
|
||||
id: nextId++,
|
||||
x: rand() * WORLD_W,
|
||||
y: rand() * WORLD_H,
|
||||
priority: 1,
|
||||
style: { pointRadiusPx: 2 + Math.floor(rand() * 3) },
|
||||
hitSlopPx: 0,
|
||||
};
|
||||
primitives.push(star);
|
||||
}
|
||||
|
||||
// 30 stroked circles (orbits / influence rings).
|
||||
for (let i = 0; i < 30; i++) {
|
||||
const orbit: CirclePrim = {
|
||||
kind: "circle",
|
||||
id: nextId++,
|
||||
x: rand() * WORLD_W,
|
||||
y: rand() * WORLD_H,
|
||||
radius: 80 + rand() * 220,
|
||||
priority: 2,
|
||||
style: { strokeWidthPx: 1, strokeAlpha: 0.6 },
|
||||
hitSlopPx: 0,
|
||||
};
|
||||
primitives.push(orbit);
|
||||
}
|
||||
|
||||
// 10 filled translucent circles (zones).
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const zone: CirclePrim = {
|
||||
kind: "circle",
|
||||
id: nextId++,
|
||||
x: rand() * WORLD_W,
|
||||
y: rand() * WORLD_H,
|
||||
radius: 150 + rand() * 250,
|
||||
priority: 0,
|
||||
style: { fillColor: 0x37474f, fillAlpha: 0.25 },
|
||||
hitSlopPx: 0,
|
||||
};
|
||||
primitives.push(zone);
|
||||
}
|
||||
|
||||
// 10 lines (routes between random anchor points).
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const route: LinePrim = {
|
||||
kind: "line",
|
||||
id: nextId++,
|
||||
x1: rand() * WORLD_W,
|
||||
y1: rand() * WORLD_H,
|
||||
x2: rand() * WORLD_W,
|
||||
y2: rand() * WORLD_H,
|
||||
priority: 3,
|
||||
style: { strokeWidthPx: 1, strokeAlpha: 0.8 },
|
||||
hitSlopPx: 0,
|
||||
};
|
||||
primitives.push(route);
|
||||
}
|
||||
|
||||
return new World(WORLD_W, WORLD_H, primitives);
|
||||
}
|
||||
Reference in New Issue
Block a user