The compat module provides utilities for converting between chessops formats and those used by other chess libraries like chessground and scalachess.
Chessground Compatibility
chessgroundDests
Converts legal moves to chessground’s destination format.
import { chessgroundDests } from 'chessops/compat';
import { Chess } from 'chessops/chess';
const pos = Chess.default();
const dests = chessgroundDests(pos);
console.log(dests.get('e2')); // ['e3', 'e4']
console.log(dests.get('g1')); // ['f3', 'h3']
The position to compute legal move destinations for
Options:
chess960?: boolean - If true, uses Chess960 castling notation (king captures rook)
return
Map<SquareName, SquareName[]>
Map from source square to array of destination squares. Includes both standard and Chess960 castling destinations unless chess960: true is specified.
By default, this function includes both types of castling destinations (king-to-rook and king-to-destination) so chessground’s rookCastles option works correctly. Enable chess960: true to only include Chess960-style castling.
chessgroundMove
Converts a move to chessground’s move format.
import { chessgroundMove } from 'chessops/compat';
const normalMove = { from: 12, to: 28 }; // e2-e4
console.log(chessgroundMove(normalMove)); // ['e2', 'e4']
const drop = { role: 'queen', to: 39 }; // Q@h5
console.log(chessgroundMove(drop)); // ['h5']
Array with [from, to] for normal moves, or [to] for drops
Scalachess Compatibility
scalachessCharPair
Converts a move to scalachess’s binary char-pair format.
import { scalachessCharPair } from 'chessops/compat';
const move = { from: 12, to: 28 }; // e2-e4
console.log(scalachessCharPair(move)); // Two-character string
// Promotion
const promotion = { from: 48, to: 56, promotion: 'queen' }; // a7-a8=Q
console.log(scalachessCharPair(promotion));
// Drop
const drop = { role: 'queen', to: 39 }; // Q@h5
console.log(scalachessCharPair(drop));
Two-character string encoding the move in scalachess format
This encoding is used by Lichess and scalachess for compact binary move representation. The format encodes source square, destination square, and promotion piece (if any) in just two characters.
Variant Conversion
lichessRules
Converts Lichess variant names to chessops Rules.
import { lichessRules } from 'chessops/compat';
console.log(lichessRules('standard')); // 'chess'
console.log(lichessRules('chess960')); // 'chess'
console.log(lichessRules('kingOfTheHill')); // 'kingofthehill'
console.log(lichessRules('threeCheck')); // '3check'
console.log(lichessRules('crazyhouse')); // 'crazyhouse'
console.log(lichessRules('atomic')); // 'atomic'
console.log(lichessRules('horde')); // 'horde'
console.log(lichessRules('racingKings')); // 'racingkings'
console.log(lichessRules('antichess')); // 'antichess'
Lichess variant name: ‘standard’ | ‘chess960’ | ‘antichess’ | ‘fromPosition’ | ‘kingOfTheHill’ | ‘threeCheck’ | ‘atomic’ | ‘horde’ | ‘racingKings’ | ‘crazyhouse’
The corresponding chessops Rules type
lichessVariant
Converts chessops Rules to Lichess variant names.
import { lichessVariant } from 'chessops/compat';
console.log(lichessVariant('chess')); // 'standard'
console.log(lichessVariant('kingofthehill')); // 'kingOfTheHill'
console.log(lichessVariant('3check')); // 'threeCheck'
console.log(lichessVariant('crazyhouse')); // 'crazyhouse'
console.log(lichessVariant('atomic')); // 'atomic'
console.log(lichessVariant('horde')); // 'horde'
console.log(lichessVariant('racingkings')); // 'racingKings'
console.log(lichessVariant('antichess')); // 'antichess'
The corresponding Lichess variant name
Usage Examples
Integrating with Chessground
import { chessgroundDests, chessgroundMove } from 'chessops/compat';
import { Chess } from 'chessops/chess';
import { parseSan } from 'chessops/san';
import { Chessground } from 'chessground';
const pos = Chess.default();
const cg = Chessground(document.getElementById('board')!, {
fen: pos.toSetup().board.fen,
turnColor: pos.turn,
movable: {
free: false,
dests: chessgroundDests(pos),
},
});
// Handle user moves
cg.set({
movable: {
events: {
after: (orig, dest) => {
// Convert chessground move to SAN
const move = parseSan(pos, `${orig}${dest}`);
if (move) {
pos.play(move);
cg.set({
fen: pos.toSetup().board.fen,
turnColor: pos.turn,
movable: { dests: chessgroundDests(pos) },
});
}
},
},
},
});
Chess960 Support
import { chessgroundDests } from 'chessops/compat';
import { Chess } from 'chessops/chess';
import { parseFen } from 'chessops/fen';
// Chess960 position
const fen = 'rkbqnbnr/pppppppp/8/8/8/8/PPPPPPPP/RKBQNBNR w KQkq - 0 1';
const setup = parseFen(fen).unwrap();
const pos = Chess.fromSetup(setup).unwrap();
// Enable chess960 mode for chessground
const dests = chessgroundDests(pos, { chess960: true });
// Configure chessground
chessground.set({
fen,
movable: {
dests,
},
chess960: true,
});
Sending Moves to Server
import { scalachessCharPair } from 'chessops/compat';
import { parseSan } from 'chessops/san';
import { Chess } from 'chessops/chess';
const pos = Chess.default();
const move = parseSan(pos, 'e4')!;
// Encode move for transmission
const encoded = scalachessCharPair(move);
// Send to server (compact binary format)
await fetch('/api/move', {
method: 'POST',
body: JSON.stringify({ move: encoded }),
});
Multi-Variant Support
import { lichessRules, lichessVariant, chessgroundDests } from 'chessops/compat';
import { defaultPosition } from 'chessops/variant';
function initGame(variant: string) {
// Convert Lichess variant to chessops rules
const rules = lichessRules(variant as any);
// Create position
const pos = defaultPosition(rules);
// Setup chessground
return {
fen: pos.toSetup().board.fen,
dests: chessgroundDests(pos),
variant: lichessVariant(rules),
};
}
const game = initGame('threeCheck');
console.log(game.variant); // 'threeCheck'
Handling Drops in Crazyhouse
import { chessgroundMove, chessgroundDests } from 'chessops/compat';
import { Crazyhouse } from 'chessops/variant';
import { parseFen } from 'chessops/fen';
const setup = parseFen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR[Qq] w KQkq - 0 1').unwrap();
const pos = Crazyhouse.fromSetup(setup).unwrap();
// Get drop destinations for chessground
const dests = chessgroundDests(pos);
// Chessground uses pockets, represented as special squares
// Q@h5 becomes a drop move
const drop = { role: 'queen' as const, to: 39 }; // h5
const cgMove = chessgroundMove(drop);
console.log(cgMove); // ['h5'] (single element for drops)
pos.play(drop);
Converting Between Systems
import { scalachessCharPair, chessgroundMove } from 'chessops/compat';
import { parseSan } from 'chessops/san';
import { Chess } from 'chessops/chess';
const pos = Chess.default();
const move = parseSan(pos, 'Nf3')!;
// For different systems
const forChessground = chessgroundMove(move);
console.log(forChessground); // ['g1', 'f3']
const forScalachess = scalachessCharPair(move);
console.log(forScalachess.length); // 2 (compact binary)