Built in mChatAI #2: How "a real chess engine, not random moves" became Speed Chess

Built in mChatAI #2: How "a real chess engine, not random moves" became Speed Chess

This is the second entry in Built in mChatAI, the series where I walk through something I built with the app and show my work. The first post was Sunset Glider — a hand-rolled canvas game with no framework underneath it. This one is the opposite pole. Speed Chess leans hard on reusable game-engine parts from an open registry, and a cheap model did the assembling.

Speed Chess — a mobile-first blitz board, White's clock ticking at 4:47, the board as the hero

It started with a demanding one-liner: I didn't want a toy that shuffled pieces around. I wanted a real opponent. Here's the origin ask, word for word:

Chess versus the computer with an Easy / Medium / Hard difficulty selector. The computer opponent MUST use a real chess engine (minimax with piece-square evaluation) that defends its pieces and does not give away material — not random moves. Easy = shallow search, Hard = deeper search.

That build installed cleanly. Out of it came a working chess-vs-computer with three difficulty levels — an opponent that actually searches for moves and doesn't hang its queen. That build became the base every later version iterated on.

Where the engine actually came from

Here's the part I want to be honest about, because it's the interesting part.

The model did not write a minimax chess engine from scratch. The chess rules and the search AI come from reusable components — we call them "Lego" — that live in the open mchatai-source registry, which is public on GitHub. What the model did was assemble and wire together the right registry parts into a working game, and then iterate on it one focused edit at a time.

The pieces it pulled in and inlined:

That's the real story of Speed Chess: the platform supplies a correct chess engine as Lego, and a small model composes it into a playable game and customizes it. Contrast that with Sunset Glider, which was written by hand against a bare canvas with no framework at all. Same app, two completely different build styles — and both are legitimate. Sometimes you want the model to write everything; sometimes you want it to stand on parts that are already correct.

For the record, this is a real chess implementation, not a facade. Reading the final file: per-piece pseudo-legal move generation, then filtered so you can't make a move that leaves your own king in check (_wouldLeaveKingInCheck, isKingInCheck), plus checkmate and stalemate detection and castling. The AI is genuine negamax with alpha-beta pruning (if (alpha >= beta) break) over a material + piece-square evaluation, with search depth scaling by difficulty: 2 plies on Easy, 3 on Medium, 4 on Hard.

The three change-requests

After the base build, the game grew through three focused change-requests. Each one is a recorded ask — the harness wraps every request with a short "write-first, preserve what works, stay offline" preamble, but the substance is below, verbatim.

v2 — castling notation:

Castling now works in the chess engine. Make ONE improvement: in the move-history list, show a castling move as "O-O" for kingside or "O-O-O" for queenside, instead of a plain king move.

Small, but it's the kind of correctness detail that makes a chess move list feel right. Kingside castling now reads O-O, queenside reads O-O-O.

v3 — the speed clock (this is the one that made it "Speed Chess"):

add a SPEED-CHESS clock. (1) Two countdown clocks, White and Black, shown near the board in mm:ss. (2) The side-to-move clock ticks down 1s/second; on each move, stop your clock and start the opponent's. (3) At 0:00 that side LOSES ON TIME — end the game, show "White wins on time" / "Black wins on time". (4) A time picker with 1 / 3 / 5 / 10 minute buttons (default 5).

This is the turning point. Two whiteTime/blackTime countdowns, shown mm:ss, ticking via setInterval, that flag the game at zero. A blitz clock turned a chess app into a speed chess app.

v4 — mobile-first, board-as-hero (the ask had four numbered items; I've quoted items 1, 2, and 4 as recorded — item 3 in the original list isn't reproduced here):

make this look great on a phone by making the chess board the hero and shrinking the surrounding chrome... 1. Compact the clocks into a single slim row of two small clocks. 2. Fold Difficulty, Play-as, and the Time control into a compact collapsible "Settings" panel that is CLOSED by default. 4. Make the board the hero: maximize board size to fill the width on mobile, keep squares and pieces large and easily tappable (~44px+ touch targets).

This is the version you'd recognize as the published one: a slim two-clock row, a collapsed Settings panel, and a big tappable board that fills the screen.

An honest note on v5

The published build is internally "v5," and I don't want to oversell it. v5 added no new player-facing feature. A code diff shows it was an engine-hardening / robustness pass — it added fallback evaluation and move-generation helpers — and then it got published as "Speed Chess."

So the real feature arc is: engine origin → castling notation → speed clock → mobile-first, shipped as v5. There's no secret v5 feature. It was a stabilize-and-ship step.

Run facts

For the people who like the receipts:

What the platform did around all this

mChatAI+ is a native macOS app, and its builder — AIWizard — turns a plain-English goal into a playable mini-app and then iterates on it the same way. A few things happened quietly in the background of this series:

None of it locked me to one provider, either: I brought my own keys, and the same flow runs on Claude, GPT, Gemini, or a local model.

Play it

If you want to build something like this — hand-rolled like Sunset Glider, or assembled from registry Lego like Speed Chess — grab the app: https://mchatai.com/macos-app.

— Lawrence