Interactive Fiction Companion

Interactive Fiction Companion
Start here

Where is your story right now?

Be honest rather than optimistic. The wrong state gives you the wrong advice.

I cannot see your story from here — there is no analyser on this page reading your .ink file. You tell me where you are and I will tell you what to do next. Structure detection that genuinely looks at your manuscript is being built into the Workshop app, which is the only place that can honestly do it.

Already know what you are looking for?

State 1

Nothing yet

“What am I even making?”

You are here because there is no story yet. Good. This is the shortest state and the one people spend the longest dreading.

You do not need an idea. You need a skeleton.

An idea will not save you and a blank page will not give you one. What gets you moving is a structure that already runs, so that the first thing you do is decorate rather than invent. So take mine.

Paste this into the Workshop app. It runs the moment you paste it, so you have a working game before you have made a single decision. It also loops forever — every room eventually leads back to another room, and the ending loops right back to the start. That is by design. Don't fix the loop. Decorating it is the point: the structure is given to you free, and your creativity goes on top of it.

Ink
Welcome to The Nine Rooms!
-> room_1


=== room_1
You are in the first room. There is a door to the north.
+ Go north
    -> room_2
+ Sit Here
    -> room_1

=== room_2
You are in the Second Room.
There is a door to the south.
There is a door to the east.
There is a door to the west.
There is a door to the north.
+ Go north
    -> room_3
+ Go south
    -> room_1
+ Go east
    -> room_4
+ Go west
    -> room_5

=== room_3
You have entered the third room.
There is a door to the south.
There is a door to the north.
+ Go north
    -> room_6
+ Go south
    -> room_2

=== room_4
You have entered the fourth room.
There is a door to the west.
+ Go west
    -> room_2
+ Stay Here
    -> room_4

=== room_5
You have entered the fifth room.
There is a door to the east.
+ Go east
    -> room_2
+ Stay Here
    -> room_5

=== room_6
You have entered the sixth room.
There is a door to the south.
There is a door to the north.
There is a door to the west.
There is a door to the east.
+ Go north
    -> room_9
+ Go south
    -> room_3
+ Go east
    -> room_8
+ Go west
    -> room_7

=== room_7
You have entered the seventh room.
There is a door to the east.
+ Go east
    -> room_6
+ Stay Here
    -> room_7

=== room_8
You have entered the eighth room.
There is a door to the west.
+ Go west
    -> room_6
+ Stay Here
    -> room_8

=== room_9
This is the Final Room. There is no escape from here.
Make your choice:
+ Win the Game
    -> end_game
+ Stay Here
    -> room_9

=== end_game
You have won the game! Or have you?
-> room_1

What you are actually looking at

Two things, and that is genuinely all so far.

A knot is just a named section of your story. You mark it with ===. Think of knots like chapters or scenes. A divert sends the reader to a knot, and it looks like an arrow, ->. Think of -> as “go to.” That's all it means.

So a room is just a named place in the graph, and it can stand for anything you want it to. It doesn't have to be a dungeon — it can be outside, in a labyrinth, anywhere. It doesn't have to be places, it can be choices. It doesn't have to be choices, it can be events. It doesn't have to be choices made by the protagonist at all.

Three premises, if you want one handed to you

These are all mine, and you are welcome to them. Take one and stop deliberating.

The tavern

You walk into a dimly lit tavern. The bartender looks up. What'll it be?

Why it works: the reader is in a place, with a person, being asked a question, in three lines. Nothing needs explaining. You can start writing choices immediately.

Ink
=== tavern ===
You walk into a dimly lit tavern.
The bartender looks up.
What'll it be?
* Ale, please.
    The bartender slides a foamy mug your way.
    -> tavern
* Just water.
    The bartender raises an eyebrow but pours you a glass.
    -> tavern
* I'm not thirsty.
    The bartender shrugs and turns away.
    -> market

=== market ===
You step outside into the bright sun.
Stardew, but you're trapped?

You wake up, groggy, in an unfamiliar place. There are nine rooms and one of them is a greenhouse.

Why it works: it gives you a reason to grow things, which gives you numbers that climb, which is state before you have had to think about state. This is the Nine Rooms skeleton with a mood poured into it.

Ink
VAR has_key = false
VAR onion_seeds = 0
VAR onion_sprouts = 0

=== room_4
This is a greenhouse - there are many pots and soil here, and a cabinet with a lock on it.
{ onion_sprouts > 0: You see {onion_sprouts} onion sprouts. }
There is a door to the west.
+ Go west
    -> room_2
+ { has_key } Unlock the cabinet.
    There is a secret tunnel in the cabinet!
    -> room_7
+ { onion_seeds > 0 } Plant an onion seed
    ~ onion_sprouts = onion_sprouts + 1
    ~ onion_seeds = onion_seeds - 1
    You plant an onion seed
    -> room_4
The ferryman

The ferryman does not look up when you board.

Why it works: one character, one crossing, one thing you are tracking — whether he warms to you. Small enough to finish, and the whole thing is a single meaningful choice repeated.

Ink
VAR trust = 0

=== arrival
The ferryman does not look up when you board.
+ ["It's cold."]
    ~ trust = trust + 1
    "It is," he agrees, and something in him unlocks a notch.
    -> crossing
+ [Say nothing.]
    ~ trust = trust - 1
    The silence sets, like something cooling.
    -> crossing

=== crossing
The water goes by underneath, {trust > 0: companionably|like an argument you are losing}.
{trust > 0: He offers you his coat.|He does not offer you his coat.}
-> END
Decorate the rooms of the dungeon!

That is the assignment. Add descriptions of what is in the rooms. Don't add new rooms yet, don't add variables yet, don't restructure anything. Nine rooms, decorated, all the way through. Anything else is a way of not starting.

You are out of this state when

Your dungeon is yours. Every room says something only you would have written, and you have played it through at least once from the first room to the last.

Then you're in state 2.

State 2

It runs

“Why does it feel flat?”

It runs. You played it. And something is wrong with it that you cannot name, which is much worse than something being wrong with it that you can.

Here is the thing nobody tells you: the flatness is almost never in the prose. It is in the shape. Your reader makes a choice and the story does not carry it anywhere. So before you rewrite a single sentence, go and find out what shape you actually built.

Diamond first. Always.

If you learn exactly one shape, learn this one, because it is the shape that fixes flat.

Open, differ, converge. The reader picks a path, something changes, and the story comes back together. Divergence is cheap — three short branches. Convergence is rich — one long shared trunk, seasoned by what they picked. You write the trunk once, and it reads differently for everybody.

Ink
VAR approach = ""

The cave mouth yawns before you. How do you enter?

* [Torch raised high]
  Light floods the walls, revealing ancient paintings.
  ~ approach = "bold"
* [Creeping in the shadows]
  You slip inside silently. Something skitters away.
  ~ approach = "stealthy"
* [Calling out a greeting]
  Your voice echoes back threefold. Then silence.
  ~ approach = "friendly"
- -> cave_interior

=== cave_interior ===
The cave opens into a vast chamber.
{approach == "bold": The paintings continue deeper, guiding your way.}
{approach == "stealthy": Your eyes have adjusted. You see everything.}
{approach == "friendly": A faint voice answers from the dark.}
Something glints on the far wall.
-> END

Look at what that costs you: three short branches and one paragraph. Look at what it buys: the cave chamber knows how you walked in. That is the entire trick, and every other shape on this page is a variation on it.

This page cannot see your story

I want to be straight with you about that. There is no analyser here reading your .ink and telling you what you built — I am asking you, and you are answering. Real structure detection is being built into the Workshop app, where the story actually lives and where a tool can genuinely see it. Until then, the diagnosis is yours to make, and the questions below are how you make it.

Name the shape you built

Answer these about your own story. Answer honestly rather than aspirationally.

  1. Do any two paths ever meet again? If no — every choice leads somewhere unique and nothing reconverges — you built a Time Cave, and that is why it feels unfinishable.
  2. Is there one room the reader keeps returning to? Then you built a Weave or a Hub-and-Spoke — a Weave if the options run out, a Hub-and-Spoke if they unlock each other.
  3. Does everything reconverge, every time, immediately? That is Branch-and-Bottleneck, and if it feels flat it is because nothing is surviving the bottleneck.
  4. Does it reconverge and the trunk knows what you did? Congratulations, that is a Foldback, and you are further along than you thought.
  5. Is it a straight line of obstacles? Gauntlet. Fine shape. Check that failing one does not end the story.
  6. None of the above — it just goes forward and the choices are flavour? Then you have a spine with no shape on it yet, and a Diamond is the first one to put there.

The ramp

The shapes are tiered, and the tiers are not a ranking — they are an order of operations. Every shape in the Basic column can be built out of knots, choices and diverts alone. Everything in Intermediate wants a variable. Everything in Advanced wants a state model you already trust, which is why starting there goes so badly.

Basic

Where everyone starts. One choice, one consequence, no bookkeeping. You can write either of these knowing nothing but knots, choices and diverts.

Intermediate

These need a variable or two. You are no longer branching the text — you are branching the state and letting it colour a shared path. This is where most finished stories live.

Advanced

These are what you graduate into, and they all want the same thing: a state model you trust. Do not start here. Arrive here.

Every shape’s way out

This is the part I actually want you to keep. Each shape has a characteristic way of going wrong and a specific shape it turns into when you fix it. You are not abandoning what you built — you are growing it.

If you builtand it feels like thisgo here next
DiamondYour reader picks, something happens, and by the next paragraph it may as well not have happened at all.Foldback
Time CaveYou are on scene twelve of twenty-seven, you have four more endings to write, and you cannot face scene thirteen. The story feels unfinishable because it is.Branch-and-Bottleneck
Branch-and-BottleneckThe bottlenecks are so tight nothing survives them. The reader chose, and by chapter three it is the same story it would have been anyway. This is on rails with extra steps.Foldback
FoldbackYour spine remembers, but only for one sentence per checkpoint. The seasoning is thinner than the branches were, and the reader can feel it.QBN
GauntletYour challenges can only be failed. One stumble and the reader is dead, restarting, and not coming back.Hub-and-Spoke
Hub-and-SpokeEverything is unlocked at once. The reader is looking at eleven options with no reason on earth to pick any particular one.QBN
WeaveThe reader keeps coming back to your hub and it says the exact same thing every single time. The room stops feeling like a place and starts feeling like a menu.Loop-and-Grow
Loop-and-GrowThe reader loops, and nothing has changed. It does not read as a loop — it reads as a bug.Weave
Parallel PathsTwo storylines, and you are writing every scene twice. Track B is three beats behind Track A and getting further behind.Branch-and-Bottleneck
QBNYou have accumulated so much state that you genuinely cannot predict what the reader will be looking at. You are debugging your own story.Branch-and-Bottleneck

Full cards for all ten, with the code for each:

The flat diamond

The most common flatness of all, and the easiest to fix. You built a diamond, the reader chose, the paths converged — and the trunk doesn't mention it. Nothing came through. Give each branch a VAR to set on its way past, and read it back in the trunk. That one line turns a diamond into a Foldback, and a Foldback is a story that remembers.

You are out of this state when

You can say out loud what shape your story is, and name the one it should grow into next.

Making it remember is state 3.

State 3

It has a shape

“How do I make it remember me?”

You have a shape. Now you want the story to remember you, and this is the single move that separates a branching story from a good one.

It is also, and I am going to say this once and then leave you alone about it, the moment you start programming. Variables, conditionals, state. Nobody is going to make you call it that. But that is what you are doing, and you are about to find out you can.

VAR and ~

Sometimes you need the story to remember something — did the player pick up the key? Are they friendly or rude? Declare a variable at the top of the file with VAR, and change it anywhere with ~, which just means ‘do something behind the scenes’ — the reader never sees that line.

Ink
VAR has_key = false
VAR friendliness = 0

* Pick up the key.
    ~ has_key = true
    You grab the rusty key.

+ Look around the room.
    The room is cold and empty.

Conditions

Now that you can remember things, you can check them with conditions. Read { has_key } as ‘if has_key is true.’ Gate a whole block of text, or gate a single choice — and gating the choice is the stronger move, because a reader who never found the key never even sees that the option existed.

Ink
{ has_key:
    You unlock the door and step through.
- else:
    The door is locked. You need a key.
}

* { has_key } Unlock the door.
    The door creaks open.
* Try to force it open.
    It won't budge.

Plant, remind, payoff

Having a variable is not the same as the reader feeling it. The most satisfying use of state has three beats, and skipping the middle one is why so many stories with variables still read as flat.

  1. Plant. The reader does something — picks up an item, helps someone, reads a note — and a flag flips. They should barely notice.
  2. Remind. Later, one sentence that lets them know the story kept it. This is the beat everybody skips, and it is the one that does the work.
  3. Payoff. Something is different. A path opens, a character reacts, an ending exists that otherwise would not have.
Ink
VAR knows_password = false

// PLANT
=== office ===
A sticky note on the monitor reads: "DELTA-7"
~ knows_password = true
You memorize it and move on.
-> corridor

// REMIND
=== terminal ===
A login prompt blinks on the screen.
{knows_password: The sticky note. DELTA-7. Could that be it?}

// PAYOFF
* {knows_password} [Type DELTA-7]
    Access granted. Files flood the screen.
    -> secret_files
* [Try to guess]
    You type "password." Denied. "admin." Denied.
    -> terminal_locked

Season the trunk, don’t duplicate it

Here is the discipline that keeps this from exploding on you. When state changes a scene, you do not write two copies of the scene. You write one, and you season it.

Ink
VAR trust = 0

=== arrival
The ferryman does not look up when you board.
+ ["It's cold."]
    ~ trust = trust + 1
    "It is," he agrees, and something in him unlocks a notch.
    -> crossing
+ [Say nothing.]
    ~ trust = trust - 1
    The silence sets, like something cooling.
    -> crossing

=== crossing
The water goes by underneath, {trust > 0: companionably|like an argument you are losing}.
{trust > 0: He offers you his coat.|He does not offer you his coat.}
-> END

One crossing. Not two. The {trust > 0: companionably|like an argument you are losing} is doing the entire job — same paragraph, different story. Write the trunk first, plain, all the way through. Season it afterwards. Do it in that order and you will never once find yourself maintaining two versions of the same scene.

Two things you get for free

Ink counts visits for you. A knot name evaluates to how many times it has been visited, and you never had to declare anything:

Ink
=== market ===
{market == 1: The market is overwhelming on first visit. So many stalls.}
{market == 2: The market feels more familiar now. You know where things are.}
{market > 2: You navigate the market on autopilot.}

+ [Browse the stalls] -> stalls
+ [Leave the market] -> town_square

And an irreversible choice needs no new syntax at all — just an assignment guarded so the choice that fires it can never fire again. Turning the key sets ~ door_sealed = true, and the choice that turned it required not door_sealed to appear at all. So the instant it fires, its own condition goes false, and the option is gone for the rest of the story. Once turned, it doesn't turn back.

Ink
VAR has_key = false
VAR door_sealed = false

=== room_9
The final room. {has_key: The lock is waiting for what you are carrying.|There is a lock, and you have nothing to put in it.}
+ {has_key and not door_sealed} [Turn the key]
    ~ door_sealed = true
    It turns once. It will not turn back.
    -> end_game
+ [Stay here] -> room_9
+ [Go back south] -> room_6
How many variables?

Three to seven. Go past seven and you will lose track of what the reader can possibly be seeing; go under three and the choices stop feeling consequential. And decide the list before you write the branches — state you retrofit is state you will get wrong.

You are out of this state when

There is at least one moment where you can point at the screen and say “that sentence is there because of something the reader did three scenes ago.”

If it is starting to sprawl, that is state 4.

State 4

It is getting messy

“This is unmanageable.”

You are here because it has got away from you. That is not a sign you are bad at this. It is a sign you are far enough in for the structure to start mattering, and every branching story goes wrong in exactly one of two ways.

The two ways a branching story dies

Knowing which one you are drifting toward is half the craft.

Failure 1
Combinatorial explosion

You write a choice with 3 options, each leads to a new scene with 3 options, each leads to… and suddenly you are writing 27 scenes for a 3-choice story. You burn out at scene 12. The player only ever sees 3 of them.

Cause: treating every choice as a fork that needs its own downstream content.

You have built: a Time Cave. Grow it into: Branch-and-Bottleneck — let the paths reconverge, and write the next chapter once.

Failure 2
On rails

The player makes choices, but the story barrels toward the same scenes regardless. Choices feel cosmetic. Players disengage.

Cause: over-correcting for explosion and converging everything immediately, with no consequence carried forward.

You have built: a bottlenecked spine with nothing getting through. Grow it into: a Foldback — same spine, but it remembers which way you came.

The fix for both is the same thing: state

Don't branch the text — branch the variables, then let those variables colour a shared path. Explosion happens when you duplicate scenes; rails happen when you refuse to. State is the third option, and it is the only one that scales.

Five heuristics, in order

  1. Decide your shape first. Diamond? Branch-and-bottleneck? Quality-based? Pick it before you write a word of prose. That is what are for.
  2. Pick your tracked state. What 3–7 variables actually matter? Go past ~7 and you'll lose track; go too few and choices stop feeling consequential.
  3. Plan your bottlenecks before your branches. Know where the river reconverges before you let it split.
  4. Aim for diamonds two to four beats long. Branch, let the player feel the difference, converge. Repeat.
  5. Make divergence cheap and convergence rich. Short branches, long shared trunks, coloured by state.

Untangling what you already have

You do not have to start over. You almost never have to start over. Three moves, in this order:

  1. Draw it. You cannot fix a shape you cannot see. Get a map of your own story out of an AI — it is genuinely good at this, and it will show you the branch you forgot to terminate.
  2. Find the widest point and put a bottleneck just after it. Every path from that fan-out gets a divert to one shared knot. Everything downstream of that knot you now only have to write once.
  3. Push the difference into variables. Whatever made those branches feel different — that goes into a VAR now, and gets read back in the trunk you just merged them into.
Prompt
Draw a mermaid flowchart of the knots in this Ink story and how they connect --
which choice from which room leads to which knot. Use the room names as labels,
and mark any tunnel or loop clearly.
Where AI helps and where it does not

AI is excellent at filling a shape and bad at choosing one. Good: mapping what you have, decorating rooms, tonal variation, expanding a diamond to size, generating the flavour text that makes convergence rich. Bad: choosing the shape, designing the state model, deciding what the story means, knowing which choice should be irreversible. Decide your state first — even a scribbled list of three things — then ask AI to help you use it.

You are out of this state when

You can draw your story on one piece of paper, and there are fewer distinct scenes on it than there were when you started untangling.

Then it is time to ask whether it is finished.

State 5

It is ready

“Is it good enough?”

You think it is done. Let's find out. Nothing here needs anybody's permission — this is all stuff you can check yourself, before you ever hit publish.

Read it like a stranger

Play it in Preview, not in the editor. Typos hide in the Manuscript and jump right out in Preview, and so does every clunky transition you stopped being able to hear.

  • Every path reaches -> END or loops back to a valid choice. No dead ends — a knot with no choices and no divert leaves your reader stranded.
  • At least one variable gets a moment where an earlier choice visibly changes the story later on. That is the whole point of tracking it.
  • You have played at least two different paths yourself, start to finish, and both make narrative sense.
  • Your characters' lines still sound like them when you read them out loud, from the first scene to the last.
  • Your choice transitions read as prose, not as clunk. Read them aloud too.
  • Your # mood: tags match the scene rather than habit — # mood:danger on a calm beat reads as a bug.
  • Nothing on any path contradicts something the reader already saw on that same path.

That last one is the hardest to check by hand, because it means walking every combination. Hand it to an AI — this is one of the things it is genuinely good at:

Prompt
Here's my Ink script with variables and conditions:
[PASTE YOUR FULL SCRIPT]

Playtest this for me. Try these paths:
1. The "completionist" -- find everything, talk to everyone
2. The "speedrunner" -- take the most direct route to an ending
3. The "contrarian" -- choose the least obvious option every time

For each path, tell me:
- Does the story make sense from start to finish?
- Are there any dead ends (no choices and no -> END)?
- Are there moments where a variable SHOULD matter but doesn't?
- Any dialogue that contradicts what happened earlier on this path?

The three errors you will actually hit

ErrorFix
not found: knot_nameCheck spelling — knot names must match exactly.
Story stops unexpectedlyYou are missing a -> END or a divert to the next knot.
Choice doesn't appearMake sure it starts with * or + and is indented under the right knot.

Handing it over

Publishing happens in the Workshop app, and there are three things it wants from you that your story does not have yet.

  1. Tags. A # mood: tag on its own line before the content it colours — wonder, calm, sadness, danger. A # live:characterId tag lights up the character voice indicator while that character is speaking.
  2. Metadata. Title, the in-world author, themes. The metadata drawer walks you through it; underneath, it is building a JSON bundle with your compiled Ink, your characters, and that metadata block.
  3. Review. Submit it. Review is LLM-backed and it hard-gates publish — your story's review status has to come back passed before it goes live. That is a real gate, not a formality. Work the checklist above and most stories clear it first time.
Ink
# mood:calm
-> arrival

=== arrival
# live:ferryman
The ferryman does not look up when you board.
+ ["It's cold."] -> crossing
+ [Say nothing.] -> crossing

=== crossing
# mood:sadness
"Go on, then," he says. "It doesn't get easier from here."
-> END
If it comes back rated mature

Put enough people in a room writing interactive fiction and somebody will write something dark. That is a certainty, not a risk. A mature rating does not reject your story — it routes to manual review, and there is a human on the other end of that who has approved plenty. Intense, complicated, dark work still ships.

And then the next one

Publish it, then go and play what somebody else built. That part is not optional and it is not sentimental — you will learn more about your own choices from watching a stranger's story fail to remember them than from any amount of rereading your own.

What to learn next: threads (<- knot_name, pulling a parallel storyline into the scene you are in), LISTs for state that is more than true-or-false, and functions for text your story generates rather than text you typed. All of it builds directly on what you just did. None of it was needed to finish.

Everything above is the technique. Here is what the technique doesn’t give you.

I teach this as a one-day intensive, and the difference is not the material — the material is on this page. The difference is a room: somebody to play your story who is not you, somebody to play theirs, and me on hand for the stretch where you are stuck on something that turns out to be a typo. If you want that, it is on the class list. If you don't, keep going. The flow works alone.

Reference

The ten shapes

The vocabulary the rest of this page is speaking.

Ten shapes. They are composable — you can nest diamonds inside hub spokes, chain gauntlets into a branch-and-bottleneck spine, or use QBN to decide which shape fires next. Think of them like functions: pick a shape, fill in your content, connect it to the next one.

Every card carries the same three things: when to use it, the way you can tell you have accidentally built it badly, and the shape it grows into when you fix that. Paste any of the code straight into the Workshop app.

Basic

Where everyone starts. One choice, one consequence, no bookkeeping. You can write either of these knowing nothing but knots, choices and diverts.

Intermediate

These need a variable or two. You are no longer branching the text — you are branching the state and letting it colour a shared path. This is where most finished stories live.

Advanced

These are what you graduate into, and they all want the same thing: a state model you trust. Do not start here. Arrive here.

Tier 10 shapes

Diamond

Open, differ, converge. Single chokepoint fans out then reconverges.

Basic Branching

When you want a meaningful choice that flavors later text without multiplying your workload. The reader picks a path, something changes, and the story comes back together.

You have this one when

Your reader picks, something happens, and by the next paragraph it may as well not have happened at all.

The way out

Give the branch something to leave behind. One VAR, set inside each option, read back in the trunk. A diamond that remembers is a Foldback. Go to Foldback →

Ink
VAR approach = ""

The cave mouth yawns before you. How do you enter?

* [Torch raised high]
  Light floods the walls, revealing ancient paintings.
  ~ approach = "bold"
* [Creeping in the shadows]
  You slip inside silently. Something skitters away.
  ~ approach = "stealthy"
* [Calling out a greeting]
  Your voice echoes back threefold. Then silence.
  ~ approach = "friendly"
- -> cave_interior

=== cave_interior ===
The cave opens into a vast chamber.
{approach == "bold": The paintings continue deeper, guiding your way.}
{approach == "stealthy": Your eyes have adjusted. You see everything.}
{approach == "friendly": A faint voice answers from the dark.}
Something glints on the far wall.
-> END
END END END END END END END END

Time Cave

Pure exponential branching. No convergence. Every choice leads to unique content.

Basic Branching

When you want maximum divergence and every playthrough to feel completely different. Best for short stories because content grows exponentially. Classic "Choose Your Own Adventure" shape.

You have this one when

You are on scene twelve of twenty-seven, you have four more endings to write, and you cannot face scene thirteen. The story feels unfinishable because it is.

The way out

Let the paths come back together. Fan out, let the reader feel the difference, then reconverge and write the next chapter once. That is Branch-and-Bottleneck. Go to Branch-and-Bottleneck →

Ink
The letter says: "Come to the docks at midnight."
* [Go to the docks]
  A figure waits in the fog.
  ** [Approach them]
    "You came." They hand you a key.
    *** [Take the key]
      The key opens a warehouse. Inside: gold.
      -> END
    *** [Refuse the key]
      "Your loss." They vanish into the fog.
      -> END
  ** [Hide and watch]
    They wait. Then leave a package on the ground.
    *** [Take the package]
      Inside: a map to somewhere far away.
      -> END
    *** [Leave it]
      You walk home. Some mysteries stay unsolved.
      -> END
* [Burn the letter]
  The paper curls and blackens.
  ** [Go to bed]
    You sleep soundly. Life goes on.
    -> END
  ** [Regret it immediately]
    You fish the scraps from the fire.
    "...docks...mid..." Useless.
    -> END

Branch-and-Bottleneck

Repeated diamonds chained. The most common game structure (Telltale, Life is Strange, etc).

Intermediate Composable

When you want an episodic structure with meaningful choices that don't spiral out of control. Each "chapter" fans out and reconverges, so you only need to write the next chapter from one starting point. This is the workhorse of commercial narrative games.

You have this one when

The bottlenecks are so tight nothing survives them. The reader chose, and by chapter three it is the same story it would have been anyway. This is on rails with extra steps.

The way out

Something has to get through the bottleneck. Set state in the branch, read it in the trunk, and let it keep mattering two chapters later. That is a Foldback. Go to Foldback →

Ink
VAR ch1_choice = ""
VAR ch2_choice = ""

-> chapter_one

=== chapter_one ===
The king demands your counsel.
* [Advise war]
  "Strike first," you say. The king smiles.
  ~ ch1_choice = "war"
* [Advise diplomacy]
  "Send an envoy." The king frowns but nods.
  ~ ch1_choice = "peace"
- -> chapter_two

=== chapter_two ===
{ch1_choice == "war": Troops gather at the border.}
{ch1_choice == "peace": An envoy rides out at dawn.}
A spy brings disturbing news.
* [Interrogate the spy]
  Under pressure, they reveal a traitor.
  ~ ch2_choice = "traitor"
* [Follow the spy secretly]
  They lead you to a hidden camp.
  ~ ch2_choice = "camp"
- -> chapter_three

=== chapter_three ===
{ch2_choice == "traitor": You confront the traitor at court.}
{ch2_choice == "camp": You raid the camp at dawn.}
The kingdom's fate is sealed.
{ch1_choice == "war" and ch2_choice == "traitor": A bloody but decisive victory.}
{ch1_choice == "peace" and ch2_choice == "camp": A quiet triumph. No one even knows.}
-> END
remembers

Foldback

Branches that always rejoin the spine, but the story remembers which path you took.

Intermediate Branching

When you want the illusion of major divergence while keeping a manageable story spine. The player takes different scenic routes but always arrives at the same checkpoints, and the prose acknowledges their specific journey.

You have this one when

Your spine remembers, but only for one sentence per checkpoint. The seasoning is thinner than the branches were, and the reader can feel it.

The way out

Stop adding branches and start adding state. Fewer forks, more qualities, and let the accumulated qualities decide what the scene even offers. That is QBN. Go to QBN →

Ink
// Foldback: paths FEEL different but arrive at the same outcome.
// Compare with Branch-and-Bottleneck where endings genuinely diverge.

-> prison

=== prison ===
The cell door is rusted. You need to get out.
* [Pick the lock]
  Click. Click. The door swings open.
  You slip into the corridor, heart pounding.
  -> courtyard
* [Smash the wall]
  Brick dust everywhere. A hole, barely big enough.
  You squeeze through, scraping skin on stone.
  -> courtyard

=== courtyard ===
// Same destination regardless of path above.
The courtyard stretches before you. The gate is ahead.
* [Climb the wall]
  Your fingers find holds in the old mortar.
  Over the top. You drop to the other side.
  -> road
* [Bluff the gatekeeper]
  "Shift change." He squints, shrugs, waves you through.
  -> road

=== road ===
// The ending is IDENTICAL. That's the point of Foldback:
// the player felt agency, but the story spine never moved.
Miles later, you stop to breathe.
You're free. The road stretches ahead.
Whatever happened back there — it's done now.
-> END
Gate 1 Gate 2 wounds

Gauntlet

Gated stations, fail forward. Linear sequence where you can pass clean or messy.

Intermediate Linear

When you want a sequence of challenges that the player always gets through, but their performance accumulates. Great for tension-building where the final outcome depends on how many gates you passed cleanly.

You have this one when

Your challenges can only be failed. One stumble and the reader is dead, restarting, and not coming back.

The way out

Fail forward. Every gate gets a way through that always works and a penalty that counts up, and the ending reads the tally. If it still feels like a corridor, let the reader pick the order and it becomes a Hub-and-Spoke. Go to Hub-and-Spoke →

Ink
VAR wounds = 0
VAR has_rope = true

-> gate_one

=== gate_one ===
A chasm blocks the path. Far side, ten feet away.
* {has_rope} [Throw the rope across]
  The rope catches! You cross safely.
* [Jump for it]
  You leap — and barely catch the edge.
  ~ wounds = wounds + 1
  Your hands are bleeding. But you made it.
- -> gate_two

=== gate_two ===
A locked door. The lock is rusted.
* {wounds == 0} [Pick the lock with steady hands]
  Click. It opens smoothly.
* [Force it open]
  You slam your shoulder into it. It gives.
  ~ wounds = wounds + 1
  Something in your shoulder pops.
- -> ending

=== ending ===
You stumble into daylight.
{wounds == 0: Not a scratch on you. Perfect run.}
{wounds == 1: Battered, but alive. Could be worse.}
{wounds >= 2: You collapse. Barely made it.}
-> END
HUB spoke 1 2 3 4 flags

Hub-and-Spoke

Central hub with gated spokes. Return to hub after each spoke, new options unlock.

Intermediate Branching

When you want the player to explore a location or conversation where completing one area unlocks another. Classic RPG town or detective investigation structure. Each spoke is a self-contained scene.

You have this one when

Everything is unlocked at once. The reader is looking at eleven options with no reason on earth to pick any particular one.

The way out

Gate the spokes. A flag set in one spoke opens the next, and suddenly there is an order the reader discovers instead of one you enforced. Gate on accumulated qualities instead of single flags and you have grown a QBN. Go to QBN →

Ink
VAR talked_to_guard = false
VAR searched_alley = false

-> town_square

=== town_square ===
The town square. People bustle past.
+ {not talked_to_guard} [Talk to the guard]
  -> guard
+ {not searched_alley} [Search the alley]
  -> alley
+ {talked_to_guard and searched_alley} [Enter the locked tower]
  The clues align. You know the password.
  -> tower
+ [Leave town]
  You walk away, mystery unsolved.
  -> END

=== guard ===
"Saw someone in the alley last night," the guard mutters.
~ talked_to_guard = true
-> town_square

=== alley ===
Behind the crates: a torn note. "The password is MOONRISE."
~ searched_alley = true
-> town_square

=== tower ===
"MOONRISE," you whisper. The door swings open.
Inside, the truth awaits.
-> END
HUB visited?

Weave

Sticky hub, visit branches, return. Hub knot loops, tracks what you've visited.

Intermediate State Driven

When you want the player to explore a space at their own pace, examining things in any order. Each option disappears after being used, and the story moves on when everything has been seen.

You have this one when

The reader keeps coming back to your hub and it says the exact same thing every single time. The room stops feeling like a place and starts feeling like a menu.

The way out

Use the visit count you already get for free, or a sequence, so the hub reads differently on the second pass. If the whole scene should change and not just the sentence, grow it into Loop-and-Grow. Go to Loop-and-Grow →

Ink
VAR saw_fish = false
VAR saw_herbs = false
VAR saw_fortune = false

-> market_square

=== market_square ===
The market bustles around you.
+ {not saw_fish} [Visit the fish stall]
  The fishmonger waves a gleaming trout.
  "Fresh today! Caught it meself!"
  ~ saw_fish = true
  -> market_square
+ {not saw_herbs} [Browse the herb cart]
  Lavender and rosemary scent hits you.
  The herbalist nods knowingly.
  ~ saw_herbs = true
  -> market_square
+ {not saw_fortune} [See the fortune teller]
  She turns a card. The Tower.
  "Change is coming," she whispers.
  ~ saw_fortune = true
  -> market_square
+ {saw_fish and saw_herbs and saw_fortune} [Leave the market]
  You've seen it all. Time to move on.
  -> END
+ [Leave the market early]
  You slip away through the crowd.
  -> END
LOOP turn 1 turn 2 turn 3 early mid late

Loop-and-Grow

Same scene revisited with accumulated state changing what's available.

Advanced State Driven

When you want to model progression through repetition, like a Groundhog Day loop, a growing relationship, or a place that changes over time. Each visit feels different because state has evolved.

You have this one when

The reader loops, and nothing has changed. It does not read as a loop — it reads as a bug.

The way out

Every trip round has to move a number or set a flag, and the text has to show it. If nothing accumulates, you do not have a loop-and-grow, you have a Weave — so make it one and let the options run out. Go to Weave →

Ink
LIST Knowledge = seeds, water, sunlight

-> garden

=== garden ===
{LIST_COUNT(Knowledge) == 0: The garden is dead earth. Nothing grows.}
{Knowledge ? seeds: Small green shoots push through the soil.}
{Knowledge ? water: The earth is dark and damp.}
{Knowledge ? sunlight: Golden light pools between the leaves.}

+ {not (Knowledge ? seeds)} [Plant the seeds you found]
  You press seeds into the earth, one by one.
  ~ Knowledge += seeds
  -> garden
+ {not (Knowledge ? water)} [Dig a channel to the stream]
  Water trickles in, soaking the ground.
  ~ Knowledge += water
  -> garden
+ {not (Knowledge ? sunlight)} [Cut back the dead branches overhead]
  Light floods in. The soil warms.
  ~ Knowledge += sunlight
  -> garden
+ {Knowledge ? (seeds, water, sunlight)} [Sit in your garden]
  It took time. But look at it now.
  -> END
Path A Path B bridge bridge

Parallel Paths

Two sustained storylines with occasional bridge points where you can cross over.

Advanced Composable

When you want two fundamentally different experiences that occasionally intersect. Good for dual-protagonist stories or "upstairs/downstairs" structures where the player commits to a perspective but can switch at key moments.

You have this one when

Two storylines, and you are writing every scene twice. Track B is three beats behind Track A and getting further behind.

The way out

Collapse them. One trunk, one track variable, and the scenes read differently depending on who is walking through them. You lose almost nothing and you halve the writing — that is Branch-and-Bottleneck again. Go to Branch-and-Bottleneck →

Ink
VAR current_path = "none"

Two letters arrive. One sealed in red, one in blue.
* [Open the red letter]
  ~ current_path = "red"
  -> red_1
* [Open the blue letter]
  ~ current_path = "blue"
  -> blue_1

=== red_1 ===
The Red Court summons you. Intrigue and poison.
* [Continue on the red path]
  -> red_2
* [Defect to the blue side]
  ~ current_path = "blue"
  -> blue_2

=== blue_1 ===
The Blue Fleet needs a navigator. Salt and stars.
* [Continue on the blue path]
  -> blue_2
* [Defect to the red side]
  ~ current_path = "red"
  -> red_2

=== red_2 ===
The courtiers whisper your name.
{current_path == "red": You've been here all along. They trust you.}
{current_path == "blue": A defector. They watch you carefully.}
-> finale

=== blue_2 ===
The horizon stretches forever.
{current_path == "blue": The crew knows you. You belong.}
{current_path == "red": A landlubber on deck. You have much to prove.}
-> finale

=== finale ===
War comes regardless. But where you stand determines everything.
-> END
mood trust clues SELECT scene A scene B scene C

QBN (Quality-Based Narrative)

State determines which content appears. Different text and choices surface based on accumulated qualities.

Advanced State Driven

When you want the story to feel responsive to the player's accumulated identity or stats. Instead of explicit branching, content appears or hides based on who the player has become. This is how Fallen London works.

You have this one when

You have accumulated so much state that you genuinely cannot predict what the reader will be looking at. You are debugging your own story.

The way out

Cut back to three to seven qualities that actually matter, and pin a spine back underneath so there is always a next scene even when every check fails. Branch-and-Bottleneck is the floor you put under it. Go to Branch-and-Bottleneck →

Ink
LIST Traits = brave, clever, kind
VAR reputation = 0

-> tavern

=== tavern ===
The tavern is loud tonight.
{Traits ? brave: The scarred fighter nods at you from across the room.}
{Traits ? clever: You notice the barkeep's loaded dice.}
{Traits ? kind: A child tugs your sleeve, eyes wide.}

* {not (Traits ? brave)} [Stand up to the bully]
  You shove him back. The room goes quiet.
  ~ Traits += brave
  -> tavern
* {not (Traits ? clever)} [Challenge the barkeep's game]
  "Those dice are weighted." He goes pale.
  ~ Traits += clever
  -> tavern
* {not (Traits ? kind)} [Buy the child a meal]
  The kid grins. Warmth blooms in your chest.
  ~ Traits += kind
  -> tavern
* {LIST_COUNT(Traits) >= 2} [You've made your mark. Leave.]
  ~ reputation = LIST_COUNT(Traits)
  The door swings shut behind you.
  Reputation earned: {reputation}.
  -> END

The escape routes, all in one place

If you builtand it feels like thisgo here next
DiamondYour reader picks, something happens, and by the next paragraph it may as well not have happened at all.Foldback
Time CaveYou are on scene twelve of twenty-seven, you have four more endings to write, and you cannot face scene thirteen. The story feels unfinishable because it is.Branch-and-Bottleneck
Branch-and-BottleneckThe bottlenecks are so tight nothing survives them. The reader chose, and by chapter three it is the same story it would have been anyway. This is on rails with extra steps.Foldback
FoldbackYour spine remembers, but only for one sentence per checkpoint. The seasoning is thinner than the branches were, and the reader can feel it.QBN
GauntletYour challenges can only be failed. One stumble and the reader is dead, restarting, and not coming back.Hub-and-Spoke
Hub-and-SpokeEverything is unlocked at once. The reader is looking at eleven options with no reason on earth to pick any particular one.QBN
WeaveThe reader keeps coming back to your hub and it says the exact same thing every single time. The room stops feeling like a place and starts feeling like a menu.Loop-and-Grow
Loop-and-GrowThe reader loops, and nothing has changed. It does not read as a loop — it reads as a bug.Weave
Parallel PathsTwo storylines, and you are writing every scene twice. Track B is three beats behind Track A and getting further behind.Branch-and-Bottleneck
QBNYou have accumulated so much state that you genuinely cannot predict what the reader will be looking at. You are debugging your own story.Branch-and-Bottleneck

These ten cards are condensed from the Ink Shape Catalog, which also carries a vibe prompt for each shape. For nesting them inside one another, the Shape Composition Guide. For where these shapes come from and what published work uses them, the Story Structure Atlas. For the AI prompts that fill them, the Vibe Authoring Toolkit.