{"formatVersion":1,"storiesVersion":"1.83.0","actions":[{"type":"setFlag","group":"state","desc":"Set a boolean flag true.","params":"flag","wiring":"reducer"},{"type":"clearFlag","group":"state","desc":"Set a boolean flag false.","params":"flag","wiring":"reducer"},{"type":"incVar","group":"state","desc":"Add to a numeric variable (counters/clocks).","params":"var, by","wiring":"reducer"},{"type":"setVar","group":"state","desc":"Set a variable to a number or string.","params":"var, value","wiring":"reducer"},{"type":"tickClock","group":"state","desc":"Advance a declared clock by N.","params":"clock, by","wiring":"reducer"},{"type":"addClue","group":"state","desc":"Add a clue to the investigation board.","params":"clue","wiring":"reducer"},{"type":"setObjective","group":"state","desc":"Set a quest objective’s status.","params":"objective, to","wiring":"reducer"},{"type":"adjustRelationship","group":"state","desc":"Shift an NPC relationship score.","params":"npc, by","wiring":"reducer"},{"type":"grantAdvantageNext","group":"state","desc":"Advantage on the next check (or initiative).","params":"scope?","wiring":"reducer"},{"type":"grantDisadvantageNext","group":"state","desc":"Disadvantage on the next check (or initiative).","params":"scope?","wiring":"reducer"},{"type":"applyDamage","group":"combat","desc":"Deal damage (dice or amount) to a target.","params":"target, dice?|amount?, damageType?","wiring":"reducer"},{"type":"applyHeal","group":"combat","desc":"Heal a target (dice or amount).","params":"target, dice?|amount?","wiring":"reducer"},{"type":"applyCondition","group":"combat","desc":"Apply a 5e condition to a target.","params":"target, condition","wiring":"reducer"},{"type":"clearCondition","group":"combat","desc":"Remove a condition from a target.","params":"target, condition","wiring":"reducer"},{"type":"requestCheck","group":"combat","desc":"Deprecated — author an ability/skill check as a skillCheck NODE (with outcome tiers), not a then-list action.","params":"ability?|skill?, dc, adv?","wiring":"engine"},{"type":"resolveAbility","group":"combat","desc":"Deprecated — not wired; apply effects via applyDamage/applyHeal/applyCondition (or an item), not this verb.","params":"elementId, targets?","wiring":"engine"},{"type":"startCombat","group":"combat","desc":"Deprecated — begin an encounter via a combat NODE (with onVictory/onDefeat/onFlee), not a then-list action.","params":"encounter","wiring":"engine"},{"type":"grantItem","group":"rewards","desc":"Give an item to the hero’s bag.","params":"itemId, qty?, note?","wiring":"reducer"},{"type":"grantGold","group":"rewards","desc":"Give gold (folds into the purse + ledger).","params":"gp, note?","wiring":"reducer"},{"type":"grantCoins","group":"rewards","desc":"Give mixed coins (cp/sp/ep/gp/pp).","params":"coins, note?","wiring":"reducer"},{"type":"spendCoins","group":"rewards","desc":"Deduct coins (gate with an affords condition).","params":"amount, note?","wiring":"reducer"},{"type":"grantLevel","group":"rewards","desc":"Level the hero up (milestone).","params":"—","wiring":"reducer"},{"type":"awardXp","group":"rewards","desc":"Award XP toward the next level.","params":"xp","wiring":"reducer"},{"type":"craftItem","group":"rewards","desc":"Craft from a recipe — consume the ingredients, grant the output (re-validated against the bag).","params":"recipeId","wiring":"engine"},{"type":"grantInspiration","group":"rewards","desc":"Grant real Heroic Inspiration — spendable at the combat roll windows (✨).","params":"amount?","wiring":"reducer"},{"type":"rollTable","group":"random","desc":"Roll a seeded weighted table and apply the picked entry.","params":"table[], note?","wiring":"engine"},{"type":"callScene","group":"flow","desc":"Jump to a node and push a return address (sub-scene).","params":"node","wiring":"engine"},{"type":"returnScene","group":"flow","desc":"Pop back to the caller of a sub-scene.","params":"—","wiring":"engine"},{"type":"ifThen","group":"flow","desc":"Run `then` (else `else`) by an inline condition — conditional effects inside a then-list.","params":"if, then, else?","wiring":"engine"},{"type":"consumeItem","group":"sheet","desc":"Consume a single-use item the hero holds.","params":"itemId, qty?","wiring":"reducer"},{"type":"useItem","group":"sheet","desc":"Use an owned item — a PLAYER command from the bag/inventory (not an author then-list action).","params":"itemId","wiring":"command"},{"type":"spendResource","group":"sheet","desc":"Spend a resource/slot the hero actually has.","params":"key, amount?","wiring":"reducer"},{"type":"revealObject","group":"scene","desc":"Reveal a hidden scene object.","params":"objectId","wiring":"reducer"},{"type":"setObjectState","group":"scene","desc":"Set a scene object’s state key (drives layer swaps).","params":"objectId, key, value","wiring":"reducer"},{"type":"moveActor","group":"scene","desc":"Move an actor to a zone.","params":"actorId, zoneId","wiring":"reducer"},{"type":"setActorVisibility","group":"scene","desc":"Set an actor visible/hidden/concealed.","params":"actorId, visibility","wiring":"reducer"},{"type":"goto","group":"flow","desc":"Jump to another node.","params":"node","wiring":"engine"},{"type":"emitEvent","group":"io","desc":"Emit a domain event (analytics / AI / voice hook seam).","params":"name, props?","wiring":"runner"},{"type":"showScene","group":"io","desc":"Show a scene on the shared display.","params":"sceneRef","wiring":"runner"},{"type":"playAudio","group":"io","desc":"Play a soundboard clip.","params":"trackId","wiring":"runner"},{"type":"showToast","group":"io","desc":"Float a short message to the player (\"You found 10 silver\").","params":"text, ms?","wiring":"runner"}],"conditions":[{"key":"all","desc":"All sub-conditions are true (AND).","params":"all: Condition[]"},{"key":"any","desc":"Any sub-condition is true (OR).","params":"any: Condition[]"},{"key":"not","desc":"The sub-condition is false (NOT).","params":"not: Condition"},{"key":"flag","desc":"A flag equals a boolean.","params":"flag, is"},{"key":"hasFlag","desc":"A flag is truthy (shorthand).","params":"hasFlag"},{"key":"var","desc":"A variable compares (==,!=,>,>=,<,<=) to a value.","params":"var, op, value"},{"key":"clock","desc":"A clock is within gte/lte bounds.","params":"clock, gte?, lte?"},{"key":"hasClue","desc":"The hero has learned a clue.","params":"hasClue"},{"key":"objective","desc":"An objective has a given status.","params":"objective, is"},{"key":"relationship","desc":"An NPC relationship is within gte/lte bounds.","params":"relationship, gte?, lte?"},{"key":"hasItem","desc":"The hero holds an item (optional qty).","params":"hasItem, qty?"},{"key":"affords","desc":"The purse can afford a coin cost.","params":"affords: {cp?,sp?,ep?,gp?,pp?}"},{"key":"visited","desc":"A node has been entered at least once.","params":"visited: NodeId"},{"key":"visitCount","desc":"A node’s visit count is within gte/lte bounds.","params":"visitCount, gte?, lte?"},{"key":"inZone","desc":"The hero is in a given scene zone.","params":"inZone: zoneId"},{"key":"objectState","desc":"A scene object’s state key matches (default: revealed).","params":"objectState: {id, key?, is}"},{"key":"stat","desc":"Compare a character stat (level / xp / hp / maxHp).","params":"stat, op, value"}],"triggers":[{"key":"onEnterNode","fires":true,"desc":"When a node is entered."},{"key":"onExitNode","fires":false,"desc":"When a node is left (reserved)."},{"key":"onChoice","fires":false,"desc":"When a choice is taken (reserved)."},{"key":"onCheckTier","fires":false,"desc":"When a check resolves to a tier (reserved)."},{"key":"onCombatEnd","fires":false,"desc":"When combat ends (reserved)."},{"key":"onFlagSet","fires":false,"desc":"When a flag is set (reserved)."},{"key":"onVarChange","fires":false,"desc":"When a variable changes (reserved)."},{"key":"onZoneEnter","fires":true,"desc":"When the hero moves into a scene zone (gate with inZone)."},{"key":"onAttacked","fires":false,"desc":"In-combat reaction window — reserved/deferred (task #52)."}],"nodeKinds":[{"kind":"scene","desc":"Narrative beat: prose + optional interactables / passive onEnterCheck → next."},{"kind":"choice","desc":"A branch: a list of choices (each with optional requires / then / next)."},{"kind":"dialogue","desc":"A conversation: conditional lines + response choices in one node."},{"kind":"skillCheck","desc":"An ability/skill check with 5 outcome tiers + a failure model."},{"kind":"challenge","desc":"A skill challenge: reach N successes before M failures."},{"kind":"combat","desc":"An encounter → onVictory / onDefeat / onFlee."},{"kind":"loot","desc":"Grant rewards (then actions) → next."},{"kind":"transition","desc":"A conditional jump to another node."},{"kind":"gate","desc":"First matching branch wins; else a fallback node."},{"kind":"consequence","desc":"Apply effects (then actions) → next."},{"kind":"rest","desc":"A short/long rest (spend Hit Dice / refresh resources) → next."},{"kind":"hub","desc":"A revisitable hub with conditional exits."},{"kind":"ending","desc":"A terminal node (endingId + outcome + epilogue variants)."}],"note":"The closed authoring vocabulary, derived from the single-source catalog. Default-deny: any verb not in `actions` is rejected by the validator and cannot execute. This is the grounding surface for AI authoring (so a model cannot invent a verb)."}