Skip to content

Demo Pack

Kurt edited this page Jul 9, 2026 · 6 revisions

Demo Pack

Audience: Builder Status: ✅ Ready

The demo pack is the reference world that ships in the repo (internal/content/packs/demo). It's a complete, playable example every builder can read as a template: three connected zones, mobs with scripted behavior, items, abilities, loot, crafting, chargen, and display templates — all in the directory-tree pack format. If you want to see how a real pack fits together, read the demo alongside the Pack Entity Reference.

What it is and how it loads

The demo is embedded into the binary (//go:embed) for tests and bare dev runs, and seeded into Postgres by make seed (telos-seedImportPack). Its manifest (pack.yaml) is deliberately tiny — pack: demo and default_combat: melee — and the rest lives in per-section files and a zones/ subtree. A minimal core pack is its bootstrap counterpart: core is layered under every real pack so the world always has at least a lobby, even before demo content is seeded (see Content Loading & Hot Reload).

The three zones

Zone Feel Notable content
midgaard the home town / hub — where players spawn the temple, the market, a guild hall; the friendly quartermaster mob
darkwood the wilderness across the market boundary a grove, a cave; the goblin-chief world boss + its herald warstone; a cave spider; an archmage
crypt a dungeon skeletons and a tomb-guardian with full stat sheets and aggro

The zones are wired together by cross-zone exits — walking north out of the market crosses into the darkwood grove (north: darkwood:room:grove). When both zones are co-hosted on one shard this is an in-process move; when they're on different shards it becomes a cross-shard handoff. (Cross-pack exits are not allowed — a pack is a self-contained world.)

Reading the tree as a template

Under zones/00-midgaard/ the numeric-prefixed files show the canonical split:

packs/demo/
  pack.yaml                 # manifest: pack name + default_combat
  attributes.yaml           # pack-global def sections...
  resources.yaml
  damage_types.yaml
  abilities.yaml            # fireball, lightning bolt, life drain, cure, craft/salvage verbs
  affects.yaml
  combat_profiles.yaml      # the "melee" profile
  channels.yaml            # gossip / newbie / guild
  loot_tables.yaml  rarity_tiers.yaml  affix_defs.yaml
  recipes.yaml  wear_slots.yaml  tracks.yaml  bundles.yaml  chargens.yaml
  display_defs.yaml        # score + who sheets
  regions.yaml  spawn_schedules.yaml
  zones/
    00-midgaard/
      00-zone.yaml  10-rooms.yaml  20-items.yaml  30-mobs.yaml  40-resets.yaml
    01-darkwood.yaml       # a whole zone can also be one file
    02-crypt.yaml

The prefixes are a readability convention — the loader merges by ref, not by position (see Pack Authoring). Each file maps directly to a section in the Pack Entity Reference.

Scripted behavior worth studying

The demo is also the best worked reference for Lua scripting and hooks:

  • The quartermaster greets each newcomer once, using an on("greet") trigger and per-instance self.state to remember who it has met.
  • The world-boss loop spans zones and the director: a herald warstone reacts to a spawn.boss world event with on_world(...) and mud.spawn; when the goblin chief dies, its on("death") fires signal_world("boss.died", ...) and the director reschedules it a week later.
  • Reactions: an archmage counters a spell with an on("BeforeCastCommit") hook calling rx:cancel(); a warden buffs its AC for one swing with on("ToHit") and rx:modify("ac", 5).
  • A room affect: the cave spider webs entrants via on("enter") and self:apply_affect("web").
  • Lua-scripted abilities: lightning bolt and life drain roll dice in Lua and route damage through the gated ctx.target:damage{...} funnel.
  • Display templates: the score and who sheets are content Lua using the ui toolkit.

Because it exercises nearly every engine surface, the demo doubles as a regression fixture — it's expected to render consistently across the engine's content migration.

Clone this wiki locally