Chess

100 chess variants with AI, embed support, and a headless SDK for server-side consumers.

Embed via iframe

Drop a board into any page with a single iframe. The embed is fully responsive and touch-ready.

<iframe
  src="https://engine.moddable.games/play/?embed=1&variant=standard"
  style="width:100%;max-width:560px;aspect-ratio:1/1;border:none"
  title="Play Chess"
></iframe>

URL parameters

ParamValuesDefault
embed1Required for embed mode
variantAny variant keystandard
opponentai | humanai in embed
difficultybeginner | easy | medium | hard | expertmedium
colorwhite | blackwhite
piecesPiece set IDmce-fairy-complete
flipped1Board orientation

postMessage control

Control the embed without reloading the iframe. Send messages to iframe.contentWindow:

// Change variant
iframe.contentWindow.postMessage({ type: 'chess:setVariant', variant: 'atomic' }, '*')

// Change difficulty (also activates AI)
iframe.contentWindow.postMessage({ type: 'chess:setDifficulty', difficulty: 'hard' }, '*')

// Switch between human/AI
iframe.contentWindow.postMessage({ type: 'chess:setOpponent', opponent: 'ai' }, '*')

// Game controls
iframe.contentWindow.postMessage({ type: 'chess:newGame' }, '*')
iframe.contentWindow.postMessage({ type: 'chess:undo' }, '*')
iframe.contentWindow.postMessage({ type: 'chess:flip' }, '*')

// Change piece set
iframe.contentWindow.postMessage({ type: 'chess:setPieces', set: 'mce-chess' }, '*')

// Change board theme
iframe.contentWindow.postMessage({ type: 'chess:setTheme', theme: 'cosmic' }, '*')
// Themes: classic, cosmic, wood, marble, neon, minimal, transparent

Events from embed

Listen on the parent window for game events:

window.addEventListener('message', (e) => {
  switch (e.data.type) {
    case 'chess:ready':
      // { variant, fen }
      break
    case 'chess:move':
      // { from, to, fen, variant }
      break
    case 'chess:status':
      // { text: 'white'|'black'|'draw', gameOver: true, variant }
      break
  }
})

Chess SDK

Headless SDK for server-side tools, APIs, and direct browser consumption.

import {
  listVariants,
  createGame,
  getLegalMoves,
  analyzePosition,
  getGameStatus,
  renderSvg,
  createAI,
} from '@moddable/engine/play'

listVariants(group?)

Returns all registered variants with metadata.

const all = listVariants()          // 100 variants
// [{ key, label, group, board, description, rule }]

getLegalMoves(variant, fen?)

Returns all legal moves in algebraic notation.

const moves = getLegalMoves('standard')  // starting position: 20 moves
// [{ from: 'e2', to: 'e4', capture: false, promotion: null, flag: null }]

analyzePosition(variant, fen?, depth?)

AI evaluation with best move.

const result = analyzePosition('standard', null, 4)
// { bestMove: 'e2e4', evaluation: 0.3 }

renderSvg(variant, fen?, opts?)

Renders a board position as an SVG string. No DOM required.

const { svg, rows, cols } = renderSvg('capablanca')
// svg = '<svg xmlns="..." ...' (14KB, self-contained)

const custom = renderSvg('standard', 'rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1')

getGameStatus(variant, fen?)

const status = getGameStatus('standard', 'some-fen')
// { status: 'active', gameOver: false, turn: 'white', inCheck: false }
// or: { status: 'checkmate', gameOver: true }

Game state management

const game = createGame('chess', 'atomic')
const moves = game.getLegalMoves()
game.applyMove(moves[0])

Variant parameters

Every chess variant is expressed through the plugin's parametric configuration, with no per-variant code. These keys go under engine.plugins.chess in the variant's frontmatter. See Authoring a Variant for the file layout.

ParameterDefaultEffect
setupfamilyFEN-like starting position. One rank per /, digits for empty runs.
castlingtrueWhether castling is available.
enPassanttrueWhether pawns may capture en passant.
doubleSteptrueWhether pawns may advance two squares from their start rank.
torpedofalsePawns may double-step from anywhere, not only the start rank.
promotionChoicesQ R B NPiece types a pawn may promote to.
promotionRowderivedOverride the promotion rank when it is not the far edge.
pawnStartRowderivedOverride the double-step rank. Derived from the setup when absent.
royalTypekingWhich piece type is royal. none removes check and checkmate entirely.
rookTyperookWhich piece type castles with the royal.
pawnTypepawnWhich piece type follows pawn rules.
noCheckfalseSkip check detection. Required when royalType: none.
stalemateMeaningdrawdraw, win or loss for the stalemated player.
winConditioncheckmateAlternative terminal condition, e.g. antichess.
checkThresholdNumber of checks that wins. Three-check chess sets 3.
dropsfalseCaptured pieces enter a hand and may be dropped. The crazyhouse shape.
placementPiecesPieces placed during a setup phase rather than present at the start.
randomSetupfalseShuffle the back rank. The chess960 shape.
playerCount2Number of armies. Above two, declare advancement as well.
advancement{0:-1, 1:1}Which way each seat advances, by owner index. Scalar, or [dr, dc] on a cross-shaped board.
visibilityFog-of-war and dark-chess style restrictions.
piecesMovement definitions for pieces beyond the standard six. See Defining a new piece.
vocabularyMaps piece types to FEN symbols, keyed by owner index.
extendsInherit another variant's rule config, then override.

A key the plugin does not recognise is reported on the console as [chess] Unknown config keys: … and otherwise ignored, so the variant silently plays with the default. Check that warning first when a rule appears not to take effect.

Variants

100 variants registered and playable. Use the key as the variant URL parameter or SDK argument.

KeyBoardDistinguishing rule
standard8×8Standard FIDE rules
absorptionChess8×8Capturing piece gains the victim's movement abilities
almost-chess8×8White's Queen replaced by a Chancellor (R+N)
amazon-chess8×8Queens replaced by Amazons (Q+N)
andernachChess8×8Capturing piece changes colour
antichess8×8Captures mandatory; first to lose all pieces wins
asean8×8Southeast Asian rules: Makruk-family pieces, rank-6 promotion
atomic8×8Captures explode all adjacent non-pawn pieces
benedictChess8×8No captures; attacked enemies convert to your colour
berolinaChess8×8Pawns move diagonal, capture straight (inverted)
berserkChess8×8Check grants one bonus move
birds-chess8×101874 variant with Guard (R+N) and Equerry (B+N)
breakthrough7×7Pawns only; first to reach the far rank wins
bruskyhexHorizontal 84-hex board, 10 pawns per side
byzantine-chess4×16Circular board, Shatranj pieces, stalemate wins
capablanca8×10Archbishop (B+N) and Chancellor (R+N) on a wider board
carrera8×101617 variant with Champion (R+N) and Centaur (B+N)
chancellor-chess9×9Chancellor (R+N) added on 9×9
chaturanga8×8Ancient Indian ancestor; weak counsellor, leaping elephant
checklessChess8×8Cannot give check unless it is checkmate
chess9608×8Randomised back rank (960 positions)
chigorin8×8White's Bishops replaced by Knights
circular-chess4×1664 squares in 4 concentric rings; no castling
codrus8×8Win by getting your own King captured
courier8×12Medieval 1202 variant on a 12-wide board
crazyhouse8×8Captured pieces switch sides and can be dropped
cylinder-chess8×8a-file wraps to h-file
darkChess8×8Total fog; only see your own pieces' squares
de-vasahex81-hex rhombus board
diana6×6No queens or knights; bishops and rooks only
diceChess8×8Die roll constrains which piece type must move
displacementChess8×8Swap positions with adjacent friendly pieces
duckChess8×8Place a blocking duck on any empty square after each move
einsteinChess8×8Non-capturing moves demote; captures promote
empire8×8Asymmetric: FIDE Kingdom vs Empire dynasty
endgame-chess8×8Kings and pawns only from move one
extinction8×8Lose any piece type entirely and you lose
fiveCheck8×8Five checks wins
fogOfWar8×8See only squares your pieces can move to
giveaway8×8Forced captures; stalemate is a loss
glinskihex91-cell hexagonal board; three bishops per side
grand10×10Marshal and Cardinal; pawns start on rank 3
gridChess8×8Moves must cross a 2×2 grid line
half-chess4×84-rank board; armies start adjacent
hexapawn3×3Six pawns; reach far rank wins
hoppel-poppel8×8Knights capture like bishops; bishops capture like knights
horde8×8White: full army vs Black: 36 pawns
immunizationChess8×8Captures grant adjacent enemies temporary immunity
janus8×10Two Januses (B+N) on a 10-wide board
khans-chess8×8Asymmetric: FIDE vs Mongol Horde with divergent movers
kingOfTheHill8×8King reaching d4/d5/e4/e5 wins instantly
knightmate8×8Knight is royal; Kings move as knights
leganChess8×8Berolina pawns; King and Queen swap squares
los-alamos6×6First computer chess (1956); no Bishops
madrasiChess8×8Same-type opposing pieces paralyse each other
maharaja8×8One Amazon (Q+N) vs a full army
makpong8×8King cannot move out of check; must block or capture
makruk8×8Thai chess; Khon moves 5 directions, rank-6 promotion
marseillais8×8Two moves per turn (except White's first)
mccooeyhex91-hex board; diagonal pawn captures, stalemate draws
medusaChess8×8Queen petrifies attacked enemies for 2 turns
mini-hexchesshex37-hex board; no Queen piece
minichess5×5Gardner's 5×5 with all piece types
monsterChess8×8White moves twice but starts with only K, R, pawns
nightrider8×8Knights replaced by Nightriders (chained knight-leaps)
no-castling8×8Standard chess without castling
noRetreat8×8Pieces cannot move toward their own starting rank
oblong-chess16×4Historical 4×16 board; Shatranj pieces
omnicide8×8Lose all pieces to win; captures NOT forced
orda-chess8×8Asymmetric: standard vs Horde with divergent movers
orda-mirror8×8Both players use the Horde army
ouk-chaktrang8×8Cambodian chess; King may leap as Knight on first move
patrolChess8×8Can only capture when defended by a friendly piece
pawns-only8×8Kings and pawns only; first to promote wins
peasants-revolt8×8White: K+8P vs Black: K+2N+8P
petty5×6All piece types on 5×6; single copies
poisonChess8×8Capture squares become poisoned for 3 turns
progressive8×8Moves escalate: 1, 2, 3, 4... Check ends turn early
progressive-italian8×8Progressive; no check until final move of turn
racingKings8×8No checks; race your King to rank 8
recruitmentChess8×8Captured piece defects to vacated square
rifle8×8Capturing piece stays on its square
shafranhex70-hex board with 9 files; castling permitted
shatar8×8Mongolian chess; mate must include shak; bare king draws
shatranj8×8Medieval Islamic chess; bare king and stalemate win
shatranj-kamil10×1010×10 Arabic variant with War Machines
singleCheck8×8One check wins
sittuyin8×8Burmese chess; placement opening phase
stalemate-wins8×8Stalemate is a win instead of a draw
suicideChess8×8Forced captures; stalemate is a draw
teleportChess8×83 teleports per game; move any piece to any empty square
threeCheck8×8Three checks wins
toroidal-byzantine4×16Circular board with radial wraparound
toroidal-chess8×8All four edges wrap (torus topology)
torpedo8×8Pawns can double-step from any rank
turkish-great-chess-iii12×12Ottoman 12×12 with multiple rook-type pieces
turkish-great-chess-iv14×1414×14 with mixed Indian/Persian piece names
upside-down8×8Pieces start on the opponent's back rank
weakChess8×8Weakest piece type must move first
wildebeest10×11Camels and Wildebeests (N+Camel) on 11×10

AI difficulties

LevelDepthNotes
beginner1Random with basic blunder avoidance
easy2Simple evaluation, no deep tactics
medium3Full evaluation, opening book, captures extended
hard4Transposition table, quiescence search
expert5+Full search with iterative deepening

Puzzle API

1,876 puzzles available as static JSON at /api/puzzles/index.json.

// Fetch puzzle data
const res = await fetch('https://engine.moddable.games/api/puzzles/index.json')
const data = await res.json()

// data.standard = [{ id, fen, position, turn, variantSlug, solution, rating, themes, setupMove? }]
// data.variants = [{ id, variant, variantSlug, fen, position, turn, solution, rating, setupMove? }]
// data.meta = { count: 1876, standard: 1118, variants: 758, schemaVersion: 2 }
//
// position: the FEN the solver faces (after setupMove is applied through the engine).
// fen: provenance — the source position before the opponent's move.
// setupMove: if present, the move that was applied to fen to produce position.
// variantSlug: kebab-case key matching play/playability-manifest.json.