Campaign API Reference
Welcome to the Campaign Cookbook Campaign API documentation. This guide will help you create dynamic, replayable campaigns for the Campaign Cookbook reading pane.
renderer/dm-toolkit/dm-toolkit-controller.js, renderer/dm-toolkit/campaign-library.js, and the 30 real bundled campaign JSON files in data/campaigns/ - not against memory or an earlier spec. If something here looks different from what you remember, this version is the one that matches the shipping app. See Campaign Structure for the full schema reference.
What is the Campaign API?
Campaigns are JSON files that:
- Reference real, named towns and NPCs that Campaign Cookbook generates automatically per party+campaign
- Keep adventures appropriately scaled with population-based filtering
- Support branching narratives based on DM choices
- Degrade gracefully to generic text if generation is ever unavailable
Key Features
Dynamic Location Placeholders
Reference locations instead of hardcoded names. readAloud text must be wrapped in a read-aloud div with <p> tags inside - see Campaign Structure for why:
Scoped Location Selection
Keep early adventures feeling small, and later ones grand, using population-based filters. Parameters are pipe-free, comma-separated key=value pairs after a colon:
{randomBurg:maxPopulation=300}
{nearestDungeon:type=Cave,difficulty=hard}
Quest Action System
Control quest state transitions through DM choices:
Quick Example
Here's a complete scene that uses the Campaign API - this would actually work if pasted into a real campaign file:
Available Placeholders
| Placeholder | Description | Parameters |
|---|---|---|
{nearestBurg} |
Closest settlement to starting location | None |
{randomBurg} |
Random settlement from the party's generated roster | minPopulation, maxPopulation |
{capitalCity} |
Capital city (highest population) | None |
{targetBurg} |
A second, distinct random settlement pick, cached once per campaign load | None |
{nearestDungeon} |
Closest dungeon to starting location | type, difficulty |
{randomDungeon} |
Random dungeon flavor-text entry (not a real, playable dungeon) | type, difficulty |
{targetDungeon} |
A second, distinct random dungeon pick, cached once per campaign load | None |
{dungeon:id} |
Not flavor text - opens a real, playable, campaign-authored dungeons[] entry |
None |
{monster:Name} |
Monster stat block from the bundled bestiary | count, variant (pipe-separated after the name) |
{nobleNPC}, {merchantNPC}, {cultistNPC}, {priestNPC} |
A real generated D&D 5e NPC - name plus a full clickable stat block. Add _2, _3, etc. ({nobleNPC_2}) for a genuinely different person, not the same one reused. |
None |
See Placeholders Overview
for the complete list, including {nearestTemple},
{randomRuin}, {randomTower},
{targetLocation}, and {randomNPC_<profession>}.
Quest Actions
| Action | Description | Syntax |
|---|---|---|
| accept | Marks quest as accepted/active | accept:Quest Name |
| complete | Marks quest as completed, allocates rewards | complete:Quest Name |
| fail | Marks quest as failed | fail:Quest Name |
Next Steps
Ready to start writing?
Follow the Quick Start Guide to create your first campaign.
Or dive into the Placeholders Overview to learn about dynamic location references.