Tabia
Chess UX runtime — PGN parser + game state + collection layer + UCI engine client. Pure data layer. The building blocks any chess app needs, with rendering and app shell left to the consumer.
Tabia (Arabic: طبيعة, “essence”) — in chess, a known starting position from which variations branch off. The framework other projects depart from.
What’s here
Section titled “What’s here”Tabia/├── src/│ ├── pgn-parser.js ← variant-agnostic PGN tokenize + serialize│ ├── fen.js ← FEN parse + semantic validation, normalization│ ├── game.js ← `createGame(pgn, opts)` — tree-shaped game│ │ state with variations, comments, NAGs, drawables│ ├── local-target.js ← default in-memory Target backing a Game│ │ (move tree + record + start FEN)│ ├── games.js ← collection layer: identity hashing, prefix│ │ detection, merge with attributed annotations│ ├── replay.js ← `ReplayEngine` — step/seek through a game,│ │ position hashing│ ├── record.js ← flat-record schema + helpers (FIELD_SCHEMA)│ ├── engine/ ← generic UCI engine client + curated registry│ ├── utils.js ← small shared helpers (formatName, resultClass, …)│ └── index.js ← public exports├── docs/│ ├── ROADMAP.md ← module roadmap│ ├── SPEC-lifecycle.md ← state-event slice lifecycle│ ├── SPEC-engine-integration.md ← UCI ↔ lifecycle bridge│ └── SPEC-target-interface.md ← the Target contract└── package.jsonTabia is data-only. It does no rendering. Apps compose Tabia with a renderer at the app boundary — typically Rabbit for SVG board output.
Quick start
Section titled “Quick start”There’s no in-repo demo or build step — Tabia is consumed by importing
from src/. The canonical “what does Tabia look like in use?” example
is the PROMOTE-stack harness at ../dev/, which exercises
Tabia + Motif + Rabbit together.
import { createGame } from 'tabia';
const game = createGame(pgnText);game.goToNext();console.log(game.getCurrentFen());console.log(game.getPgn());What’s intentionally NOT here yet
Section titled “What’s intentionally NOT here yet”- View mounters (
mountMoveList,mountBranchPopover,mountToolbar,mountEditorToolbar). Motif owns the chess-aware UI components; if a mounter is useful, it belongs in Motif, not here. - Editor mutations as mounters. Comment editing, NAG picker, variation promote/demote — extractable into their own modules when a consumer needs them.
See docs/ROADMAP.md for the order these will land.
What’s intentionally NEVER here
Section titled “What’s intentionally NEVER here”- Keyboard binding. Keymaps and the binder live in Motif — they cross subsystems (Tabia + Rabbit + Motif components) and need DOM event handling, which a data-only library doesn’t pull in.
- Rendering or UI. Boards render through Rabbit; chess-aware UI components live in Motif.
Dependencies
Section titled “Dependencies”chess.js— move legality, position computation
Optional but recommended in consuming apps:
- Motif — design tokens, chess-aware web components
- Rabbit — SVG board renderer that pairs naturally with
Tabia’s
Gamestate PROMOTE/dev/— local harness composing all three
Roadmap (not yet committed)
Section titled “Roadmap (not yet committed)”- View mounters / editor mounters — emerge as consumers need them.
- Keyboard binding utility.
bindKeyboard(game, target)per the canonical Motif keymap. - NAG kit as a stand-alone module under
src/nag/. - Variant support. Parameterize the position engine so non-standard chess works without forking the runtime.