FideLite.ArtFideLite.Art code golf · chess arbiter · bytes · FIDE · 5.2.2 · 6.9 · JavaScript · single file

The world's smallest chess arbiter to enforce every official rule.

The rule engine is 1,527 bytes of plain source. In rule correctness and FIDE compliance it is among the most complete engines anywhere; in function per byte it leads by a wide margin — and that is the claim this project rests on. It is written in JavaScript and runs in the browser: no libraries, no install, no server. The showcase build for the claim is a single 2.4 KB HTML file: every rule, a clickable board and a live clock, running on any device with a browser — the same file you play below and can download.

dcebaecd∅899999999∅800000000∅800000000∅800000000∅800000000∅811111111∅854632645∅8

The entire starting position as the engine's array holds it: 64 hexadecimal digits (base 16, written with 0–9 and a–f), a1 through h8 in order, with an 8-cell gap between ranks. Each digit is one square, and each colour in the strip marks one piece type; a white piece's code is the black one's plus 8. That is the engine's board representation.

Empty 0Pawn 1/9King 2/aQueen 3/bKnight 4/cRook 5/dBishop 6/e

Every square shows four things: its name, the piece's hexadecimal code, its glyph (the piece's Unicode symbol — ♞, ♛), and the index the engine uses.

The index is written in hexadecimal: the high digit is the rank, the low digit the file — a1 00, h8 77. Cells whose low digit is 8–f lie off the board; the faint column on the right shows each rank's eight such cells as one. What this layout buys the engine is covered on the “The engine itself” tab.

~1.5 billion nodes0 deviations
“Perfection is reached not when there is nothing left to add, but when there is nothing left to remove.”Antoine de Saint-Exupéry

Golfstack

The code itself, its worth, and the craft of Golfstack

A complete, tournament-grade chess arbiter fits into a single JavaScript file of 1,527 bytes. As a single playable HTML file it comes to 1.7–2.7 KB (KB is a unit of file size; 1 KB = 1024 bytes), depending on what the interface offers and whether the HTML follows old or modern conventions. FideLite is an engineering exercise in packing the most function into the least space, written the code-golf way — carving away every byte of filler without changing what the program does. Golfstack is what I call that way of working.

In the main builds, two people play each other on the same device. The engine never suggests a move; it arbitrates the game, and it needs no external library to do so.

There are no shortcuts on the rules side. You can see how each article is handled, one by one, on the “Rules and their application” tab. The claim procedure for the 50-move rule and threefold repetition, and the offer–acceptance–lapse cycle of a draw by agreement, work as the handbook describes: a claim can be made on the move about to be played, an offer lapses once the opponent moves without accepting it, and checkmate takes precedence over every automatic draw. When a player resigns or runs out of time in a position where the opponent cannot mate, the result follows the test that 5.1.2 and 6.9 set out. Most major platforms take shortcuts on these articles.

Technical features

  • An interface that feels like a modern website. In the default builds the selected square and its legal destinations are highlighted, a promotion picker pops up, and indicators show check and a pending draw offer; after each move the board turns to face the player to move. The glyphs, the clock symbol and the indicators all come from Unicode — no image files, no web fonts, no requests to an external server. The more minimal builds draw the board in plain text, and some draw no board at all.
  • Fischer time control and a readable clock. In the builds with a clock the default time control is 10+5: ten minutes per player, plus a five-second increment added to the player's time on every move. Both clocks are shown as MINUTES : SECONDS next to their emoji, and you can see the increment being added on every move. The moment a flag falls, the result is declared automatically.
  • Move generation and robustness. The chess logic holds no surprises: an illegal move is never accepted, a legal one is never rejected, and no result code is ever triggered in the wrong position. This rests on measurement — the engine passes the standard chess-programming test suites with zero errors at reasonable depths.
  • Rule accuracy and how games end. When a game ends, the engine does not just say “draw”; it reports which of the fifteen results actually occurred, by name. The codes are only two characters long yet mnemonic — you can tell at a glance what each letter stands for — and all fifteen map one-to-one onto articles in the FIDE handbook. Stalemate, threefold repetition, dead position: nothing is left ambiguous.
  • The hard half of the draw. Some articles in the federations' rulebooks are skipped by most implementations, or reduced to their simplest form; this engine tries to apply them as written. FIDE's well-known Articles 6.9 and 5.2.2 in particular are not skipped but implemented as far as the algorithm could take them. The payoff is concrete: most unfair results are prevented. Details here.
  • A modular structure. The rule layer sits on one side, the interface on the other. Remove the draw offer, the clock or the automatic draw limits and everything else keeps working; the starting position (from a FEN, if you like) and the time control are both configurable. Code-golf chess projects rarely keep this separation: in most of them you can no longer tell where the rules end and the gameplay begins.
  • Readability and mnemonics. The source was written to run, not to be read: single-letter names, one line, inlined functions. Even so, the naming is not arbitrary — wherever the byte budget allowed, each name echoes the English word it stands for. What the code actually does is walked through line by line in a separate section.
  • Speed and depth. Most of an arbiter's work is done within a single ply, but on the hard half of the draw the engine really does look ahead — and it does so during the game, at the moment a flag falls or a player resigns, not just in testing. So speed is not cosmetic. It also matters in testing, where perft (the standard correctness test that counts every move sequence of a given length from a position) counts millions of nodes. The engine's fast variant covers both: the same rules, 117 bytes longer, logically identical. The benchmarks are under a separate heading. And it matters for the bot: the search built on top of the engine calls it again at every node, so the engine's speed sets how deep the bot can look in the same time.
  • The bot is a separate layer. The claim is about function per byte: a bot is not required, and adding one does not break rule equivalence. Builds with a bot fall outside the claim; the reasons are below, and the measurements are on the Builds tab.

The real claim is not any one of these items but the ratio itself: function per byte. The whole rule set sits in a single file — hard as diamond, dense as a black hole. It is also a reflection of my ego, as a craftsman and as an artist. ;)

The engine was tested thousands of times during development, edge cases included, and every known bug was fixed. Even so, I am always open to hardening it further, within my own principles: if you spot a way to shave off one more byte — or, more worryingly, a bug, a crash or a wrong ruling — write to cuneytinan37@gmail.com.

Live exhibit

Pick a build and play

Not one game but an exhibition. The repository holds 36 files you can play straight in the browser, and the variety runs along three axes: in the rules, from a legality-only build to a full FIDE arbiter; in the interface, from a clickable board to UCI notation and blindfold builds that draw no board at all; and among the special builds, all the way to bots, more polished interfaces and builds that mirror the rules of Lichess and Chess.com. The variety takes its cue from the Ship of Theseus: it is there so that the line between full chess and something less can be argued over and thought about. That is also why I call the generator that adds and removes rules on the fly Chesseus!

Each build runs in its own frame, and the clocks only start ticking once you start the game. Switching builds ends the current game.

Pick a rule level first, then a build. In each level the first build, default, is that level's main file. L3 is the full arbiter: the rule layer is identical in all of its builds; what changes is how you enter a move, how the board is drawn and which indicators are shown. L1 and L2 are the lower rule levels; both are outside the claim. special is a layer of its own: builds that fit none of these levels, most of them derived from them, some at odds with the project's own principles. The details are in the Special builds section at the end of the Builds tab. nonbrowser in L1, L2 and L3 is a terminal build: it does not run in a browser, so it cannot be played here, but you can view its code, or download it and run it with node.

If the board feels small in the builds that draw one, use the browser's zoom — Ctrl +, or ⌘ + on macOS; Ctrl 0 (⌘ 0 on macOS) resets it. In the builds that open a prompt() dialog, nothing will appear if your browser blocks dialogs; download the file and open it locally, or allow dialogs.

Level
Build

Selected build L3. Start the game or show its code.

Ready

The story

Carving the marble — a chess universe fitted into bytes

Code golf is the art of writing a program in as few bytes as possible without giving up any of its functionality, its rules or its logical correctness. There is one constraint: the behaviour stays the same, the size shrinks.

From beginning to end this project chased a single question:

How few bytes can a complete, 100% FIDE-compliant game of chess fit into, skipping no rule from the first move to the last?

The answer is below. But to ask the question at all, I first had to decide what counts as “complete”.

What can you remove and still have chess? (the Chesseus problem)

Writing the engine, I found myself in the middle of the Ship of Theseus paradox: what can you strip out of a game of chess and still be left with chess?

An unavoidable question of identity surfaces here. I did not take medieval chess as my starting point — in that game the bishop leaps exactly two squares diagonally, the queen's ancestor moves one square diagonally, and neither castling nor the pawn's double step is yet established. The two share a name, but they are fundamentally different games; taking the older one as the baseline would have meant answering the question for another game.

What I took as the starting point was this: today's piece movement (without castling), check, checkmate and stalemate, the pawn's single-square advance, and automatic promotion to a queen. That is the core left once everything removable has been removed. Take away one more article and the game stops being chess.

With the core in hand, there was only one direction left: adding.

From core to full arbitration

The engine was not built in one go; it grew in overlapping rounds.

Underpromotion came first: the pawn was no longer condemned to become a queen, and the knight, bishop and rook became options too. Then the pawn's double step, and with it en passant, which has to come along — the two are inseparable, because the second closes the loophole the first opens. Then castling. At that point, everything on the board was chess as we play it today.

After that I moved off the board. In theory the move counter keeps a game from running forever, in practice the clock does; both entered the engine at this stage.

Normally I would have stopped there. But having come this far I wanted to finish the rest of the rulebook: repetition, insufficient material, draw offers and draw claims, flag fall, resignation. That also brought in the rulings that arise not from moves on the board but from the players and the clock.

The path was far from a straight line. Again and again I had to go back after noticing that a rule I had already added did not match FIDE exactly, or behaved wrongly in a particular position. Sometimes a new discovery forced me to scrap the whole solution I had written up to that point. Every reversal meant a structural rewrite followed by another round of byte optimisation; the code grew, then shrank again.

It was a long and instructive process, on both the coding and the chess-logic side. The turning points I ran into along the way — which rule broke what, which discovery forced a rewrite of what — are set out on the Technical detail tab.

Where the carving stops

Asked how he made his sculptures, Michelangelo is famously said to have answered:

The sculpture is already complete inside the block of marble. I merely carve away the parts that are not needed.Michelangelo

That is what I did in Golfstack. The rules were a given from the outset; the work was carving away everything superfluous in the code that expressed them.

The name for where that carving ends is Kolmogorov complexity: the length of the shortest program that can produce a given object. Code golf is precisely a walk toward that bound — and the bound is provably uncomputable, so no one can tell you in advance where to stop. You find your way by measuring. The added constraint here is that the carving has to be lossless: drop a single article from the logic the rules require, and what remains is not a smaller chess but a lesser one.

The answer to the question is therefore a single number: 1,527 bytes. engine.js arbitrates an official game between two human players from the first move to the last; bundled with a front end into a single playable file, it comes to between 1,715 and 2,744 bytes, depending on the interface and on whether the HTML follows old or modern conventions.

Why the browser, and why JavaScript

One of the first questions that comes up is this: why the browser, why JavaScript?

The first half of the answer is about reach. Measured by how many devices, operating systems and environments it opens on, the browser wins by a wide margin. No compiler, no runtime to install, no package manager; double-clicking the downloaded file is enough. On top of that, HTML gives you the visual layer almost for free: the board, the clocks and the indicators need no separate UI framework, and the file opens even if <html>, <head> and <body> are omitted entirely. If the engine had any further to go to reach a player, the size claim would mean nothing in practice.

The second half is about the language itself. JavaScript suits Golfstack far better than you might expect: it needs no variable-declaration keyword, imposes no boilerplate of entry point and imports, and implicit type coercion means the board's numeric encoding never forces an explicit cast. Arrow functions, the ternary operator and the comma operator together let an entire function collapse into a single expression with no braces and no return. JavaScript also lends itself naturally to self-extracting packers; the engine's packed build relies directly on that.

The obvious objection: the browser weighs hundreds of megabytes and supplies both the JavaScript engine and the runtime. Isn't 1,527 bytes just a sleight of hand, then?

There is no such thing as a zero baseline. Written in C it would need libc and an operating system; written in assembly, an instruction set and a machine. A measure that also counts the runtime has nowhere to stop; measured that way, no size claim could be made in any language. Code golf therefore always draws the line in the same place: the code you write and the libraries you pull in count; the environment and the baseline do not. Neither the browser, the operating system nor the processor counts toward the total. Cross-language comparisons use this measure, and record attempts are open to any language.

Those who take the end user's view and want a stricter measure have a point too: same environment, same language, zero libraries. Both are legitimate, and a single file passes both — no library downloaded, bundled in or added.

The “smallest in the world” claim rests on both measures. I have searched for quite a while and have not found anything smaller that enforces every official rule, in JavaScript or any other language. The claim is falsifiable, and it should be: it falls the moment someone ships something smaller. Until then it stands.

The rule layer is one thing, the bot another

The second question is harder: there are builds with a bot right here on this page, so why does the claim leave them out entirely?

The usual route is well known: draw a board, set up the pieces, and let the player take on a bot that plays a little better than random; most attempts so far have followed that path. The code-golf world has chess bots squeezed into a few hundred bytes, but to make room they give up almost every rule that forms the backbone of the game — castling, en passant, the 50-move rule, threefold repetition. Bot logic bloats the code considerably; a two-player build is far cheaper on the byte budget. And adding a bot contributes nothing to FIDE compliance.

The real issue is measurability. What counts as a bot is vague: is a sub-100-byte program that plays random legal moves a bot? Is one that counts material a bot, or is the bar higher? Who decides? Rules are not like that; they are exact. Whether a piece of code implements an article can be verified by inspection, with no room for argument. Even where coverage falls short, the measure stays exact: every draw the engine declares is a real one (soundness), while some real draws are missed (completeness) — and the misses come to roughly one game in 2.2 million in real-world play; a missed draw can change the result only at a flag fall or a resignation. For a few articles, pushing coverage to 100% is hard, but even that is a precise target whose gain per byte can be calculated; a bot has no such definition. I did try writing a bot along the way; then I put all my energy into the side that can be measured.

The two are kept apart in the code as well, and that is by design. The engine core knows nothing about the driver, so layering a search on top of it, or intertwining the two, does not break rule equivalence. That is exactly how the bot builds on this engine came about: the same rules, minus the clock and the player-to-player interactions, with a search on top. I do not consider that side finished: before a bot can be included in the claim, it has to clear the same bar the arbiter did — it has to be a masterpiece in its ratio of quality to bytes. That is a longer job, but since it is a hobby I enjoy a great deal, I will make a serious attempt at a record on that side too.

Here is what the measurable side has bought: on the hard half of the draw, this engine is far ahead of the major platforms. I will go on record here — even the strictest of them stop at the material test (is there enough left on the board to mate with?) rather than follow the rulebook to the letter. Looking at the position itself — whether a mate can still be constructed once the flag has fallen, and detecting blocked positions — is rare. And this has been measured: Miguel Ambrona's CHA-Solver found 204,060 wrongly decided games in the Lichess open database, and this engine rules more than 98% of them correctly. Some platforms make deliberate choices, such as Chess.com's blend of FIDE and USCF; the choice here is a different one: one rulebook, one standard.

Beyond the bytes

Code-golf chess projects usually cut corners on the 50-move rule, threefold repetition and insufficient material — often on castling and en passant too — and focus on the bare core alone. I went where hardly anyone goes, and I think that is exactly where the project's originality comes from. As far as I know, no arbiter engine anywhere fits the whole FIDE rulebook into fewer bytes than FideLite — and it carries a blocked-position detector I have not come across on any major platform.

It is not a commercial product and does not pretend to be. But layering every rule of chess this way and fitting them into as few bytes as possible is pure engineering — pushing the limits on the code side.

I had substantial help getting here from AI models such as Claude and Gemini. Those tools dramatically compressed work that would normally take months: debugging, code optimisation, untangling browser quirks. The decisions stayed mine; what I gained was speed.

In a letter to his brother, Chekhov called brevity the sister of talent. In this project I tried to reduce the vast world of chess to its shortest form without losing any of its function.

FideLite — what the name and the logo mean

The FideLite logo: on a grid five squares wide, the piece moves leading out of the centre square are marked in colour The FideLite logo: on a grid five squares wide, the piece moves leading out of the centre square are marked in colour

The name has two parts: FIDE + Lite. Together they echo the French fidélité — fidelity, adherence. That is precisely the point: the file shrinks, its adherence to the rulebook does not. “Lite” stands for lightness, “Fide” for the federation; together, an arbiter that drops no article for the sake of being light.

The logo is built around a single square. The square at the centre is the origin; the remaining twenty-four squares are where pieces moving from that square can go.

  • Origin — the single square at the centre
  • Knight — eight neutral squares, the L-shaped jumps
  • Rook — eight turquoise squares, four straight rays
  • Bishop — eight lilac squares, four diagonal rays
  • Queen — every rook and bishop square
  • King — the maroonyellow frame, a one-step range
  • Pawn — the square its single-step advance lands on: the FIDElite wordmark