Mate How to Make a Chess Game (Browser AI Loop 2026)

By Arron R.15 min read
How to make a chess game in 2026: use chess.js 1.4.0 for the rules engine, render an 8x8 CSS grid in React or Phaser 4, wire drag-and-drop against chess.moves a

Chess is the game programmers keep trying to write and rarely finish, because the query "how to make a chess game" hides three separate engineering problems stacked on top of each other. Rendering an 8-by-8 board is a five-minute job. Legal move generation with castling, en passant, promotion, and check detection is a two-day rabbit hole. And a minimax AI opponent that plays without embarrassing itself is another weekend on top of that. In 2026 the honest browser recipe splits the three cleanly: the open-source chess.js library at version 1.4.0 handles the rules, WizardGenie scaffolds the React or Phaser 4 board renderer around it, Sorceress AI Image Gen supplies the piece art and captured-piece tray, and Sorceress SFX Gen ships the move click, capture thud, and check bell. This guide is the honest end-to-end for how to make a chess game as a browser build a single developer can finish in a weekend.

How to make a chess game browser pipeline: 8x8 board render, chess.js legal-move generation, AI Image Gen piece sprites, minimax AI opponent, PGN export card
The 2026 chess game browser recipe: WizardGenie scaffolds the React or Phaser 4 board renderer, chess.js 1.4.0 handles legal move generation and check detection, AI Image Gen supplies the six piece pairs, and a 40-line minimax function plays the AI side.

What "how to make a chess game" actually means in 2026 (three layers)

The query "how to make a chess game" hides three very different requests. Some searchers want a two-player local chess board where two humans share the keyboard and mouse and take turns - a five-hour project that stops at legal moves and does not need an AI at all. Some searchers want a single-player chess build with an AI opponent, which adds a minimax or alpha-beta search on top of the legal-move layer. And some searchers want an online multiplayer chess site with rating, matchmaking, and time control, which layers a backend and a websocket server on top of the first two - a multi-week project the shape of a full startup, not a weekend build. This guide targets the second: how to make a chess game with an AI opponent that runs entirely in the browser and ships in a weekend.

The honest default is a three-layer stack: rules layer (legal moves, check detection, PGN export - use chess.js, do not roll your own), render layer (an 8-by-8 grid, six piece art pairs, drag-and-drop input - build with React and CSS grid or with Phaser 4), and AI layer (a 40-line minimax with alpha-beta pruning and a simple material-plus-position evaluation function). Each layer is roughly 100 to 300 lines of code and each is a natural WizardGenie prompt. The trap almost every "how to make a chess game" tutorial falls into is writing the rules layer from scratch, spending two weeks debugging en passant edge cases, and never getting to the AI. Section three walks through why chess.js exists, why you should use it, and what a chess.js-based build looks like in practice.

The chess game loop in one minute (render input validate AI-reply check)

Five moving parts and nothing else, in a strict order per turn. First, render the current board position - iterate the 64 squares, place a piece sprite on every occupied square using the current game state (or the FEN string exposed by chess.js). Second, read player input - listen for a drag-start on a piece belonging to the side to move, highlight the legal target squares by calling chess.moves({ square, verbose: true }), and register a drag-drop on a highlighted target. Third, validate and apply the move - call chess.move({ from, to, promotion }), which either returns the applied move object or null if illegal. If null, snap the piece back to its source square. Fourth, if the game is still on (check chess.isGameOver() and the side-to-move), fire the AI opponent - it picks a move from chess.moves() using minimax and calls chess.move() on its pick. Fifth, run the post-move pass - check chess.inCheck(), chess.isCheckmate(), chess.isDraw(), and update the HUD with turn count, capture list, and check banner.

That is the entire loop. Five steps executed once per turn, with the render pass repeating any time state changes, driven by React re-render or a Phaser tween. Everything else - the move-hint dots, the last-move highlight, the captured-piece tray, the PGN export button, the takeback button, the difficulty slider - is polish layered on top of this core loop. Keep the loop tight and the five-step order strict, delegate every rules question to chess.js, and the whole game slots into place in a few hundred lines of code.

Pick your engine for how to make a chess game: React + chess.js, Phaser 4, or WizardGenie from scratch

Three good browser targets in 2026, each with a very different trade-off. React plus chess.js is the honest default for a browser chess game and it is the pick 90% of readers should take. chess.js version 1.4.0 (verified 2026-08-09 against npmjs.com/package/chess.js) is a headless TypeScript library with zero runtime dependencies that ships legal move generation, check and checkmate detection, draw rules (threefold repetition, fifty-move, stalemate, insufficient material), FEN parsing, PGN import and export, ASCII board rendering, and an attackers() helper for square-under-attack queries. Wrap it in a React component that renders an 8-by-8 CSS grid with an onDrop handler per square, and you have a functional chess game in under 300 lines. React's built-in state model handles the "current game state - re-render" cycle cleanly.

Phaser 4.2.1 "Giedi" (released 9 July 2026, verified against phaser.io/download/stable on 2026-08-09) is the right pick when you want piece movement to animate (a sliding rook, a bouncing knight jump), when the board is embedded inside a bigger scene, or when the build ships as a downloadable Electron app rather than a webpage. Phaser's Scene manager, Sprite class, and tween chain make animated piece movement and last-move flash almost free. Combine Phaser as the renderer with chess.js as the rules engine - the two libraries do not know about each other, but they compose cleanly through a thin adapter that maps chess.js algebraic squares (a1 through h8) to Phaser world coordinates.

Writing the rules layer from scratch inside WizardGenie is the third path. It is educational, it costs nothing in dependencies, and it is a strong exercise in bitboard algorithms and move validation. It is also the path that will burn your weekend on en passant and castling-through-check edge cases. Only take this route if you specifically want to learn how a chess engine works internally; every shippable browser chess game in 2026 uses chess.js or one of its ports (chess.js has 4,369 stars on GitHub as of 2026-08-09 and is the reference implementation for browser chess in JavaScript). Three.js r185 (verified against threejs.org on 2026-08-09) is a valid fourth option for a 3D chess set with animated pieces and a rotating camera, but that is a stylistic remix on top of the same three-layer stack - the rules and AI layers are unchanged.

Comparison table of browser engines for a chess game: React plus chess.js, Phaser 4 plus chess.js, WizardGenie from scratch, and Three.js plus chess.js, across best-for rules-engine animation build-size and complexity
React plus chess.js is the honest default for a browser chess game in 2026. Phaser 4 layers animated piece movement on top of the same rules engine; Three.js drives a 3D remix. Only roll your own rules layer if the exercise itself is the point.

Step 1 — render the 8x8 board and generate piece art in AI Image Gen

Sketch the board first. A standard chess board is 8 files (columns, labelled a to h left to right from White's view) by 8 ranks (rows, labelled 1 at White's back rank to 8 at Black's). Squares alternate light and dark; the bottom-right square from White's view (h1) is always light. In CSS grid this is nine lines of code: a display: grid container with grid-template-columns: repeat(8, 1fr), 64 child divs, and a :nth-child rule that colors squares based on the sum of row and column index. In Phaser 4, spawn 64 Rectangle game objects at 80-pixel spacing and tint them. Either way, the pure render is under 20 lines of code.

The piece art is the fun part. Open Sorceress AI Image Gen. Chess needs six piece types (pawn, knight, bishop, rook, queen, king) in two colors (white and black) for a total of twelve piece images. Prompt for each pair in one shot: "chess piece, pawn, white on transparent background, top-down 3/4 view, cartoon vector art, 256 by 256, matte finish, subtle drop shadow", then swap "pawn" for the other five pieces and "white" for "black" on the second pass. Twelve generations in the mid-tier settings runs single-digit credits each, so budget 60 to 120 credits (0.60 to 1.20 USD at the standard rate of 100 credits per dollar, verified 2026-08-09 in src/lib/models.ts line 69 as CREDITS_PER_DOLLAR = 100). Save each image with a canonical filename - wP.png, wN.png, wB.png, wR.png, wQ.png, wK.png, and the same six with a leading b for black. chess.js's own board representation uses the same one-letter piece codes (p, n, b, r, q, k), so the mapping from game state to sprite is a two-line function.

Alternative: skip piece art entirely and use Unicode chess symbols (♔ through ♟), which every modern browser font supports. Set them at 48-point in a matching CSS grid cell and you have a functional but plain-looking board in zero credits. Ship the Unicode version first to prove the game logic, then upgrade to AI Image Gen art on the polish pass. Also generate a captured-piece tray background, a check banner ("WHITE IN CHECK"), a checkmate victory card, and a promotion-picker overlay - four small assets at another 20 to 40 credits total.

Step 2 — wire legal-move generation and move validation in WizardGenie

Open WizardGenie. WizardGenie is the Sorceress game-native coding agent, available on Windows desktop (with auto-updater, Early Access and above) and as a no-install web build at /wizard-genie/app. Its coding-model lineup (verified 2026-08-09 in src/app/_home-v2/_data/tools.ts lines 735 to 742) covers Claude Opus 4.7, Claude Sonnet 4.6, GPT-5.5, Gemini 3.1 Pro, DeepSeek V4 Pro, Kimi K2.5, Grok 4.2, and MiniMax M2.7. Any of the frontier models scaffolds the whole project on the first prompt. For a two-agent budget setup, pair Claude Opus 4.7 or GPT-5.5 as the Planner with DeepSeek V4 Pro or Kimi K2.5 as the Executor - the cheap Executor writes the actual TypeScript at roughly one-fifth of the cost of a single-frontier session.

The seed prompt is one paragraph. "Scaffold a React app called mate. Install chess.js version 1.4.0 as a dependency. Component ChessBoard renders an 8x8 CSS grid, each square is 80 by 80 pixels, alternating light and dark. Load the twelve piece PNG assets from /assets/pieces/. Wire drag-and-drop: on drag-start of a piece belonging to the side to move, call chess.moves({ square, verbose: true }) and highlight legal target squares with a green ring. On drop, call chess.move({ from, to, promotion: 'q' }); if the move is null, snap back to source. After every valid move, if not chess.isGameOver() and the side to move is Black, call the AI opponent function to pick and play its move. HUD shows current turn count, last move in algebraic notation, captured pieces per side, and check banner when chess.inCheck() is true. Include a Takeback button that calls chess.undo() twice (last human move and last AI reply) and a PGN Export button that copies chess.pgn() to clipboard." Feed that to any coding model in the lineup and you get a working two-player scaffold in under five minutes.

The chess.js API surface a browser chess game actually uses is small. new Chess() starts a game from the standard position. chess.move(moveObject) applies a move or returns null. chess.moves({ square, verbose: true }) returns every legal move from a given square with full metadata. chess.isGameOver(), chess.isCheckmate(), chess.isDraw(), chess.isStalemate(), chess.isThreefoldRepetition(), and chess.isInsufficientMaterial() cover every end-state you need to detect. chess.board() returns a 2D array for rendering. chess.fen() and chess.pgn() serialize the game for save-and-load and for the export button. chess.undo() unrolls the last move. That is the whole API most builds touch - do not reach for the exotic helpers until the base game works.

Step 3 — drop in a minimax AI opponent and SFX Gen click and capture sounds

The AI layer is where most chess-game projects abandon. Do not roll your own; write minimax with alpha-beta pruning at a small search depth, use a straightforward evaluation function, and stop there. The playable range for a browser chess AI is depth three (fast, sometimes hangs a piece) through depth five (slow but respectable club-player strength). Depth six or higher without transposition tables and iterative deepening runs into browser main-thread hangs of several seconds per move.

The prompt for WizardGenie is direct. "Add a function aiMove(chess) that plays the black side. Use minimax with alpha-beta pruning at search depth 3. Evaluation function: material score using standard piece values (pawn 100, knight 320, bishop 330, rook 500, queen 900, king 20000) plus a piece-square table bonus for central pawns and knights; positive score favours black. On each recursion, generate the moves array with chess.moves({ verbose: true }), apply each move with chess.move(), recurse to depth-1, undo with chess.undo(), and prune when alpha exceeds beta. Return the best-scoring move for black. Wrap the call in setTimeout(fn, 200) so the UI can render the human's move before the AI thinks. Add a difficulty slider that maps to search depth (1 for Easy, 3 for Medium, 5 for Hard) and clamps to depth 4 on mobile browsers to avoid main-thread hangs." That is a 40-line function once WizardGenie writes it, and it plays a game most browser visitors will lose in the low twenty-move range.

Audio next. Open Sorceress SFX Gen. SFX Gen bills 1 credit per second of generated audio (verified 2026-08-09 in src/app/sfx-gen/page.tsx line 23 as SEED_AUDIO_CREDITS_PER_SECOND = 1). Three clips carry the whole chess audio bed: a soft wood-on-wood click on any move (prompt: "soft chess piece placing on wooden board, 0.4 seconds, single tap"), a heavier capture thud when a piece takes another (prompt: "chess piece capture, wooden knock with soft attack, 0.6 seconds"), and a rising check bell when the king is attacked (prompt: "small brass bell chime, single strike with short decay, 0.8 seconds"). Three clips at a total of about 1.8 seconds cost roughly 2 to 4 credits. Add an optional checkmate fanfare (prompt: "triumphant brass fanfare, single note flourish, 1.5 seconds") and a draw stalemate sting for another 2 to 3 credits. Attach the click to chess.move()'s return, the capture to any move where chess.move()'s returned captured field is set, and the bell to chess.inCheck(). The whole audio pack is under 10 credits (0.10 USD).

Minimax chess AI opponent diagram at depth 3: node tree with best-move selection, material evaluation with pawn 100 knight 320 bishop 330 rook 500 queen 900, difficulty slider mapping to search depth
The 40-line minimax AI opponent for how to make a chess game: alpha-beta pruning at depth 3, material score using standard piece values, a piece-square table bonus for centre control. Wrap the call in a setTimeout so the human's move renders before the AI thinks.

Step 4 (bonus) — PGN export, takeback, and clock in WizardGenie

Three small polish features separate a coding-exercise chess board from something a friend will actually play. Wire all three in the same WizardGenie session and the total scope stays under 100 extra lines.

PGN export first. chess.js's chess.pgn() method returns the full move list in standard Portable Game Notation including seven-tag roster headers. Bind a button to copy that string to the clipboard using navigator.clipboard.writeText(chess.pgn()). That PGN string loads directly into any online chess viewer, into SCID, or back into your own game via chess.loadPgn(str). Two lines of code and your visitors can save, share, and re-analyse their games.

Takeback next. Bind a button to call chess.undo() twice in a row - the first undo unrolls the AI's reply, the second unrolls the human's own move, restoring the position to where the human's turn started. If takeback should be disabled once the game is over, gate the button on !chess.isGameOver(). If you want to limit takebacks (three per game, say), keep a counter in component state. Ten lines of code covers all three variations.

Chess clock last. Two numbers per side (time remaining in seconds, increment per move), a setInterval that ticks the side-to-move's clock down every 100 milliseconds, and a check at every clock tick for time-out. Blitz (5 minutes plus 3-second increment), rapid (10 plus 5), and classical (30 plus 30) are the three presets to expose. On time-out, the timed-out side loses regardless of position. Add a small clock UI at the top and bottom of the board that changes color when under 30 seconds. Twenty lines of code covers the whole clock feature. This step is optional; many browser chess builds skip the clock entirely for casual play.

What a how to make a chess game project costs on Sorceress in 2026

Concrete asset and generation budget for a browser chess game from empty repo to zip-and-ship playable, all numbers verified 2026-08-09 against local Sorceress source:

  • Twelve piece PNG sprites (AI Image Gen): roughly 5 to 10 credits per generation at mid-tier quality, 12 generations, so 60 to 120 credits (0.60 to 1.20 USD). Skip and use Unicode chess symbols for zero credits if you want a text-only version.
  • Captured-piece tray, check banner, checkmate card, promotion overlay (AI Image Gen): 4 assets at 5 to 10 credits each, so 20 to 40 credits (0.20 to 0.40 USD).
  • Move click, capture thud, check bell, checkmate fanfare (SFX Gen): 1 credit per second, 4 clips at under 1 second each, so about 3 to 5 credits (0.03 to 0.05 USD).
  • chess.js library: free, open-source, MIT licensed. Version 1.4.0 verified 2026-08-09 as the current stable release on npm with 4,369 GitHub stars.
  • WizardGenie coding time: effectively free on the Sorceress side (bring your own model API key, or use one of the built-in trial-key options). Model-side API cost for a 3-to-4-hour prompt session on a cheap Executor like DeepSeek V4 Pro is typically under 0.60 USD, or under 1.50 USD on Claude Opus 4.7 as a single-frontier session.
  • Total for one complete browser chess game build: 83 to 165 credits, or roughly 0.83 to 1.65 USD in Sorceress credits, plus under 1.50 USD in model API time. Under 3.15 USD end-to-end for a first browser chess game with a working minimax AI opponent.

Sorceress bills 100 credits per dollar at the standard rate (CREDITS_PER_DOLLAR = 100 in src/lib/models.ts line 69). New accounts start with 100 free credits (SIGNUP_GRANT = 100 in src/app/api/admin/credits/route.ts line 12), which covers the twelve piece sprites at the low end of the range plus the entire audio pack with room left over. The Sorceress Lifetime tier at 49 USD one-time (LIFETIME_PRICE = 49 in src/app/plans/page.tsx line 51) covers unlimited AI Image Gen and SFX Gen use, which matters if you plan to build a full piece-set library (medieval, sci-fi, chibi anime, real-photo wooden set) or a chess variant collection (Chess960, King of the Hill, three-check, atomic) on top of the base build.

For related browser-game pipelines that share this "wire the rules engine, generate the art, prompt the AI opponent, ship the browser build" spine, the closest reads are Guess How to Make Wordle (Browser Guess Grid 2026) for the same grid-plus-input-plus-feedback pattern on a puzzle game, Flap How to Make Flappy Bird (Browser Loop 2026) for the one-mechanic-plus-scoring weekender template, and Stack How to Make Tetris (Browser Falling Blocks 2026) for another grid-and-turn-order arcade classic that fits the same weekend budget. The Sorceress Tools Guide is the master index for every tool this guide referenced. Under four dollars, one weekend, and how to make a chess game with a working AI opponent is a done deal.

Frequently Asked Questions

Should I use chess.js or write my own move-validation code?

Use chess.js for every browser chess game unless the exercise of writing a chess engine from scratch is itself the goal. chess.js version 1.4.0 (verified 2026-08-09 against npmjs.com/package/chess.js) is a TypeScript library with zero runtime dependencies that ships legal move generation, check and checkmate detection, all draw rules (threefold repetition, fifty-move, stalemate, insufficient material), FEN parsing, PGN import and export, and an attackers() helper. It has 4,369 GitHub stars and is the reference implementation for browser chess. Rolling your own move validation means implementing en passant, castling-through-check, promotion, and threefold-repetition detection correctly - that is a two-week rabbit hole even for experienced developers, and every edge case you miss produces a bug players will notice. The chess.js API surface an actual chess UI touches is small (about eight methods) and composes cleanly with any renderer. If you specifically want to learn how a chess engine works, write your own AND use chess.js as the reference implementation to test against.

How long does it take to make a browser chess game with an AI opponent?

About twelve to twenty hours for a first shippable browser build if you follow the pipeline in this guide. Roughly one hour to sketch the three layers (rules, render, AI) and the state shape on paper. About two to three hours to prompt WizardGenie through the React or Phaser 4 renderer with drag-and-drop, chess.js legal-move highlighting, and move application. Around 30 minutes to generate the twelve piece sprites in AI Image Gen (or zero if you use Unicode chess symbols for the first version). Roughly three to five hours to write the 40-line minimax AI with alpha-beta pruning, a material-plus-piece-square evaluation function, and a difficulty slider that clamps search depth. About one hour for the check banner, checkmate card, captured-piece tray, PGN export, and takeback buttons. Around 30 minutes for the SFX Gen move click, capture thud, and check bell. Experienced JavaScript developers who have built a game UI before can hit playable in under eight hours; the extra hours cover the AI-tuning pass and the polish that makes rotations, animations, and end-state detection feel right.

Which browser engine should I use for a chess game in 2026?

React plus chess.js is the honest default for 90 percent of readers. React's built-in state model handles the game-state-to-render cycle cleanly, CSS grid renders the 8x8 board in nine lines of style, and drag-and-drop is a standard browser API. Phaser 4.2.1 Giedi (released 9 July 2026, verified against phaser.io/download/stable on 2026-08-09) is the right pick if you want animated piece movement (a sliding rook, a knight-jump arc), if the chessboard is embedded in a larger game scene, or if you plan to ship the build as a downloadable Electron app. Three.js r185 (verified against threejs.org on 2026-08-09) drives a 3D chess set with a rotating camera and animated captures - stylistic remix on top of the same three-layer stack. Vanilla HTML plus a single script tag is the fourth path, valid for a code-golf entry or a first-principles learning demo but harder to extend. WizardGenie scaffolds the project in whichever of the three you pick from a single natural-language seed prompt.

How do you write a minimax chess AI in 40 lines?

Minimax with alpha-beta pruning at search depth three is the sweet spot for a browser chess AI opponent: fast enough to move in under two seconds on a mid-range laptop, strong enough to punish obvious human blunders, weak enough to be beatable in a casual game. The core function recurses through possible move sequences and returns the best-scoring move for the AI side. Standard piece values in centipawns are pawn 100, knight 320, bishop 330, rook 500, queen 900, king 20000 - taken from decades of chess-engine literature and used by open-source engines like Stockfish and Lc0 as the material baseline. The evaluation function sums material for both sides (positive if the AI side is ahead) and adds a small piece-square table bonus for pieces on strong squares (central pawns, developed knights, castled king). Alpha-beta pruning skips branches where the current player already has a better guaranteed alternative, cutting the effective branching factor from about 35 down to under 10. Wrap the call in a setTimeout with a 200-millisecond delay so the browser renders the human's move before the AI blocks the main thread. Add a difficulty slider mapping to search depth (Easy 1, Medium 3, Hard 5) with a hard cap of 4 on mobile browsers where deeper searches hang. WizardGenie writes the whole 40-line function from a one-paragraph prompt.

How do I export a chess game as PGN for sharing or analysis?

chess.js's chess.pgn() method returns the full move list in standard Portable Game Notation, including the seven-tag roster headers (Event, Site, Date, Round, White, Black, Result) at the top and every move in standard algebraic notation. Bind a button that calls navigator.clipboard.writeText(chess.pgn()) and your visitors can paste their game directly into any online chess viewer, into SCID vs. PC for local analysis, into Lichess or chess.com's PGN import (their sites), or back into your own game via chess.loadPgn(str) for a takeback-past-the-current-position replay feature. Add optional PGN header setters (chess.header('White', 'You'), chess.header('Black', 'AI Depth 3'), chess.header('Date', new Date().toISOString().slice(0,10).replace(/-/g,'.'))) before the export so shared games carry useful metadata. Two lines of code for the copy button, ten more for the header setters. That single feature turns your build from a coding exercise into a game people will save and share.

Sources

  1. chess.js - TypeScript chess library (jhlywa/chess.js on GitHub)
  2. Phaser 4 - HTML5 Game Framework
  3. MDN - HTML Drag and Drop API
  4. Wikipedia - Portable Game Notation (PGN)
Written by Arron R.·3,299 words·15 min read

Related posts