Settings Reference
Complete documentation for tabs/settings.json.
AttributeSettings Schema
interface AttributeSettings {
attributeNames: string[] // ✅ Thematic attribute names for the world
startingAttributeValue: number // ✅ Base attribute value (balanced: 0)
startingAttributePoints: number // ✅ Points to allocate at creation (balanced: 0)
maxStartingAttribute: number // ✅ Hard cap at creation (balanced: 0)
attributeBonusModifier: number // ✅ Multiplier for attribute bonus to checks (balanced: 2.5)
lowAttributeThreshold: number // ✅ Below this grants weakness traits (balanced: 8)
lowAttributeTraits: Record<string, string> // ✅ Weakness descriptions per attribute (required; use {} for none)
attributeStatModifiers: Record<string, AttributeStatModifier> // ✅ Keyed by attribute name (required; use {} for none)
attributeDamageModifiers?: Record<string, number> // ✅ Per-point % bonus to OUTGOING damage, keyed by attribute. e.g. { strength: 1 } = +1% damage per point of strength. Use positive values; negative values are ignored
attributeDamageReductionModifiers?: Record<string, number> // ✅ Per-point % reduction to INCOMING damage, keyed by attribute. e.g. { dexterity: 1 } = -1% damage taken per point of dexterity. Use positive values; negative values are ignored
}
interface AttributeStatModifier {
variable: string // Resource name (e.g. 'health' or custom resource)
amount: number // Bonus per attribute point
}
Legend
- ✅ Predefine-able: Can be set in config, used directly
SkillSettings Schema
interface SkillSettings {
trainingCooldown: number // ✅ Ticks between training (balanced: 10)
skillBonusModifier: number // ✅ Multiplier for skill level to checks (balanced: 1)
maxSkillLevel: number // ✅ Maximum skill level (balanced: 999)
maxSkillSuccessLevel: number // ✅ Maximum absolute contribution any single skill, attribute, ability, random roll, or context modifier can make to a success check (balanced: 999)
startingXPToLevelUpSkill: number // ✅ XP for first skill level (balanced: 50)
additionalXPRequiredPerSkillLevel: number // ✅ Additional XP per level (balanced: 50)
baseXPFromSkillUpgrade: number // ✅ Bonus XP on skill level-up (balanced: 100)
charXPPerSkillLevel: number // ✅ Character XP from skill progression (balanced: 100)
baseChanceToLearnNewSkill: number // ✅ Learning success rate 0-1 (balanced: 1)
skillLearningBonusModifier: number // ✅ Attribute contribution to learning (balanced: 1)
xpFromNewSkill: number // ✅ Character XP awarded when learning a new skill (balanced: 200)
skillTypeDifficultyBonus: Record<string, number> // ✅ Bonus by skill type, always include "none": 0
skillXPRewards: SkillXPRewards // ✅ XP amounts by impact size
newSkillGenerationEnabled: boolean // ✅ Allow AI to invent skills beyond the config (default: true)
}
interface SkillXPRewards {
small: number // ✅ XP for small impact (balanced: 50)
medium: number // ✅ XP for medium impact (balanced: 100)
large: number // ✅ XP for large impact (balanced: 150)
huge: number // ✅ XP for huge impact (balanced: 200)
}
LocationSettings Schema
interface LocationSettings {
regionSize: number // ✅ Region size in km (balanced: 100). Location x/y must stay within half this value of the origin; farther placements are flagged as off the map
simpleRadius: number // ✅ Simple interaction radius in km (balanced: 5)
complexRadius: number // ✅ Complex interaction radius in km (balanced: 10)
regionLocationCount: number // ✅ Locations per region (world-specific)
avgTravelDistance: number // ✅ Average distance between locations (balanced: 40)
minTravelDistance: number // ✅ Minimum distance between locations (balanced: 20)
newRegionGenerationEnabled: boolean // ✅ Whether the engine pre-generates adjacent regions as players approach boundaries (default: true). Set false to keep the world bounded to predefined regions only.
encountersEnabled: boolean // ✅ Whether random wilderness encounters can interrupt travel between locations (default: false)
regionMapBorderFeatheringEnabled?: boolean // ✅ Whether region map images use the feathered border and rounded frame treatment (default: false)
}
Removed: regionFactionCount. The engine no longer generates factions (see the factions skill), so nothing reads this field; drop it from existing configs.
ItemSettings Schema
interface ItemSettings {
currencyName: string // ✅ Thematic currency name (world-specific)
startingItems: StartingItem[] // ✅ Items at character creation (balanced: [])
itemCategories: string[] // ✅ Must include "Armor", "Consumable"
itemSlots: ItemSlot[] // ✅ Must include 7 armor slots
}
interface StartingItem {
name: string // Item key from items.json
quantity: number // Number of items
}
interface ItemSlot {
slot: string // Slot name (head, chest, etc.)
category: string // Category from itemCategories
quantity: number // Max items in slot
}
CombatSettings Schema
interface CombatSettings {
baseCombatXP: number // ✅ Base XP for combat victory (balanced: 200)
minCombatXP: number // ✅ Minimum XP from combat (balanced: 50)
abilityCooldown: number // ✅ Cooldown given to AI-generated (learned) abilities, and the minimum turns between learning new ones. Does NOT affect predefined abilities (balanced: 0)
abilityBonus: number // ✅ Default bonus given to AI-generated (learned) abilities. Does NOT scale predefined abilities, which use their own authored bonus (balanced: 10)
npcDailyHealingAmount: number // ✅ NPC healing per day (balanced: 999)
damageTypes: string[] // ✅ Available damage types (world-specific). Use lowercase ASCII — matching against vulnerabilities/resistances/immunities is case-sensitive and unnormalized, so "Fire" ≠ "fire" and mismatches fail silently
damageTypePresentation: Record<string, DamageTypePresentation> // ✅ UI presentation per damage type, keyed by a damageTypes entry (required; use {} for none)
}
interface DamageTypePresentation {
emoji?: string // ✅ Emoji shown next to the damage type in combat UI. Emoji characters only; text is rejected
}
OtherSettings Schema
interface OtherSettings {
npcHealthPerLevel: number // ✅ NPC HP per level (balanced: 10)
npcMinHealth: number // ✅ NPC base HP (balanced: 0)
visualNovelModeByDefault?: boolean // ✅ Applied once when a player first enters the game; unset lets the player's own device preference decide
}
Player HP scaling lives on the health resource in resourceSettings — maxValue is the level-1 maximum and gainPerLevel is the per-level growth. See the Resource schema in the ai-instructions reference.
ProgressionSettings Schema
Required section controlling character XP, level-ups, and what each level-up grants. Validation surfaces errors for bad values; if an invalid value slips into a saved config anyway, the engine silently falls back to that field’s default when the game loads.
interface ProgressionSettings {
startingCharacterLevelUpRequirement: number // ✅ XP required to reach level 2 (balanced: 500)
extraRequiredXPPerCharacterLevel: number // ✅ Additional XP added per subsequent level; 0 = flat curve (balanced: 100)
maxCharacterLevel: number // ✅ Leveling stops at this level (balanced: 999)
abilityPointEveryLevels: number // ✅ Grant ability points every N levels (balanced: 1)
abilityPointsPerGrant: number // ✅ Ability points per grant (balanced: 1)
attributePointEveryLevels: number // ✅ Grant attribute points every N levels (balanced: 5)
attributePointsPerGrant: number // ✅ Attribute points per grant (balanced: 1)
maxAttributeValue: number // ✅ Cap on any attribute raised by spending points (balanced: 999)
traitPickEveryLevels: number // ✅ Grant trait picks every N levels (balanced: 10)
traitPicksPerGrant: number // ✅ Trait picks per grant (balanced: 1)
locationDiscoveryXP: number // ✅ XP each party member gains on first entering an area (balanced: 10)
levelUpTraitPool: string[] // ✅ Trait names offered on level-up trait picks (balanced: [])
milestoneTitles: MilestoneTitle[] // ✅ Titles granted at exact levels (balanced: Initiate@1, Adept@10, Veteran@20, Expert@30, Master@40, Legend@50)
}
interface MilestoneTitle {
levelGranted: number // Level at which the title is granted (unique positive integer)
title: string // Displayed title (non-blank)
}
XP Curve
Reaching level 2 requires startingCharacterLevelUpRequirement XP; each later level adds extraRequiredXPPerCharacterLevel on top of the previous requirement (0 gives a flat curve — the only field allowed to be 0). Leveling stops entirely at maxCharacterLevel.
XP Sources
Characters gain XP from quest completion, major story events (party-wide), skill level-ups, and location discovery — every party member gains locationDiscoveryXP the first time the party enters each area (scaled up in NG+).
Level-Up Grants
On each level-up, the new level L is checked against each grant interval:
- If L is a multiple of
abilityPointEveryLevels, grantabilityPointsPerGrantability points. The defaults (1/1) reproduce the classic one-ability-point-per-level behavior. - If L is a multiple of
attributePointEveryLevels, grantattributePointsPerGrantattribute points — capped so banked points never exceed what could still be spent undermaxAttributeValue. - If L is a multiple of
traitPickEveryLevels, granttraitPicksPerGranttrait picks — capped by how many eligible pool traits remain.
Spending Points and Picks
Players spend attribute points in the Stats tab (batch spend; the spend is rejected if any attribute would exceed maxAttributeValue), unlock traits from levelUpTraitPool in the Traits tab (the offered list is filtered by trait requirements, unlockedBy, and excludedBy; effects apply immediately, just like starting traits), and choose a displayed title.
GOTCHA: an empty levelUpTraitPool (the default) means no trait picks are ever granted, regardless of traitPickEveryLevels. See the traits skill for authoring the pool traits themselves.
Milestone Titles
Titles are granted only when a level is hit exactly — a skipped milestone level is not back-granted later. A newly earned title is auto-selected and the player is prompted about it. Removing a title from the config retroactively hides it from players who already earned it. levelGranted values must be unique positive integers and titles must be non-blank.
Constraints
Every numeric field must be a positive whole number, except extraRequiredXPPerCharacterLevel which may be 0 (non-negative). levelUpTraitPool entries must name existing traits.
characterCreationMusic
characterCreationMusic?: 'fantasy' | 'nonfantasy' // ✅ Background music played during character creation. Defaults to 'fantasy'
Sets which background music plays on the character-creation screen. 'fantasy' (the default) or 'nonfantasy'.
imageModelSource
imageModelSource?: string // ✅ Image model used for every generated image (portraits, location/area images, region maps). One of: 'falai-gpt-image-2-low' | 'falai-gpt-image-2' | 'google-nano-banana-lite' | 'google-nano-banana-pro' | 'falai-flux-2-dev'
Optional top-level field that pins which image-generation model renders the world’s images while editing it. Games created from the world start with this choice as their default, but each game can be created with its own image-model selection. Leave it unset (or set to an unrecognized name) to fall back to the platform’s current default model.
worldVoices
worldVoices?: Record<string, WorldVoice> // ✅ Voice presets keyed by an id you choose; referenced by npcs[].worldVoiceId and premadeCharacters[].worldVoiceId
interface WorldVoice {
label: string // ✅ Display name shown to players (required). Use `label`, not `name`
voiceTag: string // ✅ One of the character voice tags, e.g. 'male gravelly ancient' (required; trimmed). Picks the base voice
instructions?: string // ✅ Free-text delivery guidance layered on the base voice
speed?: number // ✅ Playback speed; clamped to 0.5-2, omit for the base voice default
effects?: VoiceEffects // ✅ Audio effects chain; omit any sub-effect you do not use
exposeInCharacterCreation?: boolean // ✅ true lets players pick this preset for their own character at character creation. NPC and premade assignment works either way
}
interface VoiceEffects {
pitch?: { enabled: boolean, semitones: number } // ✅ Pitch shift, -12..12 semitones
reverb?: { enabled: boolean, space: 'room' | 'hall' | 'cavern', mix: number } // ✅ mix is the wet/dry balance 0-1
echo?: { enabled: boolean, delayMs: number, feedback: number, mix: number } // ✅ delayMs 40-1000, feedback 0-0.85, mix 0-1
eq?: { // ✅ Six fixed bands: cuts outside, shelves inside, two bells in the middle
enabled: boolean
highPass: { enabled: boolean, frequency: number }
lowShelf: { enabled: boolean, frequency: number, gainDb: number }
bell1: { enabled: boolean, frequency: number, gainDb: number, q: number }
bell2: { enabled: boolean, frequency: number, gainDb: number, q: number }
highShelf: { enabled: boolean, frequency: number, gainDb: number }
lowPass: { enabled: boolean, frequency: number }
} // ✅ Band gainDb -15..15, q 0.3-8
distortion?: { enabled: boolean, drive: number } // ✅ drive 0 (clean) to 1
output?: { enabled: boolean, gainDb: number, compressor: boolean } // ✅ gainDb -12..12
}
A catalog of reusable voice presets. NPCs and premade characters reference a preset with worldVoiceId; the id must exist in worldVoices. Only presets with exposeInCharacterCreation: true appear as choices when players build their own character.
The engine sanitizes every preset on load: label and voiceTag are trimmed, speed and every effect parameter are clamped into the ranges above, a missing or non-numeric parameter falls back to its default rather than failing, and an effect with enabled: false is kept but inactive. The catalog size is capped, so keep it to voices the world actually uses.
Example:
{
"gravel-elder": {
"label": "Gravel Elder",
"voiceTag": "male gravelly ancient",
"instructions": "Slow, weary, every sentence costs effort.",
"speed": 0.9,
"effects": {
"reverb": { "enabled": true, "space": "hall", "mix": 0.2 }
},
"exposeInCharacterCreation": false
}
}
successLevelSettings
successLevelSettings: SuccessLevelSettings // ✅ Required top-level field; the example world carries the stock ladder below
interface SuccessLevelSettings {
firstSuccessfulTierId: string // ✅ id of the lowest tier that counts as a success; it and every higher band succeed
tiers: SuccessTier[] // ✅ Contiguous whole-number score bands; list order does not matter, bands do
}
interface SuccessTier {
id: string // ✅ Unique key, referenced by firstSuccessfulTierId
name: string // ✅ Player-facing outcome name, unique ignoring case and surrounding spaces. action-success-level trigger conditions name tiers by this
minScore: number | null // ✅ Lowest adjusted score in the band; null only on the lowest tier
maxScore: number | null // ✅ Highest adjusted score in the band; null only on the highest tier. The next tier starts one point higher
prompt: string // ✅ Narration note for this outcome; is replaced with the acting character's name
imageUrl?: string | null // ✅ Optional image shown with the result, on official Latitude image hosting
}
The success ladder turns a player’s skill-check score into a named outcome. The score (see Skill Check Formula) is adjusted down by 2 per 10 character levels, and the tier whose band contains the adjusted score is the outcome. The tier’s name is the success level shown to players and recorded on the action, and its prompt is the note the narrator receives for that action. Simple actions (no check needed) and impossible actions do not use the ladder. NPC actions never use it either; they keep the engine’s fixed bands (see NPC Success Rolls).
Every tier from firstSuccessfulTierId upward is a success; tiers below it are failures. Successful tiers also carry a strength from 0 (the first successful tier) to 1 (the highest tier), spaced evenly across the successful tiers; a ladder with a single successful tier gives it full strength. Strength is what combat reads:
| Action | Effect of a successful tier with strength s |
|---|---|
| Attack or heal | Base damage 8 + 20 × s (rounded), before the level bonus and the usual multipliers. A simple action uses 16. Failures deal nothing |
| Evade or defend | Incoming damage reduced by 0.5 + 1.6 × s, capped at 1.0, so any success from roughly a third of the way up the successful tiers fully nullifies the hit. A simple action fully nullifies |
| preventAttack or subdue | Full effect on any success |
| Buff | Buff potency 0.2 + 0.8 × s; the damage boost granted by a buff intent is 0.1 + 0.4 × s |
| Combat conflict | When a player’s defend or evade contests an NPC attack, a player success with strength 0.5 or more turns the NPC’s attack into a failure; a weaker success limits it to mixed results |
The highest tier is the critical outcome; the lowest failing tier is the critical failure.
Bands are whole numbers and contiguous: each tier starts one point above the previous tier’s maxScore, with no gaps or overlaps, only the lowest tier has minScore: null, and only the highest tier has maxScore: null. Ids are unique, and names are unique ignoring case and surrounding spaces. During play the engine falls back to the stock ladder in place of a ladder that breaks these rules; an authored world must carry a valid ladder of its own.
Stock ladder (the one in the example world):
| Tier | id | Band | Outcome |
|---|---|---|---|
| Critical Failure | critical-failure | up to -66 | failure |
| Failure | failure | -65 to -51 | failure |
| Mixed Results | mixed-results | -50 to -26 | success, strength 0 (first successful tier) |
| Basic Success | basic-success | -25 to -1 | success, strength 0.25 |
| Success | success | 0 to 24 | success, strength 0.5 |
| Great Success | great-success | 25 to 49 | success, strength 0.75 |
| Critical Success | critical-success | 50 and up | success, strength 1 |
Renaming a tier changes what action-success-level conditions must name; a condition naming a tier the ladder no longer has stays inactive (see the triggers reference).
Skill Check Formula
successScore = totalBonus - totalDifficulty
adjustedScore = successScore - floor(characterLevel / 10) * 2 (placed on the success ladder)
totalBonus = skillBonus + attributeBonus + earlyGameBonus + randomBonus + modifierBonus
Where:
skillBonus = skillBonusModifier * effectiveSkillLevel
attributeBonus = (effectiveAttribute - 10) * attributeBonusModifier
earlyGameBonus = 10 (if gameTick < 50, else 0)
The attribute is the one linked by the relevant skill, taken from the world’s skill definition or, failing that, the character’s own skill entry. The link resolves against the character’s attributes by exact key first, then ignoring case and spacing. A skill whose attribute matches none of the character’s attributes contributes no attribute bonus at all.
Combat Balance System
Player HP Formula
Player HP at level L = resourceSettings.health.maxValue
+ gainPerLevel × (L - 1)
+ milestoneHealthBonus
Where milestoneHealthBonus = floor(L / 5) × 5. maxValue is level-1 HP; gainPerLevel accrues from level 2 onward.
Example at level 20 with balanced values (maxValue=80, gainPerLevel=10):
- Base: 80 + (10 × 19) = 270
- Milestone: floor(20/5) × 5 = 20
- Total: 290 HP
Player Damage Formula
Player DPR = 16.4 + (2.5 × level) + milestoneDamageBonus
Where milestoneDamageBonus = floor(level / 5) × 2
NPC damage scales more simply: +2.0 per level with no milestone bonuses. So a high-level player out-scales an equal-level NPC slightly (2.5/level + milestones vs. a flat 2.0/level).
These are engine constants, not configurable. They determine how fast players deal damage at each level.
NPC HP Formula
NPC HP = (npcHealthPerLevel × level + npcMinHealth) × tierHPModifier × healthMultiplier × difficultyHealthMultiplier
When an NPC has no authored hpMax, this is derived live whenever it’s needed (not frozen at world load), so HP always reflects the game’s current difficulty. An authored hpMax on an NPC with an authored level is used exactly as written; on a level-less NPC it only guarantees a minimum. See the npcs reference for details.
| Tier | HP Modifier |
|---|---|
| trivial | 0.15 |
| weak | 0.5 |
| average | 1.0 |
| strong | 1.25 |
| elite | 1.5 |
| boss | 1.7 |
| mythic | 1.85 |
NPC Tier Damage Modifiers
Each tier also scales NPC damage output (engine constants, not configurable):
| Tier | Damage Modifier |
|---|---|
| trivial | 0.65 |
| weak | 0.8 |
| average | 1.0 |
| strong | 1.12 |
| elite | 1.25 |
| boss | 1.4 |
| mythic | 1.55 |
Milestone Bonuses
Players receive milestone bonuses every 5 character levels (engine constants):
| Milestone | HP Bonus | Damage Bonus |
|---|---|---|
| Every 5 levels | +5 HP | +2 damage |
Example at level 25: 5 milestones = +25 HP, +10 damage on top of per-level scaling.
Difficulty Multipliers
NPC stats scale by encounter difficulty (engine constants, not configurable):
| Difficulty | NPC Damage | NPC Health |
|---|---|---|
| very easy | 0.7× | 0.5× |
| easy | 0.85× | 0.75× |
| medium | 1.0× | 1.0× |
| hard | 1.15× | 1.25× |
| very hard | 1.3× | 1.5× |
Level-Differential Damage Reduction
When an attacker hits a target that is a higher level than themselves, outgoing damage is reduced. Each level of difference adds less than the last (5% for the first, diminishing by 10% per step), and the total plateaus at 27.5% once the gap reaches 10 levels.
| Levels target is above attacker | Damage reduction |
|---|---|
| 1 | 5.0% |
| 2 | 9.5% |
| 3 | 13.5% |
| 4 | 17.0% |
| 5 | 20.0% |
| 6 | 22.5% |
| 7 | 24.5% |
| 8 | 26.0% |
| 9 | 27.0% |
| 10+ | 27.5% (max) |
Hitting a target at the same or lower level applies no reduction.
Impact
Every attack carries an impact value from 50 to 200 (100 = normal) that the AI assigns per-attack based on how the action is described. It multiplies damage by impact / 100, and applies to both player and NPC attacks.
| Impact | Multiplier |
|---|---|
| 50 | 0.5× |
| 100 | 1.0× |
| 150 | 1.5× |
| 200 | 2.0× |
Evasion
A character that takes a defend / evade action on a turn reduces the incoming damage of attacks against them that turn. For players the reduction is 0.5 + 1.6 × strength of the resolved success tier, capped at 1.0 (see successLevelSettings); a reduction of 1.0 fully nullifies the hit (it lands but deals 0), and a failed roll gives no reduction. This is an active, per-turn choice driven by the defend roll, not a passive stat.
NPC Success Rolls
An NPC attack’s success level is fixed RNG each turn (NPCs have no skills or attributes to roll). NPC rolls use the engine’s own fixed bands and names, independent of the world’s successLevelSettings:
| Outcome | Chance |
|---|---|
| critical success | 10% |
| great success | 20% |
| success | 40% |
| basic success | 30% |
The only way an NPC attack drops below “basic success” is combat conflict: when a player’s defend or evade action succeeds against it, the attacking NPC’s outcome is degraded. A player success with strength 0.5 or more (Success or better on the stock ladder) turns the NPC’s attack into a failure; a weaker success limits it to mixed results. The conflict only touches the contested NPC intent, so an NPC’s other actions that turn resolve normally.
Encounter Health Budget
The engine targets 4 rounds to kill (TTK) when sizing encounters:
Encounter HP Budget = 4 × effectivePartySize × playerExpectedDPR
Where effectivePartySize = playerCount + (npcAllyCount × 0.7)
NPC allies count at 70% effectiveness. This determines total enemy HP the engine distributes across NPCs in a generated encounter.
Skill XP Requirements
XP to reach skill level N = startingXPToLevelUpSkill + (N - 1) * additionalXPRequiredPerSkillLevel
With balanced values (50/50):
- Level 1: 50 XP
- Level 10: 500 XP
- Level 30: 1,500 XP
Character Level XP Requirements
Both fields live in progressionSettings:
XP to reach character level N = startingCharacterLevelUpRequirement + (N - 2) * extraRequiredXPPerCharacterLevel
With balanced values (500/100):
- Level 2: 500 XP
- Level 5: 800 XP
- Level 10: 1,300 XP
Leveling stops at maxCharacterLevel.
Power Level Success Rates
| Power Level | Skill Range | vs Medium (30) | vs Hard (60) |
|---|---|---|---|
| I | 1-10 | Fails most | Fails almost all |
| II | 10-30 | Sometimes | Rarely |
| III | 30-40 | Usually | Sometimes |
| IV | 40-60 | Almost always | Usually |
Cross-References
| Field | References |
|---|---|
itemSettings.itemCategories | Used by tabs/items.json category field |
itemSettings.itemSlots[].category | Must match itemCategories values |
combatSettings.damageTypes | Used by NPC vulnerabilities/resistances/immunities and as the keys of combatSettings.damageTypePresentation |
worldVoices keys | Referenced by npcs[].worldVoiceId and premadeCharacters[].worldVoiceId |
successLevelSettings.tiers[].name | Named by action-success-level conditions in tabs/triggers.json |
successLevelSettings.firstSuccessfulTierId | A tiers[].id in the same section |
attributeSettings.attributeNames | Used in trait and skill attribute associations |
progressionSettings.levelUpTraitPool | Trait keys from tabs/traits.json (see the traits skill) |
resourceSettings keys | Used by ability and trait resource modifiers |