Skip to content

1. Create the Campaign Shell

This chapter creates the smallest useful source file for The Drowned Bell. It contains campaign identity, opening narrative, and the root collections that later chapters will fill.

Download Checkpoint 1 — campaign shell

  • The difference between a design document and a campaign payload
  • Why campaign IDs must be stable
  • How namespacing prevents collisions
  • Why a predictable root shape makes later work easier
  • How to check JSON syntax before campaign validation

Create tutorial_codex.json and paste this payload:

{
"id": "tutorial_codex",
"title": "The Drowned Bell",
"version": 1,
"description": "A bell rings beneath the ruined belfry outside Greyhaven. Find a missing courier's warning, recruit a local seer, and descend into the flooded crypt before the echoes claim the town.",
"intro": {
"title": "A Bell Where No Bell Stands",
"subtitle": "Greyhaven, before the fourth toll",
"text": [
"Greyhaven has stopped sleeping.",
"For three nights, a bell has sounded beneath the hills north of town. The old belfry collapsed generations ago, and no bronze remains in its tower, yet each toll rolls through the wells and floorboards as though the earth itself were ringing.",
"At dawn, you reach the town road. Somewhere beyond the roofs, a fourth toll begins."
],
"canSkip": true
},
"towns": {},
"dungeons": {},
"npcs": {},
"companions": {},
"items": {},
"monsters": {},
"dialogue": {},
"quests": {},
"spells": {},
"shrines": {},
"lootTables": {},
"worldRules": {},
"townServices": [],
"safetyZones": [],
"worldPlacements": [],
"triggers": []
}

tutorial_codex is the campaign’s machine identity. Other objects will use it as a namespace:

tutorial_codex:greyhaven
tutorial_codex:mara_vey
tutorial_codex:missing_courier

The colon separates the campaign namespace from the object’s local name. It is a convention that makes ownership and references obvious.

The title is player-facing copy. It can be revised more safely than the campaign ID, though published presentation changes should still be reviewed.

This tutorial begins at version 1. A version number is not a substitute for stable IDs or migration planning.

The description summarizes the player-facing premise. It should describe the campaign, not implementation details such as “contains two quests and a trigger.”

The intro object is presentation shown when the campaign begins. At this checkpoint it establishes tone, but does not yet choose a starting coordinate. Greyhaven and the starting location arrive together in Chapter 2.

text is an ordered array of paragraphs. Keeping paragraphs separate gives the runtime control over presentation and makes revisions easier to review.

canSkip: true lets returning testers move through the introduction quickly.

A consistent root shape gives every later chapter an obvious insertion point:

towns → town definitions
npcs → non-companion characters
dialogue → dialogue roots
quests → quest definitions
worldPlacements → chests, features, and scenes
triggers → event-driven campaign reactions

Empty collections also make diffs easier to read. You add content to an existing location instead of repeatedly restructuring the file.

We will check this small campaign shell before adding Greyhaven, characters, or quests. Working in small checkpoints makes errors easier to understand: when only one section has changed, there are fewer places for a mistake to hide.

Before the Author tools can check campaign rules, the file must first be readable as JSON. This is a JSON syntax check, not yet a campaign validation check.

Common JSON syntax mistakes include:

  • a trailing comma after the final property,
  • quotation marks inside text that have not been escaped,
  • a missing closing brace or bracket,
  • comments such as // add quests later.

JSON does not support comments.

A JSON-aware editor can catch many of these mistakes while you type:

  • Visual Studio Code provides built-in JSON checking, error underlines, formatting, bracket matching, and folding. Make sure the language mode is JSON, not JSON with Comments.
  • Notepad++ recognizes .json files and provides JSON syntax highlighting. Highlighting helps you spot structure, but it may not identify every syntax error without an additional JSON validation plugin.
  1. Open the Author tools.
  2. Select Validate Campaign.
  3. Choose tutorial_codex.json.
  4. Correct any JSON syntax errors first, then correct any campaign validation errors or warnings.

At this checkpoint, the validator checks the campaign data in plain terms:

  • the campaign has a usable ID, title, and version,
  • the known root collections have the expected object or array shape,
  • supplied values use supported data types,
  • the payload follows the current campaign contract closely enough to continue building.

There is not yet meaningful gameplay to test. Passing this checkpoint does not prove that the future campaign will be reachable, balanced, clear, or fun. It proves that this small foundation is readable and structurally acceptable before we build on it.

The progression is:

Can the file be read as JSON?
→ Does it follow the campaign rules?
→ Does it actually work in the game?

You should now have:

  • campaign ID tutorial_codex,
  • title, version, and description,
  • an intro with ordered narrative text,
  • empty canonical root collections,
  • no campaign-owned object IDs yet.

Continue to Chapter 2: Add Greyhaven.