The table, the hall, the rules and the guide: three boards drawn in Gygax's colours, a drake to play, the article in full, and the pages that walk a player in

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CCLa2PaEeCj8njQZSWGqHx
This commit is contained in:
Eric WagonerandClaude Fable 5.1 committed 2026-10-26 16:39:50 -04:00
1 parent 1ef5b23712
commit b9efe304a0
29 files changed
+1116 -333

No files matched your search

+40 -15
View File
@@ -1,8 +1,6 @@
<script lang="ts">
// How to play: a walk through the page in the game's own voice, one
// screenshot per section, from the hall to a first game. Capture the
// figures from the running game into static/guide/ and describe what a
// new player is looking at, not what the code does.
// How to play: a walk from the hall to a first game, in the game's own
// voice, with a figure for each part of the page.
import { page } from '$app/state';
/** Opened from a table, the page offers the way back to it and carries it to its cross-links. */
@@ -18,11 +16,12 @@
<header>
{#if room}<a class="back" href={`/join/${room}`}>Back to your game</a>{' · '}{/if}<a class="back" href="/">Back to the hall</a> · <a class="back" href={withRoom('/rules')}>The rules</a>
<h1>How to play</h1>
<p class="lede">Two sentences that set the scene: who the player is, and what they are trying to do.</p>
<p class="lede">You command Gold or Scarlet, 42 pieces spread across the air, the land and the underworld, and you are after the other King. If you know chess you know most of it already. The rest is learning which pieces can climb and which can dig.</p>
<nav aria-label="Sections">
<a href="#hall">The hall</a>
<a href="#table">The table</a>
<a href="#board">The board</a>
<a href="#boards">The boards</a>
<a href="#moving">Making a move</a>
<a href="#gallery">The Peanut Gallery and table talk</a>
<a href="#first">A first game</a>
</nav>
@@ -30,29 +29,43 @@
<section id="hall">
<h2>The hall</h2>
<p>Write your name and choose your company. <strong>Play now against the bot</strong> seats you across from the bot and begins. <strong>Open a table</strong> lays a table and hands you a link and a four-letter code to send. <strong>Join one</strong> takes a code someone sent you. Beneath, <em>your games</em> lists every table this browser holds a seat at, and whose move it is.</p>
<figure><img src="/guide/hall.png" alt="The hall: a name field, the two table choices, the button to play the drake, and the opening position drawn beside them" loading="lazy" /></figure>
<p>Write your name and choose your company. <strong>Play now against a drake</strong> seats you across from the house player and begins at once. <strong>Open a table</strong> lays a table and hands you a link and a four-letter code to send to a friend. <strong>Join one</strong> takes a code someone sent you.</p>
<p>Two choices sit above the buttons. <em>You play</em> picks your side, and Gold moves first. <em>The Sylphs</em> picks where the six Sylphs start. As Gygax printed it, Gold's Dragon can take an undefended Sylph on the very first move, which a reader of the Chess Variant Pages took for a misprint. The shifted setup moves the Sylphs one file over, out of reach. Beneath the buttons, <em>your games</em> lists every table this browser holds a seat at and whose move it is.</p>
</section>
<section id="table">
<h2>The table</h2>
<p>A table fills as players open the link. Whoever laid it is the host. The host may seat a bot in any empty chair or send one away, and they begin the game when the company suits them, however full the table. Once begun, the seats are closed.</p>
<figure><img src="/guide/table.png" alt="A table laid: the room code, the link to send, two seats, and the Begin button" loading="lazy" /></figure>
<p>A table seats two. Whoever laid it is the host. The host may seat a drake in the empty chair or send one away, and begins the game when the company is right. Once begun, the seats are closed, and anyone else who opens the link watches from the Peanut Gallery.</p>
</section>
<section id="board">
<h2>The board</h2>
<p>What the player sees during play, section by section, with a figure for each.</p>
<section id="boards">
<h2>The boards</h2>
<figure><img src="/guide/boards.png" alt="The three boards one above the other in the opening position, the air in blue and white, the land in green and amber, the underworld in red and brown" loading="lazy" /></figure>
<p>The three boards stand one above the other, the air at the top, the land in the middle and the underworld at the bottom, in the colours Gygax suggested. Your side is nearest you on every board. Each piece is a disc bearing the initial Gygax gave it, with Dr for the Dragon so it is not mistaken for a Dwarf. The square names along the edges are his too, and you can hide them under <em>preferences</em>.</p>
<p>The strip above the boards says whose move it is and warns when a King is in check. The record beside the boards lists the moves played in Gygax's notation. Click one to see it on the boards, and click again, or make your move, to come back to now.</p>
</section>
<section id="moving">
<h2>Making a move</h2>
<figure><img src="/guide/move.png" alt="A Gold Dragon selected in the air, with dots on every square it can reach and a ring around the Scarlet Sylph it can take" loading="lazy" /></figure>
<p>Tap one of your pieces and every square it can reach lights up, on its own board and on any board it can climb or drop to. A dot marks an empty square and a ring marks a piece it can take. Tap the square and the move is made. Tap the piece again, or anywhere else, to put it down. With a keyboard, the arrows walk a board, Page Up and Page Down change boards, Enter picks up and sets down, and Escape cancels.</p>
<p>A move that would leave your own King in check is never offered. If you would rather be asked before a move goes, turn on <em>confirm a move before it is sent</em> in preferences.</p>
<p>A piece under a Basilisk's gaze is drawn pale with a frost ring around it. It is frozen and can do nothing until the Basilisk moves or is taken.</p>
</section>
<section id="gallery">
<h2>The Peanut Gallery and table talk</h2>
<p>A room's link is an invitation to sit while the table is laid and to watch once the game has begun. Anyone who opens it without a seat takes a place in the Peanut Gallery, shown only what every player at the table could see. <em>Table talk</em> is for the players seated, unless the host lets the gallery talk. Then a watcher gives a name, and their lines are marked as the gallery's. A line goes to everyone at the table and everyone in the gallery, and is kept with the game.</p>
<p>A seat can follow you to another device. <em>Transfer seat</em> in the masthead gives four words, good for ten minutes, and the hall on the other device claims them. If your browser loses the seat, the host's <em>Seats</em> makes those words for you. If a player cannot go on, the host can give their seat to a bot there, and the same words bring them back to it. When a game ends, anyone at the table may call for a rematch, which opens a new table for the same company and holds their seats until they are back. While a table is laid, you may challenge the keeper of this site to a seat; the note beside the button gives the hour where they live.</p>
<p>A room's link is an invitation to sit while the table is laid and to watch once the game has begun. Anyone who opens it without a seat takes a place in the Peanut Gallery and sees the whole game, since nothing in Wyrm is hidden. <em>Table talk</em> is for the two players, unless the host lets the gallery talk. Then a watcher gives a name, and their lines are marked as the gallery's. Every line is kept with the game.</p>
<p>A seat can follow you to another device. <em>Transfer seat</em> in the masthead gives four words, good for ten minutes, and the hall on the other device claims them. If your browser loses the seat, the host's <em>Seats</em> makes those words for you. If a player cannot go on, the host can give their seat to a drake there, and the same words bring them back to it. When a game ends, either player may call for a rematch, which opens a new table for the same company and holds the seats until both are back. While a table is laid, you may challenge the keeper of this site to a seat, and the note beside the button gives the hour where they live.</p>
</section>
<section id="first">
<h2>A first game</h2>
<p>The advice you would give a friend across the table for their first few turns.</p>
<p>The full rules are on the <a href="/rules">rules page</a>. If a rule here reads wrong to you, or something misbehaves, <a href="mailto:eric@ericwagoner.com">send word</a>. The hall's <em>about this game</em> lists the other ways to reach the keeper.</p>
<p>Play a drake first. It plays a fair game and never minds how long you take. Begin as you would at chess, with Warriors stepping forward and the knights of the land, the Unicorns and Heroes, coming out behind them. Gygax's own advice is to hold the Mage and the Paladin back until the lesser pieces are developed, and to keep your Dragon home. It starts directly above your King for a reason. A Dragon that flies off to raid leaves the King open to the other Dragon, which strikes the land from the air without ever coming down.</p>
<p>Watch the Basilisks. Anything you leave on the land directly above an enemy Basilisk is frozen on the spot, and a frozen piece may as well be off the board. The Cleric is stronger than it looks, since it is the only piece that plays the same on all three boards, and the Dwarves, if you do not hurry them forward, make good guards late in the game.</p>
<p>The full rules, piece by piece, are on the <a href={withRoom('/rules')}>rules page</a>, with Gygax's article beneath them. If a rule here reads wrong to you, or something misbehaves, <a href="mailto:eric@ericwagoner.com">send word</a>, or use <em>Report</em> in the masthead at the table, which pins what you saw to the move it happened on. The hall's <em>about this game</em> lists the other ways to reach the keeper.</p>
</section>
</main>
@@ -68,4 +81,16 @@
p + p {
margin-top: 0.7rem;
}
figure {
margin: 0 0 0.9rem;
}
figure img {
display: block;
width: 100%;
height: auto;
border: 1px solid var(--rule-strong);
border-radius: 6px;
}
</style>
+3 -3
View File
@@ -169,7 +169,7 @@
{:else if room?.started}
<p class="standfirst">You are <em>{room.nameOf(room.me)}</em>, playing {room.others.map((s) => s.name).join(', ')}.{#if !room.connected} <span class="muted">Reconnecting.</span>{/if}</p>
{:else}
<p class="standfirst">A game between people, played by turns whenever each of you has a moment.</p>
<p class="standfirst">Gold and Scarlet move by turns, and the boards wait for whoever is away.</p>
{/if}
</div>
<nav class="actions">
@@ -184,7 +184,7 @@
<button type="button" class="quiet" title="A phrase that brings this seat to another device" onclick={transfer}>Transfer seat</button>
{/if}
{#if room.isHost && room.started}
<button type="button" class="quiet" title="Bring a player back to a seat their browser lost, or give a seat to a bot" onclick={() => (seatsOpen = true)}>Seats</button>
<button type="button" class="quiet" title="Bring a player back to a seat their browser lost, or give a seat to a drake" onclick={() => (seatsOpen = true)}>Seats</button>
{/if}
{/if}
<button type="button" class="quiet" onclick={() => (prefsOpen = true)}>Preferences</button>
@@ -240,7 +240,7 @@
{/if}
{#if room?.started && !seatLost && room.view.seats.some((s) => s.standIn)}
<p class="notice muted">A bot plays for {room.view.seats.filter((s) => s.standIn).map((s) => s.name).join(', ')}, at the host's word, until a transfer phrase from the host brings them back.</p>
<p class="notice muted">A drake plays for {room.view.seats.filter((s) => s.standIn).map((s) => s.name).join(', ')}, at the host's word, until a transfer phrase from the host brings them back.</p>
{/if}
{#if watching && room?.started && !room.view.over}
+170 -10
View File
@@ -1,12 +1,16 @@
<script lang="ts">
// The rules page: the game's own text, structured for reading mid-game.
// Keep the original rules text verbatim in docs/ and render from it
// where you can, so the page and the engine follow one source.
// The rules page: the game as this table plays it, piece by piece, then
// Gygax's article in full from docs/source.md, which the engine follows.
import { page } from '$app/state';
import { sections } from '$lib/source';
/** Opened from a table, the page offers the way back to it and carries it to its cross-links. */
const room = $derived((page.url.searchParams.get('room') ?? '').toUpperCase());
const withRoom = (path: string) => (room ? `${path}?room=${room}` : path);
const source = sections();
/** The article proper runs from its title to the end of "Putting together a game"; the notes around it are the transcriber's. */
const article = source.filter((s) => s.id !== 'the-source-text' && s.id !== 'decisions');
const decisions = source.find((s) => s.id === 'decisions');
</script>
<svelte:head>
@@ -17,31 +21,187 @@
<header>
{#if room}<a class="back" href={`/join/${room}`}>Back to your game</a>{' · '}{/if}<a class="back" href="/">Back to the hall</a> · <a class="back" href={withRoom('/guide')}>How to play</a>
<h1>The rules</h1>
<p class="lede">One paragraph on where these rules come from and which edition or text this page follows.</p>
<p class="lede">
Wyrm plays Dragonchess as Gary Gygax published it in Dragon Magazine No. 100, August 1985. The article is the only rules text there is. It is transcribed in full at the foot of this page, and the game follows it word for word, with the handful of readings the text leaves open settled under <a href="#decisions">What this table decides</a>.
</p>
<nav aria-label="Sections">
<a href="#boards">The boards</a>
<a href="#winning">Winning</a>
<a href="#air">The air</a>
<a href="#land">The land</a>
<a href="#underworld">The underworld</a>
<a href="#between">Between the boards</a>
<a href="#decisions">What this table decides</a>
<a href="#source">The original text</a>
</nav>
</header>
<section id="turn">
<h2>A turn</h2>
<p>What each player does on a turn, in order, in short paragraphs. Put the thing a player checks mid-game first.</p>
<section id="boards">
<h2>The boards</h2>
<p>
Three boards lie one above another, each twelve squares wide and eight deep. The top board is the air, the middle board the land, and the bottom board the underworld. Gold and Scarlet each have 42 pieces, and Gold moves first. A square is named by its board, its file and its rank, so <strong>3g1</strong> is the air above Gold's King and <strong>1g8</strong> the underworld beneath Scarlet's. The files run a to l from Gold's left, the ranks 1 to 8 from Gold's side, and the square at Gold's near right corner, l1, is light.
</p>
<p>
A move takes one piece to one square. A piece lands on an empty square or on an enemy piece, which is taken, and never on a friend. Some pieces live on one board for the whole game, and some pass between boards in ways of their own. There is no castling, no two-square first step for a Warrior, and so no capture in passing.
</p>
</section>
<section id="winning">
<h2>Winning</h2>
<p>How the game ends and who wins, including draws.</p>
<p>
A King attacked by an enemy piece is in check, and a move may not leave your own King in check. A King in check with no way out, by moving, by taking the attacker or by putting a piece in the way, is checkmated, and the game is lost. A player who is not in check but has no legal move at all is stalemated, and the game is drawn. The game is also drawn when the same position stands for the third time with the same side to move, and when fifty moves pass on each side without a capture.
</p>
<p>
A Basilisk in the underworld freezes the enemy piece on the square directly above it. A frozen piece cannot move, cannot take and threatens nothing, though it still blocks the square it stands on. A frozen King cannot step out of check, so it is mated by any attack that cannot be answered by a capture or a block.
</p>
</section>
<section id="air">
<h2>The pieces of the air</h2>
<p>
<strong>Sylph</strong>, six a side. A Sylph is a pawn turned inside out. It moves one square diagonally forward and captures the square straight ahead. It can also capture the enemy piece directly beneath it on the land, and that is the only way down. On the land it cannot move except to climb back, without capturing, to the square directly above it or to any empty one of its six starting squares. A Sylph that reaches the far rank can go no further on the air board, but it can still strike down, and once it has it may climb again into a starting square.
</p>
<p>
<strong>Griffon</strong>, two a side. In the air a Griffon leaps two squares one way and three the other, over anything in between, the way a knight leaps one and two. It can drop to the land on any of the four squares diagonally next to the square beneath it, taking a piece there or not. On the land it loses its flight and moves one square diagonally, and it rises again to any of the four squares diagonally next to the square above it.
</p>
<p>
<strong>Dragon</strong>, one a side. The Dragon never leaves the air. It slides any distance along a diagonal, or steps one square in any direction. It also strikes from afar. Without moving, it can take an enemy piece on the land that stands directly beneath it or on one of the four squares beside that one. The piece is removed and the Dragon stays where it is. That strike is the Dragon's whole move, and it counts as an attack for check.
</p>
</section>
<section id="land">
<h2>The pieces of the land</h2>
<p>
<strong>Warrior</strong>, twelve a side. A pawn that cannot take a double first step. It moves one square straight forward and captures one square diagonally forward. On reaching the far rank it becomes a Hero, with no choice in the matter. It never leaves the land.
</p>
<p>
<strong>Oliphant</strong>, two a side, moves like a rook. <strong>Unicorn</strong>, two a side, moves like a knight. <strong>Thief</strong>, two a side, moves like a bishop. None of the three leaves the land.
</p>
<p>
<strong>Hero</strong>, two a side. On the land a Hero moves one or two squares along a diagonal, leaping over whatever is on the square between. It can also go up to the air or down to the underworld, landing on any of the four squares diagonally next to the square above or below it, and may take a piece as it goes. Off the land, its only move is back, to any of the four squares diagonally next to the square above or below it.
</p>
<p>
<strong>Cleric</strong>, one a side. On any board the Cleric moves one square in any direction, like a king. It also steps straight up or down one board. It is the one piece that plays the same on all three boards.
</p>
<p>
<strong>Mage</strong>, one a side. On the land the Mage is a queen, sliding any distance along a rank, file or diagonal. It can also move straight up or down one board or two, though to pass through the land the square there must be empty. In the air or the underworld it is reduced to one square sideways, forward or back.
</p>
<p>
<strong>King</strong>, one a side. On the land the King moves one square in any direction, and it may step straight up to the air or down to the underworld. On either of those boards it can do nothing but come straight back to the land.
</p>
<p>
<strong>Paladin</strong>, one a side. On the land the Paladin has the king's move and the knight's leap together. It can also leap between boards the way a knight leaps on one, one board up or down and two squares along a rank or file, or two boards and one square, over anything in between. In the air or the underworld it keeps only the king's step.
</p>
</section>
<section id="underworld">
<h2>The pieces of the underworld</h2>
<p>
<strong>Dwarf</strong>, six a side. A Dwarf moves one square straight forward or one square sideways without capturing, and captures one square diagonally forward. From the underworld it can take the enemy piece directly above it on the land, and on the land it keeps the same moves. It comes back down only to the empty square directly beneath it. A Dwarf on the far rank can still move sideways and between the boards, and it never reaches the air.
</p>
<p>
<strong>Basilisk</strong>, two a side. A Basilisk moves one square straight or diagonally forward, taking what is there, or one square straight back onto an empty square. It never leaves the underworld. The enemy piece directly above it on the land is frozen for as long as the Basilisk stays beneath it.
</p>
<p>
<strong>Elemental</strong>, one a side. In the underworld the Elemental moves one or two squares along a rank or file and captures the same way, with the nearer square empty before it can reach the further. It can also move one square diagonally, but never captures that way. It climbs to the land only to capture, moving one square along a rank or file to an empty square and then straight up onto an enemy piece. On the land it can do nothing but come down, straight down through an empty square and then one square along a rank or file, taking a piece there or not.
</p>
</section>
<section id="between">
<h2>Between the boards</h2>
<p>
Five kinds of piece pass between boards. The Griffon, the Hero and the Paladin leap, and nothing in the way stops them. The Mage and the Elemental do not leap. A Mage going from the underworld to the air needs the square on the land between to be empty, and an Elemental needs the square beside it empty on the way up and the square beneath it empty on the way down. The Sylph, the Dwarf, the Cleric and the King move straight up or down, one board at a time, onto the square itself.
</p>
</section>
<section id="decisions">
<h2>What this table decides</h2>
<p class="muted">
Gygax's text contradicts itself in two places and leaves a few cases unsaid. These are the readings the game follows, as recorded with the transcription. Two of them are choices the host makes when opening a table.
</p>
{#if decisions}{@html decisions.html}{/if}
</section>
<section id="source">
<h2>The original text</h2>
<p>The full source text, in collapsible sections, so a rules question can be settled by the words the engine follows.</p>
<p class="muted">
"Dragonchess" by Gary Gygax, Dragon Magazine No. 100, August 1985, pages 34 to 40. Transcribed from the keeper's copy. The diagrams are described in words where they stood. Open a heading to read that part.
</p>
{#each article as s (s.id)}
<details>
<summary>{s.title}</summary>
<div class="source">{@html s.html}</div>
</details>
{/each}
</section>
<p class="word">If this page reads a rule differently from the original text, that is a bug. Please <a href="mailto:eric@ericwagoner.com">send word</a>.</p>
</main>
<style>
nav {
display: flex;
flex-wrap: wrap;
gap: 0.3rem 1rem;
margin: 1rem 0 0.5rem;
font-size: 0.95rem;
}
p + p {
margin-top: 0.7rem;
}
details {
border-top: 1px solid var(--rule);
padding: 0.5rem 0;
}
summary {
cursor: pointer;
font-weight: 500;
}
.source {
padding: 0.5rem 0 0.4rem 1rem;
border-left: 2px solid var(--rule-strong);
color: var(--bone-dim);
font-size: 0.95rem;
}
.source :global(p + p),
.source :global(pre + p),
.source :global(p + pre),
.source :global(table) {
margin-top: 0.7rem;
}
.source :global(pre) {
font-size: 0.85rem;
line-height: 1.35;
overflow-x: auto;
}
.source :global(table) {
border-collapse: collapse;
}
.source :global(th),
.source :global(td) {
padding: 0.15rem 0.8rem 0.15rem 0;
text-align: left;
}
#decisions :global(ol) {
padding-left: 1.4rem;
}
#decisions :global(li + li) {
margin-top: 0.5rem;
}
.word {
margin-top: 2rem;
color: var(--bone-faint);
color: var(--bone-dim);
font-size: 0.9rem;
}
</style>