A TypeScript engine for the Kingdomino board game and its expansions.
This engine provides the core logic for Kingdomino: state management, rule enforcement, scoring, and turn flow. It is not a UI — consumers drive the game by calling engine methods and passing game state back in.
The engine is stateless: each method takes the current game state as input and returns a new game state. It is your responsibility to persist the state between calls.
- Node.js >= 20
npm install @pompidup/kingdomino-engineimport { createGameEngine, isGameWithNextAction } from "@pompidup/kingdomino-engine";
const engine = createGameEngine({});
// Create and set up a game
let game = engine.createGame({ mode: "Classic" });
game = engine.addPlayers({ game, players: ["Alice", "Bob"] });
game = engine.startGame({ game });
// Game loop
while (isGameWithNextAction(game)) {
const { nextLord, nextAction } = game.nextAction;
if (nextAction === "pickDomino") {
const domino = game.currentDominoes.find((d) => !d.picked);
if (domino) {
game = engine.chooseDomino({ game, lordId: nextLord, dominoPick: domino.domino.number });
}
} else if (nextAction === "placeDomino") {
const lord = game.lords.find((l) => l.id === nextLord);
const player = game.players.find((p) => p.id === lord?.playerId);
if (lord?.dominoPicked && player) {
const placements = engine.getValidPlacements({ kingdom: player.kingdom, domino: lord.dominoPicked });
if (placements.length > 0) {
game = engine.placeDomino({ game, lordId: nextLord, position: placements[0].position, rotation: placements[0].rotation });
} else {
game = engine.discardDomino({ game, lordId: nextLord });
}
}
} else {
game = engine.discardDomino({ game, lordId: nextLord });
}
}
const results = engine.getResults({ game });
console.log(results.result);| Mode | Description |
|---|---|
| Classic | Original Kingdomino rules. 1-4 players, 5x5 kingdom, terrain-based scoring. |
| QueenDomino | Full Queendomino expansion with buildings, coins, knights, the Queen and the Dragon. |
| KingdominoOrigins-Discovery | Origins expansion — volcanoes, fire tokens, fire-based scoring. |
| KingdominoOrigins-Totem | Origins — Discovery + wooden resources + totem majority tiles. |
| KingdominoOrigins-Tribe | Origins — Discovery + resources + cave board + cavemen recruitment. |
| AgeOfGiants | Age of Giants extension — giants, quest tiles, 5-player support, 12 new dominos on Classic. |
| AgeOfGiants-QueenDomino | Age of Giants combined with QueenDomino. |
let game = engine.createGame({ mode: "Classic" });
let game = engine.createGame({ mode: "QueenDomino" });
let game = engine.createGame({ mode: "KingdominoOrigins-Discovery" });
let game = engine.createGame({ mode: "AgeOfGiants" });See Game Modes for rules, player counts, and extra rules details.
The QueenDomino mode adds significant new mechanics to the base game:
- Construction squares on some domino tiles where buildings can be placed
- Coins (7 starting) used to purchase buildings or use the Dragon
- Knights (max 3) placed on dominos to collect tax from construction squares
- Buildings (18 types) purchased from the Builders Board, granting crowns, towers, and end-game bonuses
- The Queen goes to the player with the most towers, granting +1 crown to the best territory
- The Dragon burns a building tile from the Builders Board
The turn flow is extended with optional actions after placing a domino:
placeDomino → placeKnight → constructBuilding → useDragon → pickDomino
(optional) (optional) (optional)
// Handle QueenDomino optional actions in your game loop
if (nextAction === "placeKnight" || nextAction === "constructBuilding" || nextAction === "useDragon") {
game = engine.skipOptionalAction({ game, lordId: nextLord });
}See Queendomino Guide for the complete rules, building list, and game loop example.
Origins introduces prehistoric terrains and fire-based scoring across three modes:
- Discovery: Volcanoes provide fire tokens. Scoring = region size × fire symbols.
- Totem: Discovery + wooden resources + totem majority tiles for bonus points.
- Tribe: Discovery + resources + cave board with 22 cavemen to recruit.
if (nextAction === "placeFireToken") {
game = engine.placeFireToken({ game, lordId: nextLord, position });
}
if (nextAction === "recruitCaveman") {
game = engine.recruitCaveman({ game, lordId: nextLord, cavemanId, position, resourcePositions });
}See Origins Guide for the complete rules and mechanics.
Age of Giants extends Classic (or QueenDomino) with giants, quest tiles, and 5-player support:
- 60 dominos (48 original + 12 new with giant/footprint symbols)
- Giants cover crowns on your kingdom, reducing opponents' scores
- Quest tiles (2 per game) provide end-game bonus scoring conditions
- 5-player support with 5 dominos revealed per turn
if (nextAction === "placeGiant") {
game = engine.placeGiant({ game, lordId: nextLord, position });
}
if (nextAction === "sendGiant") {
game = engine.sendGiant({ game, lordId: nextLord, giantIndex, targetPlayerId, targetCrownPosition });
}See Age of Giants Guide for the complete rules and mechanics.
| Rule | Description | Restriction |
|---|---|---|
| The Middle Kingdom | +10 points if castle is centered | — |
| Harmony | +5 points if no dominos were discarded | — |
| The Mighty Duel | All 48 dominos, 7x7 kingdom | 2 players only |
| Dynasty | Play 3 games, highest total wins | — |
game = engine.addExtraRules({ game, extraRules: ["The middle Kingdom", "Harmony"] });
// Dynasty: aggregate results from multiple games
const dynastyResults = engine.getDynastyResults({ games: [game1, game2, game3] });See Game Modes for details.
const engine = createGameEngine({
logging: true, // Console logging
logger: { info: console.log, error: console.error }, // Custom logger
shuffleMethod: (arr) => arr, // Custom shuffle (e.g. no-op for testing)
uuidMethod: () => "custom-uuid", // Custom UUID generator
events: { onGameEnd: () => {} }, // Event callbacks
debug: true, // Debug mode
});| Method | Description |
|---|---|
getModes |
Get available game modes |
createGame |
Create a new game |
addPlayers |
Add 1-4 players |
addExtraRules |
Add optional extra rules |
startGame |
Start the game |
chooseDomino |
Pick a domino from the revealed set |
placeDomino |
Place a domino on the kingdom |
discardDomino |
Discard when no valid placement exists |
getResults |
Get final rankings and scores |
calculateScore |
Calculate score for any kingdom |
getValidPlacements |
Find all valid placements for a domino |
canPlaceDomino |
Check if any placement exists |
serialize / deserialize |
Save and restore game state |
getDynastyResults |
Aggregate scores from multiple games |
| Method | Description |
|---|---|
placeKnight |
Place a knight and collect tax |
constructBuilding |
Buy and place a building |
useDragon |
Destroy a building tile from the board |
skipOptionalAction |
Skip the current optional action |
| Method | Description |
|---|---|
placeFireToken |
Place a fire token after placing a volcano domino |
recruitCaveman |
Recruit a caveman from the cave board (Tribe mode) |
| Method | Description |
|---|---|
placeGiant |
Place a giant on a crown in your kingdom |
sendGiant |
Send a giant to an opponent's kingdom |
See API Reference for complete method signatures, types, and error codes.
- Bot / AI: 4 built-in strategies (
randomStrategy,greedyStrategy,advancedStrategy,expertStrategy) withplayBotTurn()helper - Mixed games: Human and bot players in the same game via
bot: { strategyName }on player input - Undo / Redo: Snapshot-based history with
createGameHistory(),pushState(),undo(),redo() - Action Log: Immutable log via
wrapWithActionLog(engine)for replay withreplayActions() - Events: Callbacks via
EngineConfig.events(onDominoPlaced,onGameEnd, etc.) - Debug Mode:
wrapWithDebug(engine)with 3 verbosity levels - Seeded games: Deterministic shuffle via
createGame({ mode, seed: "my-seed" }) - Serialization:
serializeGame()/deserializeGame()and save points - WASM Build:
pnpm build:wasmproduces a WebAssembly module usable from any language
| Document | Content |
|---|---|
| Game Modes | Modes, rules by player count, extra rules, game flow |
| Queendomino Guide | Complete Queendomino rules, mechanics, and examples |
| Origins Guide | Kingdomino Origins rules, fire tokens, resources, cavemen |
| Age of Giants Guide | Age of Giants rules, giants, quest tiles, 5-player support |
| API Reference | All methods, types, error codes, and utilities |
| WASM Build | Cross-language usage via WebAssembly |
pnpm install # Install dependencies
pnpm test # Run tests (watch mode)
pnpm test -- --run # Run tests once
pnpm coverage # Tests with coverage
pnpm typecheck # Type check (tsc)
pnpm lint # Lint (biome)
pnpm build # Build (ESM to dist/)
pnpm build:wasm # Build WASM module (requires javy)- Fork the repository
- Create a branch (
git checkout -b feature/your-feature) - Make changes with tests (
pnpm test -- --run && pnpm typecheck) - Open a Pull Request