Cerebellar is now open source

Cerebellar logo

Cerebellar, our Train Jam game, was built in Unity using ink. ink is the scripting language behind 80 Days and the Sorcery! series, and was made open source last month by its developer Inkle.

We’ve decided to share the source to Cerebellar as an example to anyone who’s interested in seeing how ink integrates with Unity. You can check out the full source on Github here; the following is a quick rundown of how we integrated ink into our project.

Cerebellar is a game jam game, and so our use of ink is quite basic – the game contains several scenes (each of which is a “knot” – a section of content in ink) that are presented to the players sequentially. (I say “players” because it is a two player game – each player plays as a character, either the Rigger or the Architect.)

However, in order to have our two characters’ stories play out simultaneously and interact with each other, we had to do a couple of non-standard things, like have two ink stories running simultaneously1. When we mentioned having done this to the Inkle crew at GDC after the jam, Joe said he was pretty sure they had never thought of doing it before, and was surprised that it even worked.

We also set up some of our own functionality in ink to be able to synchronize the two stories that are playing out simultaneously; at certain points the two players need to have reached the same point in the story to continue onward. To do this, we implemented our own custom tag – a “sync” tag, which is just a line in the story that has the word “sync” on it.2

* [Sip beer.]

– sync

I drink to my misfortune.

Further on in the story, after the two characters undergo an operation to occupy the same physical space, both players now need to make choices together – you can either select the same option as your counterpart, or select a different option. In the back-end, this required us to be able to add some extra information onto the sync tag, so that in the code we know which option each player has selected.

* [Knock.] sync:knock_on_the_door
* [Open the door.] sync:open_the_door

After each player has selected an option, we need to route each players’ stories to one of six possible pieces of content – for each of the two options, there are three unique pieces of content3:

  • if both players agreed on that option,
  • if I chose this option but the other player didn’t,
  • or if the other player chose this option but I didn’t.

In this example the characters, now fused, are visiting the Rigger’s house. It’s from the Architect’s perspective, and shows the six possible pieces of content that the Architect can be presented, depending on what they and the Rigger have each selected.

= knock_on_the_door_we

We knock at the door.

-> knock_on_the_door_continue

= knock_on_the_door_i

I knock at the door.

-> knock_on_the_door_continue

= knock_on_the_door_they

I assume they’ll just open the door, but they knock instead. Is it locked? Did they forget their keys?

-> knock_on_the_door_continue

= open_the_door_we

We slide the door open.

-> open_the_door_continue

= open_the_door_i

I slide the door open.

-> open_the_door_continue

= open_the_door_they

They slide the door open.

-> open_the_door_continue

The above use of our sync functionality is one of the simplest in the game – it’s the first choice that your characters encounter once they’re merged. (For a more complex and interesting example, check out lines 1-52 of the Architect’s perspective when going to work with the Rigger here.) Since we had to get it done in time for the jam, it’s more verbose than it needs to be – in ink there are more elegant ways of doing text customization, and we could have reduced a lot of the repetition. However getting this set up didn’t take too long, and gave us the time we needed to write the story itself.

Other than our sync functionality, our use of ink is pretty standard and straightforward in our .ink story files. And similarly on the runtime side, the only non-standard thing we do is to instantiate multiple Ink.Story instances – other than that it’s fairly boilerplate. Our hope in making Cerebellar open source is that it can stand as an example for other people getting started with ink in Unity.

As well as using ink for Cerebellar, we have integrated it into the prototype for our as-yet-unannounced game, and we love the way that the structure of its language informs the writing process. It allows the writer to easily create branching choices in dialogue or situations, which then weave back together into a single narrative thread. This structure naturally affords a momentum to the scene, and the story, that a lot of traditional game narrative structures (such as dialogue trees or node-based webs) aren’t really suited for.

ink is a great foundation for telling interesting stories; we’d love for more designers and writers to try it out – we hope that Cerebellar’s source will be a useful resource for people interested in the practicalities of integration. If you want to find out more about ink, the Writing with ink tutorial is a great place to start. And if you’re digging through Cerebellar’s source files and have a question, feel free to ask it to us at info@ghostpattern.net.

  1. An ink “Story” is the runtime structure that handles the ink logic for processing a story – what sections have already been seen and how many times, where the player currently is in the story, and what their current options are.
  2. The “-” in the example is a gather, another piece of ink functionality. Read more about the ink language’s functionality in Writing with ink.
  3. In the case that the players select different options, the option that actually plays out is randomly selected.