Skip to content

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.

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.json

Tabia is data-only. It does no rendering. Apps compose Tabia with a renderer at the app boundary — typically Rabbit for SVG board output.

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());
  • 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.

  • 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.
  • 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 Game state
  • PROMOTE/dev/ — local harness composing all three
  1. View mounters / editor mounters — emerge as consumers need them.
  2. Keyboard binding utility. bindKeyboard(game, target) per the canonical Motif keymap.
  3. NAG kit as a stand-alone module under src/nag/.
  4. Variant support. Parameterize the position engine so non-standard chess works without forking the runtime.