Skip to content

Attributes

Attributes are variables that store information about your story’s state. You can use them to track things like player choices, scores, inventory, character relationships, and any other data that changes as the story progresses.

The simplest way to set an attribute is using the @set directive:

@set score = 1000
@set player_name = Alice

If the value is a number, it will be stored as a number, and true or false are stored as booleans. Otherwise, it will be stored as a string.

For boolean (true/false) values, to set as true:

@set has_key

and to set as false:

@set not has_key

or alternatively:

@unset has_key

For number values, you can increase or decrease by 1:

@inc score
@dec health

Or increase or decrease by other amounts:

@inc score 100
@dec health 5

You can set attribute values directly from section and passage links using a comma-separated list of assignments:

You can also use increment (+=) and decrement (-=) operators in link attributes:

These work both with @set and in links:

Syntax Meaning Example
a += n, a -= n Add or subtract a number @set coins += 5
a *= n, a /= n Multiply or divide by a number @set score *= 2
a = @b Copy the value of another attribute @set best_score = @score
a := text Set to some text, after processing any {{...}} in it @set greeting := Hello, {{name}}!

For example, this link copies the current score into final_score and doubles the bonus:

[[Finish]](ending, final_score=@score, bonus*=2)

The @set, @inc, @dec, and @unset directives run when a section or passage loads—they always execute regardless of any {{#if}} conditions in the text.

If you want to change an attribute conditionally (only when an {{#if}} condition is true), use the helper versions instead:

{{#if (seen "helped the wizard")}}
{{inc "reputation"}}
The wizard remembers your kindness.
{{else}}
The wizard eyes you suspiciously.
{{/if}}

The available helpers are:

  • {{set "attribute" value}} — set an attribute to a value
  • {{unset "attribute"}} — set an attribute to false
  • {{inc "attribute"}} — increase a number attribute by 1
  • {{inc "attribute" 5}} — increase by a specific amount
  • {{dec "attribute"}} — decrease by 1
  • {{dec "attribute" 3}} — decrease by a specific amount

These helpers produce no visible output—they only modify the attribute. The key difference from the @ directives is that they execute at render time, so they respect {{#if}} conditions.

You can display the value of an attribute using {{name}} (if the attribute name is all one word), or {{get "attribute name"}} for multi-word attributes or when the attribute name comes from an expression.

You chose {{gender}}.
Your full name is {{get "player name"}}.

Both {{attribute}} and {{get "attribute"}} always return the latest value, even if the attribute was just modified by a helper in the same section.

The main use for {{get}} is when you need to read an attribute whose name is stored in another variable. This enables dynamic attribute lookup:

In this example, {{get room}} looks up the value of room (e.g., “kitchen”), then uses that as the name of another attribute to retrieve (getting the description stored in the kitchen attribute).

You can also read a value using JavaScript:

var gender = squiffy.get("gender");

You can compare attribute values in {{#if}} and {{#unless}} conditions. See Conditions for the full list of operators.

Use = to check if two values are equal, and != to check if they’re not equal:

For number values, you can use:

  • a > b — greater than
  • a >= b — greater than or equal
  • a < b — less than
  • a <= b — less than or equal

You can combine conditions using and, or and not:

  • a and b — true if both are true
  • a or b — true if either is true
  • not a — true if a is not true

Each of these operators has an equivalent helper (eq, ne, gt, gte, lt, lte, and, or, not), which you can use anywhere, not just in conditions. For example, {{#if has_key and door_locked}} is the same as {{#if (and has_key door_locked)}}. See the Helpers reference for details.

You can check if the player has visited a section or passage using the {{seen}} helper. In this example, try clicking “cupboard” first to see the description of the closed cupboard. Then restart, and click “open” before “cupboard” to see the difference.

You can also use JavaScript:

if (squiffy.story.seen("passage3")) {
alert("You have seen passage3!");
}

The {{at}} helper checks if you’re currently at a specific section. It can take a single section name or an array of section names.

This helper is particularly useful in master sections or passages (see Master sections and passages), where you want to display different content depending on which section the player is in. It can also be useful when embedding text from another section.

In addition to the standard link syntax, you can create links programmatically using the {{section}} and {{passage}} helpers.

Creates a link to a section with optional custom text and attribute settings:

{{section "section_name" text="Link text" set="attribute=value, count+=1"}}

Creates a link to a passage with optional custom text and attribute settings:

{{passage "passage_name" text="Link text" set="visited=true"}}

Here’s a complete example showing how attributes can work together to create a food ordering system:

You can interact with attributes using JavaScript in any section or passage:

squiffy.set("attribute_name", value);
squiffy.set("score", 100);
squiffy.set("has_key", true);
var score = squiffy.get("score");
var hasKey = squiffy.get("has_key");

You can use the {{array}} helper to create arrays for use with other helpers like {{random}}, {{rotate}}, and {{at}}:

{{random (array "option1" "option2" "option3")}}
{{at (array "section1" "section2" "section3")}}

If an attribute holds an array, you can display one of its elements by index using Handlebars’ .[n] syntax. Indexes start at 0, so this shows the second element:

The second fruit is {{fruits.[1]}}.

See Dynamic text for more information on using arrays with dynamic content helpers.