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 fromtabs/quests.json- promotes those quests from'hidden'to'available'at start; a quest already accepted (e.g. via its authoredstatus) keeps its statusfirstQuest: 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
locationAreascannot have more entries thanlocations
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:
- Find NPC by name in game state
- Move NPC to starting location/area
- Add to
partyState.partyMembers - 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):
itemSettings.startingItems- Global starting items- Trait
startingItems- From selected traits (deduplicated) - Story start
startingItems- Story-specific items - 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.storyStarttext 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) |