Game Design & Development · Tiny-Loop Tutorial · Archetype #10

Tutorial: Choose-Your-Own-Adventure

Scene Graph Branching Choices Multiple Endings Pre-built Content

This is the exact Choose-Your-Own-Adventure archetype from What Makes a Game? — already built and running below. Play it, then swap the story and protagonist using the panel underneath. You can't break the loop itself; that part is locked. Once you've tuned a version you like, you'll build this same architecture two more times: with Scratch's blocks, then from real scratch in JavaScript.

🗺️ The Architecture

Every tiny-loop game starts as a concept, then gets broken into a core loop, a systems list, and a structure — before anyone touches sprites or colors. A CYOA's "structure" isn't a maze grid or a spawn timer — it's a branch map: which choice leads to which scene.

🌱ConceptA story where every choice changes what happens next.
🔁Core LoopScene shown → pick choice A or B → new scene → repeat until an ending.
🧩SystemsScene display, choice buttons, branch lookup, ending detection.
🏁Win/LoseEvery path ends somewhere — some endings are better than others.

The branch map for "Lost in Space" — the same shape every story below uses, just with different scenes:

Start:
Oxygen Leak
A: Patch It
B: Call Control
Push Through Meteors
Bad Ending
Wait It Out
Good Ending
Coast to Station
Good Ending
Use Reserve Boosters
Bad Ending

The four systems, in order of execution on every choice:

  1. Scene display system — shows the current scene's text and its two choice buttons.
  2. Choice system — each button is labeled with that choice's text, not "A" or "B" — the player never sees the underlying scene IDs.
  3. Branch lookup system — clicking a choice looks up which scene ID it points to and jumps there.
  4. Ending detection system — some scenes are marked as endings; reaching one stops the loop and shows a good- or bad-ending screen.

🎮 Play & Customize

Read the scene, then click a choice. There's no wrong click to worry about mid-story — every choice leads somewhere, some endings are just better than others.

Lost in Space Scene 1
🧑‍🚀

Loading…

Tune the Game (limited, on purpose)

Notice what you can't change here: there's no field for "how branching works" or "how endings are detected." That's the engine — the part every version of this game shares. You're only choosing which story (content) plays through it. That's the limit, on purpose.

What the two selects actually touch in the engine: Story only decides which entire scene-graph object stories[config.story] gets loaded — "Lost in Space," "Forest Temple," and "Time Travel Lab" have completely different scenes and endings, but they're all shaped exactly the same way (a start id, scenes with choices, endings marked ending: true), which is why the same goTo() function can walk any of them. Protagonist Sprite only sets avatarEl.textContent — it's never read by the branching logic at all.

👀 Peek at the Code

The game running above is this code — nothing hidden. It's split into two parts on purpose: a story graph (content) you just picked with the panel, and a locked engine that walks it.

✏️ Content — this is what the panel above picks between

👆 Right now config.story is 'space' and config.avatar is '🧑‍🚀' — hit "Apply & Restart" above to see these change. The excerpt below is always the "Lost in Space" scene graph as an example of the shape every story shares; switching stories swaps in a different object of the same shape, not different engine code.

const story = {
  start: {
    text: "Your ship's alarm blares — oxygen leak! What do you do?",
    choices: [
      { label: 'Patch the leak yourself', next: 'patch' },
      { label: 'Call mission control',   next: 'call' }
    ]
  },
  waitPod: {
    text: "You wait safely, then dock right on schedule. Mission success!",
    ending: true, good: true
  }
  // ...more scenes
};
🔒 Engine — locked, shared by every version of this game
function goTo(sceneId) {
  const scene = story[sceneId];

  // 1. an ending scene stops the loop
  if (scene.ending) { showEnding(scene.good); return; }

  // 2. otherwise render the scene text
  renderText(scene.text);

  // 3. render one button per choice
  scene.choices.forEach(choice => {
    renderButton(choice.label, () => goTo(choice.next)); // 4. jump on click
  });
}
This is what "architecture" means in practice: the story graph is the part of the design doc you filled out in Lesson 1 — but instead of one goal and one mechanic, it's a whole map of scenes and choices (the "structure diagram" from the drawing-board section). The engine is still the part no one writes twice: the same display, choice, and ending systems run every branching story you build.

🛠️ Now Build It For Real

You've played a working Choose-Your-Own-Adventure and seen exactly how it's built. Next, build this same architecture yourself — twice, in two different tools.

🧩 Step 1 — Build It in Scratch

The "Build the Loop with Blocks" section above already shows the exact scripts — backdrop, sprites, Lists (your numbered branch map), variables, and all six scripts, block by block, in Scratch's own category colors. Open a Scratch tab side-by-side and copy each script exactly; the game should come to life the same way it does here.

Open a blank Scratch project tab →

Want more practice first? There's no official in-editor deck for branching stories specifically, but the official Create a Story tutorial covers backdrops, characters, and dialogue these scenes build on.

Step 2 — Code It From Real Scratch (Lesson 2) Write this same scene-display, choice, and branch-lookup system yourself in plain JavaScript — no engine, no blocks. ↩️ Back to the Archetype Grid Return to What Makes a Game? — you've now seen a tutorial for every tiny-loop archetype except Dodging, which gets its own full build in Lesson 2.