Checkpoint ink architecture updates

This commit is contained in:
2026-05-24 16:00:22 +02:00
parent 01c8b1aff6
commit 510901f5bf
14 changed files with 1218 additions and 643 deletions
+15 -3
View File
@@ -27,12 +27,24 @@ Ink source files and game UI localization files must be saved as UTF-8 and must
## Ink Authoring State
Use Ink's built-in visit state for simple facts such as "this knot has been shown". Do not create parallel boolean flags for knot visits. Use explicit LIST-based state chains only when the state has semantic order or knowledge progression, such as character-generation dependencies, relationship frames, evidence chains, or episode progress.
Use Ink's built-in visit state for simple facts such as "this knot has been shown". Do not create parallel boolean flags for knot visits.
Use a separate `LIST` with the `state_*` helpers whenever a tracker expresses a linear process, even if it has only two states such as "begun" and "completed". A later state in such a list is a high-watermark and implies the earlier states. Prefer several small parallel progress lists over one overpacked encounter state when that is cleaner for authoring, knowledge modelling, or NPC reasoning. This matches the Inkle-style knowledge-base pattern: independent lines of knowledge and progress advance separately, then content queries the combination.
Use `state_reach(first_state)` to begin a progress chain. Use `state_reach_if_started(later_state)` when a normal action can advance or complete a chain only if that chain is already active. This prevents generic actions such as washing hands or inspecting an object from retroactively starting a task they merely could have fulfilled.
Use `mark`, `has`, and `lacks` only for a coherent group of independent facts that can be true separately and do not imply one another.
Eibenreith authored content uses a mandatory bucket architecture. Rooms are installed through `enter_room(location, entry, look, exits, bucket)`. The active choice surface collects choices in this order: moment, room entry/look, exits, episode, game. Chosen atomic content ends with `-> TURN`; bucket/provider knots end with `-> DONE`. Authored chapter files must not call the internal `provide_choices` implementation directly.
`helpers.ink` owns global helper variables, helper functions, `TURN`, and active choice-surface dispatch. `buckets.ink` owns the game-wide bucket. Even when empty, `game_bucket` remains a real content bucket and must stay available for cross-episode game material.
Companion-aware dialogue should use Ink helpers instead of repeating location checks. `present(character)` checks whether an NPC is in the current room. `alone()` is true when no tracked NPC is present. `alone_with(character)` is true when exactly that tracked NPC is present, and is intended for private dialogue options.
Player-choice impact uses three distinct mechanisms. Cascades use semantic state chains when a choice changes the route, episode outcome, or later structure. Callbacks use named facts for exact remembered choices. Heuristics use route counters and relationship-matrix queries to color tone or summarize repeated patterns. Do not use a route heuristic when the later text needs to remember one specific earlier line.
When multiple choices from one prioritized family can appear on the same choice surface, use `claim_choice_gate(gate)` to allow only the first valid item in source order. This is mainly for `#auto` families such as Viktor return comments. The helper is transient and resets at the start of every `provide_choices`; it must not be used as story memory.
## Choice Text Perspective
Choice text must describe the player character's intention before the action is taken. Do not write choices from a post-hoc author perspective that reveals what the branch will discover. For example, use "try the door" before the destination is known, not "go to the second-class cars"; use automatic or hidden events for things the player character cannot control, such as the train entering a tunnel.
@@ -239,12 +251,12 @@ Choice tags:
- `#letter[x]`
- `#optional`
- `#action[name]`
- `#auto`, `#auto(2)`, `#auto[keyword]`, `#auto[keyword](2)`
- `#auto`, `#auto(2)`, `#auto:keyword`, `#auto:keyword(2)`
The active choice UI is one list. Explicit keys are reserved first, then remaining choices receive `1` through `0`, then `A` through `Z`.
Before key assignment, choices are ordered by invisible `#action` groups. The first appearance of each action group in the authored list determines group order. Choices inside each group are randomized for presentation. Choices without an action group form one final group shown last. Group labels are not displayed.
`#auto` marks an ordinary Ink choice that should not be rendered as a visible button. Auto choices still need a developer-facing bracket choice text, for example `[AUTO: Tunnelspiegelung]`, so the Ink remains testable in Inky. The browser selects the first ready auto choice when the choice surface becomes ready. Ink still owns availability and once-only behavior through normal choice syntax and conditions. A numeric parameter delays the trigger by UI choice turns since the last matching auto trigger. Without a keyword the delay is global; with a keyword it applies only to that keyword. Use global `#auto(n)` when different auto events must not happen back-to-back, and keyworded `#auto[name](n)` when only repeated events of the same class should be spaced out.
`#auto` marks an ordinary Ink choice that should not be rendered as a visible button. Auto choices still need a developer-facing bracket choice text, for example `[AUTO: Tunnelspiegelung]`, so the Ink remains testable in Inky. The browser selects the first ready auto choice when the choice surface becomes ready. Ink still owns availability and once-only behavior through normal choice syntax and conditions. A numeric parameter delays the trigger by UI choice turns since the last matching auto trigger. Without a keyword the delay is global; with a keyword it applies only to that keyword. Use global `#auto(n)` when different auto events must not happen back-to-back, and keyworded `#auto:name(n)` when only repeated events of the same class should be spaced out. Use the colon form for keyed auto tags on choice lines.
TTS instruction tags are paragraph/block metadata. They are ignored by renderers and by providers that do not support per-request reading instructions. Providerless `#tts[...]` and `#tts(...)` are the default authoring forms; provider-specific forms are optional filters for provider overrides. OpenAI consumes matching instructions only for `gpt-4o-mini-tts`, where they are sent as the Speech API `instructions` field. Instructions should describe delivery, such as tone, emotion, intonation, pace, accent, whispering, humming, or singing style.