robesris
Navia Dratp - a real-time multiplayer board game in Phoenix LiveView with a Claude-powered opponent that explains its reasoning
I built a free online version of Navia Dratp (yes, that’s the actual spelling), a long out of print strategy game by Bandai. Think chess + mana and deckbuilding. It’s Elixir + Phoenix LiveView.
Real-time multiplayer with no separate frontend. It’s all LiveView + PubSub, so each game is its own process with its own topic, both players’ sockets subscribe, and moves, clocks, and state changes broadcast without me having to build a websocket layer or a JS SPA. Drag-and-drop, live per-move clocks, spectators, and reconnect-survival all fall out of LiveView.
An LLM (Claude) opponent that’s structurally incapable of corrupting game state. This was an interesting experiment. The delicate part wasn’t getting Claude to play, it was making it safe. The model never emits a raw move; the backend generates the set of server-validated legal moves and the model only picks one, so a hallucinated or malformed response can’t do anything illegal. At worst it chooses badly, which it then explains to you in plain language after each move. One pitfall worth passing along: I first modeled the chosen-move field as an integer in the JSON schema, which invited the model to sample runaway integers. Making it a string (with tolerant parsing) fixed it. Schema number fields are a trap for LLM tool calls.
A development journal Claude kept the whole way, in its own voice — including some philosophical musings, and a game it lost to me while we were building it: Development Journal · Navia Dratp
A learn-to-play tutorial for a gentle introduction to the game: Lobby · Navia Dratp → Click “Learn to Play”
Play it (no install, runs in the browser, and is mobile-friendly):
If you’d rather play a person than the AI, sign up for the current tournament, The Isle of the Stones: The Isle of the Stones · Navia Dratp
First Post!
robesris
Sorry, there’s currently some crashing going on with the site, give me a few minutes and it should be stable again. ![]()








