Choosing a variable is easier when you make each decision separately:
- Does the value need a mutable name, a remembered name, or a calculation?
- Where should that name be available?
- If an App owns it, which scope should own the value?
Input controls and visible labels are separate configuration. They do not change the kind or scope of a variable.
Choose the declaration
Use let for a temporary value that only the current program needs:
let roll = Rand::pick(1..=20);
Use var for a mutable value. Without persistent storage, it starts from its default on each use:
var difficulty = 10;
Add mem when that local or hosted variable should keep its latest value:
mem var durability = 100;
Use const when the value should always be calculated from other values:
const damaged = durability < 50;
These keywords describe what the declaration does. Its location and optional App scope decide who can use it and who owns its value.
Choose the local location
A declaration without an App scope belongs to the module where it is written.
At the top level of an Item, it is available to every custom action on that Item. A Memory variable belongs to that individual non-stackable Item and travels with it.
Inside an Item action, it belongs only to that action. This is useful for an input or state that no other action needs.
At the top level of a Boop, it belongs to that Boop. Its Memory variables are stored separately for each JOI using it.
Use the narrowest location that contains every place where the variable is needed.
Add an App scope when several creations need it
An App declaration adds one scope before the declaration:
playergives each registered JOI a value shared across the App’s linked creations.appgives the entire App one shared value.hostprovides the declaration separately to each linked Item or Boop.
The rest of the declaration keeps the meaning it already had:
player var $reputation = 0;
app var $eventProgress = 0;
host mem var $attempts = 0;
Here, player, app, and host answer the ownership question. var still declares a mutable value, and mem still adds persistent storage where it is optional.
Player and App scopes are persistent by definition, so their mutable declarations do not use mem. In the Host scope, choose var for an execution value or mem var for a value stored by each host.
App variable names begin with $, making the source of the variable visible when linked code uses it.
Keep calculations in the right scope
A constant uses the same ownership decision:
const damaged = durability < 50;
player const $exhausted = $energy == 0;
app const $eventComplete = $eventProgress >= $eventGoal;
host const $mastered = $attempts >= 5;
Choose the scope from the values in the expression. A calculation about one Item stays local. A calculation about one JOI uses the Player scope. A calculation about shared App state uses the App scope.
Configure input separately
Add input: true only when the person running the creation should provide the value:
var mood: choice = "playful" with {
input: true,
choices: ("playful", "intense"),
};
The with block changes how JOI presents the declaration. It does not make the variable temporary, persistent, local, or App-owned.
Start with the declaration, place it in the narrowest useful location, and add an App scope only when the value must cross creation boundaries.