Skip to content

Helpers reference

Squiffy uses Handlebars as its text processing engine, providing a powerful set of helpers for dynamic content. This page is a quick reference for all available helpers.

Squiffy processes all text through Handlebars, which means you can use:

  • Double curly braces {{}} to output values and call helpers
  • Block helpers with {{#helper}}...{{/helper}} syntax
  • Comments with {{! comment text }}
  • Markdown formatting (converted to HTML automatically)

Understanding parentheses vs double brackets

Section titled “Understanding parentheses vs double brackets”

When working with helpers, you’ll encounter two different bracket types:

Double brackets {{}} - Output values or call helpers:

{{score}} - Display an attribute
{{set "score" 100}} - Call a helper
{{#if has_key}}...{{/if}} - Block helper

Parentheses () - Subexpressions (helper arguments):

When you need to pass the result of one helper as an argument to another helper, use parentheses:

{{#if (and has_key door_locked)}}Can unlock{{/if}}
{{random (array "red" "green" "blue")}}
{{#if (eq status "complete")}}Done{{/if}}

In these examples:

  • (and has_key door_locked) - The and helper returns true/false, which becomes the condition for if
  • (array "red" "green" "blue") - The array helper creates an array, which is passed to random
  • (eq status "complete") - The eq helper returns true/false for the if condition

Why not {{#if {{and ...}}}}?

You cannot nest {{}} inside {{}} - that’s invalid Handlebars syntax. Use parentheses for subexpressions:

❌ Wrong: {{#if {{and has_key door_locked}}}}...{{/if}}
✅ Right: {{#if (and has_key door_locked)}}...{{/if}}
❌ Wrong: {{random {{array "a" "b" "c"}}}}
✅ Right: {{random (array "a" "b" "c")}}

Nesting subexpressions:

You can nest parentheses to combine multiple helpers:

{{#if (and (gt score 100) (not game_over))}}
You have a high score and the game is still running!
{{/if}}

Here, (gt score 100) and (not game_over) are evaluated first, then their results are passed to and, and finally the result of and is passed to if.

See Attributes for detailed documentation and examples.

HelperDescriptionExample
{{attribute}}Display attribute value (single-word names, always gets latest value){{score}}
{{get "name"}}Get attribute value (for multi-word names or dynamic attribute names from expressions){{get "player name"}}
HelperParametersDescriptionExample
{{set}}"attribute" valueSet attribute to a value{{set "score" 100}}
{{unset}}"attribute"Set attribute to false{{unset "has_key"}}
{{inc}}"attribute" [amount]Increment by 1 or specified amount{{inc "score"}} or {{inc "score" 10}}
{{dec}}"attribute" [amount]Decrement by 1 or specified amount{{dec "health"}} or {{dec "health" 5}}

See Attributes for examples.

HelperDescriptionExample
{{eq a b}}Returns true if a equals b{{#if (eq status "complete")}}Done{{/if}}
{{ne a b}}Returns true if a not equals b{{#if (ne health 0)}}Still alive{{/if}}
{{gt a b}}Returns true if a > b{{#if (gt score 100)}}High score!{{/if}}
{{gte a b}}Returns true if a >= b{{#if (gte level 5)}}Advanced{{/if}}
{{lt a b}}Returns true if a < b{{#if (lt health 20)}}Low health{{/if}}
{{lte a b}}Returns true if a <= b{{#if (lte age 18)}}Minor{{/if}}

See Attributes for examples.

HelperDescriptionExample
{{and ...}}Returns true if all arguments are truthy{{#if (and has_key door_locked)}}Can unlock{{/if}}
{{or ...}}Returns true if any argument is truthy{{#if (or is_admin is_moderator)}}Has powers{{/if}}
{{not value}}Negates a boolean value{{#if (not game_over)}}Continue{{/if}}

See Attributes for examples.

HelperParametersDescriptionExample
{{seen}}"name"Check if section/passage has been visited{{#if (seen "intro")}}Welcome back{{/if}}
{{at}}"name" or (array ...)Check if currently at a specific section{{#if (at "ending")}}Game over{{/if}}

See Attributes for examples.

HelperParametersDescription
{{section}}"name" [text="..."] [set="..."]Create a section link with optional custom text and attribute changes
{{passage}}"name" [text="..."] [set="..."]Create a passage link with optional custom text and attribute changes

Example:

{{section "next_room" text="Enter" set="visited=true, count+=1"}}
HelperParametersDescriptionExample
{{embed}}"name"Embed text from another section or passage{{embed "description"}}
{{array}}item1 item2 ...Create an array for use with other helpers{{array "red" "green" "blue"}}

See Attributes for embed examples.

These helpers let you manage arrays stored in attributes - useful for tracking items, available options, or game state.

HelperParametersDescriptionExample
{{array}}item1 item2 ...Create an array{{set "items" (array "a" "b" "c")}}
{{append}}"attribute" valueAppend value to array stored in attribute{{append "inventory" "sword"}}
{{prepend}}"attribute" valuePrepend value to array stored in attribute{{prepend "queue" "urgent"}}
{{pop}}"attribute"Remove and return first element from array{{set "next" (pop "queue")}}
{{remove}}"attribute" valueRemove first matching value from array{{remove "inventory" "key"}}
HelperParametersDescriptionExample
{{contains}}"attribute" value or (array ...) valueCheck if array contains value{{#if (contains "inventory" "key")}}...{{/if}}
{{length}}"attribute" or (array ...)Get number of elements in array{{length "inventory"}}

Track available game rounds:

{{!-- Initialize available rounds --}}
{{set "rounds" (array "Quiz" "Challenge" "Bonus")}}
{{!-- Pick a random round --}}
{{set "current" (random rounds)}}
You're playing: {{current}}
{{!-- Remove it so it can't be picked again --}}
{{remove "rounds" current}}
{{!-- Check if more rounds remain --}}
{{#if (gt (length "rounds") 0)}}
[[Play next round]]
{{else}}
[[Final round]]
{{/if}}

Manage an inventory:

{{set "inventory" (array)}}
[pick up sword]:
{{append "inventory" "sword"}}
You picked up the sword.
[use key]:
{{#if (contains "inventory" "key")}}
{{remove "inventory" "key"}}
You used the key.
{{else}}
You don't have a key.
{{/if}}

Process a queue:

{{set "tasks" (array "Task A" "Task B" "Task C")}}
[next task]:
{{#if (gt (length "tasks") 0)}}
Now doing: {{pop "tasks"}}
{{else}}
All tasks complete!
{{/if}}

See Dynamic text for detailed documentation and examples.

HelperParametersDescription
{{random}}(array ...) [set="attribute"]Select a random item from an array, optionally storing the result

Example:

The weather is {{random (array "sunny" "cloudy" "rainy") set="weather"}}.
HelperParametersDescription
{{#animate}}...{{/animate}}"effect" [trigger="link"] [style="..."] [loop=true]Animate text with visual effects

Available effects:

  • typewriter - Text appears character by character
  • toast - Text slides in from bottom
  • fadeIn - Text fades in
  • continue - Clickable link that pauses animation queue

Example:

{{#animate "typewriter"}}This text appears gradually.{{/animate}}
HelperParametersDescription
{{#label}}...{{/label}}"name"Create a labeled span that can be replaced later
{{replace}}"label" [text]Replace the content of a labeled span

Example:

I bought {{#label "item"}}milk{{/label}}.
[change]:
{{replace "item"}}bread{{/replace}}
HelperParametersDescription
{{rotate}}(array ...) [set="attribute"] [show="next"]Create a cycling link that rotates through options infinitely
{{sequence}}(array ...) [set="attribute"] [show="next"]Create a sequence link that disables after the last option

Example:

Size: {{rotate (array "small" "medium" "large") set="size"}}
HelperParametersDescription
{{live}}"attribute" [section="name"] [passage="name"]Display attribute value that updates automatically when the attribute changes

Example:

Score: {{live "score"}}

The section and passage parameters let you display processed content from another section/passage that updates when the attribute changes:

{{live "category" section="categoryDescription"}}

In addition to Squiffy’s custom helpers, you have access to standard Handlebars block helpers:

HelperDescriptionExample
{{#if}}...{{/if}}Conditional content{{#if has_key}}You have a key{{/if}}
{{#if}}...{{else}}...{{/if}}Conditional with fallback{{#if alive}}Living{{else}}Dead{{/if}}
{{#if}}...{{else if}}...{{/if}}Multiple conditions{{#if (gt score 100)}}High{{else if (gt score 50)}}Medium{{else}}Low{{/if}}
{{#unless}}...{{/unless}}Inverted conditional{{#unless game_over}}Keep playing{{/unless}}
{{#each}}...{{/each}}Iterate over arrays (advanced usage)Not commonly used in Squiffy

Squiffy has two ways to modify attributes:

Execute when a section or passage loads, before any rendering:

@set score = 100
@inc counter
@dec health
@unset flag
  • Always execute, regardless of any {{#if}} conditions in the text
  • Run once when the section/passage loads
  • Cannot be used inside conditionals

Execute during rendering, at the point where they appear in the text:

{{set "score" 100}}
{{inc "counter"}}
{{dec "health"}}
{{unset "flag"}}
  • Respect {{#if}} conditions - only execute if the condition is true
  • Run at render time, when that part of the text is processed
  • Can be used inside conditionals and helpers

When to use each:

  • Use directives for unconditional changes when a section/passage loads
  • Use helpers for conditional changes that depend on {{#if}} or other conditions

Advanced users can define custom Handlebars helpers in the @ui section using JavaScript. See the examples directory for examples of custom animations and helpers.