Here are descriptions of recent software projects I'm allowed to discuss (i.e. non-professional work.)
GM Trainer is a sandbox environment for RPG Game Masters (GMs) to realistically practice spontaneous creativity. It uses LLMs to simulate human players' responses to the GM's descriptive narration, giving GMs a training ground to exercise critical skills like improvising descriptions, decisively answering player questions, and giving logical game-world responses to player actions.
![screenshot](https://private-user-images.githubusercontent.com/11641081/323745322-8df54159-4002-42bb-ae31-5d029cc03498.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjQyOTYyODcsIm5iZiI6MTcyNDI5NTk4NywicGF0aCI6Ii8xMTY0MTA4MS8zMjM3NDUzMjItOGRmNTQxNTktNDAwMi00MmJiLWFlMzEtNWQwMjljYzAzNDk4LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MjIlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODIyVDAzMDYyN1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWU1NWZlMTcwOTgwYTIzOTkzOGFjM2JmNTlmYzFjMjVmOTk2OGI4ZTgxMzU4NmE5NzBlNWJkMWI1MjU1NDNmNGImWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0._LfXFEDnmhrc5_iuEMKkhOuJ0C-ozUVlL3YnhU4y_Yw)
For my MSc research thesis, I researched, designed, and programmed ROLEPLAYINGGAME1, the first tabletop-RPG companion app to support runtime editing of game rules and content without stopping gameplay. My aims were to:
- Combine the flexibility of traditional RPGs with the complex, real-time processing of videogames by enabling game worlds and game rules to grow and change during use.
- Assess the viability of an all-in-one platform not only for playing and GMing RPGs, but also for designing them, because game designers' needs aren't met by existing apps.
ROLEPLAYINGGAME is a web application. To target the browser, I needed a way to evaluate game rules on the backend and frontend alike, for server-side validation and rule-sensitive UIs respectively. I avoided code duplication by implementing ROLEPLAYINGGAME in Clojure, which has production-grade compilers to both Java and JavaScript. This made >95% of my backend code portable to the frontend.
To efficiently make game state available to frontend clients, whenever a user action changed the game state, I sent a diff from the server to all clients. Having game state available on clients was necessary to keep information-rich UIs up to date. One of those UIs is shown below.
![The GM's Inspector, with a command and one parameter specified.](https://private-user-images.githubusercontent.com/11641081/320327319-2d412f53-fa5d-420f-9586-f89c9bd6ba50.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjQyOTYyODcsIm5iZiI6MTcyNDI5NTk4NywicGF0aCI6Ii8xMTY0MTA4MS8zMjAzMjczMTktMmQ0MTJmNTMtZmE1ZC00MjBmLTk1ODYtZjg5YzliZDZiYTUwLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MjIlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODIyVDAzMDYyN1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWJjMDg2ZWMzYmIwM2U3ZWUwOWMyMjRmN2U0MTBmZDk0MzhjYzg2NmZiZTk5NTA4ZTlmZjYzZDYwNTdmOGQ4MzUmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.EnYtwe3G318NFakgrAagZKvSX9yPQtghUPg4iDAEiyM)
The Inspector, part of the Game Master's UI, affords rapid, context-aware interaction with all game entities.
In this screenshot, a GM is using the Inspector: a context-sensitive menu for dispatching commands on in-game entities. For each command (like dislocate
), the parameters for which the character Arvak can slot into (like target-entity
) are dynamically discovered by introspection on Clojure functions. The GM can click any entity on any main UI screen to add it to the Inspector2.
My master's thesis grew out of my long-standing interest in implementing tabletop RPG systems in software. Before starting my MSc, I had already developed several Python tools for my own custom game system, including a pricing simulator for over 1,000 17th-century items, a program that generates characters' life stories based on their stats, and CLI tools for rapidly updating the game world during live gameplay.
![One vendor from a market price table from my homemade RPG app.](https://private-user-images.githubusercontent.com/11641081/320332572-5c7ee7a2-5c72-4cc0-8bf2-e6de5f93ba0b.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjQyOTYyODcsIm5iZiI6MTcyNDI5NTk4NywicGF0aCI6Ii8xMTY0MTA4MS8zMjAzMzI1NzItNWM3ZWU3YTItNWM3Mi00Y2MwLThiZjItZTZkZTVmOTNiYTBiLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MjIlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODIyVDAzMDYyN1omWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWQ1NjM4Mzc5Y2RkMWQyMzA4MDI2ZGU0ZDM5ODFjNGM4MzM4MmQ1ODBjYTg0YjZmODgwY2U4MGVkZjNhYjVkZjUmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.S4SlD2tWv2v7eltUHcIvDBpPhN6Pq2MRQhJ7ewSmHj8)
One of the tables created by the pricing simulator.
The pricing simulator brings depth, granularity, and logic to an aspect of RPGs that has never progressed beyond numbers made up on the spot. As an example of my dedication, here's an explanation of how it works.
The simulator inputs are encyclopedia data on the relative abundance of raw materials at real-life cities. Every city "exports" some fraction of its resources everywhere else, using an all-pairs shortest path network. We then determine raw material prices for each city: the more abundant, the cheaper the unit price.
Tens of thousands of calculations specify how raw materials transform into purchasable tradegoods, specifying quantities like the length and radius of a spear haft, the thickness of a clay pot, and the amount of wood needed to build a half-timbered house. Each tradegood is defined by a "recipe," which I create by researching 17th-century manufacturing. A recipe consists of raw materials and other, simpler recipes, so the set of recipes forms a directed forest. Summing the prices of a recipe's components gives the tradegoods's final player-facing price3.
I made the text adventure Ryan Quest as a surprise birthday present for my best friend from college, Ryan Wright. The player controls Ryan in a parody of his real life. After doing all the writing, coding, and user testing, I flew out to surprise him with the game in person.
Ryan Quest was written in Inform 7, an unusual programming language which is laser-focused on being good for creating interactive fiction.
Footnotes
-
An acronym for RPG Operation, Learning, and Execution Platform Laden with Advantages for Yielding Infinitely Nitty-Gritty Games that Allow Malleable Evolution. ↩
-
For instance, the exploration hex grid (partially shown above) would let the GM operate on characters, items, and individual hexes just by clicking. ↩
-
This explanation glosses over some complexities relevant to game design, but not to engineering; I'd be happy to discuss my work (and yours!) in more detail by email. ↩