Portable Game Notation import/export with headers, comments, and move annotation support. PGN (Portable Game Notation) is the standard format for recording chess games, including metadata, moves, and annotations.
Export the current game as PGN format with customizable formatting options.
class Chess {
/**
* Export game as PGN string
* @param options - PGN formatting options
* @returns PGN string representation of the game
*/
pgn(options?: PgnOptions): string;
}
interface PgnOptions {
/** String to use for line breaks (default: '\n') */
newline?: string;
/** Maximum line width for wrapping (0 = no wrapping) */
maxWidth?: number;
}Usage Examples:
import { Chess } from "chess.js";
const chess = new Chess();
// Set up game headers
chess.setHeader('Event', 'World Championship');
chess.setHeader('Site', 'New York');
chess.setHeader('Date', '2024.01.15');
chess.setHeader('Round', '1');
chess.setHeader('White', 'Carlsen, Magnus');
chess.setHeader('Black', 'Nepomniachtchi, Ian');
// Play some moves
chess.move('e4');
chess.move('e5');
chess.move('Nf3');
chess.move('Nc6');
// Export as PGN
console.log(chess.pgn());
/*
[Event "World Championship"]
[Site "New York"]
[Date "2024.01.15"]
[Round "1"]
[White "Carlsen, Magnus"]
[Black "Nepomniachtchi, Ian"]
[Result "*"]
1. e4 e5 2. Nf3 Nc6 *
*/
// Custom formatting
const htmlPgn = chess.pgn({
newline: '<br />',
maxWidth: 40
});
console.log(htmlPgn);Import complete games from PGN format with support for headers, moves, and annotations.
class Chess {
/**
* Load game from PGN string
* @param pgn - PGN string to parse
* @param options - Parsing options
* @throws Error if PGN is invalid
*/
loadPgn(pgn: string, options?: LoadPgnOptions): void;
}
interface LoadPgnOptions {
/** Use strict SAN parsing (reject non-standard moves) */
strict?: boolean;
/** Custom newline character pattern (default: '\r?\n') */
newlineChar?: string;
}Usage Examples:
const chess = new Chess();
const pgnString = `
[Event "Casual Game"]
[Site "Berlin GER"]
[Date "1852.??.??"]
[Round "?"]
[White "Adolf Anderssen"]
[Black "Jean Dufresne"]
[Result "1-0"]
1.e4 e5 2.Nf3 Nc6 3.Bc4 Bc5 4.b4 Bxb4 5.c3 Ba5 6.d4 exd4 7.O-O
d3 8.Qb3 Qf6 9.e5 Qg6 10.Re1 Nge7 11.Ba3 b5 12.Qxb5 Rb8 13.Qa4
Bb6 14.Nbd2 Bb7 15.Ne4 Qf5 16.Bxd3 Qh5 17.Nf6+ gxf6 18.exf6
Rg8 19.Rad1 Qxf3 20.Rxe7+ Nxe7 21.Qxd7+ Kxd7 22.Bf5+ Ke8
23.Bd7+ Kf8 24.Bxe7# 1-0
`;
chess.loadPgn(pgnString);
// Access loaded headers
console.log(chess.getHeaders());
// { Event: 'Casual Game', Site: 'Berlin GER', ... }
// Get loaded moves
console.log(chess.history());
// ['e4', 'e5', 'Nf3', 'Nc6', ...]
// Non-standard notation (permissive parser)
const sloppyPgn = `
1. Pc2c4 Pe7e5
2. Ng1f3 Nb8c6
3. g2g3 Bf8b4
`;
chess.loadPgn(sloppyPgn); // Works with permissive parser
// Strict parsing
try {
chess.loadPgn(sloppyPgn, { strict: true });
} catch (error) {
console.error('Strict parsing failed:', error.message);
}
// Custom newline character
const colonSeparatedPgn = '1. e4 e5:2. Nf3 Nc6:3. Bc4 Bc5';
chess.loadPgn(colonSeparatedPgn, { newlineChar: ':' });Comprehensive PGN header management with support for standard and custom headers.
class Chess {
/**
* Get all non-null PGN headers
* @returns Object containing all set headers
*/
getHeaders(): Record<string, string>;
/**
* Set a PGN header value
* @param key - Header name
* @param value - Header value
* @returns Updated headers object
*/
setHeader(key: string, value: string): Record<string, string>;
/**
* Remove a PGN header
* @param key - Header name to remove
* @returns True if header was removed, false if not found
*/
removeHeader(key: string): boolean;
/**
* @deprecated Legacy header method - use setHeader/getHeaders instead
*/
header(...args: string[]): Record<string, string | null>;
}Usage Examples:
const chess = new Chess();
// Set standard headers
chess.setHeader('Event', 'World Championship');
chess.setHeader('Site', 'London');
chess.setHeader('Date', '2024.03.15');
chess.setHeader('Round', '5');
chess.setHeader('White', 'Player One');
chess.setHeader('Black', 'Player Two');
// Set custom headers
chess.setHeader('Annotator', 'Stockfish 15');
chess.setHeader('TimeControl', '40/7200:3600+30');
// Get all headers
const headers = chess.getHeaders();
console.log(headers);
// { Event: 'World Championship', Site: 'London', ... }
// Remove header
const removed = chess.removeHeader('Annotator');
console.log(removed); // true
// Check if header exists
if ('Event' in chess.getHeaders()) {
console.log('Event header is set');
}
// Required PGN headers (Seven Tag Roster)
const requiredHeaders = [
'Event', 'Site', 'Date', 'Round', 'White', 'Black', 'Result'
];Add, retrieve, and manage position comments within games.
class Chess {
/**
* Get comment for current position
* @returns Comment string or undefined if no comment
*/
getComment(): string;
/**
* Set comment for current position
* @param comment - Comment text
*/
setComment(comment: string): void;
/**
* Remove comment for current position
* @returns Removed comment or undefined
*/
removeComment(): string;
/**
* Get all comments in the game
* @returns Array of comment objects with FEN and comment text
*/
getComments(): CommentInfo[];
/**
* Remove all comments from the game
* @returns Array of removed comments
*/
removeComments(): CommentInfo[];
/**
* @deprecated Use removeComment instead
*/
deleteComment(): string;
/**
* @deprecated Use removeComments instead
*/
deleteComments(): CommentInfo[];
}
interface CommentInfo {
/** FEN string of the position */
fen: string;
/** Comment text */
comment: string;
}Usage Examples:
const chess = new Chess();
chess.move('e4');
chess.setComment("King's pawn opening");
chess.move('e5');
chess.move('Nf3');
chess.setComment('Developing the knight');
// Get current position comment
console.log(chess.getComment()); // 'Developing the knight'
// Get all comments
const allComments = chess.getComments();
console.log(allComments);
// [
// { fen: '...', comment: "King's pawn opening" },
// { fen: '...', comment: 'Developing the knight' }
// ]
// Remove current comment
const removed = chess.removeComment();
console.log(removed); // 'Developing the knight'
// Export PGN with comments
console.log(chess.pgn());
// 1. e4 {King's pawn opening} e5 2. Nf3 *Required headers that should be present in every PGN:
const SEVEN_TAG_ROSTER = {
Event: '?', // Tournament or match name
Site: '?', // Location
Date: '????.??.??', // Date (YYYY.MM.DD format)
Round: '?', // Round number
White: '?', // White player name
Black: '?', // Black player name
Result: '*' // Game result: 1-0, 0-1, 1/2-1/2, or *
};Additional optional headers:
const SUPPLEMENTAL_HEADERS = [
'WhiteTitle', 'BlackTitle', // Player titles
'WhiteElo', 'BlackElo', // Player ratings
'EventDate', 'EventSponsor', // Event information
'Section', 'Stage', 'Board', // Tournament details
'Opening', 'Variation', 'SubVariation', 'ECO', // Opening information
'Time', 'UTCTime', 'UTCDate', // Timing information
'TimeControl', // Time control format
'SetUp', 'FEN', // Custom starting position
'Termination', // How game ended
'Annotator', 'Mode', 'PlyCount' // Additional metadata
];1., 2., etc.{comment text}!, ?, !!, ??, !?, ?!$1, $2, etc. (Numeric Annotation Glyphs)(alternative moves)1-0, 0-1, 1/2-1/2, *[Event "World Championship"]
[Site "Reykjavik ISL"]
[Date "1972.07.11"]
[Round "6"]
[White "Fischer, Robert J."]
[Black "Spassky, Boris V."]
[Result "1-0"]
[ECO "D59"]
1. c4 e6 2. Nf3 d5 3. d4 Nf6 4. Nc3 Be7 5. Bg5 O-O 6. e3 h6
7. Bh4 b6 8. cxd5 Nxd5 9. Bxe7 Qxe7 10. Nxd5 exd5 11. Rc1 Be6
12. Qa4 c5 13. Qa3 Rc8 {An interesting position} 14. Bb5 a6
15. dxc5 bxc5 16. O-O Ra7 17. Be2 Nd7 18. Nd4 Qf8 19. Nxe6 fxe6
20. e4 d4 21. f4 Qe7 22. e5 Rb8 23. Bc4 Kh8 24. Qh3 Nf8
25. b3 a5 26. f5 exf5 27. Rxf5 Nh7 28. Rcf1 Qd8 29. Qg3 Re7
30. h4 Rbb7 31. e6 Rbc7 32. Qe5 Qe8 33. a4 Qd8 34. R1f2 Qe8
35. R2f3 Qd8 36. Bd3 Qe8 37. Qe4 Nf6 38. Rxf6 gxf6 39. Rxf6 Kg8
40. Bc4 Kh8 41. Qf4 1-0const pgnWithSetup = `
[SetUp "1"]
[FEN "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1"]
1...e5 2. Nf3 Nc6 3. Bb5 a6
`;
chess.loadPgn(pgnWithSetup);
console.log(chess.fen()); // Starts from custom position// Robust PGN loading
function safePgnLoad(pgnString: string): { success: boolean; error?: string } {
try {
const chess = new Chess();
chess.loadPgn(pgnString);
return { success: true };
} catch (error) {
return { success: false, error: error.message };
}
}
// Common PGN errors
const errors = [
'Invalid move in PGN: Xyz',
'Invalid PGN: FEN tag must be supplied with SetUp tag',
'Error parsing PGN move text'
];interface PgnOptions {
newline?: string;
maxWidth?: number;
}
interface LoadPgnOptions {
strict?: boolean;
newlineChar?: string;
}
interface CommentInfo {
fen: string;
comment: string;
}
// Standard PGN headers
const SEVEN_TAG_ROSTER: Record<string, string> = {
Event: '?',
Site: '?',
Date: '????.??.??',
Round: '?',
White: '?',
Black: '?',
Result: '*'
};