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
What you will learn
Section titled “What you will learn”- 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 the file
Section titled “Create the file”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": []}Understand the identity fields
Section titled “Understand the identity fields”tutorial_codex is the campaign’s machine identity. Other objects will use it as a namespace:
tutorial_codex:greyhaventutorial_codex:mara_veytutorial_codex:missing_courierThe 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.
version
Section titled “version”This tutorial begins at version 1. A version number is not a substitute for stable IDs or migration planning.
description
Section titled “description”The description summarizes the player-facing premise. It should describe the campaign, not implementation details such as “contains two quests and a trigger.”
Understand the intro
Section titled “Understand the intro”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.
Why include empty root collections?
Section titled “Why include empty root collections?”A consistent root shape gives every later chapter an obvious insertion point:
towns → town definitionsnpcs → non-companion charactersdialogue → dialogue rootsquests → quest definitionsworldPlacements → chests, features, and scenestriggers → event-driven campaign reactionsEmpty collections also make diffs easier to read. You add content to an existing location instead of repeatedly restructuring the file.
Validating our progress
Section titled “Validating our progress”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.
1. Check the JSON syntax
Section titled “1. Check the JSON syntax”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
.jsonfiles and provides JSON syntax highlighting. Highlighting helps you spot structure, but it may not identify every syntax error without an additional JSON validation plugin.
2. Validate the campaign shell
Section titled “2. Validate the campaign shell”- Open the Author tools.
- Select Validate Campaign.
- Choose
tutorial_codex.json. - 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?Checkpoint 1
Section titled “Checkpoint 1”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.