I’m (still) obsessed with Twine. I love that it makes it easy for regular people to make interactive stories and videogames. I love that it publishes to standard web formats like HTML, CSS, and JavaScript. I love that it’s been embraced by outsiders and badasses of all stripes. Maybe most of all, I love that it gives English undergrads a really good reason to learn some coding and programming.
Here are some guides I’ve put together for my students in ENGL 563, “Introduction to Digital Humanities,” to get them started with Twine. These guides assume some basic familiarity with HTML and CSS. If you don’t have this, I’d recommend checking out my Total Beginner’s Guide to HTML + CSS (or any one of the countless introductions to these topics available online.)
For now, I have four guides:
Note: If you’re looking for my older guides to Twine 2.0, they now live here.
1. Passages and Links
This guide explains what a passage is in Twine and how to create links between them. These instructions apply to any story format in Twine, including the default Twine 2.1 format, Harlowe, and my preferred story format, SugarCube 2.
Download PDF Version: Getting Started with Twine
The concept of a passage
Twine games are made up of “passages” — discrete chunks of texts. (In classical hypertext theory, these are called “lexias.”) Playing a Twine game involves moving from one passage to another. Passages have two elements: a name and content. The passage name is never shown to the player; it’s just used behind the scenes to guide the reader on their path through the game. The content, on the other hand, is what the user sees when they reach that passage of the game.
Making links
To make a Twine game, all you need to know is how to make links between passages. Twine makes this pretty easy. While editing a passage, create links with [[double square brackets]]. For example,
You are in a room with two doors. You can either enter [[the door on the left]] or [[the door on the right]].
Twine is smart and will automatically create two new passages to match what you’ve typed, one called “the door on the left” and one called “the door on the right.” Players of your game will be able to click on the words between the brackets, which will bring them to the corresponding passages. If you would like simpler passage names, you can use | (the character you get when you type Shift-\). For instance, you could type,
You are in a room with two doors. You can either enter [[the door on the left|leftdoor]] or [[the door on the right|rightdoor]].
Here, within the [[double square brackets]], the text before the | is what the reader sees and clicks on, and the text after the | is the name of the passage you’re linking to. Twine will create links to passages called leftdoor and rightdoor, which are slightly easier to work with than the unwieldy longer names.
There are lots of ways to make your Twine game look better (with CSS) or behave more like a game (by adding variables and doing some programming). But even if all you do is make a bunch passages tied together with links, you’ve totally made a Twine game — don’t let anyone tell you any differently!
2. Making Your Game Look Awesome with CSS
This guide explains how to use CSS to change the appearance of your Twine 2.1 game. All these instructions are based on the SugarCube 2 story format. Before beginning, make sure that your Twine game is set up for the SugarCube format. To do so, click on the name of your story in its main “story map” view. Select “Change Story Format” and check the box next to “SugarCube 2.x” This guide was designed for my students, and assumes some familiarity with HTML and CSS.
Download PDF Version: Making Your Twine Game Look Awesome with CSS
Remembering the basics
One of the things I love about Twine is that it publishes to standard web formats. It uses HTML for content, CSS for presentation, and JavaScript for anything programming-related. Because it uses these standard formats, your game can be played on basically every computer, phone, tablet, etc.
By default, Twine games in SugarCube look pretty awful. That should motivate you to put your own personal visual stamp on your game. Good news: since you already know some CSS, this is pretty easy.
To edit a Twine story’s CSS, click on the name your story from its main “story map” screen, then click on “Edit Story Stylesheet.” This will load a screen that is just a plain old (empty) CSS file.
Changing default settings
Since Twine games are just regular HTML files, it shouldn’t come as much of a surprise that you change the default appearance of most things in your game by styling the body element (the highest-level element in the HTML “document tree.”)
Adding the following code, for instance, would change the background color to white, make the default color dark grey, change the default font to Futura, and make the default font size a little bigger:
body { background-color: white; color: darkgrey; font-family: Futura,Impact,Helvetica,sans-serif; font-size: 125%; }
Again unsurprisingly, changing the color and behavior of links is achieved by styling the a element, HTML’s element for links:
a { color: red; } a:hover { color: crimson; text-decoration: none; border-bottom: 4px solid crimson; }
Changing the appearance of individual passages
Okay, so that changes the default settings for your whole game. But what if you want only a particular passage to have its own background color, or its own special font?
Again, Twine’s the best, and it makes it pretty easy. The first thing you need to do is open the passage you want to do something special with. Right underneath the passage name is an option that says +tag. Click on it to add a tag of your choosing. For instance, let’s say we want to add a tag called “hooray” for a particularly happy passage. Write in the word hooray and click on the checkmark.
Now we need to create a set of instructions for your web browser to follow when it displays this passage. To do so, we go back to to the “Edit Story Stylesheet” page and create a CSS class with a name matching the “tag” we inserted above. In this case, we make a class called hooray (remember, in CSS, class names have to be preceded by a period):
.hooray { background-color: pink; color: cornflowerblue; font-size: 200%; }
Now when your player gets to this passage, they will be met by a pink background and big blue text.
Hiding the sidebar
If, like me, you’re not fond of the default sidebar in SugarCube games, you can hide it pretty easily. Just enter the following code into your story’s CSS file.
#ui-bar { display: none; }
(SugarCube puts the sidebar into an HTML div with the id of ui-bar. This CSS instruction just tells your browser not to display that div.)
Since by default your story makes room for the sidebar, you will also want to add the following code to provide a more sensible margin:
#story { margin-left: 3.5em; }
Adding your own HTML and styling it with CSS
As you can see, Twine does quite a bit of hand-holding. You don’t need to enter your own HTML code for paragraphs, for instance: it puts in
s for you. But if you’re not happy with the way Twine is inserting HTML in your game, you can enter your own HTML code right into a passage.
For instance, you might want to have a spooky effect where text disappears if a user mouses over it. You could do that by sticking your own HTML div element into a Twine passage and styling it in CSS.
For instance, you might have a passage that says the following.
There is a spooky UFO in the sky. <div class="aliens">When you look at it, it disappears.</div> But you’re sure it’s there.
You could then add a few lines to your story’s CSS file in which you style this div’s aliens class to make it disappear when the user’s mouse hovers over the element.
.aliens:hover { opacity: 0; transition: 1s all ease; }
This HTML and CSS code would then work together to make the words “When you look at it, it disappears” disappear when the user’s cursor hovers over them, by gradually transitioning the opacity of the aliens div to zero over a span of one second.
You now know everything you need to know to create a fully customized visual experience in your Twine game. Go nuts!
3. Adding Images and Music
This guide explains how to add images and music to your Twine 2.1 game, and also how to design a folder structure and use relative links. Before beginning, make sure that your Twine 2.1 game is set up for the SugarCube 2 format. To do so, click on the name of your story in its main “story map” view. Select “Change Story Format” and check the box next to “SugarCube 2.x.” Note: this guide assumes some familiarity with HTML and CSS.
Download PDF version: Adding Images and Music
Adding a photo or video from the web
Adding media to your Twine game is as easy as adding HTML tags. Let’s say that you want to add a picture of a spooky hallway to the first passage of your game about being stuck in a hallway. All you would need to do is search for “hallway” on Google, refine to Images, find an image you like, and then click on “View Image.” Now the image will be displayed in your browser, and its URL will be in the address bar. All you need to do is grab its URL by using “Copy.”
Now you have all of the information you need to insert this image into your Twine game. Let’s add an HTML img tag right above the existing content in the passage:
<img src="https://vignette1.wikia.nocookie.net/thestanleyparable/images/6/60/Two_Doors_Room.jpg" alt="A photo of a hallway and two doors" /> You are in a hallway. You see two doors: [[the door on the left]] and the [[the door on the right]].
Good coding practice requires that you enter an alt= tag to describe the content of your image in words. Otherwise, this is all very straightforward. There you have it: there’s an image in your game.
You could just as easily insert a video from YouTube into your game. Just find the video you want to insert, click on “Share” under the video, select “Embed,” and copy the HTML code into your game. There you have it: there’s a video in your game.
Building a folder structure
Okay, that works — but it’s not ideal. First of all, if you worked this way, you’d probably need to rely on images made by other people — things already on the web, rather than your own original content designed just for the game. Second, let’s say you release your brilliant game, and then the link to your image goes dead. Now you’ve got an unsightly missing image in your game. Worse yet, imagine that it turns out the image you grabbed off the web is under copyright, and you get an angry letter from the copyright holder’s lawyer.
The way to get total creative control over your game is to design it in a folder structure you’ve created yourself. Let’s say, for example, that I make a folder called “Hallway Game” somewhere on my computer’s hard drive. This is going to be where my game and all of its media assets (images, audio tracks, etc.) are going to live. In the main hallwaygame folder, I’m going to put the game itself, which I’ll plan on calling “Hallway Game.html” (remember, Twine games publish as HTML files).
Now within the “Hallway Game” folder, I’m going to make a subfolder called images, which is where I’ll put all the images for my game. Let’s say I’ve made my own original image of a hallway with two doors at the end. I’ll save that image as hallway.jpg and put it in the images subfolder I’ve just created.
Now, rather than using full URL to a file on the web, I’m going to use what is called a relative link. Rather that specifying where the image is on the web, I’m going to specify where the image is in relation to the main Twine file (Hallway Game.html). I know exactly where hallway.jpg is relative to hallwaygame.html, since I’ve placed it into my very own folder structure: it’s in a subfolder called images. The way of representing that as a relative path in HTML is as follows: images/hallway.jpg
So let’s put that relative path into my previous passage as the src of my img tag.
<img src="images/hallway.jpg" alt="A photo of a hallway and two doors" /> You are in a hallway. You see two doors: [[the door on the left]] and the [[the door on the right]].
If you press the Play button in Twine, you’ll see — uh oh! — that the image doesn’t appear. That’s because when you press Play in Twine, you’re just seeing a kind of preview of your game. Where this “preview” exists is a tricky question. It’s sort of in a netherworld. It’s not published on the web for all to see; and while it’s somewhere on your computer, it’s not in a place that you can usefully access. So let’s bring the Twine game out of this netherworld and put it somewhere concrete. We do this by clicking on the story name from the main “story map” view and selecting “Publish to File.” Excellent: now let’s save our game as “Hallway Game.html” in the folder we created for it.
Now, let’s leave Twine for a moment. Let’s go to the folder where we saved “Hallway Game.html” and double click on it. It will open up in a web browser — and if you’ve entered your img tag correctly, your image will display.
Now collect a bunch more images for your game, and save them all in the images subfolder. Wherever you want them to appear in your game, use img tags with relative paths pointing to images/. Now your Twine game is all in one place — all contained within the hallwaygame folder. You could now upload this folder onto a webserver and it would display just as well as it does on your own computer. (Since relative paths are, well, relative, they don’t care whether they’re on your computer or on the web — all they care about is how to get from one place to another, and whether you’re on the web or on your own computer, the way of getting from “Hallway Game.html” to “hallway.jpg” is the same: look into the subfolder images, and it will be there.
Adding music
In theory, there is nothing special about adding music. You could just use the standard HTML tags for adding music. In practice, though, SugarCube 2 has a much simpler way to add music — a set of so-called “macros” that make working with music a breeze.
The first thing we need to get some music (.mp3 format works best; and don’t break any laws if you’re planning on hosting your game publicly — remember the lawyers!). Next, as with images, we need to figure out where we’ll store the music. Like we did with our images, let’s put all of our music into its own subfolder of the main hallwaygame folder. Let’s call this subfolder music.
SugarCube’s audio macros work in two steps. First, you need to load the songs and give them unique names. Next, when you’re ready to actually play the song, or pause the song, or fade the song out, you insert a different macro in the particular passage of your story where you want this to happen.
To load the songs, we’re going to create a new passage called StoryInit. This is a special passage that SugarCube treats in a special way: it executes all the commands in this passage before showing the player the first passage of the game. StoryInit isn’t linked to any other passages, because it isn’t part of the story. It’s just a place for doing mundane business related to the story. Here, we’ll use it to load songs.
Okay, so let’s make a passage called StoryInit and write in the following code:
<<cacheaudio "mainsong" "music/dauphin.mp3">> <<cacheaudio "happysong" "music/henry.mp3">>
The first line creates an “audio asset” named main song (though you can call it whatever you want) out of an audio file called dauphin.mp3 that is located in the music subfolder relative to “Hallway Game.html”. The second line creates a second audio asset called happysong out of a file called henry.mp3 that we’ve put in this same folder.
Now that our songs are loaded, let’s do something with them! Let’s say we want mainsong to start playing right away as soon as our player starts the game. All we need to do is add the following code into the first passage:
<<audio mainsong play>>
This line invokes SugarCube’s audio macro, then specifies the name of the loaded song we want to play (mainsong, created in StoryInit), and then specifies an action (play starts playing the song).
If you hit “Play” within Twine, you’ll notice that this isn’t working yet. Well, of course it isn’t working! We need to bring our Twine game out of the netherworld and use the “Publish to File” feature to save it as a concrete HTML file in the “Hallway Game” folder — its true home, where all its media assets are located! — before it will start working. If you do that, it you’ll hear your song.
Now let’s say that when your player gets to the “win” screen, you want to reward them with a happy song. Placing the following lines of code into that “winning” passage will fade out mainsong and fade in happysong, the other song we created in StoryInit
<<audio mainsong stop>> <<audio happysong play>>
One you again publish your game to the “Hallway Game” folder, you’ll find that you now have a very advanced Twine game, complete with a soundtrack that adapts to the action!
Next, you will want to check out the full list of SugarCube 2.x audio commands (it can do a lot more than just play and stop!).
4. Variables and Programming
This guide explains how to use variables and do basic programming in Twine 2.1. All these instructions are based on the SugarCube 2 story format. Before beginning, make sure that your Twine 2.1 game is set up for the SugarCube 2 format. To do so, click on the name of your story in its main “story map” view. Select “Change Story Format” and check the box next to “Sugarcube 2.x”
Download PDF Version: Programming in Twine
What is a variable?
A variable is container whose contents can be changed. (It gets its name from the fact that its contents are “variable.”) Think of it as an envelope. You might put a piece of paper into the envelope that says “Adam.” You might put a piece of paper into it that says 9. You might put an entire novel into it.
Variables have names and values. The value of a variable is the “content” described above — the word “Adam,” or the number 9, or the entire novel. The name is just the shorthand that Twine will use to access whatever is in it. You have to decide on the variable’s name, but you can call it whatever you want. The only rule is that Twine variables always need to start with a dollar sign ($). To bring a variable to life, use SugarCube’s <<set>> command, which does two things: creates a variable with a certain name, and gives it its initial “value.”
<<set $myvariable to "Adam">> <<set $myothervariable to 99>> <<set $yetanother to true>>
These are the three main types of variables might want to make: text (aka “strings”), numbers (aka “numeric” variables), and true/false (aka “booleans”). Notice that you need to put quotation marks around the contents of text variables. Don’t use quotes for numbers or for true/false variables.
Application #1: Using a key in your game
Let’s say that you’re making a game about escaping from a castle. In order to be able to exit the castle, your player needs to find the key to the door. This key is hidden in some obscure passage of your game; you’ve made it deliberately hard to find.
You’ll want a variable called something like $hasKey which will take one of two values: false when the player doesn’t have it, and true when she finds it.
By default, the player doesn’t have the key. So in the first passage of your game, you’ll want to create your variable, and set its to false, like this:
<<set $hasKey to false>>
In the passage when your reader enters the hidden room and discovers the key, you’ll want to have set the value of $hasKey to true. You can do that by putting the following line of code into that passage:
<<set $hasKey to true>>
(Note that <<set>> can create variables — but if the variable already exists, it just modifies the value of the variable.)
Okay, so now imagine we’re in the passage of your game where the player has finally reached the main door of the castle and is trying to escape. If they have the key, they can escape. If they don’t, they can’t. To implement this, you could use a SugarCube conditional statement, like this:
<<if $hasKey is true>>You insert your key into the door and it opens. You [[walk through the door|outside]]. <<elseif $hasKey is false>>You try to open the door, but it's locked, and it won't budge. You'll need to [[keep looking for the key|start]]. <</if>>
Twine begins by evaluating the first line of the if statement; if that’s not true, it looks at the first elseif line, then looks at the rest of the elseif lines (if there are any more), and then stops working when it reaches <</if>>, which means that the if statement is over. In addition to if and elseif, you can also write else, which just means “If none of the if or elseif conditions are met, then do this.) Also, note that if you’re working with numbers, you can use conditional operators like gt (“greater than”) and lt (“less than”) instead of just is.
What this all means is the following. First, Twine will check whether the value of $hasKey is true. If it is, it will display the text “You insert your key into the door and it opens” and give the user the option to click on a link to a passage where they’re outside the castle. If $hasKey isn’t true, Twine won’t display that text to the user, and the user won’t be able to click on that link. Now, Twine will evaluate the next possibility. Here it will evaluate whether $hasKey is false. If it’s false (which is it by default, since we set that as its initial value in the opening passage), then Twine will display the text “You try to open the door, but it’s locked, and it won’t budge,” and the only option will be to click on a link that takes them back to the start of the game, to re-start their search for that obscure passage where $hasKey is set to true.
Application #2: Checking a player’s name
Let’s say you want to make a game in which you ask for a player’s name, and then give some customized feedback if you recognize it.
On your first passage, use SugarCube’s built-in code for displaying a text box and sticking whatever the player writes into a variable:
Enter your name: <<textbox "$name" "">> When you're ready, click [[here]].
This code specifies that whatever the player enters into the text box will be stored in a variable called $name (the “” just means that there is no default text in the box — if you wrote “Enter your name here” in that space, the text box would initially show up with “Enter your name here” written in it.)
Now, on the next page, you could make it so that your game displays a special message if someone has entered their name as “Adam.”
<<if $name is "Adam">>Hey, your name's Adam! So is mine! <<else>>Hi, $name. <</if>>
Twine will only display “Hey, your name’s Adam! So is mine!” if the variable $name is equal to “Adam”. Otherwise — <<else>> — it just will say “Hi,” and repeat the person’s name back to her (yes, this is a cool thing about variables. If you write the variable name into a regular span of text, Twine will replace it with the value of the variable when it actually shows it to the player.)
Application #3: Recording a player’s “happiness”
Let’s say you want your game to record a running tally of how “happy” your player is. You could do this with a numeric variable. For instance, at the beginning of your game, you could include:
<<set $happiness to 0>>
Then, whenever something happens to make your player happy, you could include this line:
<<set $happiness to $happiness + 1>>
If the player’s happiness level is zero going in to this passage, this line of code will set it to 1 (0 + 1 = 1). If the player’s happiness level is 3 going in, this line of code will set it to 4 (3 + 1 = 4). The reason you don’t want this line to be <<set $happiness to 1>> is that this would erase any “running tally” you’ve got going, and just set the value of happiness to 1, regardless of how happy your player was before stumbling into this particular passage.
When something happens to make your player unhappy, you could include this line of code:
<<set $happiness to $happiness - 1>>
Later on, let’s say that your player gets a phone call from a friend. If their happiness level is above a certain threshold, they decide to go out for ice cream. If their happiness level is below this threshold, they don’t pick up the phone and stay inside. You might code this as follows:
<<if $happiness gte 5>>You pick up the phone and she asks you out for ice cream and you [[totally go]]. <<else>>You don’t feel like picking up. I guess you’ll never know what she wanted to ask you about. You [[stay at home]]. <</if>>
Here, if your $happiness variable has a value of 5 or higher (gte is SugarCube-speak for “greater than or equal to”), your player will get the chance to navigate to the ice cream passage. Otherwise — <<else>> — their only option is to proceed to the “stay at home” passage.
These are just a few examples to get you started. If you get excited by this, you will want to check out this full list of SugarCube 2.x macros.
That’s it! Now go forth and make awesome Twine games!!!