Eight quality-of-life turns for strangers, newcomers, and veterans

For visitors: the landing shows a clip card of the maze before asking
for a name; "Play now against a clockwork wizard" is one tap from the
landing to the first turn (the room, the seat, and the flip each
follow as the server confirms the last); pass-the-device and seat
transfer fold behind "More ways to play".

For a first game: automatons default to apprentice until this browser
has seen a game through, then step up to adept unless the tier was
picked by hand; the council speaks once unasked on a first turn; a
finished game offers "play again" (the same bots re-seated in a fresh
room) and "share the tale" (the whole replay as a link).

For players who know the box: a House rulings tab in help — what the
digital table does differently, every rulings revision (now exported
from the engine as RULES_REVISIONS, which the deckRev doc block points
at), and the 76 cards the FAQ has spoken on. And the arrow keys and
WASD walk on the board as they already did in the first-person pane.

The recorder's poster settle lengthens to outlast a change-of-eyes
wipe; two cards had caught the title card instead of the maze.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jm2auWk6RP71CjaAb4FMoG
This commit is contained in:
Eric Wagoner
2026-09-03 19:24:46 -04:00
co-authored by Claude Fable 5.1
parent 2b5c2c4884
commit 53fba77a55
6 changed files with 206 additions and 47 deletions
+11 -3
View File
@@ -27,6 +27,10 @@ export interface Prefs {
handLeft: boolean;
/** The first-turn coaching slip has been read and dismissed. */
coached: boolean;
/** The automaton tier was picked by hand (so a finished game leaves it alone). */
tierChosen: boolean;
/** Games this browser has seen through to a winner. */
finishedGames: number;
}
const KEY = "wizwar-prefs";
@@ -34,8 +38,8 @@ const KEY = "wizwar-prefs";
function load(): Prefs {
const fallback: Prefs = {
art: "photo", autoGrab: false, flourishes: true, wizardName: "", color: null,
cautions: true, botTier: "adept", instantReplay: true, liveFp: false, handLeft: false,
coached: false,
cautions: true, botTier: "apprentice", instantReplay: true, liveFp: false, handLeft: false,
coached: false, tierChosen: false, finishedGames: 0,
};
try {
const raw = localStorage.getItem(KEY);
@@ -48,11 +52,15 @@ function load(): Prefs {
wizardName: typeof p.wizardName === "string" ? p.wizardName.slice(0, 20) : "",
color: typeof p.color === "number" && p.color >= 0 && p.color <= 5 ? p.color : null,
cautions: p.cautions !== false,
botTier: p.botTier === "apprentice" || p.botTier === "archmage" ? p.botTier : "adept",
// A first game is against an apprentice; a browser that has finished
// one is promoted to adept unless the tier was picked by hand.
botTier: p.botTier === "adept" || p.botTier === "archmage" ? p.botTier : "apprentice",
instantReplay: p.instantReplay !== false,
liveFp: p.liveFp === true,
handLeft: p.handLeft === true,
coached: p.coached === true,
tierChosen: p.tierChosen === true,
finishedGames: typeof p.finishedGames === "number" ? p.finishedGames : 0,
};
} catch {
return fallback;