6.2 KiB
Markup Guidelines
This file documents author-facing Ink tag conventions. The active parser normalizes tags into structured StoryTag objects before they reach the UI.
Implemented Tag Forms
Use bracket tags for titles, filenames, and longer text:
#chapter[Eibenreith]
#image[statue.png](square)
#music[Kaiserpunk Waltz.mp3](crossfade, loop, lead=8)
#sfx[church-bells.ogg](max=8, fade)
#score[You reached an ending.]
#achievement[First Steps]
#alert[Try examining the room.]
Use colon tags for short identifiers, categories, and choice keys:
#action:movement
#key:l
#sort:last
#gated:noble
Bare flags are accepted as tags with no value:
#optional
#auto
Right-Page Glossary Notes
Glossary notes are story tags scoped to the paragraph/block they belong to. They affect only the right-page story rendering, never choice text or command history.
The conductor points toward Eibenreith.
#gloss[Eibenreith](A fictional alpine town in the Kaiserpunk setting.)
The bracket value is the visible term to find. The parenthesized value is the note shown on hover/focus. The renderer marks every matching instance of the term in the same right-page block. The tag is not displayed and is not sent to TTS. Avoid raw Ink control characters in the explanation; |, {, and } must be escaped in Ink as \|, \{, and \} if they are needed literally.
TTS Reading Instructions
TTS instruction tags are story tags scoped to the paragraph/block they belong to. They are not rendered, and they are only sent to TTS providers that support per-request reading instructions. Currently this means OpenAI with gpt-4o-mini-tts.
„Ich habe nichts gesehen“, sagt Viktor.
#tts[Read softly, with controlled unease.]
The default form omits a provider and is the preferred authoring style. Providers that support instructions may consume it; providers that do not support instructions silently ignore it. Provider-specific instructions are only needed when two providers should receive different direction, or when an instruction must be hidden from all but one provider. They use the tag parameter position:
„Ich habe nichts gesehen“, sagt Viktor.
#tts[openai](Read softly, with controlled unease.)
The shorthand #tts-openai[...] is also accepted. #tts(...) is equivalent to providerless #tts[...] if parentheses read better in a local context. tts-1 and tts-1-hd ignore these instructions because the OpenAI speech endpoint only supports the instructions request parameter for gpt-4o-mini-tts.
Keep instructions short and describe performance rather than content. OpenAI's TTS guide recommends using gpt-4o-mini-tts when you need controllable delivery; useful instruction targets include tone, emotional range, intonation, speaking speed, accent, impressions, and whispering. Good examples:
#tts[Speak with restrained concern and a slower pace.]
#tts[Whisper the line with controlled urgency.]
#tts-openai[Use a dry, formal tone; avoid melodrama.]
Avoid repeating the full dialogue in the instruction. Put the words to be spoken in the story text, and use #tts only to describe how the provider should read that block.
Choice Metadata
Choice tags are placed on the Ink choice they belong to:
* [__Schaue__: Aus dem Fenster.]
#action:orientation
#key:l
Implemented choice metadata:
#key:x: reserves keyboard keyXfor the choice.#letter[x]: older equivalent for reserving keyboard keyX.#action:groupor#action[group]: assigns the choice to an invisible action group.#auto: hides the choice from the visible list and lets the UI choose it automatically when it is ready.
The current UI renders all non-auto choices in one visible list. Choices are first grouped by #action in the order each new action group appears in the authored choice list. Choices inside each group are randomized. Choices without #action form one final unlabelled group shown after all tagged groups. Explicit keys are assigned before automatic keys; choices without explicit keys receive 1 through 0, then A through Z in final visible order while skipping explicit keys. #optional choices are displayed italic. Grouping columns, #gated[...], and #sort[...] are documented authoring conventions or future metadata, not fully implemented UI behavior yet.
Auto choices are ordinary Ink choices, usually with no visible [...] choice text. Ink owns their availability and once-only behavior; the UI owns automatic selection and timing. Supported forms:
* {condition} #auto
-> event
* {condition} #auto(2)
-> event
* {condition} #auto[tunnel](2)
-> event
#auto fires as soon as it is the first ready auto choice. #auto(2) waits at least two UI choice turns since the previous global auto trigger. #auto[keyword](2) waits only against the same keyword, so unrelated auto groups do not throttle each other. Use the global form when two different authored events must not fire immediately after each other.
Popup And End-State Tags
These tags may appear as Ink global tags, paragraph tags, or empty tag-only lines. They are dispatched through the same tag channel as media tags.
#score[You reached the quiet ending.]
#error[The story ended unexpectedly.]
#achievement[First Steps]
#alert[Try examining objects before using them.]
#score[...]: intended ending. When the turn reachesinputMode: end, the UI shows a localized ending popup with the tag value as the optional message.#error[...]: unrecoverable ending. The UI shows a localized error popup with the tag value as the optional message. The Ink engine emits this automatically if Ink runs out of content without an explicit#score[...]or#error[...].#achievement[...]: queued localized achievement popup while the game continues.#alert[...]: queued localized player hint/tutorial popup while the game continues.
Existing Media And Structure Tags
#chapter[Title]
#section
#textblock
#image[filename.png](landscape)
#image[filename.png](portrait pause=2)
#image[filename.png](square lead=1.5)
#music[track.mp3](crossfade, loop, lead=4)
#sfx[file.ogg](max=8 fade fade-duration=2)
Asset filenames resolve relative to the configured image, music, and sound folders.