# RoomleScript Overview
# What is RoomleScript?
RoomleScript is our proprietary language, which is most similar to JavaScript. In the Component object, which you define with the Json component files, the values of the objects' attributes are either constants or RoomleScripts.
To tell, which attribute value is available in RoomleScript, please refer to Roomle Configuration Catalog Structure Format, chapter "JSON Objects". Wherever there is Script<type>, you can use either a constant of that type, or a RoomleScript, which returns the value of that type.
# Roomle Script Basic overview
# Internal Variables
Variables do not have a keyword to declare them. Once a variable is first assigned, it is initialized and declared as well. The data type is assigned automatically, just like in JavaScript. There are following data types available:
- Boolean
- Integer
- Float
- String (enclosed in 'single quotes')
- Array of Float
Example:
booleanVariable = true; /* or false, also 1 and 0 work implicitly */
anInteger = 64;
aDecimalOrFloatValue = 3.141;
stringText = 'hello';
anArray = [131.05, 314, -16.64];
It is the responsibility of the scripter, that all used variables are initialized by the time they are used. This is especially important to test during reloading docked configurations, because variables can be initialized from other components as well. In order to be sure that all variables are intialized, we've defined as best practice to use following construct at the beginning of the onUpdate script:
if (ifnull(inited, false) == false) {
inited = true;
variablesOrConstants = 564;
you = false;
wantTo = 33423.5423;
initialize = 'empty';
}
The ifnull function returns the false fallback value if the inited variable is not initialized (is null), which it is at the beginning of the component instance life. Setting inited = true makes sure that the inside of the block won't run more than once.
# Comments
There 3 ways commenting inside RoomleScripts:
// single line comment
# equal single line comment
/* multi
line
comment
*/
Attention: using single line comments breaks "Load into Kernel" functionality, therefore it is recommended to use the /* multi line */ style comments. Even the Roomle Component Formatter will convert // style comments to:
/* single line comment */
# Operators and Expressions
Precedence | Operator | Description |
---|---|---|
1 | -a , +a | Unary plus and minus |
2 | !a | Logical NOT |
3 | a++ | Suffix/postfix increment |
4 | a*b , a/b | Multiplication and division |
5 | a+b , a-b , a\|b | Addition, subtraction and concatenation |
6 | a>=b , a<=b , a>b , a<b | Relational operators < and ≤ and > and ≥ respectively |
7 | a==b , a!=b | Equality operators = and ≠ respectively |
8 | a&&b | Logical AND |
9 | a\|\|b | Logical OR |
10 | a?b:c | Ternary conditional |
The Roomle script does not have a %
(modulo) operator, but has the fmod(dividend: float, divisor: float) : float
function.
To write an expression inside RoomleScript:
totalHeight = ((hasPlinth) * plinthHeight) + countOfShelves * 400 + (countOfShelves - 1) * woodThickness;
Note: Prior to January 2022, it was recommended to use extensive brackets with the negation operator, making the parsing more robust. This is not necessary anymore.
Example of expressions in the Component definition:
{
...
"parameters": [
...
{
"key": "width",
"type": "Decimal",
"defaultValue": 800,
"valueObjects": [
{
"value": "800",
"condition": "depth < 600"
},
{
"value": "1200",
"condition": true
},
{
"value": "1600",
"condition": "depth == 800;"
}
],
"enabled": true,
"visible": "height > 400",
"visibleInPartList": "height > 400"
},
...
],
"articleNr": "'500.' | widthCode | '.' | materialCode",
...
}
# Branching
In RoomleScript, if
-else
blocks can be nested to mimic if
-else
-if
blocks as in many other popular languages:
if (booleanExpression) {
...
} else if (anotherBooleanExpression) {
...
} else {
...
}
# Return
The return
statement terminates the script immediately.
This statement can be invoked anywhere within a script.
All subsequent commands are skipped and the script ends.
...
if (booleanExpression) {
return;
}
...
# Loops
For-loop is available within RoomleScript, syntax is identical with JavaScript:
for (i = 0; i < loopsCount; i++) {
...
}
break
and continue
statements are available
The break
statement terminates a for
-loop. If a break
statement is inside nested loops, the innermost loop containing the statement is terminated. A break
statement that is not inside a loop is ignored and has no effect.
The continue
statement ends the current step, triggers the increment and if for-loop condition is still true, enters the next step.
for (i = 0; i < loopsCount; i++) {
...
if (goNext) {
continue;
}
if (quitTheCycle) {
break;
}
...
}
# Scope and Context of Variables
Default scope of any internal variable or parameter is the whole current component. Some scripts have read/write access to the component data, some scripts only have a read access. To find out, which scripts can access which context, you can refer to the Script Access Rights chapter.
RoomleScript also provides contexts in several occasions. This is an overview of them:
prefix | availability | purpose |
---|---|---|
nothing | current component | |
_. | current script | Use this for local helper variables. Variable will be set to null after current script finishes. |
parameter. | parameter.onValueChange script | provides userTriggeredChange : boolean getter |
other. | all scripts in connection (onUpdate , condition , assigmentScripts ) | access to all parameters and internal vars of the component on the other side of the connection |
self. | all scripts in connection (onUpdate , condition , assigmentScripts ) | actually is redundant, but helps to understand the code unambigously and should be used whenever other. is used |
connection. | all scripts in connection (onUpdate , condition , assigmentScripts ) | provides index , position , isPreview There are two connections in one docking/sibling point dock pair, one on each side. You can store and read variables relevant to the connection at the self side |
other_connection. | all scripts in connection (onUpdate , condition , assigmentScripts ) | Same as before, but targets the other side of the connection. |
Note: For parameter.userTriggeredChange
, see the Parameters chapter. For other
, self
, and connection
contexts, see the Docking Logic Basics - Assignments and Docking Logic Basics - Ranges chapters.
# Available functions
For reference on available functions, see Roomle Configuration Catalog Structure Format, chapter RoomleScript.
# Internal values
Some scripts have internal values defined. See the table and their purpose:
identifier | context | purpose |
---|---|---|
articleNr | articleNr script | sets the current component's article number |
number | subComponent.numberInPartList | sets the subcomponent's count of entries in the part list |
connection.isPreview | docking condition | read-only, returns true if in docking preview state |
connection.index | docking range | returns index of the docking point in the range array |
connection.position | docking range, line | returns Vector3f position of the child relative to the parent's coordinate system |
condition | all conditions | sets the result of the condition |
label | all label scripts | Has value from the labels map in current language. Overwrite with value based on the script |
language | all label scripts | Getter for the language ISO code of the current locale the configurator runs with. |
parameter.userTriggeredChange | parameter.onValueChange script | getter to determine if user has just interacted with this parameter |
# Custom functions
At the moment, you can not define functions. However, for repetitive code between components, in some cases you can use a subcomponent with assignment and superseding as a workaround. For more information, see the SubComponents chapter
# Arrays
RoomleScript supports arrays of floats. To initialize the array:
array = [0, 0, 0, 0];
emptyArray = [];
for (_.i = 0; _.i < arrayLengthNeeded; _.i++) {
pushback(emptyArray, 0);
}
arrayFromVars = [someVar, someParameter, 3, 4];
To access values in the array, get(array, index)
and set(array, index, value)
functions are used (VS Code snippets: getValueFromArray
, setValueInArray
)
value = get(array, 3);
set(array, 3, 32.146);
Note: RoomleSript does not (yet) support accessing values using index in square brackets, like array[5].
# Calling Order of the Scripts
In order to understand the order in which the configurator scripts are called, please refer to the Update logic chapter.