Skip to content

mik0lajek/chessian

Repository files navigation

Chessian

Import chess games from PGN into beautifully structured Obsidian notes.

Chessian automatically detects chess openings, game outcomes, time variants, and termination reasons—then renders everything into your customizable note templates. No manual metadata entry required.

Table of Contents

Key Features

PGN Import Methods

  • Paste PGN - Directly paste PGN notation into modal
  • Chess.com API - Fetch recent public games by username, then copy PGN or create a note from the selected game
  • Lichess API - Coming soon - Import directly from Lichess

Automatic Metadata Extraction

Chessian enriches raw PGN data with intelligent detection:

Opening Detection

  • Prefers PGN Opening and ECO tags when available
  • Falls back to analyzing move sequences against the complete ECO database (A–E, 4000+ variations)
  • Uses exact move-order matching first, then a conservative transposition fallback for common alternative move orders
  • Extracts:
    • Opening: Full descriptive name (e.g., "Sicilian Defense")
    • Variation: Specific variation branch (e.g., "Najdorf Variation")
    • ECO: Standard classification code (e.g., "B90")
  • Note: PGN headers are treated as the source of truth. Move-based detection is used when those headers are missing.

Opening Detection Disclaimer
Openings are detected using the Lichess open ECO database and move-based analysis. Due to differences in classification methods between platforms, detected openings may not always match those shown on Chess.com or other services.

Linkable Openings

  • Major opening names become wiki-links: [[Sicilian Defense]]
  • Linkable openings are configurable in settings
  • The settings UI builds its opening list from the same ECO data used for opening detection
  • Use the two-column selector to move openings between Selected and Available
  • Search by opening name or ECO code, sort by name or ECO, and restore the default curated selection
  • Only full opening names are linked (no partial matches)

Intelligent Outcome Detection

Automatically infers your game result:

  • Reads your username from settings (Lichess or Chess.com)
  • Compares against PGN player names
  • Converts 1-0, 0-1, 1/2-1/2win, loss, draw
  • Falls back to raw PGN result if username not found
  • Player perspective fields (player, opponent, playerColor, ownElo, opponentElo) are only filled when your configured username matches White or Black

Chess.com Recent Games

  • Uses the public Chess.com archives API; no authentication required
  • Fetches the latest monthly archive for the entered username
  • Shows recent games with date, players, result, and time control
  • Lets you Copy PGN or Use in template to create a note through the existing PGN flow
  • Caches fetched games in memory during the current plugin session to avoid repeated requests for the same username

Time Variant Classification

Infers game type from time control:

  • 0–60 secBullet
  • 61–180 secBlitz
  • 181–600 secRapid
  • 600+ secClassical

Game Links

Automatically extracts or reconstructs:

  • Lichess: https://lichess.org/<gameId>
  • Chess.com: Extracted from PGN tags
  • Fallback: Uses GameId or Link tag if present

Termination Detection

Parses how the game ended:

  • Types: Checkmate, Resignation, Timeout, Stalemate, Repetition, 50-move rule, Insufficient material, Agreement, Abandoned, Fair play violation
  • Multilingual keyword detection (English, Polish)
  • Provides both normalized type + localized label

Date Normalization

  • Converts PGN date format YYYY.MM.DD → Standard YYYY-MM-DD

Custom Templates

Define exactly how your notes look. Three template types:

In settings, each template field includes a Restore default button. The Template variables help button shows the available {{variable}} placeholders without leaving Obsidian.

Note Content (noteTemplate)

# {{white}} vs {{black}}

**Opening:** {{openingBaseLinked}}{{openingVariation}}  
**Variant:** {{variant}} | **ECO:** {{eco}}  
**Result:** {{outcome}} ({{terminationLabel}})

## Moves
{{moves}}

## Analysis
_Add your analysis here..._

Filename (filenameTemplate)

{{date}} - {{white}} vs {{black}}

This creates: 2026-04-14 - Magnus vs Ding.md

Frontmatter (frontmatterTemplate)

---
white: {{white}}
whiteElo: {{whiteElo}}
black: {{black}}
blackElo: {{blackElo}}
eco: {{eco}}
opening: {{opening}}
openingBase: {{openingBase}}
openingBaseLinked: {{openingBaseLinked}}
variant: {{variant}}
outcome: {{outcome}}
termination: {{terminationLabel}}
date: {{date}}
link: {{link}}
---

Missing values in frontmatter are rendered as null so generated YAML stays valid. For example, if the configured username is not a participant in the game, perspective fields can safely render as:

player: null
opponent: null
ownElo: null

Available Template Variables

Variable Type Example
white string "Magnus Carlsen"
whiteElo number "2758"
black string "Ding Liren"
blackElo number "2700"
player string | null "Magnus Carlsen"
opponent string | null "Ding Liren"
ownElo number | null "2758"
opponentElo number | null "2700"
playerColor string | null "white"
result string "1-0"
outcome string "win"
opening string "Sicilian Defense: Najdorf Variation"
openingBase string "Sicilian Defense"
openingBaseLinked string "[[Sicilian Defense]]"
openingVariation string "Najdorf Variation"
openingLinkable boolean "true"
eco string "B90"
variant string "rapid"
date string "2026-04-14"
dateLabel string "2026-04-14"
timeControl string "300+3"
timeControlLabel string "5+3"
platform string "lichess" / "chess.com"
site string "lichess.org"
link string "https://lichess.org/abc123"
gameId string "abc123"
termination string "checkmate"
terminationLabel string "Checkmate"
movesCount number "42"
moves string "1. e4 c5 2. Nf3 d6"
movesList string[] ["e4", "c5", "Nf3", "d6"]
pgn string Full PGN text with headers
rawPgn string Original unprocessed PGN text

The in-app variable helper groups variables into Common, Players and perspective, Game details, Moves, Advanced, and Future API fields. Planned future API placeholders are shown as disabled hints only.

Duplicate Handling

Smart filename generation prevents data loss:

  • First import: Game.md
  • Second: Game-1.md
  • Third: Game-2.md
  • Works across all import methods consistently
  • Generated filenames are sanitized for Obsidian vault paths
  • Missing nested folders in the configured default folder are created automatically

Configuration

Settings

  • Default folder – Where imported notes are created (default: Chess)
  • Language – English or Polish. Applies to settings UI and localized generated labels.
  • Lichess username – For auto-detecting wins/losses in Lichess games
  • Chess.com username - For Chess.com game outcome detection and as the default username in the Chess.com import tab
  • Smart result detection – Toggle automatic win/loss/draw inference
  • Templates – Customize filename, frontmatter, and note body templates; restore defaults when needed
  • Template variables – Open an in-app helper listing all available template placeholders
  • Linkable openings – Choose which detected opening names become Obsidian wiki-links
    • Move openings between Selected and Available with double-click or Enter
    • Filter selected and available openings independently
    • Search/filter by ECO code
    • Sort by opening name or ECO code
    • Restore the curated defaults or clear all opening links

How It Works (Technical Overview)

Chess.com imports fetch recent public games from the latest monthly archive, map the API response into the shared game model, and then reuse the same PGN parsing, enrichment, templating, and file creation flow as pasted PGNs.

1. Parsing

Raw PGN is parsed into components:

  • Player names, ratings, dates
  • PGN tags (ECO, Site, Result, TimeControl, Termination, etc.)
  • Move list (cleaned of annotations and numeric markers)
  • Full PGN text (pgn) and original raw PGN (rawPgn)

2. Opening Detection

A trie-based tree is built from ECO database at plugin load:

root
 ├─ e4
 │  ├─ c5 (Sicilian Defense)
 │  │  ├─ d6 (Sicilian Defense: Open)
 │  │  └─ e6 (Sicilian Defense: French Variation)
 │  └─ e5 (Open Game)
 ...

For each game, Chessian first uses PGN Opening and ECO tags when present. When those tags are missing, moves are traversed through the tree and the deepest exact match is used. If the exact path only finds an early match, a side-aware transposition fallback can prefer a deeper ECO line reached through a common alternative move order.

2.1 Linkable Opening Selection

The settings tab derives a unique list of opening names from the ECO database. Selected openings are saved in plugin settings and used during enrichment to decide whether {{openingBaseLinked}} should render as a wiki-link.

ECO codes are displayed as compact contiguous ranges. Non-contiguous codes remain explicit, for example:

A00, A03, A10-A11

3. Enrichment

Game data is augmented with:

  • Detected opening name + variation + ECO code
  • Wiki-linked opening names based on your selected linkable openings
  • Inferred outcome (win/loss/draw)
  • Inferred variant (bullet/blitz/rapid/classical)
  • Reconstructed game link
  • Normalized termination reason
  • Player perspective only when the configured username matches White or Black
  • Display-friendly fields such as dateLabel, timeControlLabel, and localized termination labels

4. Template Rendering

enrichPGN() output is merged into templates using simple {{variable}} substitution.

Internally, Chessian maps parsed/enriched data into a structured Game model with players, ratings, opening, metadata, moves, and PGN fields. Existing template variables remain backward compatible.

Frontmatter rendering is YAML-safe: missing values and PGN/API ? ratings are rendered as null in frontmatter rather than placeholder text.

5. File Creation

Note is created with smart duplicate prevention to avoid overwrites.

Installation

From Community Plugins

  1. Open Obsidian → Settings → Community plugins → Browse
  2. Search "Chessian"
  3. Install and Enable

Disclaimer This plugin is not yet available in the Obsidian Community Plugins directory.

Manual Installation (Development)

# Clone
git clone https://github.com/mik0lajek/chessian
cd chessian

# Install dependencies
npm install

# Build
npm run build

# Output: main.js, manifest.json

Copy to: <YourVault>/.obsidian/plugins/chessian/

Testing

Run the unit test suite:

npm test

Run tests with coverage:

npm run test:coverage

Quick Start

  1. Set your username in plugin settings (Lichess or Chess.com)
  2. Optionally choose your Language, templates, and linkable openings
  3. Click Chessian icon in ribbon (or open modal)
  4. Paste a PGN manually, or open the Chess.com tab and fetch recent games by username
  5. Select Create note for pasted PGN, or Use in template for a Chess.com game
  6. Note is created in your default folder with all metadata extracted and templated

Example:

Input: [White "Magnus"] [Black "Ding"] [Result "1-0"] ... 1.e4 c5 2.Nf3 ...

Output: 
File: "2026-04-14 - Magnus vs Ding.md"
Content:
---
white: Magnus
black: Ding  
opening: [[Sicilian Defense]]
outcome: win
---

# Magnus vs Ding
Opening: [[Sicilian Defense]] – Najdorf Variation (B90)
Result: win

Roadmap

  • v1.1 - Lichess API integration (direct game import)
  • v1.2 - Additional Chess.com controls and filtering
  • v1.3 - Interactive board rendering (move-by-move visualization)

Known Limitations

  • Board rendering not yet implemented
  • Lichess API is still a placeholder
  • Chess.com import uses only public recent monthly archives and does not support authentication
  • Chess.com game cache is in-memory only and resets when the plugin reloads
  • Template system is basic (no conditionals or filters)
  • Supports online PGNs only (Lichess, Chess.com formats)

Contributing

Found a bug or have an idea? Open an issue on GitHub.

License

MIT (See LICENSE)

About

Tool for turning PGN chess games into structured Obsidian notes with customizable templates, automatic metadata extraction, and interactive move-based board rendering.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages