DEV Community

AI Predictions Dev
AI Predictions Dev

Posted on

I built a roguelike whose dungeon master is an LLM running 100% in the browser

Most "AI games" phone home. Every turn is an API round-trip, every player burns your tokens, and the whole thing dies the day the bill scares you. I wanted the opposite: a text roguelike where the dungeon master is an LLM that runs entirely in the player's browser — no server, no API key, no per-token cost, and it keeps working offline after the first load.

Here's the architecture and the one bug that taught me the most.

The core trick: WebLLM + WebGPU

WebLLM compiles quantized models to WebGPU, so inference runs on the player's GPU. There is no backend at all.

const cdn = "https://esm.run/@mlc-ai/web-llm";
const webllm = await import(/* webpackIgnore: true */ cdn);
const engine = await webllm.CreateMLCEngine(MODEL_ID, {
  initProgressCallback: p => setLoading(p.text),
});
Enter fullscreen mode Exit fullscreen mode

First load pulls the weights once (the browser caches them). After that every turn is local and free.

Let the model narrate — never let it adjudicate

A dungeon master should be creative, but it must not be allowed to break the rules. The split that made it stable:

  • Narrative comes back as free prose. Let it cook.
  • Mechanics — HP delta, items, whether the run ends — come back as a small JSON object the engine validates. The game loop trusts the JSON, not the prose.

My most instructive bug: early on I let the prose drive death detection (regex for "you die"), and the model cheerfully killed players on turn one with pure flavor text — "this could be the end of you" → game over. Moving death to an integer the engine owns (if (hp <= 0)) fixed it instantly.

Rule of thumb: the LLM writes the story; your code keeps the score.

Why on-device is the right default for indie games

  • $0 marginal cost — 10 players or 10,000, the server bill is identical: nothing.
  • Privacy — choices never leave the device.
  • Offline — runs on a plane after first load.
  • No rate limits, no leaked keys.

The tradeoff is model size: you run something small enough to load in a tab, so prompt design carries real weight. For a narrative game master that's a fair trade.

One engine, many games (config beats code)

Genre is just a config object — palette, HUD labels, seed scenarios, system prompt. Same engine, swap the config, ship a different game. Adding a genre is data, not a code change, which means a generator can author new ones.

If you want to poke at a live one, the cyberpunk build (NeonHeist) and a few others are up under Games at bestpaid.app — all running on-device.

Happy to go deeper on the JSON-contract prompt or the WebGPU loading UX in the comments.

Top comments (0)