Branching Story Example

An advanced campaign demonstrating diverging narrative paths, moral choices, and multiple endings. Every field below is one the app actually reads.

This page previously contradicted Campaign Structure. An earlier version used episodeId+name for episodes and a top-level quests array with a status field ("available"/"hidden") that doesn't exist anywhere in the real app. It's been rewritten to use episodeNumber+title and the real questTemplates shape - quests aren't "hidden," they simply get accepted by a scene's questActions whenever the DM reaches that branch.

Campaign Overview

The Cult of the Serpent

Level: 3-6

Duration: 5-8 sessions

Synopsis: A mysterious cult is growing in power. The party's choices determine whether they become heroes, villains, or something in between.

Features Demonstrated:

  • Three distinct narrative branches
  • Multiple endings (ally with cult, destroy cult, neutral path)
  • Quest failure leading to alternative storylines
  • Moral gray areas and consequences
  • Faction reputation system
  • Exclusive quest paths based on prior choices

Story Structure Diagram

Scene 1: Introduction | Scene 2: Quest Accept | Scene 3: First Contact / | \ / | \ / | \ Ally Path Neutral Path Destroy Path (Scene 4a) (Scene 4b) (Scene 4c) | | | (Scene 5a) (Scene 5b) (Scene 5c) | | | Ending A Ending B Ending C

A Key Subtlety: Quest Matching Is Scoped to the Current Episode

Verified against processQuestActions(): when a choice's questActions fires, the app looks up the quest name in getEpisode(this.currentState.episodeNumber).questTemplates - the episode it currently thinks it's in at the moment the choice is clicked, which is before that click's scene transition takes effect (episode transitions are detected inside showScene(), which runs after quest actions are processed). Practically, this means: a quest template must be defined in the questTemplates of whichever episode is "current" when each of its accept/complete/fail actions fires - not just wherever the quest was first introduced. The example below defines Investigate the Cult plus all three follow-on quests in episode 1 (since all four are accepted or completed while episode 1 is still current), and duplicates each follow-on quest's definition into the branch episode that later completes or fails it.

Complete Campaign JSON (Key Scenes)

{ "id": "cult-of-serpent", "name": "The Cult of the Serpent", "description": "A morally complex campaign where the DM's choices shape the story's direction and outcome.", "levelRange": { "min": 3, "max": 6 }, "episodes": [ { "id": 1, "episodeNumber": 1, "title": "The Investigation", "questTemplates": [ { "name": "Investigate the Cult", "type": "investigation", "description": "Learn more about the mysterious cult operating near {nearestBurg}", "rewards": { "xp": 150 } }, { "name": "Destroy the Cult", "type": "combat", "description": "Eliminate the cult threat permanently", "rewards": { "xp": 400, "reputation": { "faction": "The Temple", "value": 25 } } }, { "name": "Join the Cult", "type": "faction", "description": "Embrace the serpent's wisdom and power", "rewards": { "xp": 400, "reputation": { "faction": "The Cult", "value": 25 } } }, { "name": "Broker Peace", "type": "diplomacy", "description": "Find a middle ground between the cult and the town", "rewards": { "xp": 500, "gold": 100 } } ], "scenes": [ { "sceneId": "ep1-scene1", "title": "Strange Happenings", "readAloud": "<div class='read-aloud'><p>People in {nearestBurg} have been disappearing. Not kidnapped - they simply leave in the night, abandoning everything.</p><p>The town priest, Father Aldous, suspects a cult. 'They gather in {nearestDungeon:type=Ancient-Crypt},' he says. 'We must stop them before more souls are lost.'</p></div>", "choices": [ { "text": "Accept quest to investigate the cult", "nextScene": "ep1-scene2", "questActions": ["accept:Investigate the Cult"] } ] }, { "sceneId": "ep1-scene2", "title": "The Crypt", "readAloud": "<div class='read-aloud'><p>You approach {nearestDungeon:type=Ancient-Crypt} at dusk. Hooded figures chant in an ancient language. At the center, a woman in crimson robes addresses the gathered crowd.</p><p>'We offer knowledge,' she calls out. 'The serpent teaches truth that your priests hide from you.'</p></div>", "choices": [ { "text": "Attack the cult immediately", "nextScene": "ep1-scene3-attack" }, { "text": "Approach peacefully and listen to their teachings", "nextScene": "ep1-scene3-listen" }, { "text": "Observe from hiding (Stealth check)", "nextScene": "ep1-scene3-observe" } ] }, { "sceneId": "ep1-scene3-attack", "title": "The Destroy Path Begins", "readAloud": "<div class='read-aloud'><p>You draw weapons and charge. The cultists scatter, but the woman in crimson stands her ground.</p><p>'So you choose violence,' she says sadly. 'Very well. You will learn nothing today but regret.'</p><p>You defeat them, but find no evidence of wrongdoing - just religious texts and personal belongings.</p></div>", "dmNotes": { "enemies": { "cultists": { "count": 4, "hp": 9, "ac": 11 }, "high_priestess": { "count": 1, "hp": 58, "ac": 14 } } }, "choices": [ { "text": "Continue hunting cult members", "nextScene": "ep2-destroy-path", "questActions": [ "complete:Investigate the Cult", "accept:Destroy the Cult" ] } ] }, { "sceneId": "ep1-scene3-listen", "title": "The Ally Path Begins", "readAloud": "<div class='read-aloud'><p>You step forward peacefully. The woman in crimson smiles.</p><p>'Welcome, seekers. I am Sister Vexis. We offer knowledge the temple hoards - healing arts, ancient wisdom, truths about the gods.'</p><p>'The temple calls us evil because we threaten their monopoly on divine power. But judge for yourself - have we harmed anyone?'</p></div>", "choices": [ { "text": "Join the cult and learn their ways", "nextScene": "ep2-ally-path", "questActions": [ "complete:Investigate the Cult", "accept:Join the Cult" ] }, { "text": "Politely decline and return to report your findings", "nextScene": "ep1-scene3-neutral" } ] }, { "sceneId": "ep1-scene3-observe", "title": "The Neutral Path Begins", "readAloud": "<div class='read-aloud'><p>You watch from the shadows, gathering information. The cult teaches healing magic, philosophy, and meditation. No sacrifices, no dark rituals - just... learning.</p><p>However, you also notice their teachings contradict the temple's doctrine on several key points.</p></div>", "choices": [ { "text": "Report back to Father Aldous with your findings", "nextScene": "ep1-scene3-neutral" } ] }, { "sceneId": "ep1-scene3-neutral", "title": "A Difficult Choice", "readAloud": "<div class='read-aloud'><p>You return to Father Aldous with your report. He's furious.</p><p>'Heretics! They must be destroyed!' he demands. 'Will you help us, or do you side with blasphemers?'</p><p>But you're not sure the cult is truly evil. They seem to genuinely help people.</p></div>", "choices": [ { "text": "Help the temple destroy the cult", "nextScene": "ep2-destroy-path", "questActions": [ "complete:Investigate the Cult", "accept:Destroy the Cult" ] }, { "text": "Refuse and try to broker peace between temple and cult", "nextScene": "ep2-neutral-path", "questActions": [ "complete:Investigate the Cult", "accept:Broker Peace" ] }, { "text": "Side with the cult against the temple", "nextScene": "ep2-ally-path", "questActions": [ "complete:Investigate the Cult", "accept:Join the Cult" ] } ] } ] }, { "id": 2, "episodeNumber": 2, "title": "The Purge", "questTemplates": [ { "name": "Destroy the Cult", "type": "combat", "description": "Eliminate the cult threat permanently", "rewards": { "xp": 400, "reputation": { "faction": "The Temple", "value": 25 } } } ], "scenes": [ { "sceneId": "ep2-destroy-path", "title": "Hunting Heretics", "readAloud": "<div class='read-aloud'><p>You've chosen to eliminate the cult. Father Aldous provides you with a list of known members in {nearestBurg}.</p><p>As you hunt them down, you notice many are just ordinary people - healers, teachers, farmers - who joined seeking knowledge. But orders are orders.</p></div>", "choices": [ { "text": "Finish the purge and report back", "nextScene": "ep2-destroy-ending", "questActions": ["complete:Destroy the Cult"] } ] }, { "sceneId": "ep2-destroy-ending", "title": "Ending: The Purge", "readAloud": "<div class='read-aloud'><p>The cult is destroyed. {nearestBurg} returns to the temple's control.</p><p>Father Aldous thanks you, but the townsfolk look at you with fear. You killed healers, teachers, friends.</p><p>The temple's power is secure, but at what cost?</p><p><strong>Ending: Zealot's Path</strong></p></div>", "choices": [] } ] }, { "id": 3, "episodeNumber": 3, "title": "The Serpent's Embrace", "questTemplates": [ { "name": "Join the Cult", "type": "faction", "description": "Embrace the serpent's wisdom and power", "rewards": { "xp": 400, "reputation": { "faction": "The Cult", "value": 25 } } } ], "scenes": [ { "sceneId": "ep2-ally-path", "title": "Initiation", "readAloud": "<div class='read-aloud'><p>Sister Vexis welcomes you into the cult. You learn their healing arts and ancient knowledge.</p><p>But the temple is preparing to attack. Father Aldous has declared the cult heretical and called for its destruction.</p><p>'We must defend ourselves,' Sister Vexis says. 'Will you stand with us?'</p></div>", "choices": [ { "text": "Defend the cult against the temple", "nextScene": "ep2-ally-ending", "questActions": ["complete:Join the Cult"] } ] }, { "sceneId": "ep2-ally-ending", "title": "Ending: New Order", "readAloud": "<div class='read-aloud'><p>You defend the cult against the temple's forces. Father Aldous falls in battle.</p><p>The cult takes control of {nearestBurg}. Knowledge flows freely now, healing magic available to all.</p><p>But some whisper that you've simply replaced one dogma with another.</p><p><strong>Ending: Serpent's Champion</strong></p></div>", "choices": [] } ] }, { "id": 4, "episodeNumber": 4, "title": "The Middle Path", "questTemplates": [ { "name": "Broker Peace", "type": "diplomacy", "description": "Find a middle ground between the cult and the town", "rewards": { "xp": 500, "gold": 100 } } ], "scenes": [ { "sceneId": "ep2-neutral-path", "title": "Mediation", "readAloud": "<div class='read-aloud'><p>You attempt to broker peace. Both sides reluctantly agree to meet.</p></div>", "choices": [ { "text": "DC 16 Persuasion - Success: Achieve lasting peace", "nextScene": "ep2-neutral-success", "questActions": ["complete:Broker Peace"] }, { "text": "DC 16 Persuasion - Failure: Negotiations break down", "nextScene": "ep2-neutral-war", "questActions": ["fail:Broker Peace"] } ] }, { "sceneId": "ep2-neutral-success", "title": "Ending: Balance Restored", "readAloud": "<div class='read-aloud'><p>Through diplomacy, you achieve the impossible - the temple and cult agree to coexist.</p><p>{nearestBurg} benefits from both traditions. The temple maintains moral authority, while the cult provides healing and education.</p><p>Your name is spoken with reverence as the Peacemaker.</p><p><strong>Ending: Wisdom's Path</strong></p></div>", "choices": [] }, { "sceneId": "ep2-neutral-war", "title": "Ending: Civil War", "readAloud": "<div class='read-aloud'><p>Your mediation fails. War erupts between temple and cult.</p><p>{nearestBurg} tears itself apart. Both sides suffer devastating losses.</p><p>You leave the burning town behind, haunted by your failure to prevent the bloodshed.</p><p><strong>Ending: Ashes</strong></p></div>", "choices": [] } ] } ] }
Why episode numbers 2, 3, 4 for three mutually-exclusive branches? getEpisode() finds the first episode object matching a given episodeNumber, so three different branch episodes can't all reuse episodeNumber: 2 - only the first one would ever be found. Since only one branch is ever visited per playthrough, non-sequential episode numbers across parallel branches are fine; they don't need to represent story chronology.

Key Features Explained

1. True Branching Structure

Unlike linear campaigns, this creates three completely different story paths:

2. Four Different Endings

3. Exclusive Quest Chains

Notice how each branch's accept: action fires alongside complete:Investigate the Cult, so only one of the three follow-on quests ever gets accepted per playthrough:

Initial: "Investigate the Cult" (accepted at ep1-scene1)

Then, depending on the choice at ep1-scene3-*:
→ "Destroy the Cult" (accepted if you attack)
→ "Join the Cult" (accepted if you ally)
→ "Broker Peace" (accepted if you observe/negotiate)

4. Moral Gray Area

No choice is clearly "good" or "evil":

Design Patterns

Pattern 1: Point of No Return

Scene 3 is the branching point. After this choice, paths never converge:

ep1-scene3-attack → Episode 2 "The Purge" → Ending A
ep1-scene3-listen → Episode 3 "The Serpent's Embrace" → Ending B
ep1-scene3-observe → Episode 4 "The Middle Path" → Ending C or D

Pattern 2: Cascading Consequences

Early choices affect later options:

Pattern 3: Failure Creates Story

Failed neutral path doesn't end campaign - it creates a unique "civil war" ending:

Persuasion Success → "Wisdom's Path" ending
Persuasion Failure → "Ashes" ending (still valid conclusion)

Customization Ideas

Add More Branch Points

Create sub-branches within each path:

// Within Destroy Path { "text": "Spare the cult children", "nextScene": "ep2-destroy-merciful" }, { "text": "Show no mercy to anyone", "nextScene": "ep2-destroy-ruthless" }

Add Reconciliation Path

Allow players to switch paths mid-campaign:

Started Destroy Path → Discover temple corruption → Switch to Ally Path

Add Hidden Ending

Unlock secret ending if specific conditions met:

Testing Branching Campaigns

Critical: Test every path from start to finish. Branching campaigns multiply testing requirements.

Path Testing Checklist

Best Practices for Branching

1. Clearly Signal Branch Points

Make it obvious when choices have major consequences:

✓ Good: "This choice will determine your allegiance"
✗ Bad: Hidden consequences players don't see coming

2. Make All Paths Equal Length

Don't punish players for choosing one path over another:

✓ Good: Destroy Path (5 scenes), Ally Path (5 scenes), Neutral Path (5 scenes)
✗ Bad: Destroy Path (8 scenes), Ally Path (2 scenes) - feels unbalanced

3. Ensure All Endings Are Satisfying

Even "bad" endings should feel complete:

✓ Good: Civil War ending shows consequences and aftermath
✗ Bad: "You failed. Campaign over." (no closure)

See Also