Notes on Building TalesMUD

From LOTD in 2018 to TalesMUD today — why Go, why Svelte, what MUDs and BBS door games have to do with it, and where this is going.

The RPG genre and multiplayer games have fascinated me for a long time, even if I was never the person who logged 4000 hours into an MMO. I knew the history though — the big graphical MMOs didn't appear from nowhere. AberMUD, TinyMUD, DikuMUD came first. They invented the mechanics that EverQuest and WoW refined decades later. Dark Age of Camelot was built by Mark Jacobs, who before that built Dragon's Gate, and GemStone before that. The genre tree goes all the way down to a terminal prompt.

And then there were DOOR games. If you remember BBS systems, you remember them. The most famous was LORD — Legend of the Red Dragon. You'd log into the BBS, pick LORD, and have a fixed number of actions for the day: fight monsters, visit the inn, challenge another player. Global leaderboard, seasonal resets, PvP. And eventually, if you were strong enough, you'd face the dragon.

LORD basically invented the loop that makes mobile games addictive today — daily limited actions, social pressure, a progression ceiling that reset periodically — just forty years earlier. Both MUDs and DOOR games lived in the back of my head as the kind of thing I wanted to build: text-driven, narrative-rich, multiplayer by default, no install required.

LOTD: The First Attempt (2018)

In 2018 I started LOTD — Lair of the Dragon. It was my first real attempt at a MUD server, and it had an idea I still think was genuinely interesting: it supported both TCP (telnet) clients and WebSocket clients simultaneously. Both types of players connected to the same game world. TCP handlers and WebSocket handlers both fed into the same game instance, which processed commands and broadcast results back out through whichever transport each client had connected on.

A cool concept. Also much more complexity than I needed for a first version. LOTD taught me what the problem actually was, and I took the WebSocket and game server components forward when I eventually rewrote it.

Around the same time — and into 2019 and 2020 — I was working on something called dungeonsrv. It was aimed at providing generic REST services for mobile and browser RPG games, with server-side scripting support so you could, for example, run a script at item instantiation time to change the item's description based on the time of day, or the moon calendar. That idea never went away. A version of it eventually made it into TalesMUD's Lua scripting layer.

dungeonsrv also had a procedural dungeon generator — still pretty basic, but it produced interesting results and it's something I still want to incorporate properly: either as a source of genuinely random generated rooms, or as a tool in the content editor for bootstrapping zone layouts.

The first live version of TalesMUD shipped under a different name: Tales of a Pirate, running at talesofapirate.com. It was a sandbox for testing the ideas and the stack. And it's where the real decisions about what this project was going to be got made.

On Choosing Go

My first look at Go didn't impress me. The syntax looked plain, almost boring. The ecosystem seemed small. I moved on.

What brought me back, of all things, was the blockchain hype of 2017-2018. A lot of blockchain and crypto infrastructure was written in Go — not the chains themselves (usually C++), but the tooling, the SDKs, the connectors. Go was everywhere in that space, so I started reading. Then in early 2018 I found the Twirp post — Twitch's RPC framework for Go — and that was it. I finally sat down and wrote something real with it.

What initially put me off — the plain syntax, the lack of magic — turned into exactly what I liked. Go is simple in the best way. The standard library handles most of what other languages need frameworks for. You write clear, direct code, and it runs fast and reliably.

I was missing generics for a long time (they've since landed). I also looked at Rust, read through some of the API docs and examples. The honest reason I didn't switch: my investment in Go already outweighed the benefits of starting over. That's a pragmatic reason, not a technical one, but I think it's the right one.

More than anything: I wanted to build a bigger project in Go. Not a to-do app, not a hello world. Something with real complexity — network code, embedded scripting, a game loop, concurrency, sessions — that would force me to actually understand the language. That's what TalesMUD gave me.

On Choosing Svelte

The browser frontend needed to run a terminal. I'd come across xterm.js — the same terminal emulator that powers VS Code's integrated terminal — and that was the obvious choice for rendering the game client. Real terminal behaviour, real escape sequence support, and open source.

For the framework around it, my React and Vue experience was shallow — I'd done small projects with both but never went deep. I'd been reading about Svelte and liked what I saw: a reactive component framework that compiles down to minimal JavaScript, no virtual DOM, the store concept built in. It reminded me of a DHH post I'd read about Basecamp's new mail app — their explicit choice to rely on as few third-party JavaScript packages as possible.

That philosophy appealed to me. Pick something minimal and understand it fully, rather than pulling in a dependency graph you can't reason about. Svelte was the right call.

What the Project Actually Is

After several iterations, here's what TalesMUD became:

  • A Go backend — single binary, embeds the Svelte frontend, WebSocket game server, HTTP REST API, SQLite persistence via modernc.org/sqlite
  • A Svelte game client — xterm.js terminal rendering, minimap, tab widgets, quest log, inventory panels
  • A web content editor — browser-based CRUD for rooms, NPCs, items, quests, dialog trees, loot tables, and scripts
  • Turn-based combat — initiative rolls, 29 skills across 6 classes, status effects, XP and loot distribution
  • A full quest system — Kill, Collect, Deliver, Visit, Talk, and Custom Lua objective types
  • Lua scripting — I originally planned JavaScript via otto, but Lua is a much better fit for game scripting. Eight API modules give scripts access to everything: items, rooms, characters, NPCs, dialogs, quests, game messaging, utilities
  • Auth0 integration — optional authentication, three roles (player, creator, admin)
  • Docker deployment — single docker compose up gets you a running game server

The content pipeline is worth calling out specifically: world content is authored as Markdown files and exported to YAML, which the server imports at startup. It's the same approach static site generators use for content — file-based authoring, version-controlled, diff-friendly. You can build an entire zone in a text editor and git push it.

The Platform Vision

The longer-term idea is bigger than just a framework. I want TalesMUD to be a platform — something you can fork, customize, and run as your own game server. A wild version of that involves Docker and Kubernetes APIs, spinning up isolated game servers on demand. A simpler version is what already exists: clean import/export, container images, and a content pipeline that's easy to version-control and hand off.

The systems are deliberately genre-agnostic. Nothing in the combat engine requires swords and magic. Nothing in the room system requires a fantasy setting. The same framework that runs a medieval dungeon can run a sci-fi space station or a post-apocalyptic wasteland — if you write the content for it.

Adding TCP/telnet support is also still on the list. It would mean compatibility with the classic MUD client ecosystem — clients that have had decades of development time and come with their own scripting and mapping tools. The technical work isn't the hard part; the hard part is that the current auth model relies entirely on Auth0 tokens, and TCP clients don't do OAuth flows. A separate password-based auth path would need to exist first.

Veilspan: The Living Proof

The best way to know a framework works is to build something real with it. Veilspan is a fantasy world set in the ruins of Aethermoor — real zones, real NPCs, real quests, real combat. It's the official demo deployment of TalesMUD, running the current development version live.

Go play it. See what the framework can actually do before you decide whether it's worth building on.

Where It Goes From Here

TalesMUD is v0.1 and the core is solid. The things I want to build next:

  • NPC AI state machine — patrol, flee, conversation-triggered behaviour
  • Party system — grouped players, shared XP, group combat
  • Crafting system — item creation from components
  • Procedural dungeon generation — bringing dungeonsrv's work back in
  • Global event system — scripted world events, scheduled triggers
  • Faction system — reputation, faction-gated content
  • Mobile client — UI elements (skill bar, directional pad) mapped to text commands under the hood

If any of that sounds interesting — the code, the content, the ideas — I'd genuinely love contributors. Whether that's opening issues, fixing bugs, writing a zone, or building your own world and showing it off.

The source is at github.com/TalesMUD/talesmud. Follow progress on X (@atla_) or GitHub (@atla).

Start with the Getting Started guide if you want to run it. Or just play Veilspan first.

— atla