Phase 3: hotseat play — the whole game in one browser

Hotseat runs the engine entirely client-side; no server is involved.
The lobby takes comma-separated names (2-6 wizards), and the game
plays through the same table UI, with one addition: a full-screen
hand-off card between actors — "pass the device to Morgana, tap when
only they can see the screen" — shown whenever the needed input moves
to another wizard (turns, counteractions, forced discards,
interrupts). Each player sees only their own hand while seated. The
game saves itself to localStorage after every command (config +
command log, replayed on resume — the server's own determinism
trick), so "set the game aside" keeps it and "abandon game" forgets
it; a Resume Hotseat button appears whenever a save exists. Fixed en
route: the engine's structuredClone cannot digest Svelte's reactive
proxies, so hotseat snapshots state before every engine call.
Verified live: 3-player game started, reloaded, resumed, turn ended,
device handed to the next wizard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-16 00:13:59 -04:00
co-authored by Claude Fable 5
parent 85b40be113
commit 9323399b60
3 changed files with 276 additions and 33 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ import { cardDef } from "@wizwar/engine";
const SERVER_URL = import.meta.env.VITE_WIZWAR_SERVER ?? "ws://localhost:8787";
function humanize(e: GameEvent): string | null {
export function humanize(e: GameEvent): string | null {
switch (e.type) {
case "gameStarted": return `Game started — ${e.players.join(", ")}. ${e.firstPlayer} goes first.`;
case "turnStarted": return `${e.player}'s turn (round ${e.round}) —`;