Planning out a new Text Adventure app
I used to start an app (I use the terms app/web app/site pretty interchangeably) with a vague concept then dive straight into code. I've since learned the more planning I do, the more things work out. Of course I can get stuck in planning mode and never get past it, but if I'm not motivated to move past planning mode it probably wasn't meant to be.
My planning involves creating rough flowcharts, data mapping, and a UI sketch. These are not done by making one then the next. It's an iterative process where updating one document makes me realise other documents need updating and so on. Only once I'm happy with them do I start to code.
The planning docs are in no way sacred, I'm happy to toss them or do something different once I get started, but having I find that having a plan at the start almost always makes the process run smoother. I mention the concept here, I'll briefly go through other aspects below.
Rough Flowcharts
There are a fair few quick flowcharts I created for this app. I'll put a couple up here to show how easy they are to make, and how it helps clarify my thinking.
I write code in VSCode or lately, Cursor. I'm a bit fan of _docs folder and including all my planning docs – written in Markdown as a plaintext file. For VS Code/Cursor I have the MermaidJS extension installed which lets me create simple flows straight in the Markdown document. Super easy to update and change. I can also show those charts easily on a site, so here they are.
A single room/location
Traditionally in Choose Your Own Adventure style Text Adventure, we open a page, read some text, then make a choice. A chart for that would be something like:
The markdown
flowchart TD enter --> text[read text] text --> east[go east] text --> west[go west]
Creates the chart
%%{init: {'theme':'neutral'}}%% flowchart TD enter --> text[read text] text --> east[go east] text --> west[go west]
Choosing West and East would take the reader to another page and cycle begins again. It ends when the player hits a resolution page.
I wanted to add game elements, like locked doors, battles, traps, puzzles, and so forth. They added a lot of complexity. My initial chart for a location was:
The markdown
flowchart TD enter --> text[page text] text --> picture{picture?} text --> outbound{outbound?} text --> creature(((creature))) text --> trap(((trap))) text --> back[go back] text --> puzzle(((puzzle))) text --> fin trap --> fin trap --> outbound puzzle -- solves --> outbound puzzle -- unsolved --> back picture -- yes --> show_picture(show picture) outbound -- choice --> back_d[go back] outbound -- choice --> show_N([show next area]) outbound -- choice --> locked(((locked door))) locked -- pick or smash --> show_N locked -- fail --> outbound creature --> outbound
Create the chart
%%{init: {'theme':'neutral'}}%% flowchart TD enter --> text[page text] text --> picture{picture?} text --> outbound{outbound?} text --> creature(((creature))) text --> trap(((trap))) text --> back[go back] text --> puzzle(((puzzle))) text --> fin trap --> fin trap --> outbound puzzle -- solves --> outbound puzzle -- unsolved --> back picture -- yes --> show_picture(show picture) outbound -- choice --> back_d[go back] outbound -- choice --> show_N([show next area]) outbound -- choice --> locked(((locked door))) locked -- pick or smash --> show_N locked -- fail --> outbound creature --> outbound creature --> fin
Simply thinking though charting the flow helps me think thorough the logic, and brings to my attention things I would have missed if I went straight into coding.
My next step is to look at each node on the chart and see if the node could do with more explanation via a flowchart. Here's what ended up behind the "trap" node after I thought about it, and why even a simple text adventure can get a bit complicated:
%%{init: {'theme':'neutral'}}%% flowchart TD text[page text] text --> check_traps{check for traps?} check_traps -- Yes --> find_trap{find trap} check_traps -- No --> had_trap{had trap?} had_trap -- Yes ---> kills_player{kills player?} had_trap -- No ---> show_next[Next area] find_trap -- Yes --> attempt_disarm{attempt disarm?} find_trap -- No --> had_trap attempt_disarm -- Yes --> disarm_success{disarm success?} attempt_disarm -- No --> text disarm_success -- No --> kills_player disarm_success -- Yes --> show_next[Next area] kills_player -- Yes --> player_die_trap[[player dead]] kills_player -- No --> show_next[show next area]
Phew! I go over the charts, digging in where I feel it's needed, until I think I have a good grasp on how the while app's login is going to flow.
Data / mapping
My next step is deciding what data will be needed, and who needs access to what data. Again, just writing down the data I think I need often leads me to discovering holes in the data, and realising things are more complicated than they initially looked.
Here's a couple of tables from my initial planning (again done in Markdown):
-
user
- name
- avatar_url
- has_many stories
-
story
- belongs to user
- has_many pages
- title
- thumbnail
-
page
- belongs to story
- has_many outbound
- has_many loots
- has_many creatures
- has_many traps
- has_many puzzles
- short code
- text (md)
- options (dynamic)
- search for traps
- talk to creature
- fight creature
- attempt to sneak past creature
I do this for every piece of data I can think of and dig in where needed. Any decent framework can be started with less – it's easy to add columns to tables with migrations
UI Sketch
I've used a great wireframing tool for years Balsamiq. It creates wireframes that feel hand drawn, meaning I don't get bogged down in minor details irrelevant to the planning. I sketch out pages, link between them, and can mock out an apps flow and UI. This lets me show other people and get feedback on creating a text adventure this way before I've written a single line of code.
The basics I needed to get started and provide enough to get feedback were:
User home page
New story page
Story map page (with story in progress)
Story page (after clicking on a node in the map)
Into the code!
I was now ready to start coding.
You probably notice I haven't mocked out actually showing playing a text adventure, which seems pretty important, but that's because I'm not concerned with it.
I know how the pages will look – the user creates pages in Markdown and can see how they look by previewing as they edit. And gameplay logic is pretty straight forward as I already have the flows done.
I like keeping these lightweight docs live throughout app development. I keep it all in the one Git repo so have one source of truth. And once the logic is mapped out, the code is easy to write.
At this stage I don't really worry about design or visuals, it's all about the flow of the logic through the stories. The lighter I can keep the weight as I develop, the less I have to worry about. As a solo dev this is exactly how I like to work.