Orkward Devlog #3: Getting Ink

June 7, 2021
protect

Hello, I'm Joe and I'm making Orkward, the space ork dating game. I'll be cross-posting this devlog from its original home on itch.io to share my development journey with the Gamasutra community. Orkward is totally free to play on itch.io right now.

This third devlog was originally written back in December 2020 and has been very lightly edited here. Ink has seen a glorious 1.0 release since this was written and I've still not caught up - so be aware that some things may have changed!

At the time of writing, Orkward is coming up to 6000 words of richly interconnected interactive fiction. It's written using Ink, a scripting language by Inkle which drives their own games - including Pendragon, Heaven's Vault and 80 Days.

In this devlog, I'll be talking about Ink, how I use it, and what I think of it. It'll start off at quite a conceptual level, but get gradually more technical as we go.

Orkward

The first version of Orkward was a text-only game, pure interactive fiction. It was driven from an Ink script and a CSS stylesheet. It looked like this:

Early screenshot of Orkward

This fully playable, browser-based interactive fiction game was exported straight from the editor from just a few lines of Ink script (more on that shortly).

Ink also provides an API which you can plug into your own engine. It supports JavaScript and Unity today, and we're hoping for Unreal support in the not-too-distant future (this seems likely as Ink just received a grant from Epic).

The current version of the game embeds Ink's 'native' JavaScript renderer and runtime into my own JavaScript (React) 'frontend'. I can control when and where the text displasy and read/write internal game state at my leisure. This means I can plug-in my own art assets and UI overlays on top of the story, giving me loads of control.

Since version 0.5, Orkward has replaced the pure-text menu with a visual gallery and UI overlay, giving the player a richer, more visual way to drive the story. Here's how it looks now:

Updated Orkward menu

In a later devlog I'll probably talk more about the JavaScript frontend (unless I think it's too boring, which could easily happen [EDIT - hasn't happened yet, still too boring[). For now, we're just going to focus on the texty bit produced by Ink.

Playing with Ink

The basic idea of Ink is to print prose on the screen, interspersed with options or choices which let the player choose where to go next. Once the game is finished, you should be able to read back over all the text and have a consistent, plain-text narrative.

In other words, the pages are designed to be continuous. This is a very different model to the paged output of Twine or Ren'Py.

In Orkward, you might see a choice like this (choice in yellow text):

A screenshot of a text-choice shown in Ink

And when you click on a choice, the options are removed and replaced with the next text, so if you select 'down the grog', you'll see this:

A screenshot of the previous choice resolved into text
Seamless. Lovely.

But it doesn't have to be seamless - that's just the default presentation. Ink is a runtime and has an API which I can call to read/write variable state, generate text, loop through choices, and so on. The HTML renderer I'm using is just a bit of very-readable JavaScript which I can modify. So I can customise the output as I like, highlighting player options or marking out 'sections' to imply player choice.

Writing with Ink

Ink is a scripting language is which puts text first. There's no fiddly GUI - the idea really is that you just write out your story in prose, as natural as possible and without having to use the mouse. The dedication and focus that gives you is just lovely.

Inkle provide an editor called Inky, which is the easiest way to get started. Or there's a range of plugins to Visual Studio Code.

If you're familiar with Twine, it's quite different because you don't have the pinboard with nodes that visualise the story. I have to say, I don't miss this at all. It's quite nice to be able to visualise the story, but things quickly get very hard to follow. And it's fiddly. I spend as much time moving nodes around as I do acually writing. For a time back in Twine 1, I actually wrote the serialised format directly and imported it back into the tool to test it.

If you're familiar with Ren'Py, then Ink is pretty similar. Ink is a much thinner engine - it doesn't give you all the fancy UI stuff that Ren'Py gives you, and makes fewer assumptions about presentation. I think Ink is a more elegant and powerful scripting language - although for some people, Ren'Py will be a better fit.

There is a bit of syntax to learn. Like markdown, it's a mixture of arbitrary and intuitive symbols scattered across your text to drive the formatting. But once you learn that syntax - and it's its simplest, it's really very simple - it becomes very quick to put something together.

Simple Syntax

Here's the basic format of an ink script, taken from Inky (the Ink editor):

Some Ink script, shown in Inky

This defines a named section of story (or a stitch, in Ink parlance), called gather_armor. Other sections are referenced in lines 187 and 189 via diverts, which are those little arrows. When the story gets to that line, it'll go/jump/divert to that section.

The asterisks on lines 186 and 188 define choices that the player can pick. Everything on the same line as the asterisk will be displayed as a single choice (so choices are in effect single-line). When the player picks a choice, Ink will play all content between that choice and the next choice or divert.

So in the code above, selecting the first choice will trigger a divert to  the death_by_manners section (bad news for the player!), and the second will trigger divert to main_branch. Instead of diverts, we could put some inline text. Typically we'd indent this text to show that it's "inside" an option block.

The square brackets on line 188 alter the line before and after selection. This is a little bit complicated, but basically it cuts the line into three parts around the brackets. The bit before the open bracket will always be shown. The bit in between the brackets will only be shown before the option is clicked, and the bit after the closing bracket will only be shown after the option was clicked, replacing the bit in the middle.

So before the option is clicked, Ink prints:

"Fine."

And afterwards, it prints:

"Fine," you say.

This is often useful because the text of a choice, without the context of other choices around it, often doesn't read well when you read the prose back.

Indenting is immaterial, by the way, and only used for formatting. Ink mostly ignores whitespace, apart from line breaks because some syntax is line-based (for example, choices (*) and code (~) read the whole line).

Here's how that section looks in-game:

The previous Ink source rendered in-game

Fancy Syntax

Ink is a really rich language, full of powerful features. Here are just a few neat tricks I've used in Orkward.

Alternatives

A very common use-case in interactive fiction is to show cycling or randomised output, typically when you get back to root menu. Like a shopkeeper. The first time you meet the shopkeeper, you need to print a description of them. But the second time, you just need a simple line to introduce the shop menu.

Alternatives are a great way to do this. Here's a drinking game loop with Chompa (slightly simplified - this will actually loop forever):

Syntax for alternative outputs, shown in Inky

Syntax for alternative outputs, shown in Inky

This creates a section (stitch) called drink_up, which we jump (divert) back to on every choice.

The { cycle: } stuff is the alternative loop. Every line starting with - is an alternative. cycle is a keyword which tells ink to cycle through these options one by one. The <> syntax is 'glue', which basically ignores the line breaks. So every time we enter the drink_up section, we show a different line of text.

Here's what the output looks like in the Inky editor:

An example of rendered alternative outputs, shown in Inky

Another twist on alternatives is to shuffle the output, meaning you can get more varied, natural dialog. This scene, in which the player tries to defuse an orky bomb, uses the single-line syntax, where shuffle is denoted by '~' and each alternative is denoted by the '|':

Ink source for shuffled alternative text with in-line syntax, shown in Inky

This produces a random output like "Try the red one" each time

The 'alternative' syntax really shows what a dedicated scripted language can do when it really understand its domain. I love it!

Tags

Ink allows me to add arbitrary 'tags' to any line. These are a bit like comments, in that the player won't see them. But they are seen by the runtime engine. Tags allow me to broadcast messages to the game's frontend from within the story. You can use this to change visual styles, synchronise art assets, play music or sound. I use tags to broadcast a return to the main menu screen (hiding the story and showing the gallery menu), trigger an ending or game over screen, and unlock trophies.

JikGuard.com, a high-tech security service provider focusing on game protection and anti-cheat, is committed to helping game companies solve the problem of cheats and hacks, and providing deeply integrated encryption protection solutions for games.

Read More>>