# Roomle Script Built-in Functions

This is an overview of native RoomleScript functions provided by the core. These functions can be used directly and provide functionalities that are not achievable through standard scripting.

The functions are grouped by their availability in different script contexts. Some functions are available everywhere, some only in specific scripts like `onUpdate`, `connection`, `collision condition` or `geometry`.

## How To Read This Document

The function documentation follows a specific format to ensure clarity and consistency. Each function is documented with its name, signature, parameters, return type, usage examples, and any exceptions it may throw. The documentation is structured to help you quickly understand how to use each function effectively.

This documentation is also available in our VS Code extension in the autocomplete and hover tooltips, making it easier to access while coding.

The function signatures are written in a TypeScript-like syntax to enhance readability and understanding of the function's structure, an example follows:

```javascript
functionName(
    parameter1: type,
    *optionalParameter: type[ = defaultValue],
    **keywordParameter: type[ = defaultValue],
) : returnType
```

Parameters without any asterisks (\*) are required. Parameters with a single asterisk are optional parameters, and are identified by their order in the parameter list. Parameters with double asterisks (\*\*) can be used as keyword arguments, meaning they can be provided in any order and are identified by their name.

Optional and keyword parameters of these build-in functions can (but don't have to) have default values, which are used if the parameter is not provided when the function is called.

The types used in the signatures are internal RoomleScript types, which are a subset of JavaScript/TypeScript types, as well as the default values, with following exceptions, that are not part of the RoomleScript syntax and have no meaning and are no keywords in RoomleScript:

* `any`: can be anything (TypeScript-any-like)
* `null`: null value; `null` itself has no meaning in the RoomleScript language
* `[type]`: array of the given type
* `[[type]]`: array of arrays of the given type

## General Functions

These functions are universally available and you can utilize them in any script context.

### Math

These are mathematical functions.

#### asin

```javascript
asin(
    a: float
) : float
```

Arcus sine (arcsine)

Parameters:

* `a`: value between -1 and 1

Returns: arcsine of `a` in radians.

Usage:

```javascript
v = 0.5;
angleRad = asin(v); /* returns 523598776 */
angle = (angleRad / M_PI) * 180; /* 30 */
```

#### acos

```javascript
acos(
    a: float
) : float
```

Arcus cosine (arccosine)

Parameters:

* `a`: float value between -1 and 1

Returns: arccosine of `a` in radians.

Usage:

```javascript
v = 0.5;
angleRad = acos(v); /* returns 1.04719755 */
angle = (angleRad / M_PI) * 180; /* 60 */
```

#### atan

```javascript
atan(
    a: float
) : float
```

Arcus tangent.

Parameters:

* `a`: value between -1 and 1

Returns: arctangent of `a` in radians.

#### atan2

```javascript
atan2(
    y: float,
    x: float
) : float
```

Arcus tangent defined by ratio of opposite and adjacent side of the triangle.

Parameters:

* `y`: length of opposite side
* `x`: length of adjacent side

Returns: arctangent of the angle in radians.

#### ceil

```javascript
ceil(
    number: float,
    digits: float
) : float
```

Nearest higher value

Parameters:

* `number`: the number to be ceiled
* `digits`: count of decimal digits

Returns: Nearest higher value rounded to given amount of decimal spaces.

Usage:

```javascript
x = 123.4567;
ceil(x, 0); /* returns 124 */
ceil(x, 2); /* returns 123.46 */
```

#### cos

```javascript
cos(
    valueRad: float
) : float
```

Cosine

Parameters:

* `valueRad`: value in radians

Returns: cosine value of `a`.

#### cosh

```javascript
cosh(
    valueRad: float
) : float
```

Hyperbolic cosine

Parameters:

* `valueRad`: value in radians

Returns: hyperbolic cosine value of `a`.

#### exp

```javascript
exp(
    x: float
) : float
```

Exponential function

Parameters:

* `x`: the exponent

Returns: Value of e powered to `x`

#### fabs

```javascript
fabs(
    x: float
) : float
```

Absolute value

Parameters:

* `x`: value

Returns: `x` if `x` is positive or `-x` if x is negative.

Usage:

```javascript
fabs(5); /* returns 5 */
fabs(-5); /* returns 5 */
```

#### floor

```javascript
floor(
    number: float,
    digits: float
) : float
```

Nearest lower value

Parameters:

* `number`: the number to be floored
* `digits`: count of decimal digits

Returns: Nearest lower value rounded to given amount of decimal spaces.

Usage:

```javascript
x = 123.4567;
floor(x, 0); /* returns 123 */
floor(x, 2); /* returns 123.45 */
```

#### fmod

```javascript
fmod(
    dividend: float,
    divisor: float
) : float
```

Floating point modulo

Parameters:

* `dividend`: float
* `divisor`: float

Returns: Modulo as float.

> ⚠️ **Warning:** Works well only with integers that can be represented by single precision floating point numbers (32 bits, up to around 7 digits).

Usage:

```javascript
fmod(13, 4); /* returns 1 */
fmod(12, 4); /* returns 0 */
fmod(123456789, 1234567); /* will not work well */
```

#### log

```javascript
log(
    value: float
) : float
```

Natural logarithm

Parameters:

* `value`

Returns: Logarithm of the value with base of `e` (\~2.718)

Usage:

```javascript
log(100); /* returns ~4.605 */
log(M_E); /* returns 1 */
log(1); /* returns 0 */
log(0); /* returns -inf */
```

#### log10

```javascript
log10(
    value: float
) : float
```

Common logarithm

Parameters:

* `value`

Returns: Logarithm of the value with base of 10

Usage:

```javascript
log10(100); /* returns 2 */
log10(M_E); /* returns ~0.434 */
log10(1); /* returns 0 */
log10(0); /* returns -inf */
```

#### pow

```javascript
pow(
    value: float,
    exponent: float
) : float
```

Power function

Parameters:

* `value`: the value to compute power
* `exponent`

Returns: value powered to exponent.

#### round

```javascript
round(
    number: float,
    digits: float
) : float
```

Nearest rounded value

Parameters:

* `number`: the number to be rounded
* `digits`: count of decimal digits

Returns: Nearest value rounded to given amount of decimal spaces.

Usage:

```javascript
x = 1.234567;
round(x, 0); /* returns 1 */
round(x, 1); /* returns 1.2 */
round(x, 2); /* returns 1.23 */
round(x, 3); /* returns 1.235 */
round(x, 4); /* returns 1.2346 */
```

#### sin

```javascript
sin(
    valueRad: float
) : float
```

Sine

Parameters:

* `valueRad`: value in radians

Returns: sie value of `a`.

#### sinh

```javascript
sinh(
    valueRad: float
) : float
```

Hyperbolic sine

Parameters:

* `valueRad`: value in radians

Returns: hyperbolic sine value of `a`.

#### sqrt

```javascript
sqrt(
    number: float
) : float
```

Square root

Parameters:`number`: zero or positive number

Returns: Square root of the number or `nan`

Usage:

```javascript
sqrt(2); /* returns M_SQRT2 or ~1.414 */
```

#### tan

```javascript
tan(
    valueRad: float
) : float
```

Tangent

Parameters:

* `valueRad`: value in radians

Returns: tangent value of `a`.

#### tanh

```javascript
tanh(
    valueRad: float
) : float
```

Hyperbolic tangent

Parameters:

* `valueRad`: value in radians

Returns: hyperbolic tangent value of `a`.

### Data Type Conversions

Functions to convert between data types.

#### float

```javascript
float(
    value: any
) : float
```

Convert to float

Parameters:

* `value` the value to try to convert to float

Returns: If `value` starts with number, returns the first parsed number, otherwise 0.

Usage:

```javascript
float('5'); /* returns 5.0 */
float('5 hello 3432'); /* returns 5.0 */
float('5.3'); /* returns 5.3 */
float('5,3'); /* returns 5.0 */
float(' 5'); /* returns 5.0 */
float('_5'); /* returns 0.0 */
float([5]); /* returns 0.0 */
float([1]); /* returns 0.0 */
float(Vector3f{5,5,5}) /* returns 0.0 */
```

#### string

```javascript
string(
    input: any,
    *decimalSpaces: Integer = 2
) : String
```

toString function - converts value to string.

Parameters:

* `input` value to stringify
* `decimalSpaces` if input is an Integer or float, defines the amount of decimal spaces of the number to show; default is 2
  * note: not appliable to array, Vector2f, Vector3f, String

Returns: Value converted to string.

Usage:

```javascript
string('some string') /* returns 'some string' */
string('some string', 4) /* returns 'some string' */
string(M_PI) /* returns '3.14' */
string(M_PI, 0) /* returns '3' */
string(M_PI, 2) /* returns '3.14' */
string(M_PI, 5) /* returns '3.14159' */
string([1, 2]) /* returns '[1.00,2.00]' */
string([1, 2], 0) /* returns '[1.00,2.00]' */
string(Vector2f{1, 2}) /* returns '{1.00,2.00}' */
string(Vector2f{1, 2}, 0) /* returns '{1.00,2.00}' */
string('1.00', 0) /* returns '1.00' */
string('1', 5) /* returns '1' */
```

#### stringToArray

```javascript
stringToArray(
    stringifiedArray: string
) : [float]
```

Parses a string to array.

Parameters:

* `stringifiedArray`: stirng in a `[number, number, ...]` pattern

Returns: The parsed array or null if failed.

Usage:

```javascript
arr = stringToArray('[1,2,3]');
x = get(arr, 0); /* returns 1 */
```

#### stringToVector2f

```javascript
stringToVector2f(
    stringifiedVector: string
) : Vector2f
```

Parses a string as Vector2f.

Parameters:

* `stringifiedVector`: String in a `Vector2f{number, number}` or `{number, number}` pattern

Throws:

* `[1301]` Error getting value

Returns: The parsed vector or null if failed.

Usage:

* Vector parameter

```json
{
  "key": "size",
  "type": "String",
  "valueObjects": [
    {
      "value": "{100,200}",
      "labels": {
        "en": "10 x 20"
      }
    },
    {
      "value": "Vector3f{1000,200}",
      "labels": {
        "en": "100 x 20"
      }
    }
  ]
}
```

```javascript
_size = stringToVector2f(size);
 AddCube(Vector3f{xFromVector(_size), yFromVector(_size), 500});
```

#### stringToVector3f

```javascript
stringToVector3f(
    stringifiedVector: string
) : Vector3f
```

Parses a string as Vector3f.

Parameters:

* `stringifiedVector`: String in a `Vector3f{number, number, number}` or `{number, number, number}` pattern

Throws:

* `[1301]` Error getting value

Returns: The parsed vector or null if failed.

Usage:

* Vector parameter

```json
{
  "key": "size",
  "type": "String",
  "valueObjects": [
    {
      "value": "{100,200,300}",
      "labels": {
        "en": "10 x 20 x 30"
      }
    },
    {
      "value": "Vector3f{1000,200,300}",
      "labels": {
        "en": "100 x 20 x 30"
      }
    }
  ]
}
```

```javascript
_size = stringToVector3f(size);
 AddCube(Vector3f{xFromVector(_size), yFromVector(_size), zFromVector(_size)});
```

#### typeOf

```javascript
typeOf(
    value: any
) : String
```

Returns the RoomleScript type name of a value.

Parameters:

* `value`: the value for which the type should be returned

Returns: One of `Null`, `Integer`, `Decimal`, `String`, `Boolean`, `Array`, `Object`, `Vector2` or `Vector3`. Missing values and null values return `Null`.

Usage:

```javascript
typeOf(1i); /* returns 'Integer' */
typeOf(1.25); /* returns 'Decimal' */
typeOf('value'); /* returns 'String' */
typeOf(true); /* returns 'Boolean' */
typeOf([1, 2, 3]); /* returns 'Array' */
typeOf(Vector2f{1, 2}); /* returns 'Vector2' */
typeOf(Vector3f{1, 2, 3}); /* returns 'Vector3' */
typeOf(getData('object')); /* returns 'Object' if the data entry is an object */
typeOf(missingValue); /* returns 'Null' */
```

### Array Operators

Functions that operate on arrays, like accessing and setting values, searching, inserting etc.

#### get

```javascript
get(
    array: [float],
    index: Integer
) : float
```

Reads an array element at a given index.

To write an array element, refer to [set](#set).

Parameters:

* `array`: the array you want to access
* `index`: index of the element in the array, index of the first element is zero `0`
  * ⚠️ float indices will floor to the next lower integer

Returns: The number from the array at the given index or 0 if fails.

Throws:

* `[1404]` Index out of bounds. Returns 0 in this case, execution continues

Usage:

```javascript
arr = [10, 20, 30, 40];
get(arr, 2); /* returns 30 */
get(arr, 2.9); /* returns 20 */
get(arr, 2.999999); /* returns 20 */
get(
  arr,
  2.9999999
); /* returns 30 (floating point precision flips to index 3) */
get(arr, 5); /* returns 0, throws 1404 */
get(arr, -1); /* returns 0, throws 1404 */
```

#### inArray

```javascript
inArray(
    valueToCheck: any,
    value1: any,
    value2: any,
    ...
) : boolean
```

Useful for checking if a list of values contains a specific value.

Arguments

* `searchedValue`: the value that is being searched for in the list
* `array`: the array to check

Returns

* `true` if valueToCheck is equal to at least one of the other values, otherwise `false`

Usage:

```javascript
inArray(1, [1, 2, 3, 1]); /* returns 1 */
inArray(10, [1, 2, 3, 1]); /* returns 0 */
```

#### indexOf

```javascript
indexOf(
    searchedValue: float,
    array: [float]
) : Integer
```

Find index of a value in an array.

Parameters:

* `searchedValue`: the value that is being looked for
* `array`: the array to search

Returns: Index of the first occurence of the value in the array or -1 if no occurence.

Usage:

```javascript
indexOf(1, [1, 2, 3, 1]); /* returns 0 */
indexOf(10, [1, 2, 3, 1]); /* returns -1 */
```

#### insert

```javascript
insert(
    array: [float],
    index: Integer,
    value: float | [float]
) : void
```

Insert into array in front of the element at given index

Parameters:

* `array`: array into which the values are inserted
* `index`: index of the element before which the values will insert
* `value`: value to be inserted, can be a number or an array of numbers

Throws:

* `[1404]` index out of bounds

Usage:

```javascript
arr = [10, 20];
insert(arr, 1, 15); /* arr is [10, 15, 20] */
insert(arr, 0, [0, 5]); /* arr is [0, 5, 10, 15, 20] */
insert(arr, 5, 25); /* arr stays [0, 5, 10, 15, 20], throws [1404] */
insert(arr, -1, 5); /* arr stays [0, 5, 10, 15, 20], throws [1404] */
```

#### intersection

```javascript
intersection(
    a: [float],
    b: [float]
) : [float]
```

Intersection of arrays

Parameters:

* `a`, `b`: two arrays of numbers

Returns: Array with elements that are present in both arrays.

Usage:

```javascript
intersection([3, 2, 1], [2, 3, 4, 5]); /* returns [2, 3] */
intersection([3, 2, 1], [5, 4, 3, 2]); /* returns [3, 2] */
intersection([1, 2, 3], [4, 5, 6]); /* returns [] */
intersection([1], [1, 1, 1]); /* returns [1, 1, 1] */
intersection([1, 1, 1], [1]); /* returns [1, 1, 1] */
```

#### length

```javascript
length(
    array: [float]
) : Integer
```

Length of array (for the length of a String, refer to [size](#size)).

Parameters: \* `array`: array of floats

Returns: count of the array elements.

Usage:

```javascript
a = [];
b = [0, 1, 2];
c = [0];
length(a); /* returns 0 */
length(b); /* returns 3 */
length(c); /* returns 1 */
```

#### popBack

```javascript
popBack(
    array: [float]
) : float
```

Returns and removes last number from array.

Parameters:

* `array`

Returns: Last number of array, original array has this value removed or 0 if `[1405]` is thrown.

Throws:

* `[1405]`: popBack empty array

Usage:

```javascript
arr = [10, 20];
x1 = popBack(arr); /* returns 20, arr is [10] */
x2 = popBack(arr); /* returns 10, arr is [] */
x3 = popBack(arr); /* returns 0, arr is [], throws [1405] */
```

#### pushBack

```javascript
pushBack(
    array: [float],
    value: float
) : void
```

Pushes a value at the end of an array.

Parameters:

* `array`: the array to which to push
* `value`: the value to push

Usage:

```javascript
arr = [];
for (_.i = 0; _.i < 5; _.i = _.i + 1) {
  pushBack(arr, 0);
}
/* arr is [0, 0, 0, 0, 0] */
```

#### removeAt

```javascript
removeAt(
    array: [float],
    index: Integer
) : float
```

Remove element at index from an array and return the next.

Parameters:

* `array`: the array from which the element should be removed
* `index`: index at which to remove the element, first index is 0

Returns: Next element after the one that has been removed or 0 if the element is the last one or if `[1404]` has been thrown.

Throws:

* `[1404]`: Index out of bounds

Usage:

```javascript
arr = [10, 20, 30, 40, 50];
x1 = removeAt(arr, 2); /* returns 40, arr is [10, 20, 40, 50] */
x2 = removeAt(arr, 3); /* returns 0, arr is [10, 20, 40] */
x3 = removeAt(arr, 3); /* returns 0 and throws 1404, arr stays as it is */
x3 = removeAt(arr, -1); /* returns 0 and throws 1404, arr stays as it is */
```

#### set

```javascript
set(
    array: [float],
    index: Integer,
    value: float
) : void
```

Sets value of an array element at a given index.

Parameters:

* `array`: the array you want to set
* `index`: index of the element in the array, index of the first element is zero `0`
  * ⚠️ float indices will floor to the next lower integer
* `value`: the new value that will replace the old value

Throws:

* `[1404]` Index out of bounds.

Usage:

```javascript
arr = [1, 2, 3];
set(arr, 0, 5); /* [5, 2, 3] */
set(arr, 1, get(arr, 2)); /* [5, 3, 3] */
set(arr, 2, get(arr, 2) + 1); /* [5, 3, 4] */
```

### String Operators

Functions that operate on strings, like checking for patterns, getting length, splitting etc.

#### like

```javascript
like(
    input: String,
    pattern: String
) : Boolean
```

Returns true if input matches the pattern. The pattern is a String with placeholders for one any single character or any subString.

This is the `OPTION_LIKE` operator from the IDM 3.1 standard, which itself is designed to be similar on the SQL's `LIKE` operator.

Parameters:

* `input`: the String to check against the pattern
* `pattern`: a case sensitive String pattern, where `_` is a wildcard for any single character and `%` is a wildcard representing any subString at least 1 character long
  * `a_` - length 2, starts with `a`
  * `a%` - any String starting with `a`
  * `_a` - length 2, ends with `a`
  * `%a` - any String that ends with a
  * `%a%` - any String that contains `a`

Returns: `true` if String matches to the pattern, otherwise `false`

Usage:

```javascript
like('Hello beautiful world', 'Hello') 
/* false; no wildcard, pattern means equls to 'Hello' */

like('Hello beautiful world', 'Hello%')
/* true; pattern means starts with 'Hello' */

like('Hello beautiful world', '%beatiful%')
/* true; pattern means contains 'beatiful' */

like('Hello beautiful world', '%Hello%')
/* false; pattern means contains 'Hello' which is preceded and followed by other characters */

like('Hello beautiful world', 'Hello%world')
/* true; pattern means starts with 'Hello' and ends with 'world' */

like('Hello beautiful world', 'h%';
/* false; pattern means starts with 'h' */
```

#### size

```javascript
size(
    input: String
) : Integer
```

Length of String.

Parameters: \* `input`: String

Returns: count of the String's characters.

Usage:

```javascript
a = 'Hello';
b = '';
size(a); /* returns 5 */
size(b); /* returns 0 */
```

#### stringPart

```javascript
stringPart(
    input: String,
    delimiter: String,
    index: Integer,
    *fallback: String = ''
) : String
```

Splits a string with a delimiter and returns the part under the given index.

Parameters:

* `input`: the string intended to be parsed
* `delimiter`: a string that will be used to separate the input string
* `index`: index of the part that will
* `fallback`: optional value to return if fails, empty string `''` by default

Returns: part of the string or a fallback value (defined or `''`) if fails.

Usage:

```javascript
_.id = 'abcd:efgh';
_.catalogueId = stringPart(id, ':', 0); /* returns 'abcd' */
_.externalId = stringPart(id, ':', 1); /* returns 'efgh' */
_.empty = stringPart(id, ':', 2); /* returns '' */
_.fallback = stringPart(id, ':', 2, 'NULL'); /* returns 'NULL' */
```

#### stringSplit

```javascript
stringSplit(
    input: String,
    delimiter: String
) : [String]
```

Splits a string with a delimiter and returns the parts as an array.

Parameters:

* `input`: the string intended to be parsed
* `delimiter`: a string that will be used to separate the input string

Returns: Array of string parts or an empty array if input is an empty string.

Usage:

```javascript
_.id = 'abcd:efgh';
_.idParts = stringSplit(id, ':'); /* returns ['abcd', 'ergh'] */
_.catalogueId = get(iidPartsd, 0); /* returns 'abcd' */
_.externalId = get(idParts,  1); /* returns 'efgh' */
```

#### substring

```javascript
substring(
    input: String,
    startIndex: Integer,
    length: Integer
) : String
```

Returns part of string based on position and length.

Parameters:

* `input`: the string from which the substring is to be extraced
* `startIndex`: index where the substring starts, first index is 0
* `length`: length of the substring

Returns: Part of string starting at the given index of the given length. Empty string is returned for every character that is outside of the string, rather than throwing an exception.

Usage:

```javascript
substring('my string', 3, 6); /* returns 'string' */
substring('my string', 3, 0); /* returns '' */
substring('my string', -3, 6); /* returns '' */
substring('my string', -3, 6); /* returns '' */
substring('my string', 0, 100); /* returns 'my string' */
substring('my string', 10, 100); /* returns '' */
```

### Component Data Functions

Component definitions can provide static non-changeable data in the JSON format. These functions allow to access and query this data and even evaluate them as expressions. There are several versions of these functions. Functions starting with `get` return the data as is, `evaluate` functions evaluate the data as RoomleScript expressions and `find` functions return arrays of data that match a certain criteria. In the basic form, these functions query the data of the current component definition. There are variants for accessing the data of a subComponent. If data is not found, there are variants of the functions that differ in the way they handle this case. Functions with `OrNull` suffix return `null` if data is not found, functions with `WithDefault` suffix return a default fallback value passed as an argument. Without any suffix, the functions return `null` and display an error message in the console.

These can return not only values, but also objects and arrays. The elements of the objects can be accessed with the `.` (member access) operator. Multidimensional arrays or lists of arrays are not supported because the RoomleScript does not support multidimensional arrays at all, not even for basic data types.

#### getData

```javascript
getData(
    ...key : String | Integer
) : any | null    
```

Retrieves data from the data storage JSON object in the `component.data`.

⚠️ This does not handle non-existing path and scripter needs to ensure that the requested path exists.

Attributes:

* `key`: path parts as String keys or Integer array indices; path segments are separate arguments, e.g. `getData('a', 'b', 0, 'c')` to access `data.a.b[0].c`

Returns: The retrieved data or null if data wasn't found, accompanied by an error message in the console.

Throws:

* `[1308]` Data not found

Usage:

* define the `data` in the component definition

```json
{
    "id": "test:data",
    "data": {
        "size": 300,
        "colors": [
            "isdt:red",
            "isdt:green"
        ],
        "elementTypes": {
            "smallbox": {
                "label": "Small Box"
            },
            "bigsphere": {
                "label": "Big Sphere"
            }
        }
    }
}
```

* retrieve them using the `getData` function

```javascript
/* returns 300 */
width = getData('size');
/* returns 'isdt:green' */
color = getData('colors', 1);
/* returns the 'Small Box' or 'Big Sphere' based on the current value of elementType variable */
label = getData('elementTypes', elementType, 'label');
```

#### getDataOrNull

```javascript
getDataOrNull(
    ...key : String | Integer
) : any | null    
```

Retrieves data from the data storage JSON object in the `component.data` or `null` if data wasn't found without emitting any error message.

Attributes:

* `key`: path parts as String keys or Integer array indices; path segments are separate arguments, e.g. `getData('a', 'b', 0, 'c')` to access `data.a.b[0].c`

Returns: The retrieved data or null.

Usage:

* define the `data` in the component definition

```json
{
    "id": "test:data",
    "data": {
        "size": 300,
        "colors": [
            "isdt:red",
            "isdt:green"
        ],
        "elementTypes": {
            "smallbox": {
                "label": "Small Box",
                "hasChildDock": true
            },
            "bigsphere": {
                "label": "Big Sphere",
                "hasParentDock": true
            }
        }
    }
}
```

* retrieve them using the `getDataOrNull` function in the `condition` script of a `parentDocking`

```javascript
_.hasParentDock = getDataOrNull('elementTypes', elementType, 'hasParentDock');
if (isnull(_.hasParentDock) || _.hasParentDock == false) {
  /* kill this docking if the element type has no docking possibility in the first step */
  return false;
}
/* conitnue with the condition evaluation */
```

#### getDataWithDefault

```javascript
getDataWithDefault(
    ...key : String | Integer,
    defaultValue: any
) : any
```

Retrieves data from the data storage JSON object in the `component.data` and returns a fallback value if entry hasn't been found.

Attributes:

* `key`: path parts as String keys or Integer array indices; path segments are separate arguments, e.g. `getData('a', 'b', 0, 'c')` to access `data.a.b[0].c`
* `defaultValue`: value to return if target path doesn't exist

Returns: The retrieved data or fallback.

Usage:

* define the `data` in the component definition

```json
{
    "id": "test:data",
    "parameters": [
        {
            "key": "elementType",
            "validValues": [
                "armchair",
                "inline"
            ]
        }
    ],
    "data": {
        "translations": {
            "armchair": {
                "en": "Armchair",
                "de": "Sessel",
                "fr": "Fauteuil"
            },
            ...
        }
    }
}
```

* retrieve them using the `getDataWithDefault` function in a `label` script:

```javascript
return getDataWithDefault(
    'translations',
    elementType,
    language,
    getData('translations', elementType, 'en')
);
```

Note: `language` hold the ISO code of the current language. It can be `es` for example, in which case the translation entry doesn't exist. Because `elementType` has a list of validValues, the developer can make sure that the `getData` will always return a value.

#### getSubComponentData

```javascript
getSubComponentData(
    subComponentInternalId : String
    ...key : String | Integer
) : any | null
```

Retrieves a `component.data` from another component, that is being linked as a subComponent of this component. Works exactly same as the [`getData`](#getdata) counterpart, just in a different component.

Attributes:

* `subComponentInternalId`: internalId of a subComponent definition
* `key`: path parts as String keys or Integer array indices; path segments are separate arguments, e.g. `getData('a', 'b', 0, 'c')` to access `data.a.b[0].c`

Returns: The retrieved data or null.

Throws:

* `[1308]` Data not found

Usage:

* Data subComponent:

```json
{
    "id": "mycatalog:component_with_data",
    "data": {
        "elementTypes": {
            "chair": {
                "articleCode": "MCH-75"
            },
        },
        "materialArticleCodes": {
            "fabric_pg1_red": "10.1-1001",
            "fabric_pg1_blue": "10.1-1002",
            "leather_pg6_palebrown": "20.6-1001"
        }
    }
}
```

* Main component:

```json
"subComponents": [
    {
        "internalId": "DATACOMPONENT",
        "componentId": "mycatalog:component_with_data",
        "active": false,
        "numberInPartList": 0
    }
]
```

* Retrieve the data:

```javascript
productCode = getSubComponentData(
  'DATACOMPONENT', // internalId of the subComponent
  'elementTypes',
  'chair',
  'articleCode'
);
materialCode = getSubComponentDataWithDefault(
  'DATACOMPONENT',
  'materialArticleCodes',
  stringPart(material, ':', 1),
  'UNDEFINED'
);
articleNr = productCode | ' ' | materialCode;
```

#### getSubComponentDataOrNull

```javascript
getSubComponentDataOrNull(
    subComponentInternalId : String,
    ...key : String | Integer
) : any | null
```

OrNull counterpart of `getSubComponentData`. See [`getDataOrNull`](#getdataornull) and [`getSubComponentData`](#getsubcomponentdata).

#### getSubComponentDataWithDefault

```javascript
getSubComponentDataWithDefault(
    subComponentInternalId : String,
    ...key : String | Integer
    defaultValue: any
) : any | null
```

Same as `getSubComponentDataWithDefault`, but considers the value an expression and attempts to evaluate it. See [evaluateData functions](#evaluatedata-functions) and [getSubComponentDataWithDefault](#getsubcomponentdatawithdefault).

#### evaluateData

```javascript
evaluateData(
    ...key : String | Integer
) : any | null
```

Same as `getData`, but considers the value an expression and attempts to evaluate it. See [evaluateData functions](#evaluatedata-functions) and [getData](#getdata).

#### evaluateDataOrNull

```javascript
evaluateDataOrNull(
    ...key : String | Integer
) : any | null
```

Same as `getDataOrNull`, but considers the value an expression and attempts to evaluate it. See [evaluateData functions](#evaluatedata-functions) and [getDataOrNull](#getdataornull).

**evaluateDataWithDefault**

```javascript
evaluateDataWithDefault(
    ...key : String | Integer,
    defaultValue: any
) : any
```

Same as `getDataWithDefault`, but considers the value an expression and attempts to evaluate it. See [evaluateData functions](#evaluatedata-functions) and [getDataWithDefault](#getdatawithdefault).

#### evaluateSubComponentData

```javascript
evaluateSubComponentData(
    subComponentInternalId : String,
    ...key : String | Integer
) : any | null
```

Same as `getSubComponentData`, but considers the value an expression and attempts to evaluate it. See [evaluateData functions](#evaluatedata-functions) and [getSubComponentData](#getsubcomponentdata).

#### evaluateSubComponentDataOrNull

```javascript
evaluateSubComponentDataOrNull(
    subComponentInternalId : String,
    ...key : String | Integer
) : any | null
```

Same as `getSubComponentDataOrNull`, but considers the value an expression and attempts to evaluate it. See [evaluateData functions](#evaluatedata-functions) and [getSubComponentDataOrNull](#getsubcomponentdataornull).

#### evaluateSubComponentDataWithDefault

```javascript
evaluateSubComponentDataWithDefault(
    subComponentInternalId : String,
    ...key : String | Integer,
    defaultValue: any
) : any
```

Same as `getSubComponentDataWithDefault`, but considers the value an expression and attempts to evaluate it. See [evaluateData functions](#evaluatedata-functions) and [getSubComponentDataWithDefault](#getsubcomponentdatawithdefault).

#### findData

```javascript
findData(
    ...key : String | Integer,
    filterFunction: string,
) : [{key: String | Integer, value: any}]
```

Parameters:

* `key`: path parts as String keys or Integer array indices; path segments are separate arguments, e.g. `findData('a', 'b', 0, 'c', 'myFilterFunction')` to access `data.a.b[0].c`; this is the path to an object or an array of objects, which will be filtered
* `filterFunction`: name of the criteria function as a string; this function is called for each key-value pair in the target object or for each element in the target array

The filter function has following header `filterFunction(key: String | Integer, value: any) : boolean` and has to be available at the time of the `findData` call. The `filterFunction` is accessed by its name as a string argument. It can be either a local function or a component function.

The `findData` functions are useful for finding data based on a criteria function. The result of this function is an array of retrieved data objects that match the criteria. The criteria function is a function available in the same context where the `findData` function is called. It has two arguments (one for the key, the other for the value) and returns a boolean value indicating whether the key-value pair matches the criteria. This function is called by its name as a string argument. The Roomle Component Tool provides a code snippet to help you retrieve the data, giving you a template for the find function, criteria function, and the code comes nested in a wrapper function. See the example below for more details and good practice recommendations.

The `findData` function is somewhat similar to the `filter` function in JavaScript (returns an array of matching objects), but it is specifically designed to work with the Roomle Component Tool's data structure. To have an actual `find` counterpart, you can retrieve the first element of the array returned by `findData` and return it as a value, as in the following example.

The `findData` function returns an array of objects that meet the criteria function. If there is no match, the array is empty (length is 0). The return value of the function has the following structure:

```javascript
[
    {
        key: String | Integer, 
        value: Object | String | Integer | Float | Boolean
    },
    ...
]
```

Example usage:

* Let's say we have the following data and a length parameter, based on which we want to retrieve the data entry:

```json
{
    "data": {
        "beamConstruction": [
            { "minLength": 0, "maxLength": 1000, "screwsCount": 2, "material": "isdt:red" },
            { "minLength": 1000, "maxLength": 1600, "screwsCount": 3, "material": "isdt:green" },
            { "minLength": 1600, "maxLength": 2000, "screwsCount": 4, "material": "isdt:blue" }
        ]
    }
}
```

It is recommended to encapsulate the findData call in a helper function in order to keep the code clean. Example for a recommended pattern for the `findData` function usage:

```javascript
// Use a wrapper function to encapsulate the logic. Use a _ or __ prefix to avoid variable shadowing.
function find_beamConstruction(__length) {
    // The criteria function, where the key is either the index of the data in the array or the key of the object in the data object.
    function find_beamConstruction_filter(key, value) {
        // in this example:
        // key is 0, 1, 2
        // value is the object at that index: {minLength, maxLength, screwsCount, material}
        return __length > value.minLength && __length <= value.maxLength;
    }
    // Call the findData function, where we define the path of the data in the same way as in the getData function.
    // The last argument is the stringified name of the criteria function.
    _.beamConstruction_raw = findData('beamConstruction', 'find_beamConstruction_filter'); // returns an array of objects that match the criteria
    
    /**
     * _.beamConstruction_raw is:
     * [
     *     {
     *         key: 0, 1 or 2,
     *         value: { "minLength": ..., "maxLength": ..., "screwsCount": ..., "material": ... }
     *     }
     * ]
     */

    if (length(_.beamConstruction_raw) > 0) { // if the search result is not empty, the length is greater than 0
        _.beamConstruction_raw_0 = get(_.beamConstruction_raw, 0);
        // Extract the first element of the array and return it.
        _.found = _.beamConstruction_raw_0.value;
        return _.found;
    }
}

// either null or the first matching object
beamConstruction = find_beamConstruction(length);

// ---- use the found data ----
AddCube({self.length, 20, 50});
 SetObjSurface(self.beamConstruction.material);
```

> Hint: You can use the `findData` code snippet provided by the Roomle Component Tool. It generates a wrapper function, a criteria function, and the `findData` call. You just need to fill in the criteria logic and the data path.

Filter the data at the path by a criteria function. This is a `getData` counterpart.

#### findAndEvaluateData

```javascript
findAndEvaluateData(
    ...key : String | Integer,
    filterFunction: string
) : [{key: String | Integer, value: any}]
```

Filter the data at the path by a criteria function and evaluate them. Works like [`findData`](#finddata), but string scripts are considered to be script expressions and the result contains their resulting values. The difference is like between [`getData`](#getdata) and [`evaluateData`](#evaluateData) counterpart.

#### findSubComponentData

```javascript
findSubComponentData(
    subComponentInternalId : String,
    ...key : String | Integer,
    filterFunction: string
) : [{key: String | Integer, value: any}]
```

Filter the data at the path in a subComponent by a criteria function. See the [`findData`](#finddata) and [`getSubComponentData`](#getsubcomponentdata) counterpart.

#### findAndEvaluateSubComponentData

```javascript
findAndEvaluateSubComponentData(
    subComponentInternalId : String,
    ...key : String | Integer,
    filterFunction: string
) : [{key: String | Integer, value: any}]
```

Filter the data at the path in a subComponent by a criteria function and evaluate them. This is an [`findData`](#finddata) and [`evaluateSubComponentData`](#evaluatesubcomponentdata) counterpart.

#### findDataKey

```javascript
findDataKey(
    ...key : String | Integer,
    filterFunction: string
) : [string]
```

Returns: Array of keys of the data objects that match the criteria.

Similarly to the `findData` family of functions, which return the objects themselves, the `findDataKey` functions return an array of keys of the data objects that match the criteria. The keys are either numerical indices for the cases where an array is searched, or the keys of the object in the data object. This is useful in cases where the data contains a mix of data that you would retrieve with the `getData`, but also a few entries that you would like to evaluate, as in the following example:

```json
{
    "data": {
        "beamConstruction": {
            "short": {
                "minLength": 0,
                "maxLength": 1000,
                "screws": 2,
                "material": "isdt:red",
                "articleNr": "'R' | string(beamLength, 0) | 'S2'"
            },
            "medium": {
                "minLength": 1000,
                "maxLength": 1600,
                "screws": 3,
                "material": "isdt:green",
                "articleNr": "'G' | string(beamLength, 0) | 'S3'"
            },
            "long": {
                "minLength": 1600,
                "maxLength": 2000,
                "screws": 4,
                "material": "isdt:blue",
                "articleNr": "'B' | string(beamLength, 0) | 'S4'"
            }
        }
    }
}
```

```javascript
function getBeamConstructionIndex(__length) {
    function find_beamConstruction_filter(key, value) {
        return __length > value.minLength && __length <= value.maxLength;
    }
    _.beamConstructionIndices = findDataKey('beamConstruction', 'find_beamConstruction_filter'); // based on the criteria ['short' or 'medium' or 'long']
    if (length(_.beamConstructionIndices) > 0) {
        return get(_.beamConstructionIndices, 0);
    }
}

beamConstructionIndex = getBeamConstructionIndex(length); // either 'short', 'medium' or 'long', or NULL_VALUE

articleNr = evaluateData('beamConstruction', beamConstructionIndex, 'articleNr' );
```

#### findSubComponentDataKey

```javascript
findDataKey(
    subComponentInternalId : String,
    ...key : String | Integer,
    filterFunction: string
) : [string]
```

Counterpart of [`findDataKey`](#finddatakey) for searching in subComponents.

### Miscellaneous Functions

Functions that do not fit in the categories above.

#### activeGroupInView

```javascript
activeGroupInView() : String
```

Queries the configurator UI to get the currently selected parameter group. This is useful for manipulating geometry based on what the user is configuring.

> ⚠️ **Warning:** This function can query the open group into a variable which can be used in the whole component. This is dangeours and can cause serious errors, because it is possible to change configuration based on the user interaction. The values retrieved by this function should only be used in the `geometry` script to change the view to hide walls, open doors etc. or to remove certain docking previews in the `parentDocking` `condition` if used together with the `connection.isPreview` getter. It is especially important to note, that this function IS NOT intended to project its value into the article number, label, pricing or docking points coordinates.

Returns: `key` property of the current parameter group

Usage:

* geometry:

```javascript
_.displayOpenDoor = activeGroupInView() === 'grpInternalEquipment';

AddCube(Vectorf3{doowWidth, doorThickness, doorHeight});
if (_.displayOpenDoor) {
    /* rotate the door to visualize it is open */
    RotateMatrixBy(Vector3f{0, 0, 1}, Vector3f{0, 0, 0}, 105);
}
```

* parent docking condition:

```javascript
if (connection.isPreview) {
    _.showPreviewOnOuterWall = activeGroupInView() !== 'grpInternalEquipment');
    if (!_.showPreviewOnOuterWall) {
        return false;
    }
}
```

#### getAbsolutePosition

```javascript
getAbsolutePosition() : String
```

Only in `collisionCondition`: `(componentRuntimeId: int) : Vector3f`

Returns the position of the current component in the coordinate system of the root component. This is the absolute position of the component withing the configuration, because the root component is always placed at the zero.

Inside of the `collisionCondition` script it is possible to optionally pass a componentId to the function to retrieve the absolute position of another component in the configuration.

> ⚠️ **Warning:** This function does not consider rotation of the docking points. It always returns the position of the component origin, regardless its rotation.

#### getComponentProperty

```javascript
getComponentProperty(
    key: 'runtimeId' | 'externalId' | 'catalogId',
    *componentId: integer
) : integer | string
```

Returns the unique runtime id, or component Id of the current component. If this function is used in a `collisionCondition` script, such a property of another colliding component can be retrieved.

Note: parts of an ID are `catalogId:externalId`

Parameters:

* `key` either `runtimeId`, `externalId` or `catalogId` string values
* `componentId` a runtime ID of a different component, only availabe in the `collisionCondition`

Returns:

* unique runtime ID as an integer
* external or catalog ID as a string

Usage:

```javascript
id = getComponentProperty('runtimeId'); // equivalent to getUniqueRuntimeId()
componentId =
  getComponentProperty('catalogId') | ':' | getComponentProperty('externalId'); // get current component combinedId
```

```json
"collisionCondition": "
    for (i = 0; i < length(collidingComponentIDs); i++) {
        collidingComponentId = get(collidingComponentIDs, i);
        // avoid collision with the catalog:shelf component
        if (getComponentProperty('externalId', collidingComponentId) == 'shelf') {
            return false;
        }
    }
    return true;
"
```

#### getDockPosition

```javascript
getDockPosition() : Vector3f
```

Get position of child docking point in the coordinate system of the parent.

Returns: Vector from parent origin to child docking point or zero Vector3f if component is the root component.

See [getPosition](#getposition) for more details.

#### getDockPositionRelativeToParentDock

```javascript
getDockPositionRelativeToParentDock() : Vector3f
```

Get position of the child docking point in the coordinate system of the parent relative to the parent docking point.

Returns:

* point - point: ideally zero Vector3f or the offset if configuration doesn't reload properly
* range - point: ideally zero Vector3f or the offset if configuration doesn't reload properly
* line - point: Vector from the beginning of the dockLine to the child docking point
* root: zero Vector3f

#### getEnvironmentProperty

```javascript
getEnvironmentProperty(
    key: 'country' | 'currency' | 'language' | 'unit' | 'unitString' | 'level'
) : String | int | null
```

Gets the environment property of the current configurator session. These properties can be set in the url arguments or behind the configuratorId in the [Tenant Settings](/rubens/content-creation/scripting-resources/200_150_tenantsettings.md).

Returns:

* `country` -> the ISO 3166-1 alpha-2 country code, e.g. 'us', 'de'
* `currency` -> the ISO 4217 currency code, e.g. 'USD', 'EUR'
* `language` -> the ISO 639-1 language code, e.g. 'en', 'de'
* `unit` -> `mm`, `cm`, `inch`, `inchfeet`
* `level` -> the current value/parameter `restrictionLevel`

#### getObjectProperty

```javascript
getObjectProperty(
    key: 'wallthickness' | 'configurationLoaded', 
    *defaultValue: boolean | int | float | string
) : boolean | int | float | string
```

Returns the value for the given property-key from the plan object.

`wallthickness`: Returns the thickness of the wall to which the plan object is attached if the object is used as a construction element. Otherwise, the default value or, if not present, 0 is returned.

`configurationLoaded`: Returns if the initial loading process of the configuration is completed.

#### getMaterialProperty

```javascript
getMaterialProperty(
    materialId: String, 
    propertyName: String, 
    fallback: String
) : String
```

Retrieves additional material data defined in material properties. See [Using GetMaterialPropery Function](/rubens/content-creation/scripting-resources/200_140_getmaterialproperty.md) for detailed description.

Parameters:

* `materialId`: Id of the target material
* `propertyName`: name of the property on the given material
* `fallback`: Value to return if material or property are missing

Returns: the value stored in the material property or fallback if no material is found or if the material doesn't have the property.

Usage:

* exmaple material entry:

```json
{
    "externalIdentifier": "fabric_blue",
    "id": "isdt:fabric_blue",
    "properties": {
        "pricegroup": "30"
    },
    ...
}
```

```javascript
getMaterialProperty(
  'isdt:fabric_blue',
  'pricegroup',
  'NULL'
); /* returns '30' */
getMaterialProperty('isdt:fabric_blue', 'type', 'NULL'); /* returns 'NULL' */
getMaterialProperty('doesnt:exist', 'something', 'NULL'); /* returns 'NULL' */
```

#### getPosition

```javascript
getPosition() : Vector3f
```

Only in `collisionCondition`: `(componentRuntimeId: int) : Vector3f`

Get position of the child component in the coordinate system of the parent.

Returns: Vector3f leading from parent component origin to child component origin or zero Vector if component is the root component.

Usage:

```javascript
position = getPosition();
parentOrigin = Vector3f{
    - xFromVector(position),
    - yFromVector(position),
    - zFromVector(position)
};
```

![Scheme of getPosition functions operation.](/files/I4QZbLjF2OQucsqKDqD5)

#### getListOfPolygonsFromSvg

```javascript
getListOfPolygonsFromSvg(
    svgData: String,
    *curvePointDensity: (int >= 2) = 8
) : Array<Vector2f>
```

An alternative way to get a list of 2D points from an SVG to [getPointlistFromSvg](#getpointlistfromsvg) is the `getListOfPolygonsFromSvg` function. This function returns a list of polygons, where each polygon is a list of points. The output of this function can be directly uesed with the `AddPrism` function to create a 3D geometry from an SVG input, including holes.

```json
{
    "id": "documentaiton:svg_prism_with_holes",
    "geometry": "
        _.svgData = '<svg width=\"600\" height=\"600\"><path d=\"M0 50 A50 50 0 0 0 50 0 H500 V600 H0 Z M200 200 A50 50 0 1 0 201 201 Z M400 400 A50 50 0 1 0 401 401 Z\" /></svg>';
        _.polygons = getListOfPolygonsFromSvg(_.svgData);
        AddPrism(100, _.polygons, bevelWidth = 0);
        SetObjSurface('egger:h3332_st10');
        RotateMatrixBy({1,0,0},{0,0,0},-90);
    "
}
```

![prism from SVG with holes](/files/0lATnhdtPttkhJGqkbXq)

[**Example - Prism from SVG with holes**](https://www.roomle.com/t/cp/index.html?id=roomle_script_documentation:prism-from-svg-with-holes)

#### getPointlistFromSvg

```javascript
getPointlistFromSvg(
    svgData: String,
    *index: int = 0,
    *curvePointDensity: (int >= 2) = 8
) : Array<Vector2f>
```

Converts SVG path data to a list of 2D points. This can be further used to pass to the [AddPrism](#addprism) function to create an three dimensional object from an 2D SVG input.

This function supports all the basic functionality of SVGs but is limited to the geometrical shape related properties. It can create a pointlist (contour) from the SVG, but does not read any color values (color, gradient, etc.) or any advanced functiality (animations, etc.).

It is also possible to read multiple shapes defined in a single SVG file. It is necessary to pass the index of the desired shape. If not, the first shape is always returned by default.

It is also possible to define the pointlist resolution for curves, called "curve point density". If a shape consist of a straight line, only the start and end points get added to the list. If the shape is a curve it adds the amount of points defined by the value on that curve depending on the curve-point-density parameter, including the start and end points. Therefore, the minimum value is 2. If none is provided it defaults to 8, which was chosen to be a good value for use cases in RoomleScript.

The following table shows the outcomes when using different values for the curve point density parameter.

| 2                                                                   | 4                                                                   | 8 (default)                                                         | 16                                                                  |
| ------------------------------------------------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------- |
| <img src="/files/z4XbypiXZjG34OIY8EJR" alt="" data-size="original"> | <img src="/files/cIJu3HAGtH5AXsvP3f8L" alt="" data-size="original"> | <img src="/files/dU8il9p8pINPHNJCp1CL" alt="" data-size="original"> | <img src="/files/LerUyY6ezBAPQZTfM15w" alt="" data-size="original"> |

The provided SVG data has to be a string and can not be loaded directly from a file. It is necessary to paste the SVG file contents into a component definition, preferably into the `data` structure.

The function is memoized, so if you call it multiple times with the same SVG data and curve point density, the pointlist is only calculated once and cached for later calls. This makes it possible to call this function multiple times with different indices without a performance impact.

```json
{
    "id": "catalog:component",
    "geometry": "
        _.svgData = '<svg width=\"600\" height=\"600\">
                <rect fill=\"#3dc1d3\" x=\"0\" y=\"0\" width=\"100\" height=\"100\"/>
                <rect fill=\"#3dc1d3\" x=\"100\" y=\"100\" width=\"200\" height=\"200\"/>
                <rect fill=\"#3dc1d3\" x=\"300\" y=\"300\" width=\"300\" height=\"300\"/>
            </svg>';

        AddPrism(100, getPointlistFromSvg(_.svgData, 0), bevelWidth = 0);
            SetObjSurface('isdt:yellow');

        AddPrism(100, getPointlistFromSvg(_.svgData, 1), bevelWidth = 0);
            SetObjSurface('isdt:red');

        AddPrism(100, getPointlistFromSvg(_.svgData, 2), bevelWidth = 0);
            SetObjSurface('isdt:blue');
    "
}
```

The outcome of this example looks like this:

<figure><img src="/files/vRhahfekzjvbpY3GIpUh" alt=""><figcaption><p>3D geometries created from an SVG-file input</p></figcaption></figure>

Notice how the offset definition in the SVG content also affects the position of the geometry in the 3D scene.

#### getUniqueRuntimeId

```javascript
getUniqueRuntimeId() : Integer
```

Returns unique runtime ID that has been assigned to this component instance in the configurator. Every root component, child component and subComponent will have an unique number. This number is not reused after for example deleting components. It is not persistent between configuration instances. Can be used to determine the timing order in which the components have been added to the configuration.

It is useful as a decision factor between two components connected via sibling points in cases that no other way to choose one component from more.

This number is not persistent between configurator instances (i.e. after configuration reload or between undo/redo actions) and in most cases, storing it as a parameter makes no sense and can lead to errors.

Example: See the [Quadpost Shelf System template](/rubens/content-creation/scripting-resources/400_30_quadpost.md)

Returns: Integer representing the unique runtime ID of the component in the configuration.

Usage:

```javascript
/* in onUpdate */
if (isnull(uid)) {
  /* enter only in the first onUpdate call */
  uid = getUniqueRuntimeId(); /* could be for example 7 */
}
/* in a siblingPoint.assignmentScripts.onUpdate script to determine owner of the shared wall */
// the higher one wins
if (self.height > other.height) {
  self.hasSharedWall = true;
} else if (self.height < other.height) {
  self.hasSharedWall = false;
// both are same height, let the older one win
} else {
  self.hasSharedWall = self.uid > other.uid;
}
```

#### ifnull

```javascript
ifnull(
    variable: any,
    fallback: any
) : any
```

Checks if a variable is undefined or null and returns the variable or fallback. Useful for making sure a variable is defined.

Parameters:

* `variable`: the variable to check for null
* `fallback`: a value to return if varialbe is null or undefined

Returns:

* either the `variable` or the `fallback` if `variable` is null

Usage:

```javascript
/* checks if variable 'initialized' is null and if yes, returns true in order to enter the block */
if (ifnull(initialized, true)) {
  /* make sure to initialize in order to enter only once */
  initialized = true;
}
```

#### in

```javascript
in(
    valueToCheck: any, 
    value1: any, value2: any, ...
) : boolean
```

Useful for checking if a list of values containes a specific value.

Parameters:

* `valueToCheck`: the value that is being searched for in the list
* `valueN`: any number of arguments that will form the list

Returns

* `true` if valueToCheck is equal to at least one of the other values, otherwise `false`

Usage:

```javascript
fruit = 'banana';
isFruit = in(fruit, 'apple', 'banana', 'cherry');       /* true */
pearIsValid = in('pear', 'apple', 'banana', 'cherry');  /* false */
```

Most used to compare a variable to a list of constants, however you can also check a constant to a list of variables.

```javascript
/* check if at least one of variables is true */
isGroceryItem = in(true, isFruit, isVegetable, isDairy);
/* which is actually equivalent to */
isGroceryItem = (isFruit + isVegetable + isDairy) > 0;
```

#### isEnabled

```javascript
isEnabled(
    parameterKey: String
) : Boolean
```

Returns if a parameter is enabled.

Parameters:

* `parameterKey`: key of the parameter

Returns: True if the parameter exists and its `enabled` flag is true, false otherwise.

Usage:

```javascript
if (isVisible(depth)) {
  actualDepth = depth;
} else {
  /* do not take the depth parameter value but a fallback */
  actualDepth = 700;
}
```

#### isnull

```javascript
isnull(
    value: any
) : Boolean
```

Checks for null values.

Parameters:

* `value`: identifier to be checked

Returns: True if identifier is undeclared, null or after setnull call.

Usage:

* initialize on component load, at the beginning of onUpdate

```javascript
if (isnull(initialized)) {
  initialized = true;
  /* initialize values here */
}
```

* in a connection script of a docking range:

```javascript
/* compute indeces of the docking point */
if (isnull(connection.i)) { connection.i = xFromVector(connection.position) / > offset; }
if (isnull(connection.j)) { connection.j = yFromVector(connection.position) / > offset; }
```

#### isVisible

```javascript
isVisible(
    parameterKey: String
) : Boolean
```

Returns if a parameter is visible.

Parameters:

* `parameterKey`: the parameter key to get the visible flag value from

Returns: True if the parameter exists and its `enabled` flag is true, false otherwise.

Usage:

```javascript
if (isVisible(depth)) {
  actualDepth = depth;
} else {
  /* do not take the depth parameter value but a fallback */
  actualDepth = 700;
}
```

#### setnull

```javascript
setnull(
    variable: any
) : void
```

Undeclares a variable of given name and sets it to null.

Usage:

```javascript
setnull(x);
if (isnull(x)) {  /* true */
   ...
}
```

#### xFromVector

```javascript
xFromVector(
    v: Vector2f | Vector3f
) : float
```

Get X component of a Vector

Parameters:

* `v` the vector

Returns: x component of the Vector or 0 if fails

Usage:

```javascript
v2 = Vector2f{10, 20};
v3 = Vector3f{100, 200, 300};
x2 = xFromVector(v2); /* returns 10 */
x3 = xFromVector(v3); /* returns 100 */
```

#### yFromVector

```javascript
yFromVector(
    v: Vector2f | Vector3f
) : float
```

`(v : Vector2f | Vector3f) : float`

Get Y component of a Vector

Parameters:

* `v` the vector

Returns: X component of the Vector or 0 if fails

Usage:

```javascript
v2 = Vector2f{10, 20};
v3 = Vector3f{100, 200, 300};
x2 = yFromVector(v2); /* returns 20 */
x3 = yFromVector(v3); /* returns 200 */
```

#### zFromVector

```javascript
zFromVector(
    v: Vector3f
) : float
```

Get Z component of a Vector

Parameters:

* `v` the vector

Returns: Z component of the Vector or 0 if fails

Usage:

```javascript
v2 = Vector2f{10, 20};
v3 = Vector3f{100, 200, 300};
x2 = zFromVector(v2); /* returns 0 */
x3 = zFromVector(v3); /* returns 300 */
```

## onUpdate Script Functions

Functions available in the main `onUpdate` script of the component definition. Attempt to call these functions in other scripts will result in an error. Calls from an `onUpdate` type component function is possible.

### AddAbsoluteDimensioning

```javascript
AddAbsoluteDimensioning(
    axis: string,
    from: float,
    to: float,
    level: int,
    *context: 'component' | 'object' | 'both' = 'component',
    *label: string = ''
) : void
```

Dynamic possibility to add a component dimensioning object from the onUpdate script. Values for the axis are `x`, `y` and `z` by default and you can add more axes using the [`AddAbsoluteDimensioningAxis`](#addabsolutedimensioningaxis). See [Dimensioning](/rubens/content-creation/roomlescript-reference/configurationformat.md#dimensioning) for more detailed description.

### AddAbsoluteDimensioningAxis

```javascript
AddAbsoluteDimensioningAxis(
    key: string,
    origin: Vector3f,
    direction: Vector3f,
    labelDirection: Vector3f
) : void
```

Dynamic possibility to add a component dimensioning object from the onUpdate script. See [Dimensioning](/rubens/content-creation/roomlescript-reference/configurationformat.md#dimensioning) for more detailed description.

### requestDockItem

```javascript
requestDockItem(
    item: string,
    parentPosition: Vector3f,
    *childPosition: Vector3f
) : void
```

Sends a docking request to the configurator. After the current update call will have been finished, a docking of the defined configuration will happen. Connection and child component will be available in the next update call. Because the docking does not happen in the configurator kernel, compatible version of the SDK has to be used in custom integration for this function to be available. You need to define which docking points to use on both side by their positions.

This function is only valid in the main `onUpdate` script and must be inside an if-block.

Parameters:

* `item` Either an itemId or a stringified configuration JSON that should dock.
* `parentPostion` Vector3f containing coordinates of a valid parent docking point on the parent side.
* `childPostion` Optional: Vector3f containing coordinates of a valid child docking point. If not provided, the first valid child docking point will be used.

Hint: To find out the correct arguments, you can do the docking manually and then check the configuration (which can be achieved by calling `RoomleConfigurator.getCurrentConfiguration()` or by using the interface buttons of the Rubens CLI). The parent docking point argument is the `dockPosition` of the child component, the child docking point is the `dockChild` value of the child component. Both these vectors are equal to the evaluated `position` values of the docking points.

Hint: It is better to not hardcode the catalogId of the current component, because the component could be published into a draft catalog. You can retrieve the catalogId by calling the [`getComponentProperty('catalogId')`](#getcomponentproperty) function, in which case the docked component will always be from the same catalog as the parent component.

Usage:

```
/*
  Get the catalogId of the current component and create a childComponentId by appending ':itemId'.
  It is better not to hardcode the catalogId, because the component could be published into a draft catalog.
*/
_.catalogId = getComponentProperty('catalogId');
_.childItemId = _.catalogId | ':' | 'itemId';
_.childComponentId = _.catalogId | ':' | 'componentId';
_.assignedWidth = 200;

requestDockItem('catalog:itemId', Vector3f{width / 2, 0, 0}, Vector3f{ 0, 0, 0 });
requestDockItem(
  '{
    \"componentId\": \"' | _.childComponentId | '\", 
      \"parameters\": {
        \"width\": ' | _.assignedWidth | '
      }
    }
  ', 
  Vector3f{ width / 2, 0, 0 },
  Vector3f{ - ' | _.assignedWidth | ' / 2, 0, 0 });
```

### setBoxForMeasurement

```javascript
setBoxForMeasurement(
    Box: Vector3f,
    Offset: Vector3f
) : void
```

Defines the box to be used for calculating the measurements of this component. This overrides the bounding box of the geometry in order to change the measurements.

⚠️ This is only valid if called in `onUpdate`

Parameters:

* `Box`: defines the size of the bounding box
* `Offset`: position of the left rear bottom corner of the box

Hint: This behaves like a combination of [AddPlainCube](#addplaincube) and [MoveMatrixBy](#movematrixby). Refer to the [Dimensioning](/rubens/content-creation/scripting-resources/200_120_dimensioning.md#measurement-box) chapter for more information and examples.

Usage:

```javascript
setBoxForMeasurement(Vector3f{1600, 800, 670}, Vector3f{-800, 0, 0});
```

### setEnabled

```javascript
setEnabled(
    parameterKey: String,
    value: Boolean
) : void
```

Sets and overrides the `enabled` flag of the parameter with the given key. This applies for the update loop in which this call is done.

Parameters:

* `parameterKey`: key of the parameter
* `value`: final status of the `enabled` flag

Usage:

```json
"parameters": [
    {
        "key": "width",
        "type": "Decimal",
        "defaultValue": 100,
        "unitType": "length",
        "enabled": true,
        "validValues": [100, 200, 300]
    }
],
"onUpdate": "setEnabled('width', false) /* disables the width parameter */"
```

### setOrigin

```javascript
setOrigin(
    origin: Vector3f
) : void
```

For computing the position in the Room Planner and the Rubens Configurator, the origin of a component is always the center of bounding box of the current geometry. This however can cause movement relative to the floor while changing dimensions or animating. This function allows to set a custom origin for the component, anchoring it to a specific point.

See [Origin of Components](/rubens/content-creation/roomlescript-reference/configurationformat.md#origin-of-components) for more details.

### setVisible

```javascript
setVisible(
    parameterKey: String,
    value: Boolean
) : void
```

Sets and overrides the `visible` flag of the parameter with the given key. This applies for the update loop in which this call is done.

Parameters:

* `parameterKey`: key of the parameter
* `value`: final status of the `visible` flag

Usage:

```json
{
    "parameters": [
        {
            "key": "width",
            "type": "Decimal",
            "defaultValue": 100,
            "unitType": "length",
            "visible": true,
            "validValues": [100, 200, 300]
        }
    ],
    "onUpdate": "setVisible('width', false) /* hides the width parameter */"
}
```

## Collision Condition Script Functions

Functions are only available in the `collisionCondition` script of a docking point, range or line. Attempt to call these functions in other scripts will result in an error. To learn more about collision detection and how it works in RoomleScript, see [Collision detection of docked components](/rubens/content-creation/roomlescript-reference/configurationformat.md#collision-detection-of-docked-components).

Note: Inside the collisionCondition script, there are variants of the [`getAbsolutePosition`](#getAbsolutePosition), [`getPosition`](#getPosition) and [`getComponentProperty`](#getComponentProperty) functions that allow to pass a component runtime ID to retrieve information about the other component in the collision.

### collidingComponentIDs

```javascript
collidingComponentIDs : [Integer]
```

This is not a function, but a getter available in the collisionCondition script. It contains list of other components that collide by their bounding boxes or by their boundingGeometry. You can iterate over elements of this list and check other collision condition script functions to evaluate the collision condition value.

Example:

```javascript
// iterate over the other colliding components
for (_.i = 0; _.i < length(collidingComponentIDs); _.i++) {
    _.collidingComponentId = get(collidingComponentIDs, _.i); // unique runtime ID of the colliding componen
    _.collidingComponentExternalId = getComponentProperty('externalId', _.collidingComponentId); // externalId part of the componentId
    // avoid collision with shelf, hanger and drawer components of the mywardrobe configurator
    if (in(_.collidingComponentExternalId, 'mywardrobe_shelf', 'mywardrobe_hanger', 'mywardrobe_drawer')) {
        return false;
    }
}
return true;
```

### getBoxForMeasurementOrigin

```javascript
getBoxForMeasurementOrigin(
    *runtimeId: int
) : Vector3f
```

Returns the (local) origin position of the measurement box of this component relative to its own root (not global!). ONLY Inside of the `collisionCondition` script it is possible to optionally pass a componentId to the function to retrieve the data from the corresponding component.

### getBoxForMeasurementSize

```javascript
getBoxForMeasurementSize(
    *runtimeId: int
) : Vector3f
```

Returns the size of the measurement box of this component. ONLY Inside of the `collisionCondition` script it is possible to optionally pass a componentId to the function to retrieve the data from the corresponding component.

### getBoxOrigin

```javascript
getBoxOrigin(
    *runtimeId: int
) : Vector3f
```

Returns local origin position of the bounding box of the (other) component with the given runtimeId (or of this/self component if no runtimeId is given) relative to the root of this/self component.

### getBoxSize

```javascript
getBoxSize(
    *runtimeId: int
) : Vector3f
```

Returns size of the bounding box of the (other) component with the given runtimeId (or of this/self component if no runtimeId is given).

## Geometry Functions

These functions are available in the `geometry`, `boundingGeometry`, `previewGeometry` and `geometryHD` scripts and in functions of type `geometry`.

Geometry functions are of two kinds: instantiation functions and modification functions. The modification functions always apply to the last call of the instantiation function of to the last group that was started with a `BeginGroup()` call and ended with an `EndGroup()` call. CSG operators apply to the last two instantiation function calls or groups and provide a new modification target.

There are certain enumerations that are used in some of the geometry functions argument. See:

* [EdgeStyle](/rubens/content-creation/roomlescript-reference/configurationformat.md#edgestyle)

### Keyword Arguments of Geometry Functions

In order to be able to fulfill various requirements, like bevel styles and sizes or material mappings, there are many optional parameters for the geometry functions. To avoid confusion and to make the geometry functions easier to use and read, some geometry functions support these parameters to be passed as [keyword arguments](/rubens/content-creation/roomlescript-reference/roomlescript-language-reference.md#keyword-arguments).

See the function signatures to see which parameters can are optional and can therefore be passed as keyword arguments. See their datatype to determine if a single value or an array of values can be passed.

If the parameter is an array, this array follows a specific index scheme to apply the values to the respective face of the geometry. The overview of the indices is shown in the respective function documentation below.

If these arrays are shorter than the number of faces, the first value at index 0 is applied to the rest of the faces.

#### Material Parameters

All basic geometry functions support passing a list (array) of material IDs directly in the constructor, either via array of strings or keyword arguments. If different materials get passed, the geometry gets created with the provided different materials. The order of the IDs inside the array is defined as mentioned above in the section [Geometry faces indices](/rubens/content-creation/roomlescript-reference/configurationformat.md#Geometry-faces-indices).

If a material for a side gets provided via keyword arguments but no base material ("material") was given an error message will be logged and the base material gets set to the default value (empty string which results in plain white in the renderer). Some geometries, like prism or cylinder, have no left, right, front and back, but only a side/mantle that goes all around. In this case the material for the side has to be set via the 'materialFront' property or corresponding index in the array, all other provided side materials will be ignored.

If `SetObjSurface(...)` function gets called after component creation, all previously defined materials get overridden.

Example:

For the `AddCube` function, the `materials` parameter can be used as follows:

```javascript
[
    'isdt:black',  // base - all faces
    'isdt:white',  // bevel - bevel is changed to white
    'isdt:red'     // top - top is changed to red
                   // the rest has isdt:black - the first value of the array
]
```

which is equivalent to:

```javascript
material = 'isdt:black',
materialBevel = 'isdt:white',
materialTop = 'isdt:red'
// the rest has isdt:black - the base material parameter
```

```javascript
materials = ['isdt:red', 'isdt:green', 'isdt:blue', 'isdt:black', 'isdt:cyan', 'isdt:magenta', 'isdt:yellow', 'isdt:white'];
AddCube(Vector3f{1000, 1000, 1000}, Vector2f{1, 1}, 0, Vector2f{0, 0}, 50, materials);
```

The result is a cube with a green bevel, a blue top, black bottom, cyan front, magenta back, yellow left side and white right side. The first member in the array is always the base material, so if not all sides are explicitly set to a material these sides get the base material assigned.

#### Edge Style and Width Parameters

See [Edge Style](/rubens/content-creation/roomlescript-reference/configurationformat.md#edgestyle) for more details and examples.

### UvTransform parameters

Similar to the multi-material arrays for geometry construtor functions it is possible to pass multiple different UV-transforms for all basic geometries. That means that all three different UV-transforms can be passed via a single value, to apply the same UV-transform to all faces, or as arrays of values, to apply different UV-transforms to different faces. So for example a `uvScale` can be passed as single value like `Vector2f{2, 2}` to apply a 2-times scaling to all faces of the geometry, or as multiple value array `[{2, 2}, {3, 3}, {4, 4}]` to apply different UV-scalings to different faces of the geometry. The order of the transforms inside the array is defined the same way as it is for the multi material arrays, see the individual function reference documentation for details.

If `SetUvTransform(...)` function gets called after component creation, the transform gets added to the existing one.

```javascript
/*
    If the wood texture has vertical grain orientation, 
    a shelf with correct UV mapping, long in the X direction
    can be created like this:
*/
AddCube(
    {800, 400, 19},
    material = 'isdt:wood_oak',
    uvRotation = 90
);

/*
    If this shelf should be created with the long side in Y direction,
    either use the first one and RotateMatrixBy afterwards, or keep the top and bottom
    rotation at 0:
*/
AddCube(
    {400, 800, 19},
    material = 'isdt:wood_oak',
    uvRotation = [90, 90, 0, 0],
    edgeStyle = 'fillet',
    bevelWidth = 5
);
```

#### EdgeStyle Parameters

With the `edgeStyle` keyword argument it is possible to set the edge style of the geometry. The available values are `edge`, `chamfer`, `fillet` or `defeult`.

| value     | description                                                                                  |
| --------- | -------------------------------------------------------------------------------------------- |
| `edge`    | Creates a sharp edge, no beveling.                                                           |
| `chamfer` | Creates a chamfered edge, where the edge gets cut off at an angle of 45°.                    |
| `fillet`  | Creates a rounded edge, where the edge gets rounded with a radius of the bevel width.        |
| `default` | Default edges for backward compatibility. Creates a chamfer edge with fillet normal vectors. |

![edge style](/files/tJYMv7yZuQXjS7MEhkkE)

**Cube**

```json
{
    "id": "roomle_script_documentation:cube_edge_style",
    "geometry": "
        AddCube(
            {1000, 1000, 1000},
            bevelWidth = 250,
            edgeStyle = 'fillet',
            material = 'kronospan:k411_oe',
            materialBevel = 'kronospan:k353_rt'
        );
    "
}
```

![cube with edge style](/files/So5Z07v6i77RSX01DPvl)

[**Example - cube with edge style**](https://www.roomle.com/t/cp/?id=roomle_script_documentation:cube_edge_style_item)

**Prism**

```json
{
    "id": "roomle_script_documentation:prism_edge_style",
    "geometry": "
        _.p = [{1000, 0}];
        for (_.i = 1; _.i < 6; _.i++) {
            _.a = 2 * M_PI * _.i / 6;
            pushBack(_.p, {1000 * cos(_.a), 1000 * sin(_.a)});
        }
        AddPrism(
            1000,
            _.p,
            bevelWidth = 300,
            edgeStyle = 'chamfer',
            material = 'egger:h1344_st32',
            materialBevel = 'egger:f206_pm'
        );
    "
}
```

![prism with edge style](/files/1hmvAPl4Iq7elfH5uf33)

[**Example - cube with edge style**](https://www.roomle.com/t/cp/?id=roomle_script_documentation:prism_edge_style_item)

**Cylinder**

```json
{
    "id": "roomle_script_documentation:cylinder_edge_style",
    "geometry": "
        AddCylinder(
            500,
            500,
            1000,
            32,
            bevelWidth = 250,
            edgeStyle = 'fillet',
            material = 'pfleiderer:r30023_vv',
            materialBevel = 'pfleiderer:s63028_xmsm'
        );
    "
}
```

![cylinder with edge style](/files/AArAEKkAlfxQasxSYWRO)

[**Example - cube with edge style**](https://www.roomle.com/t/cp/?id=roomle_script_documentation:cylinder_edge_style_item)

**Cone, truncated Cone**

![cone geometry](/files/zzpIIvBjJlnrNDgglfYw)

```json
{
    "id": "catalog_id:component",
    "geometry": "
        AddCylinder(
            600,
            160,
            1000,
            32,
            bevelWidth = 200,
            edgeStyle = 'fillet',
            material = 'egger:h3359_st32',
            materialBevel = 'egger:f093_st7'
        );
    "
}
```

![cone with edge style](/files/5ip0G2agJ2ff4k2kSjgj)

[**Example - cube with edge style**](https://www.roomle.com/t/cp/?id=roomle_script_documentation:cone_edge_style_item)

#### Individual edge Style and Width Paramameter

It is possible to define the edge style and width for each side of the geometry individually. This can be done with the keyword arguments `edgeStyleTop`, `edgeStyleBottom`, `edgeStyleSide` and `edgeWidthTop`, `edgeWidthBottom`, `edgeWidthSide`. The allowed values for the edge styles are the same as for the `edgeStyle` keyword argument, so `edge`, `chamfer`, `fillet` or `default`.\
However, unlike with `edgeStyle` the value for `edgeStyleTop`, `edgeStyleBottom`, `edgeStyleSide` cannot only be a single value but also an array of values, where the index of the value inside the array defines the edge of the geometry it gets applied to. If the value is not an array but a single value, it applies to all edges in the area. In addtion a spcific edge cann be addressed by using the keywords `edgeStyleTopyN`, `edgeStyleBottomN`, `edgeStyleSideN`, `edgeWidthTopN`, `edgeWidthBottomN`, or `edgeWidthSideN`, wher `N` is the index of the edge.\
This allows the edge style and width to be defined in a structured manner. For example, the general edge style and the general edge width can be defined with `edgeStyle` and `bevelWidth` and additionally a different style and/or width for the top can be defined with `edgeStyleTop` or `edgeWidthTop` and on top a specific edge can be defined with `edgeStyleTop0`, `edgeStyleTop1`, etc. or `edgeWidthTop0`, `edgeWidthTop1`, etc. This allows for a very flexible definition of the edge style and width for each side of the geometry.

### Instantiation Functions

#### AddCube

```javascript
(
  Size:Vector3f{width,depth,height},
  **uvScale: Vector2f | [Vector2f] = {1, 1},
  **uvRotation: float | [float] = 0,
  **uvOffset: Vector2f | [Vector2f] = {0, 0},
  **bevelWidth: float = 2,
  **edgeWidthTop, **edgeWidthBottom, **edgeWidthSide: float = null,
  **edgeWidthTop0, **edgeWidthBottom0, **edgeWidthSide0, **edgeWidthTop1, **edgeWidthBottom1, **edgeWidthSide1, **edgeWidthTop2, **edgeWidthBottom2, **edgeWidthSide2, **edgeWidthTop3, **edgeWidthBottom3, **edgeWidthSide3 : float = null,
  **material: String = '<empty material>',
  **materials: Array<String> = [],
  **materialBevel, **materialTop, **materialBottom**, **materialFront, **materialBack, **materialLeft, **materialRight: String = null,
  **edgeStyle: EdgeStyle = 'default',
  **edgeStyleTop, **edgeStyleBottom, **edgeStyleSide: EdgeStyle = null,
  **edgeStyleTop0, **edgeStyleBottom0, **edgeStyleSide0, **edgeStyleTop1, **edgeStyleBottom1, **edgeStyleSide1, **edgeStyleTop2, **edgeStyleBottom2, **edgeStyleSide2, **edgeStyleTop3, **edgeStyleBottom3, **edgeStyleSide3 : EdgeStyle = null
) : void
```

Parameters:

* `Size`: Vector3f defining the size of the cube in width (x), depth (y) and height (z) direction
* `uvScale`: Vector2f defining the scaling of the UV coordinates in U and V. The higher the value, the more often texture repeats (it appears smaller).
* `uvRotation`: float defining the rotation of the UV coordinates in degrees
* `uvOffset`: Vector2f defining the offset of the UV coordinates in U and V direction
* `bevelWidth` / `edgeWidth*`: float defining the width of the bevel on all edges of the cube. If set to 0, edges are sharp.
* `material*`: materialId of the material to be applied to the base or to the specific face of the cube
* `materials`: array of materials applied to the faces of the cube:
* `edgeStyle*`: style of all edges of the cube. See [EdgeStyle](/rubens/content-creation/roomlescript-reference/configurationformat.md#edgestyle) for possible values.

Adds a beveled or plain cube (depending on the argumnets) to the scene, placed by the left rear lower corner. Its origin is in the center of the cube and an internal transformation is applied to move the cube to instantiate at the mentioned corner. This makes it easier to position the cube in the scene, but has the side effect that animated rotation is applied around the center of the cube.

Array indices:

Parameters that have a possibility to pass an array will follow these indices to apply the values to the respective face of the cube. If the array has less than 8 entries, the first entry at index of 0 is applied to the rest of the faces.

| Geometry Face | Array Index | Example keyword argument |
| ------------- | ----------- | ------------------------ |
| BASE          | 0           | `material`               |
| BEVEL         | 1           | `materialBevel`          |
| TOP           | 2           | `materialTop`            |
| BOTTOM        | 3           | `materialBottom`         |
| FRONT         | 4           | `materialFront`          |
| BACK          | 5           | `materialBack`           |
| LEFT          | 6           | `materialLeft`           |
| RIGHT         | 7           | `materialRight`          |

Example:

```javascript
AddCube(
    {800, 400, 19},
    material = 'isdt:wood_oak',
    uvRotation = 90
);
```

![Shelf from AddCube](/files/i6Ur9vXwe6UsFnvSAZ93)

```javascript
AddCube(
    {1000, 500, 100},
    material = 'demoCatalogId:grid', // all faces
    materialBevel = 'isdt:yellow', // all bevels
    edgeStyleTop = 'fillet', // all top edges rounded, but rear edge sharp
    edgeStyleTop1 = 'edge',
    edgeWidthTop = 10,
    edgeStyleSide = 'edge', // default sharp edges at side
    edgeStyleSide2 = 'fillet', // front left edge
    edgeWidthSide2 = 10,
    edgeStyleSide3 = 'fillet', // front right edge
    edgeWidthSide3 = 10,
    edgeWidthBottom = 0,
    uvRotation = [0, 0, 90, 0, 45, 45, 45, 45], // top rotated in right angle, all sides 45 degrees
    uvScale = [{1, 1}, {1, 1}, {10, 10}] // top scaled 10 times
);
```

![AddCube with Keyword arguments](/files/EKWETNX2SXeQv4NU4n62)

#### AddCylinder

```javascript
(
  RadiusBottom: float,
  RadiusTop: float,
  Height: float,
  CircleSegments: float,
  **uvScale:Vector2f | [Vector2f] = {1, 1},
  **uvRotation:float | [float] = 0,
  **uvOffset:Vector2f | [Vector2f] = {0, 0},
  **bevelWidth: float = 2,
  **material: String = null,
  **materials: [String] = null,
  **edgeStyle: EdgeStyle = 'default',
  **edgeWidthTop: EdgeStyle = null,
  **edgeWidthBottom: EdgeStyle = null,
  **edgeStyleTop: EdgeStyle = null,
  **edgeStyleBottom: EdgeStyle =null,
) : void
```

Adds a cylinder or cone (based on if the two radii are same or different). Its origin is in the center of the bottom base.

Parameters:

* `radiusBottom` radius of the bottom base
* `radiusTop` radius of the top
* `height` height (distance of bottom and top)
* `faces` number of faces that form the prism approximating the cylinder (3 - triangular prism, 6 - hexagonal prism etc.)
* `uvScale` multiply UV values of the vertices - the higher the value, the smaller the material
* `uvRotation` rotate UV values of the vertices, in a left-hand direction
* `uvOffset` increase UV values of the vertices -> moves the material in a negative direction
* `bevelWidth` default 2, size of the cube's bevel (measured parallel to its walls)

Array indices:

| Geometry Face | Index | Keyword                                                |
| ------------- | ----- | ------------------------------------------------------ |
| BASE          | 0     | `material`                                             |
| BEVEL         | 1     | `materialBevel`                                        |
| TOP           | 2     | `materialTop`                                          |
| BOTTOM        | 3     | `materialBottom`                                       |
| SIDE          | 4     | `materialSide`                                         |
| SIDE #N       |       | `materialSide0`, `materialSide1`, `materialSide2`, ... |

Usage:

```javascript
AddCylinder(1000, 300, 2000, 32, Vector2f{1, 1}, 0, Vector2f{0, 0}, 100);
 SetObjSurface('isdt:white');
```

![Cone made with the AddCylinder function example.](/files/l62PGcfQSiljRcYjzk7j)

#### AddDimensioning

```javascript
(
    axis: String,
    from: float,
    to: float,
    level: int,
    *context: 'component' | 'object' | 'both' = 'component',
    *label: String,
    *parameterKey: String = null,
    *parameterFunction: String = null
) : void
```

Adds a [Geometry dimensioning](/rubens/content-creation/roomlescript-reference/configurationformat.md#geometry-dimensioning) object to the scene. See the chapter linked chapter to learn about the feature.

Parameters:

* `axis`: Name of the dimensioning axis to use. Must be defined with the [`AddDimensioningAxis`](#adddimensioningaxis) function prior to use.
* `from`: Start point of the dimensioning line along the axis in mm.
* `to`: End point of the dimensioning line along the axis in mm.
* `level`: Level of the dimensioning line in mm. Similar to dimensioning level.
* `context`: Context in which the dimensioning is applied. Possible values are `component` (default) and `scene`.
* `parameterKey`: Optional parameter key to link the dimensioning to a parameter. If provided, the dimensioning will be interactive, providing an input field in the 3D scene.
* `parameterFunction`: Optional parameter function to link the dimensioning to a parameter function. If provided, the dimensioning will be interactive, providing an input field in the 3D scene, which takes the value of the interactive dimensoning and passes the returned value into the parameter function.

An existing axis name must be provided, which must be defined with the [`AddDimensioningAxis`](#adddimensioningaxis) function first.

#### AddDimensioningAxis

```javascript
(
    key: string,
    origin: Vector3f,
    direction: Vector3f,
    labelDirection: Vector3f
) : void
```

Defines a free dimensioning axis for the [AddDimensioning](#adddimensioning) function that can be used with a dimensioning object.

Parameters:

* `key`: Unique key of the axis to be used in the `AddDimensioning` function.
* `origin`: Origin of the axis in local coordinates, serving as a 0 point for the `from`, `to` values of the dimensioning object.
* `direction`: Direction of the axis as a direction (possible unit) vector, serving also as the positive direction for the `to` value of the dimensioning object. Length of this vector does not matter.
* `labelDirection`: Direction into which the dimensioning line is drawn. Length of this vector does not matter.

#### AddExternalMesh

```javascript
(
    meshId: String,
    Bounds: Vector3f,
    *BoundsOffset: Vector3f,
    *uvScale: Vector2f = {1, 1},
    *uvRotation: float = 0,
    *uvOffset: Vector2f = {0, 0}
) : void
```

Instantiate a mesh stored in RAPI (the Rubens Admin database). Has an overload for modifying UV settings.

Parameters:

* `meshId` the ID of the mesh in a `catalogueId:meshName` pattern
* `Bounds` size of the bounding box of the mesh useful for measurements, camera position and preview cube
* `BoundsOffset` position of the bounding box
* `uvScale` multiply UV values of the vertices - the higher the value, the smaller the material
* `uvRotation` rotate UV values of the vertices, in a left-hand direction
* `uvOffset` increase UV values of the vertices -> moves the material in a negative direction

When performing an export from Blender with the Roomle Blender Addon, you will get a `txt` file with `AddExternalMesh` functions accompanying the files you will be uploading to Rubens Admin. You can also get the function from the RuAd mesh entry page. Bounds and boundsOffset tells the configurator the size and position of the loading box until the mesh is loaded.

#### AddLightSource

```javascript
AddLightSource(
    type: 'spot' | 'point' | 'area',
    position: Vector3f, 
    **direction: Vector3f, 
    **angle: number, 
    **color: string, 
    **intensity: number,
    **distance: number,
    **penumbra: number, 
    **decay: number, 
    **width: number, 
    **height: number
) : void
```

Adds a light to the scene. See [Light sources](/rubens/content-creation/roomlescript-reference/configurationformat.md#light-sources) for more information.

A light source is a target for modifier functions, like `MoveMatrixBy` and can be grouped.

Parameters:

* `type`: type of the light source, possible values are `spot`, `point` and `area`
* `position`: position of the light source
* `direction`: direction of the light source, required for `spot` and `area` lights
* `angle`: angle of the light cone for `spot` lights, in degrees
* `color`: color of the light, as hex code, e.g. `#ffffff` for white
* `intensity`: intensity of the light
* `distance`: distance of the light, how far the light reaches for `spot` and `point` lights
* `penumbra`: softness of the edge of the light cone for `spot` lights, between 0 and 1
* `decay`: amount the light dims along the distance, for `spot` and `point` lights, higher values mean nearer dimming
* `width`: width of the light source for `area` light source
* `height`: height of the light source for `area` light source

#### AddMesh

```javascript
AddMesh(
    Vertices: [Vector3f]
) : void
```

Creates a mesh from a list of vertices, calculating triangles, normals and UVs automatically.

```javascript
AddMesh(
    Vertices: [Vector3f], 
    Indices: [Integer],
    uvCoordinates: [Vector2f],
    normals: [Vector3f]
) : void
```

Creates a mesh from list of vertices, triangles, normals and UVs are defined manually.

* Parameters:
* `vertices` list of the vertices
* `indices` list of indices of the vertices forming the triangles, following a left-hand thumb rule
  * ⚠️ length of the indices array must be divisible by 3
* `uvCoordinates` multiply UV values of the vertices - the higher the value, the smaller the material
  * ⚠️ length of the array must be the same as the length of the `vertices` array
* `normals` rotate UV values of the vertices, in a left-hand direction
  * ⚠️ length of the array must be the same as the length of the `vertices` array

Usage:

```javascript
n2 = 1 / sqrt(2);
n3 = 1 / sqrt(3);
AddMesh(
    Vector3f[
        /* 0 */{0, 0, 0},
        /* 1 */{300, 0, 0},
        /* 2 */{0, 300, 0},
        /* 3 */{0, 0, 300}
    ],
    [
        0, 1, 2,
        0, 3, 1,
        0, 2, 3
    ],
    Vector2f[
        /* uv coordinate of vertex 0 */{0, 0},
        /* uv coordinate of vertex 1 */{600, 0},
        /* uv coordinate of vertex 2 */{600, -600},
        /* uv coordinate of vertex 3 */{0, 600}
    ],
    Vector3f[
        /* normal of vertex 0 */{n3, n3, n3},
        /* normal of vertex 1 */{0, n2, n2},
        /* normal of vertex 2 */{n2, 0, n2},
        /* normal of vertex 3 */{n2, n2, 0}
    ]
);
SetObjSurface('demoCatalogId:grid');
```

![AddMesh example.](/files/GiaUKn9ASe4PVskkQq46)

Creates a mesh from list of vertices, triangles, UV and normal coordinates.

```javasript
(
  vertices: [Vector3f],
  indices: [Integer],
  *uvScale: Vector2f,
  *uvRotation: float,
  *uvOffset: Vector2f
) : void
```

Creates a mesh from list of vertices and triangles. Overload for UV modifiers is available.

* Parameters:
* `vertices` list of the vertices
* `indices` list of indices of the vertices forming the triangles, following a left-hand thumb rule
  * ⚠️ length of the indices array must be divisible by 3
* `uvScale` multiply UV values of the vertices - the higher the value, the smaller the material
* `uvRotation` rotate UV values of the vertices, in a left-hand direction
* `uvOffset` increase UV values of the vertices -> moves the material in a negative direction

Usage:

```javascript
AddMesh(
    Vector3f[
        {0, 0, 0},   /* index 0, origin */
        {300, 0, 0}, /* index 1, right */
        {0, 300, 0}, /* index 2, forward */
        {0, 0, 300}  /* index 3, top */
    ],
    [
        0, 1, 2,  /* triangle in Z plane */
        0, 3, 1,  /* triangle in Y plane */
        0, 2, 3   /* triangle in X plane */
    ]
);
 SetObjSurface('demoCatalogId:grid');
```

![AddMesh triangle winding order example.](/files/6fNSCsLhAhFvHifJuaFk)

Creates a mesh from list of vertices, triangles, UV and normal coordinates.

#### AddPlainCube

```javascript
AddPlainCube(
    Size: Vector3f,
    *uvScale: Vector2f | [Vector2f] = {1, 1},
    *uvRotation: float | [float] = 0,
    *uvOffset: Vector2f | [Vector2f] = {0, 0},
    *materials: [String]
) : void
```

A cube with sharp edges. A shortcut for an `AddCube` with bevel size of 0.

Usage:

```javascript
AddPlainCube({1000, 1000, 1000});
```

#### AddPrism

```javascript
AddPrism(
    Height: float,
    Vertices: [Vector2f] | [[Vector2f]],
    **uvScale: Vector2f | [Vector2f] = {1, 1},
    **uvRotation: float | [float] = 0,
    **uvOffset: Vector2f | [Vector2f] = {0, 0},
    **bevelWidth: float = 2,
    **material: String = '<empty material>',
    **materials: [String],
    **materialBevel: String,
    **materialTop: String,
    **materialBottom: String,
    **materialSide: String,
    **materialSide0: String,
    **materialSideN: String,
    **edgeStyle: EdgeStyle = 'default',
    **edgeWidthTop: EdgeStyle,
    **edgeWidthBottom: EdgeStyle,
    **edgeStyleTop: EdgeStyle,
    **edgeStyleBottom: EdgeStyle
) : void
```

Extrusion of a planar closed sketch in the Z direction. If the materials array is not used, the bevel is not an actual geometric bevel like in cases of other primitive shapes, but is faked by adjustments of normals (this ensures backward compatibility).

Parameters:

* `Height` length of the extrusion
* `Vertices`
  * if `[Vector2f]`: list of vertices forming the sketch
  * if `[[Vector2f]]`: First `[Vector2f]` is the outer contour, the following `[Vector2f]` are holes in the shape
* `materials`: An array with at least two materials triggers the new construction algorithm with real bevels. See description below.
* `bevelWidth`, `edgeStyle`, `material`, ... see [Keyword Arguments of Geometry Functions](#keyword-arguments-of-geometry-functions) for more details and [AddCube](#addcube) for an example.

Creates an extruded object given the 2D Shape and the height where bevel width 0 creates sharp prism. You can optionally pass an array with material IDs, see [Material parameter](/rubens/content-creation/roomlescript-reference/configurationformat.md#Material-parameter). The values for `uvScale`, `uvRotation` and `uvOffset` can also be passed via array to apply different transforms to each geometry face, see section [UvTransform parameters](/rubens/content-creation/roomlescript-reference/configurationformat.md#UvTransform-parameters). Bevels where not working correctly for prisms so there is a new implementation in place. To use the new construction algorithm you need to pass more then one material or uvTransform to the construction function. This can be the same material or uvTransform twice but it is needed to trigger the new algorithm. This extra step is needed to ensure backwards compatibility.

Array indices:

| Geometry Face | Index | Keyword                                                |
| ------------- | ----- | ------------------------------------------------------ |
| BASE          | 0     | `material`                                             |
| BEVEL         | 1     | `materialBevel`                                        |
| TOP           | 2     | `materialTop`                                          |
| BOTTOM        | 3     | `materialBottom`                                       |
| SIDE          | 4     | `materialSide`                                         |
| SIDE #N       | N     | `materialSide0`, `materialSide1`, `materialSide2`, ... |

Usage: Example of a 90 degrees slice of a cirle.

```javascript
/* sine values for angles */
s0 = 0;
s15 = 0.2588190451;
s30 = 0.5;
s45 = 0.7071067812;
s60 = 0.8660254038;
s75 = 0.9659258263;
s90 = 1;
radius = 100;
AddPrism(
    100,
    Vector2f[
        {0, 0},
        {radius * s90, radius * s0},
        {radius * s75, radius * s15},
        {radius * s60, radius * s30},
        {radius * s45, radius * s45},
        {radius * s30, radius * s60},
        {radius * s15, radius * s75},
        {radius * s0, radius * s90}
    ]
);
 SetObjSurface('demoCatalogId:grid');
```

Prisim with individual materials for each side:

```json
{
    "id": "roomle_script_documentation:prism_side_face_material",
    "geometry": "
        AddPrism(
            500,
            [{0, 500}, {476, 155}, {294, -405}, {-294, -405}, {-476, 155}],
            bevelWidth = 20,
            material = 'roomle_script_documentation:black',
            materialBevel = 'roomle_script_documentation:white',
            materialSide0 = 'roomle_script_documentation:red',
            materialSide1 = 'roomle_script_documentation:green',
            materialSide2 = 'roomle_script_documentation:blue',
            materialSide3 = 'roomle_script_documentation:yellow',
            materialSide4 = 'roomle_script_documentation:magenta'
        );
    "
}
```

[**Example - prism with individual material on either side**](https://www.roomle.com/t/cp/?id=roomle_script_documentation:prism_side_face_material_item)

![prism with individual material on either side](/files/NnUrVblBZBwQXeHxlvYQ)

[**Example - prism with individual uv transformation on either side**](https://www.roomle.com/t/cp/?id=roomle_script_documentation:prism_side_face_uv_item)

![prism with individual uv transformation on either side](/files/B4oOOUWC1V4FO3UjzKTy)

**Prism with cut-outs**

It is possible to create a prism with cut-outs (holes) in the geometry. To do this, an array of polygons is passed to the `AddPrism` function. Polygons are defined as arrays of points, where each point is a Vector2f. The polygon defines the outline and the holes of the prism. The function `AddPrism` creates a prism with the specified outline and holes, subtracting the holes from the prism geometry. Unlike the CSG MINUS operator, the cut-outs are not created by a 3D operation, but by defining the holes in the outline of the prism.

Examples:

```json
{
    "id": "roomle_script_documentation:prism-with-hole",
    "geometry": "
        _.outline = [{-300, -600}, {300, -600}];
        _.n = 64;
        for (_.i = 0; _.i < _.n / 2; _.i++) {
            _.a = M_PI * _.i / (_.n / 2);
            pushBack(_.outline, {300 * cos(_.a), 300 * sin(_.a)});
        }
        _.hole = [{180, 0}];
        for (_.i = 1; _.i < _.n; _.i++) {
            _.a = 2 * M_PI * _.i / _.n;
            pushBack(_.hole, {180 * cos(_.a), 180 * sin(_.a)});
        }
        AddPrism(
            100,
            [_.outline, _.hole],
            bevelWidth = 50,
            edgeStyle = 'chamfer'
        );
        SetObjSurface('pfleiderer:f76001_sd');
        RotateMatrixBy({1,0,0},{0,0,0},90);
    "
}
```

![prism with hole](/files/pIEkoMHOy7iQkpeDs0W0)

[**Example - Prism with hole**](https://www.roomle.com/t/cp/index.html?id=roomle_script_documentation:prism-with-hole)

```json
{
    "id": "catalog_id:component",
    "geometry": "
        _.outline = [{0, 0}, {0, 800}, {1150, 800}, {1200, 850}, {1200, 1150}, {1250, 1200}, {2000, 1200}, {2000, 0}];
        _.hole1 = [{200, 200}, {200, 600}, {600, 600}, {600, 200}];
        _.hole2 = [{700, 200}, {700, 600}, {1100, 600}, {1100, 200}];
        _.polygons = [_.outline, _.hole1, _.hole2];
        AddPrism(
            120,
            _.polygons,
            edgeWidthTop = 50,
            edgeStyle = 'edge',
            edgeStyleTop = ['edge', 'chamfer', 'chamfer', 'chamfer', 'chamfer', 'chamfer', 'edge', 'edge'],
            edgeWidthBottom = 0,
            edgeStyleBottom = 'edge',
            material = 'egger:u311_st9',
            materialTop = 'egger:f030_st75',
            materialBevel = 'egger:h3408_st38',
            materialSide1 = 'egger:h3408_st38',
            materialSide2 = 'egger:h3408_st38',
            materialSide3 = 'egger:h3408_st38',
            materialSide4 = 'egger:h3408_st38',
            materialSide5 = 'egger:h3408_st38'
        );
    "
}
```

![worttop with cut-outs](/files/AC6PJBzg5NDrRlzdT8xQ)

[**Example - Worktop with cutouts**](https://www.roomle.com/t/cp/index.html?id=roomle_script_documentation:prism-edge-style-and-holes)

#### AddRectangle

```javascript
AddRectangle(
    Size: Vector2f,
    *uvScale: Vector2f | [Vector2f] = {1, 1},
    *uvRotation: float | [float] = 0,
    *uvOffset: Vector2f | [Vector2f] = {0, 0},
    *materials: [String]
) : void
```

Adds an up facing flat quad in the ground plane with origin in its center. Passing multiple materials or uvTransforms via array is possible but has no effect because Rectangle has only one face. Only the first value will be taken.

Parameters:

* `Size` size of the quad
* `uvScale` multiply UV values of the vertices - the higher the value, the smaller the material
* `uvRotation` rotate UV values of the vertices, in a left-hand direction
* `uvOffset` increase UV values of the vertices -> moves the material in a negative direction
* `materials` material or array of materials to be applied to the quad

#### Copy

```javascript
Copy(
    *copyAnimations: Boolean = false
) : void
```

Creates a copy of the last instantiated object and switches the target of all modifiers to the newly created copy instantiated object.

\[Animations] are not copied by default. If the `copyAnimations` parameter is set to true, all animations of the original object are copied to the new object as well.

Usage:

```javascript
screws = 3;
width = 400;
spacing = width / (screws + 1);
offset = spacing / 2;

AddCube(Vector3f{400, 40, 10});
 SetObjSurface('isdt:gray');

BeginObjGroup('CREW + NUT + SHIM');
    /* shim */
    AddCylinder(14, 14, 1, 32, Vector2f{1, 1}, 0, Vector2f{0, 0}, 0);
     MoveMatrixBy(Vector3f{0, 0, -1});
    Copy();
     MoveMatrixBy(Vector3f{0, 0, 11});
    /* nut */
    AddCylinder(10, 10, 7, 6, Vector2f{1, 1}, 0, Vector2f{0, 0}, 0);
     MoveMatrixBy(Vector3f{0, 0, -8});
    Copy();
     MoveMatrixBy(Vector3f{0, 0, 19});
    /* screw */
    AddCylinder(3, 3, 14, 32);
     MoveMatrixBy(Vector3f{0, 0, -2});
EndObjGroup('SCREW + NUT + SHIM');
 SetObjSurface('demoCatalogId:chrome');
 MoveMatrixBy(Vector3f{spacing, 20, 0});

/* start with one, we already have the first screw */
for (i = 1; i < screws; i = i + 1) {
    Copy();
     MoveMatrixBy(Vector3f{spacing, 0, 0});
}
```

#### SubComponent

```javascript
SubComponent(
    subComponentInternalId: String
) : void
```

Instantiates a geometry of the subComponent of a given `internalId` with its current assigned values. The subComponent must have its `active` flag set to true. Any modifiers will apply to the whole subComponent geometry as if it was in a group.

For detailed explanation, refer to the [SubComponents](/rubens/content-creation/scripting-resources/200_70_subcomponents.md) chapter.

Usage:

```json
"subComponents": [
    {
        "internalId": "SOFA",
        "active": "elementType == 'sofa'",
        "numberInPartList": 1,
        "assignments": {
            "material": "material_primary"
        }
    }
]
```

```javascript
if (elementType == 'SOFA') {
  SubComponent('SOFA');
}
```

### Grouping Functions

Most modifier functions target the last object (some CSG operators target the last two objects). To apply properties to multiple objects at once, you can group them and treat them further as one object. Grouping is done with `BeginObjGroup();` and `EndObjGroup();` functions. SubComponent instance also behaves like a group. If a custom component geometry function instantiates some geometry, it is not treated as a group and wrapping the contents of the function with `BeginObjGroup();` and `EndObjGroup();` is recommended in the function body.

#### BeginObjGroup

```javascript
BeginObjGroup() : void
```

Starts an object group. All further geometry objects until the `EndObjGroup();` call will be in the same group and will be affected by all other modifiers at once.

`BeginObjGroup();` will indent furher code by 4 spaces in the Roomle Component Tool VS Code extension. Every `BeginObjGroup();` should match to an `EndObjGroup();`. Can be nested in any way and combined with `SubComponent` or CSG operator calls.

Parameters:

* there are no arguments, but it is a common to pass a String argument defining the name of the group, however this serves more like as a comment and is ignored by the core.

Usage:

```javascript
BeginObjGroup();
    AddCube(Vector3f{1000, 1000, 1000});
     SetObjSurface('isdt:blue');
    MoveMatrixBy(Vector3f{ -1000, 0, 0});
    AddSphere(Vector3f{1000, 1000, 1000});
     MoveMatrixBy(Vector3f{0, 0, 500});
     SetObjSurface('isdt:green');
EndObjGroup();
 SetObjSurface('isdt:red'); /* overrides colour of the objects in the group, all will be red */
 MoveMatrixBy(Vector3f{0, 500, 0});
/*
adds to the position of the objects in the group:
* cube is at {-1000, 500, 0}
* sphere is at {0, 500, 500}
*/
```

#### EndObjGroup

```javascript
EndObjGroup() : void
```

Closes the group started by BeginObjGroup. Removes 4 spaces from indentation.

### Modifier Functions

Modifiers are functions called after an object or object group. There are transformations (position, rotation and scale of the object), UV transformations (modify texture mapping) and set material functions in RoomleScript. These functions are indented by one extra space in the Roomle Component Tool VS Code extension to add legibility.

Recommended order of transformations (which is also the most intuitive):

1. Scale
2. Rotate
3. Move

#### IntersectWithWalls

```javascript
IntersectWithWalls() : void
```

Indicates that the previously constructed geometry must be intersected with walls. Intersection with walls cannot be applied prior to 3D Boolean operations. Therefore, using a geometry that needs to be intersected by walls in a Boolean operation will result in an error. This should be used together with `component.planInteraction.intersectWithWalls` set to true.

#### MoveMatrixBy

```javascript
MoveMatrixBy(
    translation: Vector3f
) : void
```

Applies translation transformation to the last object or group. The position will be added (not overriden) to all previous transformations.

Parameters:

* `move`: addition to the position vector of the last object or group

Usage:

```javascript
AddCube(Vector3f{1000, 1000, 1000});
 MoveMatrixBy(Vector3f{0, 0, 1000}); /* moves 1000 mm up*/
```

#### MoveUvMatrixBy

```javascript
MoveUvMatrixBy(
    uvOffset: Vector2f
) : void
```

Addition to the mesh's UV coordinates. Positive values bring the texture to the left and to down on a cube.

Parameters:

* `uvOffset` the amount to move

Usage:

```javascript
AddCube(Vector3f{1000, 1000, 1000});
 SetObjSurface('demoCatalogId:grid');
 MoveUvMatrixBy(Vector2f{500, 100});
```

#### ReverseFaces

```javascript
ReverseFaces() : void
```

Reverses the faces of the last drawn object or group. This can fix issues when a mesh is drawn inside out, e.g. after a negative scale operation (mirroring). The winding order of the triangles is reversed.

#### RotateMatrixBy

```javascript
RotateMatrixBy(
    axis: Vector3f,
    pivot: Vector3f,
    angle: float
) : void
```

Parameters:

* `axis`: a direction vector of the axis around which you rotate
* `pivot`: a point definiing the position of the axis (together with `axis` defines the line)
* `angle`: amount of rotation in degrees

Applies the rotation transformation to the last object or group around a defined axis by an amount of degrees of angle in a clockwise direction.

![rotate](/files/a6CdM3hAMwdj771RRGo9)

The object is always rotated around the origin of the world (0, 0, 0). That means if the centre of the mesh is not (0, 0, 0) or the object is moved prior to rotation, the origin of the world is the pivot point of the rotation.

![rotate around orign](/files/V6U3BkhBnYLTUMSy9y5J)

To get better control over the rotation, the pivot point can be specified explicitly.

![rotate around pivot](/files/RbXZziq5dQndazeWr3QM)

Hint: This is a left hand rule. If you place your left hand thumb in the direction of the axis, fingers will show the positive direction of the rotation. To understand

Usage:

```javascript
AddCube(Vector3f{1000, 1000, 1000});
/* lifts the cube by its left side by 5 degrees */
/* axis goes forward through the lower right side edge */
 RotateMatrixBy(Vector3f{0, 1, 0}, Vector3f{1000, 0, 0}, 5);
```

#### RotateUvMatrixBy

```javascript
RotateUvMatrixBy(
    uvRotation: float
) : void
```

Rotation of the mesh's UV coordinates. Positive values rotatet the texture clockwise.

Parameters:

* `uvRotation` the amount to rotate

Usage:

```javascript
AddCube(Vector3f{1000, 1000, 1000});
 SetObjSurface('demoCatalogId:grid');
 RotateUvMatrixBy(45);
```

#### ScaleMatrixBy

```javascript
ScaleMatrixBy(
    scaling: Vector3f,
    *pivot: Vector3f = {0, 0, 0}
) : void
```

Applies a scale transform to the last object or group. Neutral value is 1.

Parameters:

* `scaling`: amount of scale to apply (multiply to previous, not override)
* `origin`: pivot point of the scaling operation

![scale](/files/dUfPX4V2cHtj6PUSYEFr)

The object is always scaled relative the origin of the world (0, 0, 0). This means that if the centre of the mesh is not (0, 0, 0) or the object is moved prior to scaling, the origin of the world is the pivot point for scaling.

![scale relative to origin](/files/xrDdWEuhNh3fGtBlepqe)

To get better control over the scaling, the pivot point can be specified explicitly.

![scale relative to pivot](/files/4On6Os0PUTVDYGapngQ3)

Usage:

```javascript
AddCube(Vector3f{1000, 1000, 1000});
 ScaleMatrixBy(Vector3f{1, 1, 0.001}, Vector3f{0, 0, 1000}); /* scales the cube to 1 mm thickness, top surface of the cube stays in place */
```

#### SetObjSurface

```javascript
SetObjSurface(
    MaterialId: String
) : void
```

Applies a material from RAPI to all meshes and faces of the last object or group.

Parameters:

* `MaterialId`: in format `catalogue:externalId` leading to an existing material entry in RAPI

Usage:

```javascript
AddCube(Vector3f{1000, 1000, 1000});
 SetObjSurface('isdt:black_transparent'); /* applies transparent black material to the cube */
```

#### SetObjSurfaceAttribute

```javascript
SetObjSurfaceAttribute(
    attributeName: string
) : void
```

Modifies the last object's material shader values. This is especially useful if you intend to have one normal map material which you can afterwards colourize in multiple possible colours. See [Material Attributes](/rubens/content-creation/roomlescript-reference/configurationformat.md#material-attributes) for more details.

Parameters:

* `attributeName`: either of the material definition, like `'color'`, `'alpha'`, `'roughness'`, `'metallic'` string values
* `attributeValue`:
  * `0.0f` to `1.0f` if `attributeName` is `alpha`, `rougness` or `metallic`
  * if attributeName is color, then a JavaScript compatible color definition, such as:
    * `#ffffff`
    * `rgb(255, 0, 128)`
    * `rgb(50%, 0%, 100%)`

Usage:

```javascript
AddSphere(Vector3f{1000, 1000, 1000});
 SetObjSurface('isdt:red');
 SetObjSurfaceAttribute('alpha', 0.5); // 50% transparency
 SetObjSurfaceAttribute('color', '#00ff00'); // green
```

#### SetUvTransform

```javascript
SetUvTransform(
    uvScale: Vector2f,
    uvRotation: float,
    uvOffset: Vector2f
) : void
```

Sets the UV trasnforms to a given values. This overrides any previous modifiers.

Parameters:

* `uvScale` multiply UV values of the vertices, neutral value is 1
* `uvRotation` rotate UV values of the vertices, in a left-hand direction
* `uvOffset` increase UV values of the vertices

#### ScaleUvMatrixBy

```javascript
ScaleUvMatrixBy(
    uvScale: Vector2f
) : void
```

Multiplication of mesh's UV coordinates. Higher values make the texture smaller. Neutral value is 1.

Parameters:

* `uvScale` the amount to scale; neutral value is 1; the higher the number, the more often the texture is repeated

Usage:

```javascript
AddCube(Vector3f{1000, 1000, 1000});
 SetObjSurface('demoCatalogId:grid');
 ScaleUvMatrixBy(Vector2f{2, 1});
```

### CSG Operators

CSG operators are modifiers to the meshes, which split or combine them. Some of them target the last two objects, some only the last one. CSG operators, especially the And, Or and Minus, are expensive operations and should be used sparingly and only with as simple geometries as possible. for example, if you want to cut a round hole into a cube, the maximum feasible performant option is 3 MinusOperator calls with a cylinder, creating a very complex mesh already. Standard mesh creation workflow is should be the first choice. Options are external meshes, AddPrism which can create geometry with holes or defining where the cuts into the geometry are and replace the partion of the mesh with a simple, preferably primitive geometry without bevels.

![CSG operations example](/files/QseXolzMKPfCVOx1AZf8)

#### AndOperator

```javascript
AndOperator() : void
```

Interserction of the last two objects or meshes.

Usage:

```javascript
AddSphere(Vector3f{500, 500, 500});
AddCube(Vector3f{400, 400, 400}, Vector2f{5, 5}, 0, Vector2f{0, 0}, 0);
 MoveMatrixBy(Vector3f{ -400 / 2, -400 / 2, -400 / 2});
AndOperator();
```

![Boolean operations example.](/files/1zc5rTEfz0U1JESuPLMy)

#### ClipOperator

```javascript
ClipOperator(
    position: Vector3f,
    direction: Vector3f,
    *material: String,
    *uvScale: Vector2f,
    *uvRotation: float,
    *uvOffset: Vector2f
) : void
```

Clips the previously constructed geometry with a plane and optionally creates a cap. The cap geometry is only generated if a material is specified. The resulting geometry object is the original part and the eventual cap together (modifiers target them whole).

Parameters:

* `position`: a point on the clipping plane
* `direction`: the normal vector of the clipping plane, the partion of the mesh in the direction of this vector will be kept
* `material`: if specified, the cap (filler) will be created with this material; otherwise the mesh will be cut open
* `uvScale`: multiply UV values of the cap's vertices
* `uvRotation`: rotate UV values of the cap's vertices, in a left-hand direction
* `uvOffset`: increase UV values of the cap's vertices

Example: see [ClipOperator](/rubens/content-creation/roomlescript-reference/configurationformat.md#clipoperator) for more details.

#### MinusOperator

```javascript
MinusOperator() : void
```

Subtracts the geometry of the last object from the penultimate object. Intersection plane will have imprinted the last object's UV map values.

This operator is very expensive and should be used sparingly. It should be tried out and checked for performance on the target meshes before production use.

Usage:

```javascript
AddSphere(Vector3f{500, 500, 500});
AddCube(Vector3f{400, 400, 400}, Vector2f{5, 5}, 0, Vector2f{0, 0}, 0);
 MoveMatrixBy(Vector3f{ -400 / 2, -400 / 2, -400 / 2});
MinusOperator();
```

![Example of how the second object imprints its UV mapping.](/files/0H7HkhexrKqrM1oB2eY0)

#### OrOperator

```javascript
OrOperator() : void
```

Union of two last geometry objects. Works similarily to an object group, but bakes the meshes in one, removing vertices inside the internal volume.

Usage:

```javascript
AddSphere(Vector3f{500, 500, 500});
AddCube(Vector3f{400, 400, 400}, Vector2f{5, 5}, 0, Vector2f{0, 0}, 0);
 MoveMatrixBy(Vector3f{ -400 / 2, -400 / 2, -400 / 2});
MinusOperator();
```

![Example of the OrOperator](/files/29ruljE2rO0k3ROJYshO)

#### StretchOperator

```javascript
StretchOperator(
    position: Vector3f,
    direction: Vector3f,
    distance: float,
    *material: String,
    *uvScale: Vector2f,
    *uvRotation: float,
    *uvOffset: Vector2f
) : void
```

Stretches the previously constructed geometry with at a plane. The object is divided into 2 parts in the plane and an the contour of the cut is extruded and inserted between the two parts. The part in the direction of the normal vector is moved, the other part stays in place. The resulting geometry object is the original parts and the extruded part together (modifiers target them whole).

Parameters:

* `position`: a point on the cutting plane
* `direction`: the normal vector of the cutting plane
* `distance`: the amount of extrusion in the direction of the normal vector
* `material`: material of the inserted extrusion; if not specified, the material of the target object is used
* `uvScale`: multiply UV values of the extrusion's vertices
* `uvRotation`: rotate UV values of the extrusion's vertices, in a left-hand direction
* `uvOffset`: increase UV values of the extrusion's vertices

### Animations

For the animations topic, see the [Animations Matrix](/rubens/content-creation/roomlescript-reference/configurationformat.md#animations-matrix) chapter.

There are two versions of the animation functions:

* `AnimatedMoveBy`, `AnimatedRotateBy`, `AnimatedScaleBy` that are recommended for preferred use and work in the same manner as the standard transformation functions, are applied to the object or object groups in the same way.
* `AnimationMatrixMoveBy`, `AnimationMatrixRotateBy`, `AnimationMatrixScaleBy` that apply the animation transformations to the local origins of the individual meshes. This is not as intuitive to use, but could be useful in some special cases. Note: cube from the AddCube function has its local origin at the center, not at its insertion point in the left-rear-bottom corner.

Animation functions have a `key` parameter, which is the `${animation.key}:${actionKey}`. E.g.:

```json
"animations": [
    {
        "key": "doors",
        "actions": [
            {
                "key": "close"
            },
            {
                "key": "open"
            }
        ]
    }
],
```

The keys are `doors:close` and `doors:open`.

#### AnimatedMoveBy

```javascript
AnimatedMoveBy(
    key: String,
    translation: Vector3f
) : void
```

Creates a translation animation for the last object or group.

#### AnimatedRotateBy

```javascript
AnimatedRotateBy(
    key: String,
    axis: Vector3f,
    pivot: Vector3f,
    angle: float
) : void
```

Creates a rotation animation for the last object or group.

#### AnimatedScaleBy

```javascript
AnimatedScaleBy(
    key: String,
    scaling: Vector3f,
    *pivot: Vector3f
) : void
```

Creates a scale animation for the last object or group.

#### AnimationMatrixMoveBy

```javascript
AnimationMatrixMoveBy(
    key: String,
    translation: Vector3f
) : void
```

Creates a translation animation for the local origin of the individual meshes of the last object or group.

#### AnimationMatrixRotateBy

```javascript
AnimationMatrixRotateBy(
    key: String,
    axis: Vector3f,
    pivot: Vector3f,
    angle: float
) : void
```

Creates a rotation animation for the local origin of the individual meshes of the last object or group.

#### AnimationMatrixScaleBy

```javascript
AnimationMatrixScaleBy(
    key: String,
    scaling: Vector3f,
    *pivot: Vector3f
) : void
```

Creates a scale animation for the local origin of the individual meshes of the last object or group.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.roomle.com/rubens/content-creation/roomlescript-reference/roomlescript-built-in-functions.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
