{"$schema":"https://json-schema.org/draft/2020-12/schema","title":"Content","type":"object","properties":{"formatVersion":{"type":"integer","format":"uint32","minimum":0},"features":{"$ref":"#/$defs/Features"},"bundles":{"description":"The bundles the game was given (L-199; docs/architecture_spec.md, \"Bundles\"): the editor\ngroups their modules under their names and offers a newer version's modules. The modules\nthemselves are on by their own switches; the engine never reads this. Not written while\nempty (none recorded: none given).","type":"array","items":{"$ref":"#/$defs/BundleGiven"}},"moduleVersions":{"description":"The modules the game uses with their versions when it was published (L-197;\ndocs/architecture_spec.md, \"Versions and dependencies\"): an engine refuses a newer major\nversion of a module than it carries (`engine.module_newer`). Not written while empty.","type":"object","additionalProperties":{"type":"string"}},"packages":{"description":"The workspace's packages the game uses (L-197 i2): publishing copies their files into the\nrelease. The engine never reads this (it is handed the package files). Not written while\nempty.","type":"array","items":{"$ref":"#/$defs/PackageGiven"}},"modules":{"description":"Each workspace package's own content by its ID (L-197 i9), as its `module.json`'s schema\ndescribes it; its `content` host call answers its part. Not written while empty.","type":"object","additionalProperties":true},"settings":{"$ref":"#/$defs/Settings"},"values":{"type":"array","items":{"$ref":"#/$defs/ValueDef"},"default":[]},"formulas":{"description":"Calculations written once and used by name (`trust_bonus(3)`); not written while empty,\nso older content keeps its canonical JSON.","type":"array","items":{"$ref":"#/$defs/SharedFormula"}},"maps":{"description":"World maps (Maps); not written while empty.","type":"array","items":{"$ref":"#/$defs/GameMap"}},"time":{"description":"The game's clock (Time, P6-09).","anyOf":[{"$ref":"#/$defs/GameTime"},{"type":"null"}]},"weather":{"description":"The game's weather (Weather, P6-10).","anyOf":[{"$ref":"#/$defs/GameWeather"},{"type":"null"}]},"chapters":{"type":"array","items":{"$ref":"#/$defs/Chapter"},"default":[]},"rules":{"type":"array","items":{"$ref":"#/$defs/EveryPassageRule"},"default":[]},"storyRules":{"description":"Story rules that move the story (L-19): when a condition becomes true, to a passage or an\nending.","type":"array","items":{"$ref":"#/$defs/StoryRule"}},"passages":{"type":"array","items":{"$ref":"#/$defs/Passage"},"default":[]},"decks":{"description":"Decks of cards the game draws by the player's state (storylets, L-29); not written while\nempty.","type":"array","items":{"$ref":"#/$defs/Deck"}},"endings":{"type":"array","items":{"$ref":"#/$defs/Ending"},"default":[]},"characters":{"type":"array","items":{"$ref":"#/$defs/Character"},"default":[]},"roles":{"description":"Roles a line may be spoken by (L-93): filled by a present character when shown.","type":"array","items":{"$ref":"#/$defs/Role"}},"classes":{"type":"array","items":{"$ref":"#/$defs/Class"},"default":[]},"equipmentSlots":{"type":"array","items":{"$ref":"#/$defs/EquipmentSlot"},"default":[]},"things":{"type":"array","items":{"$ref":"#/$defs/Thing"},"default":[]},"combinations":{"type":"array","items":{"$ref":"#/$defs/Combination"},"default":[]},"storages":{"description":"Things feature: places to keep things besides the inventory.","type":"array","items":{"$ref":"#/$defs/Storage"},"default":[]},"shops":{"description":"Things feature: lists of things to buy and sell; not written while empty.","type":"array","items":{"$ref":"#/$defs/Shop"}},"collections":{"type":"array","items":{"$ref":"#/$defs/Collection"},"default":[]},"lootTables":{"type":"array","items":{"$ref":"#/$defs/LootTable"},"default":[]},"enemies":{"type":"array","items":{"$ref":"#/$defs/Enemy"},"default":[]},"encounters":{"type":"array","items":{"$ref":"#/$defs/Encounter"},"default":[]},"encounterAreas":{"description":"Encounters on the way (Battles; L-63); not written while empty.","type":"array","items":{"$ref":"#/$defs/EncounterArea"}},"camp":{"description":"The camp (Camp feature; P6-08); not written while none.","anyOf":[{"$ref":"#/$defs/Camp"},{"type":"null"}]},"skills":{"type":"array","items":{"$ref":"#/$defs/Skill"},"default":[]},"statusEffects":{"type":"array","items":{"$ref":"#/$defs/StatusEffect"},"default":[]},"battleRules":{"description":"Settings of the Battles feature. Not read in a build without battles (P6-33): the code it\nkeeps reads [`Content::battle_rows`] instead, and `battleRules` is kept as it was read.","$ref":"#/$defs/BattleRules","default":{"defeatBarId":null,"speedValueId":null,"turnOrder":"round_by_speed","basicAttackSkillId":null,"damageTypes":[],"healingFormula":"user.attack * skill.power / 100","hitChance":"clamp(0.9 + (user.speed - target.speed) * 0.01, 0.5, 1)","critChance":"0.05","critMultiplier":1.5,"fleeChance":"0.5","variancePercent":10,"defendMultiplier":0.5,"xpDistribution":"each_alive_full","afterBattle":{"restore":"none","reviveDefeated":false}}},"progression":{"description":"Settings of the Levels feature. Not read in a build without levels (P6-33): the code it\nkeeps reads [`Content::max_level`] and [`Content::stat_points`] instead, and `progression`\nis kept as it was read.","$ref":"#/$defs/Progression","default":{"maxLevel":20,"xpCurve":{"mode":"formula","xpToNext":"round(20 * pow(level, 1.5))"},"defaultEnemyXp":"enemy.level * 10","onLevelUp":{"restoreBars":true,"skillPoints":0,"statPoints":0},"learnsets":false,"skillPoints":false,"statPoints":false,"raisable":[]}},"texts":{"description":"Player text overrides by key (`menu.inventory` → \"Satchel\").","type":"object","additionalProperties":{"type":"string"},"default":{}},"translations":{"description":"Translations in a project (L-21; docs/game_systems_spec.md, \"Translations\"): other\nlanguages by BCP 47 code, their texts by text address; not written while empty.","type":"object","additionalProperties":{"$ref":"#/$defs/Translation"}},"book":{"$ref":"#/$defs/BookSettings","default":{"enabled":false,"title":"","author":"","pageSize":"a5","illustrations":"grayscale","numbering":{"mode":"shuffled","seed":1},"combat":{"mode":"rounds","rounds":{"attackDice":2,"attackValueId":"","hitTarget":"7 + floor(defender.defense / 2)","damage":"max(1, attacker.attack - floor(defender.defense / 2))","enemyTargets":"lowest_bar","skills":false,"things":false},"check":{"dice":2,"valueId":"","target":"7"}}}},"editor":{"description":"Creator-UI-only; removed from manifests.","anyOf":[{"$ref":"#/$defs/EditorMeta"},{"type":"null"}]}},"required":["formatVersion","features","settings"],"$defs":{"Features":{"type":"object","properties":{"scenes":{"type":"boolean"},"characters":{"type":"boolean"},"things":{"type":"boolean"},"equipment":{"type":"boolean"},"documents":{"type":"boolean"},"collections":{"type":"boolean"},"checks":{"type":"boolean"},"battles":{"type":"boolean"},"skills":{"type":"boolean"},"levels":{"$ref":"#/$defs/LevelMode"},"talkSounds":{"description":"Not written while off, so content from before it keeps its canonical JSON.","type":"boolean"},"maps":{"type":"boolean"},"camp":{"description":"A place to rest, opened from the menu (P6-08).","type":"boolean"},"time":{"description":"The game's clock (P6-09).","type":"boolean"},"weather":{"description":"Weather that changes by itself (P6-10).","type":"boolean"},"dungeons":{"description":"Dungeons on passages (L-155).","type":"boolean"}},"required":["scenes","characters","things","equipment","documents","collections","checks","battles","skills","levels"]},"LevelMode":{"type":"string","enum":["off","xp","story"]},"BundleGiven":{"description":"A bundle a game was given, at the version it was given (L-199).","type":"object","properties":{"bundleId":{"description":"The registry's bundle (`rpg`).","type":"string"},"version":{"description":"Its version when given (or when its newer modules were last taken).","type":"string"}},"required":["bundleId","version"]},"PackageGiven":{"description":"A workspace's package a game uses, at the version it uses (L-197 i2; docs/architecture_spec.md,\n\"Installing packages\").","type":"object","properties":{"id":{"description":"The package's ID (`<publisher>.<name>`).","type":"string"},"version":{"description":"Its version (semver), as the workspace stores it.","type":"string"}},"required":["id","version"]},"Settings":{"type":"object","properties":{"language":{"type":"string"},"madeFor":{"description":"The screens the game is made for (P8-26; none: desktop and phone): the playtest's sizes,\nthe screen check and the player's note follow it.","anyOf":[{"$ref":"#/$defs/MadeFor"},{"type":"null"}]},"resolution":{"$ref":"#/$defs/Resolution"},"look":{"description":"The look of the game (format 2; `settings.font` of format 1 is `look.font`); the default\nlook is not written, so content without one keeps its canonical JSON (and replay hashes).","$ref":"#/$defs/Look"},"start":{"$ref":"#/$defs/StartPassage"},"startingParty":{"type":"array","items":{"type":"string"},"default":[]},"maxActivePartySize":{"type":"integer","format":"uint32","minimum":0},"startingThings":{"type":"array","items":{"$ref":"#/$defs/ThingQty"},"default":[]},"inventory":{"$ref":"#/$defs/InventorySettings"},"currencyValueId":{"type":["string","null"]},"player":{"$ref":"#/$defs/PlayerSettings"},"talk":{"description":"Talk sounds: the narrator's voice for lines without a speaker.","anyOf":[{"$ref":"#/$defs/TalkSettings"},{"type":"null"}]},"card":{"description":"The card picture (16 : 9, with its alt text) a game shows wherever it is listed: the start\npage's cards and stage; none: the title screen's cover, else a picture made from the look.","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"credits":{"description":"The credits an ending may roll: roles and names, in order.","type":"array","items":{"$ref":"#/$defs/Credit"}},"extras":{"description":"L-31: the extras the title screen offers (none: no extras).","$ref":"#/$defs/Extras"}},"required":["language","resolution","start","maxActivePartySize","inventory","player"]},"MadeFor":{"description":"The screens a game is made for (P8-26; docs/playtest_spec.md, \"Made for\").","oneOf":[{"description":"Desktop and phone.","type":"string","const":"all"},{"description":"Desktop and laptop screens: the playtest and the screen check leave phones out.","type":"string","const":"desktop"},{"description":"Phones: the playtest and the screen check leave the large screens out.","type":"string","const":"phone"}]},"Resolution":{"type":"object","properties":{"width":{"type":"integer","format":"uint32","minimum":0},"height":{"type":"integer","format":"uint32","minimum":0}},"required":["width","height"]},"Look":{"type":"object","properties":{"theme":{"$ref":"#/$defs/Theme","default":"paper"},"variants":{"description":"Look variants (L-48, `look_variants.rs`): named partial looks for chapters, labelled\npassages or a `screen` step.","type":"array","items":{"$ref":"#/$defs/LookVariant"}},"rules":{"description":"Style rules on named parts (L-50, `style_rules.rs`), for what the settings do not reach.","type":"array","items":{"$ref":"#/$defs/StyleRule"}},"cursors":{"description":"A cursor for each situation (P6-16, `cursors.rs`; `normal` stands for `cursor` when both\nare set). Only the player's shell reads it, from the stored content.","anyOf":[{"$ref":"#/$defs/CursorSet"},{"type":"null"}]},"colors":{"description":"Colours over the theme's (`#rrggbb`).","anyOf":[{"$ref":"#/$defs/LookColors"},{"type":"null"}]},"font":{"description":"The story text's font (none: the theme's).","anyOf":[{"$ref":"#/$defs/Font"},{"type":"null"}]},"headingFont":{"description":"Titles and ending names (none: the theme's).","anyOf":[{"$ref":"#/$defs/Font"},{"type":"null"}]},"choices":{"description":"How choices look (none: the theme's).","anyOf":[{"$ref":"#/$defs/ChoiceStyle"},{"type":"null"}]},"background":{"description":"Behind the text column (not in scene passages).","anyOf":[{"$ref":"#/$defs/LookBackground"},{"type":"null"}]},"keepPicture":{"description":"Each picture shown in the story stays behind it as the background once the next line\ncomes (P6-06; none: off).","type":["boolean","null"]},"picturesOnPage":{"description":"Pictures shown in the story stay on the page in the column, never the stage on a wide\nwindow (P8-25; book-like looks; none: the stage).","type":["boolean","null"]},"titleScreen":{"description":"With it, the game opens on a title screen.","anyOf":[{"$ref":"#/$defs/TitleScreen"},{"type":"null"}]},"textReveal":{"description":"Lines appear gradually, word by word or letter by letter (none: at once).","anyOf":[{"$ref":"#/$defs/TextReveal"},{"type":"null"}]},"dialogue":{"description":"How spoken lines look (none: the name before the line).","anyOf":[{"$ref":"#/$defs/DialogueLook"},{"type":"null"}]},"story":{"description":"What stays on screen (none: the whole story).","anyOf":[{"$ref":"#/$defs/StoryView"},{"type":"null"}]},"inventory":{"description":"How the menu shows the things carried and worn (L-177; none: as lists).","anyOf":[{"$ref":"#/$defs/InventoryLook"},{"type":"null"}]},"transition":{"description":"The change between passages with `story` `passage` or `line` (none: none).","anyOf":[{"$ref":"#/$defs/PassageChange"},{"type":"null"}]},"motion":{"description":"Movement: how things appear, change and stand (none: the style's personality).","anyOf":[{"$ref":"#/$defs/MotionLook"},{"type":"null"}]},"layout":{"description":"Where the story, the picture and the options stand (none: the style's).","anyOf":[{"$ref":"#/$defs/Layout"},{"type":"null"}]},"mask":{"description":"The areas of the fixed screen (`layout` `fixed`, P6-05; none: picture above, boxes below).","anyOf":[{"$ref":"#/$defs/FixedMask"},{"type":"null"}]},"topBar":{"description":"Where the top bar sits (none: the style's).","anyOf":[{"$ref":"#/$defs/TopBarPlace"},{"type":"null"}]},"screens":{"description":"Title, ending, menu, loading, battle and map of their own (none: the style's).","anyOf":[{"$ref":"#/$defs/ScreensLook"},{"type":"null"}]},"palette":{"description":"Colours of boxes, faded text, lines and option buttons (none: derived from the three).","anyOf":[{"$ref":"#/$defs/Palette"},{"type":"null"}]},"nameFont":{"description":"Speaker names (none: the story font).","anyOf":[{"$ref":"#/$defs/Font"},{"type":"null"}]},"uiFont":{"description":"Buttons, menus and the status line (none: the story font).","anyOf":[{"$ref":"#/$defs/Font"},{"type":"null"}]},"text":{"description":"Size, line spacing, column and alignment of the story text (none: the style's).","anyOf":[{"$ref":"#/$defs/TextLook"},{"type":"null"}]},"shape":{"description":"Corners, borders and shadows of boxes and buttons alike.","anyOf":[{"$ref":"#/$defs/Shape"},{"type":"null"}]},"frame":{"description":"A frame for every box: an uploaded picture (9-slice) or one that comes with Talebench.","anyOf":[{"$ref":"#/$defs/BoxFrame"},{"type":"null"}]},"pictureFrame":{"description":"Around the story's pictures (none: the style's).","anyOf":[{"$ref":"#/$defs/FrameName"},{"type":"null"}]},"panelPicture":{"description":"A texture inside boxes, behind their text and under the frame.","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"choiceStyle":{"description":"How option buttons are aligned and how wide they are.","anyOf":[{"$ref":"#/$defs/ChoiceLayout"},{"type":"null"}]},"continueMarker":{"description":"Where a line waits for the player (none: a blinking arrow).","anyOf":[{"$ref":"#/$defs/ContinueMarker"},{"type":"null"}]},"sounds":{"description":"Interface sounds, on the player's sound-effects volume.","anyOf":[{"$ref":"#/$defs/LookSounds"},{"type":"null"}]},"options":{"description":"The options the player picks from, of their own (none: the style's).","anyOf":[{"$ref":"#/$defs/OptionsLook"},{"type":"null"}]},"buttons":{"description":"_Continue_, the top bar, menus and dialogs (none: the style's).","anyOf":[{"$ref":"#/$defs/ButtonsLook"},{"type":"null"}]},"initial":{"description":"A large first letter (none: the style's).","anyOf":[{"$ref":"#/$defs/InitialLook"},{"type":"null"}]},"icons":{"description":"An icon set that comes with Talebench and uploaded pictures per place.","anyOf":[{"$ref":"#/$defs/IconsLook"},{"type":"null"}]},"divider":{"description":"What stands between passages and scenes.","anyOf":[{"$ref":"#/$defs/Divider"},{"type":"null"}]},"chapterHeading":{"description":"How a chapter's title looks, in the player and in the book.","anyOf":[{"$ref":"#/$defs/ChapterHeading"},{"type":"null"}]},"density":{"description":"Scales all spacing (targets stay 44 px).","anyOf":[{"$ref":"#/$defs/Density"},{"type":"null"}]},"skin":{"description":"Frames or pictures for the top bar, tabs, chips, notices, bars and sliders.","anyOf":[{"$ref":"#/$defs/SkinLook"},{"type":"null"}]},"cursor":{"description":"The cursor on pointer devices.","anyOf":[{"$ref":"#/$defs/CursorLook"},{"type":"null"}]},"focusStyle":{"description":"How the focused control is marked.","anyOf":[{"$ref":"#/$defs/FocusStyle"},{"type":"null"}]},"speakerColor":{"description":"Where a character's colour shows.","anyOf":[{"$ref":"#/$defs/SpeakerColor"},{"type":"null"}]},"pixelArt":{"description":"Pictures, sprites, figures, portraits and the map scaled without smoothing (L-71; none:\noff).","type":["boolean","null"]},"dice":{"description":"How dice battles draw their dice (L-99; none: pips).","anyOf":[{"$ref":"#/$defs/DiceFaces"},{"type":"null"}]},"diceShowOpponent":{"description":"Dice battles show the opponent's throw in the tray (L-99; none: shown; false: the log\nonly).","type":["boolean","null"]},"diceReveal":{"description":"Dice battles: the dice of a throw land one after another or all at once (playtest\n2026-10-25; none: one after another).","anyOf":[{"$ref":"#/$defs/DiceReveal"},{"type":"null"}]},"diceStyle":{"description":"How the dice of dice battles look (L-99; none: plain, in the look's own colours).","anyOf":[{"$ref":"#/$defs/DiceStyle"},{"type":"null"}]},"diceTable":{"description":"The table a one-against-one dice battle stands on (P8-43; none: plain, the look's own\ncolours): its lanes, action lane, circles and commands drawn as one set.","anyOf":[{"$ref":"#/$defs/DiceTable"},{"type":"null"}]},"diceEffects":{"description":"Dice that feel real (L-107): the throw's motion and effects (none: full in dice battles;\nlight: the roll and the combination's glow only; off: the short roll of before).","anyOf":[{"$ref":"#/$defs/DiceEffects"},{"type":"null"}]},"diceSounds":{"description":"Dice battles' sounds made by the player (L-107; none: on).","type":["boolean","null"]},"screenShake":{"description":"A critical shakes the screen briefly (L-107; none: on).","type":["boolean","null"]},"haptics":{"description":"Phones vibrate as dice land (L-107; none: on).","type":["boolean","null"]},"dicePreview":{"description":"The dice tray says what a choice would do before it is confirmed, and when one die is\nmissing for a rarer combination (L-108; none: on).","type":["boolean","null"]}}},"Theme":{"oneOf":[{"type":"string","enum":["paper","night","parchment","clean","typewriter","storybook","fantasy","starlight"]},{"description":"The classic consoles: deep blue fading boxes, a pixel font (L-71).","type":"string","const":"retro"}]},"LookVariant":{"description":"A named partial look: what it sets replaces the game's look while it applies, the rest stays.","type":"object","properties":{"id":{"description":"`lkv_…`.","type":"string"},"name":{"description":"The creator's name for it (\"Flashback\"); players never see it.","type":"string"},"chapterIds":{"description":"Applies in the passages of these chapters.","type":"array","items":{"type":"string"}},"labelIds":{"description":"Applies in passages with one of these labels (before a chapter's variant).","type":"array","items":{"type":"string"}},"colors":{"description":"Colours over the game's, each on its own.","anyOf":[{"$ref":"#/$defs/LookColors"},{"type":"null"}]},"palette":{"description":"Box, faded text, line and option colours over the game's, each on its own.","anyOf":[{"$ref":"#/$defs/Palette"},{"type":"null"}]},"font":{"anyOf":[{"$ref":"#/$defs/Font"},{"type":"null"}]},"headingFont":{"anyOf":[{"$ref":"#/$defs/Font"},{"type":"null"}]},"background":{"description":"The picture behind the text column.","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"frame":{"description":"Around boxes.","anyOf":[{"$ref":"#/$defs/BoxFrame"},{"type":"null"}]},"pictureFrame":{"description":"Around the story's pictures.","anyOf":[{"$ref":"#/$defs/FrameName"},{"type":"null"}]},"panelPicture":{"description":"The texture inside boxes.","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"filter":{"description":"Over the scene, the stage and the story's pictures while no `screen` step set a filter\n(`none`: no filter).","anyOf":[{"$ref":"#/$defs/ScreenFilter"},{"type":"null"}]},"layout":{"description":"A layout of its own while it applies (P6-05: a chapter in the fixed screen).","anyOf":[{"$ref":"#/$defs/Layout"},{"type":"null"}]},"mask":{"description":"The fixed screen's mask with `layout` `fixed` (none: the game's).","anyOf":[{"$ref":"#/$defs/FixedMask"},{"type":"null"}]},"cursors":{"description":"Cursors of its own while it applies (P6-16: a dungeon with a torch), each situation over\nthe game's; only the player's shell reads them.","anyOf":[{"$ref":"#/$defs/CursorSet"},{"type":"null"}]}},"required":["id","name"]},"LookColors":{"type":"object","properties":{"background":{"type":["string","null"]},"text":{"type":["string","null"]},"accent":{"type":["string","null"]}}},"Palette":{"description":"Colours over the derived ones (`#rrggbb`).","type":"object","properties":{"panel":{"description":"Boxes: the dialogue box, cards, menus, the reader.","type":["string","null"]},"panelText":{"type":["string","null"]},"muted":{"type":["string","null"]},"border":{"type":["string","null"]},"choice":{"description":"Option buttons.","type":["string","null"]},"choiceText":{"type":["string","null"]},"panelTo":{"description":"Boxes fade from `panel` to this colour (L-71; none: one colour).","type":["string","null"]},"panelDirection":{"description":"Which way boxes fade (none: downwards).","anyOf":[{"$ref":"#/$defs/PanelDirection"},{"type":"null"}]}}},"PanelDirection":{"description":"Which way a box's colour fades to `panelTo` (L-71).","type":"string","enum":["down","right"]},"Font":{"description":"An uploaded font (WOFF2) or one of the font styles that come with Talebench (the reader's\nsystem fonts of that kind).","oneOf":[{"type":"object","properties":{"assetId":{"type":"string"},"type":{"type":"string","const":"asset"}},"required":["type","assetId"]},{"type":"object","properties":{"name":{"$ref":"#/$defs/BuiltinFont"},"type":{"type":"string","const":"builtin"}},"required":["type","name"]}]},"BuiltinFont":{"oneOf":[{"type":"string","enum":["classic","sans","rounded","mono","garamond","cormorant","cinzel","fell","inter","nunito","courier_prime","pixel","handwritten","ornate","fairytale","display"]},{"description":"The reader's system fonts of a kind.","type":"string","const":"serif"},{"description":"Fonts that come with Talebench (packages/fonts).","type":"string","const":"literata"},{"description":"Initial fonts (decorative capitals for large first letters).","type":"string","const":"blackletter"}]},"ImageRef":{"type":"object","properties":{"assetId":{"type":"string"},"alt":{"type":["string","null"]}},"required":["assetId"]},"BoxFrame":{"description":"A box frame: one that comes with Talebench, or an uploaded picture (stored as before).","anyOf":[{"type":"object","properties":{"builtin":{"$ref":"#/$defs/FrameName"}},"required":["builtin"]},{"$ref":"#/$defs/Frame"}]},"FrameName":{"description":"Frames that come with Talebench (docs/game_systems_spec.md, \"Frames that come with\nTalebench\"): drawn by the player in the look's colours.","type":"string","enum":["none","line","double","gilded","wood","parchment","tech","pixel","storybook"]},"Frame":{"description":"A 9-slice frame: the picture's outer `slice` pixels on each side stay as they are, the middle\nstretches or repeats.","type":"object","properties":{"image":{"$ref":"#/$defs/ImageRef"},"slice":{"description":"Pixels of the picture's border, on each side.","type":"integer","format":"uint32","minimum":0},"fill":{"anyOf":[{"$ref":"#/$defs/FrameFill"},{"type":"null"}]}},"required":["image","slice"]},"FrameFill":{"type":"string","enum":["stretch","repeat"]},"ScreenFilter":{"description":"A filter over the scene picture and the stage, kept until changed like the tint.","type":"string","enum":["none","sepia","greyscale","blur","vignette"]},"Layout":{"description":"Where the story, the picture and the options stand (L-45); below 480 px always the column.","oneOf":[{"type":"string","enum":["column","picture_left","picture_right","sidebar","spread","cinema","one_screen"]},{"description":"Areas of fixed place and size that never move with what they hold (P6-05): the picture,\nthe narration, the dialogue and the choices, from the look's `mask`.","type":"string","const":"fixed"}]},"FixedMask":{"description":"The fixed screen's mask (P6-05, docs/game_systems_spec.md, \"A fixed screen\"): a ready mask,\nwhether narration and dialogue share a box, and the areas the creator moved.","type":"object","properties":{"kind":{"$ref":"#/$defs/MaskKind","default":"picture_above"},"boxes":{"anyOf":[{"$ref":"#/$defs/MaskBoxes"},{"type":"null"}]},"areas":{"description":"On wide windows only: on a phone every mask has its fixed stacked form.","anyOf":[{"$ref":"#/$defs/MaskAreas"},{"type":"null"}]},"picture":{"description":"The picture area's size (none: medium, the mask's own share; L-83), on every screen.","anyOf":[{"$ref":"#/$defs/PictureSize"},{"type":"null"}]}}},"MaskKind":{"description":"A ready mask of the fixed screen (P6-05); its areas are in `packages/format/src/mask.ts`.","oneOf":[{"description":"The picture above, the boxes below.","type":"string","const":"picture_above"},{"description":"The picture over the whole window, the boxes over it.","type":"string","const":"picture_full"},{"description":"The picture on the left, the text on the right.","type":"string","const":"picture_left"},{"description":"The picture on the right, the text on the left.","type":"string","const":"picture_right"},{"description":"A gamebook's page: a picture at the head, the text, the options at the foot.","type":"string","const":"gamebook"}]},"MaskBoxes":{"description":"Narration and dialogue in two boxes, or in one.","type":"string","enum":["two","one"]},"MaskAreas":{"description":"Areas the creator moved or sized (each none: the ready mask's).","type":"object","properties":{"picture":{"anyOf":[{"$ref":"#/$defs/MaskArea"},{"type":"null"}]},"narration":{"anyOf":[{"$ref":"#/$defs/MaskArea"},{"type":"null"}]},"dialogue":{"anyOf":[{"$ref":"#/$defs/MaskArea"},{"type":"null"}]},"choices":{"anyOf":[{"$ref":"#/$defs/MaskArea"},{"type":"null"}]}}},"MaskArea":{"description":"One area of the fixed screen: its place and size as shares (0–1) of the window below the bar.","type":"object","properties":{"x":{"type":"number","format":"double","minimum":0,"maximum":1},"y":{"type":"number","format":"double","minimum":0,"maximum":1},"w":{"type":"number","format":"double","minimum":0,"maximum":1},"h":{"type":"number","format":"double","minimum":0,"maximum":1}},"required":["x","y","w","h"]},"PictureSize":{"description":"The fixed screen's picture area against the mask's own share (L-83): the boxes take what a\nsmaller picture frees; the background is not affected.","type":"string","enum":["small","medium","large"]},"CursorSet":{"description":"A cursor for each situation: every one but `normal` falls back as noted.","type":"object","properties":{"normal":{"description":"Over the page.","$ref":"#/$defs/CursorLook"},"choose":{"description":"Over an option, a button, a link (none: `normal`).","anyOf":[{"$ref":"#/$defs/CursorLook"},{"type":"null"}]},"disabled":{"description":"Over an option that cannot be taken (none: `normal`).","anyOf":[{"$ref":"#/$defs/CursorLook"},{"type":"null"}]},"wait":{"description":"While the game loads or a line is revealed that cannot be skipped (none: `normal`).","anyOf":[{"$ref":"#/$defs/CursorLook"},{"type":"null"}]},"hotspot":{"description":"Over a hotspot, by what it does (each none: `choose`).","anyOf":[{"$ref":"#/$defs/HotspotCursors"},{"type":"null"}]},"battle":{"description":"Choosing a target in a battle (each none: `choose`).","anyOf":[{"$ref":"#/$defs/BattleCursors"},{"type":"null"}]},"map":{"description":"Over a place to travel to and while planning a route (each none: `choose`).","anyOf":[{"$ref":"#/$defs/MapCursors"},{"type":"null"}]},"carry":{"description":"While a thing is held to use on something: the thing's icon, or a cursor (none: the\nsituation's own cursor).","anyOf":[{"$ref":"#/$defs/CarryCursor"},{"type":"null"}]},"size":{"description":"The size the pictures are shown at, 24 to 64 CSS pixels (none: 32); a picture twice the\nsize is sharp on dense screens.","type":["integer","null"],"format":"uint32","minimum":0}},"required":["normal"]},"CursorLook":{"description":"A cursor on pointer devices: one that comes with Talebench or an uploaded picture with its tip\n(none: the top left).","anyOf":[{"type":"object","properties":{"builtin":{"$ref":"#/$defs/CursorName"}},"required":["builtin"]},{"type":"object","properties":{"image":{"$ref":"#/$defs/ImageRef"},"tip":{"description":"Where it points, in the picture's pixels (P6-16; none: the top left).","anyOf":[{"$ref":"#/$defs/CursorTip"},{"type":"null"}]}},"required":["image"]}]},"CursorName":{"description":"The cursors that come with Talebench (`none`: the browser's own).","type":"string","enum":["none","quill","gauntlet","wand","pixel","crosshair"]},"CursorTip":{"description":"A cursor picture's point, in the picture's pixels from its top left (P6-16).","type":"object","properties":{"x":{"type":"integer","format":"uint32","minimum":0},"y":{"type":"integer","format":"uint32","minimum":0}},"required":["x","y"]},"HotspotCursors":{"description":"Over a hotspot, by what it does.","type":"object","properties":{"look":{"anyOf":[{"$ref":"#/$defs/CursorLook"},{"type":"null"}]},"talk":{"anyOf":[{"$ref":"#/$defs/CursorLook"},{"type":"null"}]},"take":{"anyOf":[{"$ref":"#/$defs/CursorLook"},{"type":"null"}]},"use":{"anyOf":[{"$ref":"#/$defs/CursorLook"},{"type":"null"}]},"go":{"anyOf":[{"$ref":"#/$defs/CursorLook"},{"type":"null"}]}}},"BattleCursors":{"description":"Choosing a target: a foe, someone of the party, where no target is.","type":"object","properties":{"foe":{"anyOf":[{"$ref":"#/$defs/CursorLook"},{"type":"null"}]},"ally":{"anyOf":[{"$ref":"#/$defs/CursorLook"},{"type":"null"}]},"nothing":{"anyOf":[{"$ref":"#/$defs/CursorLook"},{"type":"null"}]}}},"MapCursors":{"description":"Over a place to travel to, and while planning a route.","type":"object","properties":{"place":{"anyOf":[{"$ref":"#/$defs/CursorLook"},{"type":"null"}]},"route":{"anyOf":[{"$ref":"#/$defs/CursorLook"},{"type":"null"}]}}},"CarryCursor":{"description":"While a thing is held: its icon, or a cursor of its own. Read by a hand-written reader\n(`buffered.rs`): serde's untagged reader would buffer it.","anyOf":[{"$ref":"#/$defs/CarryThing"},{"$ref":"#/$defs/CursorLook"}]},"CarryThing":{"description":"`thing`: the held thing's icon (its picture; none: the hand of `choose`).","type":"string","enum":["thing"]},"StyleRule":{"description":"One rule: `{ part: \"option\", state: \"hover\", property: \"shadow\", value: \"0 0 12px accent\" }`.","type":"object","properties":{"id":{"description":"`lkr_…`.","type":"string"},"part":{"description":"A published part (`option`, `dialogue-box`, …).","type":"string"},"state":{"description":"`hover`, `pressed`, `chosen`, `disabled` or `focus` (none: always).","type":["string","null"]},"property":{"description":"A property of the allowlist (`shadow`, `corners`, …).","type":"string"},"value":{"description":"The value in the property's form (`0 0 12px accent`).","type":"string"}},"required":["id","part","property","value"]},"ChoiceStyle":{"type":"string","enum":["buttons","links","list"]},"LookBackground":{"description":"The look's background picture: an image, and how the picture standing behind the story fills\nthe screen (P6-19, docs/game_systems_spec.md, \"On every screen size\").","type":"object","properties":{"assetId":{"type":"string"},"alt":{"type":["string","null"]},"fit":{"description":"How the background standing behind the story (this picture, a passage's or a chapter's)\nfills the screen (none: `cover`).","anyOf":[{"$ref":"#/$defs/BackgroundFit"},{"type":"null"}]}},"required":["assetId"]},"BackgroundFit":{"description":"How the background fills the screen: covering it (cropped to its shape) or whole on the\nlook's colour (_Show it whole_, for pictures with a frame drawn into them).","type":"string","enum":["cover","contain"]},"TitleScreen":{"type":"object","properties":{"cover":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"subtitle":{"type":["string","null"]},"author":{"type":["string","null"]}}},"TextReveal":{"description":"How lines of story text appear when they are not shown at once.","type":"object","properties":{"unit":{"$ref":"#/$defs/RevealUnit"},"speed":{"description":"Letters per second, 10 to 120.","type":"number","format":"double"}},"required":["unit","speed"]},"RevealUnit":{"type":"string","enum":["words","letters"]},"DialogueLook":{"description":"How spoken lines look: the name before the line, a dialogue box, full-screen text or bubbles.","type":"object","properties":{"style":{"$ref":"#/$defs/DialogueStyle"},"portrait":{"$ref":"#/$defs/DialoguePortrait"},"name":{"$ref":"#/$defs/DialogueName"},"place":{"$ref":"#/$defs/DialoguePlace"},"choices":{"description":"Where options stand: right above the box's room (on one screen), right below the box, or\nin the middle of the scene (none: above the box on one screen, below it in the story).","anyOf":[{"$ref":"#/$defs/DialogueChoices"},{"type":"null"}]},"boxes":{"description":"In the story: one box whose text changes, the lines it replaced plain above it, or a box\nfor every line (none: one).","anyOf":[{"$ref":"#/$defs/DialogueBoxes"},{"type":"null"}]},"narration":{"$ref":"#/$defs/DialogueNarration"},"lines":{"description":"The box keeps room for this many lines, 2 to 8 (none: it fits its text).","type":["integer","null"],"format":"uint32","minimum":0},"opacity":{"description":"How much the panel of the box, the page or a bubble covers, 0.3 to 1 (none: 1).","type":["number","null"],"format":"double"},"you":{"description":"With bubbles: the character whose lines stand on the right.","type":["string","null"]},"box":{"description":"The dialogue box and its name plate, of their own (none: the boxes').","anyOf":[{"$ref":"#/$defs/DialogueBoxLook"},{"type":"null"}]}},"required":["style","portrait","name","place","narration"]},"DialogueStyle":{"oneOf":[{"type":"string","enum":["inline","box"]},{"description":"Full-screen text: the passage's lines on a see-through page over the whole window.","type":"string","const":"page"},{"description":"Chat bubbles, as in a messenger.","type":"string","const":"bubbles"}]},"DialoguePortrait":{"description":"Where the box shows the portrait; `speaker_side`: where the speaker stands on stage.","type":"string","enum":["none","left","right","speaker_side"]},"DialogueName":{"type":"string","enum":["in_box","plate","none"]},"DialoguePlace":{"type":"string","enum":["in_story","bottom","top","middle"]},"DialogueChoices":{"type":"string","enum":["above_box","below_box","center"]},"DialogueBoxes":{"type":"string","enum":["one","each_line"]},"DialogueNarration":{"type":"string","enum":["box","plain"]},"DialogueBoxLook":{"description":"The dialogue box and its name plate.","type":"object","properties":{"shape":{"description":"Corners, border and shadow (none: the look's `shape`, then the kind's).","anyOf":[{"$ref":"#/$defs/Shape"},{"type":"null"}]},"frame":{"description":"A frame that comes with Talebench or an uploaded picture.","anyOf":[{"$ref":"#/$defs/BoxFrame"},{"type":"null"}]},"font":{"anyOf":[{"$ref":"#/$defs/Font"},{"type":"null"}]},"colors":{"description":"Fill, text and border (`#rrggbb`); hover and pressed are derived from them.","anyOf":[{"$ref":"#/$defs/PartColors"},{"type":"null"}]},"size":{"anyOf":[{"$ref":"#/$defs/PartSize"},{"type":"null"}]},"texture":{"description":"A texture inside the box (none: the boxes').","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"plate":{"description":"How the speaker's name stands (none: the style's).","anyOf":[{"$ref":"#/$defs/PlateKind"},{"type":"null"}]}}},"Shape":{"type":"object","properties":{"corners":{"anyOf":[{"$ref":"#/$defs/Corners"},{"type":"null"}]},"border":{"anyOf":[{"$ref":"#/$defs/BorderLine"},{"type":"null"}]},"shadow":{"anyOf":[{"$ref":"#/$defs/Shadow"},{"type":"null"}]}}},"Corners":{"type":"string","enum":["square","soft","round"]},"BorderLine":{"type":"string","enum":["none","thin","thick","double"]},"Shadow":{"type":"string","enum":["none","soft","hard"]},"PartColors":{"type":"object","properties":{"fill":{"type":["string","null"]},"text":{"type":["string","null"]},"border":{"type":["string","null"]}}},"PartSize":{"type":"string","enum":["compact","normal","large"]},"PlateKind":{"oneOf":[{"description":"A tab on the box's top edge.","type":"string","const":"tab"},{"description":"A banner across the top edge.","type":"string","const":"banner"},{"description":"A ribbon with folded ends.","type":"string","const":"ribbon"},{"description":"The name in the box, before the text.","type":"string","const":"inline"}]},"StoryView":{"description":"What stays on screen: the whole story, only the current passage, one line at a time, or\nlines while they fit (the oldest fade when the next would not; P4-29).","type":"string","enum":["all","passage","line","fit"]},"InventoryLook":{"description":"The game-like inventory (L-177; docs/playtest_spec.md, \"Menu\"): how the things carried and\nworn are shown.","type":"object","properties":{"layout":{"description":"Lists (the default) or a bag of squares beside each member's figure.","$ref":"#/$defs/InventoryLayout","default":"list"},"size":{"description":"The squares' size (none: medium); on a phone never under 44 px.","anyOf":[{"$ref":"#/$defs/InventorySize"},{"type":"null"}]},"figure":{"description":"What the placed slots stand on (none: a silhouette that comes with Talebench).","anyOf":[{"$ref":"#/$defs/InventoryFigure"},{"type":"null"}]},"columns":{"description":"The most squares in a row of the bag, 3 to 10 (none: as many as fit); fewer where less\nroom is left.","type":["integer","null"],"format":"uint8","minimum":0,"maximum":255}}},"InventoryLayout":{"oneOf":[{"description":"_Things_ and _Equipment_ as lists with buttons.","type":"string","const":"list"},{"description":"One screen per member: the bag as a grid of square icons, the slots on the figure, things\ndragged or tapped into place.","type":"string","const":"bag"}]},"InventorySize":{"type":"string","enum":["small","medium","large"]},"InventoryFigure":{"oneOf":[{"description":"A standing figure that comes with Talebench, in the text's colour.","type":"string","const":"silhouette"},{"description":"The member's own picture (its portrait), the slots over it.","type":"string","const":"portrait"},{"description":"No figure: the slots side by side, places left aside.","type":"string","const":"none"}]},"PassageChange":{"description":"How one passage gives way to the next when the screen is cleared.","oneOf":[{"type":"string","enum":["none","fade","slide"]},{"description":"The new picture or text appears through the old (L-46).","type":"string","const":"dissolve"},{"description":"The new one wipes across from the left.","type":"string","const":"wipe"},{"description":"A circle opens from the middle.","type":"string","const":"iris"},{"description":"The old one turns away like a page.","type":"string","const":"page_turn"},{"description":"The old one breaks into blocks, the new one forms from them.","type":"string","const":"pixelate"}]},"MotionLook":{"description":"Movement (L-46, docs/game_systems_spec.md, \"Individual looks and finish\"): each part falls\nback to the personality, the personality to the style.","type":"object","properties":{"personality":{"anyOf":[{"$ref":"#/$defs/MotionPersonality"},{"type":"null"}]},"lines":{"anyOf":[{"$ref":"#/$defs/Appear"},{"type":"null"}]},"options":{"anyOf":[{"$ref":"#/$defs/OptionsAppear"},{"type":"null"}]},"taken":{"anyOf":[{"$ref":"#/$defs/TakenMotion"},{"type":"null"}]},"pictures":{"description":"When a scene's picture, a backdrop or an expression changes.","anyOf":[{"$ref":"#/$defs/PassageChange"},{"type":"null"}]},"idle":{"anyOf":[{"$ref":"#/$defs/IdleMotion"},{"type":"null"}]},"speaking":{"anyOf":[{"$ref":"#/$defs/SpeakingMotion"},{"type":"null"}]}}},"MotionPersonality":{"description":"The game's movement personality (L-46): durations, easings, and what moves by default.","type":"string","enum":["calm","snappy","bouncy","dreamy","mechanical","none"]},"Appear":{"description":"How a new line or option appears.","type":"string","enum":["none","fade","rise"]},"OptionsAppear":{"description":"Options appear together or one after another.","type":"string","enum":["together","one_by_one"]},"TakenMotion":{"description":"How a chosen option is taken into the story.","oneOf":[{"description":"The others fade, it stays a moment.","type":"string","const":"settle"},{"description":"It flies up into the story.","type":"string","const":"rise"},{"description":"Gone at once.","type":"string","const":"none"}]},"IdleMotion":{"description":"A figure on stage while idle.","type":"string","enum":["none","breathe","bob"]},"SpeakingMotion":{"description":"A figure on stage while it speaks.","type":"string","enum":["none","bounce"]},"TopBarPlace":{"description":"Where the bar with the status line, Menu and Settings sits.","type":"string","enum":["top","bottom","side","floating","on_hover"]},"ScreensLook":{"description":"Screens of their own (L-45): each part falls back to the style.","type":"object","properties":{"title":{"anyOf":[{"$ref":"#/$defs/TitleScreenLook"},{"type":"null"}]},"ending":{"anyOf":[{"$ref":"#/$defs/EndingScreenLook"},{"type":"null"}]},"menu":{"anyOf":[{"$ref":"#/$defs/MenuScreenLook"},{"type":"null"}]},"loading":{"anyOf":[{"$ref":"#/$defs/LoadingScreenLook"},{"type":"null"}]},"battle":{"anyOf":[{"$ref":"#/$defs/BattleScreenLook"},{"type":"null"}]},"map":{"anyOf":[{"$ref":"#/$defs/MapScreenLook"},{"type":"null"}]}}},"TitleScreenLook":{"description":"The title screen's own arrangement (L-45).","type":"object","properties":{"arrangement":{"anyOf":[{"$ref":"#/$defs/Arrangement"},{"type":"null"}]},"background":{"anyOf":[{"$ref":"#/$defs/ScreenBackground"},{"type":"null"}]},"logo":{"description":"A picture instead of the title's words (they stay for screen readers).","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"buttons":{"anyOf":[{"$ref":"#/$defs/ButtonsPlace"},{"type":"null"}]},"music":{"description":"Music while the title screen shows.","type":["string","null"]}}},"Arrangement":{"description":"How a screen (title, ending) arranges its parts.","type":"string","enum":["centred","left","band","full_bleed"]},"ScreenBackground":{"description":"A screen's background: the style's, the cover blurred, a colour or a picture.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"style"}},"required":["type"]},{"type":"object","properties":{"type":{"type":"string","const":"blurred_cover"}},"required":["type"]},{"type":"object","properties":{"color":{"type":"string"},"type":{"type":"string","const":"color"}},"required":["type","color"]},{"type":"object","properties":{"image":{"$ref":"#/$defs/ImageRef"},"type":{"type":"string","const":"picture"}},"required":["type","image"]}]},"ButtonsPlace":{"description":"Where the title screen's buttons stand.","type":"string","enum":["below","left","right","bottom"]},"EndingScreenLook":{"description":"The ending screen's arrangement.","type":"object","properties":{"arrangement":{"anyOf":[{"$ref":"#/$defs/Arrangement"},{"type":"null"}]},"background":{"anyOf":[{"$ref":"#/$defs/ScreenBackground"},{"type":"null"}]}}},"MenuScreenLook":{"type":"object","properties":{"arrangement":{"anyOf":[{"$ref":"#/$defs/MenuArrangement"},{"type":"null"}]}}},"MenuArrangement":{"description":"Where the menu opens.","type":"string","enum":["panel_right","panel_left","centred","full"]},"LoadingScreenLook":{"type":"object","properties":{"logo":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"progress":{"anyOf":[{"$ref":"#/$defs/Progress"},{"type":"null"}]}}},"Progress":{"description":"How loading shows its progress.","type":"string","enum":["bar","ring","dots"]},"BattleScreenLook":{"type":"object","properties":{"layout":{"anyOf":[{"$ref":"#/$defs/BattleLayout"},{"type":"null"}]},"bars":{"anyOf":[{"$ref":"#/$defs/BarStyle"},{"type":"null"}]},"result":{"description":"How a won battle ends (L-65; none: `card`).","anyOf":[{"$ref":"#/$defs/BattleResultKind"},{"type":"null"}]},"windows":{"description":"Where names, bars and actions stand (L-66; none: `beside`).","anyOf":[{"$ref":"#/$defs/BattleWindows"},{"type":"null"}]}}},"BattleLayout":{"description":"How a battle stands: foes and party side by side, the foes in front, a list, or the sides\nfacing each other (L-66: foes on the left, the party on the right).","type":"string","enum":["side","front","list","across"]},"BarStyle":{"description":"How a fighter's bars (HP …) show.","type":"string","enum":["bar","segments","numbers"]},"BattleResultKind":{"description":"How a won battle ends: a card in the story that does not wait, or a victory screen with the\nspoils and a level-up box per member who rose, each waiting for a press (L-65).","type":"string","enum":["card","screen"]},"BattleWindows":{"description":"Where the battle's names, bars and actions stand (L-66): beside each figure, or in a row of\nboxes under the battle's picture.","type":"string","enum":["beside","bottom"]},"MapScreenLook":{"type":"object","properties":{"marker":{"anyOf":[{"$ref":"#/$defs/MapMarker"},{"type":"null"}]},"route":{"anyOf":[{"$ref":"#/$defs/RouteStyle"},{"type":"null"}]}}},"MapMarker":{"description":"The world map's marker for the player.","type":"string","enum":["pin","dot","flag","ring"]},"RouteStyle":{"description":"How the world map draws its routes.","type":"string","enum":["solid","dashed","dotted","footsteps"]},"TextLook":{"type":"object","properties":{"size":{"anyOf":[{"$ref":"#/$defs/TextSize"},{"type":"null"}]},"dialogueSize":{"description":"Spoken lines against the narration (none: the same size; L-83).","anyOf":[{"$ref":"#/$defs/DialogueSize"},{"type":"null"}]},"lineSpacing":{"anyOf":[{"$ref":"#/$defs/LineSpacing"},{"type":"null"}]},"width":{"anyOf":[{"$ref":"#/$defs/ColumnWidth"},{"type":"null"}]},"align":{"anyOf":[{"$ref":"#/$defs/TextAlign"},{"type":"null"}]},"marked":{"description":"How words marked for a collection entry look, and whether new entries are told (L-87;\nnone: underlined, told).","anyOf":[{"$ref":"#/$defs/MarkedLook"},{"type":"null"}]}}},"TextSize":{"type":"string","enum":["small","normal","large"]},"DialogueSize":{"description":"Spoken lines a step smaller or larger than the narration (L-83): 0.9 or 1.1 of it.","type":"string","enum":["smaller","same","larger"]},"LineSpacing":{"type":"string","enum":["tight","normal","loose"]},"ColumnWidth":{"description":"The text column; `full` uses the whole window, up to 70 characters per line for the text.","type":"string","enum":["narrow","normal","wide","full"]},"TextAlign":{"type":"string","enum":["left","justify"]},"MarkedLook":{"description":"Marked words (L-87): their look and the notice of an entry they reveal.","type":"object","properties":{"style":{"description":"None: underlined.","anyOf":[{"$ref":"#/$defs/MarkedStyle"},{"type":"null"}]},"color":{"description":"For `coloured` (none: the accent).","anyOf":[{"$ref":"#/$defs/SpanColor"},{"type":"null"}]},"showNew":{"description":"A short \"New in Lore book: Bruchmond\" when reading reveals an entry (none: shown).","type":["boolean","null"],"x-default":true}}},"MarkedStyle":{"description":"How marked words stand out; `none` still reveals and opens on a tap.","type":"string","enum":["underlined","dotted","framed","coloured","none"]},"SpanColor":{"type":"string","enum":["accent","muted","red","orange","gold","green","blue","purple"]},"ChoiceLayout":{"description":"`choiceStyle`: how option buttons sit in the column.","type":"object","properties":{"align":{"anyOf":[{"$ref":"#/$defs/ChoiceAlign"},{"type":"null"}]},"width":{"anyOf":[{"$ref":"#/$defs/ChoiceWidth"},{"type":"null"}]}}},"ChoiceAlign":{"type":"string","enum":["left","center"]},"ChoiceWidth":{"type":"string","enum":["fit","full"]},"ContinueMarker":{"description":"Where a line waits: a blinking ▼, a dot, nothing, or a picture.","anyOf":[{"$ref":"#/$defs/MarkerKind"},{"type":"object","properties":{"image":{"$ref":"#/$defs/ImageRef"}},"required":["image"]}]},"MarkerKind":{"type":"string","enum":["arrow","dot","none"]},"LookSounds":{"description":"Interface sounds (audio assets).","type":"object","properties":{"choose":{"description":"Choosing an option.","type":["string","null"]},"open":{"description":"Opening the menu or the reader.","type":["string","null"]},"close":{"description":"Closing it.","type":["string","null"]},"page":{"description":"Turning a page (a new passage, a page in the reader).","type":["string","null"]},"hover":{"description":"The pointer over an option.","type":["string","null"]},"cancel":{"description":"Going back a level (`Escape`).","type":["string","null"]},"error":{"description":"Something did not work (a locked option, a save that cannot be loaded).","type":["string","null"]},"save":{"type":["string","null"]},"load":{"type":["string","null"]},"notice":{"description":"A notice appearing.","type":["string","null"]},"achievement":{"description":"An achievement (an entry kept across playthroughs).","type":["string","null"]},"ending":{"description":"Reaching an ending.","type":["string","null"]},"typing":{"description":"A tick as each word or letter appears, when the line has no talk sound.","type":["string","null"]},"newEntry":{"description":"L-87: reading a marked word revealed an entry (none: the notice's).","type":["string","null"]},"select":{"description":"L-217: A thing, a place on a map, a save slot, a fighter or a target picked before anything happens.","type":["string","null"]},"toggle":{"description":"L-217: A setting switched on or off.","type":["string","null"]},"tab":{"description":"L-217: A tab of the menu, of a book or of the dice tray's command levels.","type":["string","null"]},"slider":{"description":"L-217: A volume or a speed let go (a short sample at the new level).","type":["string","null"]},"drag":{"description":"L-217: Something picked up to be moved (a thing in the inventory, a card).","type":["string","null"]},"drop":{"description":"L-217: Something laid down where it was moved.","type":["string","null"]},"deny":{"description":"L-217: A choice or command that cannot be taken now (softer than `error`).","type":["string","null"]},"turn":{"description":"L-217: Your move in a match (L-205).","type":["string","null"]},"copy":{"description":"L-217: A link or code copied.","type":["string","null"]},"join":{"description":"L-217: Another player joining a match.","type":["string","null"]},"reward":{"description":"L-217: Gold, a thing or experience given.","type":["string","null"]},"writing":{"description":"L-59: a writing sound that comes with Talebench instead of `typing`'s file (it wins over\nit). A name, not an enum, so the player's build carries no parser for it; the player\nignores a name it does not know.","anyOf":[{"$ref":"#/$defs/WritingSound"},{"type":"null"}]},"set":{"description":"L-72: a sound set that comes with Talebench (`chip`) for every interface and battle sound\nleft unset. A name, not an enum, as `writing`; the player ignores a set it does not know.","anyOf":[{"$ref":"#/$defs/SoundSet"},{"type":"null"}]},"ways":{"description":"L-57: whether ways left at `auto` sound as they are taken (footsteps on the next\npassage's ground, a door, a horse, oars); none: off.","type":["boolean","null"]}}},"WritingSound":{"description":"The writing sounds that come with Talebench (L-59), files of the player; only in the schema.","type":"string","enum":["quill","pencil","fountain_pen","typewriter","chalk","keyboard","soft_tick"]},"SoundSet":{"description":"The sound sets that come with Talebench (L-72), files of the player; only in the schema.","oneOf":[{"type":"string","enum":["chip"]},{"description":"L-217: natural sounds of wood, leather, parchment and metal.","type":"string","const":"table"}]},"OptionsLook":{"description":"The options the player picks from.","type":"object","properties":{"kind":{"anyOf":[{"$ref":"#/$defs/OptionKind"},{"type":"null"}]},"shape":{"description":"Corners, border and shadow (none: the look's `shape`, then the kind's).","anyOf":[{"$ref":"#/$defs/Shape"},{"type":"null"}]},"frame":{"description":"A frame that comes with Talebench or an uploaded picture.","anyOf":[{"$ref":"#/$defs/BoxFrame"},{"type":"null"}]},"font":{"anyOf":[{"$ref":"#/$defs/Font"},{"type":"null"}]},"colors":{"description":"Fill, text and border (`#rrggbb`); hover and pressed are derived from them.","anyOf":[{"$ref":"#/$defs/PartColors"},{"type":"null"}]},"size":{"anyOf":[{"$ref":"#/$defs/PartSize"},{"type":"null"}]},"marker":{"description":"What stands before each option (none: the style's).","anyOf":[{"$ref":"#/$defs/OptionMarker"},{"type":"null"}]},"chosen":{"description":"How an option chosen before looks when it is offered again (none: faded).","anyOf":[{"$ref":"#/$defs/ChosenLook"},{"type":"null"}]}}},"OptionKind":{"oneOf":[{"description":"A raised card with room around its words.","type":"string","const":"card"},{"description":"A rounded pill.","type":"string","const":"pill"},{"description":"A plain button.","type":"string","const":"button"},{"description":"A banner across the column, with pointed ends.","type":"string","const":"banner"},{"description":"A link in the text.","type":"string","const":"link"},{"description":"A numbered line.","type":"string","const":"line"}]},"OptionMarker":{"anyOf":[{"$ref":"#/$defs/OptionMarkerKind"},{"type":"object","properties":{"image":{"$ref":"#/$defs/ImageRef"}},"required":["image"]}]},"OptionMarkerKind":{"oneOf":[{"type":"string","enum":["none","diamond","arrow","dot"]},{"description":"\"1.\", \"2.\" …","type":"string","const":"number"},{"description":"The key that picks it, in a badge.","type":"string","const":"key"}]},"ChosenLook":{"oneOf":[{"type":"string","enum":["fade"]},{"description":"Struck through.","type":"string","const":"strike"},{"description":"A tick before it.","type":"string","const":"tick"},{"description":"As any other.","type":"string","const":"same"}]},"ButtonsLook":{"description":"_Continue_, the top bar's buttons, menus and dialogs.","type":"object","properties":{"kind":{"anyOf":[{"$ref":"#/$defs/ButtonKind"},{"type":"null"}]},"shape":{"description":"Corners, border and shadow (none: the look's `shape`, then the kind's).","anyOf":[{"$ref":"#/$defs/Shape"},{"type":"null"}]},"frame":{"description":"A frame that comes with Talebench or an uploaded picture.","anyOf":[{"$ref":"#/$defs/BoxFrame"},{"type":"null"}]},"font":{"anyOf":[{"$ref":"#/$defs/Font"},{"type":"null"}]},"colors":{"description":"Fill, text and border (`#rrggbb`); hover and pressed are derived from them.","anyOf":[{"$ref":"#/$defs/PartColors"},{"type":"null"}]},"size":{"anyOf":[{"$ref":"#/$defs/PartSize"},{"type":"null"}]}}},"ButtonKind":{"oneOf":[{"description":"In the accent colour.","type":"string","const":"filled"},{"description":"An accent outline.","type":"string","const":"outline"},{"description":"Words only, underlined on hover.","type":"string","const":"quiet"},{"description":"Round, with an outline.","type":"string","const":"round"}]},"InitialLook":{"description":"A large first letter (a drop cap).","type":"object","properties":{"place":{"$ref":"#/$defs/InitialPlace"},"lines":{"description":"How many lines tall, 2 to 4 (none: 3).","type":["integer","null"],"format":"uint32","minimum":0},"font":{"description":"None: the style's initial font, else its titles' font.","anyOf":[{"$ref":"#/$defs/Font"},{"type":"null"}]},"color":{"description":"`#rrggbb` (none: the accent).","type":["string","null"]},"ornament":{"description":"A picture behind the letter.","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]}},"required":["place"]},"InitialPlace":{"oneOf":[{"description":"None at all (a style's initial switched off).","type":"string","const":"none"},{"description":"The first line of the game.","type":"string","const":"game"},{"description":"The first line of each chapter.","type":"string","const":"chapter"},{"description":"The first line of each passage.","type":"string","const":"passage"}]},"IconsLook":{"type":"object","properties":{"set":{"description":"None: the style's set.","anyOf":[{"$ref":"#/$defs/IconSet"},{"type":"null"}]},"pictures":{"anyOf":[{"$ref":"#/$defs/IconPictures"},{"type":"null"}]}}},"IconSet":{"description":"The icon sets that come with Talebench, all drawn in the look's colours, or words instead.","oneOf":[{"type":"string","enum":["line","solid","pixel","engraved","hand_drawn"]},{"description":"The names as words instead of icons.","type":"string","const":"words"}]},"IconPictures":{"description":"An uploaded picture per place, instead of the set's icon (names stay the accessible labels).","type":"object","properties":{"skip":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"auto":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"hide":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"menu":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"settings":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"note":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"close":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"back":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"save":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]}}},"Divider":{"description":"What stands between passages and scenes.","oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"none"}},"required":["type"]},{"type":"object","properties":{"type":{"type":"string","const":"line"}},"required":["type"]},{"type":"object","properties":{"ornament":{"$ref":"#/$defs/Ornament"},"type":{"type":"string","const":"ornament"}},"required":["type","ornament"]},{"type":"object","properties":{"image":{"$ref":"#/$defs/ImageRef"},"type":{"type":"string","const":"picture"}},"required":["type","image"]}]},"Ornament":{"description":"The ornaments that come with Talebench, drawn in the accent colour.","type":"string","enum":["fleuron","stars","vine","knot","diamond","wave"]},"ChapterHeading":{"description":"How a chapter's title looks (its card in the player, its heading in the book).","oneOf":[{"description":"The title in the heading font.","type":"string","const":"plain"},{"description":"Spaced capitals.","type":"string","const":"caps"},{"description":"Between two ornaments (the divider's, else a fleuron).","type":"string","const":"ornament"},{"description":"Between two lines.","type":"string","const":"rule"},{"description":"A large chapter number above the title.","type":"string","const":"numeral"}]},"Density":{"description":"How much room everything has; targets stay at least 44 px.","type":"string","enum":["airy","normal","compact"]},"SkinLook":{"description":"The top bar, tabs, chips, notices, bars and sliders, each of its own.","type":"object","properties":{"topBar":{"anyOf":[{"$ref":"#/$defs/PartSkin"},{"type":"null"}]},"tabs":{"anyOf":[{"$ref":"#/$defs/PartSkin"},{"type":"null"}]},"chips":{"anyOf":[{"$ref":"#/$defs/PartSkin"},{"type":"null"}]},"notices":{"anyOf":[{"$ref":"#/$defs/PartSkin"},{"type":"null"}]},"bars":{"anyOf":[{"$ref":"#/$defs/PartSkin"},{"type":"null"}]},"sliders":{"anyOf":[{"$ref":"#/$defs/PartSkin"},{"type":"null"}]}}},"PartSkin":{"description":"A frame or pictures for one interface part: idle, hover and pressed (9-slice each).","type":"object","properties":{"frame":{"description":"A frame that comes with Talebench (none: the style's own look of the part).","anyOf":[{"$ref":"#/$defs/FrameName"},{"type":"null"}]},"idle":{"anyOf":[{"$ref":"#/$defs/Frame"},{"type":"null"}]},"hover":{"description":"None: the idle picture.","anyOf":[{"$ref":"#/$defs/Frame"},{"type":"null"}]},"pressed":{"description":"None: the hover picture.","anyOf":[{"$ref":"#/$defs/Frame"},{"type":"null"}]}}},"FocusStyle":{"description":"How the focused control is marked; always at least 3 : 1 against the page.","type":"string","enum":["ring","glow","underline","marker"]},"SpeakerColor":{"description":"Where a character's `nameColor` shows: on the name only, or also on their bubble, the\ndialogue box's border or the name plate.","type":"string","enum":["name","frame"]},"DiceFaces":{"description":"Dice drawn with pips (the classic layout) or with numbered faces; screen readers hear the\nnumber either way.","type":"string","enum":["pips","numbers"]},"DiceReveal":{"description":"How the dice of a throw appear: one after another (the default) or all at once. The engine is\nnot involved: the throw is already decided.","type":"string","enum":["one_by_one","together"]},"DiceStyle":{"description":"The dice's style: plain (the look's card and text colours), wood, bone or pixel, drawn in CSS\nonly; wood and bone keep their own colours in light and dark.","type":"string","enum":["plain","wood","bone","pixel"]},"DiceTable":{"description":"The dice table (P8-43): plain (the look's colours) or a drawn set — iron and wood: oak planks\nin iron bands with rivets, the action lane on an iron plate under a crest with glowing runes;\ndragon scale and brimstone, gothic cathedral and iron, ancient runic stone, steampunk and\nscrap metal, elven forest and ironwood: each its surface, its band, its crest and its glow.","type":"string","enum":["plain","iron_wood","dragon_brimstone","gothic_cathedral","runic_stone","steampunk_scrap","elven_forest"]},"DiceEffects":{"description":"How much a dice throw moves and shines (L-107): full, light or off. The engine is not\ninvolved: the throw is already decided.","type":"string","enum":["full","light","off"]},"StartPassage":{"type":"object","properties":{"passageId":{"type":"string"}},"required":["passageId"]},"ThingQty":{"type":"object","properties":{"thingId":{"type":"string"},"qty":{"type":"integer","format":"uint32","minimum":0},"made":{"description":"L-176: a made thing's ID (`mad_<n>`, its parts in `GameState.made`; never stacked: `qty`\n1); none: a plain thing.","type":["string","null"]}},"required":["thingId","qty"]},"InventorySettings":{"type":"object","properties":{"maxDistinct":{"type":["integer","null"],"format":"uint32","minimum":0},"defaultMaxStack":{"type":"integer","format":"uint32","minimum":0}},"required":["defaultMaxStack"]},"PlayerSettings":{"type":"object","properties":{"rewindLastChoice":{"type":"boolean"},"saving":{"description":"Where players may save into a slot (none: `anywhere`; L-68).","anyOf":[{"$ref":"#/$defs/Saving"},{"type":"null"}]},"boxColor":{"description":"Players may choose the colour of the boxes under _Settings_ (L-71; none: off).","type":["boolean","null"]}},"required":["rewindLastChoice"]},"Saving":{"description":"Where players may save into a slot (docs/game_systems_spec.md, \"Saving at save points\").","oneOf":[{"type":"string","enum":["anywhere"]},{"description":"Only in passages marked `savePoint` and at a `save` step.","type":"string","const":"save_points"}]},"TalkSettings":{"type":"object","properties":{"narrator":{"anyOf":[{"$ref":"#/$defs/TalkVoice"},{"type":"null"}]}}},"TalkVoice":{"description":"A voice for talk sounds (docs/game_systems_spec.md, \"Talk sounds\"): short sounds per syllable\nwhile a line appears. The engine only carries it; the player makes the sounds.","type":"object","properties":{"preset":{"description":"The preset the creator started from (sliders changed since keep it).","type":["string","null"]},"sound":{"$ref":"#/$defs/TalkSound"},"pitch":{"description":"The voice's middle note: semitones from A4, −24 to 24.","type":"number","format":"double"},"variance":{"description":"How far a syllable may move from it: 0 to 12 semitones.","type":"number","format":"double"},"speed":{"description":"Syllables per second, 4 to 20 (also how fast the line appears).","type":"number","format":"double"},"volume":{"description":"0 to 1, under the player's voice volume.","type":"number","format":"double"}},"required":["sound","pitch","variance","speed","volume"]},"TalkSound":{"oneOf":[{"description":"Made by the player: a short tone of this wave.","type":"object","properties":{"wave":{"$ref":"#/$defs/Wave"},"type":{"type":"string","const":"wave"}},"required":["type","wave"]},{"description":"A short recorded sound, played at each syllable's note.","type":"object","properties":{"assetId":{"type":"string"},"type":{"type":"string","const":"sample"}},"required":["type","assetId"]}]},"Wave":{"type":"string","enum":["sine","square","triangle","saw"]},"Credit":{"description":"One role of the credits and who filled it.","type":"object","properties":{"role":{"type":"string"},"names":{"type":"array","items":{"type":"string"},"default":[]}},"required":["role"]},"Extras":{"description":"The title screen's extras (L-31; docs/playtest_spec.md, \"Visual-novel extras\"), each off by\ndefault.","type":"object","properties":{"gallery":{"description":"The pictures seen.","type":"boolean"},"musicRoom":{"description":"The music heard.","type":"boolean"},"chapterSelect":{"description":"The chapters reached, once an ending is found.","type":"boolean"},"credits":{"description":"The credits on a screen of their own.","type":"boolean"}}},"ValueDef":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"type":{"$ref":"#/$defs/ValueType"},"states":{"description":"Type `state`: its states in order; `default` is a state key.","type":["array","null"],"items":{"$ref":"#/$defs/StateDef"}},"items":{"description":"Type `list`: the items it may hold; `default` holds the keys of its starting entries in\norder (L-20).","type":["array","null"],"items":{"$ref":"#/$defs/ListItem"}},"scope":{"$ref":"#/$defs/ValueScope"},"appliesTo":{"description":"Scope `character`: default `characters`.","anyOf":[{"$ref":"#/$defs/AppliesTo"},{"type":"null"}]},"chapterId":{"description":"A game value kept within one chapter (L-147): back at its default whenever the story moves\ninto another chapter; only that chapter's passages name it (`value.outside_chapter`).","type":["string","null"]},"default":{"$ref":"#/$defs/Scalar"},"min":{"type":["number","null"],"format":"double"},"max":{"type":["number","null"],"format":"double"},"bar":{"anyOf":[{"$ref":"#/$defs/Bar"},{"type":"null"}]},"shown":{"type":"boolean"},"stats":{"description":"How a shown game value appears on the Stats page (none: as a number, also in the status\nline).","anyOf":[{"$ref":"#/$defs/ValueStats"},{"type":"null"}]},"notice":{"type":["string","null"]},"codeword":{"type":["string","null"]},"maxLength":{"type":["integer","null"],"format":"uint32","minimum":0},"keep":{"description":"A game value kept across playthroughs (L-88): `MetaState.values` holds it, and a new game\nstarts with it.","$ref":"#/$defs/ValueKeep","x-default":"playthrough"}},"required":["id","key","name","type","scope","default","shown"]},"ValueType":{"oneOf":[{"type":"string","enum":["yesno","number","text"]},{"description":"One of a named list of states (a quest: not started → accepted → done); stored as its key.","type":"string","const":"state"},{"description":"Entries of its items in the order added, repeats allowed (L-20); stored as item IDs.","type":"string","const":"list"}]},"StateDef":{"description":"A state of a state value.","type":"object","properties":{"id":{"type":"string"},"key":{"description":"What formulas compare with: `quest == \"key_found\"`.","type":"string"},"name":{"type":"string"},"description":{"description":"Shown under the name where players choose it (character creation, L-32).","type":["string","null"]},"picture":{"description":"Its picture where players choose it, and the portrait of a character whose\n`portraitFromValueId` is this value (L-32).","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]}},"required":["id","key","name"]},"ListItem":{"description":"An item a list value may hold (L-20): `itm_…`, a key for formulas, a name players read.","type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"name":{"type":"string"}},"required":["id","key","name"]},"ValueScope":{"type":"string","enum":["game","character"]},"AppliesTo":{"anyOf":[{"$ref":"#/$defs/AppliesToGroup"},{"type":"object","properties":{"characterIds":{"type":"array","items":{"type":"string"}}},"required":["characterIds"]}]},"AppliesToGroup":{"oneOf":[{"type":"string","enum":["characters"]},{"description":"Characters and enemies.","type":"string","const":"everyone"},{"description":"The characters who can be in the party.","type":"string","const":"party"}]},"Scalar":{"description":"A value of a `ValueDef`: yes/no, number, text or a list's entries (L-20: item keys in a\n`default`, item IDs in a game state).","anyOf":[{"type":"boolean"},{"type":"number","format":"double"},{"type":"string"},{"type":"array","items":{"type":"string"}}]},"Bar":{"description":"A number clamped to a maximum (`hp` with maximum `max_hp`).","type":"object","properties":{"max":{"$ref":"#/$defs/BarMax"},"color":{"type":["string","null"]}},"required":["max"]},"BarMax":{"anyOf":[{"type":"object","properties":{"valueId":{"type":"string"}},"required":["valueId"]},{"type":"object","properties":{"fixed":{"type":"number","format":"double"}},"required":["fixed"]}]},"ValueStats":{"description":"A value on the Stats page (docs/game_systems_spec.md, \"Values\").","type":"object","properties":{"group":{"description":"A heading (\"Personality\", \"Skills\").","type":["string","null"]},"display":{"$ref":"#/$defs/StatDisplay"},"opposite":{"description":"`opposed`: the name of the other side (\"Cautious\" for \"Brave\").","type":["string","null"]},"statusLine":{"description":"Also in the status line.","type":"boolean","default":true}},"required":["display"]},"StatDisplay":{"type":"string","enum":["number","percent","opposed"]},"ValueKeep":{"description":"How long a value lasts (L-88).","oneOf":[{"description":"One playthrough: a new game starts at the default.","type":"string","const":"playthrough"},{"description":"Every playthrough in this browser.","type":"string","const":"all_playthroughs"}]},"SharedFormula":{"description":"A shared formula (docs/game_systems_spec.md, \"Shared formulas\").","type":"object","properties":{"id":{"description":"`fml_…`","type":"string"},"key":{"description":"The name formulas call it by (`trust_bonus`).","type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"params":{"description":"The inputs' names inside the body (numbers): `[\"base\", \"bonus\"]`.","type":"array","items":{"type":"string"},"default":[]},"body":{"description":"A formula of the `world` context using the params.","type":"string"}},"required":["id","key","name","body"]},"GameMap":{"type":"object","properties":{"id":{"description":"`map_…`","type":"string"},"name":{"type":"string"},"image":{"description":"The map picture; coordinates are its pixels (none: a plain parchment area of `size`).","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"variants":{"description":"The map picture by time of day, season or weather (P6-09), of the same size.","type":"array","items":{"$ref":"#/$defs/PictureVariant"}},"size":{"$ref":"#/$defs/MapSize"},"places":{"type":"array","items":{"$ref":"#/$defs/Place"},"default":[]},"routes":{"type":"array","items":{"$ref":"#/$defs/Route"},"default":[]},"markerSize":{"description":"Every pin's size on this map (0.5–3, default 1); a place's own multiplies it.","type":["number","null"],"format":"double"},"showNames":{"description":"The default of its places' `show_name` (default always).","anyOf":[{"$ref":"#/$defs/NameShown"},{"type":"null"}]},"thingId":{"description":"Shown only while the player has this thing; *Read* / *Use* on it opens the map.","type":["string","null"]},"planning":{"description":"The player may plan a route on it (`Engine::plan_route`).","type":"boolean"},"vehicles":{"description":"Ways of travelling that open other routes: a ship, a cart, an airship (L-64). With any,\nwalking takes `path` and `road` routes only.","type":"array","items":{"$ref":"#/$defs/Vehicle"}}},"required":["id","name","size"]},"PictureVariant":{"description":"A picture for a time of day, a season or a weather: \"the harbour at night\". Every named part\nmust hold; the most specific variant wins.","type":"object","properties":{"id":{"description":"`var_…`: the address of its picture's alt text.","type":"string"},"part":{"description":"A day part's ID.","type":["string","null"]},"season":{"description":"A season's ID.","type":["string","null"]},"weather":{"description":"A weather kind's ID.","type":["string","null"]},"image":{"$ref":"#/$defs/ImageRef"}},"required":["id","image"]},"MapSize":{"type":"object","properties":{"width":{"type":"number","format":"double"},"height":{"type":"number","format":"double"}},"required":["width","height"]},"Place":{"type":"object","properties":{"id":{"description":"`plc_…`","type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"x":{"description":"Where its pin stands.","type":"number","format":"double"},"y":{"type":"number","format":"double"},"markerSize":{"description":"The pin's size as a share of the map's (0.5–3, default 1).","type":["number","null"],"format":"double"},"showName":{"description":"The name beside the pin (default: the map's `show_names`).","anyOf":[{"$ref":"#/$defs/NameShown"},{"type":"null"}]},"passageId":{"description":"Travelling here enters this passage; entering it means \"here\".","type":["string","null"]},"startsKnown":{"description":"False: hidden until found.","type":"boolean","default":false}},"required":["id","name","x","y"]},"NameShown":{"description":"When a place's name stands beside its pin; it is always the pin's name for screen readers.","oneOf":[{"type":"string","enum":["always","on_hover"]},{"description":"The map picture has it written already.","type":"string","const":"never"}]},"Route":{"type":"object","properties":{"id":{"description":"`rte_…`","type":"string"},"from":{"description":"Place IDs of the same map.","type":"string"},"to":{"type":"string"},"points":{"description":"Bends of the drawn line between the two pins.","type":"array","items":{"$ref":"#/$defs/MapPoint"},"default":[]},"oneWay":{"description":"Only from `from` to `to`.","type":"boolean","default":false},"onlyIf":{"description":"Closed while false (shown with a lock).","type":["string","null"]},"effects":{"description":"Run when travelled (\"Time passes: +2 Hours\").","type":"array","items":{"$ref":"#/$defs/Effect"},"default":[]},"label":{"description":"\"Mountain pass\", shown along the line.","type":["string","null"]},"encounterAreaId":{"description":"Battles by chance while travelling it (L-63).","type":["string","null"]},"steps":{"description":"Draws while travelling it (none: 1); one battle at most per route.","type":["integer","null"],"format":"uint32","minimum":0},"kind":{"description":"The way it is travelled (none: `path`; L-64): on a map with vehicles, `water` and `air`\nroutes need a vehicle of that kind; the sounds on the way (L-57) read it too.","anyOf":[{"$ref":"#/$defs/RouteKind"},{"type":"null"}]},"via":{"description":"A passage on the way (L-19): a journey along it arrives at its destination, but the story\nenters this passage instead of the place's own (an ambush, a ferryman), which leads on.","anyOf":[{"$ref":"#/$defs/RouteVia"},{"type":"null"}]}},"required":["id","from","to"]},"MapPoint":{"type":"object","properties":{"x":{"type":"number","format":"double"},"y":{"type":"number","format":"double"}},"required":["x","y"]},"Effect":{"description":"One vocabulary for every effect list (section 5). Effects never move the story; exits do.\nRead by a hand-written reader (`tagged.rs`) that keeps the player's engine small.","oneOf":[{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"valueId":{"type":"string"},"characterId":{"type":["string","null"]},"to":{"type":"string"},"type":{"type":"string","const":"set"}},"required":["type","valueId","to"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"valueId":{"type":"string"},"characterId":{"type":["string","null"]},"by":{"type":"string"},"type":{"type":"string","const":"change"}},"required":["type","valueId","by"]},{"description":"An entry at the end of a list value (L-20).","type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"valueId":{"type":"string"},"characterId":{"type":["string","null"]},"itemId":{"type":"string"},"type":{"type":"string","const":"add_to_list"}},"required":["type","valueId","itemId"]},{"description":"The item's earliest entry out of a list value; without an item its first entry (L-20).","type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"valueId":{"type":"string"},"characterId":{"type":["string","null"]},"itemId":{"type":["string","null"]},"type":{"type":"string","const":"remove_from_list"}},"required":["type","valueId"]},{"description":"Empties a list value (L-20).","type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"valueId":{"type":"string"},"characterId":{"type":["string","null"]},"type":{"type":"string","const":"clear_list"}},"required":["type","valueId"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"thingId":{"type":"string"},"qty":{"type":"string"},"storageId":{"description":"Into this storage instead of the inventory (reachable or not).","type":["string","null"]},"randomParts":{"description":"L-176: a made thing's parts drawn from the random stream (one draw per group).","type":"boolean"},"parts":{"description":"L-176: a made thing with these parts (none and no `randomParts`: no parts).","type":"array","items":{"type":"string"}},"type":{"type":"string","const":"give"}},"required":["type","thingId","qty"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"thingId":{"type":"string"},"qty":{"type":"string"},"storageId":{"type":["string","null"]},"type":{"type":"string","const":"take"}},"required":["type","thingId","qty"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"characterId":{"type":"string"},"mountId":{"type":"string"},"type":{"type":"string","const":"mount"}},"required":["type","characterId","mountId"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"characterId":{"type":"string"},"type":{"type":"string","const":"dismount"}},"required":["type","characterId"]},{"description":"Weapons and shields (L-106): a thing put on a party member (none: the first) in its slot,\ngiven first when none is carried; what it takes the place of goes back to the inventory.","type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"thingId":{"type":"string"},"characterId":{"type":["string","null"]},"type":{"type":"string","const":"wear"}},"required":["type","thingId"]},{"description":"P8-87: a thing kept as a party member's (none: the first) second set in its slot, given\nfirst when none is carried (a weapon rack's choice for swapping in a dice battle).","type":"object","properties":{"onlyIf":{"type":["string","null"]},"thingId":{"type":"string"},"characterId":{"type":["string","null"]},"type":{"type":"string","const":"second_set"}},"required":["type","thingId"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"lootTableId":{"type":"string"},"type":{"type":"string","const":"give_loot"}},"required":["type","lootTableId"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"characterId":{"type":"string"},"type":{"type":"string","const":"join_party"}},"required":["type","characterId"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"characterId":{"type":"string"},"type":{"type":"string","const":"leave_party"}},"required":["type","characterId"]},{"description":"`who`: `party` or a character ID.","type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"who":{"type":"string"},"amount":{"type":"string"},"type":{"type":"string","const":"gain_xp"}},"required":["type","who","amount"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"who":{"type":"string"},"levels":{"type":"integer","format":"uint32","minimum":0},"type":{"type":"string","const":"gain_level"}},"required":["type","who","levels"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"who":{"type":"string"},"points":{"type":"integer","format":"uint32","minimum":0},"type":{"type":"string","const":"grant_skill_points"}},"required":["type","who","points"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"who":{"type":"string"},"points":{"type":"integer","format":"uint32","minimum":0},"type":{"type":"string","const":"grant_stat_points"}},"required":["type","who","points"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"characterId":{"type":"string"},"skillId":{"type":"string"},"type":{"type":"string","const":"learn_skill"}},"required":["type","characterId","skillId"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"characterId":{"type":"string"},"skillId":{"type":"string"},"type":{"type":"string","const":"forget_skill"}},"required":["type","characterId","skillId"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"who":{"type":"string"},"type":{"type":"string","const":"restore"}},"required":["type","who"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"who":{"type":"string"},"statusId":{"type":"string"},"type":{"type":"string","const":"add_status"}},"required":["type","who","statusId"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"who":{"type":"string"},"statusId":{"type":"string"},"type":{"type":"string","const":"remove_status"}},"required":["type","who","statusId"]},{"description":"Maps: the place is found.","type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"placeId":{"type":"string"},"type":{"type":"string","const":"discover_place"}},"required":["type","placeId"]},{"description":"Maps: a vehicle that waits where it was left now waits at this place (L-64).","type":"object","properties":{"onlyIf":{"type":["string","null"]},"vehicleId":{"type":"string"},"placeId":{"type":"string"},"type":{"type":"string","const":"place_vehicle"}},"required":["type","vehicleId","placeId"]},{"description":"Time: time passes (\"2 hours\"), then waits until a time of day or an hour (P6-09).","type":"object","properties":{"onlyIf":{"type":["string","null"]},"minutes":{"description":"Minutes that pass (a formula; the editor shows hours and days as 60 and 1440).","type":["string","null"]},"untilPart":{"description":"Then waits until this day part begins (\"wait until morning\"; nothing while it lasts).","type":["string","null"]},"untilHour":{"description":"Then waits until this hour, 0–23 (nothing when it is that hour on the dot).","type":["integer","null"],"format":"uint32","minimum":0},"type":{"type":"string","const":"time"}},"required":["type"]},{"description":"Weather: the weather becomes this kind (\"the storm breaks\", P6-10).","type":"object","properties":{"onlyIf":{"type":["string","null"]},"set":{"type":"string"},"type":{"type":"string","const":"weather"}},"required":["type","set"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"entryId":{"type":"string"},"sectionId":{"type":["string","null"]},"type":{"type":"string","const":"reveal"}},"required":["type","entryId"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"thingId":{"type":"string"},"type":{"type":"string","const":"mark_read"}},"required":["type","thingId"]},{"description":"L-221: _Play with a friend_ opened for this fight (an encounter played with a friend); the\ngame's state does not change (the player makes the match).","type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"encounterId":{"type":"string"},"type":{"type":"string","const":"play_with_friend"}},"required":["type","encounterId"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"assetId":{"type":["string","null"]},"fadeMs":{"type":"integer","format":"uint32","minimum":0},"volume":{"description":"Its loudness, 0–100 % under the player's own volume (L-192; none: 100).","type":["integer","null"],"format":"uint8","minimum":0,"maximum":255},"type":{"type":"string","const":"music"}},"required":["type","fadeMs"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"assetId":{"type":["string","null"]},"fadeMs":{"type":"integer","format":"uint32","minimum":0},"volume":{"description":"Its loudness, 0–100 % under the player's own volume (L-192; none: 100).","type":["integer","null"],"format":"uint8","minimum":0,"maximum":255},"type":{"type":"string","const":"ambience"}},"required":["type","fadeMs"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"assetId":{"type":"string"},"volume":{"description":"Its loudness, 0–100 % under the player's own volume (L-192; none: 100).","type":["integer","null"],"format":"uint8","minimum":0,"maximum":255},"type":{"type":"string","const":"sound"}},"required":["type","assetId"]},{"description":"The weather's own sound quiet (faded out over `fadeMs`) or back (L-192): it stays quiet\nuntil the weather changes.","type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"quiet":{"type":"boolean"},"fadeMs":{"type":"integer","format":"uint32","minimum":0},"type":{"type":"string","const":"weather_sound"}},"required":["type","quiet","fadeMs"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"damageTypeId":{"type":"string"},"formula":{"type":["string","null"]},"type":{"type":"string","const":"damage"}},"required":["type","damageTypeId"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"barId":{"type":"string"},"formula":{"type":["string","null"]},"type":{"type":"string","const":"heal"}},"required":["type","barId"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"percent":{"type":"number","format":"double"},"type":{"type":"string","const":"revive"}},"required":["type","percent"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"statusId":{"type":"string"},"chance":{"type":"string"},"type":{"type":"string","const":"apply_status"}},"required":["type","statusId","chance"]},{"type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"kind":{"$ref":"#/$defs/CleanseKind"},"type":{"type":"string","const":"cleanse"}},"required":["type","kind"]},{"description":"Defeated at once after one draw of `chance` (1 = always); `defeat` immunity resists it.","type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"chance":{"type":"string"},"type":{"type":"string","const":"defeat"}},"required":["type","chance"]},{"description":"Takes one thing a foe carries (`CombatProfile.carries`) after one draw of `chance` (L-70);\na foe is robbed once; on an ally it does nothing.","type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"chance":{"type":"string"},"type":{"type":"string","const":"steal"}},"required":["type","chance"]},{"description":"Adds `amount` to each target's morale (L-96; negative lowers it, no draw); a target without\nmorale is left alone.","type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"amount":{"type":"string"},"type":{"type":"string","const":"change_morale"}},"required":["type","amount"]},{"description":"Dice tricks (L-101): the skill or thing changes dice on the table in a dice battle, one's\nown after the throw or the opponent's before defending; never an action of its own.","type":"object","properties":{"onlyIf":{"description":"Skipped when false: the world context in story lists, per target in battle.","type":["string","null"]},"trick":{"$ref":"#/$defs/DiceTrickKind"},"on":{"$ref":"#/$defs/DiceTrickOn"},"when":{"$ref":"#/$defs/DiceTrickWhen"},"uses":{"description":"Uses per battle (none: no limit; always at most once per turn).","type":["integer","null"],"format":"uint32","minimum":0},"useWhen":{"description":"A foe's rule for using it (none: when it turns a blocked throw into a hit).","anyOf":[{"$ref":"#/$defs/DiceTrickUse"},{"type":"null"}]},"amount":{"description":"`plus` and `minus` (L-102): how much each die changes (none: 1).","type":["string","null"]},"before":{"description":"`plus` and `minus` on face-down dice: applied at once (none: at the reveal).","type":["boolean","null"]},"type":{"type":"string","const":"dice_trick"}},"required":["type","trick","on","when"]},{"description":"A package's own effect (L-197 e1): carried out by the package `module` (its\n`effect:<name>`); in a game without it, `effects.unsupported`.","type":"object","properties":{"onlyIf":{"type":["string","null"]},"module":{"type":"string"},"name":{"type":"string"},"data":true,"type":{"type":"string","const":"module"}},"required":["type","module","name"]}]},"CleanseKind":{"type":"string","enum":["harmful","helpful","all"]},"DiceTrickKind":{"description":"Dice tricks (L-101; docs/game_systems_spec.md, \"Dice battles\", \"Dice tricks\"): what a\n`dice_trick` effect does to the dice on the table.","oneOf":[{"description":"One chosen die thrown again.","type":"string","const":"reroll_one"},{"description":"One chosen die turned up or down by one (1 and 6 stay in range).","type":"string","const":"nudge"},{"description":"One chosen die turned to 6.","type":"string","const":"set_six"},{"description":"One more die thrown, the best ones kept (on the opponent's throw: the worst).","type":"string","const":"add_die"},{"description":"The opponent's rerolls do not count this turn.","type":"string","const":"lock"},{"description":"The opponent's combination does not count this throw (the sum stays).","type":"string","const":"break"},{"description":"Hidden throws (L-102): one chosen face-down die of the opponent's throw turns face up.","type":"string","const":"peek_one"},{"description":"Hidden throws (L-102): the opponent's whole throw is shown before defending.","type":"string","const":"peek_all"},{"description":"`amount` added to each of one's own dice (at most 6): the attack throw, or the defence.","type":"string","const":"plus"},{"description":"`amount` taken from each of the opponent's dice (at least 1).","type":"string","const":"minus"}]},"DiceTrickOn":{"description":"Whose dice a trick changes: one's own attack throw or the opponent's.","type":"string","enum":["own","opponent"]},"DiceTrickWhen":{"description":"When a trick is used: after one's own throw, before attacking; or on the opponent's attack\nthrow, before defending.","type":"string","enum":["after_throw","before_defence"]},"DiceTrickUse":{"description":"A foe's rule for a trick: when it turns a blocked throw into a hit (on the opponent's throw: a\nhit into a block), when the opponent's throw has a combination, or at random, one in three.","type":"string","enum":["turns_block_into_hit","against_combination","one_in_three"]},"RouteKind":{"description":"How a route is travelled (L-64).","type":"string","enum":["path","road","water","air"]},"RouteVia":{"description":"A route's passage on the way (L-19; docs/game_systems_spec.md, \"Story rules that move the\nstory\").","type":"object","properties":{"passageId":{"type":"string"},"onlyIf":{"description":"Only while true, checked on arrival (none: every journey along the route).","type":["string","null"]}},"required":["passageId"]},"Vehicle":{"description":"A way of travelling on a map (L-64, \"Ways and vehicles\").","type":"object","properties":{"id":{"description":"`veh_…`","type":"string"},"name":{"description":"\"Ship\", \"Airship\"","type":"string"},"picture":{"description":"Its marker on the map while the party travels by it or it waits at a place.","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"onlyIf":{"description":"When the party may use it.","type":["string","null"]},"kinds":{"description":"The routes it can take.","type":"array","items":{"$ref":"#/$defs/RouteKind"},"default":[]},"anywhere":{"description":"Flies straight to any known place with a passage, over every route.","type":"boolean"},"landing":{"description":"With `anywhere`: only these places (none: every known place).","type":"array","items":{"type":"string"}},"staysWhereLeft":{"description":"Waits where the party left it; used only from there.","type":"boolean"},"startsAt":{"description":"Its place at the start (with `stays_where_left`).","type":["string","null"]},"music":{"description":"Plays while travelling by it.","type":["string","null"]},"encounterRate":{"description":"Multiplies the routes' encounter chance (0: none; none: 1).","type":["number","null"],"format":"double"}},"required":["id","name"]},"GameTime":{"description":"The game's clock (`Content.time`, owned by the feature `time`).\nRead by hand (`time_read.rs`).","type":"object","properties":{"start":{"description":"When the story begins (day 1, 8:00).","$ref":"#/$defs/TimeOfDay"},"minutes":{"description":"The clock shows minutes (\"21:40\"; else whole hours, \"21:00\").","type":"boolean"},"dayParts":{"description":"The times of day by the hour they begin (Morning 6, Day 10, Evening 18, Night 22); the\nlast one goes on past midnight until the first begins.","type":"array","items":{"$ref":"#/$defs/DayPart"},"default":[]},"weekdays":{"description":"The weekdays, from the weekday of day 1 (none: weeks of seven numbered days).","type":"array","items":{"$ref":"#/$defs/Weekday"}},"months":{"description":"The months of a year, from the month of day 1 (none: no months).","type":"array","items":{"$ref":"#/$defs/Month"}},"yearDays":{"description":"Days in a year without months (none: 120, four seasons of 30 days).","type":["integer","null"],"format":"uint32","minimum":0},"seasons":{"description":"The seasons by the day of the year they begin (none: no seasons).","type":"array","items":{"$ref":"#/$defs/Season"}},"perPassage":{"description":"Minutes each passage entered takes (none: only changes move the clock).","type":["integer","null"],"format":"uint32","minimum":0},"show":{"description":"What the top bar shows: \"Day 3\", \"Evening\", \"Day 3 · 21:40\" (default both).","$ref":"#/$defs/TimeShow","default":"both"}},"required":["start"]},"TimeOfDay":{"description":"A day and a time on the clock.","type":"object","properties":{"day":{"description":"1 and up.","type":"integer","format":"uint32","minimum":0},"hour":{"description":"0–23.","type":"integer","format":"uint32","minimum":0},"minute":{"description":"0–59 (none: 0).","type":["integer","null"],"format":"uint32","minimum":0}},"required":["day","hour"]},"DayPart":{"description":"A time of day: Morning, Day, Evening, Night.","type":"object","properties":{"id":{"description":"`dpt_…`: what formulas and variants name it by (`time.part == \"dpt_…\"`).","type":"string"},"name":{"type":"string"},"from":{"description":"The hour it begins, 0–23.","type":"integer","format":"uint32","minimum":0},"tint":{"description":"A tint over the screen while it lasts (dusk, night), where the creator chose one.","anyOf":[{"$ref":"#/$defs/Tint"},{"type":"null"}]}},"required":["id","name","from"]},"Tint":{"type":"object","properties":{"color":{"description":"`#rrggbb`.","type":"string"},"amount":{"description":"0–1.","type":"number","format":"double"}},"required":["color","amount"]},"Weekday":{"type":"object","properties":{"id":{"description":"`wkd_…`","type":"string"},"name":{"type":"string"}},"required":["id","name"]},"Month":{"type":"object","properties":{"id":{"description":"`mon_…`","type":"string"},"name":{"type":"string"},"days":{"type":"integer","format":"uint32","minimum":0}},"required":["id","name","days"]},"Season":{"description":"A season: it begins on a day of the year, or with months on a month's day.","type":"object","properties":{"id":{"description":"`ssn_…`: what formulas and variants name it by (`time.season == \"ssn_…\"`).","type":"string"},"name":{"type":"string"},"month":{"description":"1 and up, with months (none: `day` is a day of the year).","type":["integer","null"],"format":"uint32","minimum":0},"day":{"type":"integer","format":"uint32","minimum":0}},"required":["id","name","day"]},"TimeShow":{"type":"string","enum":["off","day","time","both"]},"GameWeather":{"description":"The weather of a game (`Content.weather`, owned by the feature `weather`).\nRead by hand (`time_read.rs`).","type":"object","properties":{"kinds":{"description":"Clear, Rain, Storm, Snow, Fog …","type":"array","items":{"$ref":"#/$defs/WeatherKind"},"default":[]},"start":{"description":"The weather at the start (a kind's ID).","type":"string"},"passages":{"description":"It may change after this many passages entered (none: passages do not change it).","type":["integer","null"],"format":"uint32","minimum":0},"hours":{"description":"… and with Time after this many hours on the clock (none: hours do not change it).","type":["integer","null"],"format":"uint32","minimum":0},"chances":{"description":"What it may turn into: from one kind to another, with a weight. Weights below 1 in all\nare chances (\"1 time in 4\" is 0.25; what is left keeps the weather); 1 or more in all\npick one of them by weight.","type":"array","items":{"$ref":"#/$defs/WeatherChance"},"default":[]},"indoors":{"description":"Also indoors (besides passages and chapters marked indoors) while this holds: the screen\neffect stops, the sound is muffled.","type":["string","null"]}},"required":["start"]},"WeatherKind":{"type":"object","properties":{"id":{"description":"`wth_…`: what formulas, rules and variants name it by (`weather == \"wth_…\"`).","type":"string"},"name":{"type":"string"},"screen":{"description":"The screen effect that falls while it lasts (none: nothing falls).","anyOf":[{"$ref":"#/$defs/Weather"},{"type":"null"}]},"ambience":{"description":"Its loop, played beside the music and ambience (muffled indoors).","type":["string","null"]},"tint":{"description":"A tint over the screen while it lasts (a grey storm).","anyOf":[{"$ref":"#/$defs/Tint"},{"type":"null"}]}},"required":["id","name"]},"Weather":{"type":"string","enum":["none","rain","snow","fog","petals","leaves","embers","dust","fireflies"]},"WeatherChance":{"type":"object","properties":{"from":{"description":"A kind's ID, or `*` for any.","type":"string"},"to":{"type":"string"},"weight":{"description":"A formula (world context): it may ask for `time.season`, `time.part` …","type":"string"}},"required":["from","to","weight"]},"Chapter":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"color":{"type":"string"},"card":{"description":"A title card when the story enters the chapter (none: no card).","anyOf":[{"$ref":"#/$defs/ChapterCard"},{"type":"null"}]},"complete":{"description":"\"Chapter complete\" when the story leaves the chapter for a passage outside it.","type":"boolean"},"choiceStats":{"description":"L-186: when the story leaves it, the player shows what other players chose at its choices\n(the release's play statistics).","type":"boolean"},"room":{"description":"The room its passages play in when they name none (L-58).","anyOf":[{"$ref":"#/$defs/Room"},{"type":"null"}]},"music":{"description":"Its music (L-191): it starts when the story enters the chapter from outside it, before\nthe passage's own steps and scene (they win), and plays on until something changes it.","type":["string","null"]},"encounterAreaId":{"description":"Encounters on the way in its passages that name no area (L-63).","type":["string","null"]},"ground":{"description":"The ground underfoot in its passages that name none (L-57).","anyOf":[{"$ref":"#/$defs/Ground"},{"type":"null"}]},"background":{"description":"The picture behind its passages that set none of their own (P6-06; a scene's picture\nstands over it). Only the player's view reads it.","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"backgroundVariants":{"description":"The background by time of day, season or weather (P6-09): the most specific that holds.","type":"array","items":{"$ref":"#/$defs/PictureVariant"}},"indoors":{"description":"Its passages are indoors (Weather, P6-10): no weather falls, its sound is muffled.","type":"boolean"},"weatherKinds":{"description":"A weather of its own (Weather, P6-10): only these kinds here (the desert: never snow);\nthe first is what the weather becomes on arriving when the one before is not among them.","type":"array","items":{"type":"string"}}},"required":["id","title","color"]},"ChapterCard":{"description":"A chapter's title card: the title with a number above it, a picture and a sound.","type":"object","properties":{"number":{"description":"Above the title: \"Chapter 2\", \"Part II\" (none: the title alone).","type":["string","null"]},"image":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"sound":{"description":"Played once as the card appears (sound-effects volume).","type":["string","null"]}}},"Room":{"description":"The room a passage plays in (L-58, \"Room sound\"): its sound effects, talk sounds and voices\n(music and ambience with `music`) pass through a reverb or a filter. Only the player's audio\nreads it: the engine plays every passage the same. `kind` is a name, not an enum, so the\nplayer's build carries no parser for it; the player ignores a name it does not know, and\nvalidation reports it (`room.unknown`).","type":"object","properties":{"kind":{"$ref":"#/$defs/RoomKind"},"amount":{"description":"How much of the room is heard, 0–1 (none: 0.5).","type":["number","null"],"format":"double","minimum":0,"maximum":1},"music":{"description":"Music and ambience pass through the room too (else they stay dry).","type":"boolean"}},"required":["kind"]},"RoomKind":{"description":"The rooms that come with Talebench (L-58); only in the schema.","type":"string","enum":["none","small_room","hall","cave","cathedral","stairwell","forest","underwater","radio"]},"Ground":{"description":"The grounds footsteps are made for (L-57, \"Sounds on the way\"); only in the schema.","type":"string","enum":["stone","wood","grass","gravel","sand","snow","mud","water","wet","carpet","metal"]},"EveryPassageRule":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"chapterIds":{"type":["array","null"],"items":{"type":"string"}},"onlyIf":{"type":["string","null"]},"effects":{"type":"array","items":{"$ref":"#/$defs/Effect"},"default":[]},"when":{"description":"When it runs (none: each time a passage is entered): a new day, a new time of day, a\nseason, a change of weather (P6-09, P6-10).","anyOf":[{"$ref":"#/$defs/RuleWhen"},{"type":"null"}]}},"required":["id","name"]},"RuleWhen":{"description":"When an every-passage rule runs (none: each time a passage is entered).","oneOf":[{"description":"Each time a passage is entered (the default).","type":"string","const":"passage"},{"description":"When a new day begins (once for each day begun).","type":"string","const":"new_day"},{"description":"When the time of day changes.","type":"string","const":"part_changes"},{"description":"When a season begins.","type":"string","const":"season_begins"},{"description":"When the weather changes.","type":"string","const":"weather_changes"}]},"StoryRule":{"description":"A story rule (L-19; docs/game_systems_spec.md, \"Story rules that move the story\"): it moves\nthe story to its target when its condition becomes true.","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"when":{"type":"string"},"to":{"$ref":"#/$defs/StoryRuleTarget"},"chapterIds":{"description":"Only in these chapters (none: the whole game).","type":"array","items":{"type":"string"}},"again":{"description":"May move the story again after its condition was false in between (none: once).","type":"boolean"}},"required":["id","name","when","to"]},"StoryRuleTarget":{"description":"Where a story rule moves the story.","oneOf":[{"type":"object","properties":{"passageId":{"type":"string"},"type":{"type":"string","const":"passage"}},"required":["type","passageId"]},{"type":"object","properties":{"endingId":{"type":"string"},"type":{"type":"string","const":"ending"}},"required":["type","endingId"]}]},"Passage":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"chapterId":{"type":["string","null"]},"steps":{"type":"array","items":{"$ref":"#/$defs/Step"},"default":[]},"next":{"$ref":"#/$defs/Next"},"scene":{"description":"Scenes feature.","anyOf":[{"$ref":"#/$defs/SceneLayout"},{"type":"null"}]},"story":{"description":"What stays on screen in this passage (none: the look's `story`; P4-29). Only the player's\nview reads it: the engine plays every passage the same.","anyOf":[{"$ref":"#/$defs/StoryView"},{"type":"null"}]},"room":{"description":"The room this passage plays in (none: its chapter's; L-58).","anyOf":[{"$ref":"#/$defs/Room"},{"type":"null"}]},"savePoint":{"description":"Players may save here when the game saves only at save points (L-68).","type":"boolean"},"encounterAreaId":{"description":"Battles by chance when it is entered by a way on (none: its chapter's; L-63).","type":["string","null"]},"ground":{"description":"The ground underfoot here (none: its chapter's), for the footsteps of a way's `auto` sound\n(L-57). A name, as `room.kind`; the player plays none for a name it does not know.","anyOf":[{"$ref":"#/$defs/Ground"},{"type":"null"}]},"background":{"description":"The picture behind the story from this passage on, until another passage sets one (none:\nits chapter's, else the one before; P6-06). A scene's picture stands over it. Only the\nplayer's view reads it.","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"backgroundVariants":{"description":"The background by time of day, season or weather (P6-09): the most specific that holds.","type":"array","items":{"$ref":"#/$defs/PictureVariant"}},"indoors":{"description":"Indoors (Weather, P6-10; none: its chapter's): no weather falls, its sound is muffled.","type":["boolean","null"]},"takes":{"description":"Minutes entering it takes (Time, P6-09; none: the game's `perPassage`).","type":["integer","null"],"format":"uint32","minimum":0},"dungeon":{"description":"A dungeon on this passage (L-155): its kind is _Dungeon_ while it has one.","anyOf":[{"$ref":"#/$defs/Dungeon"},{"type":"null"}]},"runMap":{"description":"A run map on this passage (L-90): made anew for every playthrough.","anyOf":[{"$ref":"#/$defs/RunMap"},{"type":"null"}]}},"required":["id","title","next"]},"Step":{"description":"Read by a hand-written reader (`tagged.rs`) that keeps the player's engine small.","type":"object","properties":{"id":{"type":"string"},"onlyIf":{"type":["string","null"]}},"required":["id"],"oneOf":[{"type":"object","properties":{"speakerId":{"type":["string","null"]},"expressionId":{"type":["string","null"]},"text":{"type":"string"},"image":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"voice":{"type":["string","null"]},"voiceLine":{"description":"The line's number in voice scripts, given once (docs/book_export_spec.md, \"Stable line\nnumbers\"); never read in play.","type":["integer","null"],"format":"uint32","minimum":0},"voiceFor":{"description":"The fingerprint of the text `voice` was recorded for (8 hex digits of FNV-1a); never\nread in play.","type":["string","null"]},"place":{"description":"This line's own place while the dialogue box stands on one screen.","anyOf":[{"$ref":"#/$defs/LinePlace"},{"type":"null"}]},"type":{"type":"string","const":"text"}},"required":["type","text"]},{"type":"object","properties":{"kind":{"$ref":"#/$defs/MediaKind"},"assetId":{"type":"string"},"alt":{"type":["string","null"]},"mode":{"$ref":"#/$defs/MediaMode"},"transition":{"$ref":"#/$defs/Transition"},"waitFor":{"$ref":"#/$defs/WaitFor"},"skippable":{"type":"boolean"},"caption":{"type":["string","null"]},"print":{"type":"boolean"},"type":{"type":"string","const":"media"}},"required":["type","kind","assetId","mode","transition","waitFor","skippable","print"]},{"type":"object","properties":{"effects":{"type":"array","items":{"$ref":"#/$defs/Effect"},"default":[]},"type":{"type":"string","const":"do"}},"required":["type"]},{"type":"object","properties":{"prompt":{"type":"string"},"valueId":{"type":"string"},"type":{"type":"string","const":"ask"}},"required":["type","prompt","valueId"]},{"type":"object","properties":{"thingId":{"type":"string"},"type":{"type":"string","const":"read"}},"required":["type","thingId"]},{"description":"Opens a shop over the story and waits until it closes.","type":"object","properties":{"shopId":{"type":"string"},"type":{"type":"string","const":"shop"}},"required":["type","shopId"]},{"type":"object","properties":{"characterId":{"type":"string"},"action":{"$ref":"#/$defs/StageAction"},"position":{"anyOf":[{"$ref":"#/$defs/StagePosition"},{"type":"null"}]},"expressionId":{"type":["string","null"]},"outfitId":{"description":"The character's outfit from now on (kept off stage too).","type":["string","null"]},"flip":{"description":"Faces the other way (kept until a step says otherwise).","type":["boolean","null"]},"transition":{"description":"How it enters or leaves (default fade).","anyOf":[{"$ref":"#/$defs/Transition"},{"type":"null"}]},"type":{"type":"string","const":"stage"}},"required":["type","characterId","action"]},{"description":"A screen effect: a shake or a flash (moments), a tint, a filter or weather (lasting).","type":"object","properties":{"effect":{"$ref":"#/$defs/ScreenEffectKind"},"strength":{"anyOf":[{"$ref":"#/$defs/ShakeStrength"},{"type":"null"}]},"color":{"description":"`#rrggbb`: the flash's (default white) and the tint's colour.","type":["string","null"]},"amount":{"description":"The tint: 0–1, how strongly (0 clears it).","type":["number","null"],"format":"double"},"weather":{"anyOf":[{"$ref":"#/$defs/Weather"},{"type":"null"}]},"filter":{"description":"The filter over the scene and stage (`none` takes it away).","anyOf":[{"$ref":"#/$defs/ScreenFilter"},{"type":"null"}]},"variant":{"description":"`look`: the look variant from here on (none: the one the passage's labels or chapter\nchoose, L-48).","type":["string","null"]},"zoom":{"description":"`camera` (L-37): 1–4, how close (default 1: the whole picture).","type":["number","null"],"format":"double"},"x":{"description":"`camera`: 0–1, the point of the picture in the middle of the view, from the left\n(default 0.5).","type":["number","null"],"format":"double"},"y":{"description":"`camera`: 0–1, the same from the top (default 0.5).","type":["number","null"],"format":"double"},"durationMs":{"description":"A shake's or flash's time: 100–3000 ms (default 500); a camera move's: 0–10000 ms\n(default 1000; 0: at once).","type":["integer","null"],"format":"uint32","minimum":0},"type":{"type":"string","const":"screen"}},"required":["type","effect"]},{"description":"Offers to save right here: the player opens the save slots (L-68).","type":"object","properties":{"type":{"type":"string","const":"save"}},"required":["type"]},{"description":"The player makes their character on one screen (L-32): a name typed in, a choice among\nnamed options (pronouns, a class, a look with pictures), numbers rolled or chosen, points\nto spread; every answer is a value.","type":"object","properties":{"title":{"description":"The screen's heading (none: the player text `create.title`, \"Make your character\").","type":["string","null"]},"characterId":{"description":"The character being made: the character values asked for are theirs, and their\nportrait shows on the screen.","type":["string","null"]},"fields":{"type":"array","items":{"$ref":"#/$defs/CreateField"},"default":[]},"points":{"description":"Points the player spreads over values.","anyOf":[{"$ref":"#/$defs/CreatePoints"},{"type":"null"}]},"rerolls":{"description":"How often the player may roll the rolled numbers again (none: never).","type":["integer","null"],"format":"uint32","minimum":0},"type":{"type":"string","const":"create"}},"required":["type"]},{"description":"A package's own step (L-197 v2): taken by the package `module` (its `step:<name>`), shown\nin the story as its view (`surface` \"step\") and waiting there until the player goes on.","type":"object","properties":{"module":{"type":"string"},"name":{"type":"string"},"data":true,"type":{"type":"string","const":"module"}},"required":["type","module","name"]}]},"LinePlace":{"description":"A text step's own place while the box stands on one screen.","type":"string","enum":["top","middle","bottom"]},"MediaKind":{"type":"string","enum":["image","video"]},"MediaMode":{"type":"string","enum":["panel","fullscreen","background"]},"Transition":{"type":"string","enum":["cut","fade","slide"]},"WaitFor":{"type":"string","enum":["click","end","none"]},"StageAction":{"type":"string","enum":["enter","leave","move"]},"StagePosition":{"type":"string","enum":["left","left_center","center","center_right","right"]},"ScreenEffectKind":{"oneOf":[{"type":"string","enum":["shake","flash","tint","weather","filter"]},{"description":"A look variant from here on (L-48).","type":"string","const":"look"},{"description":"The camera zooms into or pans across the scene picture, kept until changed (L-37).","type":"string","const":"camera"}]},"ShakeStrength":{"type":"string","enum":["light","strong"]},"CreateField":{"description":"What a character-creation screen asks for (docs/game_systems_spec.md, \"Making your\ncharacter\"): the value's type decides how — a text is typed in, a state is chosen among its\nstates, a yes/no is a switch, a number is rolled (`roll`) or chosen between its `min` and\n`max`.","type":"object","properties":{"id":{"type":"string"},"valueId":{"type":"string"},"label":{"description":"The field's label (none: the value's name).","type":["string","null"]},"roll":{"description":"A number value: rolled when the screen opens (`1d6 + 6`).","type":["string","null"]}},"required":["id","valueId"]},"CreatePoints":{"description":"Points spread on a character-creation screen: each raise adds `step` to the value for `cost`\npoints, up to `max`.","type":"object","properties":{"amount":{"type":"integer","format":"uint32","minimum":0},"raise":{"type":"array","items":{"$ref":"#/$defs/RaisableValue"},"default":[]}},"required":["amount"]},"RaisableValue":{"description":"A value stat points raise.","type":"object","properties":{"valueId":{"description":"A character number value (Strength, Max HP).","type":"string"},"step":{"description":"Added to the base value per raise.","type":"number","format":"double"},"cost":{"description":"Stat points per raise.","type":"integer","format":"uint32","minimum":0,"default":1},"max":{"description":"The highest base value reachable by raising.","type":["number","null"],"format":"double","default":null}},"required":["valueId","step"]},"Next":{"description":"What happens after a passage's steps. Read by a hand-written reader (`tagged.rs`).","oneOf":[{"description":"One way on.","type":"object","properties":{"exit":{"$ref":"#/$defs/Exit"},"type":{"type":"string","const":"continue"}},"required":["type","exit"]},{"type":"object","properties":{"exits":{"type":"array","items":{"$ref":"#/$defs/Exit"}},"timeLimitMs":{"type":["integer","null"],"format":"uint32","minimum":0},"onTimeout":{"type":["string","null"]},"type":{"type":"string","const":"choices"}},"required":["type","exits"]},{"description":"Decided by the game.","type":"object","properties":{"cases":{"type":"array","items":{"$ref":"#/$defs/BranchCase"}},"otherwise":{"$ref":"#/$defs/Exit"},"type":{"type":"string","const":"branch"}},"required":["type","cases","otherwise"]}]},"Exit":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":["string","null"]},"onlyIf":{"type":["string","null"]},"ifUnavailable":{"$ref":"#/$defs/IfUnavailable","default":"hide"},"once":{"type":"boolean","default":false},"use":{"type":["string","null"]},"hotspot":{"anyOf":[{"$ref":"#/$defs/Hotspot"},{"type":"null"}]},"fallback":{"description":"Offered only when no other option of the choice is available (never stuck).","type":"boolean"},"unavailableText":{"description":"The creator's reason, shown under a greyed option in place of what it needs.","type":["string","null"]},"effects":{"type":"array","items":{"$ref":"#/$defs/Effect"},"default":[]},"to":{"$ref":"#/$defs/Target"},"sound":{"description":"The way's sound as it is taken (L-57): an audio asset, `way:<name>` (one that comes with\nTalebench), `chip:<name>`, `auto` or `none`; unset is `auto`, which plays only when the\nlook's `sounds.ways` is on. Only the player reads it.","type":["string","null"]},"screen":{"description":"Screen effects on the way (L-152): a shake or a flash as the exit is taken, a tint, filter,\nweather or look from the next passage on; never `camera`.","type":"array","items":{"$ref":"#/$defs/ExitScreen"}}},"required":["id","to"]},"IfUnavailable":{"type":"string","enum":["hide","disable"]},"Hotspot":{"type":"object","properties":{"x":{"type":"number","format":"double"},"y":{"type":"number","format":"double"},"w":{"type":"number","format":"double"},"h":{"type":"number","format":"double"},"door":{"description":"A door: the way's `auto` sound is a door opening (L-57).","type":"boolean"},"cursor":{"description":"The hotspot's own cursor (P6-16: a keyhole, a ladder), over the set's.","anyOf":[{"$ref":"#/$defs/CursorLook"},{"type":"null"}]},"does":{"description":"Which of the set's hotspot cursors it shows (P6-16; none: from its target).","anyOf":[{"$ref":"#/$defs/HotspotDoes"},{"type":"null"}]}},"required":["x","y","w","h"]},"HotspotDoes":{"description":"What a hotspot does: which of the set's hotspot cursors it shows (none: `go` for a door or a\nway to another passage, else `choose`).","type":"string","enum":["look","talk","take","use","go"]},"Target":{"description":"Read by a hand-written reader (`tagged.rs`) that keeps the player's engine small.","oneOf":[{"type":"object","properties":{"passageId":{"type":"string"},"type":{"type":"string","const":"passage"}},"required":["type","passageId"]},{"description":"Go there; `back` returns here.","type":"object","properties":{"passageId":{"type":"string"},"type":{"type":"string","const":"visit"}},"required":["type","passageId"]},{"description":"Resume the visiting passage at its `next`.","type":"object","properties":{"type":{"type":"string","const":"back"}},"required":["type"]},{"description":"Choices only: reply, then choose again (or, with `choices`, these options: a level\ndeeper, L-20).","type":"object","properties":{"reply":{"type":"array","items":{"$ref":"#/$defs/Step"}},"choices":{"type":["array","null"],"items":{"$ref":"#/$defs/Exit"}},"type":{"type":"string","const":"stay"}},"required":["type","reply"]},{"description":"Inside a reply's options only (L-20): the reply, then the options one level up\n(`previous`, the default) or the passage's own options (`passage`).","type":"object","properties":{"reply":{"type":"array","items":{"$ref":"#/$defs/Step"}},"to":{"anyOf":[{"$ref":"#/$defs/UpTo"},{"type":"null"}]},"type":{"type":"string","const":"up"}},"required":["type"]},{"type":"object","properties":{"options":{"type":"array","items":{"$ref":"#/$defs/RandomOption"}},"otherwise":{"$ref":"#/$defs/Exit"},"type":{"type":"string","const":"random"}},"required":["type","options","otherwise"]},{"type":"object","properties":{"check":{"$ref":"#/$defs/Check"},"success":{"$ref":"#/$defs/Exit"},"failure":{"$ref":"#/$defs/Exit"},"type":{"type":"string","const":"check"}},"required":["type","check","success","failure"]},{"type":"object","properties":{"encounterId":{"type":"string"},"win":{"$ref":"#/$defs/Exit"},"lose":{"$ref":"#/$defs/Exit"},"flee":{"anyOf":[{"$ref":"#/$defs/Exit"},{"type":"null"}]},"spared":{"description":"No foe fights on and one surrendered (L-96; none: `win`).","anyOf":[{"$ref":"#/$defs/Exit"},{"type":"null"}]},"joined":{"description":"No foe fights on and one joined the party (L-96; none: `win`).","anyOf":[{"$ref":"#/$defs/Exit"},{"type":"null"}]},"fledFoes":{"description":"No foe fights on and the last of them fled (L-96; none: `win`).","anyOf":[{"$ref":"#/$defs/Exit"},{"type":"null"}]},"type":{"type":"string","const":"battle"}},"required":["type","encounterId","win","lose"]},{"type":"object","properties":{"endingId":{"type":"string"},"type":{"type":"string","const":"ending"}},"required":["type","endingId"]},{"description":"Decks (L-29): draw a card and visit its passage (`visit: false`: go to it); `otherwise` when no card fits. `offer`\n(an option only): up to that many fitting cards as options of their own.","type":"object","properties":{"deckId":{"type":"string"},"otherwise":{"$ref":"#/$defs/Exit"},"offer":{"type":["integer","null"],"format":"uint32","minimum":0},"visit":{"description":"`false`: the card's passage is gone to, not visited (nothing on the return stack);\nwritten only when `false`.","type":"boolean","x-default":true},"type":{"type":"string","const":"deck"}},"required":["type","deckId","otherwise"]},{"description":"Maps: pick a place on the map; `cancel` is taken by *Stay here*.","type":"object","properties":{"mapId":{"type":"string"},"cancel":{"anyOf":[{"$ref":"#/$defs/Exit"},{"type":"null"}]},"type":{"type":"string","const":"travel"}},"required":["type","mapId"]}]},"UpTo":{"description":"Where *Reply and go back* returns to (L-20).","oneOf":[{"description":"The options one level up.","type":"string","const":"previous"},{"description":"The passage's own options.","type":"string","const":"passage"}]},"RandomOption":{"type":"object","properties":{"passageId":{"type":"string"},"weight":{"type":"number","format":"double"},"onlyIf":{"type":["string","null"]}},"required":["passageId","weight"]},"Check":{"type":"object","properties":{"label":{"description":"\"Climb the wall\"","type":"string"},"dice":{"description":"Six-sided dice, 0–3.","type":"integer","format":"uint8","minimum":0,"maximum":255},"plus":{"type":"string"},"target":{"type":"string"}},"required":["label","dice","plus","target"]},"ExitScreen":{"description":"A screen effect on the way (L-152): the `screen` step's fields but the camera's.","type":"object","properties":{"effect":{"$ref":"#/$defs/ScreenEffectKind"},"strength":{"anyOf":[{"$ref":"#/$defs/ShakeStrength"},{"type":"null"}]},"color":{"description":"`#rrggbb`: the flash's (default white) and the tint's colour.","type":["string","null"]},"amount":{"description":"The tint: 0–1, how strongly (0 clears it).","type":["number","null"],"format":"double"},"weather":{"anyOf":[{"$ref":"#/$defs/Weather"},{"type":"null"}]},"filter":{"anyOf":[{"$ref":"#/$defs/ScreenFilter"},{"type":"null"}]},"variant":{"description":"`look`: the look variant from here on.","type":["string","null"]},"durationMs":{"description":"A shake's or flash's time: 100–3000 ms (default 500).","type":["integer","null"],"format":"uint32","minimum":0}},"required":["effect"]},"BranchCase":{"type":"object","properties":{"when":{"type":"string"},"exit":{"$ref":"#/$defs/Exit"}},"required":["when","exit"]},"SceneLayout":{"type":"object","properties":{"background":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"music":{"type":["string","null"]},"ambience":{"type":["string","null"]},"sprites":{"type":"array","items":{"$ref":"#/$defs/Sprite"},"default":[]},"wrongThing":{"description":"Reply when a thing is used where no exit accepts it.","type":["array","null"],"items":{"$ref":"#/$defs/Step"}},"transition":{"description":"How this scene's picture comes in (none: the look's `motion.pictures`).","anyOf":[{"$ref":"#/$defs/PassageChange"},{"type":"null"}]},"variants":{"description":"The picture by time of day, season or weather (P6-09): the most specific that holds.","type":"array","items":{"$ref":"#/$defs/PictureVariant"}},"musicVariants":{"description":"The music by time of day, season or weather.","type":"array","items":{"$ref":"#/$defs/SoundVariant"}},"ambienceVariants":{"description":"The ambience by time of day, season or weather.","type":"array","items":{"$ref":"#/$defs/SoundVariant"}}}},"Sprite":{"type":"object","properties":{"id":{"type":"string"},"assetId":{"type":"string"},"frame":{"type":["integer","null"],"format":"uint32","minimum":0},"x":{"type":"number","format":"double"},"y":{"type":"number","format":"double"},"w":{"type":"number","format":"double"},"h":{"type":"number","format":"double"},"layer":{"type":"integer","format":"int32"},"visibleWhen":{"type":["string","null"]},"animation":{"anyOf":[{"$ref":"#/$defs/Animation"},{"type":"null"}]}},"required":["id","assetId","x","y","w","h","layer"]},"Animation":{"type":"object","properties":{"frames":{"type":"array","items":{"type":"integer","format":"uint32","minimum":0}},"fps":{"type":"number","format":"double"},"loop":{"type":"boolean"}},"required":["frames","fps","loop"]},"SoundVariant":{"description":"Music or ambience for a time of day, a season or a weather.","type":"object","properties":{"part":{"type":["string","null"]},"season":{"type":["string","null"]},"weather":{"type":["string","null"]},"assetId":{"type":"string"}},"required":["assetId"]},"Dungeon":{"type":"object","properties":{"floors":{"type":"array","items":{"$ref":"#/$defs/DungeonFloor"}},"start":{"$ref":"#/$defs/DungeonPlace"},"move":{"anyOf":[{"$ref":"#/$defs/DungeonMove"},{"type":"null"}]},"view":{"anyOf":[{"$ref":"#/$defs/DungeonViewKind"},{"type":"null"}]},"automap":{"anyOf":[{"$ref":"#/$defs/Automap"},{"type":"null"}]},"screen":{"description":"Seen from inside: its screen (L-178; none: the crawler's).","anyOf":[{"$ref":"#/$defs/DungeonScreen"},{"type":"null"}]},"tiles":{"description":"Seen from inside: its walls, floor and ceiling made from this recipe (L-179; none: the\nlook's own set).","anyOf":[{"$ref":"#/$defs/TileRecipe"},{"type":"null"}]},"look":{"description":"A built-in set (`stone`, `cave`, `crypt`, `wood`, `ship`, `station`, `pixel`; none: stone).","type":["string","null"]},"sounds":{"description":"Its own sounds for a step, a turn, a door passed and a shut door tried (L-169).","anyOf":[{"$ref":"#/$defs/DungeonSounds"},{"type":"null"}]},"roamers":{"description":"Foes that walk the dungeon (L-170).","type":"array","items":{"$ref":"#/$defs/Roamer"}},"regions":{"type":"array","items":{"$ref":"#/$defs/DungeonRegion"}},"stepEffects":{"description":"Run on every step (a torch burns down).","type":"array","items":{"$ref":"#/$defs/Effect"}},"encounterAreaId":{"type":["string","null"]},"music":{"type":["string","null"]},"ambience":{"type":["string","null"]}},"required":["floors","start"]},"DungeonFloor":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"width":{"description":"At most 64.","type":"integer","format":"uint32","minimum":0},"height":{"description":"At most 64.","type":"integer","format":"uint32","minimum":0},"cells":{"description":"The open cells; everything else is rock.","type":"array","items":{"$ref":"#/$defs/DungeonCell"},"default":[]},"edges":{"description":"What stands between two open cells (none: open).","type":"array","items":{"$ref":"#/$defs/DungeonEdge"}},"mapWhen":{"description":"While it holds the whole floor shows on the map, seen or not: a found map (L-168).","type":["string","null"]}},"required":["id","name","width","height"]},"DungeonCell":{"type":"object","properties":{"x":{"type":"integer","format":"uint32","minimum":0},"y":{"type":"integer","format":"uint32","minimum":0},"regionId":{"type":["string","null"]},"text":{"description":"Its own words (none: the region's, else words the player makes from what is there).","type":["string","null"]},"picture":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"feature":{"anyOf":[{"$ref":"#/$defs/CellFeature"},{"type":"null"}]},"looks":{"description":"What its feature looks like in the view from inside (L-181): a lever, a bell, a desk …;\nnone: the feature's own picture.","anyOf":[{"$ref":"#/$defs/FeatureLook"},{"type":"null"}]}},"required":["x","y"]},"CellFeature":{"description":"What a cell holds. Read by a hand-written reader (`tagged.rs`, L-160).","oneOf":[{"description":"Out into the story.","type":"object","properties":{"exit":{"$ref":"#/$defs/Exit"},"type":{"type":"string","const":"exit"}},"required":["type","exit"]},{"description":"A passage played, then back on this cell (`auto`: on stepping in; else an option).","type":"object","properties":{"passageId":{"type":"string"},"once":{"type":"boolean"},"auto":{"type":"boolean"},"type":{"type":"string","const":"visit"}},"required":["type","passageId"]},{"type":"object","properties":{"floorId":{"type":"string"},"x":{"type":"integer","format":"uint32","minimum":0},"y":{"type":"integer","format":"uint32","minimum":0},"type":{"type":"string","const":"stairs"}},"required":["type","floorId","x","y"]},{"description":"Opened once, stays open.","type":"object","properties":{"things":{"type":"array","items":{"$ref":"#/$defs/ThingQty"}},"effects":{"type":"array","items":{"$ref":"#/$defs/Effect"}},"type":{"type":"string","const":"chest"}},"required":["type"]},{"description":"Fought once on stepping in; won, the cell is clear.","type":"object","properties":{"encounterId":{"type":"string"},"lose":{"anyOf":[{"$ref":"#/$defs/Exit"},{"type":"null"}]},"type":{"type":"string","const":"battle"}},"required":["type","encounterId"]},{"description":"Flips a yes/no value (gates read it). L-167: `auto`, a plate pressed (yes) as the party steps\non it, no option; `hold`, back to no as the party steps off.","type":"object","properties":{"valueId":{"type":"string"},"auto":{"type":"boolean"},"hold":{"type":"boolean"},"type":{"type":"string","const":"lever"}},"required":["type","valueId"]},{"description":"L-158: changes on stepping in, a check may avoid them.","type":"object","properties":{"effects":{"type":"array","items":{"$ref":"#/$defs/Effect"}},"check":{"description":"A check the party rolls as it steps in: success avoids it (L-158).","anyOf":[{"$ref":"#/$defs/Check"},{"type":"null"}]},"hidden":{"description":"Not on the map until sprung.","type":"boolean"},"type":{"type":"string","const":"trap"}},"required":["type","effects"]},{"description":"L-158; L-166: it may turn the party (a spinner: a teleport to its own cell), run changes on\narriving (a pit), ask a check that, passed, keeps the party where it stood, and be hidden\nuntil used.","type":"object","properties":{"floorId":{"type":"string"},"x":{"type":"integer","format":"uint32","minimum":0},"y":{"type":"integer","format":"uint32","minimum":0},"turn":{"anyOf":[{"$ref":"#/$defs/TurnTo"},{"type":"null"}]},"effects":{"type":"array","items":{"$ref":"#/$defs/Effect"}},"check":{"anyOf":[{"$ref":"#/$defs/Check"},{"type":"null"}]},"hidden":{"type":"boolean"},"type":{"type":"string","const":"teleport"}},"required":["type","floorId","x","y"]},{"type":"object","properties":{"type":{"type":"string","const":"save"}},"required":["type"]},{"type":"object","properties":{"type":{"type":"string","const":"camp"}},"required":["type"]},{"description":"L-158: shows nothing and offers no way on until `seeWhen` holds.","type":"object","properties":{"seeWhen":{"type":"string"},"type":{"type":"string","const":"dark"}},"required":["type","seeWhen"]}]},"TurnTo":{"description":"Where a teleport leaves the party facing (L-166): a direction, or a turn from the way it faced.","type":"string","enum":["n","e","s","w","left","right","around"]},"FeatureLook":{"description":"The pictures a cell's feature may look like from inside (L-181), each drawn in pixel art.","type":"string","enum":["lever","bell","desk","statue","fountain","altar","bones","barrel","books","sign","well","brazier","crates","gears"]},"DungeonEdge":{"type":"object","properties":{"x":{"type":"integer","format":"uint32","minimum":0},"y":{"type":"integer","format":"uint32","minimum":0},"side":{"$ref":"#/$defs/Dir"},"kind":{"$ref":"#/$defs/WallKind"},"key":{"type":["string","null"]},"openWhen":{"type":["string","null"]},"findWhen":{"description":"secret: found, and a door from then on, once this holds (carrying the lantern, a value a\nsearch set; L-158); none: never found","type":["string","null"]},"switch":{"description":"A switch set into this wall on the side of this edge's own cell (L-188): pressed from that\ncell, it sets its yes/no value, which the gates it opens read (`openWhen`).","anyOf":[{"$ref":"#/$defs/WallSwitch"},{"type":"null"}]}},"required":["x","y","side","kind"]},"Dir":{"description":"A side of a cell, as the compass names it: north is up on the map.","type":"string","enum":["n","e","s","w"]},"WallKind":{"description":"What stands on a side of a cell (and so between it and its neighbour).","oneOf":[{"type":"string","enum":["wall","door"]},{"description":"A door that needs `key` carried; once passed it stays open.","type":"string","const":"locked"},{"description":"A wall until found (L-158).","type":"string","const":"secret"},{"description":"Passable only from this cell's side.","type":"string","const":"one_way"},{"description":"Open while `openWhen` holds (a lever's value).","type":"string","const":"gate"}]},"WallSwitch":{"description":"A switch in a wall (L-188): what pressing it does to its yes/no value.","type":"object","properties":{"valueId":{"type":"string"},"mode":{"$ref":"#/$defs/SwitchMode"},"once":{"description":"Pressed once only: then it stays as it is.","type":"boolean"}},"required":["valueId"]},"SwitchMode":{"description":"`toggle`: yes becomes no and no yes; `on` and `off` set it so.","type":"string","enum":["toggle","on","off"]},"DungeonPlace":{"description":"A cell of a floor, and (where it matters) the way the party faces.","type":"object","properties":{"floorId":{"type":"string"},"x":{"type":"integer","format":"uint32","minimum":0},"y":{"type":"integer","format":"uint32","minimum":0},"facing":{"anyOf":[{"$ref":"#/$defs/Dir"},{"type":"null"}]}},"required":["floorId","x","y"]},"DungeonMove":{"description":"How the party moves (none: by the compass).","type":"string","enum":["compass","facing"]},"DungeonViewKind":{"description":"How the player shows it (none: the map from above).","type":"string","enum":["map","inside","text"]},"Automap":{"description":"What of the map shows (none: the cells seen).","type":"string","enum":["explored","all","none"]},"DungeonScreen":{"description":"The screen of a dungeon seen from inside (L-178): a crawler's (the view, the party beside it,\na six-way pad with a compass, a message line) or the story's (the view above the words and\noptions).","type":"string","enum":["crawler","story"]},"TileRecipe":{"description":"Made tiles (L-179): the walls, floor, ceiling and doors of a dungeon seen from inside, made by\nthe player from this recipe (the same pixels for the same recipe everywhere).","type":"object","properties":{"material":{"$ref":"#/$defs/TileMaterial"},"colours":{"$ref":"#/$defs/TileColours"},"size":{"description":"How large its blocks are, 1 (small) to 4 (large); none: 2.","type":["integer","null"],"format":"uint8","minimum":0,"maximum":255},"wear":{"anyOf":[{"$ref":"#/$defs/TileWear"},{"type":"null"}]},"light":{"anyOf":[{"$ref":"#/$defs/TileLight"},{"type":"null"}]},"pixel":{"description":"Drawn as coarse pixels (a pixel-art look).","type":"boolean"},"seed":{"type":["integer","null"],"format":"uint32","minimum":0},"pictures":{"description":"The writer's own pictures per tile kind (L-179): each given one is drawn in place of the\nmade tile, in perspective and light like it.","anyOf":[{"$ref":"#/$defs/TilePictures"},{"type":"null"}]},"floor":{"description":"The floor its own way (L-189; none: as the walls' material goes, planks on planks …).","anyOf":[{"$ref":"#/$defs/TileSurface"},{"type":"null"}]},"ceiling":{"description":"The ceiling its own way (L-189; none: as the walls' material goes).","anyOf":[{"$ref":"#/$defs/TileSurface"},{"type":"null"}]}},"required":["material","colours"]},"TileMaterial":{"type":"string","enum":["stone","bricks","cave","planks","metal","hedge","ice","crystal","bone"]},"TileColours":{"description":"The base colour and the accent (mortar, grain, rivets …), `#rrggbb`.","type":"object","properties":{"base":{"type":"string"},"accent":{"type":"string"}},"required":["base","accent"]},"TileWear":{"description":"How worn, each 0–3.","type":"object","properties":{"cracks":{"type":["integer","null"],"format":"uint8","minimum":0,"maximum":255},"moss":{"type":["integer","null"],"format":"uint8","minimum":0,"maximum":255},"damp":{"type":["integer","null"],"format":"uint8","minimum":0,"maximum":255},"soot":{"type":["integer","null"],"format":"uint8","minimum":0,"maximum":255}}},"TileLight":{"type":"string","enum":["torch","cold","none"]},"TilePictures":{"description":"The writer's own pictures of a dungeon's walls, floor, ceiling and doors (L-179).","type":"object","properties":{"wall":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"floor":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"ceiling":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"door":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]}}},"TileSurface":{"description":"A floor or a ceiling made apart from the walls (L-189): its own material, and its own colours\n(none: the recipe's); the wear and the light stay the recipe's.","type":"object","properties":{"material":{"$ref":"#/$defs/TileMaterial"},"colours":{"anyOf":[{"$ref":"#/$defs/TileColours"},{"type":"null"}]}},"required":["material"]},"DungeonSounds":{"description":"A dungeon's own sounds (L-169), played as the interface sounds are.","type":"object","properties":{"step":{"type":["string","null"]},"turn":{"type":["string","null"]},"door":{"description":"A door passed (opened).","type":["string","null"]},"locked":{"description":"A way tried where a door is shut (locked, or a gate closed).","type":["string","null"]}}},"Roamer":{"description":"A group of foes that walks a floor (L-170): along its round, or towards the party once it saw it.","type":"object","properties":{"id":{"description":"`rom_…`","type":"string"},"name":{"type":"string"},"encounterId":{"description":"The battle when it meets the party.","type":"string"},"floorId":{"type":"string"},"x":{"type":"integer","format":"uint32","minimum":0},"y":{"type":"integer","format":"uint32","minimum":0},"round":{"description":"The cells it walks in turn, one per step of the party, the first where it stands, then back\nto the first; none: it stands.","type":"array","items":{"$ref":"#/$defs/CellAt"}},"chase":{"description":"Once it sees the party it walks towards it instead.","type":"boolean"},"sight":{"description":"How far it sees along an open row or column (none: 3 cells).","type":["integer","null"],"format":"uint32","minimum":0},"onlyIf":{"description":"Walks the floor only while this holds.","type":["string","null"]},"lose":{"description":"A battle lost: where it leads (none: back on the cell).","anyOf":[{"$ref":"#/$defs/Exit"},{"type":"null"}]},"picture":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]}},"required":["id","name","encounterId","floorId","x","y"]},"CellAt":{"description":"A cell of a floor, by its place.","type":"object","properties":{"x":{"type":"integer","format":"uint32","minimum":0},"y":{"type":"integer","format":"uint32","minimum":0}},"required":["x","y"]},"DungeonRegion":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"color":{"type":["string","null"]},"text":{"type":["string","null"]},"picture":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"music":{"type":["string","null"]},"encounterAreaId":{"type":["string","null"]},"room":{"description":"Its cells are one room, played as one place (L-172).","type":"boolean"},"tiles":{"description":"Its own made tiles (L-179: a mossy grotto in a cave).","anyOf":[{"$ref":"#/$defs/TileRecipe"},{"type":"null"}]}},"required":["id","name"]},"RunMap":{"description":"The recipe a passage's run map is made from.","type":"object","properties":{"rows":{"description":"Rows of places (2–15), the goal above the last.","type":"integer","format":"uint32","minimum":0},"perRow":{"description":"Places per row, min–max (1–6).","type":"array","items":{"type":"integer","format":"uint32","minimum":0},"minItems":2,"maxItems":2},"links":{"description":"How many places of the next row a place leads to, at most (1–3).","type":"integer","format":"uint32","minimum":0},"kinds":{"type":"array","items":{"$ref":"#/$defs/RunPlaceKind"}},"goal":{"description":"After the last row: the boss, a passage, an ending.","$ref":"#/$defs/Exit"}},"required":["rows","perRow","links","kinds","goal"]},"RunPlaceKind":{"description":"A kind of place: its name and icon on the map, how often it comes, where, what it does.","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"icon":{"$ref":"#/$defs/RunIcon"},"weight":{"type":"number","format":"double"},"rows":{"description":"The rows it may stand in, 1-based (none: all).","type":["array","null"],"items":{"type":"integer","format":"uint32","minimum":0},"minItems":2,"maxItems":2},"exit":{"$ref":"#/$defs/Exit"}},"required":["id","name","icon","weight","exit"]},"RunIcon":{"type":"string","enum":["fight","elite","shop","rest","event","treasure","boss"]},"Deck":{"description":"Storylets (L-29, docs/game_systems_spec.md, \"Decks\"): cards the game draws by the state.","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"draw":{"description":"How a card is drawn: the best fit (default) or by chance.","$ref":"#/$defs/DeckDraw","default":"best"},"notTwice":{"description":"By chance: the card drawn last is never drawn next.","type":"boolean"},"cards":{"type":"array","items":{"$ref":"#/$defs/Card"},"default":[]}},"required":["id","name"]},"DeckDraw":{"oneOf":[{"description":"The fitting card with the highest priority (the first of equals).","type":"string","const":"best"},{"description":"One fitting card by weight, from the game's seed.","type":"string","const":"chance"}]},"Card":{"description":"A card of a deck: a passage and when it fits.","type":"object","properties":{"id":{"type":"string"},"passageId":{"type":"string"},"onlyIf":{"type":["string","null"]},"priority":{"description":"The best fit: the highest first (default 0).","type":["number","null"],"format":"double"},"weight":{"description":"By chance: how likely among the fitting cards (default 1).","type":["number","null"],"format":"double"},"repeatable":{"description":"Drawn again and again; else used up once drawn.","type":"boolean"},"label":{"description":"Its option's text where the deck is offered as options (a player text).","type":["string","null"]}},"required":["id","passageId"]},"Ending":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"$ref":"#/$defs/EndingKind"},"image":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"text":{"type":["string","null"]},"recap":{"description":"A recap under the ending: play time, endings found of all, achievements, these values.","anyOf":[{"$ref":"#/$defs/EndingRecap"},{"type":"null"}]},"credits":{"description":"Rolls the project's credits (`settings.credits`) after the ending.","type":"boolean"}},"required":["id","name","kind"]},"EndingKind":{"type":"string","enum":["good","neutral","bad","defeat"]},"EndingRecap":{"description":"What an ending's recap lists besides play time, endings and achievements.","type":"object","properties":{"valueIds":{"description":"Game values shown with what they ended at, in this order.","type":"array","items":{"type":"string"},"default":[]}}},"Character":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string"},"name":{"type":"string"},"listName":{"description":"The name in the creator's lists only (\"Dura as a child\" for a \"Dura\", P6-04); none: the name.\nThe engine, the player and the book never read it.","type":["string","null"]},"description":{"type":["string","null"]},"nameFromValueId":{"description":"A game-scope text value, e.g. the name the player typed.","type":["string","null"]},"portrait":{"description":"The default expression.","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"portraitFromValueId":{"description":"A state value whose current state's picture is the portrait instead (the look the player\nchose, L-32); a state without a picture keeps `portrait`.","type":["string","null"]},"portraitFrame":{"description":"The part of the character's picture a dialogue shows as their portrait (P4-23); none: the\nhead and shoulders of a standing figure.","anyOf":[{"$ref":"#/$defs/PortraitFrame"},{"type":"null"}]},"expressions":{"type":"array","items":{"$ref":"#/$defs/Expression"},"default":[]},"outfits":{"description":"Layered pictures: the body and clothes, the expression drawn on top; the first is worn at\nthe start.","type":"array","items":{"$ref":"#/$defs/Outfit"}},"talk":{"description":"Talk sounds: how its lines sound while they appear.","anyOf":[{"$ref":"#/$defs/TalkVoice"},{"type":"null"}]},"cry":{"description":"In battle: its cry when a hard blow strikes it (P8-80; none: the action look's pain sound).","type":["string","null"]},"nameColor":{"description":"The colour of its name on its lines (`#rrggbb`).","type":["string","null"]},"sprite":{"type":["string","null"]},"battleSprite":{"type":["string","null"]},"battlePoses":{"description":"Its figure in battle with poses (L-66; none: `battle_sprite` as it is).","anyOf":[{"$ref":"#/$defs/BattlePoses"},{"type":"null"}]},"values":{"description":"Starting values by value ID.","type":"object","additionalProperties":{"$ref":"#/$defs/Scalar"},"default":{}},"classId":{"type":["string","null"]},"startLevel":{"type":"integer","format":"uint32","minimum":0},"skills":{"type":"array","items":{"type":"string"},"default":[]},"equipment":{"description":"Slot ID → thing ID.","type":"object","additionalProperties":{"type":"string"},"default":{}},"combat":{"description":"Can be fought, e.g. a boss the player also talks to.","anyOf":[{"$ref":"#/$defs/CombatProfile"},{"type":"null"}]},"fightsInBattle":{"description":"Default true; false: travels with the party, sits out battles (a pack animal, a child).","type":["boolean","null"],"x-default":true},"mount":{"description":"Can be ridden: a horse, a donkey, a boat, a dragon.","anyOf":[{"$ref":"#/$defs/Mount"},{"type":"null"}]},"defeat":{"description":"How it falls in battle (none: the battle look's).","anyOf":[{"$ref":"#/$defs/DefeatLook"},{"type":"null"}]},"row":{"description":"Its starting row in battle while the battle rules have rows (L-69; none: front).","anyOf":[{"$ref":"#/$defs/Row"},{"type":"null"}]}},"required":["id","key","name","startLevel"]},"PortraitFrame":{"description":"A part of a picture as shares (0–1) of its width and height: what a dialogue shows as the\nspeaker's portrait (P4-23).","type":"object","properties":{"x":{"description":"The left edge, from 0 (the picture's left) to 1.","type":"number","format":"double"},"y":{"description":"The top edge, from 0 (the picture's top) to 1.","type":"number","format":"double"},"w":{"description":"The width, a share of the picture's width (above 0, at most 1).","type":"number","format":"double"},"h":{"description":"The height, a share of the picture's height (above 0, at most 1).","type":"number","format":"double"}},"required":["x","y","w","h"]},"Expression":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"image":{"$ref":"#/$defs/ImageRef"},"talk":{"description":"Talk sounds: how the voice changes in this expression.","anyOf":[{"$ref":"#/$defs/TalkMood"},{"type":"null"}]},"blink":{"description":"The same picture with the eyes closed: the figure blinks now and then (L-46).","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"mouth":{"description":"The same picture with the mouth open: it moves while the figure speaks.","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"portraitFrame":{"description":"This expression's own portrait frame (none: the character's).","anyOf":[{"$ref":"#/$defs/PortraitFrame"},{"type":"null"}]}},"required":["id","name","image"]},"TalkMood":{"description":"An expression's change to the speaker's voice.","type":"object","properties":{"pitch":{"description":"Semitones added: −12 to 12.","type":"number","format":"double"},"speed":{"description":"Factor: 0.5 to 2.","type":"number","format":"double"},"variance":{"description":"Semitones added to the variance: −6 to 6.","type":"number","format":"double"},"volume":{"description":"Factor: 0.5 to 1.5.","type":"number","format":"double"}},"required":["pitch","speed","variance","volume"]},"Outfit":{"description":"An outfit of a character with layered pictures.","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"image":{"$ref":"#/$defs/ImageRef"}},"required":["id","name","image"]},"BattlePoses":{"description":"A figure in battle with poses (L-66): one row of frames `frame_width` pixels wide, each pose\na run of them. Presentation only: the engine never reads it.","type":"object","properties":{"sheet":{"type":"string"},"frameWidth":{"type":"integer","format":"uint32","minimum":0},"faces":{"description":"The way the figure looks as drawn (none: party left, foes right).","anyOf":[{"$ref":"#/$defs/Facing"},{"type":"null"}]},"poses":{"$ref":"#/$defs/PoseSet","default":{}}},"required":["sheet","frameWidth"]},"Facing":{"type":"string","enum":["left","right"]},"PoseSet":{"description":"Each pose's frames; a missing pose falls back to `idle`, `idle` to the sheet's first frame.","type":"object","properties":{"idle":{"anyOf":[{"$ref":"#/$defs/Pose"},{"type":"null"}]},"ready":{"anyOf":[{"$ref":"#/$defs/Pose"},{"type":"null"}]},"attack":{"anyOf":[{"$ref":"#/$defs/Pose"},{"type":"null"}]},"cast":{"anyOf":[{"$ref":"#/$defs/Pose"},{"type":"null"}]},"item":{"anyOf":[{"$ref":"#/$defs/Pose"},{"type":"null"}]},"hit":{"anyOf":[{"$ref":"#/$defs/Pose"},{"type":"null"}]},"guard":{"anyOf":[{"$ref":"#/$defs/Pose"},{"type":"null"}]},"weak":{"anyOf":[{"$ref":"#/$defs/Pose"},{"type":"null"}]},"victory":{"anyOf":[{"$ref":"#/$defs/Pose"},{"type":"null"}]},"defeated":{"anyOf":[{"$ref":"#/$defs/Pose"},{"type":"null"}]}}},"Pose":{"description":"One pose: frame numbers from 0 in playing order, at `fps`, looping or holding the last.","type":"object","properties":{"frames":{"type":"array","items":{"type":"integer","format":"uint32","minimum":0}},"fps":{"type":"integer","format":"uint32","minimum":0},"loop":{"type":"boolean","default":false}},"required":["frames","fps"]},"CombatProfile":{"type":"object","properties":{"skills":{"type":"array","items":{"type":"string"},"default":[]},"ai":{"type":"array","items":{"$ref":"#/$defs/AiRule"},"default":[]},"weaknesses":{"description":"Damage type ID → multiplier.","type":"object","additionalProperties":{"type":"number","format":"double"},"default":{}},"immunities":{"description":"Status IDs never applied, and/or `defeat`.","type":"array","items":{"type":"string"},"default":[]},"statuses":{"description":"Statuses held from the start of every battle (\"Undead\").","type":"array","items":{"type":"string"},"default":[]},"rewards":{"$ref":"#/$defs/Rewards"},"carries":{"description":"What can be stolen from it (L-70): one draw of the loot table's entries on a success.","anyOf":[{"$ref":"#/$defs/Carries"},{"type":"null"}]},"morale":{"description":"A morale bar beside its defeat bar (L-96): at or below `yields_at` it gives in. Read for a\nfoe only (an enemy, or a character fought as a foe).","anyOf":[{"$ref":"#/$defs/Morale"},{"type":"null"}]},"zones":{"description":"Hit zones (L-104): its top, middle and bottom in a dice battle with `zones`.","anyOf":[{"$ref":"#/$defs/Zones"},{"type":"null"}]},"gear":{"description":"Weapons and shields (L-106): things it fights with as if worn (their `wear.dice` and\n`wear.shield`). Read for an enemy; a character wears its own.","type":"array","items":{"type":"string"}},"secondSet":{"description":"P8-87: the things it swaps to in a dice battle with `swap`, and when.","type":"array","items":{"type":"string"}},"swapWhen":{"anyOf":[{"$ref":"#/$defs/SwapWhen"},{"type":"null"}]},"temper":{"description":"P8-95: how it fights, in one line on its card on the VS screen (\"swings a great axe,\nnever backs down\").","type":["string","null"]},"skill":{"description":"P8-98: how well it plays (none: `master`, as every foe played before).","anyOf":[{"$ref":"#/$defs/FoeSkill"},{"type":"null"}]},"style":{"description":"P8-98: what it plays for (none: `balanced`).","anyOf":[{"$ref":"#/$defs/FoeStyle"},{"type":"null"}]},"diceTells":{"description":"Dice tells (L-108): a line for a high and one for a low throw, shown while its attack's\ndice lie face down (hidden throws). Read for a foe.","anyOf":[{"$ref":"#/$defs/DiceTells"},{"type":"null"}]},"boss":{"description":"A boss (L-108): the win-rate simulator expects its fights to last longer (6–10 exchanges\nrather than 3–6).","type":"boolean"},"defenceCombinations":{"description":"Defence combinations of its own (L-109): replace the battle's `defence.combinations`\nwhen it defends (a slow golem only Brace). Read for a foe, in battles with defence throws.","anyOf":[{"$ref":"#/$defs/DiceCombinations"},{"type":"null"}]}},"required":["rewards"]},"AiRule":{"type":"object","properties":{"id":{"description":"`air_…`: given to a row with a `tell` (L-98), the address of its line's translations.","type":["string","null"]},"when":{"type":"string"},"skillId":{"type":"string"},"target":{"$ref":"#/$defs/AiTarget"},"tell":{"description":"Intents told in words (L-98): a line of story text shown before the round when this row\nchooses the foe's next action (\"The bruiser draws back his club\").","type":["string","null"]}},"required":["when","skillId","target"]},"AiTarget":{"type":"string","enum":["random_foe","weakest_foe","strongest_foe","random_ally","weakest_ally","self"]},"Rewards":{"type":"object","properties":{"xp":{"type":["string","null"]},"effects":{"type":"array","items":{"$ref":"#/$defs/Effect"},"default":[]},"lootTableId":{"type":["string","null"]}}},"Carries":{"description":"What a foe carries for a `steal` effect (L-70).","type":"object","properties":{"lootTableId":{"type":"string"}},"required":["lootTableId"]},"Morale":{"description":"A foe's morale (L-96): its size and when it gives in (both worked out at the battle's start,\n`self` the foe), and what it does then.","type":"object","properties":{"max":{"type":"string"},"yieldsAt":{"type":"string"},"then":{"$ref":"#/$defs/MoraleThen"}},"required":["max","yieldsAt","then"]},"MoraleThen":{"description":"How a foe gives in (L-96): it flees, it surrenders (stays, harmless), or it joins the party (a\ncharacter foe only).","type":"string","enum":["flee","surrender","join"]},"Zones":{"description":"Hit zones (L-104): a fighter's three zones.","type":"object","properties":{"top":{"anyOf":[{"$ref":"#/$defs/ZoneDef"},{"type":"null"}]},"middle":{"anyOf":[{"$ref":"#/$defs/ZoneDef"},{"type":"null"}]},"bottom":{"anyOf":[{"$ref":"#/$defs/ZoneDef"},{"type":"null"}]},"feet":{"description":"L-187: with four zones (top, middle, bottom are then the head, the torso, the legs).","anyOf":[{"$ref":"#/$defs/ZoneDef"},{"type":"null"}]},"hands":{"description":"P8-111: with five zones, the hands.","anyOf":[{"$ref":"#/$defs/ZoneDef"},{"type":"null"}]}}},"ZoneDef":{"description":"Hit zones (L-104): one zone of a fighter.","type":"object","properties":{"armour":{"description":"Added to the fighter's armour on this zone.","type":["string","null"]},"none":{"description":"The zone cannot be hit (a flying foe has no `bottom`): a die aimed here misses.","type":["boolean","null"]},"effect":{"description":"Runs on a hit here (on the fighter hit).","type":"array","items":{"$ref":"#/$defs/Effect"}}}},"SwapWhen":{"description":"When a foe swaps to its second set (P8-87).","oneOf":[{"type":"string","enum":["never"]},{"description":"Its own HP under a third: to the set that guards best.","type":"string","const":"own_hp_low"},{"description":"Its target within two of its blows: to the set that hits hardest.","type":"string","const":"foe_hp_low"},{"description":"Either.","type":"string","const":"both"}]},"FoeSkill":{"description":"How well a foe plays (P8-98; docs/dice_battles_spec.md, \"How well a foe plays\"): at each choice\non the table the best (master), mostly the best (veteran), one of the three best (trained), or\nwith a player's mistakes (novice).","type":"string","enum":["novice","trained","veteran","master"]},"FoeStyle":{"description":"What a foe plays for (P8-98): even, what it deals, what it takes, combinations.","type":"string","enum":["balanced","aggressive","cautious","gambler"]},"DiceTells":{"description":"Dice tells (L-108; docs/game_systems_spec.md, \"Dice battles\", \"Fairer and clearer dice\nbattles\"): a foe's line while its attack lies face down, for a high throw (its sum at least 4\na die) and for a low one (at most 3 a die). Lines are story text (variations, values).","type":"object","properties":{"high":{"type":["string","null"]},"low":{"type":["string","null"]}}},"DiceCombinations":{"description":"The combinations of a dice battle, each with its effects (none: it does not count).","type":"object","properties":{"pair":{"type":["array","null"],"items":{"$ref":"#/$defs/DiceEffect"}},"twoPairs":{"description":"With 4 dice.","type":["array","null"],"items":{"$ref":"#/$defs/DiceEffect"}},"run":{"description":"Every die in a row (1-2-3 … 4-5-6, with 4 dice 1-2-3-4 … 3-4-5-6).","type":["array","null"],"items":{"$ref":"#/$defs/DiceEffect"}},"threeOfAKind":{"type":["array","null"],"items":{"$ref":"#/$defs/DiceEffect"}},"fourOfAKind":{"description":"With 4 dice.","type":["array","null"],"items":{"$ref":"#/$defs/DiceEffect"}},"fullHouse":{"description":"P8-111: with 5 dice, three of one face and two of another.","type":["array","null"],"items":{"$ref":"#/$defs/DiceEffect"}},"fiveOfAKind":{"description":"P8-111: with 5 dice.","type":["array","null"],"items":{"$ref":"#/$defs/DiceEffect"}}}},"DiceEffect":{"description":"What a dice combination does: `{\"type\": \"extraDamage\", \"amount\": 3}`, `{\"type\": \"wound\",\n\"statusId\": \"st_wounded\"}` (a flat struct rather than a tagged enum keeps the player's engine\nsmall).","type":"object","properties":{"type":{"$ref":"#/$defs/DiceEffectKind"},"amount":{"description":"`extraDamage`: added to the sum; `critical`: the extra damage in percent (none: 50; 100\ndoubles); `ignoreArmour`: the Armour ignored (none: 2).","type":["number","null"],"format":"double"},"statusId":{"description":"`wound` and `status`.","type":["string","null"]},"on":{"description":"`status`: on the target (none) or on the thrower.","anyOf":[{"$ref":"#/$defs/DiceOn"},{"type":"null"}]},"color":{"description":"L-107: the combination's own colour (`#rrggbb`) for its glow, line or bracket and name\n(none: its default); the first of a combination's effects that names one counts. Only\nthe player reads it, from the throw's event.","type":["string","null"]},"sound":{"description":"L-107: the combination's own sound (an audio asset, or a chip sound) in place of its\ndefault stinger; the first of a combination's effects that names one counts.","type":["string","null"]},"shake":{"description":"L-190: the combination shakes the battle and rumbles a phone as it shows, harder the rarer\nit is; the first of a combination's effects that says so counts. Only the player reads it.","type":["boolean","null"]}},"required":["type"]},"DiceEffectKind":{"description":"`extraDamage`: added to the sum; `unblockable`: a blocked throw still deals 1; `critical`:\nmore damage (`amount` percent, none: 50, rounded down, at least 1 more); `wound`: a status on the target that lasts (see `StatusEffect.lasts`);\n`status`: a status on the target or the thrower; `extraTurn`: the thrower acts once more.\nL-108: `ignoreArmour`: the throw ignores `amount` (none: 2) of the target's Armour (with hit\nzones, of each zone's); `foeFewerDice`: the target throws one die fewer at its next throw\n(never below one); `keepInitiative`: the thrower acts again before the foe's next turn, once\na round; `breakGuard`: the target's Armour, shield and defence count nothing until the end of\nthe thrower's next turn. Like statuses, these four act when the throw hit.\nL-109, a defence throw's combinations: `brace` (the attack's `ignoreArmour` and\n`unblockable` do not count), `footwork` (half damage; with hit zones the highest attack die\nmoves to the better guarded neighbouring zone), `riposte` (the attack is turned away and the\ndefender strikes back), `disarm` (the attacker's weapons count nothing until the end of its\nnext turn), `perfectGuard` (the attack's damage goes back to the attacker); `clash` names the\nclash in a defence's event (not a combination's effect).","oneOf":[{"type":"string","enum":["extraDamage","unblockable","critical","wound","status","extraTurn","ignoreArmour","foeFewerDice","keepInitiative","breakGuard","brace","footwork","riposte","disarm","perfectGuard","clash"]},{"description":"P8-30, on a set defence throw: two of the attack's dice swap places (zones), the swap that\ngets most through.","type":"string","const":"feint"},{"description":"P8-30: the defence die that blocks most is taken away.","type":"string","const":"shatter"},{"description":"P8-30: no defence die counts on this blow (armour and shields still do).","type":"string","const":"breakthrough"},{"description":"P8-39, a run's: the run's dice all count as its highest die (3 · 4 · 5 → 5 · 5 · 5), turned\nbefore the defence meets them.","type":"string","const":"raiseToHighest"},{"description":"P8-42: the combination's dice count `amount` more each (a pair of 3s counts 4 · 4; a 6\ncounts 7), changed before the defence meets them.","type":"string","const":"raise"}]},"DiceOn":{"type":"string","enum":["target","self"]},"Mount":{"description":"What riding a character gives (docs/game_systems_spec.md, \"Characters and classes\").","type":"object","properties":{"seats":{"description":"Riders at once (at least 1).","type":"integer","format":"uint32","minimum":1},"modifiers":{"description":"What riding gives the rider (+2 Speed).","type":"array","items":{"$ref":"#/$defs/Modifier"},"default":[]},"grantsSkills":{"description":"Skills the rider has while riding (Charge).","type":"array","items":{"type":"string"},"default":[]}},"required":["seats"]},"Modifier":{"type":"object","properties":{"valueId":{"type":"string"},"op":{"$ref":"#/$defs/ModifierOp"},"value":{"type":"number","format":"double"}},"required":["valueId","op","value"]},"ModifierOp":{"type":"string","enum":["add","multiply"]},"DefeatLook":{"description":"How a combatant falls.","type":"object","properties":{"sound":{"type":["string","null"]},"effect":{"anyOf":[{"$ref":"#/$defs/DefeatEffect"},{"type":"null"}]}}},"DefeatEffect":{"type":"string","enum":["fade","sink","burst","none"]},"Row":{"description":"A fighter's row (L-69).","type":"string","enum":["front","back"]},"Role":{"description":"A role (L-93; docs/game_systems_spec.md, \"Roles\"): a line may be spoken by it, and the game\npicks the character who fills it when the line is shown, so a scene works with whichever\ncompanion is there.","type":"object","properties":{"id":{"type":"string"},"key":{"description":"Its name in formulas and texts (`{mentor.name}`).","type":"string"},"name":{"description":"In the creator's lists: \"the mentor\", \"whoever leads\".","type":"string"},"candidates":{"description":"Character IDs in order: the first who is present fills the role.","type":"array","items":{"type":"string"},"default":[]},"fallback":{"description":"Nobody fills it: the line is narrated without a name (default) or left out.","anyOf":[{"$ref":"#/$defs/RoleFallback"},{"type":"null"}]}},"required":["id","key","name"]},"RoleFallback":{"description":"What a line of a role nobody fills does (L-93).","type":"string","enum":["narrator","skip"]},"Class":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"growth":{"description":"Value ID → how it grows.","type":"object","additionalProperties":{"$ref":"#/$defs/Growth"},"default":{}},"learnset":{"type":"array","items":{"$ref":"#/$defs/LearnsetEntry"},"default":[]},"skillUnlocks":{"type":"array","items":{"$ref":"#/$defs/SkillUnlock"},"default":[]}},"required":["id","name"]},"Growth":{"description":"Total amount added at level L.","oneOf":[{"description":"perLevel × (L − 1)","type":"object","properties":{"perLevel":{"type":"number","format":"double"},"mode":{"type":"string","const":"linear"}},"required":["mode","perLevel"]},{"description":"Context growth, evaluated with level = L.","type":"object","properties":{"formula":{"type":"string"},"mode":{"type":"string","const":"formula"}},"required":["mode","formula"]},{"description":"values[L − 1]","type":"object","properties":{"values":{"type":"array","items":{"type":"number","format":"double"}},"mode":{"type":"string","const":"table"}},"required":["mode","values"]}]},"LearnsetEntry":{"type":"object","properties":{"level":{"type":"integer","format":"uint32","minimum":0},"skillId":{"type":"string"}},"required":["level","skillId"]},"SkillUnlock":{"type":"object","properties":{"skillId":{"type":"string"},"pointCost":{"type":"integer","format":"uint32","minimum":0},"minLevel":{"type":"integer","format":"uint32","minimum":0},"requires":{"type":"array","items":{"$ref":"#/$defs/SkillRank"},"default":[]}},"required":["skillId","pointCost","minLevel"]},"SkillRank":{"type":"object","properties":{"skillId":{"type":"string"},"rank":{"type":"integer","format":"uint32","minimum":0}},"required":["skillId","rank"]},"EquipmentSlot":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"zone":{"description":"Hit zones (L-104): the armour of a thing worn here counts on this zone only (a helmet on\n`top`); none: everywhere.","anyOf":[{"$ref":"#/$defs/Zone"},{"type":"null"}]},"place":{"description":"Where the slot stands on the figure of the game-like inventory (L-177), each from 0 (left,\ntop) to 1; none: in a column beside the figure.","anyOf":[{"$ref":"#/$defs/SlotPlace"},{"type":"null"}]}},"required":["id","name"]},"Zone":{"description":"Hit zones (L-104; docs/game_systems_spec.md, \"Dice battles\", \"Hit zones\"): where a die is aimed,\nthe first die `top`, the second `middle`, the third `bottom`; with four zones (L-187,\n`DiceRules.fourZones`) the same three are the head, the torso and the legs (`head`, `torso`,\n`legs` read as them) and the fourth die goes to the `feet`.","oneOf":[{"type":"string","enum":["top","middle","bottom"]},{"description":"L-187: only with four zones.","type":"string","const":"feet"},{"description":"P8-111: only with five zones, between the torso and the legs (gloves).","type":"string","const":"hands"}]},"SlotPlace":{"description":"A slot's place on the inventory's figure (L-177): its middle, 0–1 across and down.","type":"object","properties":{"x":{"type":"number","format":"float"},"y":{"type":"number","format":"float"}},"required":["x","y"]},"Thing":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"listName":{"description":"The name in the creator's lists only (\"Dura as a child\" for a \"Dura\", P6-04); none: the name.\nThe engine, the player and the book never read it.","type":["string","null"]},"description":{"type":["string","null"]},"icon":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"carry":{"anyOf":[{"$ref":"#/$defs/Carry"},{"type":"null"}]},"use":{"anyOf":[{"$ref":"#/$defs/ThingUse"},{"type":"null"}]},"wear":{"anyOf":[{"$ref":"#/$defs/Wear"},{"type":"null"}]},"pages":{"anyOf":[{"$ref":"#/$defs/Pages"},{"type":"null"}]},"onScreen":{"description":"Carried, it has a button on the game screen that reads or uses it (L-174: a diary at\nhand); off by default.","type":"boolean"},"made":{"description":"L-176: a pattern whose things the game makes with random parts; none: a plain thing.","anyOf":[{"$ref":"#/$defs/MadePattern"},{"type":"null"}]},"grammar":{"description":"L-176: how the words round its name agree with it (German: _Rostiges Schwert_).","anyOf":[{"$ref":"#/$defs/Grammar"},{"type":"null"}]}},"required":["id","name"]},"Carry":{"type":"object","properties":{"maxStack":{"type":["integer","null"],"format":"uint32","minimum":0},"price":{"type":["number","null"],"format":"double"}}},"ThingUse":{"type":"object","properties":{"where":{"$ref":"#/$defs/Where"},"target":{"description":"`null` = no target (lighting a lamp).","anyOf":[{"$ref":"#/$defs/TargetSpec"},{"type":"null"}]},"consumed":{"type":"boolean"},"effects":{"type":"array","items":{"$ref":"#/$defs/Effect"},"default":[]}},"required":["where","consumed"]},"Where":{"type":"string","enum":["anywhere","battle","outside_battle"]},"TargetSpec":{"type":"object","properties":{"side":{"$ref":"#/$defs/Side"},"switchSides":{"description":"Single targets: the player may move the choice to the other side (P4-30).","type":["boolean","null"]},"scope":{"$ref":"#/$defs/TargetScope"},"count":{"type":["integer","null"],"format":"uint32","minimum":0},"includeDefeated":{"type":["boolean","null"]}},"required":["side","scope"]},"Side":{"oneOf":[{"type":"string","enum":["foe","ally","self"]},{"description":"The player picks a foe or a companion (P4-30).","type":"string","const":"any"}]},"TargetScope":{"type":"string","enum":["single","all","random"]},"Wear":{"type":"object","properties":{"slotId":{"type":"string"},"modifiers":{"type":"array","items":{"$ref":"#/$defs/Modifier"},"default":[]},"grantsSkills":{"type":"array","items":{"type":"string"},"default":[]},"allowedClasses":{"type":"array","items":{"type":"string"},"default":[]},"reach":{"description":"`far`: the wearer's basic attack reaches far, from and into the back row alike (L-69).","anyOf":[{"$ref":"#/$defs/Reach"},{"type":"null"}]},"fills":{"description":"Two hands (L-106): the other slots this thing fills while worn (a greatsword fills the\nshield slot too); what is worn there comes off.","type":"array","items":{"type":"string"}},"dice":{"description":"Weapons in dice battles (L-106): how the wearer's attack dice change.","anyOf":[{"$ref":"#/$defs/GearDice"},{"type":"null"}]},"shield":{"description":"Shields in dice battles (L-106): armour held in one or two zones.","anyOf":[{"$ref":"#/$defs/Shield"},{"type":"null"}]}},"required":["slotId"]},"Reach":{"description":"How far a damage type's hits reach (L-69): `close` hits are weaker from and into the back row.","type":"string","enum":["close","far"]},"GearDice":{"description":"Weapons in dice battles (L-106; docs/game_systems_spec.md, \"Dice battles\", \"Weapons and\nshields\"): what a worn thing does to its wearer's attack throws.","type":"object","properties":{"extraDice":{"description":"Dice more (or fewer) in each attack throw (1 to 6 in all).","type":["integer","null"],"format":"int32"},"perDie":{"description":"Added to every die of an attack throw (each kept between 1 and 6).","type":["integer","null"],"format":"int32"},"combinations":{"description":"Effects added to a combination (it counts with this thing even where the rules leave it\nout).","$ref":"#/$defs/DiceCombinations","default":{}},"reach":{"description":"Hit zones: zones it reaches even where the foe has `none`.","type":"array","items":{"$ref":"#/$defs/Zone"}},"zoneEffect":{"description":"Hit zones: what a hit in one zone (or a shielded zone) does.","anyOf":[{"$ref":"#/$defs/GearZoneEffect"},{"type":"null"}]},"noParry":{"description":"Defence throws: its attacks cannot be parried or countered.","type":["boolean","null"]},"firstStrike":{"description":"With the throw for who starts: its wearer attacks once before it.","type":["boolean","null"]},"boost":{"description":"P8-86: chosen dice raised once a throw is final (the weapon set-ups: two-handed, two\nweapons, sword and shield).","anyOf":[{"$ref":"#/$defs/GearBoost"},{"type":"null"}]},"kind":{"description":"P8-88: what kind of weapon it is, and so its one trait die against die.","anyOf":[{"$ref":"#/$defs/WeaponKind"},{"type":"null"}]}}},"GearZoneEffect":{"description":"A weapon's effect on a hit in a zone (L-106).","type":"object","properties":{"zone":{"description":"`top`, `middle`, `bottom`, or `shield`: a zone the target's shield covers.","$ref":"#/$defs/GearZone"},"effects":{"description":"Run on the target after a hit there.","type":"array","items":{"$ref":"#/$defs/Effect"}},"breakShield":{"description":"A hit there breaks the target's shield: its armour counts nothing until the end of the\ntarget's next turn.","type":["boolean","null"]}},"required":["zone"]},"GearZone":{"description":"Where a weapon's zone effect works (L-106).","oneOf":[{"type":"string","enum":["top","middle","bottom","shield"]},{"description":"L-187: with four zones.","type":"string","const":"feet"}]},"GearBoost":{"description":"A weapon set-up's boosts (P8-86): what it adds to an attack's and a defence's chosen dice.","type":"object","properties":{"attack":{"description":"Once an attack throw is final, before the defence.","anyOf":[{"$ref":"#/$defs/Boost"},{"type":"null"}]},"defence":{"description":"Once a defence is thrown, before it is paired.","anyOf":[{"$ref":"#/$defs/Boost"},{"type":"null"}]}}},"Boost":{"description":"`amount` added to `dice` dice of a throw (P8-86); with `neighbours` to dice in neighbouring\nzones (or places in the row) only.","type":"object","properties":{"dice":{"description":"1 to 3.","type":"integer","format":"uint32","minimum":0},"amount":{"description":"What each chosen die counts more (1 in the standard).","type":"integer","format":"int32"},"neighbours":{"type":["boolean","null"]}},"required":["dice","amount"]},"WeaponKind":{"description":"A weapon's kind (P8-88): one trait each, die against die.","oneOf":[{"description":"Riposte: defending, each defence die 4 or more above its attack die strikes back for 1.","type":"string","const":"sword"},{"description":"Bite: the best hit of its attack deals 1 more.","type":"string","const":"axe"},{"description":"Crush: each of its attack dice blocked by exactly 1 still deals 1.","type":"string","const":"hammer"}]},"Shield":{"description":"Shields in dice battles (L-106): `armour` in the zone it is held in (two neighbouring ones with\n`covers: 2`); in a game without hit zones, everywhere.","type":"object","properties":{"armour":{"type":"number","format":"double"},"covers":{"description":"1 or 2 zones (none: 1).","type":["integer","null"],"format":"uint32","minimum":0},"move":{"description":"When the defender moves it (none: `before_defence`).","anyOf":[{"$ref":"#/$defs/ShieldMove"},{"type":"null"}]}},"required":["armour"]},"ShieldMove":{"description":"When a shield is moved (L-106): after seeing the attack's dice, or (a buckler) after one\nface-down die of a hidden throw is shown.","type":"string","enum":["before_defence","after_one_die"]},"Pages":{"type":"object","properties":{"pages":{"type":"array","items":{"$ref":"#/$defs/Page"}},"onFirstRead":{"type":"array","items":{"$ref":"#/$defs/Effect"},"default":[]}},"required":["pages"]},"Page":{"type":"object","properties":{"id":{"description":"The page's own ID: its texts' address (`pag_…/text`).","type":"string"},"title":{"type":["string","null"]},"text":{"type":"string"},"image":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"onlyIf":{"type":["string","null"]}},"required":["id","text"]},"MadePattern":{"description":"L-176: the groups a made thing's parts are drawn from, one weighted draw per group.","type":"object","properties":{"groups":{"type":"array","items":{"$ref":"#/$defs/PartGroup"}}},"required":["groups"]},"PartGroup":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"none":{"description":"How often the group gives no part (as a part's weight); none: always one.","type":["number","null"],"format":"double"},"parts":{"type":"array","items":{"$ref":"#/$defs/Part"}}},"required":["id","name","parts"]},"Part":{"type":"object","properties":{"id":{"type":"string"},"words":{"description":"Its words round the thing's name (\"Rusty\", \"of the Bear\").","type":"string"},"forms":{"description":"The words per gender of the thing (German: rostiger, rostige, rostiges); none: `words`.","type":"object","properties":{"feminine":{"type":"string"},"masculine":{"type":"string"},"neuter":{"type":"string"}},"additionalProperties":false},"place":{"$ref":"#/$defs/PartPlace"},"weight":{"type":"number","format":"double"},"rarity":{"anyOf":[{"$ref":"#/$defs/Rarity"},{"type":"null"}]},"modifiers":{"description":"What it changes while the thing is worn.","type":"array","items":{"$ref":"#/$defs/Modifier"}},"effects":{"description":"What it does when the thing is used (after the thing's own).","type":"array","items":{"$ref":"#/$defs/Effect"}},"price":{"description":"Added to the thing's price.","type":["number","null"],"format":"double"}},"required":["id","words","place","weight"]},"PartPlace":{"type":"string","enum":["before","after"]},"Rarity":{"description":"A made thing's rarity, lowest first.","type":"string","enum":["common","uncommon","rare","epic","legendary"]},"Grammar":{"type":"object","properties":{"gender":{"$ref":"#/$defs/Gender"}},"required":["gender"]},"Gender":{"type":"string","enum":["masculine","feminine","neuter"]},"Combination":{"description":"Two carried things combined in the inventory; order does not matter.","type":"object","properties":{"thingIds":{"type":"array","items":{"type":"string"},"minItems":2,"maxItems":2},"onlyIf":{"type":["string","null"]},"consume":{"type":"boolean"},"reply":{"type":["array","null"],"items":{"$ref":"#/$defs/Step"}},"effects":{"type":"array","items":{"$ref":"#/$defs/Effect"},"default":[]}},"required":["thingIds","consume"]},"Storage":{"description":"A place to keep things besides the party's inventory: a donkey's saddlebags, a chest, a vault\n(docs/game_systems_spec.md, \"Storages\").","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"owner":{"$ref":"#/$defs/StorageOwner"},"onlyIf":{"description":"Reachable only while this holds, e.g. `has(\"thg_chestkey\")`.","type":["string","null"]},"maxDistinct":{"description":"Different things; `None`: no limit.","type":["integer","null"],"format":"uint32","minimum":0,"default":null},"maxStack":{"description":"Of one thing; `None`: `settings.inventory.defaultMaxStack`.","type":["integer","null"],"format":"uint32","minimum":0,"default":null},"startingThings":{"type":"array","items":{"$ref":"#/$defs/ThingQty"},"default":[]}},"required":["id","name","owner"]},"StorageOwner":{"description":"Who or where a storage belongs to.","anyOf":[{"description":"Travels with that character while it is in the party.","type":"object","properties":{"characterId":{"type":"string"}},"required":["characterId"]},{"description":"Reachable in these passages only.","type":"object","properties":{"passageIds":{"type":"array","items":{"type":"string"}}},"required":["passageIds"]}]},"Shop":{"description":"A list of things to buy for the currency, and maybe to sell back: a market stall, a merchant,\na vending machine (docs/game_systems_spec.md, \"Shops\").","type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"keeperId":{"description":"The shopkeeper (a character): portrait and greeting voice.","type":["string","null"]},"greeting":{"type":["string","null"]},"offers":{"type":"array","items":{"$ref":"#/$defs/ShopOffer"},"default":[]},"buys":{"description":"The player may sell things here.","type":"boolean","default":false},"sellShare":{"description":"Share of a thing's price paid when selling (0–1).","type":"number","format":"double","default":0.5},"opens":{"description":"With Time (P6-09): the hour it opens, 0–23 (none: open from midnight; neither: always).","type":["integer","null"],"format":"uint32","minimum":0},"closes":{"description":"… and the hour it closes, 0–24 (over midnight when it comes first).","type":["integer","null"],"format":"uint32","minimum":0}},"required":["id","name"]},"ShopOffer":{"description":"A thing a shop sells.","type":"object","properties":{"thingId":{"type":"string"},"price":{"description":"A formula; none: the thing's `carry.price`.","type":["string","null"]},"onlyIf":{"description":"Offered only while this holds.","type":["string","null"]},"stock":{"description":"How many the shop has at the start; none: no limit.","type":["integer","null"],"format":"uint32","minimum":0}},"required":["thingId"]},"Collection":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"icon":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"entryNoun":{"description":"\"creature\", \"clue\", \"achievement\"","type":"string"},"showLocked":{"description":"Undiscovered entries listed as \"???\".","type":"boolean"},"acrossPlaythroughs":{"description":"Kept in meta state (achievements).","type":"boolean"},"showOnPage":{"description":"Listed on the published game's page for people who have not played yet (L-89): every\nentry, or only the entries marked `onPage`. Absent: not on the page.","anyOf":[{"$ref":"#/$defs/PageShow"},{"type":"null"}]},"entries":{"type":"array","items":{"$ref":"#/$defs/Entry"},"default":[]}},"required":["id","name","entryNoun","showLocked","acrossPlaythroughs"]},"PageShow":{"description":"Which entries of a collection the game's page lists (L-89).","oneOf":[{"description":"Every entry.","type":"string","const":"all"},{"description":"Only the entries marked `onPage`.","type":"string","const":"chosen"}]},"Entry":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"image":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"icon":{"description":"A small picture beside the title in lists (greyed while locked).","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"hint":{"description":"Shown instead of \"???\" while the entry is locked (\"Find all three keys\").","type":["string","null"]},"about":{"anyOf":[{"$ref":"#/$defs/About"},{"type":"null"}]},"sections":{"type":"array","items":{"$ref":"#/$defs/Section"},"default":[]},"words":{"description":"Words marked every time they appear in the story texts the engine shows (L-87).","type":"array","items":{"type":"string"}},"onPage":{"description":"Chosen for the game's page when the collection shows only chosen entries (L-89).","type":"boolean"}},"required":["id","title"]},"About":{"type":"object","properties":{"type":{"$ref":"#/$defs/AboutKind"},"id":{"type":"string"}},"required":["type","id"]},"AboutKind":{"type":"string","enum":["enemy","character","thing","passage"]},"Section":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":["string","null"]},"content":{"$ref":"#/$defs/SectionContent"},"revealWhen":{"description":"Context `visual`.","type":["string","null"]},"onRead":{"description":"Revealed when a marked word of the entry is read (L-87).","type":"boolean"}},"required":["id","content"]},"SectionContent":{"oneOf":[{"type":"object","properties":{"text":{"type":"string"},"type":{"type":"string","const":"text"}},"required":["type","text"]},{"type":"object","properties":{"facts":{"type":"array","items":{"type":"string"}},"type":{"type":"string","const":"facts"}},"required":["type","facts"]}]},"LootTable":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"rolls":{"type":"integer","format":"uint32","minimum":0},"entries":{"type":"array","items":{"$ref":"#/$defs/LootEntry"},"default":[]},"guaranteed":{"type":"array","items":{"$ref":"#/$defs/ThingQty"},"default":[]}},"required":["id","name","rolls"]},"LootEntry":{"type":"object","properties":{"thingId":{"type":["string","null"]},"weight":{"type":"number","format":"double"},"qty":{"description":"[min, max]","type":"array","items":{"type":"integer","format":"uint32","minimum":0},"minItems":2,"maxItems":2},"randomParts":{"description":"L-176: a made thing's parts drawn for each one given.","type":"boolean"}},"required":["weight","qty"]},"Enemy":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"listName":{"description":"The name in the creator's lists only (\"Dura as a child\" for a \"Dura\", P6-04); none: the name.\nThe engine, the player and the book never read it.","type":["string","null"]},"description":{"type":["string","null"]},"battleSprite":{"type":["string","null"]},"battlePoses":{"description":"Its figure in battle with poses (L-66; none: `battle_sprite` as it is).","anyOf":[{"$ref":"#/$defs/BattlePoses"},{"type":"null"}]},"portrait":{"description":"Beside its lines when it speaks.","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"talk":{"description":"Talk sounds: how its lines sound.","anyOf":[{"$ref":"#/$defs/TalkVoice"},{"type":"null"}]},"cry":{"description":"In battle: its cry when a hard blow strikes it (P8-80; none: the action look's pain sound).","type":["string","null"]},"defeat":{"description":"How it falls (none: the battle look's).","anyOf":[{"$ref":"#/$defs/DefeatLook"},{"type":"null"}]},"level":{"type":"integer","format":"uint32","minimum":0},"values":{"type":"object","additionalProperties":{"type":"number","format":"double"},"default":{}},"classId":{"type":["string","null"]},"combat":{"$ref":"#/$defs/CombatProfile"}},"required":["id","name","level","combat"]},"Encounter":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"foes":{"description":"1–8 foes.","type":"array","items":{"$ref":"#/$defs/Foe"}},"background":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"music":{"type":["string","null"]},"bonusRewards":{"$ref":"#/$defs/BonusRewards"},"turnOrder":{"description":"This battle's own turn order (L-84: a boss fought in planned turns; none: the battle\nrules').","anyOf":[{"$ref":"#/$defs/TurnOrder"},{"type":"null"}]},"sceneActions":{"description":"Actions written for this battle's scene (L-95, up to three): offered among each party\nmember's commands.","type":"array","items":{"$ref":"#/$defs/SceneAction"}},"dice":{"description":"Dice battles (L-99): this battle's own dice (none: the battle rules').","anyOf":[{"$ref":"#/$defs/DiceRules"},{"type":"null"}]},"noDice":{"description":"This battle throws no dice although the battle rules have them (`dice` is not read then).","type":["boolean","null"]},"multiplayer":{"description":"Multiplayer (L-205a; docs/architecture_spec.md, \"Multiplayer\"): this battle may be played\nby players together — `versus`, a duel of two players' fighters on the server (none: alone).","anyOf":[{"$ref":"#/$defs/Multiplayer"},{"type":"null"}]},"multiplayerMax":{"description":"A fight together's most players (L-205e, 2–4; none: 2). Only with `coop`.","type":["integer","null"],"format":"uint8","minimum":0,"maximum":255},"multiplayerSeconds":{"description":"A match's time for a move in seconds (L-226, 15–300; none: 60); a fighter select takes\ntwice it. Only on a fight played with a friend.","type":["integer","null"],"format":"uint16","minimum":0,"maximum":65535},"matchThings":{"description":"A duel's own rack (L-205d): things each side of a match has besides the game's starting\nthings (a game whose fighters take their weapons on the way, as Dice Duel's, gives its\nduel for two the weapons here). Only a match reads it.","type":"array","items":{"$ref":"#/$defs/ThingQty"}},"roster":{"description":"Choose your fighter (L-218; docs/dice_battles_spec.md): the battle opens on a fighter\nselect — the player picks one of these characters to fight as the party's one fighter,\nthe foe is picked from the rest (none: the battle opens as before). Optional, additive.","anyOf":[{"$ref":"#/$defs/Roster"},{"type":"null"}]}},"required":["id","name","foes","bonusRewards"]},"Foe":{"anyOf":[{"type":"object","properties":{"enemyId":{"type":"string"},"level":{"type":["integer","null"],"format":"uint32","minimum":0},"row":{"description":"Its row while the battle rules have rows (L-69; none: front).","anyOf":[{"$ref":"#/$defs/Row"},{"type":"null"}]}},"required":["enemyId"]},{"type":"object","properties":{"characterId":{"type":"string"},"row":{"description":"Its row while the battle rules have rows (L-69; none: front).","anyOf":[{"$ref":"#/$defs/Row"},{"type":"null"}]}},"required":["characterId"]}]},"BonusRewards":{"type":"object","properties":{"xp":{"type":"number","format":"double"},"effects":{"type":"array","items":{"$ref":"#/$defs/Effect"},"default":[]},"lootTableId":{"type":["string","null"]}},"required":["xp"]},"TurnOrder":{"oneOf":[{"type":"string","enum":["round_by_speed","party_first"]},{"description":"Time gauges fill with speed; whoever's is full acts.","type":"string","const":"active_time"},{"description":"Each round is planned as chains of actions, then played on one timeline (L-84).","type":"string","const":"planned"}]},"SceneAction":{"description":"An action written for one battle's scene (L-95): \"Cut the chandelier rope\". It takes the\nparty member's turn (planned turns: its time), runs its effects on its targets and, `once`,\nis gone for the rest of the battle.","type":"object","properties":{"id":{"description":"`sca_…`","type":"string"},"label":{"description":"\"Cut the chandelier rope\"","type":"string"},"onlyIf":{"description":"Offered only while this holds (battle context: `self` is the one acting).","type":["string","null"]},"once":{"description":"Usable once per battle, by anyone in the party.","type":"boolean","default":false},"effects":{"description":"Run as a skill's (power 100, rank 1): combat effects on the targets, the rest on the world.","type":"array","items":{"$ref":"#/$defs/Effect"},"default":[]},"targets":{"description":"Who its combat effects act on (none: no one; only its other effects run).","anyOf":[{"$ref":"#/$defs/TargetSpec"},{"type":"null"}]},"look":{"anyOf":[{"$ref":"#/$defs/ActionLook"},{"type":"null"}]},"time":{"description":"Planned turns: its time in the budget (none: 40).","type":["integer","null"],"format":"uint32","minimum":0}},"required":["id","label"]},"ActionLook":{"description":"How one action looks and sounds; every field optional, a missing one falls back (skill →\ndamage type → the battle look's `attack` or `heal`).","type":"object","properties":{"sound":{"description":"As the action starts (a swing, a spell's cast).","type":["string","null"]},"hitSound":{"description":"On each target hit.","type":["string","null"]},"painSound":{"description":"On a hit of `pain_from` damage or more, after the hit sound: the struck one's cry (P8-80).","type":["string","null"]},"painFrom":{"description":"The damage from which `pain_sound` plays (none: 6).","type":["integer","null"],"format":"uint32","minimum":0},"painMark":{"description":"On such a hit: a mark on the struck one's portrait, kept for the battle (none: none).","anyOf":[{"$ref":"#/$defs/PainMark"},{"type":"null"}]},"actor":{"description":"What the one acting does.","anyOf":[{"$ref":"#/$defs/ActorMove"},{"type":"null"}]},"animation":{"description":"A strip played over the target(s).","anyOf":[{"$ref":"#/$defs/BattleAnimation"},{"type":"null"}]},"target":{"description":"What the one hit does.","anyOf":[{"$ref":"#/$defs/TargetReaction"},{"type":"null"}]},"color":{"description":"`#rrggbb`: the flash's and the number's colour.","type":["string","null"]},"screen":{"description":"The whole battle screen.","anyOf":[{"$ref":"#/$defs/ScreenEffect"},{"type":"null"}]}}},"PainMark":{"description":"What a hard blow leaves on the struck one's portrait (P8-80).","oneOf":[{"type":"string","enum":["none"]},{"description":"A blood splash, up to three, kept for the battle.","type":"string","const":"blood"}]},"ActorMove":{"description":"What the one acting does; `step` walks toward the other side and back (L-66).","type":"string","enum":["none","lunge","jump","glow","step"]},"BattleAnimation":{"description":"An animation strip: one row of frames `frameWidth` pixels wide (the picture's height is the\nframe's), played at `fps`.","type":"object","properties":{"image":{"type":"string"},"frameWidth":{"type":"integer","format":"uint32","minimum":0},"frames":{"description":"Frame numbers in playing order, from 0.","type":"array","items":{"type":"integer","format":"uint32","minimum":0}},"fps":{"type":"integer","format":"uint32","minimum":0},"on":{"$ref":"#/$defs/AnimationPlace"}},"required":["image","frameWidth","frames","fps","on"]},"AnimationPlace":{"type":"string","enum":["each_target","side","screen"]},"TargetReaction":{"type":"string","enum":["none","shake","blink","flash","knockback"]},"ScreenEffect":{"type":"string","enum":["none","shake","flash"]},"DiceRules":{"description":"Dice battles (L-99; docs/game_systems_spec.md, \"Dice battles\"): every attack is a throw of\n`count` six-sided dice; the sum against the target's armour (at or below: blocked, above: the\ndifference is the damage), the best combination switched on adds its effects.","type":"object","properties":{"count":{"description":"3, 4 or 5 (none: 3; 5 with five zones, P8-111).","type":["integer","null"],"format":"uint32","minimum":0},"combinations":{"description":"The combinations that count, each with its effects (a combination left out does not count).","$ref":"#/$defs/DiceCombinations","default":{}},"runOf":{"description":"What a run needs (none: `all`, every die in a row; `3`: any three dice in a row, with 4\ndice too: 1-2-3-6).","anyOf":[{"$ref":"#/$defs/RunOf"},{"type":"null"}]},"rerolls":{"description":"Per turn: dice kept and the others thrown again (none: 0).","type":["integer","null"],"format":"uint32","minimum":0},"armour":{"description":"The number value that is a fighter's armour (none: armour 0).","type":["string","null"]},"addToSum":{"description":"A number value added to every attack throw's sum, the thrower's (none: nothing; \"Less\nluck\": Strength +2).","type":["string","null"]},"initiative":{"description":"The battle starts with a throw for who starts: the party's leader against the first foe,\nthe higher sum's side acts first (none: no throw).","type":["boolean","null"]},"swap":{"description":"P8-87: fighters may swap to their second set once a turn, before they attack (that attack\nwithout a boost).","type":["boolean","null"]},"versus":{"description":"P8-95: the battle opens on the VS screen (the foe's stats and weapons, the hero's weapons to\nchoose, Start), while the throw for who starts waits.","type":["boolean","null"]},"defence":{"description":"Defence throws and parries (none: the armour alone blocks).","anyOf":[{"$ref":"#/$defs/DiceDefence"},{"type":"null"}]},"zones":{"description":"Hit zones (L-104; 3 dice, or 4 with one set aside): each die is aimed at the top, middle or\nbottom of the target and meets that zone's armour on its own.","type":["boolean","null"]},"fourZones":{"description":"Four hit zones (L-187, with `zones`): head, torso, legs and feet, exactly 4 dice, none set\naside (none: three zones).","type":["boolean","null"]},"fiveZones":{"description":"Five hit zones (P8-111, with `zones`): head, torso, hands, legs and feet, exactly 5 dice\n(over `fourZones`).","type":["boolean","null"]},"runExtend":{"description":"Extending a run (L-99): after a throw that shows a run, one more die at a time; a die that\ncontinues the run at either end adds `perStep` to the attack.","anyOf":[{"$ref":"#/$defs/RunExtend"},{"type":"null"}]},"momentum":{"description":"Momentum (L-108): each throw the target blocks adds this to the thrower's next throws'\nsums until one of them hits (none: no momentum; the default set writes 1).","type":["number","null"],"format":"double"},"stealthOnes":{"description":"Stealth 1s (P8-66): with die against die or hit zones, an attack die that shows 1 as thrown\ndeals 1 past armour and shield, unless the defence die set against it shows 1 too (none:\noff).","type":["boolean","null"]}}},"RunOf":{"description":"What a run needs: \"all\" (every die in a row) or 3 (any three dice in a row).","enum":["all",3]},"DiceDefence":{"description":"Defence throws (L-99, \"Defence throws and parries\"): the defender throws its own dice, their sum\nplus its armour against the attack's sum; a rarer combination parries.","type":"object","properties":{"dice":{"description":"3 or 4 (none: as many as the attack).","type":["integer","null"],"format":"uint32","minimum":0},"parry":{"description":"A defence showing a rarer combination than the attack parries it: no damage at all.","type":["boolean","null"]},"parryMirror":{"description":"P8-110: the parry needs the attack's combination with the same pips in the defence (its\ndice as thrown: a pair of 4s by two 4s), not a rarer one (none: by rarity, as before).","type":["boolean","null"]},"counter":{"description":"With a parry: the damage the attacker takes (none: 0).","type":["number","null"],"format":"double"},"click":{"description":"A party member's defence waits for the player's \"Throw to defend\".","type":["boolean","null"]},"hidden":{"description":"Hidden attack throws (L-102): the attack's dice lie face down until the defence is thrown\n(both ways: a foe's laid defence stays face down too); reveal tricks show them.","type":["boolean","null"]},"hiddenShow":{"description":"Hidden throws (L-108): this many of a face-down throw's dice lie face up, the first ones\n(none: 0, all face down as before; the editor writes 1 when hidden throws are switched on).","type":["integer","null"],"format":"uint32","minimum":0},"counterAttack":{"description":"A defence that beats the attack die by die (both sorted high to low, every defence die\nhigher) makes the attack do nothing and strikes back at once with the defender's basic\nattack; a counter attack is never countered.","type":["boolean","null"]},"pairReroll":{"description":"P8-91: a defence throw that shows a pair may throw up to this many of its other dice again,\nonce, before it is paired (the pair's dice stay). None: no reroll.","type":["integer","null"],"format":"uint32","minimum":0},"combinations":{"description":"Defence combinations (L-109): the defence throw's own combinations, each with defence\neffects (`brace`, `footwork`, `riposte`, `disarm`, `perfectGuard`); with a set the parry by\na rarer combination is off. None: none (the parry as before).","anyOf":[{"$ref":"#/$defs/DiceCombinations"},{"type":"null"}]},"combinationsWhen":{"description":"When the defence combinations (and the clash) count: `hold_back` (none) only in a defence\nafter the defender held back, `always` in every defence.","anyOf":[{"$ref":"#/$defs/CombinationsWhen"},{"type":"null"}]},"clash":{"description":"The clash (L-109): a defence showing the same combination with the same value as the\nattack cancels it (counts as the defence combinations do).","type":["boolean","null"]},"pairs":{"description":"Die against die (P8-27; playtesters, 2026-10-31): each attack die meets one defence die,\nwhat gets through pair by pair is the blow, the armour taken off once; with `click` the\nparty throws, then puts each defence die against an attack die by hand (drag and drop).\nNone: the sums are compared, as before.","type":["boolean","null"]},"answer":{"description":"Like answers like (P8-31): a defence showing the attack's combination answers it whatever\nthe numbers — the attack's combination dice count as blocked and its combination's effects\ndo not count; with die against die and the party's defence by click only when its\ncombination dice are set against the attack's (none: off).","type":["boolean","null"]}}},"CombinationsWhen":{"description":"When a defence throw's combinations count: \"hold_back\" (only after the defender held back) or \"always\".","type":"string","enum":["hold_back","always"]},"RunExtend":{"description":"Extending a run (L-99, \"Extending a run\"): one more die thrown after a run; a die that\ncontinues it at either end grows it and adds `perStep` damage, until `maxLength` or a miss.","type":"object","properties":{"perStep":{"description":"Extra damage for each step the run grew (none: 2).","type":["number","null"],"format":"double"},"maxLength":{"description":"The longest the run can grow, at most 6 (none: 6, 1-2-3-4-5-6).","type":["integer","null"],"format":"uint32","minimum":0},"risk":{"description":"A die that does not fit also loses the run's own bonus for this attack.","type":["boolean","null"]}}},"Multiplayer":{"description":"How players play an encounter together (L-205a: `versus`; stage 2 adds `coop`).","oneOf":[{"description":"Two players' fighters against each other (the encounter's foes are not fought).","type":"string","const":"versus"},{"description":"Two to four players' fighters together as the party against the encounter's foes (L-205\nstage 2; up to four from stage 3, `multiplayerMax`).","type":"string","const":"coop"}]},"Roster":{"description":"A fighter select's list (L-218).","type":"object","properties":{"fighters":{"description":"The characters to choose from, in the grid's order.","type":"array","items":{"$ref":"#/$defs/RosterEntry"}},"foe":{"description":"Who the foe is: picked by the engine from the roster (none: `pick`), or the encounter's\nown foes.","anyOf":[{"$ref":"#/$defs/RosterFoe"},{"type":"null"}]},"chosen":{"description":"A text value that receives the player's fighter's character ID.","type":["string","null"]},"foeChosen":{"description":"A text value that receives the foe's character ID (with `pick`).","type":["string","null"]},"shuffle":{"description":"The grid in a new random order each time the select opens (none: the listed order); only\nhow the select shows it, never what the engine picks.","type":"boolean"}},"required":["fighters"]},"RosterEntry":{"description":"One fighter of a roster (L-218).","type":"object","properties":{"characterId":{"type":"string"},"lockedUnless":{"description":"Locked (shown as **?**, never picked) while this is false (none: always open).","type":["string","null"]},"hint":{"description":"What unlocks it, shown on the locked tile (\"Beat the Dice King\").","type":["string","null"]},"foeUnless":{"description":"Not picked as the foe while this holds (an arcade's beaten foes); the player may still\npick it (L-220).","type":["string","null"]}},"required":["characterId"]},"RosterFoe":{"description":"Who a roster battle's foe is (L-218).","oneOf":[{"description":"Picked by the engine from the roster's open fighters other than the player's.","type":"string","const":"pick"},{"description":"The encounter's own foes.","type":"string","const":"fixed"}]},"EncounterArea":{"description":"Encounters on the way (L-63): battles that come by chance in the passages of an area and on\nits routes. One draw per passage entered by a way on, `steps` draws per route travelled.","type":"object","properties":{"id":{"description":"`ear_…`","type":"string"},"name":{"description":"\"Grassland\", \"Cave of Winds, lower floor\"","type":"string"},"encounters":{"type":"array","items":{"$ref":"#/$defs/AreaEncounter"},"default":[]},"rate":{"description":"The chance of a battle per draw, 0–1 (a formula, world context).","type":"string"},"background":{"description":"The battles' background here (none: each encounter's).","anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"music":{"description":"Their music here (none: each encounter's).","type":["string","null"]},"firstStrike":{"description":"The chances that the party, or the foes (an ambush), act first.","anyOf":[{"$ref":"#/$defs/FirstStrike"},{"type":"null"}]},"canFlee":{"type":"boolean","default":true},"lose":{"description":"Where a lost battle leads (an ending, a passage).","$ref":"#/$defs/Exit"}},"required":["id","name","rate","lose"]},"AreaEncounter":{"description":"One encounter of an area and its weight in the pick.","type":"object","properties":{"encounterId":{"type":"string"},"weight":{"type":"number","format":"double"},"onlyIf":{"type":["string","null"]}},"required":["encounterId","weight"]},"FirstStrike":{"description":"Chances (0–1 formulas) drawn one after the other when a battle on the way starts.","type":"object","properties":{"party":{"type":"string"},"foes":{"type":"string"}},"required":["party","foes"]},"Camp":{"description":"A place to rest that players open from the menu (docs/game_systems_spec.md, \"Camp\"; P6-08):\neverything in it is an ordinary passage, thing, value or effect.","type":"object","properties":{"passageId":{"description":"The camp: its own picture, lines and options like any passage.","type":"string"},"allowedWhen":{"description":"Where players may make camp; none: anywhere outside a battle, a shop or an ending.","type":["string","null"]},"sleep":{"description":"*Sleep* in the camp; none: the camp offers no sleep.","anyOf":[{"$ref":"#/$defs/CampSleep"},{"type":"null"}]}},"required":["passageId"]},"CampSleep":{"description":"What a night in the camp does.","type":"object","properties":{"label":{"description":"The button's word; none: the player text `camp.sleep` (\"Sleep\").","type":["string","null"]},"effects":{"description":"What a night does: health back, hunger up.","type":"array","items":{"$ref":"#/$defs/Effect"},"default":[]},"dreams":{"description":"One is chosen at random (the game's random stream) among those whose condition holds.","type":"array","items":{"$ref":"#/$defs/Dream"}},"interruptedBy":{"description":"A fight in the night, by chance.","anyOf":[{"$ref":"#/$defs/NightFight"},{"type":"null"}]}}},"Dream":{"description":"A dream: a passage visited after a night, which ends with *Back* to the camp.","type":"object","properties":{"passageId":{"type":"string"},"onlyIf":{"type":["string","null"]},"weight":{"description":"How likely against the other dreams (none: 1).","type":["number","null"],"format":"double"}},"required":["passageId"]},"NightFight":{"description":"A fight that may break into the night (Battles).","type":"object","properties":{"chance":{"description":"The chance per night, 0–1, a formula.","type":"string"},"encounterId":{"type":"string"},"lose":{"description":"Where a lost night's fight leads; none: the party wakes in the camp, beaten.","anyOf":[{"$ref":"#/$defs/Exit"},{"type":"null"}]}},"required":["chance","encounterId"]},"Skill":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"icon":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"basic":{"description":"The basic attack; owned by Battles.","type":"boolean","default":false},"where":{"$ref":"#/$defs/Where"},"target":{"$ref":"#/$defs/TargetSpec"},"cost":{"type":"array","items":{"$ref":"#/$defs/Cost"},"default":[]},"cooldown":{"type":"integer","format":"uint32","minimum":0,"default":0},"power":{"type":"number","format":"double","default":0},"effects":{"type":"array","items":{"$ref":"#/$defs/Effect"},"default":[]},"ranks":{"type":"array","items":{"$ref":"#/$defs/SkillRankDef"},"default":[]},"look":{"description":"How using it looks and sounds (Fireball: cast, flames, boom).","anyOf":[{"$ref":"#/$defs/ActionLook"},{"type":"null"}]},"needsFull":{"description":"A gauge's value ID: usable only while that gauge is full, and empties it (a limit move).","type":["string","null"]},"time":{"description":"Planned turns (L-84): its cost in a fighter's time budget (none: 40; the basic attack 30).","type":["integer","null"],"format":"uint32","minimum":0},"follows":{"description":"Planned turns (L-84): combos, a bonus to its power when it comes right after a skill.","type":"array","items":{"$ref":"#/$defs/SkillCombo"}},"dice":{"description":"Skills paid with a die (L-105): in a dice battle, usable only with a die of the held throw\nthat meets the condition; with `spend` (the default) that die leaves the throw.","anyOf":[{"$ref":"#/$defs/SkillDice"},{"type":"null"}]}},"required":["id","name","where","target"]},"Cost":{"type":"object","properties":{"valueId":{"type":"string"},"amount":{"type":"number","format":"double"}},"required":["valueId","amount"]},"SkillRankDef":{"type":"object","properties":{"power":{"type":["number","null"],"format":"double"},"cost":{"type":["array","null"],"items":{"$ref":"#/$defs/Cost"}},"addEffects":{"type":["array","null"],"items":{"$ref":"#/$defs/Effect"}}}},"SkillCombo":{"description":"A combo (L-84): played right after `skill_id`, the skill's power gains `bonus`.","type":"object","properties":{"skillId":{"type":"string"},"bonus":{"description":"Added to the skill's power; a battle formula with `self.*` (the one using it).","type":"string"},"ally":{"description":"Also after an ally's action: the action just before on the round's timeline, by anyone on\nthe same side (none: only the same fighter's chain).","type":["boolean","null"]}},"required":["skillId","bonus"]},"SkillDice":{"description":"Skills paid with a die (L-105): the die a skill needs (`min` to `max`, or `exact`) and whether\nit is used up (`spend`, none: yes). A skill marked `desperate` is paid by foes whenever they are\nbelow a third of their bar.","type":"object","properties":{"min":{"type":["integer","null"],"format":"uint32","minimum":0},"max":{"type":["integer","null"],"format":"uint32","minimum":0},"exact":{"type":["integer","null"],"format":"uint32","minimum":0},"spend":{"type":["boolean","null"]},"desperate":{"type":["boolean","null"]},"set":{"description":"Special throws (L-151): a set of dice instead of one, each condition met by a different\ndie in any order (1 · 1 · 2: `exact` 1, 1 and 2); `min`, `max` and `exact` then count for\nnothing.","type":["array","null"],"items":{"$ref":"#/$defs/DieCondition"}}}},"DieCondition":{"description":"One die of a special throw's set (L-151): `min` to `max`, or `exact`.","type":"object","properties":{"min":{"type":["integer","null"],"format":"uint32","minimum":0},"max":{"type":["integer","null"],"format":"uint32","minimum":0},"exact":{"type":["integer","null"],"format":"uint32","minimum":0}}},"StatusEffect":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"icon":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"kind":{"$ref":"#/$defs/StatusKind"},"duration":{"$ref":"#/$defs/Duration"},"stacking":{"$ref":"#/$defs/Stacking"},"modifiers":{"type":"array","items":{"$ref":"#/$defs/Modifier"},"default":[]},"ticks":{"type":"array","items":{"$ref":"#/$defs/Tick"},"default":[]},"restriction":{"$ref":"#/$defs/Restriction"},"endsWhenHit":{"type":"boolean"},"endsAfterBattle":{"type":"boolean"},"lasts":{"description":"Wounds that last (L-97): kept after the battle until the next rest or until removed,\nwhatever `ends_after_battle` says (none: as `ends_after_battle` says).","anyOf":[{"$ref":"#/$defs/Lasts"},{"type":"null"}]},"sitsOut":{"description":"A character holding it at a battle's start sits the battle out (L-97).","type":"boolean"}},"required":["id","name","kind","duration","stacking","restriction","endsWhenHit","endsAfterBattle"]},"StatusKind":{"type":"string","enum":["helpful","harmful"]},"Duration":{"anyOf":[{"type":"object","properties":{"unit":{"$ref":"#/$defs/DurationUnit"},"count":{"type":"integer","format":"uint32","minimum":0}},"required":["unit","count"]},{"$ref":"#/$defs/UntilRemoved"}]},"DurationUnit":{"type":"string","enum":["turns","passages"]},"UntilRemoved":{"type":"string","enum":["until_removed"]},"Stacking":{"type":"string","enum":["refresh","extend","ignore"]},"Tick":{"type":"object","properties":{"when":{"$ref":"#/$defs/TickWhen"},"effects":{"type":"array","items":{"$ref":"#/$defs/Effect"},"default":[]}},"required":["when"]},"TickWhen":{"type":"string","enum":["turn_start","turn_end"]},"Restriction":{"type":"string","enum":["none","skip_turn","basic_attack_only","random_target"]},"Lasts":{"description":"How long a status lasts beyond its battle (L-97).","oneOf":[{"description":"Ends with the battle.","type":"string","const":"battle"},{"description":"Kept after the battle; the camp's sleep ends it.","type":"string","const":"until_rest"},{"description":"Kept until an effect removes it.","type":"string","const":"until_removed"}]},"BattleRules":{"description":"Settings of the Battles feature; defaults are used while Battles is off.","type":"object","properties":{"defeatBarId":{"description":"Required while Battles is on.","type":["string","null"],"default":null},"speedValueId":{"type":["string","null"],"default":null},"turnOrder":{"$ref":"#/$defs/TurnOrder","default":"round_by_speed"},"basicAttackSkillId":{"type":["string","null"],"default":null},"damageTypes":{"type":"array","items":{"$ref":"#/$defs/DamageType"},"default":[]},"healingFormula":{"type":"string","default":"user.attack * skill.power / 100"},"hitChance":{"type":"string","default":"clamp(0.9 + (user.speed - target.speed) * 0.01, 0.5, 1)"},"critChance":{"type":"string","default":"0.05"},"critMultiplier":{"type":"number","format":"double","default":1.5},"fleeChance":{"type":"string","default":"0.5"},"variancePercent":{"type":"number","format":"double","default":10},"defendMultiplier":{"type":"number","format":"double","default":0.5},"xpDistribution":{"$ref":"#/$defs/XpDistribution","default":"each_alive_full"},"afterBattle":{"$ref":"#/$defs/AfterBattle","default":{"restore":"none","reviveDefeated":false}},"look":{"description":"Sounds and animations (none: plain, silent). Presentation only: no result depends on it.","anyOf":[{"$ref":"#/$defs/BattleLook"},{"type":"null"}]},"activeTime":{"description":"With `turnOrder: 'active_time'`: how time gauges fill (docs/game_systems_spec.md,\n\"Active-time turns\").","anyOf":[{"$ref":"#/$defs/ActiveTime"},{"type":"null"}]},"planning":{"description":"With `turnOrder: 'planned'`: the time budget, the foes' intents and replanning\n(docs/game_systems_spec.md, \"Planned turns and skill chains\").","anyOf":[{"$ref":"#/$defs/Planning"},{"type":"null"}]},"gauges":{"description":"Gauges that fill in battle: a limit, rage, focus (docs/game_systems_spec.md, \"Gauges that\nfill in battle\").","type":"array","items":{"$ref":"#/$defs/BattleGauge"}},"rows":{"description":"A front and a back row (docs/game_systems_spec.md, \"Rows in battle\"; none: nobody has a row).","anyOf":[{"$ref":"#/$defs/BattleRows"},{"type":"null"}]},"morale":{"description":"What a foe's losses do to its morale (L-96; none: nothing).","anyOf":[{"$ref":"#/$defs/MoraleRules"},{"type":"null"}]},"refill":{"description":"Values that refill in battle (L-97): a focus each round and on defending.","type":"array","items":{"$ref":"#/$defs/Refill"}},"dice":{"description":"Dice battles (L-99): attacks are dice throws (none: as before).","anyOf":[{"$ref":"#/$defs/DiceRules"},{"type":"null"}]}}},"DamageType":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"formula":{"type":"string"},"canMiss":{"type":"boolean"},"look":{"description":"How hits of this type look and sound (\"Fire\": flames).","anyOf":[{"$ref":"#/$defs/ActionLook"},{"type":"null"}]},"reach":{"description":"With rows: `close` (none) hits are weaker from and into the back row, `far` ones not (L-69).","anyOf":[{"$ref":"#/$defs/Reach"},{"type":"null"}]}},"required":["id","name","formula","canMiss"]},"XpDistribution":{"type":"string","enum":["each_alive_full","split_among_alive","each_member_full"]},"AfterBattle":{"type":"object","properties":{"restore":{"$ref":"#/$defs/Restore"},"reviveDefeated":{"type":"boolean"}},"required":["restore","reviveDefeated"]},"Restore":{"anyOf":[{"$ref":"#/$defs/RestoreKind"},{"type":"object","properties":{"percent":{"type":"number","format":"double"}},"required":["percent"]}]},"RestoreKind":{"type":"string","enum":["none","full"]},"BattleLook":{"description":"How battles look and sound (docs/game_systems_spec.md, \"Battles\"): presentation only.","type":"object","properties":{"attack":{"description":"Every action that harms, unless its skill or damage type says else.","anyOf":[{"$ref":"#/$defs/ActionLook"},{"type":"null"}]},"heal":{"description":"Every action that heals or helps.","anyOf":[{"$ref":"#/$defs/ActionLook"},{"type":"null"}]},"crit":{"description":"Added on top of a critical hit's look.","anyOf":[{"$ref":"#/$defs/ActionLook"},{"type":"null"}]},"miss":{"description":"\"Miss!\" over the target.","anyOf":[{"$ref":"#/$defs/MissLook"},{"type":"null"}]},"defeat":{"anyOf":[{"$ref":"#/$defs/DefeatLook"},{"type":"null"}]},"numbers":{"description":"Amounts float up from the target (default true).","type":["boolean","null"],"x-default":true},"start":{"description":"As the battle begins.","anyOf":[{"$ref":"#/$defs/StartLook"},{"type":"null"}]},"victory":{"description":"A short sound or tune when the battle is won.","type":["string","null"]},"loss":{"description":"… and when it is lost.","type":["string","null"]},"victoryMusic":{"description":"A tune looping while a victory screen waits (L-65); the passage's music returns after it.","type":["string","null"]},"levelUp":{"description":"A jingle for each member who rises a level, on the level-up box (L-65).","type":["string","null"]},"cryVolume":{"description":"P8-90 (the user, playtest 2026-11-06: \"the scream sounds are too loud\"): a fighter's cry\nat this share of the sound effects' level, 0–100 (none: 50), so a cry stays under the hit.","type":["number","null"],"format":"double"},"parry":{"description":"P8-92: the sound of a parry (a rarer combination turning the whole blow away); none: the\nlibrary's `battle/parry`, else the block's.","type":["string","null"]},"diceSounds":{"description":"L-216, L-217: the dice's own sounds as files (each none: the dice effects' synthesized one).","anyOf":[{"$ref":"#/$defs/DiceSoundFiles"},{"type":"null"}]}}},"MissLook":{"type":"object","properties":{"sound":{"type":["string","null"]},"text":{"description":"\"Miss!\" over the target (default true).","type":["boolean","null"],"x-default":true}}},"StartLook":{"type":"object","properties":{"sound":{"type":["string","null"]},"effect":{"anyOf":[{"$ref":"#/$defs/StartEffect"},{"type":"null"}]}}},"StartEffect":{"type":"string","enum":["none","flash","fade"]},"DiceSoundFiles":{"description":"The dice heard from files (L-216: thrown; L-217: handled); presentation only.","type":"object","properties":{"shake":{"description":"Shaken in the cup before a throw.","type":["string","null"]},"roll":{"description":"Thrown and rolling on the table (once a throw).","type":["string","null"]},"land":{"description":"A die landing (each die).","type":["string","null"]},"pick":{"description":"A die picked up (kept, lifted to drag, chosen for a shatter).","type":["string","null"]},"drop":{"description":"A die laid down.","type":["string","null"]},"drag":{"description":"A die slid to another place.","type":["string","null"]},"hover":{"description":"The pointer over a die.","type":["string","null"]}}},"ActiveTime":{"description":"Active-time turns: a gauge of 1000 per combatant gains `fill` per tick of the engine.","type":"object","properties":{"fill":{"description":"Per tick, `self.*` in the battle context (none: the speed value), at least 1.","type":["string","null"]},"mode":{"description":"None: `wait`.","anyOf":[{"$ref":"#/$defs/ActiveTimeMode"},{"type":"null"}]},"ticksPerRound":{"description":"Ticks that make one round for formulas asking `turn` (none: 100).","type":["integer","null"],"format":"uint32","minimum":0}}},"ActiveTimeMode":{"description":"`wait`: time stands while a party member chooses; `active`: it runs on.","type":"string","enum":["wait","active"]},"Planning":{"description":"Planned turns (L-84): each round a chain of actions per fighter within a time budget, then\nevery chain plays on one timeline.","type":"object","properties":{"budget":{"description":"Each fighter's time per round, `self.*` in the battle context (none: 100).","type":["string","null"]},"intents":{"description":"The foes' next actions shown while planning (none: `shown`).","anyOf":[{"$ref":"#/$defs/PlanIntents"},{"type":"null"}]},"replan":{"description":"A chain may be changed once after the round's first actions played (none: false).","type":["boolean","null"]}}},"PlanIntents":{"type":"string","enum":["shown","hidden"]},"BattleGauge":{"description":"A character number value that fills in battle (a limit, rage, focus or momentum).","type":"object","properties":{"id":{"description":"Names the gauge (its texts' address).","type":"string"},"valueId":{"type":"string"},"max":{"type":"number","format":"double"},"fill":{"$ref":"#/$defs/GaugeFill","default":{}},"keep":{"description":"Emptied after every battle, or kept.","$ref":"#/$defs/GaugeKeep","default":"battle"},"full":{"anyOf":[{"$ref":"#/$defs/GaugeFull"},{"type":"null"}]}},"required":["id","valueId","max"]},"GaugeFill":{"description":"How much a gauge gains, each a battle formula (`amount`: the damage).","type":"object","properties":{"damageTaken":{"type":["string","null"]},"damageDealt":{"type":["string","null"]},"perTurn":{"type":["string","null"]},"allyDefeated":{"type":["string","null"]}}},"GaugeKeep":{"type":"string","enum":["battle","always"]},"GaugeFull":{"description":"As a gauge fills: a status (a trance), the command's name (Limit), its sound and glow.","type":"object","properties":{"statusId":{"type":["string","null"]},"label":{"type":["string","null"]},"look":{"anyOf":[{"$ref":"#/$defs/ActionLook"},{"type":"null"}]}}},"BattleRows":{"description":"Rows in battle (L-69): what a close hit dealt from the back row and taken there is multiplied\nby (each none: 0.5).","type":"object","properties":{"backDealt":{"type":["number","null"],"format":"double"},"backTaken":{"type":["number","null"],"format":"double"}}},"MoraleRules":{"description":"The rules' morale (L-96): what a foe's own losses do to its morale (both added).","type":"object","properties":{"onHit":{"description":"Each time a foe with morale takes damage and still stands (`amount`: the damage).","type":["string","null"]},"onAllyDown":{"description":"On every standing foe with morale when one of its side falls.","type":["string","null"]}}},"Refill":{"description":"A value that refills in battle (L-97): `per_round` at the start of each of a fighter's turns\n(planned turns: of each round, before it is planned), `on_defend` when it defends; both added\nwith `self` the fighter, kept within the value's bounds.","type":"object","properties":{"valueId":{"type":"string"},"perRound":{"type":["string","null"]},"onDefend":{"type":["string","null"]}},"required":["valueId"]},"Progression":{"description":"Settings of the Levels feature; defaults are used while levels are off.","type":"object","properties":{"maxLevel":{"type":"integer","format":"uint32","minimum":0,"default":20},"xpCurve":{"$ref":"#/$defs/XpCurve","default":{"mode":"formula","xpToNext":"round(20 * pow(level, 1.5))"}},"defaultEnemyXp":{"type":"string","default":"enemy.level * 10"},"onLevelUp":{"$ref":"#/$defs/OnLevelUp","default":{"restoreBars":true,"skillPoints":0,"statPoints":0}},"learnsets":{"type":"boolean","default":false},"skillPoints":{"type":"boolean","default":false},"statPoints":{"description":"Players choose what grows: level ups give points spent on the `raisable` values.","type":"boolean","default":false},"raisable":{"type":"array","items":{"$ref":"#/$defs/RaisableValue"},"default":[]}}},"XpCurve":{"oneOf":[{"type":"object","properties":{"xpToNext":{"type":"string"},"mode":{"type":"string","const":"formula"}},"required":["mode","xpToNext"]},{"type":"object","properties":{"xpToNext":{"type":"array","items":{"type":"number","format":"double"}},"mode":{"type":"string","const":"table"}},"required":["mode","xpToNext"]}]},"OnLevelUp":{"type":"object","properties":{"restoreBars":{"type":"boolean"},"skillPoints":{"type":"integer","format":"uint32","minimum":0},"statPoints":{"type":"integer","format":"uint32","minimum":0,"default":0}},"required":["restoreBars","skillPoints"]},"Translation":{"description":"The texts of one more language (docs/game_systems_spec.md, \"Translations\").","type":"object","properties":{"hidden":{"description":"Not offered to players yet (the playtest and the book still have it).","type":"boolean"},"texts":{"description":"By text address (`stp_ab12cd34/text`, `texts/menu.inventory`).","type":"object","additionalProperties":{"$ref":"#/$defs/TranslatedText"},"default":{}}}},"TranslatedText":{"description":"One translated text and how far it is.","type":"object","properties":{"text":{"type":"string"},"status":{"$ref":"#/$defs/TranslationStatus"},"source":{"description":"FNV-1a hash (8 hex digits) of the main text it was made from: another hash means the\nmain text changed since.","type":["string","null"]}},"required":["text","status"]},"TranslationStatus":{"description":"_Draft_, _Needs review_, _Done_: for the team, never for players.","type":"string","enum":["draft","review","done"]},"BookSettings":{"description":"docs/book_export_spec.md, section 2.","type":"object","properties":{"enabled":{"description":"Shows the Book area in the creator UI.","type":"boolean","default":false},"title":{"type":"string","default":""},"subtitle":{"type":["string","null"]},"author":{"type":"string","default":""},"cover":{"anyOf":[{"$ref":"#/$defs/ImageRef"},{"type":"null"}]},"pageSize":{"$ref":"#/$defs/PageSize","default":"a5"},"illustrations":{"$ref":"#/$defs/Illustrations","default":"grayscale"},"numbering":{"$ref":"#/$defs/Numbering","default":{"mode":"shuffled","seed":1}},"combat":{"$ref":"#/$defs/PaperCombat","default":{"mode":"rounds","rounds":{"attackDice":2,"attackValueId":"","hitTarget":"7 + floor(defender.defense / 2)","damage":"max(1, attacker.attack - floor(defender.defense / 2))","enemyTargets":"lowest_bar","skills":false,"things":false},"check":{"dice":2,"valueId":"","target":"7"}}}}},"PageSize":{"type":"string","enum":["a4","a5","us_letter","digest"]},"Illustrations":{"type":"string","enum":["none","grayscale","color"]},"Numbering":{"type":"object","properties":{"mode":{"$ref":"#/$defs/NumberingMode"},"seed":{"type":"integer","format":"uint32","minimum":0}},"required":["mode","seed"]},"NumberingMode":{"type":"string","enum":["shuffled","story_order"]},"PaperCombat":{"type":"object","properties":{"mode":{"$ref":"#/$defs/PaperMode"},"rounds":{"$ref":"#/$defs/PaperRounds"},"check":{"$ref":"#/$defs/PaperCheck"}},"required":["mode","rounds","check"]},"PaperMode":{"type":"string","enum":["rounds","check"]},"PaperRounds":{"type":"object","properties":{"attackDice":{"type":"integer","format":"uint8","minimum":0,"maximum":255},"attackValueId":{"type":"string"},"hitTarget":{"type":"string"},"damage":{"type":"string"},"enemyTargets":{"$ref":"#/$defs/EnemyTargets"},"skills":{"type":"boolean"},"things":{"type":"boolean"}},"required":["attackDice","attackValueId","hitTarget","damage","enemyTargets","skills","things"]},"EnemyTargets":{"type":"string","enum":["lowest_bar","reader_choice"]},"PaperCheck":{"type":"object","properties":{"dice":{"type":"integer","format":"uint8","minimum":0,"maximum":255},"valueId":{"type":"string"},"target":{"type":"string"}},"required":["dice","valueId","target"]},"EditorMeta":{"type":"object","properties":{"preset":{"$ref":"#/$defs/Preset"},"onboarding":{"$ref":"#/$defs/Onboarding","default":{"completed":[],"dismissed":false}},"pinned":{"description":"Story map positions by passage ID.","type":"object","additionalProperties":{"$ref":"#/$defs/Position"},"default":{}},"places":{"description":"Where every card, ending and chapter frame of the story map stood when it was last shown,\nby ID (relative to its frame as the layout places it): saved quietly by the editor, so\nanother computer sees the same map (docs/creator_ui_spec.md, \"Cards stay where the writer\nsaw them\"; L-94).","type":"object","additionalProperties":{"$ref":"#/$defs/Position"}},"folders":{"description":"Folders of lists other than passages, by list name.","type":"object","additionalProperties":{"type":"array","items":{"$ref":"#/$defs/Folder"}},"default":{}},"notes":{"description":"Notes by entity ID.","type":"object","additionalProperties":{"type":"string"},"default":{}},"labels":{"description":"Passage labels for the creator's own work (docs/creator_ui_spec.md \"Labels\").","type":"array","items":{"$ref":"#/$defs/Label"}},"passageLabels":{"description":"Label IDs by passage ID.","type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}},"testStates":{"type":"array","items":{"$ref":"#/$defs/TestState"},"default":[]},"kits":{"description":"The kits added to the project (L-162; docs/game_systems_spec.md, \"Kits\"): which kit and\nversion added which IDs, for its update and its removal. Not written while empty.","type":"array","items":{"$ref":"#/$defs/KitAdded"}},"wordsByDay":{"description":"The story's word count at the end of each day it was edited (`YYYY-MM-DD`): the story\nstatistics' words per day.","type":"object","additionalProperties":{"type":"integer","format":"uint32","minimum":0}},"ai":{"description":"The project's style guide for AI (docs/ai_spec.md \"Style guide\").","$ref":"#/$defs/AiStyle"}},"required":["preset"]},"Preset":{"type":"string","enum":["choice_story","visual_novel","point_and_click","gamebook","single_hero_rpg","party_rpg"]},"Onboarding":{"type":"object","properties":{"completed":{"type":"array","items":{"type":"string"},"default":[]},"dismissed":{"type":"boolean","default":false}}},"Position":{"type":"object","properties":{"x":{"type":"number","format":"double"},"y":{"type":"number","format":"double"}},"required":["x","y"]},"Folder":{"type":"object","properties":{"name":{"type":"string"},"ids":{"type":"array","items":{"type":"string"}}},"required":["name","ids"]},"Label":{"description":"A passage label (\"Draft\", \"Needs art\"): never seen by players or in the book.","type":"object","properties":{"id":{"description":"`lbl_…`","type":"string"},"name":{"type":"string"},"color":{"description":"A CSS colour (`#rrggbb`).","type":"string"}},"required":["id","name","color"]},"TestState":{"description":"A named, shared starting state for playtests.","type":"object","properties":{"id":{"description":"`tst_…`","type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"base":{"$ref":"#/$defs/TestStateBase"},"origin":{"$ref":"#/$defs/TestStateOrigin"},"overlay":{"$ref":"#/$defs/TestStateOverlay"},"meta":{"description":"Endings found, achievements, text seen.","anyOf":[{"$ref":"#/$defs/MetaState"},{"type":"null"}]}},"required":["id","name","base","origin","overlay"]},"TestStateBase":{"anyOf":[{"$ref":"#/$defs/ProjectStart"},{"type":"object","properties":{"testStateId":{"type":"string"}},"required":["testStateId"]}]},"ProjectStart":{"type":"string","enum":["project_start"]},"TestStateOrigin":{"anyOf":[{"$ref":"#/$defs/OriginKind"},{"type":"object","properties":{"fastForwardTo":{"type":"string"}},"required":["fastForwardTo"]}]},"OriginKind":{"type":"string","enum":["by_hand","captured"]},"TestStateOverlay":{"description":"Every field optional; records keyed by ID merge key by key, lists replace.","type":"object","properties":{"values":{"type":["object","null"],"additionalProperties":{"$ref":"#/$defs/Scalar"}},"characters":{"type":["object","null"],"additionalProperties":{"$ref":"#/$defs/CharacterOverlay"}},"party":{"type":["array","null"],"items":{"type":"string"}},"inventory":{"type":["array","null"],"items":{"$ref":"#/$defs/ThingQty"}},"knowledge":{"anyOf":[{"$ref":"#/$defs/KnowledgeOverlay"},{"type":"null"}]},"modules":{"description":"L-197 (format version 5): each module's part, a JSON merge patch on its slot\n(Collections: `{\"revealed\": {entry: sections}}`).","type":["object","null"],"additionalProperties":true},"storages":{"description":"A chest, saddlebags: storage → what it holds.","type":["object","null"],"additionalProperties":{"type":"array","items":{"$ref":"#/$defs/ThingQty"}}},"mounts":{"description":"Rider → mount (`null`: on foot, over a base that has them ride).","type":["object","null"],"additionalProperties":{"type":["string","null"]}},"outfits":{"description":"Character → outfit worn (`null`: their own look, over a base that dresses them).","type":["object","null"],"additionalProperties":{"type":["string","null"]}},"screen":{"description":"Tint, filter and weather.","anyOf":[{"$ref":"#/$defs/ScreenState"},{"type":"null"}]},"noEncounters":{"description":"*No encounters on the way*: no battle comes by chance (L-63).","type":["boolean","null"]},"clock":{"description":"Time (P6-09): the clock, in minutes since day 1, 0:00.","type":["integer","null"],"format":"uint64","minimum":0},"weather":{"description":"Weather (P6-10): a weather kind's ID.","type":["string","null"]}}},"CharacterOverlay":{"type":"object","properties":{"base":{"type":["object","null"],"additionalProperties":{"$ref":"#/$defs/Scalar"}},"level":{"type":["integer","null"],"format":"uint32","minimum":0},"xp":{"type":["number","null"],"format":"double"},"skillPoints":{"type":["integer","null"],"format":"uint32","minimum":0},"statPoints":{"type":["integer","null"],"format":"uint32","minimum":0},"skills":{"type":["array","null"],"items":{"$ref":"#/$defs/SkillState"}},"statuses":{"type":["array","null"],"items":{"$ref":"#/$defs/StatusState"}},"equipment":{"description":"`null` = empty slot.","type":["object","null"],"additionalProperties":{"type":["string","null"]}},"secondSet":{"description":"P8-87: the second set kept at hand to swap to in a dice battle (slot ID → thing ID;\n`null` = none in that slot).","type":["object","null"],"additionalProperties":{"type":["string","null"]}}}},"SkillState":{"type":"object","properties":{"skillId":{"type":"string"},"rank":{"type":"integer","format":"uint32","minimum":0}},"required":["skillId","rank"]},"StatusState":{"type":"object","properties":{"statusId":{"type":"string"},"remaining":{"type":["integer","null"],"format":"uint32","minimum":0}},"required":["statusId"]},"KnowledgeOverlay":{"description":"`Partial<Knowledge>`.","type":"object","properties":{"passageVisits":{"type":["object","null"],"additionalProperties":{"type":"integer","format":"uint32","minimum":0}},"exitsUsed":{"type":["array","null"],"items":{"type":"string"}},"thingsObtained":{"type":["array","null"],"items":{"type":"string"}},"thingsRead":{"type":["array","null"],"items":{"type":"string"}},"enemiesSeen":{"type":["array","null"],"items":{"type":"string"}},"enemiesDefeated":{"type":["object","null"],"additionalProperties":{"type":"integer","format":"uint32","minimum":0}},"charactersMet":{"type":["array","null"],"items":{"type":"string"}}}},"ScreenState":{"description":"What `screen` steps left in place.","type":"object","properties":{"tint":{"anyOf":[{"$ref":"#/$defs/Tint"},{"type":"null"}]},"weather":{"anyOf":[{"$ref":"#/$defs/Weather"},{"type":"null"}]},"filter":{"anyOf":[{"$ref":"#/$defs/ScreenFilter"},{"type":"null"}]},"variant":{"description":"The look variant a `screen` step chose (L-48).","type":["string","null"]},"camera":{"description":"The camera's framing of the scene picture (L-37; none: the whole picture).","anyOf":[{"$ref":"#/$defs/Camera"},{"type":"null"}]}}},"Camera":{"description":"The camera's framing (L-37): `zoom` times as close, centred on the point `x`, `y` of the\nscene picture (fractions of its width and height).","type":"object","properties":{"zoom":{"description":"1–4.","type":"number","format":"double"},"x":{"description":"0–1, from the left.","type":"number","format":"double"},"y":{"description":"0–1, from the top.","type":"number","format":"double"}},"required":["zoom","x","y"]},"MetaState":{"description":"Per browser and game, across playthroughs.","type":"object","properties":{"endingsFound":{"type":"array","items":{"type":"string"},"default":[]},"stepsSeen":{"description":"Text steps shown in any playthrough (skip read text).","type":"array","uniqueItems":true,"items":{"type":"string"},"default":[]},"values":{"description":"Game values kept across playthroughs (L-88), by value ID.","type":"object","additionalProperties":{"$ref":"#/$defs/Scalar"}},"modules":{"description":"L-197 (format version 5): each module's part kept across playthroughs, by module ID\n(Collections' `acrossPlaythroughs` entries in `collections.revealed`). Not written while\nempty.","type":"object","additionalProperties":true},"picturesSeen":{"description":"L-31: pictures shown by picture steps in any playthrough (asset IDs; the gallery).","type":"array","items":{"type":"string"}},"musicHeard":{"description":"L-31: music tracks heard in any playthrough (asset IDs; the music room).","type":"array","items":{"type":"string"}},"chaptersReached":{"description":"L-31: chapters reached in any playthrough, each with the passage it was first entered at\n(chapter select).","type":"object","additionalProperties":{"type":"string"}}}},"KitAdded":{"description":"A kit added to a project and what it added.","type":"object","properties":{"kitId":{"description":"The kit (`kit_…`).","type":"string"},"version":{"type":"integer","format":"uint32","minimum":0},"name":{"description":"Its name when added (a kit deleted from the workspace stays named).","type":"string"},"ids":{"description":"The IDs it added (each a new one in the project).","type":"array","items":{"type":"string"}},"from":{"description":"Every ID it brought (its ID in the project) with its ID in the kit: a newer version's item\nreplaces the one it came from, and keeps its IDs.","type":"object","additionalProperties":{"type":"string"}},"items":{"description":"Each top-level item it added (a value, a passage, a thing …) by ID, with a fingerprint of\nit as added: its removal takes only what nobody changed since.","type":"object","additionalProperties":{"type":"string"}},"open":{"description":"Its open ways: the exits (new IDs) the creator connects to the story; while one leads\nnowhere it is the warning `kit.unconnected`.","type":"array","items":{"$ref":"#/$defs/OpenWay"}},"renamed":{"description":"Formula names it brought that were taken, and the names they got (`reputation` →\n`reputation_2`).","type":"object","additionalProperties":{"type":"string"}}},"required":["kitId","version","name","ids"]},"OpenWay":{"description":"An open way of an added kit: its exit and what it is for.","type":"object","properties":{"exitId":{"type":"string"},"label":{"type":"string"}},"required":["exitId","label"]},"AiStyle":{"description":"What AI requests add to every request of their kind (docs/ai_spec.md \"Style guide\"); in the\nMVP the picture style.","type":"object","properties":{"visual":{"description":"Added to every picture request (\"watercolour, muted blues, soft light\").","type":["string","null"]}}}}}