Interact — text template

Inside an ```interact block, declare a plain-text output template with template stl: — embed control values into STL or any text and display them live. The "output side" of Interact controls — the most common and simplest template type.


When to use

  • ✅ Lightweight calculators (substitute slider/input values into a text result)
  • ✅ Configuration preview ("you selected = ..." live echo)
  • ✅ STL node dynamic generation (drag a slider, change a node's confidence / description)
  • ✅ Teaching formula echo (input → formula → result)
  • ❌ Need a chart → use Vega-Lite template
  • ❌ Need animation / SVG → use SVG template
  • ❌ Complex layout / multiple sections → split into multiple interact blocks or use Layout

Basic syntax

\```interact
slider x 0 10 5 1
template stl:
[Selected value] -> [{x}]
\```

template <type>: declares the template type + colon. Everything after the colon is template content. {var} is a placeholder.

Renders: a slider with a live STL line below: [Selected value] -> [5]. Drag → number changes.


Template types

Type Use Doc
template stl: Output STL statements / arbitrary plain text This page
template vega-lite: Output a live chart (Vega-Lite spec) Interact + Vega-Lite
template svg: Output an SVG scene SVG scenes

The "stl" type name is historical — it doesn't only output STL, it can output any text. The [A] -> [B] in the template is just text; it isn't actually parsed into STL nodes (unless you later feed the rendered output into STG).


Placeholder syntax {...}

Inside the template, { } wraps an expression that's evaluated live.

1. Direct variable reference

template stl:
[Weight] -> [{weight}]
[Name] -> [{name}]
[Active] -> [{enabled}]

2. Expressions

template stl:
[BMI] -> [{weight / (height * height)}]
[Discounted price] -> [{price * (1 - discount)}]

The mini DSL supports (see Computed for full details):

  • Arithmetic: + - * / % **
  • Comparison: == != < > <= >=
  • Logical: && || !
  • Ternary: cond ? a : b
  • Functions: pow(a, b) sqrt(x) abs(x) min(...) max(...) sin(x) cos(x) tan(x) log(x) exp(x) floor(x) ceil(x) round(x)
  • Constants: pi e

3. Format spec :fmt

template stl:
[BMI] -> [{bmi:.1f}]                ← 1 decimal place
[Price] -> [${price:.2f}]           ← 2 decimals (money)
[Percent] -> [{(rate*100):.1f}%]    ← convert to percentage
[Sci] -> [{value:.3e}]              ← scientific
[Int] -> [{count:.0f}]              ← 0 decimals (force int)
[Width] -> [{x:>10.2f}]             ← right-aligned 10-char wide + 2 decimals

Format spec syntax mirrors Python f-strings: {value:[align][width][.precision][type]}

Type Meaning Example
f float {x:.2f}
e scientific {x:.3e}
d int (force) {x:d}
s string {name:s}
% percent (auto ×100) {rate:.1%}

4. Escaping {{ }}

To output a literal { or } in the template, use double braces:

template stl:
JSON literal = {{"key": "value"}}     ← outputs {"key": "value"}

Examples

Example 1: pure echo

\```interact
slider x 0 100 50 1
template stl:
[Current value] -> [{x}]
\```

Renders: slider + one line "Current value = 50"; live update on drag.

Example 2: multi-line STL output + formatting

\```interact
slider weight 40 120 70 1
slider height 1.4 2.1 1.7 0.01
template stl:
[Weight] -> [{weight} kg]
[Height] -> [{height:.2f} m]
[BMI] -> [{(weight / (height * height)):.1f}] ::mod(category="{(weight / (height * height)) < 18.5 ? "Underweight" : (weight / (height * height)) < 24 ? "Normal" : (weight / (height * height)) < 28 ? "Overweight" : "Obese"}")
\```

Renders: 3 lines of live STL output. Line 3's category uses nested ternaries to display BMI category. For repeated expressions, refactor to computed derived values.

Example 3: free text template (not STL)

\```interact
input name "Alice"
slider age 1 100 30 1
select role "Student" "Engineer" "Teacher" "Other"
template stl:
Hello, {name}!

You're a {age}-year-old **{role}**.

Next year you'll be {age + 1}.
\```

Renders: a free-text template (not constrained to STL form). The "stl" type name is really "plain text."

Example 4: configuration preview

\```interact
input projectName "my-app"
select stack "Next.js" "Astro" "SvelteKit"
toggle typescript true
toggle eslint true
template stl:
**Project config preview**:

\```bash
npx create-{stack:s} {projectName}{typescript ? " --typescript" : ""}{eslint ? " --eslint" : ""}
\```
\```

Renders: form → live-assembled command line. toggle with ternary appends flags conditionally.


Plain-text fallback behavior

```interact blocks render as code blocks in non-supporting readers. Template content preserves {var} literals — readers see the template source + control declarations, fully understanding the original document's intent.

\```interact
slider x 0 10 5 1
template stl:
[Selected value] -> [{x}]
\```

→ Plain-text reader sees the above (with {x} placeholder), knows "x is a dynamic value here."

Reader Render
Rho Full interaction + template live-evaluation
GitHub web Code block ({x} literal visible)
Obsidian Same
VS Code default preview Same
cat / less Plain text

Common pitfalls

1. Reference an undeclared variable

\```interact
slider x 0 10 5 1
template stl:
[Result] -> [{y}]      ← ❌ y not declared
\```

→ Template outputs {y} literal or throws. All variables in template must first be declared via slider/input/select/toggle/computed.

2. Wrong format spec

template stl:
[BMI] -> [{bmi:.1}]      ← ❌ Missing type char (should be .1f / .1e)
[BMI] -> [{bmi:.1f}]     ← ✅
[BMI] -> [{bmi:f}]       ← ⚠️ Default 6 decimals; may be too many
[BMI] -> [{bmi:.1f}]     ← ✅ 1 decimal

Format specs require a type char (f / e / d / s / %).

3. Expressions with unescaped nested quotes

template stl:
[Label] -> [{name == "Alice" ? "Admin" : "User"}]    ← ❌ template's " conflicts with outer

→ The " in the template clashes with the outer STL string semantics — undefined behavior. Improvement: use single quotes in the mini DSL (if supported), or pre-compute in computed and reference the computed name.

4. Deep nesting with callout / layout

:::card
\```interact
slider x 0 10 5 1
template stl:
[Selected] -> [{x}]
\```
:::

✅ Legal. But the interact block's height changes with template output length. Keep template output line count stable or give the container a fixed min-height.

5. Template output contains markdown special chars

template stl:
[Selected] -> [{x}]      ← `[` `]` are markdown link syntax

In practice, usually fine — Rho renders template output as a fenced code block result, not triggering markdown link parsing. But watch out for * _ and other emphasis chars in template output.

6. Trying to chart with stl template

template stl:
draw a bar chart: {...}      ← ❌ stl template doesn't render charts

→ stl template outputs plain text only, no graphical rendering. For charts use template vega-lite: (see Interact + Vega-Lite).

7. Template output expects markdown rendering

template stl:
**bold** and *italic*     ← ❌ These chars output as literals, not bold/italic

→ Template defaults to plain-text output, no further markdown rendering. Some reader implementations support template html: or template markdown:, but not universal — stick to plain text for safety.


See also