Unfold Studio
Start writing
AI Writing Contest
About

Part 2: Weave

So far, we've been building branched stories in the simplest way, with "options" that link to "pages".

But this requires us to uniquely name every destination in the story, which can slow down writing and discourage minor branching.

ink has a much more powerful syntax available, designed for simplifying story flows which have an always-forwards direction (as most stories do, and most computer programs don't).

This format is called "weave", and its built out of the basic content/option syntax with two new features: the gather mark, -, and the nesting of choices and gathers.

1) Gathers

Gather points gather the flow back together

Let's go back to the first multi-choice example at the top of this document.

"What's that?" my master asked.
    *   "I am somewhat tired[."]," I repeated.
        "Really," he responded. "How deleterious."
    *   "Nothing, Monsieur!"[] I replied.
    *  "I said, this journey is appalling[."] and I want no more of it."
        "Ah," he replied, not unkindly. "I see you are feeling frustrated. Tomorrow, things will improve."

In a real game, all three of these options might well lead to the same conclusion - Monsieur Fogg leaves the room. We can do this using a gather, without the need to create any new knots, or add any diverts.

"What's that?" my master asked.
    *   "I am somewhat tired[."]," I repeated.
        "Really," he responded. "How deleterious."
    *   "Nothing, Monsieur!"[] I replied.
        "Very good, then."
    *  "I said, this journey is appalling[."] and I want no more of it."
    "Ah," he replied, not unkindly. "I see you are feeling frustrated. Tomorrow, things will improve."

-   With that Monsieur Fogg left the room.

This produces the following playthrough:

"What's that?" my master asked.

1: "I am somewhat tired."
2: "Nothing, Monsieur!"
3: "I said, this journey is appalling."

> 1
"I am somewhat tired," I repeated.
"Really," he responded. "How deleterious."
With that Monsieur Fogg left the room.

Options and gathers form chains of content

We can string these gather-and-branch sections together to make branchy sequences that always run forwards.

=== escape === 
I ran through the forest, the dogs snapping at my heels.

    *   I checked the jewels[] were still in my pocket, and the feel of them brought a spring to my step. <>

    *  I did not pause for breath[] but kept on running. <>

    *   I cheered with joy. <>

-   The road could not be much further! Mackie would have the engine running, and then I'd be safe.

    *   I reached the road and looked about[]. And would you believe it?
    *   I should interrupt to say Mackie is normally very reliable[]. He's never once let me down. Or rather, never once, previously to that night.

-   The road was empty. Mackie was nowhere to be seen.

This is the most basic kind of weave. The rest of this section details additional features that allow weaves to nest, contain side-tracks and diversions, divert within themselves, and above all, reference earlier choices to influence later ones.

The weave philsophy

Weaves are more than just a convenient encapsulation of branching flow; they're also a way to author more robust content. The escape example above has already four possible routes through, and a more complex sequence might have lots and lots more. Using normal diverts, one has to check the links by chasing the diverts from point to point and it's easy for errors to creep in.

With a weave, the flow is guaranteed to start at the top and "fall" to the bottom. Flow errors are impossible in a basic weave structure, and the output text can be easily skim read. That means there's no need to actually test all the branches in game to be sure they work as intended.

Weaves also allow for easy redrafting of choice-points; in particular, it's easy to break a sentence up and insert additional choices for variety or pacing reasons, without having to re-engineer any flow.

2) Nested Flow

The weaves shown above are quite simple, "flat" structures. Whatever the player does, they take the same number of turns to get from top to bottom. However, sometimes certain choices warrant a bit more depth or complexity.

For that, we allow weaves to nest.

This section comes with a warning. Nested weaves are very powerful and very compact, but they can take a bit of getting used to!

Options can be nested

Consider the following scene:

-   "Well, Poirot? Murder or suicide?"
*   "Murder!"
*   "Suicide!"
-   Ms. Christie lowered her manuscript a moment. The rest of the writing group sat, open-mouthed.

The first choice presented is "Murder!" or "Suicide!". If Poirot declares a suicide, there's no more to do, but in the case of murder, there's a follow-up question needed - who does he suspect?

We can add new options via a set of nested sub-choices. We tell the script that these new choices are "part of" another choice by using two asterisks, instead of just one.

-   "Well, Poirot? Murder or suicide?"
    *   "Murder!"
        "And who did it?"
        * *     "Detective-Inspector Japp!"
        * *     "Captain Hastings!"
        * *     "Myself!"
    *   "Suicide!"
    -   Mrs. Christie lowered her manuscript a moment. The rest of the writing group sat, open-mouthed.

(Note that it's good style to also indent the lines to show the nesting, but the compiler doesn't mind.)

And should we want to add new sub-options to the other route, we do that in similar fashion.

-   "Well, Poirot? Murder or suicide?"
    *   "Murder!"
        "And who did it?"
        * *     "Detective-Inspector Japp!"
        * *     "Captain Hastings!"
        * *     "Myself!"
    *   "Suicide!"
        "Really, Poirot? Are you quite sure?"
        * *     "Quite sure."
        * *     "It is perfectly obvious."
    -   Mrs. Christie lowered her manuscript a moment. The rest of the writing group sat, open-mouthed.

Now, that initial choice of accusation will lead to specific follow-up questions - but either way, the flow will come back together at the gather point, for Mrs. Christie's cameo appearance.

But what if we want a more extended sub-scene?

Gather points can be nested too

Sometimes, it's not a question of expanding the number of options, but having more than one additional beat of story. We can do this by nesting gather points as well as options.

-   "Well, Poirot? Murder or suicide?"
        *   "Murder!"
            "And who did it?"
            * *     "Detective-Inspector Japp!"
            * *     "Captain Hastings!"
            * *     "Myself!"
            - -     "You must be joking!"
            * *     "Mon ami, I am deadly serious."
            * *     "If only..."
        *   "Suicide!"
            "Really, Poirot? Are you quite sure?"
            * *     "Quite sure."
            * *     "It is perfectly obvious."
        -   Mrs. Christie lowered her manuscript a moment. The rest of the writing group sat, open-mouthed.

If the player chooses the "murder" option, they'll have two choices in a row on their sub-branch - a whole flat weave, just for them.

Advanced: What gathers do

Gathers are hopefully intuitive, but their behaviour is a little harder to put into words: in general, after an option has been taken, the story finds the next gather down that isn't on a lower level, and diverts to it.

The basic idea is this: options separate the paths of the story, and gathers bring them back together. (Hence the name, "weave"!)

You can nest as many levels are you like

Above, we used two levels of nesting; the main flow, and the sub-flow. But there's no limit to how many levels deep you can go.

-   "Tell us a tale, Captain!"
    *   "Very well, you sea-dogs. Here's a tale..."
        * *     "It was a dark and stormy night..." 
                * * *   "...and the crew were restless..." 
                        * * * *  "... and they said to their Captain..." 
                                * * * * *       "...Tell us a tale Captain!"
    *   "No, it's past your bed-time."
-   To a man, the crew began to yawn.

After a while, this sub-nesting gets hard to read and manipulate, so it's good style to divert away to a new stitch if a side-choice goes unwieldy.

But, in theory at least, you could write your entire story as a single weave.

Example: a conversation with nested nodes

Here's a longer example:

- I looked at Monsieur Fogg 
*   ... and I could contain myself no longer.
    'What is the purpose of our journey, Monsieur?'
    'A wager,' he replied.
    * *     'A wager!'[] I returned.
            He nodded. 
            * * *   'But surely that is foolishness!'
            * * *  'A most serious matter then!'
            - - -   He nodded again.
            * * *   'But can we win?'
                    'That is what we will endeavour to find out,' he answered.
            * * *   'A modest wager, I trust?'
                    'Twenty thousand pounds,' he replied, quite flatly.
            * * *   I asked nothing further of him then[.], and after a final, polite cough, he offered nothing more to me. <>
    * *     'Ah[.'],' I replied, uncertain what I thought.
    - -     After that, <>
*   ... but I said nothing[] and <> 
- we passed the day in silence.
- -> END

with a couple of possible playthroughs. A short one:

I looked at Monsieur Fogg

1: ... and I could contain myself no longer.
2: ... but I said nothing

> 2
... but I said nothing and we passed the day in silence.

and a longer one:

I looked at Monsieur Fogg

1: ... and I could contain myself no longer.
2: ... but I said nothing

> 1
... and I could contain myself no longer.
'What is the purpose of our journey, Monsieur?'
'A wager,' he replied.

1: 'A wager!'
2: 'Ah.'

> 1
'A wager!' I returned.
He nodded.

1: 'But surely that is foolishness!'
2: 'A most serious matter then!'

> 2
'A most serious matter then!'
He nodded again.

1: 'But can we win?'
2: 'A modest wager, I trust?'
3: I asked nothing further of him then.

> 2
'A modest wager, I trust?'
'Twenty thousand pounds,' he replied, quite flatly.
After that, we passed the day in silence.

Hopefully, this demonstrates the philosophy laid out above: that weaves offer a compact way to offer a lot of branching, a lot of choices, but with the guarantee of getting from beginning to end!

3) Tracking a Weave

Sometimes, the weave structure is sufficient. But when it's not, we need a bit more control.

Weaves are largely unaddressed

By default, lines of content in a weave don't have an address or label, which means they can't be diverted to, and they can't be tested for. In the most basic weave structure, choices vary the path the player takes through the weave and what they see, but once the weave is finished those choices and that path are forgotten.

But should we want to remember what the player has seen, we can - we add in labels where they're needed using the (label_name) syntax.

Gathers and options can be labelled

Gather points at any nested level can be labelled using brackets.

-  (top) 

Once labelled, gather points can be diverted to, or tested for in conditionals, just like knots and stitches. This means you can use previous decisions to alter later outcomes inside the weave, while still keeping all the advantages of a clear, reliable forward-flow.

Options can also be labelled, just like gather points, using brackets. Label brackets come before conditions in the line.

These addresses can be used in conditional tests, which can be useful for creating options unlocked by other options.

=== meet_guard ===
The guard frowns at you.

*   (greet) [Greet him]
    'Greetings.'
*   (get_out) 'Get out of my way[.'],' you tell the guard.

-   'Hmm,' replies the guard.

*   {greet}     'Having a nice day?' // only if you greeted him

*   'Hmm?'[] you reply.

*   {get_out} [Shove him aside]      // only if you threatened him
    You shove him sharply. He stares in reply, and draws his sword!
    -> fight_guard          // this route diverts out of the weave

-   'Mff,' the guard replies, and then offers you a paper bag. 'Toffee?'

Scope

Inside the same block of weave, you can simply use the label name; from outside the block you need a path, either to a different stitch within the same knot:

=== knot ===
= stitch_one 
    - (gatherpoint) Some content.
= stitch_two 
    *   {stitch_one.gatherpoint} Option

or pointing into another knot:

=== knot_one ===
-   (gather_one)
    * {knot_two.stitch_two.gather_two} Option

=== knot_two ===
= stitch_two 
    - (gather_two) 
        *   {knot_one.gather_one} Option

Advanced: all options can be labelled

In truth, all content in ink is a weave, even if there are no gathers in sight. That means you can label any option in the game with a bracket label, and then reference it using the addressing syntax. In particular, this means you can test which option a player took to reach a particular outcome.

=== fight_guard ===
...
= throw_something 
*   (rock) [Throw rock at guard] -> throw
*   (sand) [Throw sand at guard] -> throw

= throw
You hurl {throw_something.rock:a rock|a handful of sand} at the guard.

Advanced: Loops in a weave

Labelling allows us to create loops inside weaves. Here's a standard pattern for asking questions of an NPC.

- (opts)
    *   'Can I get a uniform from somewhere?'[] you ask the cheerful guard.
        'Sure. In the locker.' He grins. 'Don't think it'll fit you, though.'
    *   'Tell me about the security system.'
        'It's ancient,' the guard assures you. 'Old as coal.'
    *   'Are there dogs?'
        'Hundreds,' the guard answers, with a toothy grin. 'Hungry devils, too.'
    // We require the player to ask at least one question
    *   {loop} [Enough talking] 
        -> done
- (loop) 
    // loop a few times before the guard gets bored
    { -> opts | -> opts | }
    He scratches his head.
    'Well, can't stand around talking all day,' he declares. 
- (done)
    You thank the guard, and move away. 

Advanced: diverting to options

Options can also be diverted to: but the divert goes to the output of having chosen that choice, as though the choice had been chosen. So the content printed will ignore square bracketed text, and if the option is once-only, it will be marked as used up.

- (opts)
*   [Pull a face]
    You pull a face, and the soldier comes at you! -> shove

*   (shove) [Shove the guard aside] You shove the guard to one side, but he comes back swinging.

*   {shove} [Grapple and fight] -> fight_the_guard

-   -> opts

produces:

1: Pull a face
2: Shove the guard aside

> 1
You pull a face, and the soldier comes at you! You shove the guard to one side, but he comes back swinging.

1: Grapple and fight

>

Advanced: Gathers directly after an option

The following is valid, and frequently useful.

*   "Are you quite well, Monsieur?"[] I asked.
    - - (quitewell) "Quite well," he replied. 
*   "How did you do at the crossword, Monsieur?"[] I asked.
    -> quitewell 
*   I said nothing[] and neither did my Master.
-   We feel into companionable silence once more.

Note the level 2 gather point directly below the first option: there's nothing to gather here, really, but it gives us a handy place to divert the second option to.