Sugar 2 changes more than the names of a few functions. Sugar 1 was a template language attached to visual forms. Sugar 2 is a programming language. An Item or Boop now keeps its executable definition together in one Code module, while an App keeps its shared variables, functions, defaults, mixins, interactions, and Sessions together in Main.
This guide focuses only on converting existing Sugar 1 creations. New capabilities with no Sugar 1 equivalent belong in the Learn Sugar guides, not in the migration path.
The central change: templates became programs
In Sugar 1, a Sugar text was ordinary text. Only the expressions between { and } ran as Sugar:
The result is: {result}, @1!
The result is: and , @1! were plain template text. {result} temporarily switched into Sugar to read the variable.
Sugar 2 still supports interpolation inside Sugar text, but the text itself is now an explicit declaration:
text "The result is: {result}, @1!";
Here, text declares a possible result, quotation marks create a string, {result} inserts a named value, and ; completes the declaration. Participant references such as @1 still work inside the quoted string. Unlike Sugar 1, Sugar 2 interpolation accepts names and property paths rather than arbitrary expressions; use positional formatting for a calculation.
| Sugar 1 | Sugar 2 |
|---|---|
| Plain text in a Sugar text field | A quoted string in a text declaration |
{name} inside that text | {name} inside the declared Sugar text |
A calculated {expression} | A positional {} followed by with expression |
| One visual Sugar text row | One text declaration |
| A separate condition field | text when condition { ... } |
| A variable form | A top-level var, mem var, or const declaration |
| An Item action form | An action name { ... } declaration in the same Code module |
Convert Sugar texts
A Sugar 1 result without an expression still needs to become code.
Before:
@1 hugs @2.
After:
text "@1 hugs @2.";
Keep named values in interpolation braces. Move calculations to a positional placeholder.
Before:
@1 rolled {rand(1, sides)} on a {sides}-sided die.
After:
text "@1 rolled {} on a {sides}-sided die." with Rand::pick(1..=sides);
Several Sugar text rows become several declarations in the same Code module:
text "@1 found a silver key.";
text "@1 found a secret note.";
text "@1 found an empty box.";
JOI still chooses one matching result when the creation runs. The difference is that the possible results now live together as source code instead of separate form rows.
Convert separate conditions
Sugar 1 stored a Sugar text and its condition in separate UI fields. Sugar 2 keeps the condition beside the result it controls.
Before:
Condition: score >= 10
Sugar text: @1 reached level {level}!
After:
text when score >= 10 {
"@1 reached level {level}!"
}
The block’s final expression is the produced text. If several instructions need to run first, put them before that final expression:
text when score >= 10 {
level++;
show chip format("Level {level}");
"@1 reached level {level}!"
}
Move variables from forms into code
Sugar 1 variables were created one at a time through fields for their name, type, default value, input settings, and choices. Sugar 2 puts all of that information in a top-level declaration inside the creation’s Code module. App variables go in Main.
A Sugar 1 number variable with these form values:
Name: sides
Display name: number of sides
Type: number
Default: 20
Input: Yes
Required: Yes
Minimum: 2
Maximum: 100
Becomes:
var sides -> "Number of sides": number = 20 with {
input: true,
required: true,
min: 2,
max: 100,
};
Put shared variable declarations at the top level of the module. Use mem var only when a changed value must survive into the next run:
mem var score = 0;
var sides -> "Number of sides": number = 20 with {
input: true,
required: true,
min: 2,
max: 100,
};
Move Item actions from forms into code
In Sugar 1, each Item action was assembled through UI fields: its name, participant rules, consumed uses, variables, conditions, and Sugar text rows. In Sugar 2, all custom actions live in the Item’s Code module alongside its shared variables and functions. Each action contains its complete definition.
For example, an action form named Roll the die, requiring one or two participants, consuming one use, asking for sides, and containing a result text becomes:
action roll -> "Roll the die" {
config {
participants: 1..=2,
consumes: 1,
}
var sides -> "Number of sides": number = 20 with {
input: true,
required: true,
min: 2,
max: 100,
};
let roll = Rand::pick(1..=sides);
text "@1 rolled {roll} on a {sides}-sided die.";
}
Executable code that belongs to the whole action goes directly in its body, before the text declarations. A let created there is available to every text in that action. Code stays inside a particular text { ... } only when it should run exclusively for that selected result.
Every other old action is converted the same way and placed below the previous declaration. The Code editor becomes the one place where you can read how the Item’s shared declarations and actions work together.
Uploaded assets now live in the Item’s media library. Sugar media pools and show media decide which library resource an action can show.
Replace changed functions
Sugar 2 groups related random and date operations into namespaces. JOI replaces the removed random functions when it converts an older creation. Use the Sugar 2 forms whenever you edit or write the code yourself.
| Sugar 1 | Sugar 2 | Status |
|---|---|---|
rand(1, 20) | Rand::pick(1..=20) | Replaced |
pickRand("a", "b") | Rand::pick("a", "b") | Replaced |
chance(25) | Rand::chance(25) | Replaced |
dayOfWeek() | Date::now().weekday | Deprecated |
For an old coin flip based on rand(), express the intent directly:
Before:
It's {if rand() > 0.5 then "Heads" else "Tails"}, @1!
After:
text "It's {}, @1!" with if Rand::chance(50) then "Heads" else "Tails";
dayOfWeek() remains available for compatibility, but new and migrated code should use the date value. The new property returns a lowercase weekday:
Date::now().weekday == "monday"
Learn Sugar 2 from the beginning
JOI converts the old creation when you open its editor, but the result is now real Sugar 2 code. The best next step is to follow the documentation from What is Sugar? onward. The course introduces the new composition model first, then builds naturally through variables, conditions, functions, namespaces, programs, and declarations.
You do not need to add every new Sugar 2 capability while migrating. First understand the converted creation and make sure it behaves as expected in Sandbox Mode. Then adopt dates, matches, Apps, Automations, Embed Templates, or other new features when they solve something you actually want to build.