DraxGUI expressions and templates
Updated 28 October 2026
One small, safe language is used by bindings, visibleWhen/enabledWhen, HUD rules, node parameters, popup values and preview.
Where expressions appear
| Place | Form |
|---|---|
bind.<prop>, visibleWhen, enabledWhen, HUD rule when |
a bare expression: score >= 100 && !game_over |
| Text props and template params | template text with ${...} holes: Score: ${score} — %player% is accepted as a shorthand for ${player.name} |
Action/node parameters (with) |
a string starting with = is an expression ("=score * 2"), a string containing ${ is a template, anything else is a literal |
Values
number (IEEE double; integers print without .0), string, boolean, null, list. Arithmetic on non-finite results yields an error value; errors propagate and render as an empty string in templates (the diagnostic is reported once).
Syntax
- Literals:
12,1.5,.5(the same as0.5; no exponents),'text'or"text"(escapes\',\",\\,\n),true,false,null,[1, 2, 3]. - Names: project variables by id (
score), other projects' externally readable variables asns:id(candy_cascade:score), context objectsplayer.<field>(name, uuid, health, max_health, food, level, xp, world, x, y, z, gamemode, ping, locale, platform, andbalance: the Vault economy balance, null without Vault and an economy plugin, read at most once a second),server.<field>(online, max_players, tps, version;time: seconds since 1970 UTC;day: whole days since 1970 in the server's time zone, so it changes at the server's local midnight;next_day_in: seconds until that midnight; evaluated on the server, with sample values in previews),screen(current screen id),params.<name>(popup values),event.value,event.button, element values@<elementId>or@<elementId>.value, the active tab@<tabViewId>.tab. - Operators (lowest to highest precedence):
c ? a : b,||,&&,== !=,< <= > >=,+ -,* / %, unary! -, indexinglist[i], callsf(x). +concatenates when either side is a string; otherwise numeric. Comparisons between a number and a numeric string compare numerically.==between different non-coercible types isfalse.&&/||short-circuit and return booleans. Truthiness:false,0,"",null, empty list are false.- Ternaries need spaces around
:(c ? a : b), becausea:bwith no spaces reads as the namespaced namea:b.
Exact behaviour
The server and the editor preview give the same results. In detail:
- Number to text follows ECMAScript
Number#toString: shortest round-trip digits, plain notation for1e-6 <= |n| < 1e21(10000000, not1.0E7), exponent form outside (1e+21),-0prints0. - Text to number accepts only an optional sign, digits, an optional fraction and exponent (surrounding spaces ignored);
NaN,Infinity, hex and suffixes are not numbers. In arithmeticnullcounts as0and booleans as1/0; lists and other text are errors. - Two strings compare lexicographically (
'10' < '9'is true); any other pair compares numerically. Lists cannot be compared. list[i]needs a whole-number index; out of range (including negative) givesnull.get(list, i, default)returns the default instead.round(x, d)isMath.round(x * 10^d) / 10^d(halves go toward +infinity, soround(-2.5)is-2),0 <= d <= 10.format(n, d)prints that with exactlyddecimals.percenttakes a fraction.thousands(n)groups the integer part of the plain number text and keeps its decimals (-1,234.5); round first if needed.compact(n)uses K/M/B/T with one decimal and moves up a unit when rounding reaches 1000 (999999is1M).time(s)floors and clamps at 0.nullrenders as an empty string; lists render as[a, b]withnullitems shown asnull.joinneeds a list and defaults its separator to"".lencounts UTF-16 units, like indexing.if(c, a, b)evaluates only the chosen branch.range(n)withn <= 0is empty.- Escapes other than
\',\",\\and\nare errors. In templates an unclosed${is literal text; there is no escape for a literal${.
Functions
min(a,b,…), max(…), abs(x), round(x[,decimals]), floor(x), ceil(x), clamp(x,lo,hi), len(x), str(x), num(x), upper(s), lower(s), trim(s), contains(listOrString, x), join(list[,sep]), format(n[,decimals]), thousands(n), compact(n), percent(x[,decimals]), time(seconds) (m:ss or h:mm:ss), random(min,max) (host RNG; integer when both bounds are integers), if(c,a,b), get(list,i[,default]), list(…), range(n).
placeholder(text) fills in PlaceholderAPI placeholders for the viewing player (placeholder('%playerpoints_points%'), placeholder('Rank: %luckperms_prefix%')). A result that is a plain number or a number with thousands commas (12,450) comes back as a number, anything else as text. Each text is filled in at most once a second per player; up to 256 characters. Without PlaceholderAPI the text comes back unchanged. Previews have no player: a text containing name shows the test player's name, anything else 12450.
Limits
Expressions are limited to 2000 characters, nesting depth 32 and 10 000 evaluation steps. Lists are limited to 4096 items. There is no assignment, no loop, no reflection and no access to server objects; side effects only happen through actions.