SOURCE / PINNED RELEASE
Made of little things.
Squad Table
- Release
- d36201f8ed4f…
- Author-recorded commit
- 7b9bb681d6ba…
- License
- LICENSE
- Author’s source reference
- nostr://npub1sj2vketepqw9v6fmge5fdzuj7atj9sv6qv2jss05n2z6rl64lcfqumdsnt/wss%3A%2F%2Fgit.napplet.soy%2F/n-c043b0c0f1d
Archive hash verified: 8c0604b31f00cc5a…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
<title>Squad Table</title>
</head>
<body>
<main id="app" class="app">
<section id="lobby" class="lobby" aria-label="Tables">
<div class="lobby-inner">
<div class="lobby-intro">
<p class="lobby-kicker">Tactical hex table</p>
<p class="lobby-lede">
Set up a squad-level scenario, move counters and roll dice with an opponent: live, or a few moves a day. You bring the
rulebook; the table keeps the map, the dice and the log.
</p>
</div>
<div class="lobby-grid">
<div id="newForm" class="card card-new">
<h2>New table</h2>
<label class="field">
<span>Scenario</span>
<select id="newScenario"></select>
</label>
<p id="newBrief" class="hint"></p>
<fieldset class="field">
<legend>Your side</legend>
<div id="newSide" class="seg" role="radiogroup"></div>
</fieldset>
<div class="row">
<button id="createOnline" type="button" class="btn primary">Create online table</button>
<button id="createLocal" type="button" class="btn">Hotseat on this device</button>
</div>
<p id="onlineNote" class="hint" aria-live="polite"></p>
</div>
<div id="joinForm" class="card">
<h2>Join with a code</h2>
<label class="field">
<span>Table code from your opponent</span>
<input id="joinCode" type="text" inputmode="url" spellcheck="false" placeholder="ASL1.…" />
</label>
<div class="row">
<button id="joinButton" type="button" class="btn primary">Open table</button>
</div>
<p id="joinNote" class="hint" aria-live="polite"></p>
</div>
<section class="card card-list" aria-labelledby="myTablesTitle">
<h2 id="myTablesTitle">Your tables</h2>
<ul id="myTables" class="table-list"></ul>
<p id="myTablesEmpty" class="hint">No tables yet. Create one or join with a code.</p>
</section>
</div>
<p id="identityNote" class="hint identity-note" aria-live="polite"></p>
</div>
</section>
<section id="table" class="table" aria-label="Game table" hidden>
<header class="hud" role="toolbar" aria-label="Game controls">
<button id="backButton" class="tool" type="button" title="Back to tables" aria-label="Back to tables">
<svg viewBox="0 0 20 20" aria-hidden="true"><path d="M12.5 4 6.5 10l6 6" /></svg>
</button>
<div class="phase" aria-live="polite">
<div class="phase-text">
<span id="turnLabel" class="turn">T1</span>
<span id="activeChip" class="chip"></span>
<span id="phaseLabel" class="phase-name"></span>
</div>
<button id="endPhase" class="tool end-phase" type="button" title="End this phase. You can't go back.">End</button>
</div>
<div class="hud-tools">
<button id="rollDR" class="tool dice" type="button" title="Roll two dice (DR)">DR</button>
<button id="rolldr" class="tool dice" type="button" title="Roll one die (dr)">dr</button>
</div>
<div class="hud-right">
<span id="seatChip" class="seat"></span>
<span id="syncDot" class="sync" role="status"></span>
<button id="panelButton" class="tool" type="button" aria-expanded="true" aria-controls="panel" title="Show panel">
<svg viewBox="0 0 20 20" aria-hidden="true"><path d="M3 5h14M3 10h14M3 15h14" /></svg>
</button>
</div>
</header>
<div class="board-wrap">
<div id="boardHost" class="board-host"></div>
<div class="board-tools" role="group" aria-label="Map tools">
<button id="losButton" class="tool" type="button" aria-pressed="false" title="Check line of sight">
<svg viewBox="0 0 20 20" aria-hidden="true"><circle cx="4.5" cy="15.5" r="2" /><circle cx="15.5" cy="4.5" r="2" /><path d="M6 14 14 6" stroke-dasharray="2 2" /></svg>
<span class="tool-label">LOS</span>
</button>
<button id="undoButton" class="tool" type="button" title="Undo your last change">
<svg viewBox="0 0 20 20" aria-hidden="true"><path d="M7 5 3.5 8.5 7 12" /><path d="M4 8.5h7.5a4.5 4.5 0 0 1 0 9H9" /></svg>
<span class="tool-label">Undo</span>
</button>
<button id="soundButton" class="tool" type="button" aria-pressed="false" title="Mute battle sounds">
<svg viewBox="0 0 20 20" aria-hidden="true"><path d="M3 8h3l4-3v10l-4-3H3z" /><path class="wave" d="M13 7.5a3.5 3.5 0 0 1 0 5M15.5 5.5a6.5 6.5 0 0 1 0 9" /></svg>
<span class="tool-label">Sound</span>
</button>
</div>
<div class="zoom" role="group" aria-label="Zoom">
<button id="zoomIn" class="tool" type="button" aria-label="Zoom in">+</button>
<button id="zoomOut" class="tool" type="button" aria-label="Zoom out">−</button>
<button id="zoomFit" class="tool" type="button" aria-label="Fit map">
<svg viewBox="0 0 20 20" aria-hidden="true"><path d="M3 7V3h4M13 3h4v4M17 13v4h-4M7 17H3v-4" /></svg>
</button>
</div>
<div id="modeBar" class="mode-bar" hidden>
<span id="modeText"></span>
<div id="modeActions" class="mode-actions"></div>
</div>
<div id="toast" class="toast" role="status" aria-live="polite" hidden></div>
<div id="strip" class="strip" hidden>
<div id="stripHex" class="strip-hex"></div>
<div id="stripCounters" class="strip-counters"></div>
<div class="strip-actions">
<button id="stripMove" class="btn small primary" type="button">Move</button>
<button id="stripMore" class="btn small" type="button">Details</button>
</div>
</div>
<div id="diceTray" class="dice-tray" aria-live="polite" hidden></div>
</div>
<div id="tooSmall" class="too-small" role="status">
<p><b>Make the frame larger to play.</b></p>
<p id="tooSmallState"></p>
</div>
<aside id="panel" class="panel" aria-label="Table panel">
<div class="tabs" role="tablist">
<button class="tab" role="tab" data-tab="actions" aria-selected="true">Actions</button>
<button class="tab" role="tab" data-tab="stack" aria-selected="false">Stack</button>
<button class="tab" role="tab" data-tab="tray" aria-selected="false">Counters</button>
<button class="tab" role="tab" data-tab="log" aria-selected="false">Log<span id="logBadge" class="badge-dot" hidden></span></button>
<button class="tab" role="tab" data-tab="info" aria-selected="false">Table</button>
<button id="panelClose" class="tool slim panel-close" type="button" aria-label="Close panel">
<svg viewBox="0 0 20 20" aria-hidden="true"><path d="m5 5 10 10M15 5 5 15" /></svg>
</button>
</div>
<div class="tab-body" data-body="actions" role="tabpanel">
<div id="actionsPanel"></div>
</div>
<div class="tab-body" data-body="stack" role="tabpanel" hidden>
<div id="stackPanel"></div>
</div>
<div class="tab-body" data-body="tray" role="tabpanel" hidden>
<div id="trayPanel"></div>
</div>
<div class="tab-body tab-log" data-body="log" role="tabpanel" hidden>
<ol id="logList" class="log"></ol>
<div id="chatForm" class="chat">
<input id="rollWhy" type="text" maxlength="60" placeholder="Roll for… (optional)" aria-label="What the next roll is for" />
<div class="chat-row">
<input id="chatInput" type="text" maxlength="280" placeholder="Message" aria-label="Message" />
<button id="chatSend" class="btn small primary" type="button">Send</button>
</div>
</div>
</div>
<div class="tab-body" data-body="info" role="tabpanel" hidden>
<div id="infoPanel"></div>
</div>
</aside>
</section>
</main>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
