# 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(float):float
function.
To write an expression inside RoomleScript:
totalHeight = ((hasPlinth) * plinthHeight) + countOfShelves * 400 + (countOfShelves - 1) * woodThickness;
Warning: If you use the negation operator, it is better to use extensive brackets, making the parsing more robust.
if (someValue == anotherValue && (!negatedValue)) {
...
}
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++) {
...
}
RoomleScript knows break
and continue
statements.
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.
for (i = 0; i < loopsCount; i++) {
...
if (booleanExpression) {
break;
}
...
}
# Scope and Context of Variables
Default scope of any internal variable or parameter is the whole current component. RoomleScript also provides contexts in several occasions. This is an overview of them:
prefix | context | note |
---|---|---|
nothing | current component | |
_. | current script | use this for local helper variables; variable resets to null after script finishes |
parameter. | parameter.onValueChange script; provides userTriggeredChange | |
other. | assignmentScripts; other component in the connection | access to all parameters and internal vars of the component on the other side of the connection |
self. | assignmentScripts; current component in the connection | actually is redundant, but helps to understand the code unambigously and should be used whenever other. is used |
connection. | assignmentScripts; provides index , position , isPreview | There are two connections in one docking/sibling point dock pair, one on each side. You can store variables relevant to the connection. You can not access other component's 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 |
# 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 = [0];
for (_.i = 1; _.i < arrayLength; _.i++) {
pushback(emptyArray, 0);
}
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 support accessing values using index in square brackets, like array[5].