· Sharp.go Team
Inside the engine: how sharp.go renders 361 stones at 60fps
Five years ago a Go board at 60 frames per second with full 3D inspection was a renderer’s dream. Today it is a renderer’s afternoon. This post is the annotated walkthrough we wish existed when we started — the architecture choices, the dead ends, and the small details that made the difference.
● The Problem
01Why this is hard
Three constraints that shaped the 3D engine we are shipping today.
A Go game is a tree, not a line. At any moment the player can branch into thousands of alternative continuations, each one with its own fantasy of stones on a 19×19 grid. We wanted all three at once: an interactive 3D camera, sub-100ms analysis latency, and a transcript that does not fall over past move 200.
Each one of these is solvable on its own. The trouble is that they all touch the same hot path — the moment a stone hits the board — and they each want a different amount of time.
● Move Encoding
02A 21-byte wire format
Compact, deterministic, replayable across versions.
Every move in sharp.go is a 21-byte payload. We tried JSON, CBOR, and protobuf before settling on a hand-rolled binary. The format is small enough that 400 moves of a real game fit in 8.4 KB — about the size of a compressed JPEG of the board itself.
- 01.
Byte 0 — Color
0x00 for black, 0x01 for white. One byte. No negotiation.
- 02.
Bytes 1–2 — Coordinate
Two little-endian bytes: row (0–18) and column (0–18). 361 valid positions on a 19×19 grid.
- 03.
Bytes 3–6 — Sequence
Unsigned 32-bit move index. Sequential within a game, deterministic across replays.
- 04.
Bytes 7–10 — Wall-clock timestamp
milliseconds since game start. Used for replay scrubbing.
- 05.
Bytes 11–14 — Hash of the position
A 32-bit Zobrist hash. Lets us detect duplicate positions and superko without a full board scan.
- 06.
Bytes 15–20 — Reserved for engine signals
Captured stones, ko marker, pass flag. Reserved for forward compatibility.
"
We did not set out to invent a binary format. We set out to make analysis feel instant, and the byte count turned out to be the easiest constraint to relax last.
"

Move 217 — black plays the lower-side extension. One byte of color, two bytes of coordinate, eighteen bytes of context.
● Rendering Pipeline
03Three passes, one canvas
The order matters more than the cost.
The renderer is a strict three-pass pipeline. We do not sort, blend, or reflect across passes — each pass writes its own texture, then the next pass reads it.
● Tabs
● Design Decisions
04Why we are shipping 3D first
The reasoning behind our first product, not a verdict on 2D.
● Comparison
Engines compared
| ● Feature | sharp.go | 2D clients | Phone apps |
|---|---|---|---|
| 3D board inspection | ✓ | ✗ | ✗ |
| Sub-100ms AI feedback | ✓ | ✗ | ✓ |
| Open transcript format | ✓ | ✓ | ✗ |
| Cooperative review | ✓ | ✗ | ✗ |
| Two-click share links | ✓ | ✗ | ✓ |
| Browser-only mode | ✓ | ✗ | ✗ |
- ✓
Instanced rendering on the entire board
361 instances, one draw call. Anything else was slower.
- ✓
Cached reflections, not real-time
Re-render on camera moves greater than 5°. Players do not notice.
- ✓
Binary move format on disk
Compact, deterministic, replays of games from 2026 still load in 2027.
- ✓
Deep links as first-class URLs
Every position has a stable URL. Sharing a board is a copy-paste, not a screenshot.
● Frequently asked
01 Why does the engine use Zobrist hashing for positions? ▾
Zobrist hashes are O(1) to update on each move (xor the changed bits) and let us detect superko and duplicate positions in a single 32-bit comparison. A full board scan on every move is fine at 19×19 but does not scale to 25×25, which we plan to support.
02 Can I replay a game from a URL on a different device? ▾
Yes. Every game has a stable URL with the move sequence encoded in the path. Open the URL on any device, in any browser, and the replay begins from the same position.
03 Does the AI play at the same level offline? ▾
Yes. The on-device AI runs entirely offline and ships calibrated to a beginner level by default. You can dial it up to a stronger setting in the menu, with no network round-trip needed.
04 Why is the binary move format not documented in the public spec? ▾
Stability. The format is part of our replay compatibility promise. We will publish a stable v1 specification once the 1.0 engine ships. Until then, the format may change between minor versions.
● What's Next
05Roadmap, not promises
Things we are working on now, in order of expected cost.
The next six months are about replay portability. Every game you play should outlive the client that played it.
● Try the engine
Play on the real 3D board
No install. Open the game in your browser, play against a calibrated AI, share the position with one click.
"
The best Go UI is the one that disappears. You look at the board, not at the app.
"