VoiceRun Showcase · 2026
Voice Chess
Chess, played by voice — say “knight to F3” and it moves. Eight AI opponents. Zero LLMs. Built with VoiceRun in a single Claude Code session.
See it in action
Watch the demo
- 8
- AI opponents, ELO 400–2700
- 0
- LLM calls per game
- 5
- Three.js board worlds
- 1
- Claude Code session to build
How it was built
Claude Code + Fable 5, start to finish
The entire application — handler logic, chess engine, move parser, web UI, Three.js environments, deployment config — was designed and built in a single Claude Code session using Fable 5.
A multi-agent code review caught 10 bugs before the first test. Real game transcripts drove iterative fixes to the move parser. Design passes added Three.js themes, Lichess SVG pieces, and a PWA shell — all in conversation.
The VoiceRun stack
Event-driven Python. Push and deploy.
Step 1 of 4
User speaks
The player says "pawn to E4" into their microphone or clicks a square on the board.
A radical decision
Zero LLM calls. Entirely deterministic.
Move parsing — regex normalization, token matching against lookup tables, then filtering against python-chess legal moves. Handles “pawn to E4”, “knight F3”, “castle kingside”, and dozens of STT mishearings like “Ponda” → “pawn to”.
AI opponent — pure-Python minimax with alpha-beta pruning and piece-square tables. Depth and randomness parameters control difficulty. No API call, no latency, no cost per move.
All speech is templates — each character has canned move lines, reactions, and personality. The handler picks one and slots in the move description.
Production learnings
Promptable STT changed everything
We tried three STT providers on real chess speech. Context-aware prompting was the breakthrough — telling the model what domain to expect dramatically improved accuracy.
The hallucination trap
During menu silence, GPT-4o-mini-transcribe hallucinated from the prompt — generating text like “I see that you’re playing a voice-controlled chess game” as if someone had spoken it.
Three-part fix: semantic VAD (context-aware silence detection), a shorter prompt, and a hallucination filter that silently drops text over 80 characters or containing known generated phrases.
def _is_hallucination(text): if len(text) > 80: return True return any(m in text.lower() for m in MARKERS)
Bringing characters to life
8 opponents. 8 voices. One engine.
Each character is a unique combination of Inworld TTS voice, personality-driven dialogue, and a configurable engine. No LLM personas — just structured data that makes each opponent feel genuinely different.
Distinct voices, real personality
Every opponent speaks with a different Inworld voice — Josh for the bumbling beginner, Ashley for the intense grandmaster, Ryan for the cold machine. Their lines are canned but characterful: Woody says “Eeny meeny miny moe...” while Kasparov says “Obviously.”
Intelligence is configurable
Under the hood, every character runs the same pure-Python minimax engine. What changes is the depth (1–4 plies), randomness factor (0–40%), and think time (0.2–3s). Difficulty is a dial, not a different model.
"kasparov": { "voice": {"provider": "inworld", "identifier": "Ashley"}, "engine": {"depth": 4, "randomness": 0.0, "think_ms": (1500, 3000)}, "move_lines": ["Obviously, {}.", "The only move: {}."], "win_line": "As expected.", }
ELO 400 · Voice: Josh
Woody
Impulsive beginner. Thinks 0.2–0.6s. 40% random moves. "Is that good?"
ELO 800 · Voice: Sophie
Patzer
Coffee-shop casual. 25% random. "I'm feeling knight to F6."
ELO 1200 · Voice: Brian
Fritz
Club regular. Methodical. "After some thought, bishop to C4."
ELO 1500 · Voice: Luna
Vera
Tournament player. "Think carefully." 0.7–1.8s thinks.
ELO 1800 · Voice: Eleanor
Morphy
Sharp attacker. No randomness. "Naturally, queen to D5."
ELO 2100 · Voice: Alex
Tal
Master tactician. "The position demands bishop takes F7."
ELO 2400 · Voice: Ashley
Kasparov
Relentless grandmaster. 1.5–3s deliberation. "As expected."
ELO 2700 · Voice: Ryan
Deep Blue
Maximum engine strength. "Move calculated: rook to D1."
Design & interactivity
Five themes. Real pieces. Click and voice.
Three.js powers five environments: stars with nebulae, a torchlit dungeon with embers, frosted glass, a cyber grid, and warm dust motes. Lichess SVG pieces animate with spring physics.
Click-to-move sends UCI notation through sendTextEvent() — the same handler path as voice. The system doesn’t know which input method you used.
Two voices, one session
System messages use OpenAI Nova. Opponent moves use their character’s Inworld voice. You hear the difference between the game engine and your opponent instantly.
Human-like think times
Each character has a random think delay between 0.2 and 3 seconds — Woody blurts out a move in 200ms, Kasparov deliberates for up to 3 seconds. A SilenceEvent fills the gap between instant engine computation and the character’s persona.
PWA-ready
Service worker, manifest, safe-area insets. Add to home screen and it runs standalone.
What will you build?
Voice Chess went from empty directory to deployed game in one working session. A Solutions Architect can help you scope your own — or pip install voicerun-cli and start tonight.