or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

board-representation.mdfen-support.mdgame-analysis.mdgame-management.mdindex.mdmove-operations.mdpgn-support.md
tile.json

pgn-support.mddocs/

PGN Support

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.

Capabilities

PGN Export

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);

PGN Import

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: ':' });

Header Management

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'
];

Comment Management

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 *

PGN Format Specification

Standard Headers (Seven Tag Roster)

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 *
};

Supplemental Headers

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
];

Move Text Format

  • Move numbers: 1., 2., etc.
  • Moves: Standard Algebraic Notation (SAN)
  • Comments: {comment text}
  • Annotations: !, ?, !!, ??, !?, ?!
  • NAGs: $1, $2, etc. (Numeric Annotation Glyphs)
  • Variations: (alternative moves)
  • Result markers: 1-0, 0-1, 1/2-1/2, *

Example PGN Structure

[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-0

Advanced PGN Features

Loading with Custom Starting Position

const 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

Error Handling

// 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'
];

Types

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: '*'
};