ReferenceReference

Variable reference

Look up variable declarations, scopes, storage, types, labels, input configuration, and availability.

Declaration shape

A mutable variable uses var. The optional mem modifier adds persistent storage where the variable would otherwise restart from its default:

var health = 100;
mem var charges = 5;

A calculated, read-only variable uses const:

const healthPercent = clamp((health / maxHealth) * 100, 0, 100);

App Main adds a scope before the declaration and requires a $ name:

player var $health = 100;
app const $eventComplete = $eventProgress >= $eventGoal;
host mem var $attempts = 0;

Every declaration ends with a semicolon.

Declaration keywords

var declares a mutable value. Sugar may assign a new value to it later.

mem modifies a local or hosted var declaration so JOI keeps its latest value. It is not a separate variable kind and cannot modify const.

const declares a value calculated from an expression. It cannot be assigned, reset, remembered, configured with with, or entered by the user. Random functions are not allowed in its expression.

App scopes

Every variable declared in App Main begins with one scope:

  • player gives each registered JOI a separate value.
  • app gives the App one value shared by everyone.
  • host provides the declaration separately to each linked Item or Boop.

The scope establishes ownership. The keywords after it still establish whether the declaration is mutable, persistent, or calculated.

Mutable Player and App values are persistent by definition, so those scopes do not use mem. A mutable Host value uses mem only when each host should keep its latest value.

An App supports up to 50 variables. App scopes cannot be used on declarations inside an Item, action, or Boop.

Types

Sugar normally infers the type from the initial value:

DeclarationRuntime value
var name = "Alex";str
var score = 10;number
var enabled = true;bool
var mode: choice = "first";The string, number, or boolean type used by its choices
var reward: Item;An Item object selected from inventory
var target: Joi = None;A JOI selected in chat
var targets: List<Joi> = ();A list of JOIs selected in chat
var target: Seat = None;A Session seat selected in chat
var targets: List<Seat> = ();A list of Session seats selected in chat
var art: Media = &cover;A Media resource value
var delay: Duration = Duration::minutes(15);A Duration value
var history = ("one", "two");A list value
`let transform: Fn =value

Scalar annotations are optional: str, number, and bool. The choice type and compound Item type select JOI-specific input controls. Joi, List<Joi>, Seat, and List<Seat> use JOI’s existing chat pickers. Date, Duration, Media, and Pronoun preserve their matching value type and cannot use input: true. Fn and lists containing Fn may only be held by execution-local let variables.

Scalar types are lowercase. Compound types are PascalCase.

In List<Joi>, List is the collection type and Joi is its type argument, meaning every entry is a Joi value. Read it as “list of JOIs.” Every Sugar type may be a type argument, including scalars and lists: List<number>, List<str>, List<bool>, and List<List<number>> are all valid.

Labels and with

Use the display arrow -> when the visible label should differ from the variable name:

var hp -> "Health" = 100;

Use with for input and display configuration:

mem var mood -> "Current mood": choice = "happy" with {
  input: true,
  required: true,
  choices: ("happy", "sad", "very_excited" -> "Very excited"),
};
SettingMeaning
inputShow a control before Sugar runs
requiredRequire an answer. This needs input: true
minLowest value accepted by a number input
maxHighest value accepted by a number input, or None for no maximum
choicesValues offered by a choice input
countExact or ranged number of entries for List<Joi> and List<Seat> inputs

A plain string choice such as "very_excited" receives the label Very excited. Write "very_excited" -> "Thrilled" to display a different label while keeping "very_excited" as its Sugar value. Values in a choice may be strings, numbers, or booleans, but one variable cannot mix those types. Its initial value must use the same type and appear in choices. The label after -> remains a string.

Joi and Seat inputs can limit their picker with a list expression:

var rival: Joi = None with input => true, required => true, choices => JOIS;
var rivals: List<Seat> = () with {
  input: true,
  required: true,
  choices: SEATS.filter(|seat| seat != SELF),
  count: 1..=3,
};

JOI accepts only values from that list when the action runs. count accepts 1 through 6 entries.

min and max constrain the numeric value held by one number variable. count constrains how many entries are held by one List<Joi> or List<Seat> variable. They do not configure the same thing.

Location and availability

Where a local declaration appears determines where its name is available:

LocationAvailability
Item top levelEvery custom action on that Item
Item actionOnly that action
Boop top levelThat Boop
Current program with letThat program; an action’s let values also reach its texts

An Item, Item action, or Boop supports up to 50 variables in each declaration scope.

An Item-level Memory variable belongs to one non-stackable Item. An action-level Memory variable belongs to that action. A Boop Memory variable is stored separately for each JOI using the Boop.

Stackable Items cannot remember variables because JOI cannot attach a separate value to each copy.

Storage

Storage follows from the declaration modifiers and App scope:

  • A local or hosted mutable variable restarts from its default unless it has mem.
  • A mutable Player value is stored separately for each registered JOI.
  • A mutable App value has one stored copy for the App.
  • A constant has no stored result and is recalculated from its expression.

For a hosted Memory variable, an Item stores the value on its individual instance. A Boop stores a separate value for each JOI using it. A linked creation can change its starting value with defaults.

If a person cancels a required confirmation, JOI saves none of the changes made by that run.

Assignments

Item action and Boop programs can assign:

  • Mutable local declarations
  • Mutable App declarations available in that context
  • let variables created by the current program

They cannot assign:

  • Constants
  • Item objects selected from inventory
  • App variables outside the current Automation scope
  • Variables supplied to an Embed Template by its caller

Conditions cannot assign outside variables. An Embed Template may change only the let variables it creates.

Names and value limits

Variable names contain up to 32 characters. They begin with a letter or underscore, followed by letters, numbers, or underscores. App names use the same rules after $.

str variables contain up to 2,000 characters. Lists and objects must stay within the collection limits.