Built-in trackers
gameTracker, pieceTracker, and tileTracker — what they count and what their state looks like.
Chessalyzer ships with three ready-made trackers. All examples below run on the three-game games.pgn from the quickstart, and every output block is the real thing — paste the code, and you'll see the same numbers.
gameTracker — results and openings
The simplest of the three: it reads each game's headers and result, and counts. It needs headers, which Chessalyzer parses automatically as soon as a game tracker is attached.
import { analyzePGN } from 'chessalyzer';
import { gameTracker } from 'chessalyzer/trackers';
const games = gameTracker();
await analyzePGN('games.pgn', { trackers: [games] });
console.log(games.state);{
results: { white: 1, black: 1, draw: 1 },
gameCount: 3,
eco: { A02: 1, B20: 1, C23: 1 },
}| Field | What it counts |
|---|---|
results | Wins by white, wins by black, draws |
gameCount | Games processed |
eco | Games per ECO opening code |
pieceTracker — who captures whom
A capture matrix: for every starting piece, how often it captured each opposing piece. Pieces are named by their starting square — Qd is the queen, Pe the king's pawn, Nb the knight that began on the b-file — and each color gets its own table under w and b.
import { analyzePGN } from 'chessalyzer';
import { pieceTracker } from 'chessalyzer/trackers';
const pieces = pieceTracker();
await analyzePGN('games.pgn', { trackers: [pieces] });
console.log(pieces.state.w.Qd.Pf); // 1 — white's queen captured black's f-pawnOur file only has three captures, so the (large, mostly zero) state boils down to:
{
w: {
Qd: { Pf: 1 }, // game 1: Qxf7 — the scholar's mate
Bf: { Bc: 1 }, // game 3: Bxd7 — bishop takes bishop
},
b: {
Qd: { Bf: 1 }, // game 3: Qxd7 — black's queen strikes back
},
}tileTracker — the life of every square
The workhorse. For each of the 64 squares it records, per color and per piece:
movedTo— how often a piece moved to this squareoccupiedFor— how many half-moves a piece sat on this squarecaptures— captures that happened on this squarelosses— pieces that were captured on this square
import { analyzePGN } from 'chessalyzer';
import { tileTracker } from 'chessalyzer/trackers';
const tiles = tileTracker();
await analyzePGN('games.pgn', { trackers: [tiles] });
console.log(tiles.state.movesTotal); // 19
console.log(tiles.state.squares['f7']);State is keyed by algebraic square — tiles.state.squares['f7'] is the f7 report. And f7 turns out to be the most dramatic square in our file — the scholar's mate happened right there:
{
w: {
total: { movedTo: 1, occupiedFor: 0, captures: 1, losses: 0 },
byPiece: {
Qd: { movedTo: 1, occupiedFor: 0, captures: 1, losses: 0 },
// …15 more white pieces, all zero
},
},
b: {
total: { movedTo: 0, occupiedFor: 18, captures: 0, losses: 1 },
byPiece: {
Pf: { movedTo: 0, occupiedFor: 18, captures: 0, losses: 1 },
// …15 more black pieces, all zero
},
},
}Reading it: black's f-pawn (Pf) never moved and defended f7 for 18 half-moves across the games, until white's queen (Qd) took it — once, and checkmate.
total combines all pieces of one color; byPiece breaks it down. You'll usually read state through heatmap presets rather than by hand — both tileTracker and pieceTracker states plug straight into generateHeatmap.