Use values, calculations, conditions, and actions to build your rules.
Scripting reference
Write your text normally. Use { } for built-in player references and [ ] for your values, conditions, and actions. Insert an expression offers ready-made examples.
Take [counter++] sip(s)Starts with “Take 1 sip(s)”. Next time, it shows 2.
Related commands can share brackets: [label("New Rule"), foil()]. Separate them with commas; they run left to right. Commas inside quotes or function arguments stay part of that value. Functions take arguments in parentheses. Blocks contain text and commands: keep [if …], [choose], [option(…)], and their closing tags in separate brackets.
When does it happen?
Only the winning slice runs. Its result is locked when the spin starts, and its changes take effect on landing. Closing or reopening never reruns the slice. Add/remove prompts wait for you to submit them and can each be completed once. Preview shows an example result and plays its emoji reactions, without changing values or slices.
Read, change, or pause a value
[counter]- Show the current value. New numbers start at 1; text and player values start empty.
[counter++] · [counter+=2]- Show the old number, then add 1 or 2. If counter is 3,
[counter+=2] shows 3 and leaves counter at 5.
[counter--] · [counter-=2]- Show the old number, then subtract 1 or 2. Numbers never go below 1.
[counter=5]- Set and show the new value immediately.
[counter=null]- Clear the value. It displays None. Adding or subtracting now does nothing: it stays null until another slice sets it, you edit Current, or you reset it.
[*counter=null]- Add
* just after the opening bracket to hide a value from the text. The expression still runs. For example, [*counter+=2] adds 2 without printing the old number.
Expressions run left to right. Later expressions in the same slice see earlier changes, including increments. A null number stays null even when the action is silent.
Math and functions
Inside brackets, write custom value names without extra brackets or braces. Keep braces for built-in players, such as {player}. Functions can nest.
[rent * 3] · [cost = (rent + fee) * 3]- Display a calculation, or save its result. Use
+, -, *, /, and % (remainder). Multiplication and division come before addition and subtraction; parentheses change the order.
[counter += bonus * 2]- Show the old counter, then add the calculated amount.
-= works the same way for subtraction.
[random(1, max_sips)]- Random whole number, including both endpoints. Bounds may be calculations and must be in ascending order. Each call rolls independently. Store a roll with
[roll = random(1, 3)] and reuse [roll] when you need the same number again.
[random_item("Take 1 sip", "Give 1 sip", "Free pass")]- Randomly return one of the supplied options. In this example, each of the three phrases has a 1 in 3 chance. You can supply up to 48 options; repeated options increase their chance. Use numbers together, or text and player references together. Player references keep their identity; plain text stays text. A
null option can also be selected. To let the player choose instead, use a choose block.
[min(rent + 1, 5)] · [max(base - discount, 1)]- Return the smallest or largest argument. Accepts 2–16 numbers.
[clamp(value, 1, 5)]- Keep a number between the minimum and maximum. Equivalent to
[min(max(value, 1), 5)]. Reversed bounds are invalid.
[fallback(target, "Nobody")]- Use the second value only when the first is null or empty text. This does not set target. Both values must have compatible types.
[owner = target]- Copy a value, including null. Copying a player keeps their identity and color; removing that player clears both references. Quoted text remains text even if it matches a player's name.
Stored numbers are whole numbers from 1 to 1,000,000,000. Intermediate calculations may be zero or negative. Division drops the fractional part toward zero: [7 / 2] shows 3. Division by zero, overflow, reversed bounds, and math with null skip an assignment and leave its previous value unchanged. A standalone invalid calculation shows None.
The wheel never rolls: [random(1, 3)] shows “1 to 3” and random_item shows “Random choice”. Composed random calculations show the calculation until the turn resolves. Preview uses a separate example result; it cannot change the game. Reopening the result never rerolls.
Use [random(1, 3)] for a random range. [1-3] means subtraction.
Choose text with a condition
[if target] means “if target is set”. Null and empty text are unset. Only the selected branch runs; the other branch cannot change values.
[if target][target] takes 3 sips[else]You are now the goose! [*target={player}][/if]No goose yet? The current player becomes the goose. Otherwise, the stored goose takes 3 sips.
[if counter >= 5]Big challenge[else]Small challenge[/if]Compare a number using >, >=, <, <=, == (equal), or != (not equal). A null number takes the else branch for all numeric comparisons.
[if counter >= 5]Big challenge[elseif counter >= 3]Medium challenge[else]Small challenge[/if]Read it as “if this, otherwise if that, otherwise.”
[if slot_a == {player}]You hold Seat A[else]You are outside Seat A[/if]Use == or != to compare players, another value, or quoted text such as "upheld". Test an empty value explicitly with [if slot_a == null]. Other comparisons involving null are false.
[if val1 + val2 > 5 and not target]Combined total is over 5 and no target is set.[/if]Combine tests with and, or, and not. Parentheses group tests. Comparisons come before and, and comes before or. Unneeded branches are not evaluated. Invalid math, including math with null, makes that condition false.
[else] is optional; without it, a false condition shows nothing. Always finish with [/if]. Conditions may be nested. Use [elseif …] for another test before [else]; the first matching branch wins.
Players and random choices
{player} · {next_player} · {prev_player}- The spinner and their neighbors in the current turn order. Previous wraps from the first player to the last, even on the first spin. With one player, all three refer to that player; with no players, they are null.
{any_player1}- A random player, including the current player.
{other_player1}- A random player other than the current player.
{any_player2}, {any_player3}, …- Additional distinct people. The same slot repeats the same name for this result. Any and Other groups are independent, so they can overlap.
[target={player}]- Remember that player in target; read it later with
[target]. Removing them from Players clears the reference to null. Plain text with the same name stays text; assigning quoted text replaces the player association.
[random(1, 3)]- Choose a whole number from 1 to 3, inclusive. The wheel shows “1 to 3”; the result shows the chosen number.
Random names are fresh on each winning turn. Previews show Random player, or a count such as 2 random players for joined slots. If there are not enough eligible players, the missing slots are null.
[if {other_player1}]{other_player1} takes a sip[else]Take a sip yourself[/if]A fallback keeps the rule readable when no other player is available.
Remember changing text
[rule="Make a toast"]- Set and show a text value. Text choices use double quotes.
[rule=random_item("Make a toast","Choose a song")]- Randomly select, remember, and show one item. This does not prompt the player.
[rule] [*rule=random_item("Make a toast","Choose a song")]Show the current rule, then choose one for next time. Set its starting text in Default.
Short labels and choices
[label("New Rule"), foil()]Make a new house rule.foil() gives the slice a subtle holographic shimmer and sparkles. It adds no words or game actions. Put it inside an [if …] branch for a conditional effect. It appears as the wheel renders and respects reduced-motion preferences.
[label("Portal to Hell"), fire()]Welcome to Hell.fire() adds a smoky fire glow and rising embers across the slice, strongest along the bottom when selected and clipped beneath its text. Like foil(), it is a silent visual attribute and can go inside a condition. Reduced motion keeps the glow still. Crowded wheels limit simultaneous decorative motion. Both effects can share brackets with label() or color().
[label("Rosewood Avenue")]You landed on someone else’s property. Choose what to do.The label appears only on the wheel. The remaining text appears in the result. Labels can display values, such as [label("Rent [rent]")], but cannot change them.
[choose][option("Pay rent: [rent] sips")]Take [rent] sips.[option("Take over: [rent * 3] sips")]Take [rent * 3] sips. [*owner={player}]You own it now![/choose]Offer 2–8 buttons. Only the selected option runs, once. Finish the choice before spinning again; closing or refreshing keeps it pending. Put choices inside an if block to offer them only when needed. Add a condition such as [option("Sell Rosewood", when=rosewood == {player})] to show only eligible buttons. when= accepts the same conditions as if, including and, or, not, and true/false. An [else] before [/choose] supplies a fallback when none are available. Choices cannot contain other choices. Option conditions can use math and logic, but not random functions: store a roll before the choice if you need one. Only the selected option runs its calculations and actions.
[rent * 3] displays three times rent without changing it. Calculations can use other values and nested functions. A null value displays None. Preview lets you try choices without changing your game.
Turns and wheel actions
[spin_again()]- Keep the next spin with this player. The host starts it normally; it does not spin automatically. After the extra spin, turns resume in order unless another spin_again lands. Repeating the command in one result reserves just one extra turn. It survives refresh; removing the player cancels it. A choice grants the extra turn only when that option is selected. Preview never changes turns.
[add_slice()]- Show a text field in the winning result. Submit it to add one slice with weight 3 and an automatic color. The wheel holds up to 48 slices.
[remove_slice()]- Show a picker in the winning result. Choose a slice and press Remove slice. Protected slices are excluded.
Add optional=true to either command to offer a Skip button: [add_slice(optional=true)] or [remove_slice(optional=true)]. Skipping completes that prompt without changing the wheel; reopening the result keeps it skipped. Omit the option, or use optional=false, to hide Skip. Close dismisses the dialog, but the next spin reopens unfinished prompts. If the wheel is full or no slices can be removed, that unavailable action does not block the next spin.
Each prompt can be completed once for that result. Closing leaves an unfinished prompt available in Last result until the next spin. Refreshing keeps both unfinished and completed prompts.
To keep an action slice available, protect it with the lock in Advanced. [remove_slice()] cannot remove protected slices.
Make up a new challenge! [add_slice()]The command becomes a prompt below the result text. Put it inside an [if …] branch to offer it only when the condition matches.
Change the scene
To recolor an entire wheel from one result, set a shared phase there, such as [*realm="hell"]. Give each slice a conditional color() attribute as below. All slices follow that phase when the result closes; they do not need to be landed on individually. These rules follow their slices when reordered or deleted, without relying on index numbers.
[if realm == "hell"][color("#882b3d")][else][color("#b6d9ee")][/if]color() controls how a slice looks whenever its label renders, like foil(). Use it for colors that follow a phase or value, without landing on each slice first. It overrides the Advanced color while that branch applies; a branch without it uses the Advanced color. Text contrast adjusts automatically. It is silent, does not change stored values, and accepts a stable six-digit hex color or text value. Random colors are skipped.
[set_slice_weight(2)]- Set the slice that ran this command to a whole-number weight from 1 to 99. Smaller weights make it less likely to land next time. Accepts calculations and number values, such as
set_slice_weight(chance + 1).
[set_slice_color("#b6ddf2")]- Change that slice’s color using a quoted six-digit hex color or a text value containing one. Its text contrast adjusts automatically.
These commands run once on landing, or when their choice is selected, and add no result text. The landed wheel stays still until you close the result; then its size and color update for future spins. Invalid values are skipped. Preview changes nothing. Reopening a result does not run them again. Changes survive refresh and export. Removing the originating slice makes later commands for it harmless.
[set_background("https://example.com/hell.jpg")]- Set the page background on landing. Keeps the current Fill/Fit/Tile settings.
[set_center_image("https://example.com/center.gif")]- Set the center image or GIF. Keeps its zoom and rotation preference.
[set_background(null)] · [set_center_image(null)]- Clear an image. Functions also accept a value containing a direct HTTP or HTTPS image link. Unsafe links are skipped. Only links are saved in exports.
[*realm="hell"][set_background("https://example.com/hell.jpg")]Welcome to Hell.Replace the example link with your own image. On another slice, switch back with realm="heaven" and the Heaven image.
[if realm == "hell"]Take 3 sips[else]Give 1 sip[/if]Every slice can change its displayed label and behavior based on the realm. Set realm's Default to heaven. The current spin keeps its labels still; the next view uses the changed realm.
Image commands add no text to the wheel or result. Write any announcement yourself. Scene changes apply once on landing or after choosing the option containing them. Preview does not change images. Images preload when possible; while loading or after a failed load, the previous scene stays visible. Reset to defaults resets values only; it does not reset images.
Emoji reactions
Spread some love! [emote("💖", "🌈")]On landing, a short burst of these emojis floats up across the screen. The command does not appear in the result text.
Use 1 to 8 quoted emojis, separated by commas: [emote("💖", "🌈")]. Reactions run once on landing, respect reduced motion, and never replay when reopening the result. Multiple reaction commands share one short burst. Use Preview to try the effect.
Wheel previews show the emojis. Add * to hide that preview too: [*emote("💖", "🌈")]. Conditions work with reactions just like other actions.
If something does not work
Unfinished expressions and conflicting types show a message in setup. Correct them to spin again; the editor stays usable. Use one type per value name: a number cannot also hold text or a player.
During a result, an unsafe update is skipped and its value stays unchanged. Numbers stay between 1 and 1,000,000,000. Adding beyond that limit does nothing. Null values also ignore addition and subtraction.
Deeply nested conditions and oversized expressions are rejected instead of being run.
Game values and notes
Current is the value the game uses now. Default is the starting value; changing it does not overwrite Current. Reset to defaults restores all current values and leaves the last result unchanged.
Use lowercase command names as shown. Value names are case-sensitive: counter and Counter are different. Use letters, digits, or underscores; start with a letter or underscore. Values are detected from your slices. Edit their defaults here; they disappear from Game values when no slice references them.
Notes can display values such as Goose: [target]. They only read values; they never run assignments or increments.
To display a bracket literally, add a backslash: \[counter].