Letter the warp openings and show where they lead
Paired openings now share a printed letter (A, B, C ...), exactly as the physical boards mark them — making the 2-player crossed pairings legible at a glance. While standing on an opening, its destination square pulses with a dashed green ring, so "leave at B, re-enter at B" stops being a leap of faith. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
87a5067c77
commit
d7afe3a5ca
@@ -64,6 +64,20 @@
|
||||
return boxes;
|
||||
});
|
||||
|
||||
// Warp pairs share a letter, like the printed openings on the real boards.
|
||||
const warpLetters = $derived.by(() => {
|
||||
const letters = new Map<string, string>();
|
||||
let next = 0;
|
||||
for (const w of view.board.warps) {
|
||||
const a = `${w.from.cell.x},${w.from.cell.y}`;
|
||||
const b = `${w.to.cell.x},${w.to.cell.y}`;
|
||||
const key = [a, b].sort().join("|");
|
||||
if (!letters.has(key)) letters.set(key, String.fromCharCode(65 + next++));
|
||||
letters.set(a, letters.get(key)!);
|
||||
}
|
||||
return letters;
|
||||
});
|
||||
|
||||
// Group players by cell so co-located wizards fan out.
|
||||
const wizardsByCell = $derived.by(() => {
|
||||
const map = new Map<string, typeof view.players>();
|
||||
@@ -209,6 +223,7 @@
|
||||
(w.from.side === "S" ? CELL * 0.42 : w.from.side === "N" ? -CELL * 0.42 : 0)}
|
||||
{@const standing = view.players.some((p) =>
|
||||
p.id === view.you && p.position.x === w.from.cell.x && p.position.y === w.from.cell.y)}
|
||||
{@const letter = warpLetters.get(`${w.from.cell.x},${w.from.cell.y}`) ?? ""}
|
||||
<g
|
||||
class="warp-g" class:standing
|
||||
role="button" tabindex="-1"
|
||||
@@ -218,7 +233,19 @@
|
||||
<circle cx={wx} cy={wy} r={11} class="warp-hit" />
|
||||
<text x={wx} y={wy + 4.5} class="warp"
|
||||
>{w.from.side === "N" ? "↑" : w.from.side === "S" ? "↓" : w.from.side === "E" ? "→" : "←"}</text>
|
||||
<text
|
||||
x={wx + (w.from.side === "E" ? -13 : w.from.side === "W" ? 13 : 12)}
|
||||
y={wy + (w.from.side === "N" ? 13 : w.from.side === "S" ? -9 : 4)}
|
||||
class="warp-letter"
|
||||
>{letter}</text>
|
||||
</g>
|
||||
{#if standing}
|
||||
<!-- show where this opening leads -->
|
||||
<circle
|
||||
cx={w.to.cell.x * CELL + CELL / 2} cy={w.to.cell.y * CELL + CELL / 2}
|
||||
r={CELL * 0.42} class="warp-dest"
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
<!-- wizards -->
|
||||
@@ -342,6 +369,29 @@
|
||||
stroke-width: 2;
|
||||
}
|
||||
.warp-g.standing .warp { opacity: 1; }
|
||||
.warp-letter {
|
||||
font-family: "Oswald", sans-serif;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
text-anchor: middle;
|
||||
fill: #6a5c44;
|
||||
pointer-events: none;
|
||||
}
|
||||
.warp-dest {
|
||||
fill: none;
|
||||
stroke: #2e7d32;
|
||||
stroke-width: 2.5;
|
||||
stroke-dasharray: 7 4;
|
||||
pointer-events: none;
|
||||
animation: warp-pulse 1.6s ease-in-out infinite;
|
||||
}
|
||||
@keyframes warp-pulse {
|
||||
0%, 100% { opacity: 0.9; }
|
||||
50% { opacity: 0.35; }
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.warp-dest { animation: none; }
|
||||
}
|
||||
.wizard { cursor: pointer; }
|
||||
.wizard-label {
|
||||
font-family: "Oswald", sans-serif;
|
||||
|
||||
Reference in New Issue
Block a user