A chess engine with a built-in web UI. Play in your browser, no setup beyond one binary.
Quick Start · Play Now · Internals · Contribute
A ~2400 ELO chess engine written in C++17. Single binary, no dependencies, no internet required. Built-in web UI with drag-and-drop play, clock, move history, and live eval. Connect it to any UCI GUI. Multi-threaded search, Syzygy tablebases, opening book, the works.
Why another chess engine? Most serious engines are CLI-only and require a separate GUI. DriftWood ships one binary that speaks UCI, has a web UI baked in, and has a clean enough codebase to read, learn from, and hack on.
graph TB
subgraph "driftwood (single binary)"
UI["Web UI<br/>chessboard.js + chess.js"]
HTTP["HTTP Server<br/>cpp-httplib"]
UCI["UCI Protocol"]
SEARCH["Searcher<br/>PVS + Lazy SMP"]
EVAL["Evaluation"]
TT["Transposition Table"]
BOOK["Opening Book"]
SYZYGY["Syzygy Tablebases"]
BOARD["Board<br/>bitboards + Zobrist"]
MOVEGEN["Move Generation<br/>magic bitboards"]
end
UI <-->|REST API| HTTP
UCI <--> SEARCH
HTTP --> SEARCH
SEARCH --> EVAL
SEARCH --> TT
SEARCH --> BOOK
SEARCH --> SYZYGY
EVAL --> BOARD
SEARCH --> BOARD
BOARD --> MOVEGEN
style UI fill:#2d3748,stroke:#718096,color:#e2e8f0
style HTTP fill:#2d3748,stroke:#718096,color:#e2e8f0
style UCI fill:#2d3748,stroke:#718096,color:#e2e8f0
style SEARCH fill:#2b6cb0,stroke:#3182ce,color:#fff
style EVAL fill:#2b6cb0,stroke:#3182ce,color:#fff
style TT fill:#2f855a,stroke:#38a169,color:#fff
style BOOK fill:#2f855a,stroke:#38a169,color:#fff
style SYZYGY fill:#2f855a,stroke:#38a169,color:#fff
style BOARD fill:#744210,stroke:#d69e2e,color:#fff
style MOVEGEN fill:#744210,stroke:#d69e2e,color:#fff
git clone https://github.com/akorite/driftwood.git
cd driftwood
cmake -B build -S . -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)
./build/driftwood serveOpen http://localhost:8080, pick a side, play.
| Drag-and-drop with legal move indicators | Clock with 1 / 3 / 10 / 30 minute presets |
| Move history in SAN (click to jump back) | Captured pieces display |
| Live evaluation + depth readout | Board flip (F), new game (N) |
Everything is vendored under web/vendor/. Works fully offline, no CDN, no npm install.
DriftWood is a real chess engine, not a toy. It has the search techniques you'd find in competitive engines, implemented in ~4K lines of readable C++17.
flowchart TD
ID["Iterative Deepening<br/>depth 1, 2, 3, ..."]
AW["Aspiration Window<br/>narrow search first"]
PVS["PVS: Search root move"]
ORDER["Move Ordering<br/>TT hash > MVV-LVA > Killers > History"]
PRUNE{"Pruning checks"}
LMR["LMR: reduce late moves"]
NMP["Null-Move: skip side, search reduced"]
FUTILITY["Futility: prune at frontier"]
RAZOR["Razoring: drop to qsearch"]
EXTEND["Check Extension: +1 ply"]
QS["Quiescence Search<br/>captures only, stand-pat"]
STORE["Store in TT"]
NEXT{"More moves?"}
DEEPER{"time_up?"}
ID --> AW --> PVS --> ORDER --> PRUNE
PRUNE -->|quiet + low depth| LMR
PRUNE -->|non-endgame| NMP
PRUNE -->|frontier, eval < alpha| FUTILITY
PRUNE -->|very low depth| RAZOR
PRUNE -->|in check| EXTEND
LMR --> NEXT
NMP --> NEXT
FUTILITY --> NEXT
RAZOR --> QS --> NEXT
EXTEND --> PVS
NEXT -->|yes| PVS
NEXT -->|no| STORE --> DEEPER
DEEPER -->|no| ID
DEEPER -->|yes| DONE["Return best move"]
style ID fill:#2b6cb0,stroke:#3182ce,color:#fff
style PVS fill:#2b6cb0,stroke:#3182ce,color:#fff
style QS fill:#2b6cb0,stroke:#3182ce,color:#fff
style PRUNE fill:#c53030,stroke:#e53e3e,color:#fff
style LMR fill:#744210,stroke:#d69e2e,color:#fff
style NMP fill:#744210,stroke:#d69e2e,color:#fff
style FUTILITY fill:#744210,stroke:#d69e2e,color:#fff
style RAZOR fill:#744210,stroke:#d69e2e,color:#fff
style EXTEND fill:#2f855a,stroke:#38a169,color:#fff
style STORE fill:#2f855a,stroke:#38a169,color:#fff
- Material + piece-square tables with middlegame/endgame interpolation
- Mobility (N, B, R, Q), king safety (pawn shield, attacker weights)
- Pawn structure: doubled, isolated, passed, backward, candidates
- Knight outposts, bishop pair, rook on 7th, space, threats
- Passed pawn king proximity
flowchart LR
subgraph shared["Shared State"]
TT["Transposition Table<br/>(1-1024 MB)"]
end
subgraph t0["Thread 0"]
H0["History"]
K0["Killers"]
C0["Countermove"]
end
subgraph t1["Thread 1"]
H1["History"]
K1["Killers"]
C1["Countermove"]
end
subgraph tN["Thread N"]
HN["History"]
KN["Killers"]
CN["Countermove"]
end
t0 <-->|read/write| TT
t1 <-->|read/write| TT
tN <-->|read/write| TT
style shared fill:#2f855a,stroke:#38a169,color:#fff
style TT fill:#2b6cb0,stroke:#3182ce,color:#fff
style t0 fill:#2d3748,stroke:#718096,color:#e2e8f0
style t1 fill:#2d3748,stroke:#718096,color:#e2e8f0
style tN fill:#2d3748,stroke:#718096,color:#e2e8f0
Lazy SMP: multiple threads share one transposition table, each with private history/killers/countermover. Thread count configurable via UCI (setoption name Threads value 4).
- Opening book: 321 entries, weighted random selection
- Syzygy tablebases: WDL/DTZ probing for 6-7 man endgames
- Time management: adaptive budgeting per clock tier, depth caps per budget
| Option | Type | Default | Description |
|---|---|---|---|
Hash |
spin | 64 | Transposition table size (MB) |
Threads |
spin | 1 | Search threads |
SyzygyPath |
string | Path to Syzygy tablebase files | |
BookFile |
string | books/driftwood.bin |
Opening book path |
BookMoves |
spin | 12 | Maximum book moves |
The web UI is backed by a simple REST API. Use it to build your own frontends or integrate DriftWood into anything.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/new_game?color=white|black|random |
Start a new game |
| POST | /api/move |
Send a move, get engine reply |
| GET | /api/state?fen=<FEN> |
Legal moves, check/mate status |
| GET | /api/eval?fen=<FEN>&depth=N |
Evaluation with PV line |
./build/driftwood # UCI mode (default)
./build/driftwood serve [port] # Web UI on :8080
./build/driftwood perft 5 # Move generator verification
./build/driftwood bench 12 # Benchmark (nodes/sec)
./build/driftwood selfplay 20 # Engine vs. itselfcd build && ctest --output-on-failure54+ tests covering move generation, evaluation correctness, search tactics, TT behavior, Lazy SMP determinism, and SEE.
cmake -B build -S . -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)Requirements: C++17 (GCC 9+ / Clang 10+ / MSVC 2019+), CMake 3.16+. That's it. No Boost, no external libs. GoogleTest is fetched automatically for the test suite.
Cross-platform:
- Linux / macOS:
gcc/clang - Windows: MSVC or MinGW
Contributions welcome. Bug fixes, evaluation tuning, new pruning ideas, test positions, docs.
See CONTRIBUTING.md for setup, code style, and PR checklist. Open an issue or discussion before large changes.
MIT

