Inspiration
In 1988, Interplay released Battle Chess — a game where chess pieces came alive and fought each other on the board. Knights would charge, rooks would turn into rock monsters, and pawns would kick each other in the shins. It was a revelation. For the first time, chess felt like a battle, not a math problem. But Battle Chess was pure spectacle — it didn't teach you anything. You still needed to already know how to play.
Then Harry Potter came along and put wizard chess on screen — Ron commanding "Knight to H3" before his knight charges to its death. Same fantasy, bigger scale, still no real game you could play.
Adventurer's Gambit is what happens when you combine Battle Chess's idea (pieces that fight) with what it was missing (a mentor that teaches). The 3D combat is the hook — Rogues, Mages, and Barbarians clashing with an Undead Army on a dungeon board. But underneath, an AI mentor powered by Amazon Nova explains chess in plain language, adapts to your skill level, and remembers what it's already taught you. Battle Chess made chess entertaining. I wanted to make it accessible.
What it does
You command an RPG party — Rogues, Mages, Barbarians — against an Undead Army on a 3D dungeon board. Captures trigger combat animations. A kill feed tracks the carnage. Hover over any character to see its chess role and RPG name — you learn chess vocabulary without trying.
Every turn, Stockfish crunches the position for accuracy, then Amazon Nova 2 Lite translates that into advice a beginner can follow: "Move your Ranger to C4 — this controls the long diagonal and pressures the center." It grades your moves, explains your mistakes, and tracks what it's already taught you so it never repeats itself. When the game ends, you get a personalized post-game breakdown — not "good game," but "your piece development was strong in the opening, but you left your king exposed for 12 moves."
Battle Mode strips out the mentor for pure competitive play with ELO ratings and a leaderboard.
How I built it
Stockfish WASM runs inside a Lambda function overprovisioned to 3GB memory (~2 vCPUs) so the engine doesn't choke. Hono handles routing. On every player turn, the backend runs Stockfish at a higher depth than the AI opponent, packages the evaluation into structured data, and sends it to Nova 2 Lite through Bedrock's Converse API with extended thinking. Nova gets the full teaching history — every concept it's taught, every mistake the player made, whether they followed its last recommendation — and produces a response that continues the lesson coherently.
The frontend is React Three Fiber rendering ~20 animated characters simultaneously with skeletal animations (idle, walk, attack, death), projectile physics, post-processing bloom, and floating HTML nameplates — all at 60fps. Zustand manages game state. KayKit asset packs provided the 3D characters.
DynamoDB stores game state with TTL cleanup. A GSI powers the ELO leaderboard. CloudFront serves the frontend from S3 with aggressive caching on static assets. The entire stack is CDK — under 200 lines of infrastructure code.
Challenges I ran into
My first attempt was to have Nova play chess directly. No Stockfish, no engine — just give Nova the board state and ask it to pick a move. It couldn't do it. It would suggest illegal moves, hallucinate piece positions, and occasionally try to move pieces that had already been captured. LLMs don't do spatial reasoning over an 8x8 grid, and chess requires perfect legality checking. That experiment died fast, and I brought in Stockfish as the chess brain.
Even with Stockfish handling the moves, Nova struggled to read the board. I was passing it the full position data — every piece, every square, evaluation scores, principal variation lines — and without extended thinking enabled, it would just guess. It would claim a bishop was on d5 when it was on c4, or describe threats that didn't exist. Turning on extended thinking was the fix. With reasoning mode, Nova actually processes the structured board data instead of pattern-matching past chess commentary. That was the single biggest quality jump in the entire project.
Tuning Stockfish difficulty was its own challenge. A raw Stockfish engine at even moderate depth will crush any beginner — that's not a learning experience, that's a beating. I had to tune multiple parameters to create fair opponents: search depth (3/6/10 for easy/medium/hard), skill level (Stockfish's built-in strength limiter), and multi-PV count to control how many candidate moves the engine considers. Easy mode runs at depth 3 with skill level 0 and a 50% blunder chance. But here's the critical design decision: the mentor always runs Stockfish at a higher depth than the opponent — depth 10 for beginners, 12 for intermediate, 14 for advanced. If you follow the mentor's suggestion, you will actually win. That asymmetry is what makes the teaching loop credible.
Prompt engineering was harder than the 3D graphics. Early versions of the mentor sounded like a chess blog — "an interesting positional choice" — instead of telling you what to do. I iterated on the system prompt extensively, giving Nova a rigid output schema and feeding it the full teaching memory on every call so it could build on previous lessons rather than starting fresh each turn.
Accomplishments that I'm proud of
Passing Stockfish's full principal variation lines to Nova was the unlock that turned the mentor from a move-by-move commentator into a strategist. Each PV line is a 4-6 move sequence representing the engine's predicted best play. The mentor prompt explicitly instructs Nova to think in multi-move plans, not single-move reactions — "describe the strategic idea across the full PV sequence." When the player follows the recommended move, the system tracks whether the opponent's response matched the predicted PV, and on the next turn Nova can say "the opponent deviated from the expected response — here's how to adapt." That plan continuity is what makes it feel like you're being coached through a game, not just getting isolated tips.
The Stockfish depth asymmetry — mentor always smarter than the opponent — sounds simple, but it's the design decision that makes the teaching loop credible. Without it, the mentor might recommend moves that don't actually beat the opponent, and the player would learn not to trust it.
I built this entire 3D game with zero prior game development experience. The KayKit free asset packs gave me production-quality characters — Rogues, Mages, Barbarians, Skeletons — with skeletal animations for idle, walk, attack, and death. React Three Fiber made 3D feel like regular React development: useState for hover effects, useFrame for animation loops, drei's Html component for floating nameplates. I went from never having touched Three.js to rendering 20+ animated characters with projectile physics, post-processing bloom, and combat choreography. Hat tip to Claude Code and Claude Opus 4.6 for being the pair programmer that made this possible.
The post-game recap pulls from the entire game's teaching context to produce analysis that's personal to how you played. Two players who lose the same game get different recaps based on their skill tier and the specific mistakes they made.
What I learned
Don't ask LLMs to do what engines do. My first instinct was to have Nova play chess. It can't. The moment I separated concerns — Stockfish for accuracy, Nova for communication — everything clicked. The LLM's job is translation, not computation.
Extended thinking is powerful but comes with a latency tradeoff. Nova 2 Lite offers three reasoning effort levels — low, medium, and high. Without any extended thinking, Nova would skim the board data and hallucinate piece positions. With it, Nova actually reads the FEN string, processes the position, and produces accurate analysis. But higher reasoning effort means longer response times, and in a real-time game every second of wait matters. I landed on low effort for the mentor — it's enough for Nova to reason through structured Stockfish data without adding noticeable delay. Prompt caching on the system prompt compounds the savings: the large mentor prompt (tier instructions, grading rubric, output format) is cached after the first call in a game, so subsequent turns only pay for the new position data.
React Three Fiber is production-ready. I was skeptical about running 20+ animated 3D models with post-processing in a browser, but R3F + drei handled it cleanly. The component model makes 3D feel like normal React — useState for hover effects, useFrame for animation loops. A PerformanceMonitor from drei dynamically scales DPR to maintain frame rate on weaker hardware.
What's next for Adventurer's Gambit
- Multiplayer — WebSocket connections so two players fight on the same 3D board with synchronized combat animations.
- Puzzle mode where Nova generates drills targeting your specific weaknesses from past games.
- Multilingual mentorship — Nova already handles multiple languages, so offering the mentor in Spanish, Hindi, or Mandarin is mostly a prompt change.
The long-term goal is getting this into classrooms where the RPG framing and adaptive teaching can reach kids who'd never sit through a traditional chess lesson.
Built With
- amazon-cloudfront-cdn
- amazon-dynamodb
- bedrock
- lambda
- nova
- react
- three.js
- typescript
Log in or sign up for Devpost to join the conversation.