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.
# Squad Table: design brief
**Job:** an online table for squad-level WWII hex wargames such as Advanced
Squad Leader. It enforces the rules in stages, aiming at full ASL. The turn
sequence is locked, and each phase has an Actions menu. Movement, line of
sight, fire, morale, rally and close combat are automated by a rules engine
(`src/rules/`). Every number it uses is in `src/rules/data.ts`, so players can
check them against their own charts.
## Flows
- **Online table.** A signed-in player creates a table (scenario and side) and
shares a code. The opponent opens it and takes the other seat. Anyone with the
code can watch and chat.
- **Async and live in one model.** Every change is an action appended to the
table's log in the `tables` backend module (`backend/`). Dice are rolled by
the module, never by the client. Closing the app and coming back days later
replays the log. When both players are online, a WebRTC room per table sends
"refresh now" hints and pointer outlines, so moves appear in about a second
and a half.
- **Hotseat.** The same reducer with the log kept in NAP storage. Use it when the
host has no backend, or for solo setup.
- **Tools.** Drag stacks (mouse), or pick counters and then Move and tap a
destination (touch). Flip, rotate facing, restack, relabel, off-board and
casualty boxes, phase tracker, DR/dr with a reason, LOS thread with a
hex-by-hex terrain report, undo of your own latest change, and chat.
## Content and IP
Maps, scenarios, counter artwork and all text are original. Unit stat lines are
plain editable labels, and players can relabel any counter to match their unit
tables. The app avoids MMP's trademarks and copies no rulebook text.
## Visual direction: "war-room table"
- **Character:** a dark felt table under a lamp with a printed paper map on
it. It suits a slow, deliberate game played over a physical-feeling surface.
- **Main surface:** cream paper map with muted cartography. Woods are clustered
tree crowns, grain is hatched ochre, orchards are dotted rows, and buildings
are rooftops (brown wood, grey hatched stone). Hills use tan level tints with
brown contour strokes. Roads are pale curved bands, hedges dark green and
walls dashed grey hexside strokes. Counters are chunky square chits with a
drop shadow, nation-coloured faces (field grey, olive, khaki), NATO-style
role boxes and bold stat lines. A broken side shows a dark-red sash. Markers
use tone colours: fire red, movement yellow, state cream, terrain charcoal.
- **Interface:** olive field-kit panels, brass for selection, active state and
primary actions, condensed stencil-like system fonts, and oxblood dice
buttons. Selection is a brass hex outline, the last move a dashed arrow in
the mover's colour, and LOS a yellow thread with highlighted hexes.
- **Theme policy:** app-owned. Host theme data is not applied, because counter
and nation colours carry game meaning.
- **Sizes:** desktop has a side panel. Below 760 px the panel becomes a bottom
sheet and a stack strip appears. Below 260×200 a notice asks for a larger
frame and shows the turn, phase and last roll. Touch drags pan; mouse drags
move stacks.
- **Cover:** `preview.png` is a mid-game hotseat state with an LOS thread and
dice (1200×750).
## Domains
All optional, with fallbacks:
| Domain | Use | Fallback when absent |
| --- | --- | --- |
| `cvm` | online tables | hotseat only |
| `identity` | seat ownership | watching only |
| `webrtc` | live hints | polling every 4 s |
| `storage` | table list and hotseat saves | not remembered |
| `config` | map coordinates, pointer sharing, auto-live | defaults |
`relay` and `outbox` are not used.
## Known gaps
- **Concealment is not hidden from the opponent.** "?" markers are visible
counters. The log is public to anyone with the code, so hidden setup needs a
future design.
- **Public online tables need provider admission.** The backend provider uses
an allowlist, so this creator must be admitted, then run
`soyli backend deploy backend/backend.json`. Local preview works without it.
- **Touch is not tested on real phones.** Touch pan, pinch and tap were not
exercised on a real device, only through layout screenshots at phone sizes.
