Browser game
Wizard Chess
Chess in a 3D stone hall: pieces walk to their square and break into stone when captured.
Chess in a 3D stone hall in the browser. Pieces walk to their square, a capturing piece strikes with its weapon, and the captured one breaks into stone fragments that pile up at the edge of the board for the rest of the game. The camera orbits 360 degrees. Play the computer on 8 levels with no account, or play online with rating, clocks, replays and chat. Free, no ads, in beta. 3D piece models by nbauchat, used with permission.
What I did
Design, 3D, backend, frontend and deploy, alone, in 8 days from the first commit to a live beta.
- Built the 3D scene on three.js through react-three-fiber (WebGL 2): walking pieces, weapon strikes on captures, a camera that orbits 360 degrees.
- Made captured pieces break into stone: each piece type is sliced once in the browser along a few tilted planes, and I wrote the fragment physics myself in about 190 lines: gravity, bounce, floor friction and sleep.
- Ran Stockfish 19 (single-threaded lite WASM, 1.8 MB) in a Web Worker, with 8 levels from Novice to Master, a training mode with take-backs and 3 animation speeds.
- Wrote the online side: lobby, invite links, quick match by rating, 4 time controls, Glicko-2 ratings, leaderboard, profiles, replays in the 3D scene, game chat and direct messages.
- Made the server check every move with a PHP port of chess.js, and keep the clocks, so animation time is never charged to a player.
- Hardened it: CSP with nonces, HSTS, rate limits on every action, a firewall with auto-block, and tests for the OWASP Top 10 checks.
- Set up CI with GitHub Actions (lint, static analysis, Pest, Vitest, build), then an rsync deploy with smoke tests. A Playwright test plays e4 against the computer on production.
The decisions, and why
- Server-authoritative clocks
- The client cannot be trusted with time. The server owns the clocks, and a move animation never costs a player a second.
- Fracture in the browser, at load
- Each piece type is sliced once in the browser when the scene loads. A capture computes nothing, and the fragments that settle merge into one mesh per captured piece.
- No daemons on shared hosting
- Hostinger shared hosting has no WebSocket server and no workers. Pusher Channels carries live play with a polling fallback every 1.5 s, cron handles clocks and cleanup, and the server-side renderer listens on a Unix socket because the host refuses loopback TCP.
- Engine in a worker
- Stockfish runs in a Web Worker, so the computer thinks without freezing the scene. Playing the computer needs no account.
Built with
- Laravel 13
- PHP 8.3
- Inertia
- React 19
- TypeScript
- three.js
- react-three-fiber
- MariaDB
- Pusher
- Stockfish WASM
The numbers, and where they come from
- First commit to live beta
- 8 days
- 25 Sep to 2 Oct 2026
- Commits by launch day
- ~320
- git history, 2 Oct 2026
- Computer levels
- 8
- Novice to Master, Stockfish 19
- Online time controls
- 4
- 5+3, 10+0, 15+10, 30+0
Performance scores move a few points between runs on any site, including these. Paste the address into PageSpeed Insights and run it yourself.
Want something like this built?
New sites and apps are quoted per project; a site you already have gets the technical SEO audit service. Both start with a free 20-minute call.