Quick Start Guide
Create your first dynamic campaign in 10 minutes. This guide walks you through the essential concepts and shows you how to write a simple quest, using only fields the Campaign Cookbook actually reads.
What You'll Build
A simple investigation quest with:
- Dynamic location references using placeholders
- DM choice-driven progression
- Quest acceptance and completion tracking
- Branching outcomes based on DC checks
Step 1: Campaign File Structure
Create a new JSON file in data/campaigns/, named NN-slug.json to match the bundled campaigns' convention, and add an entry for it in data/campaigns/index.json:
Step 2: Basic Campaign Structure
Start with this minimal campaign structure. Only name, levelRange, description, and episodes actually matter to the app - there is no title, author, difficulty, or recommendedLevel field:
name, not title? The app reads campaign.name everywhere it shows the campaign title (baseCampaign?.name). It never reads a top-level title, author, or campaignId field - those were fictional in older docs and have been removed here.
Step 3: Add an Episode
Episodes contain your quest structure. Add your first episode. Set both id and episodeNumber - the app's episode lookup accepts either, but a handful of the real bundled campaigns shipped with only id and needed a runtime patch to backfill episodeNumber, so setting both up front avoids that trap. Likewise set title, not just name - episode.title is the field showEpisodeIntro() actually displays, and several bundled campaigns that only had name showed a literal "undefined" episode title until that was fixed:
{nearestBurg} - a dynamic placeholder that will be replaced with a real settlement name if data/maps/locations.json is configured, or generic fallback text ("the nearest settlement") if it isn't.
Step 4: Define Your Quest
Add a quest template to the episode:
Step 5: Create Scenes
Now add the story scenes. Start with the quest introduction. readAloud is inserted directly into the page as HTML, so it must be wrapped exactly as <div class='read-aloud'>...</div> with <p> tags inside - a bare <p> with no wrapping div will still display, but doesn't match what every real bundled campaign does and loses the read-aloud styling:
questActions array controls quest state. When the DM clicks "Accept the quest to stop the bandits", "accept:Stop the Bandits" is matched against the name field of a quest template in the current episode's questTemplates - it must match character for character.
Step 6: Add Investigation Scene
Add a scene where the party investigates the attack site:
Step 7: Add Branching Outcomes
Create different outcomes based on the DC check. Scene ids follow the convention ep{episodeNumber}-scene{N} for the main path and ep{episodeNumber}-scene{N}-{descriptor} for branches:
Step 8: Add Completion Scene
Create the final scene for quest completion:
Complete Example
Here's the full campaign file - every field in it is one the app actually reads:
Step 9: Test Your Campaign
To test your campaign:
- Place your campaign JSON in
data/campaigns/ - Add an entry to
data/campaigns/index.json(id, file, and the level-range bucket it belongs to) - Launch the app (
npm run dev) or use the Campaign Testbed to load the file directly - Select your campaign from the campaign grid
- Click through the scenes to verify choices, quest actions, and placeholders all resolve correctly
Key Concepts Learned
1. Dynamic Placeholders
{randomBurg:maxPopulation=300} // Random local settlement
{nearestDungeon:type=Cave} // Closest cave dungeon
2. Quest Actions
"questActions": ["complete:Quest Name"] // Complete quest
"questActions": ["fail:Quest Name"] // Fail quest
3. Branching Choices
Use nextScene to control story flow. null ends that branch (no further scene is shown). To move the DM into the next episode, simply point a choice's nextScene at a scene id that lives in a different episode's scenes[] array - the app auto-detects the episode transition, there's no special "end episode" field.
4. DC Checks
Present both success and failure options as separate choices for the GM to select.
Next Steps
Enhance Your Campaign
- Learn about all placeholders - Use more dynamic locations
- Master parameter syntax - Control location selection precisely
- Keep adventures local - Prevent globetrotting
- See investigation quest example - More complex structure
Advanced Features
- Multiple quests per episode
- Chain quests together
- Complex branching narratives
- NPC dialogue systems