Wartable
"Modern problems require modern solutions" – Dave Chappelle
Note: I have a demo online here. Check it out!
I started playing Dungeons & Dragons in 2018. A friend introduced me to it, and game sessions became increasingly frequent. The game is at its most fun when played in the presence of all the other players: we communicate more clearly, the game is more immersive, and the jokes land better.
In 2020, this obviously became more difficult, and we started playing remotely. In the past, some of us would occasionally play remotely, and this was easily solved with a quick video call. But now, the interactivity is significantly reduced, and we needed to find alternatives.
There are some tools. Some paid, and some not. But none of them felt ideal to us. Well, I'd been meaning to try out Three.JS, and by making a tool for our specific uses, we could get a tailored (free) solution. And so Wartable was born.
All of the main features are there. The players are able to create a new session, and have a lot of customization options. They are able to import their chosen character models into the game, and build the layout of a given situation. The tabletop is oriented towards combat, but it can also be used to establish any scene.
The tabletop also includes a ruler to calculate distance in the field, it lets you set a map overlay image, and you can even add fog of war to hide content from the players.
In terms of implementation, the stack I chose was React (with TypeScript) for the frontend, with Phoenix (for Elixir) for the backend. To build the 3D app, I used Three.JS, making use of react-three-fiber
as an abstraction for it in React.
For communication, I decided to use GraphQL, since I had a very specific feature in mind that makes implementing the tabletop far easier than it would be otherwise. GraphQL offers the Subscriptions feature. It allows the client (in this project, Apollo Client) to make a persistent query to the server. It requests that data once, and establishes a connection that receives any update regarding the chosen topic.
This was perfect for an app whose data needed to be constantly synchronized between all participants. So the tabletop simply establishes a subscription to the game session (the topic), requesting the game data. Whenever a player updates the session data, the subscription is triggered, and this new data is broadcast to the entire group. This makes use of WebSockets which, of course, I could have used directly to implement this behaviour, but the document-based nature of GraphQL fit the purpose nicely.
I initially set out to build the app without React, using only Three.JS. However, after starting the work on GraphQL subscriptions, it quickly became clear that using React was the right approach for this project. The app subscribes to a specific, shared piece of data, the Game Session. And as mentioned, this game session is kept constantly up-to-date. This, combined with the prop-based hierarchy of React, makes the use of this data much simpler. It simply flows down the tree, and each component reacts to that data as it's updated in the subscription.
Work is still ongoing, and there are plenty of ideas for new features, but the app is already being used in our sessions and really helps visualize the game. That said, Dungeons & Dragons is a game that's supposed to live in the player's mind, much like a book, so the goal is to build something that only helps us build that picture, not replace it.