Skip to main content
The FEN module provides functions for parsing and generating FEN strings, which are used to describe chess positions.

Constants

Position Constants

import { 
  INITIAL_BOARD_FEN, 
  INITIAL_EPD, 
  INITIAL_FEN,
  EMPTY_BOARD_FEN,
  EMPTY_EPD,
  EMPTY_FEN 
} from 'chessops/fen';

console.log(INITIAL_FEN);
// 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'
INITIAL_BOARD_FEN
string
Board part of starting position: 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR'
INITIAL_EPD
string
Starting position EPD (without move counters): INITIAL_BOARD_FEN + ' w KQkq -'
INITIAL_FEN
string
Complete starting position FEN: INITIAL_EPD + ' 0 1'
EMPTY_BOARD_FEN
string
Empty board: '8/8/8/8/8/8/8/8'
EMPTY_EPD
string
Empty position EPD: EMPTY_BOARD_FEN + ' w - -'
EMPTY_FEN
string
Complete empty position FEN: EMPTY_EPD + ' 0 1'

Error Handling

InvalidFen

Enum of possible FEN parsing errors.
import { InvalidFen } from 'chessops/fen';

enum InvalidFen {
  Fen = 'ERR_FEN',
  Board = 'ERR_BOARD',
  Pockets = 'ERR_POCKETS',
  Turn = 'ERR_TURN',
  Castling = 'ERR_CASTLING',
  EpSquare = 'ERR_EP_SQUARE',
  RemainingChecks = 'ERR_REMAINING_CHECKS',
  Halfmoves = 'ERR_HALFMOVES',
  Fullmoves = 'ERR_FULLMOVES',
}

FenError

Error class for FEN parsing failures.
import { FenError, parseFen } from 'chessops/fen';

const result = parseFen('invalid');
if (result.isErr) {
  const error: FenError = result.error;
  console.log(error.message); // One of the InvalidFen values
}

Parsing Functions

parseFen

Parses a complete FEN string into a Setup.
import { parseFen } from 'chessops/fen';

const result = parseFen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1');

if (result.isOk) {
  const setup = result.value;
  console.log(setup.turn); // 'white'
  console.log(setup.fullmoves); // 1
} else {
  console.error('Invalid FEN:', result.error.message);
}
fen
string
required
The FEN string to parse. Supports:
  • Standard FEN
  • FEN with pockets (Crazyhouse): [Qq] or /Qq notation
  • FEN with remaining checks (Three-check): +1+2 notation
  • Promoted pieces marked with ~
return
Result<Setup, FenError>
A Result containing either the parsed Setup or a FenError

parseBoardFen

Parses only the board part of a FEN string.
import { parseBoardFen } from 'chessops/fen';

const result = parseBoardFen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR');

if (result.isOk) {
  const board = result.value;
  console.log(board.occupied.size()); // 32
}
boardPart
string
required
The board part of a FEN string (before the first space)
return
Result<Board, FenError>
A Result containing either the parsed Board or a FenError

parsePockets

Parses pocket notation for Crazyhouse.
import { parsePockets } from 'chessops/fen';

const result = parsePockets('Qq'); // White queen, black queen

if (result.isOk) {
  const pockets = result.value;
  console.log(pockets.white.queen); // 1
  console.log(pockets.black.queen); // 1
}
pocketPart
string
required
String of piece letters (uppercase for white, lowercase for black)
return
Result<Material, FenError>
A Result containing either the parsed Material (pockets) or a FenError

parseCastlingFen

Parses castling rights from FEN notation.
import { parseCastlingFen, parseBoardFen } from 'chessops/fen';

const board = parseBoardFen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR').unwrap();
const result = parseCastlingFen(board, 'KQkq');

if (result.isOk) {
  const castlingRights = result.value;
  console.log(castlingRights.has(0)); // true (a1 rook for white queenside)
  console.log(castlingRights.has(7)); // true (h1 rook for white kingside)
}
board
Board
required
The board to use for determining rook positions
castlingPart
string
required
Castling rights string: ‘KQkq’, ‘Kk’, ‘AHah’ (Chess960), or ’-’
return
Result<SquareSet, FenError>
A Result containing either a SquareSet of rook squares with castling rights or a FenError

parseRemainingChecks

Parses remaining checks notation for Three-check variant.
import { parseRemainingChecks } from 'chessops/fen';

const result = parseRemainingChecks('2+1');

if (result.isOk) {
  const checks = result.value;
  console.log(checks.white); // 2
  console.log(checks.black); // 1
}
part
string
required
Remaining checks string: ‘3+3’, ‘2+1’, ‘+1+2’, etc.
return
Result<RemainingChecks, FenError>
A Result containing either the parsed RemainingChecks or a FenError

parsePiece

Parses a single piece from a string.
import { parsePiece } from 'chessops/fen';

const piece = parsePiece('K');
console.log(piece); // { role: 'king', color: 'white' }

const promoted = parsePiece('q~');
console.log(promoted); // { role: 'queen', color: 'black', promoted: true }
str
string
required
A piece character (K, Q, R, B, N, P for white; k, q, r, b, n, p for black), optionally followed by ’~’ for promoted
return
Piece | undefined
The parsed Piece, or undefined if invalid

Generation Functions

makeFen

Generates a FEN string from a Setup.
import { makeFen } from 'chessops/fen';
import { Chess } from 'chessops/chess';

const pos = Chess.default();
pos.play({ from: 12, to: 28 }); // e2-e4

const fen = makeFen(pos.toSetup());
console.log(fen);
// 'rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1'
setup
Setup
required
The position setup to convert to FEN
opts
FenOpts
Options:
  • epd?: boolean - If true, omits halfmove and fullmove counters (generates EPD instead of FEN)
return
string
The FEN string representation of the position

makeBoardFen

Generates only the board part of a FEN string.
import { makeBoardFen } from 'chessops/fen';
import { Board } from 'chessops/board';

const board = Board.default();
const boardFen = makeBoardFen(board);
console.log(boardFen);
// 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR'
board
Board
required
The board to convert to FEN notation
return
string
The board part of a FEN string

makePiece

Generates the FEN notation for a single piece.
import { makePiece } from 'chessops/fen';

const piece = { role: 'queen', color: 'white' };
console.log(makePiece(piece)); // 'Q'

const promoted = { role: 'queen', color: 'black', promoted: true };
console.log(makePiece(promoted)); // 'q~'
piece
Piece
required
The piece to convert
return
string
The FEN notation for the piece

makePockets

Generates pocket notation for Crazyhouse.
import { makePockets } from 'chessops/fen';
import { Material } from 'chessops/setup';

const pockets = Material.empty();
pockets.white.queen = 1;
pockets.black.pawn = 2;

console.log(makePockets(pockets)); // 'Qpp'
pocket
Material
required
The material in pockets for both sides
return
string
The pocket notation string

makeCastlingFen

Generates castling rights notation.
import { makeCastlingFen } from 'chessops/fen';
import { Board } from 'chessops/board';
import { SquareSet } from 'chessops';

const board = Board.default();
const castlingRights = SquareSet.fromSquares([0, 7, 56, 63]);

console.log(makeCastlingFen(board, castlingRights)); // 'KQkq'
board
Board
required
The board (used to determine standard vs Chess960 notation)
castlingRights
SquareSet
required
Set of squares containing rooks with castling rights
return
string
The castling rights notation

makeRemainingChecks

Generates remaining checks notation for Three-check.
import { makeRemainingChecks, RemainingChecks } from 'chessops/fen';

const checks = new RemainingChecks(2, 1);
console.log(makeRemainingChecks(checks)); // '2+1'
checks
RemainingChecks
required
The remaining checks for both sides
return
string
The remaining checks notation

Usage Examples

Round-Trip Conversion

import { parseFen, makeFen } from 'chessops/fen';

const originalFen = 'rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1';
const setup = parseFen(originalFen).unwrap();
const regeneratedFen = makeFen(setup);

console.log(originalFen === regeneratedFen); // true

Handling Variants

import { parseFen, makeFen } from 'chessops/fen';

// Crazyhouse with pockets
const zhFen = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR[Qq] w KQkq - 0 1';
const zhSetup = parseFen(zhFen).unwrap();
console.log(zhSetup.pockets?.white.queen); // 1

// Three-check with remaining checks
const tcFen = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 3+3 0 1';
const tcSetup = parseFen(tcFen).unwrap();
console.log(tcSetup.remainingChecks?.white); // 3

Custom Position Setup

import { parseFen, makeFen } from 'chessops/fen';
import { setupPosition } from 'chessops/variant';

const fen = '8/8/8/4k3/8/8/4K3/8 w - - 0 1';
const setup = parseFen(fen).unwrap();
const pos = setupPosition('chess', setup).unwrap();

console.log(pos.isEnd()); // true (insufficient material)

Build docs developers (and LLMs) love