Story Starts Reference

Complete documentation for tabs/story-starts.json.

Schema

interface StoryStart {
  name: string                      // ✅ Identifier, must match object key
  description: string               // ✅ Player-facing selection text
  storyStart: string                // ✅ Opening narrative for AI to expand
  locations: string[]               // ✅ Valid location keys from locations.json
  locationAreas: string[]           // ✅ Valid area keys, or [] for any area
  startingQuests?: string[]         // ✅ Quest ids or unique quest names; hidden quests become 'available' at start
  firstQuest?: string               // ✅ Freeform instruction for AI quest generation on turn 0
  startingItems?: InventoryDefinition[]  // ✅ Additional starting items
  startingPartyNPCs?: string[]      // ✅ NPC keys that join party at start
  isDefault?: boolean               // ✅ Used when the host does not pick a start (otherwise the first entry)
  questGenerationGuidance?: string  // ✅ Per-story-start quest generation guidance
  allowPlayerInput?: boolean        // ❌ Deleted from every start except the built-in "Write Your Own", where it is forced on
}

Legend

  • ✅ Predefine-able: Can be set in config, preserved via spread
  • ❌ Always overwritten: Set by initialization regardless of what exists in config

allowPlayerInput is engine-controlled: only the built-in story start named exactly “Write Your Own” keeps it (forced on, with an empty storyStart). Do not set it on authored starts.

Name uniqueness: keep story start display names unique. Story starts can be referenced from elsewhere in the config (for example from a trait’s unlockedBy or excludedBy) by id or by name; a name shared with another definition resolves to nothing, while an exact id always resolves.

InventoryDefinition Schema

interface InventoryDefinition {
  item: string         // Item key or name from items.json
  quantity: number     // Whole number of items to grant
}

Used by startingItems to specify additional inventory items. Entries resolve against the world’s item definitions by key or by name. Quantities must be whole numbers; fractional or absurdly large quantities are silently dropped.

Initialization Lifecycle

When a game starts with a story start, fields are processed in this order:

1. Quest Registration

All world config quests -> registered ('hidden' unless the quest authors a starting status)
      |
startingQuests quests -> hidden quests promoted to 'available'; already accepted quests keep their status
      |
firstQuest -> on turn 0, injects instruction into AI quest generation

Key difference:

  • startingQuests: Array of quest ids or unique quest names from tabs/quests.json - promotes those quests from 'hidden' to 'available' at start; a quest already accepted (e.g. via its authored status) keeps its status
  • firstQuest: Freeform text instruction - forces AI to generate a quest matching this description on turn 0

These are independent systems.

2. Location Selection

locations array provided?
    |-- Yes -> Pick random location from array
    |          |-- Filter locationAreas to those in chosen location
    |              |-- Pick random area from filtered list
    |-- No -> Pick random region
               |-- Pick random location in region
                   |-- Pick random area in location

locationAreas behavior:

  • Empty [] or omitted: ALL areas in the location are valid
  • Non-empty array: Only listed areas (that exist in location) are candidates
  • One area is randomly selected from valid candidates
  • locationAreas cannot have more entries than locations

Default start: when the host does not pick a story start, the entry with isDefault: true is used; if none is flagged, the first entry is used.

3. Party NPC Setup

For each NPC key in startingPartyNPCs:

  1. Find NPC by name in game state
  2. Move NPC to starting location/area
  3. Add to partyState.partyMembers
  4. Set npc.known = true (appears in journal)

NPCs that don’t exist in the config are silently skipped.

4. Starting Items

Items are added in priority order (all sources combined):

  1. itemSettings.startingItems - Global starting items
  2. Trait startingItems - From selected traits (deduplicated)
  3. Story start startingItems - Story-specific items
  4. Skill startingItems - From learned skills

All items are automatically equipped if valid slots are available. Late-joining players receive starting items too, in the same order.

5. Party State

After processing, partyState is initialized:

partyState.currentLocation = location.name
partyState.currentLocationArea = area
partyState.currentRegion = location.region
partyState.currentRealm = region.realm
partyState.currentCoordinates = [location.x, location.y]
partyState.day = 1              // Always 1
partyState.timeOfDay = ''       // Always empty
partyState.musicMood = 'peaceful'     // Always peaceful

6. Initial Narrative

The generateInitialStart AI task uses:

  • storyStart.storyStart text as the base narrative
  • Starting party NPCs included in context
  • Current location and area details
  • Player character backgrounds
  • Narrator style configuration

questGenerationGuidance

Optional per-story-start guidance for the quest generation AI. Layers on top of the world-level storySettings.questGenerationGuidance:

  • If both are set, world-level guidance is included as compatible context, and the story-start guidance steers quest and arc generation for this campaign.
  • If only the story-start guidance is set, only that is used.
  • If only world-level guidance is set, only that is used.

Use this when one story-start has a distinctly different tone, scope, or quest cadence from the rest of the world.

Cross-References

Field References
locations tabs/locations.json (keys, not names)
locationAreas areas object within referenced locations
startingQuests tabs/quests.json (quest ids, or unique quest names)
firstQuest Freeform text (no reference)
startingItems[].item tabs/items.json (item keys or names)
startingPartyNPCs tabs/npcs.json (keys, not names)

This site uses Just the Docs, a documentation theme for Jekyll.