Eco.json
Encyplopedia of Chess Openings (ECO) json data.
Install / Use
/learn @hayatbiralem/Eco.jsonREADME
⚠️ This repository is no longer actively maintained.
Over the past couple of years, @JeffML has become the primary contributor — extending this project with a published npm package, TypeScript utilities, CI/CD publishing, and generated data files that downstream projects now depend on.
All active development lives at JeffML/eco.json. Please use that as your starting point. Thank you, Jeff, for carrying this forward.
@chess-openings/eco.json - Archived
TypeScript utilities for consuming chess opening data from the eco.json data files.
Features
- 🎯 12,000+ chess openings with ECO codes, move sequences, and names (plus aliases)
- 🔍 FEN-based lookup with automatic position-only fallback
- 🌐 On-demand data loading from GitHub (no bundled files)
- 🔄 Opening transitions with next/previous position navigation
- 📦 TypeScript-first with complete type definitions
- 🚀 Zero dependencies (only needs Node.js 18+)
Installation
npm install @chess-openings/eco.json
Quick Start
import { openingBook, findOpening, getFromTos } from "@chess-openings/eco.json";
// Load all openings
const openings = await openingBook();
// Look up an opening by FEN
const opening = findOpening(
openings,
"rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1"
);
console.log(opening?.name); // "King's Pawn Opening"
console.log(opening?.eco); // "B00"
console.log(opening?.moves); // "1. e4"
// Get next and previous positions
const { next, from } = await getFromTos(
"rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1"
);
console.log(next[0]?.name); // "Sicilian Defense"
console.log(from[0]?.name); // "Starting Position"
API Reference
Opening Data
getLatestEcoJson(options)
Downloads opening data from GitHub by ECO category.
import { getLatestEcoJson } from "@chess-openings/eco.json";
// Load specific categories
const data = await getLatestEcoJson({
categories: ["A", "B"],
includeInterpolated: false,
});
// Load everything (default)
const allData = await getLatestEcoJson();
Options:
categories?: EcoCategory[]- Array of 'A', 'B', 'C', 'D', 'E' (default: all)includeInterpolated?: boolean- Include gap-filling variations (default: true)
openingBook()
Returns a merged collection of all openings.
import { openingBook } from "@chess-openings/eco.json";
const openings = await openingBook();
// OpeningCollection: Record<FEN, Opening>
findOpening(openingBook, fen, positionBook?)
Looks up an opening by FEN with automatic position-only fallback.
import {
findOpening,
getPositionBook,
openingBook,
} from "@chess-openings/eco.json";
const openings = await openingBook();
const posBook = getPositionBook(openings);
const opening = findOpening(openings, fen, posBook);
Parameters:
openingBook: OpeningCollection- The opening databasefen: string- FEN string to look uppositionBook?: PositionBook- Optional position-only mapping for fallback
Returns: Opening | undefined
lookupByMoves(chess, openingBook, options?)
Finds an opening by walking backward through move history. Works with any chess library implementing the ChessGameLike interface (chess.js, @chess-pgn/chess-pgn, etc.).
This function tries to find an opening match at the current position. If no match is found, it undoes moves one by one and tries again, allowing it to find the nearest named opening even when the current position has moved beyond standard opening theory.
import { ChessPGN } from "@chess-pgn/chess-pgn";
import {
openingBook,
lookupByMoves,
getPositionBook,
} from "@chess-openings/eco.json";
const chess = new ChessPGN();
chess.loadPgn("1. e4 e5 2. Nf3 Nc6 3. Bb5 a6 4. Ba4 Nf6");
const openings = await openingBook();
const posBook = getPositionBook(openings);
const result = lookupByMoves(chess, openings, { positionBook: posBook });
console.log(result.opening?.name); // "Ruy Lopez"
console.log(result.movesBack); // 0 (exact match at current position)
Parameters:
chess: ChessGameLike- Chess game instance (must havefen(),undo(),load()methods)openingBook: OpeningCollection- The opening databaseoptions?: LookupByMovesOptionsmaxMovesBack?: number- Maximum moves to walk backward (default: 50 plies / move 25)positionBook?: PositionBook- Position book for better matching
Returns: LookupByMovesResult
opening: Opening | undefined- The opening found (or undefined)movesBack: number- Number of moves walked backward (0 = exact match)
ChessGameLike Interface:
Your chess library must implement:
interface ChessGameLike {
fen(): string; // Returns current FEN
undo(): unknown; // Undoes last move (returns truthy on success, falsy/throws when no moves)
load(fen: string): void; // Loads position from FEN
}
Compatible libraries: chess.js, @chess-pgn/chess-pgn, and others with similar APIs.
Example - Position beyond opening theory:
// Many moves deep into a game
chess.loadPgn(
"1. e4 e5 2. Nf3 Nc6 3. Bb5 a6 4. Ba4 Nf6 5. O-O Be7 6. Re1 b5 7. Bb3 d6 8. c3 O-O 9. h3 Na5"
);
const result = lookupByMoves(chess, openings, { maxMovesBack: 10 });
console.log(result.opening?.name); // "Ruy Lopez: Closed"
console.log(result.movesBack); // 3 (walked back 3 moves to find opening)
getPositionBook(openingBook)
Creates a position-only FEN → full FEN array mapping.
import { getPositionBook } from "@chess-openings/eco.json";
const positionBook = getPositionBook(openings);
// Record<string, string[]>
Query Methods
getOpeningsByEco(ecoCode, openings?)
Returns all openings for a specific ECO code.
import { getOpeningsByEco } from "@chess-openings/eco.json";
// Get all Caro-Kann Defense variations
const caroKann = await getOpeningsByEco("B12");
console.log(`Found ${caroKann.length} variations`);
Parameters:
ecoCode: ECO code string (e.g., "B12", "C42")openings: Optional pre-loaded opening collection
Returns: Promise<Opening[]>
getOpeningsByEcoCategory(category, openings?)
Returns all openings for an ECO category (A, B, C, D, or E).
import {
getOpeningsByEcoCategory,
openingBook,
} from "@chess-openings/eco.json";
// Get all semi-open games (category B)
const semiOpen = await getOpeningsByEcoCategory("B");
// More efficient with pre-loaded book
const book = await openingBook();
const catA = await getOpeningsByEcoCategory("A", book);
const catB = await getOpeningsByEcoCategory("B", book);
Parameters:
category: ECO category letter ("A", "B", "C", "D", or "E")openings: Optional pre-loaded opening collection
Returns: Promise<Opening[]>
Throws: Error if category is invalid
getEcoRoots(openings?)
Returns only canonical ECO root variations (where isEcoRoot === true).
import { getEcoRoots } from "@chess-openings/eco.json";
const roots = await getEcoRoots();
console.log(`Found ${Object.keys(roots).length} ECO root variations`);
// Check if a position is an ECO root
const fen = "rnbqkb1r/pppppppp/5n2/8/4P3/8/PPPP1PPP/RNBQKBNR w KQkq - 1 2";
if (roots[fen]) {
console.log(`${roots[fen].name} is an ECO root`);
}
Parameters:
openings: Optional pre-loaded opening collection
Returns: Promise<OpeningCollection> (FEN → Opening mapping)
Transition Data
getFromToIndex()
Downloads pre-indexed transition data from GitHub.
import { getFromToIndex } from "@chess-openings/eco.json";
const index = await getFromToIndex();
// { to: Record<string, string[]>, from: Record<string, string[]> }
getFromTos(fen, openings?)
Gets next and previous opening positions with full Opening objects.
import { getFromTos } from "@chess-openings/eco.json";
const { next, from } = await getFromTos(fen);
// { next: Opening[], from: Opening[] }
Parameters:
fen: string- FEN string to look up transitions foropenings?: OpeningCollection- Optional pre-loaded opening collection
Returns: { next: Opening[], from: Opening[] }
clearFromToCache()
Clears the cached transition index.
import { clearFromToCache } from "@chess-openings/eco.json";
clearFromToCache();
Types
Opening
interface Opening {
name: string; // "Sicilian Defense"
moves: string; // "1. e4 c5"
eco: string; // "B20"
score?: number | null; // Position evaluation
next?: Opening[]; // Next positions
from?: Opening[]; // Previous positions
src?: string; // Data source
isEcoRoot?: boolean; // Root ECO variation
fen?: string; // FEN string
}
OpeningCollection
type OpeningCollection = Record<FEN, Opening>;
PositionBook
type PositionBook = Record<string, string[]>;
FromToIndex
interface FromToIndex {
to: Record
Related Skills
node-connect
353.1kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
111.6kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
353.1kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
353.1kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
