Your First Campaign
This page walks you through building the smallest campaign that loads: one Main entity, one Actor, and one Map. You package it, validate it, and boot it headless, using an example campaign as the worked reference.
Introduction
A campaign is a complete game definition written as data. You describe characters, maps, and rules in YAML files, package them as a .zip, and the Isometry binary loads them. No code changes are needed to make a game.
By the end of this page you will understand the shape every entity file shares, know which entities a campaign cannot do without, and have run the full build-validate-boot loop. An example campaign is referenced throughout so you can compare your work against a known-good campaign.
Prerequisites
Before you start, make sure you have:
- Read What is Isometry for the big picture.
- Followed Install and run so the engine binary is downloaded and runnable.
The entity file shape
Every campaign is a folder of YAML files, and every file follows the same nesting: a type name, then one or more entity keys, then the fields for each entity. An entity is a pure-data record; there are exactly 33 entity types, and they hold data only, no game logic.
A minimal Main.yaml shows the shape at its smallest:
Main:
demoMain:
actor: heroActor
map: demoMap
Read this as: a Main entity, keyed demoMain, with two fields. The values "heroActor" and "demoMap" are not actors and maps themselves; they are KeyRefs, that is, the keys of other entities the engine resolves at load time. Entity keys must be unique across the whole campaign, so a key used for an Actor cannot be reused for a Map.
Note: You may put several entities, even of different types, in one file. The loader merges every YAML file in the campaign into a single set of entities. An example campaign typically splits entities across files for clarity (
Main.yaml,heroActor.yaml,map.yaml, and so on) but co-locates helpers, for example amap.yamlthat also defines theVectorthat the map's spawn point points to.
Main: the one required entity
Every campaign must contain exactly one Main entity. It defines the campaign's starting state, and only two of its fields are required:
| Field | Type | Points to |
|---|---|---|
actor |
KeyRef | the player-controlled Actor |
map |
KeyRef | the starting Map |
If Main is missing or duplicated, validation stops with an error such as Campaign requires exactly one Main entity (found 0).
Main also accepts two optional fields:
notes— a free-text campaign description, empty by default.plugins— an ordered list of nested campaign zips to merge in; earlier entries win, and the host campaign always takes priority.
Because Main.actor and Main.map are the only required values anywhere in a minimal campaign, your next two files just need to exist under the keys Main names.
Actor: a character in the world
An Actor is a character, player-controlled or AI-driven. Every Actor field is optional, so a bare {} passes schema validation. In practice you give the player actor a name, a sprite, and a few stats.
Here are the core fields for a hero actor, trimmed to the essentials:
Actor:
heroActor:
name: Hero
sprite: heroSprite
base: 8
speed: 1.0
perception: 25
salience: 1
Each field is doing one job:
nameis the display name. Always write the clean keyname; the underscore formname_is internal and never used in campaign files.spriteis a KeyRef to a Sprite entity.baseis the actor's footprint size in pixels (minimum 0).speedis movement speed (minimum 0.0).perceptionis the vision range in pixels (minimum 0).salienceis how easily others detect this actor (minimum 0).
Warning:
speedis a Float field, so it must carry a decimal point. Write1.0, not1. Integer fields likebaseandperceptionaccept whole-number floats such as8.0, but a Float field rejects a bare integer.
A full hero also references skills, resources, measures, a menu, triggers, and timers through KeyRefArrays. You can add those later; see Create an actor for the complete field set.
Map: where play happens
A Map is a place actors occupy. Like Actor, all its fields are optional. A typical map.yaml references a tilemap, a spawn point, and more:
Map:
demoMap:
name: Demo Map
tilemap: demoTileMap
spawn: demoSpawn
Vector:
demoSpawn:
x: 128
y: 16
Note that spawn is a KeyRef to a Vector entity, not a raw coordinate. The Vector, demoSpawn, is defined in the same file. This is the co-location pattern from earlier: the helper entity lives beside the entity that uses it.
For the smallest possible campaign, even tilemap and spawn may be omitted; a bare Map satisfies schema validation, and cross-reference validation only checks that any keys you do reference exist. To build a real, walkable map, see Build a map.
Package the campaign
Isometry loads a campaign from a .zip whose single root folder matches the campaign name. All asset paths inside the YAML are relative to that root.
Package your campaign folder with a standard zip command, run from the directory that contains it:
zip -r mycampaign.zip mycampaign/ -x "*.DS_Store"
This writes mycampaign.zip with the root folder inside the archive named mycampaign, and excludes .DS_Store files. Keep that root folder name consistent with the campaign name you load.
Validate and boot it
When a campaign loads, the validator runs in four phases:
- Schema — each entity has valid fields and types.
- Cross-reference — every KeyRef points to a real key, exactly one Main exists, and no keys are duplicated.
- Asset paths — referenced files exist (only when a ZIP archive is supplied).
- Dice expressions — any dice notation parses.
On success the engine logs Campaign validation passed.
The fastest check is a quick validate, which runs the validator and exits 0 on success or 1 on failure:
isometry --validate=mycampaign.zip
To run the full load pipeline headless, place the zip next to the engine binary and boot with --network=host:
isometry --campaign=mycampaign --network=host --port=5000 --username=p --secret=p --log-level=INFO
The campaign zip must sit in the same directory as the engine executable. Logs write to log.txt in that directory. A successful boot shows Campaign validation passed followed by Successfully created Entity lines.
Note:
--network=nonecurrently loads no campaign; it is a no-op. Use--network=hostto exercise the load pipeline. See CLI reference for every flag.
If validation fails, the log names the entity and field at fault. Fix the YAML and rerun the boot command; you do not need to repackage unless you changed which files are in the zip.
See also
- Glossary — definitions of every term used here.
- Entities and KeyRefs — how typed references resolve.
- Campaign structure — file layout and the merge model.
- Validation — the four phases and their error messages.
- Create an actor — the full Actor field set.
- Build a map — tilemaps, spawns, and deployments.
- CLI reference — all command-line flags.