Skip to content

Prose & Text

Prose styling, interpolation and sanitization rules, and click-to-continue/text transitions.

Prose Styling

Ana provides several macros for styling prose content beyond simple $variable interpolation.

Paragraphs and line flow

Ana groups passage-body text into paragraphs the same way Markdown does:

  • Consecutive non-blank lines join into one paragraph, soft-wrapped together with a single space between them. Write your prose across as many source lines as you like for readability; the reader sees one flowing paragraph.
  • A blank line ends the current paragraph and starts a new one. Consecutive blank lines collapse to a single break, so you'll never get empty paragraphs.
  • Block-level content always breaks the flow. Headings, (table:), (panel:), images, --- rules, (div:)/(text-align:) containers, form/dialog widgets, and similar always flush whatever paragraph is open and stand alone, then prose resumes its own paragraph afterward.
  • (each:) / (if:) / (elseif:) / (else:) / @hook injections are transparent to paragraph flow. They don't introduce paragraph breaks of their own. Whether their content joins the surrounding paragraph or starts a new one is decided purely by the blank lines (or block-level content) inside their bodies, exactly as if that content had been written inline at the call site.

This last point matters in practice: a one-line loop body like

ana
(each: _t in (theme-list:))[- _t]

produces one flowing paragraph listing every item, soft-wrap-joined, rather than one separate paragraph per iteration. If you want each iteration on its own line, put a (br:) (or a blank line, to start a fresh paragraph each time) inside the loop body instead.

The one rule that predicts all of this

You'll sometimes see two macros that look identical in form, like (text-style: "bold")[bold] and (h3: "Heading"), behave completely differently when placed on consecutive lines: three (text-style:) lines merge into one paragraph, but three (h3:) lines stay as three separate headings. It looks like an inconsistency, but it comes straight from how Markdown works. Once you understand why, you can predict every macro's behavior:

Does the macro render as an inline <span>, or as a block element (<div>, <h1><h6>, <table>, etc.)? Inline output joins the surrounding flow. Block output always stands alone. That's the only thing that decides it: not which line you wrote it on, not whether it's inside a loop, nothing else.

This is exactly how Markdown itself behaves. Markdown just signals the difference through different syntax (**bold**/*italic* for inline vs. # Heading for block), while Ana expresses both through the same uniform (macro: args)[block] call shape. The macro's output, not its call syntax, determines which rule applies:

Renders asMacrosWhat that means for flow
inline <span>(text-style:) (text-color:) (text-opacity:) (text-size:) (font:) (text-rotate:) (text-rotate-x:) (text-rotate-y:) (span:)Joins the surrounding paragraph, like Markdown's **bold**/*italic*. Write three of these on three consecutive lines and you get one soft-wrapped paragraph, exactly as three consecutive emphasis lines would in Markdown.
block element (<div>, <h1><h6>, <table>, <hr>, …)(text-align:) (div:) (h1:)(h6:) (table:) (panel:) images, ---, form/dialog widgetsAlways flushes and stands alone, like a Markdown heading. Always its own paragraph, regardless of what's on the lines around it.

If you want a gallery of (text-style:)/(text-color:)/etc. demos to render as visually separate blocks, put a blank line between them, the same thing you'd do to keep consecutive **bold** lines from merging in plain Markdown. Writing them back-to-back with no blank line correctly merges them into one flowing paragraph; that is the intended, Markdown-faithful behavior.

ana
(text-style: "bold")[Roses are red,]

(text-style: "italic")[Violets are blue.]

You can also use (br:) to force a manual line break within a paragraph, for when you want visual line breaks but the lines are conceptually one block:

ana
(text-style: "bold")[Roses are red,]
(br:)
(text-style: "italic")[Violets are blue.]

Markdown shortcuts (inline in prose)

These work on any prose line in a passage body:

This is **bold text** in a sentence.
This is *italic text* in a sentence.
This word is ~~crossed out~~.
This is ==highlighted==.
This is `inline code`.

---

The last example (--- on its own line) renders an <hr> separator.

Limitation: Markdown spans cannot contain inline macros. For formatted text with macros inside, use (text-style:) instead.

Inline code

`inline code` renders as <code> and is shown verbatim: $variables and _temp names inside backticks are not interpolated, so you can write example Ana syntax like `(set: $player.gold to 10)` and have it display exactly as typed.

Fenced code blocks

Wrap a run of lines in triple backticks to render a <pre><code> block, useful for showing multi-line Ana syntax or other code samples in documentation-style passages:

```
(set: $player.hp to 10)
(add: $player.hp, 5)
```

An optional language tag right after the opening backticks is added as a language-<tag> class on the <code> element (for use with syntax-highlighting CSS/JS you supply):

```ana
(goto: MainStreet)
```

Like inline code spans, fenced code blocks are rendered completely verbatim: no $variable/_temp interpolation, no inline formatting, no inline macros. The block always stands on its own (it flushes any open paragraph), the same way a heading or (table:) does.

Bullet and numbered lists

Start a line with -, *, or 1. (any number followed by a period) to build a list. A run of consecutive list-marker lines becomes one <ul> or <ol>:

- Beer
- Iron Knife
- Torch

1. Pick a tab
2. Click an item
3. Read the detail pane

Whether the list renders as bullets (<ul>) or numbers (<ol>) is decided by the first item's marker: -/* produce an unordered list, N. produces an ordered list.

List items support the same inline content as a regular prose line: bold/italic/strike/highlight/code spans, $variable interpolation, _temp names, and inline macros all work:

ana
- Current gold: $player.gold
- **Important:** talk to the bartender first
- Roll result: (dice: 1, 6)

Indent a line further than the item above it to nest a sublist inside that item:

- Town
    - Tavern
    - Market
        - Butcher
        - Baker
- Countryside

Like fenced code blocks, lists are always block-level: they flush any open paragraph and stand on their own.

Styling macros (beyond markdown)

When the markdown shortcuts above aren't enough, when you need to combine effects, animate, align, or run macros inside styled content, reach for the block-styling macros. Their key advantage over the **bold** shortcut is that the block body supports full macro execution ((if:), (each:), interpolation):

ana
(text-style: "bold")[You have (count: $inv, "beer") beers.]
(text-style: "bold", "shudder")[DANGER!]          // styles combine

What's available, at a glance:

  • (text-style:): 31 named styles (bold/italic/underline families, strike variants, super/subscript, transforms like mirror/upside-down, textured outline/shadow/emboss, motion effects like shudder/sway, blur), combinable in one call.
  • (text-align:), (h1:)(h6:), (font:): alignment, semantic headings, and font family.
  • (text-color:), (text-opacity:), (text-size:), (text-rotate:): inline CSS-style spans.
  • (transition:) / (text-transition:): a one-shot entry animation on one block of content.

The block transition is not the same as the whole-zone click-to-continue transition (set with (default-transition: text, ...), covered below). Use (transition:) when a single piece of content within a passage should draw attention: a name change, a revealed clue, a consequence appearing after a delay.

Every style name, exact signatures, and CSS hooks: see Text, Prose Styling & Transitions in the reference.

Tooltips

To attach a hover/focus tooltip, add a tip, "text" pair to a (link:) or (img:) for a plain text tip, or wrap content in (tooltip:) with a nested (tip:) block for a rich tooltip that can include images. Both forms also show on keyboard focus and are themeable via --ana-tooltip-*.

ana
(link: "the locket", tip, "A tarnished silver locket.")[(goto: LocketScene)]

(tooltip:)[
    the strange potion
    (tip:)[(img: potion_red.png) Smells of cloves and something metallic.]
]

Text & Interpolation Rules

$variable interpolation happens when prose is rendered, not when macro arguments are evaluated. Concretely:

  • In prose (and inside block bodies [...]), write $player.name directly and it prints the value. (Never wrap it in curly braces; {$player.name} prints the literal braces.)
  • Inside a quoted string argument, $var is interpolated only if that macro renders its string as prose/notification text. For example, (notify: "You are in $world.location.") interpolates because the notification is displayed. A string you store in a variable stays literal: (set: _s to "Hello $world.location") keeps the $... text. To build a string from values, concatenate with +: (set: _s to "Hello " + $world.location).

Player-typed input is inert text. Values from (input:), (prompt:), and the other form macros are rendered with the browser's text APIs, so a player typing <script> or (goto: X) into a name field shows those characters literally; they are never executed as HTML or Ana. The one place raw HTML runs is (html: "..."), which is an explicit author opt-in: never feed player input into (html:).

Click-to-Continue & Text Transitions

Set a default text transition in GameInit and the text zone animates in on every navigation:

ana
(default-transition: text, typewriter)

Three modes:

ModeEffect
typewriterReveals text character by character (~30 ms/char).
dissolveAll paragraphs fade in together.
lineOne paragraph at a time, ~400 ms apart.

While text is animating the options zone is hidden; it appears when the animation finishes. Clicking anywhere in the text zone skips the remaining animation and reveals everything immediately; that's the "click to continue" behavior. No per-passage setup is needed beyond the one GameInit line.

This is distinct from (transition:) / (text-transition:), which animate one specific wrapped block at any time (see Prose Styling).