Interactive Fiction Intensive Workbook
Interactive Fiction Intensive — Workbook
Everything you paste today lives on this one page.
You write and publish in the Spaces Between Workshop app — that’s where the story actually lives. This page is the other window: the skeleton to paste, the missions to work, every construct as a copy-paste block, three recovery points if you lose the thread, and a review checklist so your story passes the first time. Keep it open all day.
One Saturday, browser-only, start to finish. No Inky, no installs — the Workshop app is where you write, preview, and publish.
Fell behind? That’s what Section 6 is for. Every checkpoint has a working .ink file. Paste it in and you’re back in the room with everyone else.
1. The day
You’ve got one story and one day: 10:00–16:00 Pacific, one hour off for lunch. Five hours of studio. The blocks below are your spine — each one ends at a checkpoint, and the checkpoints are exactly what the recovery points in Section 6 restore. Block ends and you’re not at the checkpoint yet? That’s not a sign to catch up alone — go paste the recovery file and get back in the room.
01-nine-rooms-complete.ink02-diamonds.ink-> knot -> tunnel. Then: where AI is genuinely good, and where it is not.03-publish-ready.inkTwice today we stop everything and play the Secret Tunnel song from Avatar. Sokka would want you to. First time, mid-morning: it’s a narrative idea — a hidden connection between rooms. Second time, mid-afternoon: same song, grown-up joke — the Ink -> knot -> construct, a tunnel that comes back. Same ritual. It just grew up.
2. The Nine Rooms
Paste this in. It runs the moment you paste it, so you’ve got a working game within minutes. It also loops forever — every room eventually leads back to another room, and the ending loops right back to the start. That’s 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.
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
Here are your seven missions, in order. Work them on your own dungeon — it does not have to look anything like the rooms shown below.
Decorate the rooms
Decorate the rooms of the dungeon! Add descriptions of what is in the rooms — and they don’t have to stay rooms. 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.
Underneath, you’re just working with knots and diverts. A knot is a named section of your story, marked with === — think of it like a chapter or a scene. A divert sends the reader there with an arrow, ->. That’s all it means: go to. Once you’ve got that, a room is just a named place in the graph, and it can stand for anything you want it to.
=== room_1
The first room smells of cold stone and old rain.
{lamps > 0: Your lamp throws a shaky circle of light.}
+ [Go north] -> room_2
+ {lamps == 0} [Take the lamp from its bracket]
~ lamps = lamps + 1
It is warm, which it should not be.
-> room_1
+ [Sit here a while] -> room_1A secret tunnel — and a disappearing one
Add at least one secret tunnel, through the mountains, secret secret secret secret tunnel. Don’t let the cave-in get you down, Sokka: add at least one disappearing secret tunnel.
A choice marked with * can only be picked once — come back to this section and that option is gone. A choice marked with + sticks around even after the reader returns, which is great for things they might want to do repeatedly, like ‘look around’ or ‘wait.’ This room gets to the same disappearing effect a different way: a sticky + choice guarded by {tunnel_open}, switched off with ~ tunnel_open = false the moment it’s used. Same outcome as a plain *, more control over exactly when it vanishes.
=== room_4
A dead end, except for the draught coming from behind the tapestry.
+ [Go west] -> room_2
+ {tunnel_open} [Take the secret tunnel]
~ tunnel_open = false
You crawl through. Behind you, the passage folds shut like a mouth.
-> room_7
+ [Stay here] -> room_4A secret item that vanishes when taken
Add at least one secret item that disappears after you pick it up. Is it a magic item? Does it unlock a new area? It could.
Sometimes you need the story to remember something — did the player pick up the key? You track that with a variable: declare it with VAR up top, change it with ~, which just means ‘do something behind the scenes’ — the reader never sees that line. Here, taking the key is a once-only pickup that also flips has_key, so the room and the story both remember it happened.
=== room_5
Fifth room. Empty, apart from the key on the floor.
+ {not has_key} [Take the key]
~ has_key = true
-> room_5
+ [Go east] -> room_2An irreversible choice
Add at least one irreversible choice! You don’t need any new syntax for this — just a ~ 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.
=== 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_6A number that counts up or down
Keep track of at least one number that counts up or down. Declare it with VAR, change it with ~ — that’s the whole trick. This dungeon tracks four counters at the top of the file, and the lamp count is the one that climbs. Watch it happen in Mission 1’s room_1 above: ~ lamps = lamps + 1.
The four VARs this dungeon tracks:
VAR lamps = 0 VAR tunnel_open = true VAR has_key = false VAR door_sealed = false
A loop or cycle
At least one loop or cycle should be present in the story. The simplest loop needs no gather and no label — just a divert back to where you started. The undecorated skeleton already has one: the Sit Here choice diverts straight back to room_1. A knot can divert to itself, and that’s a loop. Want one that gathers several choices back to one shared line first? See Gathers and labels in the Snippet Library.
From the plain skeleton, before decoration:
=== room_1
You are in the first room. There is a door to the north.
+ Go north
-> room_2
+ Sit Here
-> room_1At least one ending — preferably several
There should be at least one ending! But preferably, multiple. -> END is a special built-in divert — it means the story is over. Every path must end, one way or another: either divert to another knot, or use -> END.
The undecorated skeleton doesn’t actually end — its end_game loops back to room_1 forever. You have won the game! Or have you? That’s this mission’s whole job: give it a real ending.
Skeleton — no real ending yet:
=== end_game You have won the game! Or have you? -> room_1
Decorated — a real ending:
=== end_game
You step out carrying {lamps} {lamps == 1:lamp|lamps} and everything you decided.
You have won the game! Or have you?
-> END3. Snippet library
Every construct you need today, paste-ready. This is the part you keep after the day is over.
Knots
A knot is just a named section of your story. Mark it with ===. Think of knots like chapters or scenes.
=== tavern === You walk into a dimly lit tavern. The bartender looks up. === market === The market is bustling with merchants and shoppers.
Diverts
A divert sends the reader to a knot. It looks like an arrow, ->. Think of -> as ‘go to.’ That’s all it means.
=== tavern ===
You walk into a dimly lit tavern.
* Talk to the bartender.
-> bartender_chat
* Leave the tavern.
-> market
=== bartender_chat ===
"What can I get you?" the bartender asks.
=== market ===
You step outside into the bright sun.Stitches
If knots are chapters, stitches are sections within a chapter. Mark them with =. Divert to one with -> knot_name.stitch_name from outside, or just -> stitch_name from within the same knot.
=== tavern === = entrance You push open the heavy door. -> bar_area = bar_area The bartender nods at you.
* vs + — once-only vs sticky
A choice marked with * can only be picked once. Come back to this section and that option is gone. A choice marked with + sticks around even if the reader returns — great for things they might want to do repeatedly, like ‘look around’ or ‘wait.’
* Pick up the shiny coin.
You pocket the coin. // gone if you come back
+ Look around the room.
The room is cold and empty. // stays availableBracketed choice text
Text inside [square brackets] appears only in the choice button, not in the story text after selection. Text outside brackets appears in both. Read Hello[.] there. as: the choice shows “Hello.”, and the result reads “Hello there.”
* [Approach the bar] You swagger up to the counter. * [Find a dark corner] You slide into a booth near the back. * [Turn and leave] The cold night air hits your face again.
Gathers and labels
When multiple choices should lead to the same next beat, use a gather (-). It catches all three paths and continues with the same text — no need to build a separate knot just for one shared line. Want to loop back to a point instead? Give it a label with (options) and divert to it with -> options.
"What do you think happened?" Sal asks. * "Sabotage." Sal nods slowly. * "Accident." Sal looks skeptical. * "I don't know yet." Sal shrugs. - "Either way," she says, "we need to check the reactor logs." -> reactor_logs // looping back to a label: - (options) * [Wait in silence] -> options - She watches you carefully. -> next_scene
Tunnels — the 14:15 construct
A tunnel is a divert that remembers where it came from. Both paths below experience the same tunnel, but each continues to a different destination — you write it once and use it twice. -> knot -> means go there, then come back here; ->-> at the end of the tunnel means return to the caller. The tunnel has no idea who called it — that’s what makes it reusable.
=== explore_forest === The path forks at an ancient oak. * [Take the left path] -> mysterious_sound -> // tunnel: go there, then come back The left path continues deeper into the woods. -> forest_clearing * [Take the right path] -> mysterious_sound -> // same tunnel, different context The right path opens to a meadow. -> meadow === mysterious_sound === You hear something rustling in the undergrowth. * [Investigate] It's a fox. It stares at you, then vanishes. * [Ignore it] You keep walking. The sound fades. - ->-> // return to the caller
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 means ‘do something behind the scenes’ — the reader never sees that line.
VAR has_key = false
VAR friendliness = 0
* Pick up the key.
~ has_key = true
You grab the rusty key.Conditionals
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, or gate a single choice.
{ 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.Sequences — {&} {!} {~}
{a|b|c} is the default, stopping: it plays each option in turn and sticks on the last. {!...} is once-only: it stops after the last, then goes silent. {&...} is a cycle: it loops. {~...} is a shuffle: random every time. If the player visits a scene more than once, you don’t want identical text — these are how you keep it fresh.
The clock ticks. {&loudly|softly|loudly|softly}
She sighs. {!again|for the third time|one last time}
You notice {~a crack in the wall|dust on the shelf|a photograph}.# mood: tags
Put one on its own line before the content it colors: wonder, calm, sadness, danger.
# mood:wonder # mood:calm # mood:sadness # mood:danger
# live: tags
# live:characterId lights up the character voice indicator in the reader while that character is speaking.
# live:ferryman
Bundle metadata
A published story is a JSON bundle underneath: your compiled Ink, a characters map keyed by the ids your # live: tags reference, and a metadata block. This is exactly what the Workshop’s metadata drawer is filling in for you — worth knowing what it’s building.
{
"inkJson": { /* compiled ink JSON */ },
"characters": {
"narrator": {
"name": "Display Name",
"personality": "description",
"voice": "speech style",
"knowledge": "background info"
}
},
"metadata": {
"title": "Story Title",
"author": "In-World Author Name",
"authorSpecies": "Species Name",
"fylgja": "creature-sprite-id",
"fylgjaDescription": "description",
"themes": ["tag1", "tag2"],
"wordCount": 850
}
}4. Diamonds
The two ways a branching story dies
Every branching story fails one of two ways, and knowing which one you’re drifting toward is half the craft.
You write a choice with 3 options, each leads to a new scene with 3 options, each leads to… and suddenly you’re writing 27 scenes for a 3-choice story. You burn out at scene 12. The player only ever sees 3 of them. It happens when you treat every choice as a fork that needs its own downstream content.
The player makes choices, but the story barrels toward the same scenes regardless. Choices feel cosmetic. Players disengage. It happens when you over-correct for explosion and converge everything immediately, with no consequence carried forward.
The fix for both is the same thing: state. Don’t branch the text — branch the variables, then let those variables color a shared path.
Quick structural heuristics
- Decide your shape first. Diamond? Branch-and-bottleneck? Quality-based? Sketch it before you write a word of prose — see the Ink Shape Catalog.
- 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.
- Plan your bottlenecks before your branches. Know where the river reconverges before you let it split.
- Aim for diamonds ~2–4 beats long. Branch, let the player feel the difference, converge. Repeat.
- Make divergence cheap and convergence rich. Short branches, long shared trunks, colored by state.
Write the trunk first, with conditional seasoning
Write the shared path first, with {flag: ...} inserts seasoned in as you go. Then write the branch variants. Add voice and flavor choices liberally once the trunk is solid. That’s the pattern behind the crossing knot in Recovery Point 02 below: one trunk paragraph, seasoned by {trust > 0: ...|...}, never duplicated into two copies of the scene.
Chained-diamond template
Copy this, then replace the comments. It’s scaffolding, not a story — three diamonds chained end to end, trunk-first. Want to see it fully written out, with real prose? That’s Recovery Point 02.
VAR state_a = false
-> diamond_one
// -- Diamond one: branch, let the player experience the difference, converge --
=== diamond_one ===
// 2-3 choices that differ meaningfully -- divergence is cheap here
* [Choice A]
~ state_a = true
-> diamond_one_converge
* [Choice B]
-> diamond_one_converge
=== diamond_one_converge ===
// The trunk. One passage, seasoned by state_a instead of duplicated.
{state_a: text colored by the choice they made|text for the choice they didn't make}
-> diamond_two
// -- Diamond two: repeat the shape --
=== diamond_two ===
* [Choice C] -> diamond_two_converge
* [Choice D] -> diamond_two_converge
=== diamond_two_converge ===
-> diamond_three
// -- Diamond three: chain as many as the story needs --
=== diamond_three ===
// same shape again: branch, differ, converge
* [Choice E] -> diamond_three_converge
* [Choice F] -> diamond_three_converge
=== diamond_three_converge ===
-> END
5. AI prompt pack
AI is excellent at filling a shape and bad at choosing one. Good: generating the map, decorating rooms, tonal variation, procedural text, 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. Think of AI as the intern drafting scaffolding — you make the creative decisions.
Older material sometimes asks AI to help pick which variables to track. Today’s rule is sharper: AI fills, it doesn’t choose. Decide your state first — even a scribbled list of 3–7 things that matter — then ask AI to help you use it.
Map your rooms
This map won’t update when you edit yours — it’s just static. But, Any AI can help you make one! Paste your current .ink file first.
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.
Decorate a room
Write 2-3 sentences of atmospheric description for this scene in my interactive fiction:
[describe the scene]
Keep it second person ("you"), present tense, concise.
This is for a text-based game -- every word should earn its place.Tonal variation
Take this room description: [paste] Rewrite it so it feels [sinister / joyful / eerie / cozy] instead -- same events, same choices, different mood. Don't add or remove anything the player can do, just recolor how it reads.
Season a trunk (diamonds)
For after you’ve written the trunk yourself — this fills the seasoning, it doesn’t design the branch.
Here's my diamond's trunk knot:
[paste]
It currently reads the same regardless of {state}. Add 1-2 sentences of conditional seasoning --
{state: ...|...} -- that colors the trunk without duplicating it into two full copies.Character sheet
Create a character sheet for an interactive fiction NPC: Name: [name] Role in story: [what they do -- shopkeeper, rival, guide, etc.] Setting: [your story's setting] Include: - 2-3 core motivations (what drives them) - 2-3 fears (what they avoid or dread) - Speech pattern (short sentences? flowery? sarcastic? formal?) - 3 example dialogue lines that capture their voice - One thing they would NEVER say (defines their boundaries)
Dialogue, in their voice
AI gives you options. Your job is editorial. Don’t use everything it generates — pick the best lines, cut the rest. You’re the director; AI is the actors at the table read.
Here is my character sheet: [PASTE CHARACTER SHEET] Write dialogue for this character in the following situations. For each situation, give me 2-3 versions so I can pick the best one. Write in ink interactive fiction format (second person, present tense for narration). Situations: 1. The player meets this character for the first time 2. The player asks this character for help 3. The player does something this character disapproves of Keep dialogue SHORT (1-2 sentences per line). Match the speech pattern from the character sheet exactly. Include action beats between dialogue lines.
Stress-test your branches
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?
Design the system first — decide what state to track and how it should affect the story. Prompt AI for structure — let it generate the Ink scaffolding. Playtest immediately — run it in the Workshop, find what breaks. Edit for voice — AI generates the structure, you bring the soul. Iterate with AI — ‘this choice feels flat, give me three alternatives that raise the stakes.’
6. Recovery points
A working .ink file for the end of every major block. Lost the thread? Paste the previous checkpoint over your Manuscript in the Workshop app and rejoin at the next mission — that’s the whole point of an uncapped room with one facilitator. Nobody has to fall behind past a recovery point.
Restores: Your dungeon is yours, and it remembers something — the end of The Nine Rooms block. Paste this in and rejoin at Two ways a story dies.
All seven missions, worked: a lamp that counts up, a secret tunnel that closes behind you, a key that vanishes when taken, a door that seals forever once turned, a real ending.
VAR lamps = 0
VAR tunnel_open = true
VAR has_key = false
VAR door_sealed = false
Welcome to The Nine Rooms!
-> room_1
=== room_1
The first room smells of cold stone and old rain.
{lamps > 0: Your lamp throws a shaky circle of light.}
+ [Go north] -> room_2
+ {lamps == 0} [Take the lamp from its bracket]
~ lamps = lamps + 1
It is warm, which it should not be.
-> room_1
+ [Sit here a while] -> room_1
=== room_2
Four doors. The room seems to be counting them for you.
+ [Go north] -> room_3
+ [Go south] -> room_1
+ [Go east] -> room_4
+ [Go west] -> room_5
=== room_3
Something has been dragged across this floor, recently.
+ [Go north] -> room_6
+ [Go south] -> room_2
=== room_4
A dead end, except for the draught coming from behind the tapestry.
+ [Go west] -> room_2
+ {tunnel_open} [Take the secret tunnel]
~ tunnel_open = false
You crawl through. Behind you, the passage folds shut like a mouth.
-> room_7
+ [Stay here] -> room_4
=== room_5
Fifth room. Empty, apart from the key on the floor.
+ {not has_key} [Take the key]
~ has_key = true
-> room_5
+ [Go east] -> room_2
=== room_6
The sixth room is a crossroads and it knows it.
+ [Go north] -> room_9
+ [Go south] -> room_3
+ [Go east] -> room_8
+ [Go west] -> room_7
=== room_7
The seventh room is where the tunnel comes out, whether or not you used it.
+ [Go east] -> room_6
+ [Stay here] -> room_7
=== room_8
The eighth room. Someone has scratched a tally into the wall.
+ [Go west] -> room_6
+ [Stay here] -> room_8
=== 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
=== end_game
You step out carrying {lamps} {lamps == 1:lamp|lamps} and everything you decided.
You have won the game! Or have you?
-> END
Restores: Three diamonds chained; the trunk reads differently by state — the end of Many diamonds. Paste this in and rejoin at AI as co-author.
Two full diamonds and a seasoned trunk (the block asks for three — build the third from here using the chained-diamond template in Section 4). The crossing knot is the trunk-with-seasoning pattern in action: one passage, colored by trust, never duplicated.
VAR trust = 0
VAR knows_truth = false
VAR took_the_coat = false
-> arrival
// ── Diamond one ─────────────────────────────────────────────────────────
=== arrival
The ferryman does not look up when you board.
+ ["It's cold." ] -> arrival_warm
+ [Say nothing.] -> arrival_cold
= arrival_warm
~ trust = trust + 1
"It is," he agrees, and something in him unlocks a notch.
-> crossing
= arrival_cold
~ trust = trust - 1
The silence sets, like something cooling.
-> crossing
// ── Trunk, seasoned by state ────────────────────────────────────────────
=== 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.}
+ {trust > 0} [Take the coat]
~ took_the_coat = true
-> midpoint
+ [Watch the far bank] -> midpoint
// ── Diamond two ─────────────────────────────────────────────────────────
=== midpoint
Halfway, he says: "You know what's on the other side."
+ ["I do."]
~ knows_truth = true
-> midpoint_join
+ ["Tell me."]
~ trust = trust + 1
He tells you. You wish he hadn't.
~ knows_truth = true
-> midpoint_join
+ [Pretend not to hear] -> midpoint_join
= midpoint_join
The far bank resolves out of the dark.
-> landing
=== landing
{knows_truth:
You step off knowing exactly what you are walking into.
- else:
You step off into something you have refused to name.
}
{took_the_coat: The coat is still around your shoulders. You will have to give it back, eventually.}
{trust > 1: He watches you go, and you feel it.|He is already pushing off.}
-> END
Restores: The state a story needs walking into Review & publish. Carries the # mood: and # live: tags a review-ready story needs.
Short, deliberately — this is what done enough to submit looks like: a # mood: tag on every beat, a # live: tag on the speaking character, and every path reaching -> END.
VAR trust = 0
# mood:calm
-> arrival
=== arrival
# live:ferryman
The ferryman does not look up when you board.
+ ["It's cold."]
~ trust = trust + 1
"It is," he agrees.
-> crossing
+ [Say nothing.] -> crossing
=== crossing
# mood:wonder
The water goes by underneath, {trust > 0: companionably|like an argument you are losing}.
+ [Watch the far bank] -> landing
=== landing
# mood:sadness
# live:ferryman
"Go on, then," he says. "It doesn't get easier from here."
-> END
7. Review checklist
Before you submit
Here’s what you can check yourself, before you ever hit publish:
- Make sure every path reaches
-> ENDor loops back to a valid choice. No dead ends — a knot with no choices and no divert leaves your reader stranded. - Give at least one variable a moment where an earlier choice visibly changes the story later on. That’s the whole point of tracking it.
- Read your characters’ lines out loud. Does it still sound like them, start to finish?
- Check your
# mood:tags match the scene, not just habit —# mood:dangeron a calm beat reads as a bug. - Read it in Preview, not just in the Manuscript editor. Typos hide in the editor and jump right out in Preview.
- Read your choice transitions aloud. Prose should flow, not clunk.
- Play through at least two different paths yourself. Do both make narrative sense?
| Error | Fix |
|---|---|
not found: knot_name | Check spelling — knot names must match exactly. |
| Story stops unexpectedly | You’re missing a -> END or a divert to the next knot. |
| Choice doesn’t appear | Make sure it starts with * or + and is indented under the right knot. |
What editorial review checks
Review is LLM-backed and it hard-gates publish: your story’s review status has to come back passed before it can go live. That’s a real gate, not a formality — build the self-check habits above and most stories clear it the first time.
Put this many people in a room writing interactive fiction, and somebody will write something dark. That’s a certainty, not a risk. A mature rating does not reject your story — it routes to manual review. Your facilitator holds that manual-approve path and has used it before. Intense, complicated, dark work still ships. Just not always by four o’clock.
8. Next steps
Threads — not today, but real
Real stories don’t follow a single track. Subplots simmer in the background. Characters pursue their own agendas. News arrives from elsewhere. Ink’s thread system lets you weave multiple storylines together — presenting choices from different narrative strands in a single moment.
A thread (<- knot_name) pulls content from a parallel storyline into the knot you’re in, as if it were written inline, and returns with ->->, same as a tunnel. It just doesn’t fit in a single studio day alongside the Nine Rooms, diamonds, AI authoring, and publishing — and it’s the least useful construct on day one anyway. Learn it next, once today’s shapes feel comfortable.
Further down the same road: Ink’s LIST system (named, ordered state — relationships, inventory, world progression, beyond a plain VAR) and functions ({function_name()}, reusable logic that generates text from that state). Both build directly on what you did today; neither is needed to finish today.
The rest of the toolkit
Four companion tools, already live — not duplicated here, worth bookmarking:
By four, yours is on this shelf. Go build the next one.