Writing "Vault guard," a short interactive fiction story

Over the weekend, I wrote Vault guard, a short interactive fiction story about a vault, its guard, a man in black, a sword, a lunch, a tavern, and a treasure. I’ve never written anything in the IF genre before, so I wasn’t aware of the tooling that’s availableor rather, I should say I was aware, but couldn’t be bothered to install it and figure it out for a quick one-day authoring session, which includes Twine and others. This post, then, is about how I authored Vault guard in plain HTMLerr, Markdown — but it converted to HTML, and made it work as an IF story.

Light on <details>

The first thing I thought to try was to use HTML5’s <details> element, which is for text that can optionally show, well, details:

Like this (click me!) You can see the details of this section here. It can include arbitrary block-level content, including other details.

When I’m writing this post, here’s what I writeI’ll be adding little code snippets throughout this post, but you can also view the source for this and all the pages in this site by clicking the source link on the left sidebar:

I thought I could nest <details> within each other to allow the reader to branch the narrative, and it would’ve worked, except for two things:

  1. It was too hard to see which branches had been chosen, which hadn’t, and which were yet to be chosen
  2. There was no way to build a more complex relationship of branches — nesting <details> only allows for a descendent-tree-type structure, where each branch has one and only one parent, whereas true IF story-branches are able to have multiple parents

So I realized that I couldn’t use the <details> element for my storyI still haven’t been able to find a good use for this element, by the way, even though it seems like it’d be extremely useful..

Remembering pandoc

Then I remembered that I write this blog using Hakyll, which uses Pandoc under the hood to convert Markdownand a ton of other markup languages, to; it’s great software and I highly recommend it to HTML. And the great thing about Pandoc is that it has an option (--section-divs) to wrap each section (delineated by a heading) in an HTML <section> tag — and give those <section>s custom IDs and classes!

Remembering CSS

I also remembered that CSS has (with decent adoption) the :target pseudoclass, which denotes

a unique element (the target element) with an id matching the URL’s fragment. Mozilla Development Network

The upshot is that you can style elements that are explicitly linked to differently than other elements on the page, like having them displayed instead of hidden.

Working within the system

Hakyll builds a website by mapping a set of input files to a set of output files, transforming them in a variety of ways, such as running them through Pandoc and placing the generated HTML in templates. Pandoc’s Markdown has a great feature where the author can just include vanilla HTML in a file, and it’ll be passed through verbatim to the underlying templatevanilla Markdown allows this as well. So I just included a few inline CSS styles at the beginning of my filein my source, I minimized these little blocks to save space, and if I write any more, I’ll add them to my templates in Hakyll:

See, Pandoc, when run with --section-divs, not only gives the ID of the header as the ID of the section — it also sets each section’s class to the level of the header (i.e., a <h1> header will be class="level1", etc.). So the first two rules of CSS above first hide all level-two headers and their respective content, and then show the level-two sections that have been linked to.

Start button

I realized I needed a way to show the first section of the story, since it would be hidden unless linked to directly — and most URLs would just link to the bare page, not directly to the first fragment. So I set up a start button, a great big link that says BEGIN, linking to the firstThe link goes to the full page, instead of just the fragment, so that if someone clicks BEGIN from my index page, they won’t mess up the rest of the index. segmentThis method takes advantage of Pandoc’s fenced-div syntax. You could also use plain HTML.:

And I styled that button, including this with the other style at the top of the page:

Of course, now I had a new problem: a great big BEGIN link at the top of every page. Unfortunately, I couldn’t figure out a way to hide it automatically by just using CSS, so I had to use a bit of javascript:

Now my game could be played. There was just one more step: I had to write the damn thing!


WARNING: Spoilers ahead! Play the game first, if you don’t want to know how it ends before you do!

I began Vault guard with the title. It’s post number 6 of my year-long Moon photos series, where I pull a random title from a list of 400 AI-generated titles every day. I was pondering how to write something called Vault guard and I realized it could be an interesting IF story. So I began sketching out the (easier) tech-related bits, above, while writing the bare minimum of the story to test them on. I wrote the first two or three sections that way.

Soon, I realized that I’d need to actually sketch out, visually, the paths the story could take, or I’d get hopelessly lost in the branches. So I tore out a piece of paper and sketched what I had, and added where I could go.

A hand-drawn outline of the plot of “Vault guard”
A hand-drawn outline of the plot of Vault guard

Writing from the outline was much easier than trying to hold everything in my head (though I surprised myself with just how much did fit in there).

The rest of the story flowed from there, and the writing of it was much like the writing of a linear narrative.


There were two major differences, and so challenges, of writing this story as opposed to a traditional linear one: I had to make sure that loop-backs weren’t jarring and that all the branches closed.

For an example of the first challenge, there are a few Outside sections, where our Vault guard is just outside the antechamber to the Vault. They’re all pretty similar, but I had to make sure they would all work from wherever the reader could come to them from. If the reader had just gone outside after yielding to the man in black, for example, they shouldn’t be able to go back in and know, at least, that he’d be dead from the trap. Or if they met him outside when he first arrived to the Vault, then went to the Two Bucks, and then came back, they shouldn’t be able to meet him again.

The second challenge is exemplified in this Reddit exchange I had with a playtester. I’d gotten so busy finishing the story toward the end that I completely forgot to add a section! I’m really grateful to /u/evil_tugboat_capn for pointing out that issue.

Of course, I know the second challenge is mitigated by dedicated IF-authoring software, and I bet that programs like Twine have tools to help with the first. For my next story, I’m going to be looking into those tools to make it easier on myself.


Overall, writing an IF story was challenging, but like a fun challenging. I don’t write a lot of fiction, usually because it doesn’t really hold my interest — but the short scenes of IF and the nonlinear narrative allow me to be more associative, and dare I say, lyrical, which I really enjoy.

/u/evil_tugboat_capn told me that the IFComp is coming up this year, so I think I’m going to enter that (of course, I found out too late that Vault guard is ineligible, since it’s already published!) and see how I do.

Finally, writing it all by hand was actually pretty simple, and didn’t require I learn any new software. I’m continually impressed with the power Hakyll affords me, and how complex I can make a static webpage. I will try Twine and friends out (especially if I want to try making a parser-based IF game), but it’s also good to know that I can use plain Pandoc and CSS to get it done too. I’d just need to write a little helper script to check I don’t have any dead ends.