Skip to main content

Visualise PGN chess games as interactive trees; convert PGN to JSON, EDN, GraphViz DOT and HTML

Project description

chesstree

CI

A command-line tool for converting chess games between PGN, JSON, EDN, GraphViz DOT, and interactive HTML formats. It accepts PGN or chesstree JSON as input (auto-detected from the file extension) and can output JSON, EDN, PGN, DOT, dothtml, or d3html via the -f/--format flag. JSON output includes move number, SAN and UCI notation, FEN positions, comments, NAGs, and variations. DOT output models the game tree as a left-to-right digraph suitable for rendering with GraphViz tools. The dothtml format wraps the DOT graph in a self-contained browser viewer powered by d3-graphviz, with pan, zoom, and board images included. The d3html format produces a purpose-built interactive D3.js tree viewer with collapsible nodes, variation highlighting, optional hover board images, and a dark-themed layout — no GraphViz dependency required.

As a taster how the d3html format looks and works see here.

▶ See d3html output — interactive D3.js tree viewer for full details.

Output format

The tool produces a JSON (or EDN) object with four top-level keys: schema_version, headers, moves, and result. Each move entry carries SAN/UCI notation, FEN positions before and after, and optional annotations (comments, NAGs, clock, eval, arrows). Variations appear inline as { "variation": [ ... ], "branch_fen": "<FEN>" } entries.

For the full normative specification — required vs optional fields, exact types, variation placement rules, NAG encoding, comment normalization, fidelity guarantees, and versioning contract — see docs/schema.md.


Installation

Requires Python 3.9 or later.

From PyPI

pip install chesstree

Or with pipx for an isolated environment (recommended for CLI tools):

pipx install chesstree

The chesstree command is added to your PATH automatically.

From source (for development)

git clone https://github.com/benedekfazekas/chesstree
cd chesstree

python3 -m venv .venv
source .venv/bin/activate        # on Windows: .venv\Scripts\activate

pip install -e ".[dev]"

See the Development environment section below for full setup details.


Usage

usage: chesstree [-h] [--version] -i INPUT [-o OUTPUT] [-f {json,edn,pgn,dot,dothtml,d3html}]
                 [--input-format {pgn,json}] [-b] [--images MODE [MODE ...]]
                 [--template FILE] [-a] [--no-move-highlight] [-c]

options:
  -h, --help                                     show this help message and exit
  --version                                      show program's version number and exit
  -i, --input INPUT                              Input file — PGN or chesstree JSON (use '-' for stdin)
  -o, --output OUTPUT                            Output file (default: stdout)
  -f, --format {json,edn,pgn,dot,dothtml,d3html} Output format: json (default), edn, pgn, dot, dothtml, or d3html
  --input-format {pgn,json}                      Override auto-detected input format
  -b, --forblack                                 Board images from Black's perspective (dot/dothtml/d3html)
  --images MODE [MODE ...]                       Image generation mode for dot/dothtml/d3html output (default: variations)
                                                 Choices: none, all, variations, commented.
                                                 'variations' and 'commented' may be combined.
                                                 SVG files are written alongside the output file;
                                                 stdout skips writing SVGs.
                                                 Has no effect on json/edn output.
  --template FILE                                Custom HTML template for dothtml or d3html output.
                                                 Must contain the required placeholders for the chosen format.
                                                 Only used with -f dothtml or -f d3html.
  -a, --hover-for-all-moves                      Embed per-move hover board images (d3html only).
                                                 Mouseover a move to see the board position in a popup.
  --no-move-highlight                            Disable last-move square highlighting on board images.
                                                 By default the from/to squares of the last move are
                                                 coloured on every board image (dot/dothtml/d3html).
  -c, --concise                                  Compact output, no pretty-printing (json/edn output only)

The input format is auto-detected from the file extension (.pgn → PGN, .json → chesstree JSON). Use --input-format to override this when reading from stdin or a file with an unusual extension.

Supported conversions:

Input -f / --format Output
PGN json (default) chesstree JSON
PGN edn chesstree EDN
PGN dot GraphViz DOT
PGN dothtml Self-contained d3-graphviz HTML viewer
PGN d3html Self-contained D3.js interactive tree viewer
JSON pgn PGN
JSON dot GraphViz DOT
JSON dothtml Self-contained d3-graphviz HTML viewer
JSON d3html Self-contained D3.js interactive tree viewer

Examples

Convert a PGN file to JSON:

chesstree -i game.pgn -o game.json

Convert a PGN file to EDN:

chesstree -i game.pgn -f edn -o game.edn

Print compact JSON to stdout:

cat game.pgn | chesstree -i - -c

Generate board images from Black's perspective (dot/dothtml output):

chesstree -i game.pgn -f dot -o game.dot -b

Board image modes

The --images flag controls which segment nodes carry an SVG image row in DOT/dothtml output. It has no effect on JSON/EDN output (which never contains embedded images — use the fen_after field to generate board visuals with any chess library). The following modes are available:

Mode Description
variations (default) Images at the last move of each line segment — see below
all Every move gets an image
commented Only moves that carry a comment get an image
none No images at all (smallest output)

variations and commented can be combined: --images variations commented.

The variations mode in detail

A chess game tree is naturally divided into segments — runs of moves along a single line until the game ends or the tree branches. The variations mode places one image at the last move of each segment:

  • End of a line (no further moves) — the final move of the main line or of any variation always gets an image.
  • Branch point — when a position has multiple continuations (e.g. a main move and one or more alternative variations), the first continuation (the main-line choice at that fork) is the last move of the current segment and gets an image. The alternatives each start their own segment and follow the same rule recursively.

This means images appear at the moments of decision — exactly where a reader is most likely to want to visualise the board — while keeping the output compact compared to all.

Generate images only at variation endpoints (default, dot/dothtml only):

chesstree -i game.pgn -f dot -o game.dot --images variations

Generate images for every move:

chesstree -i game.pgn -f dot -o game.dot --images all

Generate images only at commented moves:

chesstree -i game.pgn -f dot -o game.dot --images commented

Generate images at both variation endpoints and commented moves:

chesstree -i game.pgn -f dot -o game.dot --images variations commented

Omit all board images:

chesstree -i game.pgn -f dot -o game.dot --images none

Last-move square highlighting

By default, board images colour the from and to squares of the last move, making it easy to see which piece moved. This applies to all image-bearing formats: dot, dothtml, and d3html.

Use --no-move-highlight to produce plain boards without any square colouring:

chesstree -i game.pgn -f dothtml -o game.html --no-move-highlight
chesstree -i game.pgn -f d3html  -o game.html --no-move-highlight
chesstree -i game.pgn -f dot     -o game.dot  --no-move-highlight

Convert a chesstree JSON file back to PGN:

chesstree -i game.json -f pgn -o game_restored.pgn

Export a PGN game to a GraphViz DOT file for visualisation:

chesstree -i game.pgn -f dot -o game.dot

Render the DOT file to SVG using GraphViz:

dot -Tsvg game.dot -o game.svg

Export from chesstree JSON to DOT:

chesstree -i game.json -f dot -o game.dot

dothtml output — d3-graphviz browser viewer

The dothtml format produces a self-contained HTML file that renders the game tree interactively in a browser using d3-graphviz. Board images are written as SVG files alongside the HTML file, which the browser loads by relative path.

# Generate HTML viewer + SVG images in ./output/
chesstree -i game.pgn -f dothtml -o output/game.html

# Open in browser
open output/game.html

The viewer includes a layout-engine selector (Dot, Circo, Fdp, …) and supports pan and zoom.

When writing to stdout, image references are included in the HTML but no SVG files are written:

chesstree -i game.pgn -f dothtml -o -

Custom HTML template (dothtml)

You can supply your own template with --template:

chesstree -i game.pgn -f dothtml --template my_template.html -o game.html

The template is plain HTML with three required placeholders:

Placeholder Replaced with
{{CHESSTREE_TITLE}} Game title string (e.g. "White vs Black at 2024.01.01")
{{CHESSTREE_IMAGES}} One .addImage("./name.svg", "144px", "144px") call per image
{{CHESSTREE_DOT}} The raw DOT string — place inside a JS backtick template literal

All three must be present or generation fails with an error listing the missing ones.


d3html output — interactive D3.js tree viewer

The d3html format produces a self-contained HTML file with a purpose-built interactive tree viewer powered by D3.js v7. Unlike dothtml it does not require GraphViz: the layout and rendering are done entirely in the browser.

# Generate HTML viewer + SVG board images in ./output/
chesstree -i game.pgn -f d3html -o output/game.html

# Open in browser
open output/game.html

Features of the viewer:

  • Tree view (default) — a full interactive tree layout:
    • Dark theme with colour-coded nodes: main-line segments (blue) are visually distinct from variation segments (purple).
    • Node headers show the line type and move range, e.g. "Main line: 1–12" or "Variation: 8–10".
    • Collapsible nodes — click any node to hide its variation children while keeping the main-line continuation visible. A badge in the header shows how many nodes are hidden. Ctrl+click collapses all children including the main-line continuation.
    • Pan and zoom via scroll and drag.
    • Drag-to-reposition individual nodes.
    • Hover board images (optional, see -a below).
    • R key / ↺ Reset button restores the automatic layout.
  • Deck view — a sequential card-by-card navigator (toggle with the 📇 Deck button):
    • Step through game info and main-line segments one card at a time with ← → arrow keys or on-screen buttons.
    • When a card has variations, clickable buttons appear below showing each variation's first move and optional comment (mirroring the tree's edge labels).
    • Click a variation button to enter it; use ← → to step between sibling variations at the same branch point. Sub-variations are accessible the same way.
    • A breadcrumb trail shows your position in the tree and lets you jump back to any ancestor level. Press Escape to go up one level.
  • Cross-view navigation — double-click any node in the tree to open it directly in the deck view (with a zoom animation); double-click a deck card to jump back to the tree view centered on that node.
  • Light/dark theme toggle applies to both views.

Board images in d3html

The --images flag works the same as for dot/dothtml:

# Default: one image per segment endpoint
chesstree -i game.pgn -f d3html -o game.html

# Images at both variation endpoints and commented moves
chesstree -i game.pgn -f d3html -o game.html --images variations commented

# No images (smallest output)
chesstree -i game.pgn -f d3html -o game.html --images none

SVG files are written alongside the HTML file. When writing to stdout, image references are included but no SVG files are written.

Hover board images (-a)

The -a / --hover-for-all-moves flag embeds a miniature board image for every individual move. Hovering over any move token in the tree shows the board position at that move in a popup:

chesstree -i game.pgn -f d3html -o game.html -a

This significantly increases file size (one small SVG per move) so it is off by default.

Custom HTML template (d3html)

chesstree -i game.pgn -f d3html --template my_d3_template.html -o game.html

The d3html template has four required placeholders (different from the dothtml placeholders):

Placeholder Replaced with
{{CHESSTREE_TITLE}} Game title string
{{CHESSTREE_TREE_DATA}} JSON tree data object (embed inside JSON.parse(\...`)`)
{{CHESSTREE_IMAGES}} JS statements that populate the boardImages dict, one per SVG file
{{CHESSTREE_HOVER_DATA}} JS statements that populate the hoverImages dict (empty when -a not used)

All four must be present or generation fails.

DOT output and board images

The --images flag applies to DOT output as well as JSON/EDN. When writing to a file, chesstree generates SVG board images and saves them in the same directory as the .dot file. GraphViz then loads the images by path when rendering the DOT:

# Write game.dot and all SVG images into ./output/
chesstree -i game.pgn -f dot --images variations commented -o output/game.dot
dot -Tsvg output/game.dot -o output/game.svg

When writing to stdout (or with -o -), image references are included in the DOT syntax but no SVG files are written — useful for piping the DOT string while skipping heavy image generation:

chesstree -i game.pgn -f dot -o - | dot -Tsvg -o game.svg   # no SVGs written

To omit images entirely from DOT output:

chesstree -i game.pgn -f dot --images none -o game.dot

Round-trip a game through JSON:

chesstree -i game.pgn -o game.json
chesstree -i game.json -f pgn -o game_restored.pgn

Versioning

chesstree uses two independent version numbers:

Version Scheme Where Bumped when
Tool version CalVer YYYY.N pyproject.toml, --version output Any release
Schema version SemVer schema_version field in JSON/EDN output Schema changes only

Running chesstree --version shows both:

chesstree 2026.1 (schema 1.2.0)

The two versions are independent: a tool release that fixes a bug or adds a new output format does not change the schema version. See docs/schema.md for the full schema compatibility contract.


Credits

chesstree is built heavily on top of python-chess by Niklas Fiekas. python-chess provides PGN parsing, board state management, FEN generation, NAG handling, and SVG board rendering — the core of what makes chesstree work.


Development environment

Setup

git clone https://github.com/benedekfazekas/chesstree
cd chesstree

python3 -m venv .venv
source .venv/bin/activate        # on Windows: .venv\Scripts\activate

pip install -e ".[dev]"

The -e flag installs the package in editable mode: changes to the source files under chesstree/ take effect immediately without reinstalling.

Running tests

pytest

With coverage:

pytest --cov=chesstree --cov-report=term-missing

Using the CLI during development

Because the package is installed in editable mode, you can run chesstree directly from the terminal (with the virtual environment active) and your latest source changes are picked up immediately:

chesstree -i path/to/game.pgn -o /tmp/out.json

Alternatively, you can invoke the module directly without installing:

python -m chesstree.cli -i path/to/game.pgn

AI assisted development

The project is developed in a supervised AI development manner where I try to keep a close eye on design choices, read and review the generated code, test the output manually etc.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

chesstree-2026.1.tar.gz (69.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

chesstree-2026.1-py3-none-any.whl (74.0 kB view details)

Uploaded Python 3

File details

Details for the file chesstree-2026.1.tar.gz.

File metadata

  • Download URL: chesstree-2026.1.tar.gz
  • Upload date:
  • Size: 69.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for chesstree-2026.1.tar.gz
Algorithm Hash digest
SHA256 af81185b64f2289fee2722490428b1a04cad0dd8ec1a16f7f9eec1185b68cf84
MD5 1f0342ddc23682e357adee9cbbe624a2
BLAKE2b-256 cbc4037b4f33e054a96fe2a6b6a11db6dcc42e1b9360de4f2444f5482e4debff

See more details on using hashes here.

Provenance

The following attestation bundles were made for chesstree-2026.1.tar.gz:

Publisher: publish.yml on benedekfazekas/chesstree

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chesstree-2026.1-py3-none-any.whl.

File metadata

  • Download URL: chesstree-2026.1-py3-none-any.whl
  • Upload date:
  • Size: 74.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for chesstree-2026.1-py3-none-any.whl
Algorithm Hash digest
SHA256 1b17f2e7e2b46b1bd29cc4f68c0ecbd02dcc9aac532383b0b638ea02b6f896da
MD5 e71ca63437da40460a86ff838ab276f5
BLAKE2b-256 5926117d9e10a0f125f0c941442d13fb1bd4dfc3ffc69f9cb60b710803411091

See more details on using hashes here.

Provenance

The following attestation bundles were made for chesstree-2026.1-py3-none-any.whl:

Publisher: publish.yml on benedekfazekas/chesstree

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page