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.

This documentation was corrected against the real, running application. Every field, code example, and placeholder behavior on this site was verified directly against 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.
New to campaign writing? Start with the Quick Start Guide to create your first campaign in minutes.

What is the Campaign API?

Campaigns are JSON files that:

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:

"readAloud": "<div class='read-aloud'><p>The merchant was last seen heading to {nearestBurg}...</p></div>"

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}
{randomBurg:maxPopulation=300}
{nearestDungeon:type=Cave,difficulty=hard}

Quest Action System

Control quest state transitions through DM choices:

"choices": [ { "text": "Accept the quest", "nextScene": "ep1-scene2", "questActions": ["accept:The Missing Merchant"] } ]

Quick Example

Here's a complete scene that uses the Campaign API - this would actually work if pasted into a real campaign file:

{ "sceneId": "ep1-scene2", "title": "The Missing Merchant", "readAloud": "<div class='read-aloud'><p>Mayor Aldric of {nearestBurg} asks for help. A merchant caravan was attacked on the road to {randomBurg:maxPopulation=300}.</p></div>", "choices": [ { "text": "Accept the quest", "nextScene": "ep1-scene3", "questActions": ["accept:The Missing Merchant"] }, { "text": "Decline", "nextScene": null } ] }

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.