Skip to main content
Version: v3.1.36

Actions

Data Actions

create(...mods)

Creates a new bot or combination of bots with the given mods. Also triggers @onCreate on all the created bots. By default, bots are created with a unique #id, #creator set to the current bot.id, and #space set to shared. Bots must be created with at least one tag. If create() tries to make a bot with zero tags then an error will be thrown.

If #creator references a non-existent bot or a bot with a different #space than the created bot, then #creator will be set to null.

Each parameter is a mod that should be applied to the new bot(s). If no parameters are specified, then the new bot will have its #creator set to bot.id and #space set to shared. If an array of mods is used for a parameter, then one bot will be created for each unique combination of mods.

Examples:

Create a red bot
let myRedBot = create({
color: "red"
});
Create a parent and a child bot
let myParentBot = create({
creator: null,
label: "Parent"
});
let myChildBot = create({
creator: getID(myParentBot),
label: "Child"
});
Create a red bot in the tempLocal space
let myBot = create({ space: "tempLocal", color: "red" });
Create a bot from multiple mods
// myBot is placed in the "myDimension" dimension and is colored green
let myBot = create({ myDimension: true }, {
color: "green"
});
Create a red bot and a blue bot
let [myRedBot, myBlueBot] = create({ creator: null}, [
{
"color": "red"
},
{
"color": "blue"
}
]);

destroy(bot)

Removes the given bot, list of bots, or bot by #id and triggers @onDestroy for each of the destroyed bots.

Note that only destroyable bots will be destroyed. Bots that have #destroyable set to false will not be destroyed.

Also note that all bots that have #creator set to the #id of a destroyed bot will also be destroyed (unless they are not destroyable). This happens recursively until there are no more bots to destroy.

Examples:

Destroying a single bot
// Destroy a single bot that has #name set to "bob"
destroy(getBot("#name", "bob"));
Destroying a list of bots
// Destroy all the bots that have #color set to "red"
destroy(getBots("#color", "red"));
Destroying a bot by its id
// Destroy the bot with the #id: "config"
destroy("config");

applyMod(bot, ...mods)

Applies the given mods to the given bot.

The first parameter is the bot that the mods should be applied to.

The other parameters are the mods that should be applied to the bot. If two mods have the same tag, then the mod that is last in the list will win.

Examples

Set the "test" tag and "name" tag on a bot
applyMod(bot, {
test: true,
name: "bob"
});

subtractMods(bot, ...mods)

Removes the tags contained in the given mod(s) from the given bot or mod.

The first parameter is the bot or mod that the tags should be removed from.

The other parameters are the bots or mods that contain the tags which should be removed from the original bot.

Examples:

Remove a mod from this bot
const mod = {
color: 'red',
name: 'bob'
};

subtractMods(this, mod);
Remove multiple mods from this bot
subtractMods(this, {
color: 'red'
}, {
name: 'bob'
});

removeTags(bot, tagSection)

Removes all the tags from the given bot that match the given tag section.

The first parameter is the bot or list of bots that should have the tags removed.

The second parameter is a string or regex that specifies which tags to remove. If given a string, then all the tags that start with the given string will be removed. If given a regex, then all the tags which match the regex will be removed.

Examples:

Remove tags starting with "abc" from this bot
removeTags(this, "abc");
Remove tags named "hello" using a case-insensitive regex from this bot
removeTags(this, /^hello$/gi)

renameTag(bot, originalTag, newTag)

Renames the given original tag on the given bot or list of bots to the given new tag. If the original tag does not exist on the bot, then no changes will take place. If the new tag already exists on the bot, then it will be overwritten with the contents of the original tag.

The first parameter is the bot or list of bots that should have the tag renamed.

The second parameter is the name of the tag that should be renamed.

The third parameter is the new name that the tag should have.

Examples:

Rename the "auxColor" tag to "color"
renameTag(this, "auxColor", "color");

changeState(bot, stateName, groupName?)

Changes the state that the given bot occupies in the given group. If the state was changed, then the @[groupName][stateName]OnExit and @[groupName][stateName]OnEnter whispers are sent to the bot.

The first parameter is the bot whose state should be changed.

The second parameter is the value that should be set on the bot.

The third parameter is the name of the tag that should be changed on the bot. If not specified, then the #state tag will be used.

Examples:

Change the #state of the bot to "Running"
// Triggers @stateRunningOnEnter
changeState(bot, "Running");
Change the #playbackState of the bot to "Playing"
// Triggers @playbackStatePlayingOnEnter
changeState(bot, "Playing", "playbackState");

getLink(...bots)

Creates and returns a bot link that references the given bots. The link can then be stored in a tag to save it. Useful for creating bot links for an arbitrary number of bots.

Each parameter is the bot or bot ID that should be linked to.

Examples

Create a link to this bot
os.toast(getLink(thisBot));

getBots(..filters)

Gets an array of bots that match all of the given filter(s). The returned array is sorted alphabetically by the #id tag.

Each parameter is a bot filter. If no filters are specified, then all bots in the inst are returned. If multiple filters are specified, then only the bots that match all of the filters are returned.

Examples

Find all bots with the "test" tag
let bots = getBots(byTag("#test"));
Find all bots with #name set to "bob" and in the #people dimension
let bots = getBots(byTag("#name", "bob"), inDimension("people"));

getBots(tag, value?)

Gets an array of bots that match the given tag and value. The returned array is sorted alphabetically by the #id tag.

The first parameter is the name of the tag. Bots that have this tag will be included as long as they also match the second parameter.

The second parameter is the value the tag should match. If not specified, then all bots with the tag will be included. If specified, then only bots that have the same tag and value will be included. If you specify a function as the value, then it will be used to match tag values.

Examples

Find all the bots with #name set to "bob"
let bots = getBots("#name", "bob");
Find all bots with a #height larger than 2
let bots = getBots("#height", height => height > 2);
Find all bots with the #test tag
let bots = getBots("#test");

getBot(...filters)

Get the first bot that matches all of the given filter(s). If multiple bots match the given filter(s), then bots are sorted alphabetically by the #id tag and the first one is returned. If no bots match the given filter(s), then undefined is returned.

Each parameter is a bot filter. If no filters are specified, then the first bot in the inst is returned. If multiple filters are specified, then the first bot that matches all of the filters is returned.

Examples

Find a bot with the #test tag
let foundBot = getBot(byTag("#test"));
Find a bot with #name set to "bob" and in the #people dimension
let foundBot = getBot(byTag("#name", "bob"), inDimension("people"));

getBot(tag, filter?)

Gets the first bot that matches the given tag and value. If multiple bots match the given tag and value, then bots are sorted alphabetically by the #id tag and the first one is returned. If no bots match the given tag and value, then undefined is returned.

The first parameter is the name of the tag to search for.

The second parameter is the value the tag should match. If not specified, then the first bot with the tag will be returned. If specified, then the first bot that has the same tag and value will be returned. If you specify a function as the value, then it will be used to match tag values.

Examples

Find the first bot with #name set to "bob"
let foundBot = getBot("#name", "bob");
Find the first bot with a #height larger than 2
let foundBot = getBot("#height", height => height > 2);
Find the first bot with the #test tag
let foundBot = getBot("#test");

getBotTagValues(tag, filter?)

Gets a list of all the values in the inst for the given tag. Optionally accepts a filter for the tag values.

The first parameter is the name of the tag to search for.

The second parameter is optional and is the filter that the tag values should match. If not specified, then all the tag values are included. If it is a function, then it will be used to match values. Otherwise, only tags that match the value will be included.

Examples:

Find the number of bots named bob and print it
const numberOfBobs = getBotTagValues("#name", "bob").length;
os.toast(numberOfBobs);
Find all the bot ages above 10
const agesOver10 = getBotTagValues("#age", age => age > 10);

getID(bot)

Gets the ID of the given bot.

The first parameter is the bot whose ID should be retrieved. If given a bot ID, then it will be returned. If given null or something that is not a bot, then null will be returned.

Examples

Get the ID of the current bot
let id = getID(bot);
Get the ID of a bot with #name set to "bob"
let id = getID(getBot("#name", "bob"));

getJSON(data)

Gets the JSON representation of the given data.

The first parameter is the data that should be cloned into the JSON format. If given a bot, then the returned JSON will be able to be able to be converted back into a mod via getMod(bot).

Examples

Store a copy of a bot in a tag
let bob = getBot("#name", "bob");
tags.savedBot = getJSON(bob);

getFormattedJSON(data)

Gets the JSON representation of the given data formatted in a human-readable manner.

The first parameter is the data that should be cloned into the JSON format. If given a bot, then the returned JSON will be able to be able to be converted back into a mod via getMod(bot).

Examples

Sort a nicely formatted copy of a bot in a tag
let bob = getBot("#name", "bob");
tags.savedBot = getFormattedJSON(bob);

getSnapshot(bots)

Gets a snapshot of the given bots. Snapshots are like mods (see getMod(bot)) except they contain multiple bots and include the ID, space, tags, and tag masks of the bots.

The first parameter is the bot or list of bots that a snapshot should be created out of.

Examples

Create a snapshot of thisBot
const snapshot = getSnapshot(thisBot);
console.log(snapshot);
Create a snapshot of all the bots
const snapshot = getSnapshot(getBots());
console.log(snapshot);

diffSnapshots(first, second)

Calculates the difference between the two given snapshots. The returned value is such that if you were to apply the changes (using applyDiffToSnapshot(snapshot, diff)) it represents to the first snapshot you would end up with the second snapshot.

The first parameter is the snapshot that should be used as the baseline for the diff.

The second parameter is the snapshot that should be used as the target for the diff.

Examples

Calculate the diff between two snapshots
const first = getSnapshot([thisBot]);
thisBot.tags.color = 'red';
const second = getSnapshot([thisBot]);
const diff = diffSnapshots(first, second);

console.log(diff);

applyDiffToSnapshot(snapshot, diff)

Applies the given difference to the given snapshot and returns a new snapshot that represents the result.

The first parameter is the snapshot that the delta should be applied to. This is also called the baseline snapshot.

The second parameter is the delta that should be applied to the snapshot. You can create a delta from two snapshots by using the diffSnapshots(first, second) function.

Examples

Calculate a new snapshot from a baseline and diff
const first = getSnapshot([thisBot]);
const diff = {
[thisBot.id]: {
tags: {
color: 'red'
}
}
};
const second = applyDiffToSnapshot(first, diff);

console.log(second);

getMod(bot)

Gets a mod for the given bot and list of tags. The returned mod will only contain tags that are contained in the given list.

The first parameter is the bot or JSON string that should be cloned into a mod.

The other parameters are the tags that should be included in the returned mod. If no other parameters are specified, then all tags are included. If a parameter is a RegEx (Regular Expression), then it will include all the tags that match the expression.

Examples:

Get a mod with the current bot
let mod = getMod(bot);
Get a mod with only the #color and #label tags
let mod = getMod(bot, "color", "label");
Get a mod with every tag that starts with "on"
let mod = getMod(bot, /^on/g);

getBotLinks(bot)

Gets the list of bot links that are stored in tags on the specified bot. Returns an array with objects that have the following structure:

let result: {
/**
* The tag that the link was parsed from.
*/
tag: string;

/**
* The bot IDs that the link references.
*/
botIDs: string[];
}[];

This function can be useful if you want to discover what tags are linking to bots and get those bot IDs.

Examples:

Get the list of bot links on this bot
console.log(getBotLinks(thisBot));

updateBotLinks(bot, idMap)

Updates the links in the given bot to point to the new Bot IDs specified in the given ID map.

The first parameter is the bot whose links should be updated.

The second parameter is an object that maps old bot IDs to the new IDs that should replace them. Each property should be an old ID and each value should be a new ID.

Examples:

Change all references to "botA" to "botB" on thisBot
updateBotLinks(thisBot, {
"botA": "botB"
});

getBotPosition(bot, dimension)

Gets the 3D position of the given bot in the given dimension.

The first parameter is the bot or bot ID whose position should be retrieved.

The second parameter is the dimension that the position should be retrieved for.

Examples:

Get the position of this bot in the #home dimension
let position = getBotPosition(thisBot, "home");

getBotRotation(bot, dimension)

Gets the 3D rotation of the given bot in the given dimension.

The first parameter is the bot or bot ID whose rotation should be retrieved.

The second parameter is the dimension that the rotation should be retrieved for.

Examples:

Get the rotation of this bot in the #home dimension
let rotation = getBotRotation(thisBot, "home");

uuid()

Creates a new UUID. Useful for generating a random identifier that is guaranteed to be unique.

Examples:

Generate a new UUID and toast it
const id = uuid();

os.toast(id);

DateTime

DateTime is a class that makes representing, manipulating, and comparing date information easier than what is possible with the normal JavaScript Date class. Internally, CasualOS uses a library called luxon to provide the DateTime class to scripts.

When you save a DateTime to a tag, CasualOS will automatically format it so that it is automatically detectable as a date and will always be represented the same no matter where in the world you are. To do this, CasualOS uses the 📅 emoji as a prefix for date + time values and automatically parses them into DateTime objects.

For example, saving 📅2022-10-03 to the date tag will make tags.date be a DateTime value that represents midnight on the 3rd of October in 2022 in the UTC-0 time zone. If you want your date to represend midnight in another time zone, you can add the IANA time zone you want to the end of the value. This is midnight in Tokyo: 📅2022-10-03 Asia/Tokyo.

See luxon for more information and examples.

Examples:

Toast the current time in the local timezone
os.toast(DateTime.now());
Toast the current time in the UTC-0 timezone
os.toast(DateTime.utc());
Toast a specific time in the local timezone
os.toast(DateTime.local(2020, 6, 5, 4, 3, 2));
Toast a specific time in the UTC-0 timezone
os.toast(DateTime.utc(2020, 6, 5, 4, 3, 2));
Toast the current date in a nicely formated string
os.toast(DateTime.now().toLocaleString()); // => '2/15/2022'
Toast the current date and time in a nicely formated string
os.toast(DateTime.now().toLocaleString(DateTime.DATETIME_FULL)); // => 'April 20, 2017, 11:32 AM EDT'
Toast the current date and time in a nicely formated string
os.toast(DateTime.now().toLocaleString(DateTime.DATETIME_FULL)); // => 'April 20, 2017, 11:32 AM EDT'
Toast a date in a nice relative format to now
os.toast(DateTime.utc(2021, 6, 5, 4, 3, 2).toRelative()); // => '8 months ago'
Compare two dates to each other in hours
const date1 = DateTime.utc(2021, 6, 5, 4, 3, 2);
const date2 = DateTime.local(2021, 6, 5, 4, 3, 2);
const duration = date1.diff(date2, 'hours');
os.toast(duration.toHuman()); // => '-4 hours'
Check if one date is before another date
const date1 = DateTime.utc(2021, 6, 5, 4, 3, 2);
const date2 = DateTime.local(2021, 6, 5, 4, 3, 2);
const date3 = DateTime.local(2021, 6, 5, 4, 3, 2);

// Is date1 before date2?
os.toast(date1 < date2); // => 'true'

// Is date2 equal to date3?
os.toast(date2.toMillis() === date3.toMillis()); // => 'true'
Check if one date has the same month as another date
const date1 = DateTime.utc(2021, 6, 5, 4, 3, 2);
const date2 = DateTime.local(2021, 6, 5, 4, 3, 2);

os.toast(date1.hasSame(date2, 'month')); // => 'true'

getDateTime(value)

Attempts to create a new DateTime object from the given value. Returns a DateTime object if successful. Returns null otherwise.

See DateTime for more information.

The first parameter is the value that should be converted into a DateTime. If it is a string, then CasualOS will attempt to parse the string. If it is a Date object then it will be converted to a DateTime by assuming the Date represents the local time zone.

Supported ISO 8601 Formats:

2022 # Just the year
2022-05 # Year + Month
2022-10-03 # Year + Month + Day
2022-10-03T07:30:00 # Year + Month + Day + Hour + Minute + Second
2022-10-03T07:30:00Z # Year + Month + Day + Hour + Minute + Second + explicit UTC-0 marker
2022-10-03T07:30:00.123Z # Year + Month + Day + Hour + Minute + Second + Milisecond + explicit UTC-0 marker
2022-10-03T07:30:00.123-05:00 # Year + Month + Day + Hour + Minute + Second + -5 hour time offset from UTC-0

Note that unless a time-zone offset is explicitly specified, the date will always be interpreted as UTC-0 time.

Supported CasualOS-specific formats:

# ISO-like formats
📅2022 # Just the year
📅2022-05 # Year + Month
📅2022-10-03 # Year + Month + Day
📅2022-10-03T07:30:00 # Date + Time (UTC-0 is assumed)
📅2022-10-03T07:30:00Z # Date + Time + explicit UTC-0 marker
📅2022-10-03T07:30:00.123Z # Date + Time + Milisecond + explicit UTC-0 marker
📅2022-10-03T07:30:00.123-05:00 # Date + Time + -5 hour time offset from UTC-0

# CasualOS formats
📅2022-10-03T07:30:00 America/New_York # Date + Time + IANA time zone that date was recorded in
📅2022-10-03T07:30:00+05:00 America/Chicago # Date + Time + +5 hour time offset from UTC-0 + IANA time zone that date should be displayed in
📅2022-10-03T07:30:00+05:00 local # Date + Time + +5 hour time offset from UTC-0 + time zone should be displayed in local time

Examples:

Create a DateTime from a string
os.toast(getDateTime('📅2022-10-03T07:30:00 America/Detroit'));
Display the given time in a nice format
os.toast(getDateTime('📅2022-10-03T07:30:00 America/Detroit').toLocaleString());
Convert a Date object to a DateTime
os.toast(getDateTime(new Date()));

Web Actions

web.hook(options)

Sends a HTTP request using the given options.

Returns a Promise that resolves with the following properties:

{
data: any,
status: number,
statusText: string,
headers: any
}

The first parameter is an object with the following properties:

let options: {
/**
* The HTTP Method that the request should use.
*/
method: string;

/**
* The URL that the request should be made to.
*/
url: string;

/**
* The headers to include in the request.
*/
headers?: {
[key: string]: string;
};

/**
* The data to send with the request.
*/
data?: any;

/**
* The shout that should be made when the request finishes.
* This is for legacy code. New code should await the returned promise.
*/
responseShout?: string;

/**
* The shout that should be made when the request finishes.
*/
responseShout?: string;

/**
* The number of retries that should be attempted for the webhook if it fails.
* Defaults to 0.
*/
retryCount?: number;

/**
* The HTTP response status codes that should allow the web request to be retried.
* Defaults to:
* - 408 - Request Timeout
* - 429 - Too Many Requests
* - 500 - Internal Server Error
* - 502 - Bad Gateway
* - 503 - Service Unavailable
* - 504 - Gateway Timeout
* - 0 - Network Failure / CORS
*/
retryStatusCodes?: number[];

/**
* The number of miliseconds to wait between retry requests.
* Defaults to 3000ms (3 seconds).
*/
retryAfterMs?: number;
};

Examples:

  1. Send a HTTP GET request to https://example.com and toast the result.
const response = await web.hook({
method: 'GET',
url: 'https://example.com',
});

os.toast(response);
  1. Send a HTTP PUT request to https://example.com with some data.
web.hook({
method: 'PUT',
url: 'https://example.com',
data: {
some: 'data'
}
});

web.get(url, options?)

Sends a HTTP GET request for the given URL using the given options.

Returns a promise that resolves with the following properties:

{
data: any,
status: number,
statusText: string,
headers: any
}

The first parameter is the URL that the request should be sent to.

The second parameter is optional and is an object with the following properties:

let options: {
/**
* The headers to include in the request.
*/
headers?: {
[key: string]: string;
};

/**
* The shout that should be made when the request finishes.
*/
responseShout?: string;

/**
* The shout that should be made when the request finishes.
*/
responseShout?: string;

/**
* The number of retries that should be attempted for the webhook if it fails.
* Defaults to 0.
*/
retryCount?: number;

/**
* The HTTP response status codes that should allow the web request to be retried.
* Defaults to:
* - 408 - Request Timeout
* - 429 - Too Many Requests
* - 500 - Internal Server Error
* - 502 - Bad Gateway
* - 503 - Service Unavailable
* - 504 - Gateway Timeout
* - 0 - Network Failure / CORS
*/
retryStatusCodes?: number[];

/**
* The number of miliseconds to wait between retry requests.
* Defaults to 3000ms (3 seconds).
*/
retryAfterMs?: number;
};

Examples:

  1. Send a HTTP GET request for https://example.com and toast the result.
const response = await web.get('https://example.com');
os.toast(response);

web.post(url, data?, options?)

Sends a HTTP POST request to the URL with the given data and using the given options.

Returns a Promise that resolves with the following properties:

{
data: any,
status: number,
statusText: string,
headers: any
}

The first parameter is the URL that the request should be sent to.

The second parameter is the data that should be included in the request.

The third parameter is an optional object with the following properties:

let options: {
/**
* The headers to include in the request.
*/
headers?: {
[key: string]: string;
};

/**
* The shout that should be made when the request finishes.
*/
responseShout?: string;

/**
* The shout that should be made when the request finishes.
*/
responseShout?: string;

/**
* The number of retries that should be attempted for the webhook if it fails.
* Defaults to 0.
*/
retryCount?: number;

/**
* The HTTP response status codes that should allow the web request to be retried.
* Defaults to:
* - 408 - Request Timeout
* - 429 - Too Many Requests
* - 500 - Internal Server Error
* - 502 - Bad Gateway
* - 503 - Service Unavailable
* - 504 - Gateway Timeout
* - 0 - Network Failure / CORS
*/
retryStatusCodes?: number[];

/**
* The number of miliseconds to wait between retry requests.
* Defaults to 3000ms (3 seconds).
*/
retryAfterMs?: number;
};

Examples:

  1. Send a HTTP POST request to https://example.com and toast the result.
const response = await web.post('https://example.com', {
some: 'data'
});

os.toast(response);

Utility Actions

animateTag(bot, tag, options)

Animates the tag on the given bot based on the specified parameters. Returns a promise that resolves when the animation is finished and throws an error when the animation is canceled. This is useful for gradually changing a tag on a bot over time. For example, moving a bot from point A to point B without teleporting it.

animateTag(bot, tag, options) is fully integrated with tag masks. This lets you animate tag values in the tempLocal, local, player, and shared spaces.

The first parameter is the bot or list of bots that the tag should be animated on.

The second parameter is the tag that should be animated.

The third parameter are the options that should be used to animate the tag. If null is used, then any active animations for the tag on these bots will be canceled. It should be an object with the following properties:

let options: {

/**
* The value that the animation should start at.
* If omitted, then the current tag value will be used.
*/
fromValue?: number;

/**
* The value that the animation should end at.
*/
toValue: number;

/**
* The number of seconds that the animation should take to complete.
*/
duration: number;

/**
* The space that the tag should be animated in.
* If not specified, then "tempLocal" will be used.
* If set to false, then the bot will be edited instead of using tag masks.
* Additionally, if the specified space is the same as the space the bot lives in
* then the bot will be edited directly.
*/
tagMaskSpace?: 'tempLocal' | 'local' | 'tempShared' | 'shared' | false;

/**
* The time that the animation should start.
* Should be the number of miliseconds since January 1st 1970 UTC-0. (e.g. os.localTime or os.agreedUponTime).
*/
startTime?: number;

/**
* The options for easing.
* Can be an "easing type" or an object that specifies the type and mode.
* If an easing type is specified, then "inout" mode is used.
* If omitted, then "linear" "inout" is used.
*
* Can also be a custom function that takes a single parameter and returns a number.
* The paramater will be a number between 0 and 1 indicating the progress through the tween.
*/
easing?: 'linear'
| 'quadratic'
| 'cubic'
| 'quartic'
| 'quintic'
| 'sinusoidal'
| 'exponential'
| 'circular'
| 'elastic'
| ((progress: number) => number)
| {
/**
* The type of easing.
*/
type: 'linear'
| 'quadratic'
| 'cubic'
| 'quartic'
| 'quintic'
| 'sinusoidal'
| 'exponential'
| 'circular'
| 'elastic';

/**
* Whether to apply the easing at the
* start (in), end (out), or start and end (inout) of the tween.
*/
mode: 'in' | 'out' | 'inout';
}
};

Examples:

  1. Animate the #count tag from 0 to 1 over 5 seconds.
await animateTag(bot, "count", {
fromValue: 0,
toValue: 1,
duration: 5
});

os.toast("Animation finished!");
  1. Run 2 animations in sequence.
await animateTag(bot, "homeX", {
fromValue: 0,
toValue: 5,
duration: 2
});

await animateTag(bot, "homeY", {
fromValue: 0,
toValue: 5,
duration: 2
});
  1. Run an animation while the #loop tag is true.
while(tags.loop) {
await animateTag(bot, "homeX", {
fromValue: 0,
toValue: 5,
duration: 2
});
}
  1. Run an animation with a "bouncy" easing mode.
await animateTag(bot, "homeX", {
fromValue: 0,
toValue: 5,
duration: 2,
easing: {
type: "elastic",
mode: "out"
}
});
  1. Run an animation with a custom easing function that causes the animation to progress in 10 distinct steps.
await animateTag(bot, "homeX", {
fromValue: 0,
toValue: 5,
duration: 2,
easing: (k) => {
return Math.floor(k * 10) / 10;
}
});
  1. Run an animation that starts in 1 second.
await animateTag(bot, "homeX", {
fromValue: 0,
toValue: 5,
duration: 2,
startTime: os.localTime + 1000,
});
  1. Animate a tag in tempShared space.
await animateTag(bot, "homeX", {
fromValue: 0,
toValue: 5,
duration: 2,
tagMaskSpace: 'tempShared'
});
  1. Cancel animations on the #homeX tag.
animateTag(bot, "homeX", {
fromValue: 0,
toValue: 5,
duration: 2
}).then(() => {
os.toast("Animation Finished!");
}).catch(() => {
os.toast("Animation Canceled!");
});

await os.sleep(500);

animateTag(bot, "homeX", null);

animateTag(bot, options)

Animates multiple tags on the given bot based on the specified parameters.

This works similarly to animateTag(bot, tag, options) but instead of providing a tag name, you instead provide an object for the fromValue and toValue options which contains the tags that should be animated.

Returns a promise that resolves when the animation is finished and throws an error when the animation is canceled. This is useful for gradually changing a set of tags on a bot over time. For example, moving a bot from point A to point B without teleporting it.

Unlike calling animateTag(bot, tag, options) multiple times, animations started with this function are grouped together. This means that canceling one animation in the group will also cancel the others.

This function is fully integrated with tag masks. This lets you animate tag values in the tempLocal, local, player, and shared spaces.

The first parameter is the bot or list of bots that the tag should be animated on.

The second parameter are the options that should be used to animate the tag. It should be an object with the following properties:

let options: {

/**
* The tags values that the animation should start at.
* Each property should be the name of a tag that should be animated.
* The values should be the starting values for the tags.
*/
fromValue: object;

/**
* The tag values that the animation should end at.
* Each property should be the name of a tag that should be animated.
* The values should be the starting values for the tags.
*/
toValue: object;

/**
* The number of seconds that the animation should take to complete.
*/
duration: number;

/**
* The space that the tag should be animated in.
* If not specified, then "tempLocal" will be used.
* If set to false, then the bot will be edited instead of using tag masks.
* Additionally, if the specified space is the same as the space the bot lives in
* then the bot will be edited directly.
*/
tagMaskSpace?: 'tempLocal' | 'local' | 'tempShared' | 'shared' | false;

/**
* The options for easing.
* Can be an "easing type" or an object that specifies the type and mode.
* If an easing type is specified, then "inout" mode is used.
* If omitted, then "linear" "inout" is used.
*/
easing?: 'linear'
| 'quadratic'
| 'cubic'
| 'quartic'
| 'quintic'
| 'sinusoidal'
| 'exponential'
| 'circular'
| 'elastic'
| {
/**
* The type of easing.
*/
type: 'linear'
| 'quadratic'
| 'cubic'
| 'quartic'
| 'quintic'
| 'sinusoidal'
| 'exponential'
| 'circular'
| 'elastic';

/**
* Whether to apply the easing at the
* start (in), end (out), or start and end (inout) of the tween.
*/
mode: 'in' | 'out' | 'inout';
}
};

Examples:

  1. Animate the #homeX and#homeY tags from 0 to 1 over 5 seconds.
await animateTag(bot, {
fromValue: {
homeX: 0,
homeY: 0,
},
toValue: {
homeX: 1,
homeY: 1
},
duration: 5
});

os.toast("Animation finished!");
  1. Animate tags in tempShared space.
await animateTag(bot, {
fromValue: {
homeX: 0,
homeY: 0,
},
toValue: {
homeX: 5,
homeY: 5
},
duration: 2,
tagMaskSpace: 'tempShared'
});

clearAnimations(bot, tag?)

Cancels the animations that are running on the given bot(s). If a tag is specified then only animations for the given tag will be canceled.

The first parameter is the bot or list of bots that should cancel their animations.

The second parameter is optional and is the tag or list of tags that the animations should be canceled for.

Examples:

  1. Cancel all animations on a bot.
clearAnimations(bot);
  1. Cancel animations for #myTag on a bot.
clearAnimations(bot, 'myTag');
  1. Cancel animations on all bots.
clearAnimations(getBots());

setTag(bot, tag, value)

Sets the given tag to the given value on the given bot, list of bots, or mod.

The first parameter is the bot, list of bots, or mod that the tag should be set on.

The second parameter is the tag that should be changed.

The third parameter is the value that should be placed into the tag(s).

Examples:

  1. Set a bot's #color to green.
setTag(this, "#color", "green");

getTag(bot, tag)

Gets the given tag value from the given bot.

The first parameter is the bot that the tag should be retrieved from.

The second parameter is the tag that should be retrieved.

Examples:

  1. Get the #color tag from this bot.
const color = getTag(this, "#color");

setTagMask(bot, tag, value, space?)

Sets the given tag mask to the given value on the given bot or list of bots. If a space is specified, then the tag mask will be set inside that space.

The first parameter is the bot or list of bots that the tag mask should be set on.

The second parameter is the tag that should be changed.

The third parameter is the value that should be placed into the tag(s).

The fourth parameter is optional and is the space that the tag mask should exist in. If omitted, then the tag mask will be created in the tempLocal space.

Examples:

  1. Set a bot's #color to green.
setTagMask(this, "#color", "green");
  1. Set a bot's #color to green in the local space.
setTagMask(this, "#color", "green", "local");

clearTagMasks(bot, space?)

Clears the tag masks on the given bot or list of bots. If a space is specified, then only the tag masks in that space will be deleted.

The first parameter is the bot or list of bots that the tag mask should be set on.

The fourth parameter is optional and is the space that the tag mask should exist in. If omitted, then the tag masks in all spaces will be deleted.

Examples:

  1. Clear all tag masks on a bot.
clearTagMasks(this);
  1. Clear all tag masks in the local space/
clearTagMasks(this, "local");

insertTagText(bot, tag, index, text)

Inserts the given text into the tag at the given index. Useful for editing the text in a tag without interrupting other players that are editing the same tag. Returns the resulting raw tag value.

The first parameter is the bot that should be edited.

The second parameter is the tag that should be edited.

The third parameter is the zero-based index that the text should be inserted at.

The fourth parameter is the string of text that should be inserted.

Examples:

  1. Add some text to the end of a tag.
insertTagText(bot, "myTag", tags.myTag.length, "xyz");
  1. Add some text to the beginning of a tag.
insertTagText(bot, "myTag", 0, "abc");

insertTagMaskText(bot, tag, index, text, space?)

Inserts the given text into the tag mask at the given index. Useful for editing the text in a tag without interrupting other players that are editing the same tag. If a space is specified, then only the tag mask in that space will be changed.

Returns the resulting raw tag value.

The first parameter is the bot that should be edited.

The second parameter is the tag that should be edited.

The third parameter is the zero-based index that the text should be inserted at.

The fourth parameter is the string of text that should be inserted.

The fifth parameter is the space that the tag mask is in. If omitted, then the tempLocal space will be used.

Examples:

  1. Add some text to the end of a tag mask.
insertTagMaskText(bot, "myTag", tags.myTag.length, "xyz");
  1. Add some text to the beginning of a tag mask that is in the local space.
insertTagMaskText(bot, "myTag", 0, "abc", "local");

deleteTagText(bot, tag, index, count)

Deletes the specified number of characters from the given tag at the given index. Useful for editing the text in a tag without interrupting other players that are editing the same tag. Returns the resulting raw tag value.

The first parameter is the bot that should be edited.

The second parameter is the tag that should be edited.

The third parameter is the zero-based index that the text should be deleted at.

The fourth parameter is the number of characters that should be deleted.

Examples:

  1. Delete the last two characters from a tag.
deleteTagText(bot, "myTag", tags.myTag.length - 2, 2);
  1. Delete the first 3 characters from a tag.
deleteTagText(bot, "myTag", 0, 3);

deleteTagMaskText(bot, tag, index, count, space?)

Deletes the specified number of characters from the given tag mask at the given index. Useful for editing the text in a tag without interrupting other players that are editing the same tag. If a space is specified, then only the tag mask in that space will be changed.

Returns the resulting raw tag value.

The first parameter is the bot that should be edited.

The second parameter is the tag that should be edited.

The third parameter is the zero-based index that the text should be deleted at.

The fourth parameter is the number of characters that should be deleted.

The fifth parameter is the space that the tag mask is in. If omitted, then the tempLocal space will be used.

Examples:

  1. Delete the last two characters from a tag mask.
deleteTagText(bot, "myTag", tags.myTag.length - 2, 2);
  1. Delete the first 3 characters from a tag mask in the local space.
deleteTagText(bot, "myTag", 0, 3, "local");

Bot Filters

byTag(tag, value?)

Creates a bot filter that includes bots that have the given tag that matches the given value.

The first parameter is the name of the tag. Bots that have this tag will be included as long as they also match the second parameter.

The second parameter is the value that the tag should match. If not specified, then all bots with the tag will be included. If specified, then only bots that have the same tag value will be included. If you specify a function as the value, then it will be used to match tag values.

Examples

  1. Find all the bots with #name set to "bob".
let bots = getBots(byTag("#name", "bob"));
  1. Find all bots with a height larger than 2.
let bots = getBots(byTag("#height", height => height > 2));
  1. Find all bots with the "test" tag.
let bots = getBots(byTag("#test"));

byID(id)

Creates a bot filter that includes the bot with the given ID.

The first parameter is the ID of the bot.

Examples

Find the bot with the ID '123'
let bot = getBot(byID("123"));

inDimension(dimension)

Creates a bot filter that includes bots that are in the given dimension. That is, they have the given tag set to true.

The first parameter is the name of the dimension.

Examples

  1. Find all the bots in the "test" dimension.
let bots = getBots(inDimension("test"));

atPosition(dimension, x, y)

Creates a bot filter that includes bots that are in the given dimension and at the given X and Y position.

When this filter is used with getBots(...filters), the returned bots are sorted in the same order that they are stacked. This means that the first bot in the array is at the bottom of the stack and the last bot is at the top of the stack (assuming they're stackable).

The first parameter is the name of the dimension.

The second parameter is the X position. That is, the left-right position of the bots in the dimension.

The third parameter is the Y position. That is, the forward-backward position of the bots in the dimension.

Examples

  1. Find all the bots at (1, 2) in the "test" dimension.
let bots = getBots(atPosition("test", 1, 2));

inStack(bot, dimension)

Creates a bot filter that includes bots in the same stack as the given bot. The given bot will always be included by this filter as long the given bot is in the given dimension.

When this filter is used with getBots(...filters), the returned bots are sorted in the same order that they are stacked. This means that the first bot in the array is at the bottom of the stack and the last bot is at the top of the stack (assuming they're stackable).

The first parameter is the bot that other bots should be in the same stack with.

The second parameter is the name of the dimension.

Examples

  1. Find all bots in the same stack as this in the "test" dimension.
let bots = getBots(inStack(this, "test"));

byCreator(bot)

Creates a bot filter that includes bots created by the given bot. That is, they have #creator set to the #id of the given bot.

The first parameter is the bot that created the other bots.

Examples

  1. Find all the bots created by this bot.
let bots = getBots(byCreator(this));

bySpace(space)

Creates a bot filter that includes bots in the given space. That is, they have #space set to the given value.

The first parameter is the space that the bots are in.

Examples

Find all bots in the tempLocal space.
let bots = getBots(bySpace("tempLocal"));

byMod(mod)

Creates a bot filter that includes bots that match the given mod.

The first parameter is the bot or mod that the other bots should match.

Examples:

  1. Find all the bots with #height set to 1 and #color set to red.
const bots = getBots(byMod({
height: 1,
color: "red"
}));

neighboring(bot, dimension, direction)

Creates a bot filter that includes bots which are neighboring the given bot. Optionally takes a direction that the neighboring bots must be in.

The first parameter is the bot that the other bots need to be neighboring.

The second parameter is the dimension that the other bots need to be in.

The third parameter is optional and is the neighboring direction to check. If not specified, then all of the supported directions will be checked. Currently, the supported directions are front, right, back, and left. If an unsupported direction is specified, then no bots will be included.

Examples:

  1. Find all bots in front of this bot in the test dimension.
const bots = getBots(neighboring(this, "test", "front"));
  1. Find all bots around this bot in the test dimension.
const bots = getBots(neighboring(this, "test"));

either(...filters)

Creates a bot filter that includes bots which match any (i.e. one or more) of the given filters.

Each parameter is a bot filter.

Examples:

  1. Find all bots with the #name bob or a #height of 2.
const bots = getBots(
either(
byTag("#name", "bob"),
byTag("height", 2)
)
);

not(filter)

Creates a function that includes bots which do not match the given filter.

The first parameter is the bot filter whose results should be negated.

Examples:

  1. Find all bots that are not in the test dimension.
const bots = getBots(not(inDimension("test")));

Event Actions

shout(name, arg?)

Sends a shout to all bots that are #listening and have a listen tag for the specified name. Optionally includes a custom that argument. Also triggers @onListen and @onAnyListen.

The first parameter is the name of the shout. e.g. Using onClick for the name will trigger all @onClick listeners.

The second parameter is the that argument to send with the shout. You do not need to specify this parameter if you do not want to.

Examples:

  1. Send a @reset event to all bots:
shout("reset");
  1. Send a @hello event with your name:
shout("hello", "Bob");

whisper(bot, name, arg?)

Sends a whisper to the specified bot(s) that are #listening and have a listen tag for the given name. Optionally includes a custom that argument. Also triggers @onListen and @onAnyListen.

The first parameter is the bot, array of bots, bot #id, or array of bot #id that the whisper should be sent to.

The second parameter is the name of the whisper. e.g. Using onClick for the name will trigger the @onClick listener for the specified bots.

The third parameter is the that argument to send with the shout. You do not need to specify this parameter if you do not want to.

Examples:

  1. Send a @reset event to all bots named Bob:
let bots = getBots("#name", "Bob");
whisper(bots, "reset");
  1. Send a @setColor event to ourself:
whisper(this, "setColor", "red");

priorityShout(events, arg?)

Shouts to all bots that are #listening and have a listen tag for the specified events until one of the bots returns a value. Optionally includes a custom that argument. Also triggers @onListen and @onAnyListen for the bots that the shout was sent to.

This function is useful when you want to shout but only want one bot to process the shout.

The first parameter is the array of event names that should be shouted. e.g. Using onClick for the name will trigger the @onClick listener until a bot returns a value.

Examples:

Shout to the first bot that handles @onClick
priorityShout(['onClick']);
Shout to the first bot that handles @myTest or @mySecondTest
priorityShout(['myTest', 'mySecondTest']);
Priority shout with a color
priorityShout(['myTest', 'mySecondTest'], "blue");

superShout(name, arg?)

Sends a shout to all of the other instances that are loaded.

The first parameter is the name of the shout. e.g. Using onClick for the name will trigger all the @onClick listeners.

The second parameter is the optional that argument to include with the shout.

Examples:

  1. Send a hello super shout to all the loaded instances.
superShout("hello");

remote(action, target?)

Sends the given action to another remote.

In CasualOS, all actions are messages which are placed in a queue and processed one at at time.

For example, the os.toast(message, duration?) action queues a message which, when processed, will show a toast message. However, before any action is performed, it is run through the @onAnyAction listener which can decide whether reject an action using action.reject(action). This lets you write rules for what actions each player is allowed to take.

There are a couple special cases. First, when you send/receive an action from someone else (i.e. they sent an action to you using the remote(action) function), it won't run by default. Instead it is wrapped as a device action and sent to @onAnyAction for processing. This lets you decide whether to allow players to send messages to each other and what the effect of those messages are. If you want to perform the action, you can use action.perform(action) on the inner device action to queue it for execution.

The first parameter is the action to send.

The second parameter is optional and is a object specifing which remote to send the action to. If not specified, then the action is sent to the server. If specified, then the action is sent to all remotes that match the given values. If given a string, then the action is sent to the remote with the matching ID.

Examples:

  1. Send a toast message to another remote.
// TODO: Get the bot ID of the other remote.
const otherRemoteId = 'otherRemoteId';

// Create a toast action
const toastAction = os.toast('My message!');

// Send the action to the other remote
// The toastAction will not be performed locally because
// it is being sent to another remote.
remote(toastAction, otherRemoteId);

sendRemoteData(remoteId, name, arg?)

Sends a @onRemoteData shout to the remote with the given ID or remotes if given a list of IDs. This is useful for sending arbitrary messages to specific remotes.

The first parameter is the remote ID or list of remote IDs that the shout should be sent to.

The second parameter is the name of the event that is being sent. This is useful for telling the difference between different messages.

The third parameter is optional and is the that argument to send with the shout. You do not need to specify this parameter if you do not want to.

Examples:

  1. Send a "custom" message to another remote.
const otherRemoteId = "otherRemoteId";

// The other remote will receive a @onRemoteData with
// that.name === "custom" and that.that === "Hello"
sendRemoteData(otherRemoteId, "custom", "Hello");
  1. Send a message to all other remotes.
const remotes = await os.remotes();
const remoteId = getID(configBot);
const otherRemotes = remotes.filter(id => id !== remoteId);

// All other remotes will receive a @onRemoteData with
// that.name === "custom" and that.that === "Hello"
sendRemoteData(otherRemotes, "custom", "Hello");

action.perform(action)

Performs the given action. This function can be used to perform actions that you have stored as data without having to find out which function to call. You can find a list of action types here.

The first parameter is the action that should be performed.

Examples:

Perform a toast action
action.perform({
type: 'show_toast',
message: 'Hello, world!',
duration: 2000
});
Perform an add bot action
action.perform({
type: 'add_bot',
id: 'bot_id',
bot: {
id: 'bot_id',
tags: {
home: true,
label: 'Hello, World!'
}
}
});

action.reject(action)

Prevents a previous action from being performed.

This is especially useful when used in a @onAnyAction listener since it lets you reject actions before they are performed.

The first parameter is the action that should be prevented/rejected.

Examples:

  1. Prevent a toast message from being performed.
const toastAction = os.toast("my message");
action.reject(toastAction);

Time Actions

os.localTime

Gets the device-local time as the number of miliseconds since midnight January 1st, 1970 UTC-0 (i.e. the Unix Epoch). This is what your device's clock thinks the current time is.

Examples

Toast the number of miliseconds since the Unix Epoch
os.toast(os.localTime);

os.agreedUponTime

Gets the shared time that has been agreed upon between devices in the inst as the number of miliseconds since midnight January 1st, 1970 UTC-0 (i.e. the Unix Epoch). This is what your device's clock thinks the inst clock says.

If an agreed upon time cannot be determined (for example, because collaboration is disabled in the inst), then this value will always be NaN.

Examples

Toast the current shared time
os.toast(os.agreedUponTime);

os.instLatency

Gets the average latency between this device's clock and the inst clock in miliseconds. Lower values tend to indicate a good connection while higher values tend to indicate a bad connection.

If an agreed upon time cannot be determined (for example, because collaboration is disabled in the inst), then this value will always be NaN.

os.instTimeOffset

Gets the calculated time offset between the inst clock and the local clock. This value is equivalent to os.agreedUponTime - os.localTime.

If an agreed upon time cannot be determined (for example, because collaboration is disabled in the inst), then this value will always be NaN.

os.instTimeOffsetSpread

Gets the spread between calculated time offsets. Higher values indicate that os.agreedUponTime is less accurate. Lower values indicate that os.agreedUponTime is more accurate.

If an agreed upon time cannot be determined (for example, because collaboration is disabled in the inst), then this value will always be NaN.

os.deadReckoningTime

Gets the shared time that has been agreed upon between devices but with an additional 50ms offset added. This offset attempts to ensure that changes/events will be recieved by all connected devices by the time it occurs, thereby making synchronized actions easier to perform.

If an agreed upon time cannot be determined (for example, because collaboration is disabled in the inst), then this value will always be NaN.

Records Actions

os.requestAuthBot()

Requests that an "authentication" bot be added to the inst for the current browser tab. Auth bots are useful for discovering general information about the logged in user and are typically associated with a https://ab1.link user account. Returns a promise that resolves with a bot that contains information about the signed in user session. Resolves with null if the user was unable to sign in.

On success, the authBot global variable will reference the bot that was returned by the promise.

See Auth Bot Tags for more information.

Examples

Request an auth bot for the user
await os.requestAuthBot();
os.toast("Logged in!");

os.getPublicRecordKey(name)

Requests an access key for the public record with the given name. Returns a promise that resolves with an object that contains the record key (if successful) or information about the error that occurred.

The first parameter is the name of the record to get the key for.

The returned object has the following structure:

let result: {
/**
* Whether the request was successful.
*/
success: boolean;

/**
* The access key that was created.
* Not included if the request failed.
*/
recordKey?: string;

/**
* The name of the record that the access key was created for.
* Not included if the request failed.
*/
recordName?: string;

/**
* The error code for failed requests.
*/
errorCode?: string;

/**
* The error message for failed requests.
*/
errorMessage?: string;

/**
* The detailed reason for failed requests.
*/
errorReason?: string;
};

Examples

Request an access key for a public record.
const result = await os.getPublicRecordKey('myPublicRecord');

if (result.success) {
os.toast(result.recordKey);
} else {
os.toast('Failed ' + result.errorMessage);
}

os.isRecordKey(value)

Determines if the given value represents a record key.

Returns true if the value is a record key and false if the value is not a record key.

The first parameter is the value to test to see if it is a record key.

Examples

Determine if a value is a record key.
const isRecordKey = os.isRecordKey(tags.myRecordKey);

os.toast(tags.myRecordKey ' is ' + (isRecordKey ? 'a' : 'not a') + ' record key.');

os.recordData(recordKey, address, data, optionsOrEndpoint?)

Stores the given data in the given record at the given address. If data already exists at the given address, it will be overwritten.

Returns a promise that resolves with an object that indicates if the request was successful.

The first parameter is the key that should be used to access the record. You can request a record key by using os.getPublicRecordKey(name).

The second parameter is the address that the data should be stored at.

The third parameter is the data that should be stored. This can be any value that can be serialized to JSON. Must be less than 300KB in size. If you need to store data larger than 300KB, you can use os.recordFile(recordKey, fileData, options?, endpoint?) instead.

The fourth parameter is optional and is the options that should be used to record the data. It has the following structure:

let options: {
/**
* The HTTP Endpoint that should be queried.
*/
endpoint?: string;

/**
* The policy that should be used for updating the record.
* - true indicates that the value can be updated by anyone.
* - An array of strings indicates the list of user IDs that are allowed to update the data.
*/
updatePolicy?: true | string[];

/**
* The policy that should be used for deleting the record.
* - true indicates that the value can be erased by anyone.
* - An array of strings indicates the list of user IDs that are allowed to delete the data.
* Note that even if a delete policy is used, the owner of the record can still erase any data in the record.
*/
deletePolicy?: true | string[];
}

Alternatively, it can be the HTTP Endpoint of the records website that the data should be recorded to. If omitted, then the preconfigured records endpoint will be used. Note that when using a custom endpoint, the record key must be a valid record key for that endpoint.

The returned object has the following structure:

let result: {
/**
* Whether the request was successful.
*/
success: boolean;

/**
* The name of the record that the data was stored in.
* Not included if the request failed.
*/
recordName?: string;

/**
* The address that the data was stored at.
* Not included if the request failed.
*/
address?: string;

/**
* The error code for failed requests.
*/
errorCode?: string;

/**
* The error message for failed requests.
*/
errorMessage?: string;
};

Examples

Publish some data to a record
const recordKeyResult = await os.getPublicRecordKey('myRecord');
if (!recordKeyResult.success) {
os.toast("Failed to get a record key! " + recordKeyResult.errorMessage);
return;
}
const result = await os.recordData(recordKeyResult.recordKey, 'myAddress', 'myData');

if (result.success) {
os.toast("Success!");
} else {
os.toast("Failed " + result.errorMessage);
}

os.eraseData(recordKey, address, endpoint?)

Erases the data stored at the given address in the given record. Returns a promise that resolves with an object that contains the data (if successful) or information about the error that occurred.

The first parameter is the key that should be used to access the record. You can request a record key by using os.getPublicRecordKey(name).

The second parameter is the address that the data is stored at.

The third parameter is optional and is the HTTP Endpoint of the records website that the data should be recorded to. If omitted, then the preconfigured records endpoint will be used. Note that when using a custom endpoint, the record key must be a valid record key for that endpoint.

The returned object has the following structure:

let result: {
/**
* Whether the request was successful.
*/
success: boolean;

/**
* The name of the record that the data was stored in.
* Not included if the request failed.
*/
recordName?: string;

/**
* The address that the data was stored at.
* Not included if the request failed.
*/
address?: string;

/**
* The error code for failed requests.
*/
errorCode?: string;

/**
* The error message for failed requests.
*/
errorMessage?: string;
};

Examples

Erase some data from a record
const recordKeyResult = await os.getPublicRecordKey('myRecord');
if (!recordKeyResult.success) {
os.toast("Failed to get a record key! " + recordKeyResult.errorMessage);
return;
}
const result = await os.eraseData(recordKeyResult.recordKey, 'myAddress');

if (result.success) {
os.toast("Success!");
} else {
os.toast("Failed " + result.errorMessage);
}

os.getData(recordKeyOrName, address, endpoint?)

Gets the data stored at the given address in the given record. Returns a promise that resolves with an object that contains the data (if successful) or information about the error that occurred.

The first parameter is the record name or a record key. This indicates the record that the data should be retrieved from. Note that you don't need a record key in order to retrieve data from a public record. Using a record name will work just fine.

The second parameter is the address that the data should be retrieved from.

The third parameter is optional and is the HTTP Endpoint of the records website that the data should be recorded to. If omitted, then the preconfigured records endpoint will be used. Note that when using a custom endpoint, the record key must be a valid record key for that endpoint.

The returned object has the following structure:

let result: {
/**
* Whether the request was successful.
*/
success: boolean;

/**
* The name of the record that the data was stored in.
* Not included if the request failed.
*/
recordName?: string;

/**
* The address that the data was stored at.
* Not included if the request failed.
*/
address?: string;

/**
* The data that was retrieved.
* Not included if the request failed.
*/
data?: any;

/**
* The ID of the user that owns the record.
* Not included if the request failed.
*/
publisherId?: string;

/**
* The ID of the user that stored the data in the record.
* Not included if the request failed.
*/
subjectId?: string;

/**
* The error code for failed requests.
* Only included if the request failed.
*/
errorCode?: string;

/**
* The error message for failed requests.
* Only included if the request failed.
*/
errorMessage?: string;
};

Examples

Get some data from a record
const result = await os.getData('myRecord', 'myAddress');

if (result.success) {
os.toast(result.data);
} else {
os.toast("Failed " + result.errorMessage);
}

os.listData(recordNameOrKey, startingAddress?, endpoint?)

Gets a partial list of data that is stored in the given record. Optionally accepts the address before the first item that should be included in the list. Returns a promise that resolves with an object that contains the items (if successful) or information about the error that occurred.

On ab1.link, the returned list is limited to 25 items.

The first parameter is the record name or a record key. This indicates the record that the data should be retrieved from. Note that you don't need a record key in order to retrieve data from a public record. Using a record name will work just fine.

The second parameter is optional and is the address after which items will be included in the list. Since items are ordered within the record by address, this can be used as way to iterate through all the data items in a record. If omitted, then the list will start with the first item.

The third parameter is optional and is the HTTP Endpoint of the records website that the data should be recorded to. If omitted, then the preconfigured records endpoint will be used. Note that when using a custom endpoint, the record key must be a valid record key for that endpoint.

The returned object has the following structure:

let result: {
/**
* Whether the request was successful.
*/
success: boolean;

/**
* The name of the record that the data was stored in.
* Not included if the request failed.
*/
recordName?: string;

/**
* The items included in the list.
* Not included if the request failed.
*/
items?: {
/**
* The address of the item.
*/
address: string;

/**
* The data contained by the item.
*/
data: any;
}[];

/**
* The error code for failed requests.
* Only included if the request failed.
*/
errorCode?: string;

/**
* The error message for failed requests.
* Only included if the request failed.
*/
errorMessage?: string;
};

Examples:

Get a list of data items in a record
const result = await os.listData('myRecord');

if (result.success) {
os.toast(result.items);
} else {
os.toast("Failed " + result.errorMessage);
}
List all the items in a record
let lastAddress;
let items = [];
while(true) {
const result = await os.listData('myRecord', lastAddress);
if (result.success) {
console.log(result.items);
items.push(...result.items);
if (result.items.length > 0) {
lastAddress = result.items[result.items.length - 1].address;
} else {
// result.items is empty, so we can break out of the loop
break;
}
} else {
os.toast("Failed " + result.errorMessage);
break;
}
}

os.recordManualApprovalData(recordKey, address, data, optionsOrEndpoint?)

Stores the given manual approval data in the given record at the given address. If data already exists at the given address, it will be overwritten.

Returns a promise that resolves with an object that indicates if the request was successful.

Works the same as os.recordData(recordKey, address, data, optionsOrEndpoint?) except that manual approval data records require the user to allow the operation manually.

os.eraseManualApprovalData(recordKey, address, endpoint?)

Erases the manual approval data stored at the given address in the given record. Returns a promise that resolves with an object that contains the data (if successful) or information about the error that occurred.

Works the same as os.eraseData(recordKeyOrName, address, endpoint?) except that manual approval data records require the user to allow the operation manually.

os.getManualApprovalData(recordKeyOrName, address, endpoint?)

Gets the manual approval data stored at the given address in the given record.

Works the same as os.getData(recordKeyOrName, address, endpoint?) except that manual approval data records require the user to allow the operation manually.

os.recordFile(recordKey, fileData, options?, endpoint?)

Stores the given file data in the given record using the given options for the file. The file can later be retrieved by using os.getFile(urlOrRecordFileResult, endpoint?).

Returns a promise that resolves with an object that contains the URL that the file was stored at (if successful) or information about the error that occurred.

The first parameter is the key that should be used to access the record. You can request a record key by using os.getPublicRecordKey(name).

The second parameter is the data that should be stored in the record. This can be a string, an object, a blob, or an ArrayBuffer.

The third parameter is optional and is an object with the following structure:

let options: {
/**
* The description of the file.
* Useful for identifying a file.
*/
description?: string;

/**
* The MIME type of the file. This describes the type of data that the file contains. (JSON, HTML, plain text, etc.)
* See https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types for more information.
*
* If this is not specified, the MIME type will be inferred from the data as follows:
* - If the data is a string, the MIME type will be `text/plain`.
* - If the data is an object, the MIME type will be `application/json`.
* - If the data is a Blob, the MIME type will be pulled from the Blob object.
* - If the data is an ArrayBuffer, the MIME type will be `application/octet-stream`.
*/
mimeType?: string;
};

The fourth parameter is optional and is the HTTP Endpoint of the records website that the data should be recorded to. If omitted, then the preconfigured records endpoint will be used. Note that when using a custom endpoint, the record key must be a valid record key for that endpoint.

The returned object has the following structure:

let result: {
/**
* Whether the request was successful.
*/
success: boolean;

/**
* The URl that the uploaded file can be accessed at.
* Not included if the request failed.
*/
url?: string;

/**
* The URL that the file already exists at.
* Only included if the request failed because the file has already been stored.
*/
existingFileUrl?: string;

/**
* The error code for failed requests.
* Only included if the request failed.
*/
errorCode?: string;

/**
* The error message for failed requests.
* Only included if the request failed.
*/
errorMessage?: string;
};

Examples

Upload a file
const files = await os.showUploadFiles();

if (files.length <= 0) {
return;
}

const file = files[0];
const result = await os.recordFile(tags.recordKey, file);

if (result.success) {
tags.uploadUrl = result.url;
os.toast("Success! Uploaded to " + result.url);
} else {
os.toast("Failed " + result.errorMessage);
}
Upload a string to a file record
const recordKeyResult = await os.getPublicRecordKey('myRecord');
if (!recordKeyResult.success) {
os.toast("Failed to get a record key! " + recordKeyResult.errorMessage);
return;
}
const result = await os.recordFile(recordKeyResult.recordKey, 'my file data');

if (result.success) {
tags.uploadUrl = result.url;
os.toast("Success! Uploaded to " + result.url);
} else {
os.toast("Failed " + result.errorMessage);
}
Upload red bots to a file record
const recordKeyResult = await os.getPublicRecordKey('myRecord');
if (!recordKeyResult.success) {
os.toast("Failed to get a record key! " + recordKeyResult.errorMessage);
return;
}
const result = await os.recordFile(recordKeyResult.recordKey, getBots("color", "red"), {
description: 'my bots'
});

if (result.success) {
tags.uploadUrl = result.url;
os.toast("Success! Uploaded to " + result.url);
} else {
os.toast("Failed " + result.errorMessage);
}
Upload a file to a custom endpoint
const files = await os.showUploadFiles();

if (files.length <= 0) {
return;
}

const file = files[0];
const result = await os.recordFile(tags.recordKey, file, undefined, 'https://myendpoint.com');

if (result.success) {
tags.uploadUrl = result.url;
os.toast("Success! Uploaded to " + result.url);
} else {
os.toast("Failed " + result.errorMessage);
}

os.eraseFile(recordKey, urlOrRecordFileResult, endpoint?)

Erases the file at the given URL or at the URL that was specified in the given os.recordFile(recordKey, fileData, options?) result.

Returns a promise that resolves with an object that indicates if the file was deleted or if an error occurred.

The first parameter is the key that should be used to access the record. You can request a record key by using os.getPublicRecordKey(name).

The second parameter is the URL that the file is stored at. It can also be the result of a os.recordFile(recordKey, fileData, options?) call.

The third parameter is optional and is the HTTP Endpoint of the records website that the data should be recorded to. If omitted, then the preconfigured records endpoint will be used. Note that when using a custom endpoint, the record key must be a valid record key for that endpoint.

The returned object has the following structure:

let result: {
/**
* Whether the request was successful.
*/
success: boolean;

/**
* The name of the record that the file was deleted from.
* Not included if the request failed.
*/
recordName?: string;

/**
* The error code for failed requests.
* Only included if the request failed.
*/
errorCode?: string;

/**
* The error message for failed requests.
* Only included if the request failed.
*/
errorMessage?: string;
};

Examples

Delete a file
const result = await os.eraseFile(tags.recordKey, fileUrl);

if (result.success) {
os.toast("Success!");
} else {
os.toast("Failed " + result.errorMessage);
}

os.getFile(urlOrRecordFileResult, endpoint?)

Downloads the file at the given URL or at the URL that was specified in the given os.recordFile(recordKey, fileData, options?) result.

Returns a promise that resolves with the file data.

The first parameter is the URL that the file is stored at. It can also be the result of a os.recordFile(recordKey, fileData, options?) call.

The second parameter is optional and is the records endpoint that should be queried.

Examples

Get a file that was uploaded
// Upload the file
const recordKeyResult = await os.getPublicRecordKey('myRecord');
if (!recordKeyResult.success) {
os.toast("Failed to get a record key! " + recordKeyResult.errorMessage);
return;
}
const result = await os.recordFile(recordKeyResult.recordKey, getBots("color", "red"), {
description: 'my bots'
});

if (result.success) {
tags.uploadUrl = result.url;
os.toast("Success! Uploaded to " + result.url);
} else {
os.toast("Failed " + result.errorMessage);
}

// Download the file later
const fileData = await os.getFile(tags.uploadUrl);

os.getPublicFile(urlOrRecordFileResult)

Downloads the file at the given URL or at the URL that was specified in the given os.recordFile(recordKey, fileData, options?) result. Throws an error if the file is not a public file.

Returns a promise that resolves with the file data.

The first parameter is the URL that the file is stored at. It can also be the result of a os.recordFile(recordKey, fileData, options?) call.

Examples

Get a file that was uploaded
// Upload the file
const recordKeyResult = await os.getPublicRecordKey('myRecord');
if (!recordKeyResult.success) {
os.toast("Failed to get a record key! " + recordKeyResult.errorMessage);
return;
}
const result = await os.recordFile(recordKeyResult.recordKey, getBots("color", "red"), {
description: 'my bots'
});

if (result.success) {
tags.uploadUrl = result.url;
os.toast("Success! Uploaded to " + result.url);
} else {
os.toast("Failed " + result.errorMessage);
}

// Download the file later
const fileData = await os.getPublicFile(tags.uploadUrl);

os.getPrivateFile(urlOrRecordFileResult, endpoint?)

Downloads the file at the given URL or at the URL that was specified in the given os.recordFile(recordKey, fileData, options?) result. Works with both public and private files.

Returns a promise that resolves with the file data.

The first parameter is the URL that the file is stored at. It can also be the result of a os.recordFile(recordKey, fileData, options?) call.

The second parameter is optional and is the records endpoint that should be queried.

Examples

Get a file that was uploaded
// Upload the file
const recordKeyResult = await os.getPublicRecordKey('myRecord');
if (!recordKeyResult.success) {
os.toast("Failed to get a record key! " + recordKeyResult.errorMessage);
return;
}
const result = await os.recordFile(recordKeyResult.recordKey, getBots("color", "red"), {
description: 'my bots',
markers: ['secret']
});

if (result.success) {
tags.uploadUrl = result.url;
os.toast("Success! Uploaded to " + result.url);
} else {
os.toast("Failed " + result.errorMessage);
}

// Download the file later
const fileData = await os.getPrivateFile(tags.uploadUrl);

os.recordEvent(recordKey, eventName, endpoint?)

Records that the given event occurred in the given record. Returns a promise that resolves with an object that indicates whether the operation was successful or unsuccessful.

The first parameter is the key that should be used to access the record. You can request a record key by using os.getPublicRecordKey(name).

The second parameter is the name of the event whose count should be incremented.

The third parameter is optional and is the HTTP Endpoint of the records website that the data should be recorded to. If omitted, then the preconfigured records endpoint will be used. Note that when using a custom endpoint, the record key must be a valid record key for that endpoint.

The returned object has the following structure:

let result: {
/**
* Whether the request was successful.
*/
success: boolean;

/**
* The name of the record.
* Not included if the request failed.
*/
recordName?: string;

/**
* The name of the event.
* Not included if the request failed.
*/
eventName?: string;

/**
* The number that was added to the event count.
* Not included if the request failed.
*/
countAdded?: number;

/**
* The error code for failed requests.
* Only included if the request failed.
*/
errorCode?: string;

/**
* The error message for failed requests.
* Only included if the request failed.
*/
errorMessage?: string;
};

Examples:

Record that a click event happened
await os.recordEvent(myRecordKey, 'click');

os.countEvents(recordNameOrKey, eventName, endpoint?)

Gets the number of times that the given event has been recorded in the given record. Returns a promise that resolves with an object that indicates whether the operation was successful or unsuccessful.

The first parameter is the name of the record that the event count should be retrieved from. It can also be a record key.

The second parameter is the name of the event whose count should be retrieved.

The third parameter is optional and is the HTTP Endpoint of the records website that the data should be recorded to. If omitted, then the preconfigured records endpoint will be used. Note that when using a custom endpoint, the record key must be a valid record key for that endpoint.

The returned object has the following structure:

let result: {
/**
* Whether the request was successful.
*/
success: boolean;

/**
* The name of the record.
* Not included if the request failed.
*/
recordName?: string;

/**
* The name of the event.
* Not included if the request failed.
*/
eventName?: string;

/**
* The number of times that the event has been recorded.
* Not included if the request failed.
*/
count?: number;

/**
* The error code for failed requests.
* Only included if the request failed.
*/
errorCode?: string;

/**
* The error message for failed requests.
* Only included if the request failed.
*/
errorMessage?: string;
};

Examples:

Get the number of times the click event has happened
const result = await os.countEvents(myRecord, 'click');

if (result.success) {
os.toast(result.count);
} else {
os.toast('Failed to get count ' + result.errorMessage);
}

OS Actions

configBot

Gets the config bot (formerly known as the player bot). This is the bot that represents the player's browser tab.

Examples:

  1. Get the config bot and set a username on it.
configBot.tags.username = "bob";
  1. Open the sheet to "testDimension".
configBot.tags.sheetPortal = "testDimension";

os.sleep(time)

Waits the amount of time provided, in miliseconds.

Returns a promise that resolves when the time has been waited.

The first parameter is time in ms to wait. 1 second is 1000ms.

Examples:

  1. Wait 2 seconds before proceeding.
os.toast("Stop!");
await os.sleep(2000);
os.toast("Hammer Time!");

os.log(...args)

Logs the given data to the developer console.

Every parameter is the data that should be logged.

Examples:

  1. Log "Hello, World!" to the browser developer console.
os.log("Hello, World!");

os.getGeolocation()

Gets the geographic location that the current device is at in the world.

Returns a promise that resolves with the location. The location is an object with the following properties:

let location: {
/**
* Whether the operation was successful.
*/
success: boolean;

/**
* The code of the error that occurred.
* Only defined if the operation was unsuccessful.
*/
errorCode?: 'permission_denied' | 'position_unavailable' | 'timeout' | 'unknown';

/**
* The message of the error that occurred.
* Only defined if the operation was unsuccessful.
*/
errorMessage?: string;

/**
* The altitude that the device is near.
* Null if the device does not support determining the altitude.
* Only defined if the operation was successful.
*/
altitude?: number;

/**
* The accuracy of the altitude in meters.
* Null if the device does not support altitude.
* Only defined if the operation was successful.
*/
altitudeAccuracy?: number;

/**
* The latitude that the device is near.
* Only defined if the operation was successful.
*/
latitude: number;

/**
* The longitude that the device is near.
* Only defined if the operation was successful.
*/
longitude: number;

/**
* The accuracy of the positional location (latitude and longitude) in meters.
* Only defined if the operation was successful.
*/
positionalAccuracy: number;

/**
* The heading of the device from north in radians.
* 0 is true north, Math.PI/2 is east, Math.PI is south and 3/2*Math.PI is west.
* This value is null if the device is unable to determine the heading.
* Only defined if the operation was successful.
*/
heading: number;

/**
* The speed that the device is moving in meters per second.
* Null if the device does not support calculating the speed.
* Only defined if the operation was successful.
*/
speed: number;

/**
* The timestamp of the geolocation result.
* Only defined if the operation was successful.
*/
timestamp: number;
}

Examples:

  1. Get the current geolocation.
const location = await os.getGeolocation();

if (location.success) {
os.toast(`You are at (${location.latitude}, ${location.longitude})`);
} else {
os.toast(location.errorMessage);
}

os.convertGeolocationToWhat3Words(location)

Converts the given geolocation to a what3words address. Returns a promise that resolves with the 3 word address.

The first parameter is the geolocation that should be converted to a 3 word address. It should be an object with the following properties:

let location: {
/**
* The latitude of the location.
*/
latitude: number;

/**
* The longitude of the location.
*/
longitude: number;

/**
* The language that the resulting 3 word address should be returned in.
* Defaults to "en". See https://developer.what3words.com/public-api/docs#available-languages for a list of available languages.
*/
language?: string;
};

Examples:

Get the current geolocation as a 3 word address
const location = await os.getGeolocation();

if (location.success) {
const address = await os.convertGeolocationToWhat3Words(location);
os.toast(address);
} else {
os.tost("Could not get geolocation");
}
Get the location of the Amway Grand as a 3 word address
const address = await os.convertGeolocationToWhat3Words({
latitude: 42.966824756903755,
longitude: -85.67309821404483,
});
os.toast(address);

os.checkout(options)

Shows a payment screen modal that lets the player purchase something. Triggers the @onCheckout shout on the server inside the given processing inst.

The first parameter is the options to use to setup the checkout screen.

Examples:

  1. Show a checkout box for 10 cookies.
os.checkout({
publishableKey: 'YOUR_PUBLISHABLE_API_KEY',
productId: '10_cookies',
title: '10 Cookies',
description: '$5.00',
processingInst: 'cookies_checkout'
});

os.download(data, filename, mimeType?)

Downloads the given data with the given filename and MIME Type.

The first parameter is the data that should be downloaded. This can be a string, object, or binary data in the form of an ArrayBuffer or Blob.

The second parameter is the name of the file that should be downloaded.

The third parameter is optional and is the MIME Type that the downloaded file should have. If not provided, then it will be inferred from the provided filename.

Examples:

  1. Download a text file named "test.txt" that contains "abc".
os.download("abc", "test.txt");

os.downloadBots(bots, filename)

Downloads the given array of bots as a .aux or a .pdf file with the given filename. Useful for quickly backing up a set of bots.

The downloaded bots will be stored in the Version 1 format of the AUX File Format, which is well suited for most scenarios. For scenarios where you want conflict-free initialization of a shared inst, you should use os.downloadBotsAsInitialzationUpdate(bots, filename).

The first parameter is the array of bots that should be downloaded.

The second parameter is the name of the file that the bots should be stored in. If the filename ends with .pdf, then a PDF file will be downloaded with the bots as embedded data. Otherwise, .aux will automatically be added to the end of the filename.

Examples:

  1. Download all the bots in the "abc" dimension as "abcBots.aux".
os.downloadBots(getBots(inDimension("abc")), "abcBots");
  1. Download the current bot as "currentBot.aux".
os.downloadBots([bot], "currentBot");
  1. Download all bots as "myServer.pdf".
os.downloadBots(getBots(), "myServer.pdf");

os.downloadBotsAsInitialzationUpdate(bots, filename)

Downloads the given array of bots as a .aux or a .pdf file with the given filename.

The downloaded bots will be stored in the Version 2 format of the AUX File Format, which is better suited towards scenarios which require conflict-free initialization of a shared inst from the AUX file. For an archive of the current state, you should use os.downloadBots(bots, filename) which is better for scenarios which require direct access to the bot data.

The first parameter is the array of bots that should be downloaded.

The second parameter is the name of the file that the bots should be stored in. If the filename ends with .pdf, then a PDF file will be downloaded with the bots as embedded data. Otherwise, .aux will automatically be added to the end of the filename.

Examples:

  1. Download all the bots in the "abc" dimension as "abcBots.aux".
os.downloadBotsAsInitialzationUpdate(getBots(inDimension("abc")), "abcBots");
  1. Download the current bot as "currentBot.aux".
os.downloadBotsAsInitialzationUpdate([bot], "currentBot");
  1. Download all bots as "myServer.pdf".
os.downloadBotsAsInitialzationUpdate(getBots(), "myServer.pdf");

os.downloadInst()

Downloads all of the shared bots into a .aux file on the player's computer. The file will have the same name as the inst.

Note that this function is almost exactly the same as os.downloadBots(bots, filename). The only difference is that all bots in the shared space are included and the file is named for you automatically.

Examples:

  1. Download the entire inst.
os.downloadInst();

os.run(script)

Runs the given script. The script will be executed in a separate environment with no bot, tags, this, data, and that variables. This means that you need to use the getBot(...filters) or getBots(...filters) functions to read bot data.

Returns a promise that resolves with the returned script value after it has been executed.

The first parameter is the script that should be executed.

Examples:

  1. Run a script that says "hello".
os.run("os.toast('hello');");
  1. Run a script from the #script tag on the current bot.
os.run(tags.script);
  1. Run a script and toast the result.
const result = await os.run("return 594 + 391");
os.toast(result);

os.replaceDragBot(botOrMod)

Replaces the bot that the user is dragging with the given bot or mod.

If called when the user is not dragging anything, then the given bot or mod will be dragged using the current input method. When in VR, the current input method is the most recently used VR controller. Otherwise it is the mouse/touchscreen.

The first parameter is the bot or mod that should be dragged. If given a bot while dragging, then that bot's @onDrag will be skippped but @onDrop will be called. If given a bot when not dragging, then that bot's @onDrag and @onDrop will be called.

Examples:

  1. Drag a clone of this bot.
let clone = create(this);
os.replaceDragBot(clone);
  1. Drag a mod that makes other bots red.
os.replaceDragBot({
"color": "red"
});

os.enableCustomDragging()

Enables "custom dragging" for the current bot drag operation.

Custom dragging tells CasualOS to not move the bot to the dragged position. Instead, it will calculate where the bot would be dragged and send that information in the @onDragging and @onAnyBotDragging listeners.

This is useful for custom bot dragging behavior like choosing to scale or rotate a bot instead of moving it.

Examples:

Enable custom dragging for the current drag operation
os.enableCustomDragging();

os.addDropSnap(...targets)

Specifies a list of snap targets that can be used to position the currently dragged bot.

If called when the user is not dragging anything, then this function does nothing.

Each parameter is a snap target and can be one of the following values:

ValueDescription
ground

The bot will snap to the ground plane. (Default when not in VR)

grid

The bot will snap to individual grid tiles.

face

The bot will snap the faces of other pointable bots.

bots

The bot will snap to other pointable bots.

A snap point object

The bot will snap to the specified position when dragged within the specified distance.

A snap axis object

The bot will snap to the specified axis when dragged within the specified distance. Currently not supported on the map portal.

Snap point objects should have the following form:

let snapPoint: {
/**
* The position that the bot should be snapped to.
*/
position: { x: number, y: number, z: number };

/**
* The distance that the bot should be from the position in order to snap to it.
*/
distance: number;
};

Snap axis objects should have the following form:

let snapAxis: {
/**
* The direction that the axis travels along.
*/
direction: { x: number, y: number, z: number };

/**
* The center point that the axis travels through.
*/
origin: { x: number, y: number, z: number };

/**
* The distance that the bot should be from any
* point along the axis in order to snap to it.
*/
distance: number;
};

Examples:

  1. Snap the dragged bot to the grid.
os.addDropSnap("grid");
  1. Snap the dragged bot to other bot faces.
os.addDropSnap("face");
  1. Snap the dragged bot to a point.
os.addDropSnap({
position: {
x: 0,
y: 0,
z: 3,
},
distance: 1
});
  1. Snap the dragged bot to the global X axis.
os.addDropSnap({
direction: {
x: 1,
y: 0,
z: 0,
},
origin: {
x: 0,
y: 0,
z: 0
},
distance: 2
});
  1. Snap the dragged bot to the center or bot faces.
os.addDropSnap({
position: {
x: 0,
y: 0,
z: 0,
},
distance: 1
}, "face");

os.addBotDropSnap(bot, ...targets)

Specifies a list of snap targets that can be used to position the currently dragged bot when it is being dropped on the given bot. This function is useful for making some bots act like a "selector" or mask for drop areas.

If called when the user is not dragging anything, then this function does nothing.

The first parameter is the bot which, when the dragged bot is being dropped onto it (as indicated by @onDropEnter/@onDropExit), the specified snap targets will take effect.

The other parameters are the snap targets and each can be one of the following values:

ValueDescription
ground

The bot will snap to the ground plane. (Default when not in VR)

grid

The bot will snap to individual grid tiles.

face

The bot will snap the faces of other pointable bots.

bots

The bot will snap to other pointable bots.

A snap point object

The bot will snap to the specified position when dragged within the specified distance.

Snap point objects should have the following form:

let snapPoint: {
/**
* The position that the bot should be snapped to.
*/
position: { x: number, y: number, z: number };

/**
* The distance that the bot should be from the position in order to snap to it.
*/
distance: number;
};

Examples:

  1. Snap the dragged bot to the grid when it is being dropped on this bot.
os.addBotDropSnap(thisBot, "grid");
  1. Snap the dragged bot to this bot's faces.
os.addBotDropSnap(thisBot, "face");
  1. Snap the dragged bot to a point when it is being dropped on this bot.
os.addBotDropSnap(thisBot, {
position: {
x: 0,
y: 0,
z: 3,
},
distance: 1
});
  1. Snap the dragged bot to the center or bot faces when it is being dropped on this bot.
os.addBotDropSnap(thisBot, {
position: {
x: 0,
y: 0,
z: 0,
},
distance: 1
}, "face");

os.addDropGrid(...targets)

Specifies a list of grids that can be used to position the currently dragged bot.

If called when the user is not dragging anything, then this function does nothing.

Each parameter is an object with the following properties:

let grid: {
/**
* The 3D position that the grid should appear at.
*/
position?: { x: number, y: number, z: number };

/**
* The 3D rotation that the grid should appear at.
*/
rotation?: { x: number, y: number, z: number, w?: number };

/**
* The bot that defines the portal that the grid should exist in.
*
* If null, then this defaults to the bot that is showing the portal that the dragged bot exists in.
* For common cases this will be the configBot, but it could also be a bot that has a portal form.
*/
portalBot?: Bot | string;

/**
* The tag that the portal uses to determine which dimension to show.
* Defaults to formAddress if the specified portalBot is not the configBot and gridPortal if the specified portalBot is the configBot.
*/
portalTag?: string;

/**
* The 2D bounds of the grid.
* Defaults to 10 x 10.
*/
bounds?: { x: number, y: number };

/**
* The priority that this grid should be evaluated in over other grids.
* Higher priorities will be evaluated before lower priorities.
*/
priority?: number;

/**
* Whether to visualize the grid while a bot is being dragged.
* Defaults to false.
*/
showGrid?: boolean;

/**
* The type of grid that this snap grid should be.
* Defaults to the type of grid that the portal bot uses.
*
* - "grid" indicates that the snap target should be a flat grid.
* - "sphere" indicates that the snap target should be a sphere.
*/
type?: 'grid' | 'sphere';
};

Examples:

Add a grid for the portal that the bot currently exists in.
os.addDropGrid({});
Add a grid with a 60 degree X rotation.
os.addDropGrid({
position: { x: 0, y: 0, z: 0 },
rotation: { x: 60 * (Math.PI / 180), y: 0, z: 0 },
});
Add a grid for a specific portal bot.
os.addDropGrid({
portalBot: getBot(byTag('form', 'portal'), byTag('formAddress', 'myDimension')),
});
Add a grid with a custom size.
os.addDropGrid({
position: { x: 0, y: 0, z: 3 },
bounds: { x: 20, y: 10 }
});
Add a grid that the user can see.
os.addDropGrid({
position: { x: 0, y: 0, z: 3 },
showGrid: true
});
Add multiple grids with custom priorities
os.addDropGrid({
position: { x: 0, y: 0, z: 3 },
bounds: { x: 10, y: 10 },
showGrid: true,
priority: 10
}, {
position: { x: 0, y: 0, z: 0 },
bounds: { x: 20, y: 20 },
showGrid: true,
priority: 20
});
Add a spherical grid that the user can see.
os.addDropGrid({
type: "sphere",
position: { x: 0, y: 0, z: 3 },
showGrid: true
});

os.addBotDropGrid(bot, ...targets)

Specifies a list of grids that can be used to position the currently dragged bot when it is being dropped on the given bot.

If called when the user is not dragging anything, then this function does nothing.

The first parameter is the bot which, when the dragged bot is being dropped onto it (as indicated by @onDropEnter/@onDropExit), the specified snap targets will take effect.

The other parameters are objects with the following properties:

let grid: {
/**
* The 3D position that the grid should appear at.
*/
position?: { x: number, y: number, z: number };

/**
* The 3D rotation that the grid should appear at.
*/
rotation?: { x: number, y: number, z: number, w?: number };

/**
* The bot that defines the portal that the grid should exist in.
*
* If null, then this defaults to the bot that is showing the portal that the dragged bot exists in.
* For common cases this will be the configBot, but it could also be a bot that has a portal form.
*/
portalBot?: Bot | string;

/**
* The tag that the portal uses to determine which dimension to show.
* Defaults to formAddress if the specified portalBot is not the configBot and gridPortal if the specified portalBot is the configBot.
*/
portalTag?: string;

/**
* The 2D bounds of the grid.
* Defaults to 10 x 10.
*/
bounds?: { x: number, y: number };

/**
* The priority that this grid should be evaluated in over other grids.
* Higher priorities will be evaluated before lower priorities.
*/
priority?: number;

/**
* Whether to visualize the grid while a bot is being dragged.
* Defaults to false.
*/
showGrid?: boolean;

/**
* The type of grid that this snap grid should be.
* Defaults to the type of grid that the portal bot uses.
*
* - "grid" indicates that the snap target should be a flat grid.
* - "sphere" indicates that the snap target should be a sphere.
*/
type?: 'grid' | 'sphere';
};

Examples:

Add a grid for the portal that the bot currently exists in when it is being dropped on this bot.
os.addDropGrid(thisBot, {});
Add a grid with a 60 degree X rotation when it is being dropped on this bot.
os.addBotDropGrid(thisBot, {
position: { x: 0, y: 0, z: 0 },
rotation: { x: 60 * (Math.PI / 180), y: 0, z: 0 },
});
Add a grid for a specific portal bot when it is being dropped on this bot.
os.addBotDropGrid(thisBot, {
portalBot: getBot(byTag('form', 'portal'), byTag('formAddress', 'myDimension')),
});
Add a grid with a custom size when it is being dropped on this bot.
os.addBotDropGrid(thisBot, {
position: { x: 0, y: 0, z: 3 },
bounds: { x: 20, y: 10 }
});
Add a grid that the user can see when it is being dropped on this bot.
os.addBotDropGrid(thisBot, {
position: { x: 0, y: 0, z: 3 },
showGrid: true
});
Add multiple grids with custom priorities when it is being dropped on this bot.
os.addBotDropGrid(thisBot, {
position: { x: 0, y: 0, z: 3 },
bounds: { x: 10, y: 10 },
showGrid: true,
priority: 10
}, {
position: { x: 0, y: 0, z: 0 },
bounds: { x: 20, y: 20 },
showGrid: true,
priority: 20
});
Add a spherical grid that the user can see.
os.addBotDropGrid(thisBot, {
type: "sphere",
position: { x: 0, y: 0, z: 3 },
showGrid: true
});

os.showChat(placeholder?)

Shows the "chat bar" at the top of the screen in CasualOS, optionally using the given text as the placeholder. Typing in the chat bar will send @onChatTyping shouts and pressing Enter will send a @onChat shout and clear the chat bar.

The first parameter is the text that the chat bar should show as the placeholder.

Examples:

  1. Show the chat bar.
os.showChat();
  1. Show the chat bar with some placeholder text.
os.showChat("hello");

os.showChat(options)

Shows the "chat bar" at the top of the screen in CasualOS, using the given options. Typing in the chat bar will send @onChatTyping shouts and pressing Enter will send a @onChat shout and clear the chat bar.

The first parameter is an object with the options that the chat bar should use. It should be an object with the following properties:

  • placeholder - The text that should be shown as a placeholder. (optional)
  • prefill - The text that should be filled into the chat bar. If the chat bar already has text in it, then setting this property does nothing.
  • placeholderColor - The color that the placeholder text should be. Defaults to #448aff.
  • backgroundColor - The color that the background of the chat bar should be. Defaults to #fff in light mode and #212121 in dark mode. If a foregroundColor is specified, then backgroundColor will always default to #fff.
  • foregroundColor - The color that the foreground (text) of the chat bar should be. Defaults to #000 in light mode and #fff in dark mode. If a backgroundColor is specified, then foregroundColor will always default to #000.

Examples:

Show the chat bar with a placeholder.
os.showChat({
placeholder: "hello"
});
Show the chat bar with some prefilled text.
os.showChat({
prefill: "this is prefilled"
});
Show the chat bar with some prefilled text and a placeholder.
os.showChat({
prefill: "this is prefilled",
placeholder: "hello"
});
Show the chat bar with a custom placeholder color.
os.showChat({
placeholder: "hello",
placeholderColor: '#44a471'
});
Show the chat bar with a custom background color.
os.showChat({
placeholder: "hello",
backgroundColor: '#f1abe2'
});
Show the chat bar with a custom foreground color.
os.showChat({
placeholder: "hello",
foregroundColor: '#531234'
});

os.hideChat()

Hides the "chat bar" at the top of the screen in CasualOS.

Examples:

  1. Hide the chat bar.
os.hideChat();

os.showHtml(html)

Shows some HTML to the player in a popup modal. This can be useful for loading a separate webpage or providing some formatted text.

The first parameter is the HTML that should be shown to the user.

Examples:

  1. Show a header with some text.
os.showHtml(`
<h1>This is some text!</h1>
`);
  1. Show a YouTube video.
os.showHtml(`
<iframe
width="560"
height="315"
src="https://www.youtube.com/embed/BHACKCNDMW8"
frameborder="0"
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen>
</iframe>
`);

os.hideHtml()

Closes the HTML popup modal.

Examples:

  1. Hide the HTML popup.
os.hideHtml();

os.share(options)

Shares the given URL or text via the device's social share capabilities. Returns a Promise that resolves when sharing has succeeded or failed.

The first parameter is an object with at least one the following properties:

  • url - The URL that should be shared. (optional)
  • text - The text that should be shared. (optional)
  • title - The title of the document that is being shared. (optional)

Examples:

  1. Share a URL.
os.share({
url: 'https://example.com'
});
  1. Share some text.
os.share({
text: 'abcdefghijklmnopqrstuvwxyz'
});

os.openCircleWipe(options?)

Causes the circular wipe animation to open around the screen. This can be used to reveal the grid portal after transitioning between screens. Returns a promise that resolves when the animation has finished running. The promise will throw an exception if os.closeCircleWipe(options?) is called while the animation is running.

The first parameter is optional and is an object that contains options for the animation:

let options: {
/**
* The duration of this half of the circle wipe animation in seconds.
* Defaults to 1.
*/
duration?: number;

/**
* The color that the circle wipe should be.
* Defaults to "black".
*/
color?: string;
}

Examples:

  1. Reveal the grid portal with a circular wipe animation.
await os.openCircleWipe();
os.toast("Revealed!");
  1. Hide the grid portal and show it after an additional second.
await os.closeCircleWipe();
await os.sleep(1000);
await os.openCircleWipe();
  1. Use a custom color for the circle wipe.
await os.openCircleWipe({
color: '#63f1aa'
});
  1. Make the circle wipe take 5 seconds to complete.
await os.openCircleWipe({
duration: 5
});

os.closeCircleWipe(options?)

Causes a circular wipe animation to close around the screen. This can be used to cover the grid portal while transitioning between scenes. Returns a promise that resolves when the animation has finished running. The promise will throw an exception if os.openCircleWipe(options?) is called while the animation is running.

The first parameter is optional and is an object that contains options for the animation:

let options: {
/**
* The duration of this half of the circle wipe animation in seconds.
* Defaults to 1.
*/
duration?: number;

/**
* The color that the circle wipe should be.
* Defaults to "black".
*/
color?: string;
}

Examples:

  1. Hide the grid portal with a circular wipe animation.
await os.closeCircleWipe();
os.toast("Hidden!");
  1. Hide the grid portal and show it after an additional second.
await os.closeCircleWipe();
await os.sleep(1000);
await os.openCircleWipe();
  1. Use a custom color for the circle wipe.
await os.closeCircleWipe({
color: '#63f1aa'
});
  1. Make the circle wipe take 5 seconds to complete.
await os.closeCircleWipe({
duration: 5
});

os.toast(message, duration?)

Shows a temporary "toast" notification to the player at the bottom of the screen with the given message. Optionally accepts a duration parameter which is the number of seconds that the message should be on the screen.

The first parameter is the text that the toast message should show.

The second parameter is optional and is the number of seconds that the message should be on the screen. (Default is 2)

Examples:

  1. Show a "Hello!" toast message.
os.toast("Hello!");
  1. Show the player a code for 5 seconds.
os.toast("this is the code", 5);

os.tip(message, pixelX?, pixelY?, duration?)

Shows a temporary "tooltip" message on the screen. Optionally placed at the specified position and shown for the given duration. Returns a promise that resolves with the ID of the new tooltip.

If a position is not specified, then a position just below the current mouse position will be used. If on mobile, then the last touch position will be used or the center of the screen if the user has not touched the screen. Additionally, if a position is not specified then the tooltip will be automatically hidden if the user moves the mouse significantly away from the position that the mouse was at when the tooltip was shown.

The first parameter is the text that the tooltip message should show.

The second parameter is optional and is the horizontal pixel position that the tooltip should be shown at on the screen. If not specified then the current mouse position will be used.

The third parameter is optional and is the vertical position that the tooltip should be shown at on the screen. If not specified then a position just below the current mouse position will be used.

The fourth parameter is optional and is the number of seconds that the toast should be shown for before automatically being hidden. (Default is 2)

Examples:

  1. Show a "Hello!" tip message.
os.tip("Hello!");
  1. Show a tip at the center of the screen.
os.tip("This is in the center of the screen.", gridPortalBot.tags.pixelWidth / 2, gridPortalBot.tags.pixelHeight / 2);
  1. Show a tip near the mouse cursor for 5 seconds.
os.tip("5 second tip.", null, null, 5);
  1. Show a tip and record its ID in a tag mask.
masks.tipID = await os.tip("Hello!");

os.hideTips(tipIDs?)

Hides the tooltips that have the specified IDs. If no arguments are specified, then all tooltips will be hidden. Returns a promise that resolves when the tooltips have been hidden.

The first parameter is the tooltip ID or array of tooltip IDs that should be hidden.

Examples:

  1. Show and hide a tooltip message.
const id = await os.tip("Hello!");
await os.sleep(1000);
await os.hideTips(id);

os.focusOn(botOrPosition, options?)

Focuses on the given bot or position. For bots in the bot or miniGridPortals, this animates the camera such that the portal focus point is placed on the given bot or position. For input bots in menu portal, this gives keyboard focus to them.

Returns a promise which resolves when the bot has been focused. For the bot and miniGridPortals this is when the animation finishes and rejects if the user takes control of the camera during the animation. For menu bots this is when the input field is focused and rejects if the bot is not a input bot.

The first parameter is the bot, bot ID, or position that should be focused. If null, then the current focus animation will be canceled.

The second parameter is optional and can be used to specify additional details about how the camera should be animated. It should be an object with the following properties:

let options: {
/*
* The zoom value to use.
* For the bot and miniGridPortals, possible values are between `0` and `80`. `1` is the default.
* For the map portal, this is the scale that the focused point should appear at.
* For example, 24000 would indicate that the scale is 1:24,000.
* If no value is specified, then the zoom will remain at its current value.
*/
zoom?: number;

/*
* The rotation value to use in radians.
* These are the polar coordinates that determine where
* the camera should orbit around the target point.
*/
rotation?: {
x: number;
y: number;

/**
* Whether to normalize the rotation. Normalized rotations are clamped to between 0 and Math.PI*2.
* You can set this to false to allow using angles more than Math.PI*2. This would allow the camera to rotate around an object multiple times.
* Defaults to true.
*/
normalize?: boolean;
};

/**
* The duration in seconds that the animation should take.
* Defaults to 1.
*/
duration?: number;

/**
* The portal that the bot should be focused in.
* If not specified, then the bot will be focused in all the portals it is in. (bot, mini and menu)
* Useful if a bot is in two portals but you only want to focus it in one portal.
*/
portal?: string;

/**
* The tag that should be focused.
* Only supported in the system portal.
*/
tag?: string;

/**
* The tag space that should be focused.
* Only supported in the system portal, sheet portal, and tag portals.
*/
space?: string;

/**
* The line number that should be selected in the editor.
* Only supported in the system portal, sheet portal, and tag portals.
*/
lineNumber?: number;

/**
* The column number that should be selected in the editor.
* Only supported in the system portal, sheet portal, and tag portals.
*/
columnNumber?: number;

/**
* The index of the first character that should be selected.
* Only supported in the system portal, sheet portal, and tag portals.
*/
startIndex?: number;

/**
* The index of the last character that should be selected.
* Only supported in the system portal, sheet portal, and tag portals.
*/
endIndex?: number;

/**
* The options for easing.
* Can be an "easing type" or an object that specifies the type and mode.
* If an easing type is specified, then "inout" mode is used.
* If omitted, then "quadratic" "inout" is used.
*/
easing?: 'linear'
| 'quadratic'
| 'cubic'
| 'quartic'
| 'quintic'
| 'sinusoidal'
| 'exponential'
| 'circular'
| 'elastic'
| {
/**
* The type of easing.
*/
type: 'linear'
| 'quadratic'
| 'cubic'
| 'quartic'
| 'quintic'
| 'sinusoidal'
| 'exponential'
| 'circular'
| 'elastic';

/**
* Whether to apply the easing at the
* start (in), end (out), or start and end (inout) of the tween.
*/
mode: 'in' | 'out' | 'inout';
}
}

See #portalCameraRotationX for more information on polar coordinates.

Examples:

  1. Move the player's view to show a bot named bob.
await os.focusOn(getBot("#name", "bob"));
  1. Move the player's view to show this bot from the top.
await os.focusOn(thisBot, {
rotation: {
x: 0,
y: 0
}
});
  1. Move the player's view to show this bot with a particular zoom value.
await os.focusOn(thisBot, {
zoom: 15
});
  1. Move the player's view to a specific position.
await os.focusOn({
x: 15,
y: 9.5
});
  1. Focus on this bot in the menu portal
await os.focusOn(thisBot, {
portal: 'menu'
});
  1. Focus on Buckingham Palace in the map portal
await os.focusOn({
x: -0.141329,
y: 51.501541
}, {
portal: 'map',
zoom: 10000
});
  1. Rotate the camera around the focus point 3 times.
await os.focusOn(thisBot, {
rotation: {
y: (Math.PI * 2) * 3,
normalize: false
}
});
  1. Focus the onClick tag in the systemPortal
await os.focusOn(thisBot, {
tag: 'onClick',
portal: 'system'
});
  1. Focus line 2 in the onClick tag in the sheetPortal
await os.focusOn(thisBot, {
tag: 'onClick',
lineNumber: 2,
portal: 'sheet'
});
  1. Focus index 9 through 15 in the onClick tag in the tagPortal
await os.focusOn(thisBot, {
tag: 'onClick',
startIndex: 9,
endIndex: 15,
portal: 'tag'
});

os.openQRCodeScanner(camera?)

Opens the QR Code scanner. While open, each scanned QR Code will send a @onQRCodeScanned shout. Optionally accepts which camera to use for scanning. (front/back)

The first parameter is optional and is a string specifing which camera to use. Defaults to 'rear'. If the given camera type is not available, then the default camera will be used. Possible values are:

ValueDescription
rear

The rear-facing camera. (Default)

front

The front-facing camera.

Examples:

  1. Open the QR Code scanner.
os.openQRCodeScanner();
  1. Open the QR Code scanner for the front-facing camera.
os.openQRCodeScanner("front");

os.closeQRCodeScanner(camera?)

Closes the QR Code scanner.

Examples:

  1. Close the QR Code scanner.
os.closeQRCodeScanner();

os.showQRCode(code)

Shows a QR Code for the given data.

The first parameter is the text or data that the generated QR Code should represent.

Examples:

  1. Show a QR Code that contains the data "hello".
os.showQRCode("hello");

os.hideQRCode()

Closes the QR Code popup modal.

Examples:

  1. Hides the QR Code popup modal.
os.hideQRCode();

os.showJoinCode(inst?, dimension?)

Shows a QR Code with a link to join the given inst and dimension. If the inst and dimension are omitted, then the current inst and dimension will be used.

The first parameter is the inst that the code should be shown for.

The second parameter is the dimension that the code should be shown for.

Examples:

  1. Show a join QR Code.
os.showJoinCode();
  1. Show a join QR Code for a inst and dimension.
os.showJoinCode("inst", "dimension");

os.openBarcodeScanner(camera?)

Opens the Barcode scanner. While open, each scanned Barcode will send a @onBarcodeScanned shout. Optionally accepts which camera to use for scanning. (front/back)

The first parameter is optional and is a string specifing which camera to use. Defaults to 'rear'. If the given camera type is not available, then the default camera will be used. Possible values are:

ValueDescription
rear

The rear-facing camera. (Default)

front

The front-facing camera.

Examples:

  1. Open the Barcode scanner.
os.openBarcodeScanner();
  1. Open the Barcode scanner for the front-facing camera.
os.openBarcodeScanner("front");

os.closeBarcodeScanner(camera?)

Closes the Barcode scanner.

Examples:

  1. Close the Barcode scanner.
os.closeBarcodeScanner();

os.showBarcode(code, format?)

Shows a Barcode for the given data. Optionally accepts the format that the barcode should be displayed in.

The first parameter is the text or data that the generated Barcode should represent.

The second parameter is optional and is the format that the barcode should be displayed in. Possible values are:

ValueDescription
code128

The Code 128 barcode format. (Default)

code39

The Code 39 barcode format.

ean13

The EAN-13 barcode format.

ean8

The EAN-8 barcode format.

upc

The UPC barcode format.

itf14

The IFT-14 barcode format.

msi

The MSI barcode format.

pharmacode

The Pharmacode barcode format.

codabar

The Codabar barcode format.

Examples:

  1. Show a Barcode that contains the data "hello".
os.showBarcode("hello");
  1. Show a UPC Barcode that contains the data "123456".
os.showBarcode("123456", 'upc');

os.hideBarcode()

Closes the Barcode popup modal.

Examples:

  1. Hides the Barcode popup modal.
os.hideBarcode();

os.openImageClassifier(options)

Opens the image classifier with the given options. Returns a promise that resolves once the image classifier has been opened.

Sends the @onImageClassifierOpened shout once opened and the @onImageClassified shout every time an image has been classified.

The first parameter is the options that should be used for the image classifier. It should be an object and has the following properties:

let options: {
/**
* The URL that the model should be loaded from.
* For Teachable Machine, this should be the shareable link that is generated when you export and upload the project.
* Can be omitted if both modelJsonUrl and modelMetadataUrl are provided.
*/
modelUrl?: string;

/**
* The URL that the model JSON should be loaded from.
* Not required. Can be used if you are storing the model JSON in a custom location (like in a record).
*/
modelJsonUrl?: string;

/**
* The URL that the model metadata should be loaded from.
* Not required. Can be used if you are storing the model metadata in a custom location (like in a record).
*/
modelMetadataUrl?: string;

/**
* The camera that should be preferred for the image classifier.
* If not provided then the rear (i.e. environment) facing camera will be preferred.
*/
cameraType?: 'rear' | 'front';
};

Examples:

Open the image classifier.
await os.openImageClassifier({
modelUrl: 'MY_MODEL_URL'
});
Open the image classifier with a specific camera.
await os.openImageClassifier({
modelUrl: 'MY_MODEL_URL',
cameraType: 'front'
});

os.closeImageClassifier()

Closes the image classifier. Returns a promise that resolves once the image classifier has been closed. Also sends the @onImageClassifierClosed shout once closed.

Examples:

Close the image classifier.
await os.closeImageClassifier();

os.showInput(value?, options?)

Shows an input modal with the given value and options. When shown, the player will be able to change the value.

Returns a Promise that resolves with the final value when the user is finished editing. This function is similar to os.showInputForTag(bot, tag, options?) except it doesn't require a bot and a tag.

The first parameter is optional and is the value that should be shown in the input modal,

The third parameter is optional and is the possible cusomization options for the input modal.

Examples:

  1. Show a basic text input modal and displays a toast message with the input value.
const value = await os.showInput();
os.toast(value);
  1. Show a text input modal with a placeholder.
const name = await os.showInput(null, {
placeholder: 'Enter a name'
});
os.toast(name);
  1. Show a input modal with a custom title.
const name = await os.showInput('My Name', {
title: 'Edit name'
});
os.toast(name);
  1. Show a color input modal with a custom title.
const color = await os.showInput('green', {
type: 'color',
title: 'Enter a custom color'
});
os.toast(color);
  1. Show an input for entering secrets (like passwords).
const secret = await os.showInput('', {
type: 'secret',
title: 'Enter a secret key'
});
os.toast(secret);
  1. Show an input for entering dates.
const date = await os.showInput('', {
type: 'date',
title: 'Enter a date'
});
os.toast(date);
  1. Show an input with a list of options.
// Null means nothing is selected
// To pre-select an item, pass in the index of the item you want selected.
const selectedItem = await os.showInput(null, {
title: 'Select your favorite superhero',
type: 'list',
placeholder: 'Superhero',
items: [
{
label: 'Superman',
value: 1
},
{
label: 'Iron Man',
value: 2
},
{
label: 'Batman',
value: 3
},
{
label: 'Wonder Woman',
value: 4
}
]
});
os.toast(selectedItem);
  1. Show an input with a list of checkboxes.
// Empty array means nothing is selected.
// To pre-select items, pass in an array with the indexes of the items you want selected.
const selectedItems = await os.showInput([], {
title: 'Check your favorite superheroes',
type: 'list',
subtype: 'checkbox',
items: [
{
label: 'Superman',
value: 1
},
{
label: 'Iron Man',
value: 2
},
{
label: 'Batman',
value: 3
},
{
label: 'Wonder Woman',
value: 4
}
]
});
os.toast(selectedItems);
  1. Show an input with a dropdown of checkboxes.
// Empty array means nothing is selected.
// To pre-select items, pass in an array with the indexes of the items you want selected.
const selectedItems = await os.showInput([], {
title: 'Select your favorite superheroes',
type: 'list',
subtype: 'multiSelect',
placeholder: 'Superhero',
items: [
{
label: 'Superman',
value: 1
},
{
label: 'Iron Man',
value: 2
},
{
label: 'Batman',
value: 3
},
{
label: 'Wonder Woman',
value: 4
}
]
});
os.toast(selectedItems);
  1. Show an input with a list of radio buttons.
// Null means nothing is selected.
// To pre-select an item, pass in the index of the item you want selected.
const selectedItem = await os.showInput(null, {
title: 'Check your favorite superheroe',
type: 'list',
subtype: 'radio',
placeholder: 'Superhero',
items: [
{
label: 'Superman',
value: 1
},
{
label: 'Iron Man',
value: 2
},
{
label: 'Batman',
value: 3
},
{
label: 'Wonder Woman',
value: 4
}
]
});
os.toast(selectedItem);

os.showInputForTag(bot, tag, options?)

Shows an input modal for the given bot and tag with the given options. When shown, the player will be able to change the value stored in the given tag. Triggers the @onSaveInput whisper when the modal is closed with saving and the @onCloseInput whisper when the modal is closed without saving.

The first parameter is the bot or bot ID that the input should be shown for,

The second parameter is the tag that should be edited on the bot.

The third parameter is optional and is the possible cusomization options for the input modal.

Examples:

  1. Show a basic text input modal for the #name tag on this bot.
os.showInputForTag(this, "name");
  1. Show a text input modal with a placeholder for the #name tag.
os.showInputForTag(this, "name", {
placeholder: 'Enter a name'
});
  1. Show a input modal with a custom title.
os.showInputForTag(this, "name", {
title: 'Edit name'
});
  1. Show a color input modal with a custom title.
os.showInputForTag(this, "color", {
type: 'color',
title: 'Enter a custom color'
});

os.showConfirm(options)

Shows a confirmation dialog using the given options. Confirmation dialogs are useful for giving users the ability to quickly confirm or cancel an action.

Returns a promise that resolves with true if the user clicked the "Confirm" button and false if they closed the dialog or clicked the "Cancel" button.

The first parameter is the options that should be used. It should be an object with the following structure:

let options: {
/**
* The title that should be shown for the dialog.
*/
title: string;

/**
* The content of the dialog.
*/
content: string;

/**
* The text that should be shown on the "Confirm" button.
*/
confirmText?: string;

/**
* The text that should be shown on the "Cancel" button.
*/
cancelText?: string;
};

Examples:

Show a confirmation dialog
let confirmed = await os.showConfirm({
title: 'Confirm',
content: 'Please confirm the action.'
});

os.toast('Confirmed: ' + (confirmed ? 'Yes' : 'No'));
Show a confirmation dialog with custom button text
let confirmed = await os.showConfirm({
title: 'Confirm',
content: 'Are you sure?',
confirmText: 'Yes',
cancelText: 'No'
});

os.toast('Confirmed: ' + (confirmed ? 'Yes' : 'No'));

os.setClipboard(text)

Copies the given text to the player's clipboard. On Chrome and Firefox, this will act like a Ctrl+C/Cmd+C. On Safari and all iOS browsers this will open a popup which prompts the player to copy the text.

The first parameter is the text that should be copied to the player's clipboard.

Examples:

  1. Copy "hello" to the player's clipboard.
os.setClipboard("hello");

os.showUploadFiles()

Shows the "Upload Files" dialog which lets the user select some files to upload to the inst. Returns a promise that resolves with the list of files that were uploaded.

Each file is an object with the following structure:

let file: {
/**
* The name of the file.
*/
name: string;

/**
* The size of the file in bytes.
*/
size: number;

/**
* The data in the file.
* If the file is a text file, the data will be a string.
* If the file is not a text file, then the data will be an ArrayBuffer.
*
* Text files have one of the following extensions:
* .txt
* .json
* .md
* .aux
* .html
* .js
* .ts
* All the other file extensions map to an ArrayBuffer.
*/
data: string | ArrayBuffer;

/**
* The MIME type of the file.
* See https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types for more information.
*/
mimeType: string;
};

Examples:

  1. Show the "Upload Files" dialog.
const files = await os.showUploadFiles();

os.toast("You uploaded " + files.length + " file(s)!");

os.showUploadAuxFile()

Shows the "Upload AUX File" dialog which lets the user select a .aux file to upload to the inst.

Examples:

  1. Show the "Upload AUX File" dialog.
os.showUploadAuxFile();

os.loadInst(inst)

Loads the given inst into the current browser tab. When the inst is loaded, the @onInstJoined shout will be triggered.

Note that separate instances cannot interact directly. They must instead interact via super shouts.

The first parameter is the name of the inst to load.

Examples:

  1. Load the fun inst.
os.loadInst("fun");

os.unloadInst()

Unloads the given inst from the current browser tab. When the inst is unloaded, the @onInstLeave shout will be triggered.

The first parameter is the name of the inst to unload.

Examples:

  1. Unload the fun inst.
os.unloadInst('fun');

os.downloadInst()

Downloads all of the shared bots into a .aux file on the player's computer. The file will have the same name as the inst.

Note that this function is almost exactly the same as os.downloadBots(bots, filename). The only difference is that all bots in the shared space are included and the file is named for you automatically.

Examples:

  1. Download the entire inst.
os.downloadInst();

os.getMediaPermission(options)

Returns a promise that resolves if the user grants the specified media permission(s). If the user blocks permission or has previously blocked permission or any other problem occurs, an error will be thrown.

The first parameter is is an object with at least one of the following properties set to true:

  • audio - Should request access to device audio (microphone). (optional)
  • video - Should request access to device video (camera). (optional)

Examples:

  1. Get permission for the device's microphone.
try {
await os.getMediaPermission({ audio: true });
} catch (e) {
console.error('Could not get permission for microphone:', e);
}
  1. Get permission for the device's microphone and camera.
try {
await os.getMediaPermission({ audio: true, video: true });
} catch (e) {
console.error('Could not get permission for microphone and/or camera:', e);
}

os.getAverageFrameRate()

Gets the number of frames that have occurred over the last second. Returns a promise that resolves with the number of frames that have ocurred in the last second.

Examples:

  1. Get the current frames per second.
masks.label = await os.getAverageFrameRate();
  1. Create a basic FPS counter.
setInterval(async () => {
masks.label = await os.getAverageFrameRate();
}, 1000);

os.arSupported()

Returns a promise that resolves with a flag indicating wether or not augmented reality is supported by the device.

Examples:

  1. Check if AR is supported:
const supported = await os.arSupported();

os.vrSupported()

Returns a promise that resolves with a flag indicating wether or not virtual reality is supported by the device.

Examples:

  1. Check if VR is supported:
const supported = await os.vrSupported();

os.enableAR(options?)

Enables augmented reality on the device.
You can check for device support by calling os.arSupported().

If enabled successfully, the @onEnterAR shout is sent to all bots.

The first parameter is optional and should be an object with the following properties:

let options: {
/**
* The frame buffer scale factor that should be used for the XR session.
* (see https://developer.mozilla.org/en-US/docs/Web/API/XRWebGLLayer/getNativeFramebufferScaleFactor)
* - Null or undefined indicates that the default should be used. (usually 1)
* - A number indicates the ratio of frame buffer pixels to output pixels. (e.g. a value of 2 will cause every 2 frame buffer pixels to be correlated with 1 output pixel, meaning that the render resolution is doubled)
* - "recommended" indicates that CasualOS should try to pick the optimal number.
*/
frameBufferScaleFactor?: number | 'recommended';
}

Examples:

  1. Enable AR.
os.enableAR();
  1. Enable AR running at half the resolution of normal.
os.enableAR({
frameBufferScaleFactor: 0.5
});

os.disableAR()

Disables augmented reality on the device.

When disabled, @onExitAR shout is sent to all bots.

Examples:

  1. Disable AR.
os.disableAR();

os.enableVR()

Enables virtual reality on the device.
You can check for device support by calling os.vrSupported().

If enabled successfully, the @onEnterVR shout is sent to all bots.

The first parameter is optional and should be an object with the following properties:

let options: {
/**
* The frame buffer scale factor that should be used for the XR session.
* (see https://developer.mozilla.org/en-US/docs/Web/API/XRWebGLLayer/getNativeFramebufferScaleFactor)
* - Null or undefined indicates that the default should be used. (usually 1)
* - A number indicates the ratio of frame buffer pixels to output pixels. (e.g. a value of 2 will cause every 2 frame buffer pixels to be correlated with 1 output pixel, meaning that the render resolution is doubled)
* - "recommended" indicates that CasualOS should try to pick the optimal number.
*/
frameBufferScaleFactor?: number | 'recommended';
}

Examples:

  1. Enable VR.
os.enableVR();
  1. Enable VR running at half the resolution of normal.
os.enableVR({
frameBufferScaleFactor: 0.5
});

os.disableVR()

Disables virtual reality on the device.

When disabled, @onExitVR shout is sent to all bots.

Examples:

  1. Disable VR.
os.disableVR();

os.enablePointOfView(center?, imu?)

Enables Point-of-View mode on the device. Useful for getting a "ground level" view in the grid portal. This will move the camera to the given position, set the camera type to perspective, and change the camera controls so that dragging the screen causes the camera to look around.

It is not possible to manually move the camera in this mode, however it is still possible to use os.focusOn(botOrPosition, options?) to move the camera.

The first parameter is optional and is the position that the camera should be placed at. If not specified, then the camera will be placed at (0, 0, 0).

The second parameter is optional and determines whether the imuPortal should be used to control the camera rotation while in Point-of-View mode.

Examples:

  1. Enable POV mode.
os.enablePointOfView();
  1. Enable POV mode at (5, 0, 3).
os.enablePointOfView({
x: 5,
y: 0,
z: 3
});
  1. Enable POV mode with the IMU.
os.enablePointOfView(undefined, true);

os.disablePointOfView()

Disables Point-of-View mode on the device. This will return the camera to its original position, set the camera type back to what it was before, and change the camera controls to the defaults.

Examples:

  1. Disable POV mode.
os.disablePointOfView();

os.getCurrentInst()

Gets the inst that is loaded.

Examples:

  1. Show a message of the current inst.
const inst = os.getCurrentInst();
os.toast(inst);

os.getCurrentDimension()

Gets the dimension that is loaded into the #gridPortal portal.

Examples:

  1. Show a message of the dimension that is currently in the #gridPortal portal.
const dimension = os.getCurrentDimension();
os.toast(dimension);

os.getMenuDimension()

Gets the dimension that is loaded into the #menuPortal portal.

Examples:

  1. Show a message of the dimension that is currently in the #menuPortal portal.
const dimension = os.getMenuDimension();
os.toast(dimension);

os.getMiniPortalDimension()

Gets the dimension that is loaded into the #miniGridPortal portal.

Examples:

  1. Show a message of the dimension that is currently in the #miniGridPortal portal.
const dimension = os.getMiniPortalDimension();
os.toast(dimension);

os.hasBotInMiniPortal(bot)

Determines if the given bot is in the dimension that is currently loaded into the #miniGridPortal portal.

The first parameter is the bot that should be checked.

Examples:

  1. Show a message if a bot named bob is in the miniGridPortal.
const bob = getBot("#name", "bob");
if (os.hasBotInMiniPortal(bob)) {
os.toast("bob is in the miniGridPortal!");
}

os.getPortalDimension(portal)

Gets the dimension that is loaded into the given portal.

The first parameter is the portal that the dimension should be retrieved for. Possible values are:

ValueDescription
grid

The #gridPortal.

sheet

The #sheetPortal.

miniGrid

The #miniGridPortal.

menu

The #menuPortal.

Examples:

  1. Get the dimension that is currently showing in the #gridPortal.
const dimension = os.getPortalDimension('grid');
  1. Get the dimension that is currently showing in the #miniGridPortal.
const dimension = os.getPortalDimension('miniGrid');
  1. Get the dimension that is currently showing in the #auxCustomPortal tag.
const dimension = os.getPortalDimension('auxCustomPortal');

os.getDimensionalDepth(dimension)

Gets the distance that the player bot is from the given dimension.

The first parameter is the dimension that should be searched for.

Possible return values are:

ValueDescription
-1

The player bot cannot access the given dimension.

0

The player bot is in the given dimension. (dimension tag is true)

1

The player bot is viewing the given dimension through a portal. (a portal tag is set to the dimension)

Examples:

  1. Get the distance to the "fun" dimension.
const distance = os.getDimensionalDepth("fun");
if (distance === 0) {
os.toast("Player is in the fun dimension");
} else if(distance === 1) {
os.toast("Player is viewing the fun dimension");
} else {
os.toast("Player cannot access the fun dimension");
}

os.raycast(portal, origin, direction)

Finds the list of bots that are in the given portal and are intersected by a ray starting at the given origin position and traveling in the given direction. Returns a promise that resolves with information about the intersected bots. It resolves with an object that has the following form:

let result: {
/**
* The list of intersections.
*/
botIntersections: BotIntersection[];

/**
* The ray that the operation sent.
*/
ray: RaycastRay;
};

/**
* Defines an interface that represents the intersection of a bot and ray.
*/
export interface BotIntersection {
/**
* The bot that was intersected.
*/
bot: Bot;

/**
* The distance from the origin of the ray that the intersection ocurred at.
*/
distance: number;

/**
* The point that the intersection ocurred at.
*/
point: Vector3;

/**
* The normal that the intersection ocurred at.
*/
normal: Vector3;

/**
* The face that the intersection hit.
*/
face: string;

/**
* The UV coordinates that the intersection ocurred at.
*/
uv: Vector2;

/**
* The portal that the bot is in.
*/
portal: string;

/**
* The dimension that the bot is in.
*/
dimension: string;
}

/**
* Defines an interface that represents a ray.
*/
export interface RaycastRay {
/**
* The origin of the ray.
*/
origin: Vector3;

/**
* The direction that the ray travels in.
*/
direction: Vector3;
}

The first parameter is the name of the portal that should be tested. It can be one of the following values:

ValueDescription
grid

Bots that are in the grid portal are tested against the ray.

miniGrid

Bots that are in the mini grid portal are tested against the ray.

map

Bots that are in the map portal are tested against the ray.

miniMap

Bots that are in the mini map portal are tested against the ray.

The second parameter is the 3D position that the ray should start at.

The third parameter is the 3D direction that the ray should travel along.

Examples:

Find the bots that are directly to the right of (0,0,0) in the grid portal
const result = await os.raycast("grid", new Vector3(0, 0, 0), new Vector3(1, 0, 0));

os.toast('Found Bots: ' + result.botIntersections.map(b => b.id).join(', '));
Find the bots that the mouse pointer is pointing at in the grid portal
const result = await os.raycast("grid", os.getPointerPosition("mouse"), os.getPointerDirection("mouse"));

os.toast('Found Bots: ' + result.botIntersections.map(b => b.id).join(', '));

os.raycastFromCamera(portal, viewportPosition)

Finds the list of bots that are in the given portal and are intersected by a ray starting at the portal camera and traveling along a path emanating from the given viewport position. Returns a promise that resolves with information about the intersected bots. It resolves with an object that has the following form:

let result: {
/**
* The list of intersections.
*/
botIntersections: BotIntersection[];

/**
* The ray that the operation sent.
*/
ray: RaycastRay;
};

/**
* Defines an interface that represents the intersection of a bot and ray.
*/
export interface BotIntersection {
/**
* The bot that was intersected.
*/
bot: Bot;

/**
* The distance from the origin of the ray that the intersection ocurred at.
*/
distance: number;

/**
* The point that the intersection ocurred at.
*/
point: Vector3;

/**
* The normal that the intersection ocurred at.
*/
normal: Vector3;

/**
* The face that the intersection hit.
*/
face: string;

/**
* The UV coordinates that the intersection ocurred at.
*/
uv: Vector2;

/**
* The portal that the bot is in.
*/
portal: string;

/**
* The dimension that the bot is in.
*/
dimension: string;
}

/**
* Defines an interface that represents a ray.
*/
export interface RaycastRay {
/**
* The origin of the ray.
*/
origin: Vector3;

/**
* The direction that the ray travels in.
*/
direction: Vector3;
}

The first parameter is the name of the portal that should be tested. It can be one of the following values:

ValueDescription
grid

Bots that are in the grid portal are tested against the ray.

miniGrid

Bots that are in the mini grid portal are tested against the ray.

map

Bots that are in the map portal are tested against the ray.

miniMap

Bots that are in the mini map portal are tested against the ray.

The second parameter is the 2D viewport position that the ray should start at. Viewport positions locate a specific point on the image that the camera produces. (X: 0, Y: 0) represents the center of the camera while (X: -1, Y: -1) represents the lower left corner and (X: 1, Y: 1) represents the upper right corner.

Examples:

Find the bots that are in the center of the screen
const result = await os.raycastFromCamera("grid", new Vector2(0, 0));

os.toast('Found Bots: ' + result.botIntersections.map(b => b.id).join(', '));
Find the bots that are on the left-center edge of the screen
const result = await os.raycastFromCamera("grid", new Vector2(-1, 0));

os.toast('Found Bots: ' + result.botIntersections.map(b => b.id).join(', '));

os.calculateRayFromCamera(portal, viewportPosition)

Calculates the ray that starts at the given portal camera and travels along the path emanating from the given viewport position. Returns a promise that resolves with information about the calculated ray. It resolves with an object that has the following form:

let result: {
/**
* The origin of the ray.
*/
origin: Vector3;

/**
* The direction that the ray travels in.
*/
direction: Vector3;
};

The first parameter is the name of the portal that should be tested. It can be one of the following values:

ValueDescription
grid

Bots that are in the grid portal are tested against the ray.

miniGrid

Bots that are in the mini grid portal are tested against the ray.

map

Bots that are in the map portal are tested against the ray.

miniMap

Bots that are in the mini map portal are tested against the ray.

The second parameter is the 2D viewport position that the ray should start at. Viewport positions locate a specific point on the image that the camera produces. (X: 0, Y: 0) represents the center of the camera while (X: -1, Y: -1) represents the lower left corner and (X: 1, Y: 1) represents the upper right corner.

Examples:

Find the ray that passes through the center of the screen
const ray = await os.calculateRayFromCamera("grid", new Vector2(0, 0));

os.toast('Calculated ray: ' + ray);
Find the ray that passes through the left-center edge of the screen
const ray = await os.raycastFromCamera("grid", new Vector2(-1, 0));

os.toast('Calculated ray: ' + ray);

os.getCameraPosition(portal?)

Gets the 3D position that the player's camera is at in the given portal.

The first parameter is optional and is the portal that the camera position should be retrieved for. Possible values are:

ValueDescription
grid

The camera position in the grid portal. (Default)

miniGrid

The camera position in the miniGridPortal.

Examples:

  1. Get the position of the player in the grid portal.
const position = os.getCameraPosition('grid');
  1. Get the position of the player in the miniGridPortal.
const position = os.getCameraPosition("mini");

os.getCameraRotation(portal?)

Gets the 3D rotation that the player's camera is at in the given portal.

The first parameter is optional and is the portal that the camera rotation should be retrieved for. Possible values are:

ValueDescription
grid

The camera rotation in the grid portal. (Default)

miniGrid

The camera rotation in the miniGridPortal.

Examples:

  1. Get the rotation of the player in the grid portal.
const rotation = os.getCameraRotation('grid');
  1. Get the rotation of the player in the miniGridPortal.
const rotation = os.getCameraRotation("mini");

os.getFocusPoint(portal?)

Gets the 3D position that the player's camera is focusing on in the given portal.

This is the same point that is highlighted when #portalShowFocusPoint is enabled for a portal.

The first parameter is optional and is the portal that the camera focus point should be retrieved for. Possible values are:

ValueDescription
grid

The camera focus point in the grid portal. (Default)

miniGrid

The camera focus point in the miniGridPortal.

Examples:

  1. Get the focus point of the player in the grid portal.
const focusPoint = os.getFocusPoint('grid');
  1. Get the focus point of the player in the miniGridPortal.
const focusPoint = os.getFocusPoint("mini");

os.getPointerPosition(pointer?)

Gets the position that the given pointer is at.

The first parameter is optional and is the pointer that the position should be retrieved for. Possible values are:

ValueDescription
mouse

The position of the mouse pointer. (Default)

left

The position of the left pointer.

right

The position of the right pointer.

Examples:

  1. Get the position of the mouse pointer.
const position = os.getPointerPosition("mouse");
  1. Get the position of the left pointer.
const position = os.getPointerPosition("left");

os.getPointerRotation(pointer?)

Gets the rotation that the given pointer is at.

The first parameter is optional and is the pointer that the rotation should be retrieved for. Possible values are:

ValueDescription
mouse

The rotation of the mouse pointer. (Default)

left

The rotation of the left pointer.

right

The rotation of the right pointer.

Examples:

  1. Get the rotation of the mouse pointer.
const rotation = os.getPointerRotation("mouse");
  1. Get the rotation of the left pointer.
const rotation = os.getPointerRotation("left");

os.getPointerDirection(pointer?)

Gets the direction that the given pointer is pointed in.

Can be combined with math.intersectPlane(origin, direction, planeNormal?, planeOrigin?) to find where on the ground the pointer is pointing.

The first parameter is optional and is the pointer that the direction should be retrieved for. Possible values are:

ValueDescription
mouse

The direction of the mouse pointer. (Default)

left

The direction of the left pointer.

right

The direction of the right pointer.

Examples:

  1. Get the direction of the mouse pointer.
const direction = os.getPointerDirection("mouse");
  1. Get the direction of the left pointer.
const direction = os.getPointerDirection("left");
  1. Find where the mouse is pointing on the ground.
const position = os.getPointerPosition();
const direction = os.getPointerDirection();
const groundPosition = math.intersectPlane(position, direction);

os.getInputState(controller, button)

Gets the state of the given button on the given controller.

The first parameter is the name of the controller that the button state should be retrieved from. Possible values are:

ValueDescription
mousePointer

The mouse.

leftPointer

The left controller. Sometimes available in VR.

rightPointer

The right controller. Sometimes available in VR.

keyboard

The keyboard.

touch

The touchscreen.

The second parameter is the name of the button that you want to get the state of. Possible values are:

ValueDescription
left

The left mouse button. Only available on the mouse pointer. On mobile devices this will also be the state of the first touch.

right

The right mouse button. Only available on the mouse pointer.

middle

The middle mouse button. Only available on the mouse pointer.

primary

The primary controller button. Only available on the left and right pointers.

squeeze

The squeeze controller button. Only available on the left and right pointers.

Any Key

The button for the given key. Only available on the keyboard.

0

The first touch. Only available on the touchscreen.

1

The second touch. Only available on the touchscreen.

2

The third touch. Only available on the touchscreen.

3

The fourth touch. Only available on the touchscreen.

5

The fifth touch. Only available on the touchscreen.

Examples:

  1. Send a toast if the left mouse button is clicked.
const state = os.getInputState("mousePointer", "left");
if (state) {
os.toast("Left mouse button is down!");
}
  1. Send a toast if the shift key is down.
const state = os.getInputState("keyboard", "Shift");
if (state) {
os.toast("Shift is down!");
}

os.getInputList()

Gets the list of supported inputs. The returned strings can be used for the controller property in os.getInputState(controller, button) calls.

Examples:

  1. Get a list of inputs and toast them.
const state = os.getInputList();
os.toast(state);

os.goToDimension(dimension)

Loads the given dimension into the #gridPortal portal. Triggers the @onPortalChanged shout for the gridPortal.

The first parameter is the dimension that should be loaded.

Examples:

  1. Load the abc dimension.
os.goToDimension('abc');

os.goToURL(url)

Redirects the current tab to the given URL. Useful for sending the player to another webpage or ambient experience.

The first parameter is the URL that the player should be sent to. Usually this is a website like https://example.com.

Examples:

  1. Send the player to https://example.com.
os.goToURL("https://example.com");

os.openURL(url)

Opens a new tab with the given URL. Useful for opening another webpage without redirecting the current tab.

The first parameter is the URL that should be loaded. Usually this is a website like https://example.com.

Examples:

  1. Open https://example.com in a new tab.
os.openURL("https://example.com");

os.openDevConsole()

Opens the developer console which contains a list of errors that scripts have issued.

Examples:

  1. Open the developer console.
os.openDevConsole();

os.playSound(url)

Loads and plays the audio (MP3, WAV, etc.) from the given URL.

Returns a promise that resolves with the ID of the sound when the sound starts playing. The sound ID can then be used with os.cancelSound(soundID) to stop the sound.

The first parameter is the URL of the audio/music/sound clip that should be played.

Examples:

  1. Play a MP3 file from another website.
os.playSound("https://www.testsounds.com/track06.mp3");

os.bufferSound(url)

Loads the audio from the given URL without playing it. Returns a promise that resolves once the sound has been loaded.

This is useful for pre-loading a sound so that there will be no delay when playing it with os.playSound(url).

The first parameter is the URL of the audio/music/sound clip that should be loaded.

Examples:

  1. Pre-load a MP3 fiel from another website.
os.bufferSound("https://www.testsounds.com/track06.mp3");

os.cancelSound(soundID)

Cancels the sound with the given ID. Returns a promise that resolves once the sound has been canceled.

The first parameter is the ID of the sound that was returned from os.playSound(url).

Examples:

  1. Cancel a sound that is playing.
const id = await os.playSound("https://www.testsounds.com/track06.mp3");
os.cancelSound(id);

os.isInDimension(dimension)

Gets whether the given dimension is loaded into the #gridPortal portal.

The first parameter is the dimension to check for.

Examples:

  1. Show a toast if the player is viewing the abc dimension.
if (os.isInDimension("abc")) {
os.toast("In the dimension!");
}

os.inSheet()

Gets whether the player is in the sheet dimension.

Examples:

  1. Show a toast if the player is viewing the sheet.
if (os.inSheet()) {
os.toast("You are in the sheet!");
}

os.importAUX(urlOrJSON)

Imports an AUX file from the given string.

If the string contains JSON, then the JSON will be imported as if it was a .aux file. If the string is a URL, then it will be downloaded and imported.

This is useful to quickly download a AUX file and load it into the current inst from a site such as https://gist.github.com/.

The first parameter is the JSON or URL that the AUX file should be imported from.

Examples:

  1. Import an AUX file from a file.
const path = '/drives/myFile.aux';
os.importAUX(path);
  1. Import an AUX file from JSON.
os.importAUX(`{
"version": 1,
"state": {
"079847e4-6a58-423d-9a86-8d4ef8be5970": {
"id": "079847e4-6a58-423d-9a86-8d4ef8be5970",
"tags": {
"color": "red"
}
}
}
}`);

os.parseBotsFromData(data)

Parses a list of bot mods from the given string of data. The data can be JSON or the contents of a PDF file. Returns an array of mods where each mod has the structure of a bot (i.e. it has id and tags properties). Returns null if the data is not valid JSON or PDF.

The first parameter is the string of JSON data or the contents of the PDF file that should parsed.

Parse the list of bots in an @onFileUpload
let bots = os.parseBotsFromData(that.file.data);

os.version()

Gets information about the version of CasualOS.

The returned value is an object with the following properties:

const returned: {
/**
* The commit of the hash that AUX was built from.
*/
hash: string;

/**
* The full version number.
*/
version: string;

/**
* The major portion of the version.
*/
major: number;

/**
* The minor portion of the version.
*/
minor: number;

/**
* The patch portion of the version.
*/
patch: number;

/**
* Whether this version is an alpha (i.e. test) version.
*/
alpha: boolean | number;

/**
* Gets the player mode of this CasualOS version.
*
* - "player" indicates that the instance has been configured for experiencing AUXes.
* - "builder" indicates that the instance has been configured for building AUXes.
*/
playerMode: 'player' | 'builder';
};

Examples:

  1. Get the current version and popup a message with it.
const info = os.version();
os.toast(info.version);
  1. Check whether the current inst is for playing AUXes.
const info = os.version();
const isPlayer = info.playerMode === "player";
os.toast('Is Player: ' + isPlayer);

os.device()

Gets information about the device that the player is using.

The returned value is an object with the following properties:

const returned: {
supportsAR: boolean;
supportsVR: boolean;
isCollaborative: boolean;
};

Examples:

  1. Get the device info and popup a message with it.
const info = os.device();
os.toast(info);

os.isCollaborative()

Gets whether the current session was loaded with collaborative features enabled.

When true, CasualOS will attempt to sync the shared (including tempShared and remoteTempShared) spaces with other players. When false, CasualOS will treat all the shared spaces like they are all tempLocal.

Examples:

  1. Toast whether the current session is collaborative.
const isCollaborative = os.isCollaborative();

os.toast(isCollaborative ? "We are collaborative!" : "We are not collaborative!");

os.requestFullscreenMode()

Attempts to enter fullscreen mode. Depending on which web browser the player is using, this might ask for permission to go fullscreen.

Note that iPhones currently don't support fullscreen mode.

Examples:

  1. Enter fullscreen mode.
os.requestFullscreenMode();

os.exitFullscreenMode()

Exists fullscreen mode.

Examples:

  1. Exit fullscreen mode.
os.exitFullscreenMode();

os.requestWakeLock()

Requests a wake lock that will keep the device screen awake. This will ask the user for permission to keep the screen awake. Returns a promise that resolves once the wake lock has been granted. If the wake lock is denied, then an error will be thrown.

Useful for a kiosk mode where the screen is always supposed to be on.

Examples:

Request a wake lock from the user.
await os.requestWakeLock();

os.disableWakeLock()

Disables the wake lock that was previously enabled. Returns a promise that resolves once the wake lock has been disabled.

Examples:

Disable the wake lock
await os.disableWakeLock();

os.getWakeLockConfiguration()

Retrieves the current wake lock state. Returns a promise that resolves with an object that contains the following properties:

let configuration: {
/**
* Whether the wake lock is enabled.
*/
enabled: boolean;
};

Examples:

Get the current wake lock state
const configuration = await os.getWakeLockConfiguration();

if (configuration.enabled) {
os.toast('Wake lock is enabled!');
} else {
os.toast('Wake lock is disabled.');
}

os.setupInst(inst, botOrMod?)

Sends an action to the server that will create the given inst if it does not exist and places a clone of the given bot or mod in it. The new bot will only be added to the inst if the inst did not exist. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when the inst has been setup.

The first parameter is the ID of the inst that should be setup.

The second parameter is optional and is the bot or mod that should be cloned into the new inst. After the bot is created, @onCreate will be triggered.

Examples:

Before os.setupInst() will work, you need to setup the @onAnyAction tag to execute events from remote devices. This is because when you run os.setupInst() from a PC or phone (a.k.a. A "remote device"), it needs to send an event to the server to actually create the new inst. By default, AUX does not perform actions that are received from a remote device. You must instruct AUX to execute these yourself.

Ensure that @onAnyAction is setup properly. The following script will execute setup_server events that were sent from other devices:

// Device actions are actions that were sent to this computer from another device
if (that.action.type === 'device') {

// The setup_server action is the action that is created
// from os.setupInst()
if (that.action.event.type === 'setup_server') {

// Execute the setup_server action
action.perform(that.action.event);
}
}
  1. Create the "test" inst:
await os.setupInst("test");
  1. Create the "test" inst with a bot inside it:
await os.setupInst("test", {
"name": "bob",
"color": "red"
});
  1. Create the "test" inst with a bot that places a bot in the "abc" dimension:
await os.setupInst("test", {
"onCreate": `@
create({
creator: null,
label: "This is in the dimension!",
color: "blue",
abc: true
});

destroy(this);
`
});

os.remoteCount(inst?)

Gets the number of remotes that are viewing the current inst. Optionally takes a parameter which is the inst that the number of remotes should be retrieved for. If omitted, then the current inst will be checked. Returns a promise that resolves with the number of active remotes.

The first parameter is optional and is the name of the inst that the number of remotes should be retrieved for. If not specified, then the current inst current inst will be used.

Examples

  1. Get the number of remotes in the current inst.
const numberOfRemotes = await os.remoteCount();

os.toast("Number of Remotes: " + numberOfRemotes);
  1. Get the number of remotes in the test inst.
const numberOfRemotes = await os.remoteCount('test');

os.toast("Number of Remotes: " + numberOfRemotes);

os.totalRemoteCount()

Gets the number of devices that are connected to the server. Returns a promise that resolves with the number of active devices.

Examples

  1. Get the number of devices on the server.
const numberOfDevices = await os.totalRemoteCount();

os.toast("Number of Devices: " + numberOfDevices);

os.instances()

Gets the list of instances that are stored on the server. Returns a promise that resolves with the list of inst names.

Examples

  1. Get the list of instances on the server.
const instances = await os.instances();

os.toast("Instances " + instances.join(','));

os.instStatuses()

Gets the list of instances that are stored on the server along with the last time that they were updated. Returns a promise that resolves with the list of instances.

The resolved list is sorted by the most recently updated first and the least recently updated last.

Examples

  1. Get the list of instances on the server along with their status.
const instances = await os.instStatuses();

os.toast("Instances " + getJSON(instances));

os.remotes()

Gets the list of remote IDs that are connected to the current inst. Returns a promise that resolves with the list of remote IDs.

The resolved list will always have at least one value that represents the current remote.

Examples

  1. Get the list of remote IDs.
const remotes = await os.remotes();

os.toast("Remotes " + remotes.join(','));

os.listInstUpdates()

Gets the list of updates that have occurred in the shared space. Returns a promise that resolves with the list of updates.

Useful when combined with os.getInstStateFromUpdates(updates) to track the history of an inst over time.

Examples

Get a list of updates to shared space
const updates = await os.listInstUpdates();

os.getInstStateFromUpdates(updates)

Calculates the inst state from the given list of updates. Returns a promise that resolves with the bot state that the updates produce.

Useful for tracking the history of an inst over time.

Examples

Get the last 5 inst states in the shared space
const updates = await os.listInstUpdates();

let states = [];
for(let i = 5; i >= 0; i--) {
const state = await os.getInstStateFromUpdates(updates.slice(0, updates.length - i));
states.push(state);
}

console.log('States: ', states);
Calculate the last deltas from shared space updates
const updates = await os.listInstUpdates();

let lastState;
let deltas = [];
for(let i = 5; i >= 0; i--) {
const state = await os.getInstStateFromUpdates(updates.slice(0, updates.length - i));

if (lastState) {
const delta = diffSnapshots(lastState, state);
deltas.push(delta);
}

lastState = state;
}
console.log('Deltas: ', deltas);

os.getCurrentInstUpdate()

Retrieves an inst update that represents the current local shared state of the inst. Returns a promise that resolves with the update.

Note that the inst update only contains bots and tag masks from the shared space. Useful for saving the current shared state of the inst so that it can be restored later or transferred to another inst.

Unlike os.createInitializationUpdate(bots), this function creates an update that is linked to this inst. This means that applying the update to the inst it was created in will not create duplicate bots. It is still possible to apply the update to other insts, but it may create duplicate bots depending on the history of the other inst.

Examples

Save the current inst state to a local bot
const update = await os.getCurrentInstUpdate();
create({
space: 'local',
backup: true,
timestamp: update.timestamp,
update: update
});
Restore from a local bot
const savedUpdates = getBots(bySpace('local'), byTag('backup', true));
savedUpdates.sort((a, b) => b.timestamp - a.timestamp);

if (savedUpdates.length > 0) {
const update = savedUpdates[0].tags.update;
await os.applyUpdatesToInst([update]);
os.toast("Restored!");
}

os.createInitializationUpdate(bots)

Creates an inst update that, when applied, ensures the given bots are created on this inst. Returns a promise that resolves with the inst update.

Note that you can apply the same update multiple times and you will end up with only one version of the bots saved in the update. Additionally, future changes to the bots will be preserved even if the update is applied again.

This feature makes inst updates useful when you want to ensure that an experience starts in an initial state but also able to change over time.

Unlike os.getCurrentInstUpdate(), this function creates an update that is not linked to this inst. This means that applying the update to the inst it was created in will create duplicate bots.

The first parameter is the list of bots that should be included in the update.

Examples

Create an update with this bot and save it to a tag
const update = await os.createInitializationUpdate([thisBot]);
tags.savedUpdate = update;
Create an update with all the bots in the home dimension
const update = await os.createInitializationUpdate(getBots(inDimension('home')));
tags.savedUpdate = update;

os.applyUpdatesToInst(updates)

Applies the given updates to the current inst. Returns a promise that resolves once the updates have been applied.

Note that you can call this function with the same update multiple times and you will end up with only one version of the bots saved in the update. Additionally, future changes to the bots will be preserved even if the update is applied again.

This feature makes inst updates useful when you want to ensure that an experience starts in an initial state but also able to change over time.

The first parameter is the list of updates that should be applied to this inst.

Examples

Apply an update that was saved to a tag
await os.applyUpdatesToInst([ tags.savedUpdate ]);

os.mergeInstUpdates(updates)

Merges the given updates into a single update. Returns the merged update.

This function is useful for compressing a list of updates into a single update that can be applied to an inst.

The first parameter is the list of updates that should be merged.

Examples

Merge a list of updates
const merged = os.mergeInstUpdates(updates);

os.beginAudioRecording(options?)

Starts a new audio recording. Returns a promise that resolves when recording has started. The returned promise will throw an error if recording could not be started. Reasons for this include insufficient permissions and not having a microphone.

The first parameter is optional and is an object that determines how the audio should be recorded. It has the following structure:

let options: {
/**
* Whether to stream the audio recording.
* If streaming is enabled, then @onAudioChunk will be triggered whenever a new
* piece of audio is available.
*/
stream?: boolean;

/**
* The MIME type that should be produced. If the given MIME type is not supported, then the default will be used.
* Defaults to a containerized format (audio/mp3, audio/webm, etc.) if not specified.
*/
mimeType?: string;

/**
* The number of samples per second (Hz) that audio/x-raw recordings should use.
* Defaults to 44100 if not specified.
*/
sampleRate?: number;
};

Triggers @onBeginAudioRecording once recording has started and continuously triggers @onAudioChunk if stream is set to true.

Examples:

  1. Record some audio for 10 seconds and download the file.
await os.beginAudioRecording();
await os.sleep(10000);
const data = await os.endAudioRecording();

os.download(data);
  1. Stream some raw audio data for 10 seconds.
await os.beginAudioRecording({
stream: true,
mimeType: 'audio/x-raw'
});
// @onAudioChunk will be called whenever a new sample is available.
await os.sleep(10000);
await os.endAudioRecording();

os.endAudioRecording()

Stops the audio recording that is in progress. Returns a promise that resolves with the recorded data. If the recording was started with stream: true, then the recorded data will be null.

Triggers @onEndAudioRecording once recording has finished.

Examples:

  1. Record some audio for 10 seconds and download the file.
await os.beginAudioRecording();
await os.sleep(10000);
const data = await os.endAudioRecording();

os.download(data);

os.meetCommand(command, ...args)

Send a command to the Jitsi Meet API. The commands are only valid if the meet portal is fully loaded (see @onMeetLoaded).

A full list of commands can be be found here in the Jitsi Meet Handbook

Examples:

  1. Change user's meet display name
os.meetCommand('displayName', 'ABC123');
  1. Close the meet.
os.meetCommand('hangup')

os.meetFunction(functionName, ...args)

Executes the given function on the Jitsi Meet API and returns a promise that resolves with the result. The functions are only valid if the meet portal is fully loaded (see @onMeetLoaded).

A full list of functions can be found here in the Jitsi Meet Handbook.

Examples:

Get a list of all the participants.
const participants = await os.meetFunction('getParticipantsInfo')
Get a list of available breakout rooms.
const rooms = await os.meetFunction('listBreakoutRooms');

Form Animation Actions

os.startFormAnimation(botOrBots, nameOrIndex, options?)

Starts the given animation on the given bot or list of bots using the given options. Returns a promise that resolves once the animation(s) have been started.

Triggers the @onFormAnimationStarted and @onAnyFormAnimationStarted listeners once the animation has started.

The first parameter is the bot or list of bots that the animation should be started on.

The second parameter is the name of the animation that should be started. Additionally, it can be the index number of the animation that should be played.

The third paramter is optional and are the options that should be used to play the animation. If provided, it should be an object with the following properties:

let options: {
/**
* The Unix time in miliseconds that the animation should start at.
*/
startTime?: number;

/**
* The time within the animation clip that the animation should start at in miliseconds.
*/
initialTime?: number;

/**
* The rate at which the animation plays.
* 1 means the animation plays normally.
* 2 means the animation plays 2x as quickly.
* 0 means that the animation is paused.
*/
timeScale?: number;

/**
* The options for looping the animation.
* If omitted, then the animation will play once and finish.
*/
loop?: {
/**
* The looping mode that should be used.
*/
mode: 'repeat' | 'pingPong';

/**
* The number of times that the animation should repeat for.
*/
count: number;
};

/**
* Whether the final animation values should be preserved when the animation finishes.
*/
clampWhenFinished?: boolean;

/**
* The number of miliseconds that the animation should take to cross fade from the previous animation.
* If null, then this animation takes over immediately. Additionally, if no previous animation was playing then this animation takes over immediately.
*/
crossFadeDuration?: number;

/**
* Whether to warp animation values during a cross fade.
*/
crossFadeWarp?: boolean;

/**
* The number of miliseconds that the animation should take to fade in.
* If null, then the animation will not fade in.
*/
fadeDuration?: number;

/**
* The address that the animations should be loaded from.
*/
animationAddress?: string;
}

Examples

Start the "Run" animation on this bot
await os.startFormAnimation(thisBot, "Run");
Start the "Run" animation on every bot in the home dimension
await os.startFormAnimation(getBots(inDimension("home")), "Run");
Start an animation that loops 5 times
await os.startFormAnimation(thisBot, "Run", {
loop: {
mode: 'repeat',
count: 5
}
});
Start an animation which starts playing 5 seconds in the future
await os.startFormAnimation(thisBot, "Run", {
startTime: os.localTime + 5000
});
Start an animation which plays at half its normal speed
await os.startFormAnimation(thisBot, "Run", {
timeScale: 0.5
});

os.stopFormAnimation(botOrBots, options?)

Stops the animations that are running on the given bot or list of bots using the given options. Returns a promise that resolves once the animations have been stopped.

This function only works for animations that have been started by os.startFormAnimation(botOrBots, nameOrIndex, options?).

Triggers the @onFormAnimationStopped and @onAnyFormAnimationStopped listeners once the animation has stopped.

The first parameter is the bot or list of bots whose animations should be stopped.

The second parameter is optional and are the options that should be used for stopping the animations. It should be an object with the following properties:

let options: {
/**
* The Unix time in miliseconds that the animation should be stopped at.
*/
stopTime?: number;

/**
* The number of miliseconds that the animation should take to fade out.
* If null, then the animation will stop immediately.
*/
fadeDuration?: number;
};

Examples

Stop the animations on this bot
await os.stopFormAnimation(thisBot);
Slowly stop the animations on this bot
await os.stopFormAnimation(thisBot, {
fadeDuration: 1000 // Take 1 second to stop the animation
});
Stop the current animation 5 seconds in the future
await os.stopFormAnimation(thisBot, {
stopTime: os.localTime + 5000
});

os.listFormAnimations(botOrAddress)

Retrieves the list of animations that are available on the given bot or GLTF mesh address. Returns a promise that resolves with a list of objects with the following form:

let animation: {
/**
* The name of the animation.
*/
name: string;

/**
* The index that the animation is at.
*/
index: number;

/**
* The duration of the animation in miliseconds.
*/
duration: number;
};

The first parameter is the bot or address that the animation list should be retrieved from.

Examples

Get the list of animations on this bot
const animations = await os.listFormAnimations(thisBot);
Get the list of animations for a specific address
const animations = await os.listFormAnimations('https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/Fox/glTF/Fox.gltf');

os.bufferFormAddressGLTF(address)

Pre-caches the given GLTF mesh address so that it will load instantly when used on a bot later. Returns a promise that resolves once the address has been cached.

The first parameter is a string and is the address that should be cached.

Examples

Buffer a specific GLTF
await os.bufferFormAddressGLTF('https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/Fox/glTF/Fox.gltf');
os.toast("Buffered!");

Room Actions

Room actions are actions that make it easy to create your own custom multimedia chat rooms. These rooms work like Zoom or Google Meet, and allow users to share their camera and microphone with each other.

However, unlike Zoom or Google Meet, Rooms give you a set of actions and listeners that can be used to setup and control your own multimedia chat sessions.

Note that these rooms are unrelated to the meetPortal. The meetPortal is a preconfigured user interface that can be used to setup multimedia chat rooms, but is somewhat limited in its configurablilty. Rooms are much more flexible, but also require slightly more work to use.

os.joinRoom(roomName, options?)

Attempts to join the given meeting room using the given options. Returns a promise that resolves with an object that indicates whether the operation was successful.

Triggers the @onRoomJoined listener once the room has been successfully joined.

Additionally, the following listeners will be triggered when the relevent events occur in the chat room:

The first parameter is the name of the room that should be joined. Any valid string can be used as a room name. Additionally, rooms are shared across instances.

The second parameter is optional and is the object that contains the additional parameters for joining the room. It is an object with the following structure:

let options: {
/**
* Whether to stream video.
* Defaults to true.
*/
video?: boolean;

/**
* Whether to stream audio.
* Defaults to true.
*/
audio?: boolean;

/**
* Whether to stream the screen.
* Defaults to false.
*/
screen?: boolean;

/**
* The HTTP endpoint of the records website that should host the meeting.
* If omitted, then the preconfigured records endpoint will be used.
*/
endpoint?: string;

/**
* The defaults that should be used for recording audio.
* Should be an object.
* See https://docs.livekit.io/client-sdk-js/interfaces/AudioCaptureOptions.html for a full list of properties.
*/
audioCaptureDefaults?: object;

/**
* The defaults that should be used for recording video. Should be an object.
* See https://docs.livekit.io/client-sdk-js/interfaces/VideoCaptureOptions.html for a full list of properties.
*/
videoCaptureDefaults?: object;

/**
* The defaults that should be used for uploading audio/video content.
* See https://docs.livekit.io/client-sdk-js/interfaces/TrackPublishDefaults.html for a full list of properties.
*/
publishDefaults?: object;

/**
* Whether to enable dynacast.
* See https://docs.livekit.io/client-sdk-js/interfaces/RoomOptions.html#dynacast for more info.
*/
dynacast?: boolean;

/**
* Whether to enable adaptive streaming. Alternatively accepts an object with properties from this page: https://docs.livekit.io/client-sdk-js/modules.html#AdaptiveStreamSettings
*/
adaptiveStream?: boolean | object;
};

Examples

Join the "myChat" room
const result = await os.joinRoom("myChat");
if (result.success) {
os.toast("Joined the room!");
} else {
os.toast("Failed to join the room: " + result.errorMessage);
}
Join a room with the video stream disabled
const result = await os.joinRoom("myChat", {
video: false
});
if (result.success) {
os.toast("Joined the room!");
} else {
os.toast("Failed to join the room: " + result.errorMessage);
}

os.leaveRoom(roomName, options?)

Attempts to exit the given room using the given options. Returns a promise that resolves with an object which indicates whether the operation was successful.

Triggers the @onRoomLeave listener once the room has been left.

The first parameter is the name of the room that should be exited.

The second parameter is optional and is the object that contains the additional parameters for leaving the room. It is an object with the following structure:

let options: {
/**
* The HTTP endpoint of the records website that should host the meeting.
* If omitted, then the preconfigured records endpoint will be used.
*/
endpoint?: string;
};

Examples

Leave the "myChat" room
const result = await os.leaveRoom("myChat");
if (result.success) {
os.toast("Left the room!");
} else {
os.toast("Failed to leave the room: " + result.errorMessage);
}

os.setRoomOptions(roomName, options)

Attempts to set the options for the given chat room. Useful for enabling/disabling video, audio, and screensharing. Returns a promise that resolves with an object indicating if the operation was successful and what the current state of the room is.

Triggers the @onRoomOptionsChanged and @onRoomTrackSubscribed/@onRoomTrackUnsubscribed listeners as needed for the specified changes.

The first parameter is the name of the room that the options should be changed in.

The second parameter is the object that contains the room parameters that should be changed. It has the following structure:

let options: {
/**
* Whether to stream video from the camera.
* If omitted, then the video will not be changed.
*/
video?: boolean;

/**
* Whether to stream audio from the microphone.
* If omitted, then the audio will not be changed.
*/
audio?: boolean;

/**
* Whether to stream the screen.
* If omitted, then the screen will not be changed.
*/
screen?: boolean;
};

Examples

Start screensharing
const result = await os.setRoomOptions("myChat", {
screen: true
});
if (result.success) {
os.toast("Screensharing started!");
} else {
os.toast("Failed to start screensharing: " + result.errorMessage);
}
Mute the microphone
const result = await os.setRoomOptions("myChat", {
audio: false
});
if (result.success) {
os.toast("Microphone muted!");
} else {
os.toast("Failed to mute microphone: " + result.errorMessage);
}

os.getRoomOptions(roomName)

Attempts to get the current options for the given chat room. Useful for determining the current state of the local video (camera), audio (microphone), and screen streams. Returns a promise that resolves with an object that contains the information.

The first parameter is the name of the room that the options should be retrieved for.

Examples

Get the current options for a room
const result = await os.getRoomOptions("myChat");
if (result.success) {
os.toast("Room options: " + JSON.stringify(result.options));
} else {
os.toast("Failed to get the options: " + result.errorMessage);
}

os.setRoomTrackOptions(roomName, trackAddress, options)

Attempts to set the current options for the specified audio/video track in the specified room. Returns a promise that resolves with an object that indicates whether the operation was successful.

This function is useful for locally muting a track or setting the video quality you want it to stream at.

The first parameter is the name of the room.

The second parameter is the address of the audio/video track. Track addresses can be obtained via the @onRoomTrackSubscribed listener.

The third parameter is the options that should be set for the track. It should be an object with the following structure:

let options: {
/**
* Whether to mute the track locally.
* This will prevent the track from streaming from the server to this device.
* If omitted, then the track will remain in its current state.
*/
muted?: boolean;

/**
* The video quality that the track should stream at.
* Only applicable for video tracks.
* If omitted, then the current video quality will be used.
*/
videoQuality?: 'high' | 'medium' | 'low' | 'off';
};

Examples

Stop streaming a track
const result = await os.setRoomTrackOptions("myChat", "myTrack", {
muted: true
});
if (result.success) {
os.toast("Track muted!");
} else {
os.toast("Failed to mute the track: " + result.errorMessage);
}
Set the video quality on a track
const result = await os.setRoomTrackOptions("myChat", "myTrack", {
videoQuality: 'low'
});
if (result.success) {
os.toast("Track video quality changed!");
} else {
os.toast("Failed to set video quality on the track: " + result.errorMessage);
}

os.getRoomTrackOptions(roomName, trackAddress)

Attempts to get the current options for the specified audio/video track in the specified room. Returns a promise that resolves with an object that contains the information. This function is useful for getting basic information about a track, like the video aspect ratio or if it is sourced from a camera or the screen.

The first parameter is the name of the room.

The second parameter is the address of the audio/video track. Track addresses can be obtained via the @onRoomTrackSubscribed listener.

Examples

Get the options for a track
const result = await os.getRoomTrackOptions("myChat", "myTrack");
if (result.success) {
os.toast("Track options: " + JSON.stringify(result.options));
} else {
os.toast("Failed to get the options: " + result.errorMessage);
}

os.getRoomRemoteOptions(roomName, remoteId)

Attempts to get the current options for the specified remote user in the specified room. Returns a promise that resolves with an object that contains information about the remote user.

This function is useful for determining if the user is streaming audio or video and how good their network connection is.

The first parameter is the name of the room.

The second parameter is the ID of the remote user whose options should be retrieved. Remote IDs can be obtained via the @onRoomRemoteJoined listener.

Examples

const result = await os.getRoomRemoteOptions("myChat", "myRemote");
if (result.success) {
os.toast("Remote options: " + JSON.stringify(result.options));
} else {
os.toast("Failed to get the options: " + result.errorMessage);
}

Debug Actions

Debug actions are actions that are either useful for automated testing/debugging or only available when run inside a debugger.

os.createDebugger(options?)

Creates a debug environment that can be used to simulate bots in isolation from the rest of the inst. Returns a promise that resolves with an object that contains all of the action functions.

One of the special things about debug environments is that the bots in the environment are totally isolated from regular bots. This means that functions like getBots(..filters) can only access bots that have been created in the debugger and actions like os.toast(message, duration?) don't do anything automatically. This can be useful for automated testing where you want to see what some bots will do without actually letting them do anything.

Additionally, debuggers can be configured to be pausable. This allows you to set pause triggers (also known as breakpoints) that temporarily stop the debugger at a specific location in a listener and allows you to inspect the current state of the script. Pausable debuggers work like normal debuggers, except that some specific functions return promises instead of a result. This is because those functions can trigger user code that could trigger a pause. When this is possible, the debugger returns a promise to your host code so you can properly handle the pause. (See the examples below for more information)

The returned object can be used to create/find bots in the debug environment and simulate interactions. The debug environment also contains several functions that make it easy to observe what has happened inside the environment and therefore determine if everything was performed correctly.

The first parameter is optional and is the options that should be used to configure the debugger. It is an object and should have the following structure:

let options: {
/**
* Whether to use real UUIDs for Bot IDs and the uuid() function.
* If set to false, then UUIDs will be predictable starting with "uuid-1" and continuing up ("uuid-2", "uuid-3", etc.).
* If set to true, then UUIDs will be unpredictable and unique.
* Defaults to false.
*/
useRealUUIDs?: boolean;

/**
* Whether to allow scripts to be asynchronous.
* If false, then all scripts will be forced to be synchronous.
* Defaults to true.
* Synchronous scripts are easier to test because they don't rely on back-and-forth (two-way) communication to handle things like web.hook().
*/
allowAsynchronousScripts: boolean;

/**
* The data that the configBot should be created from.
* Can be a mod or another bot.
*/
configBot: Bot | BotTags;

/**
* Whether the debugger is pausable.
* Pausable debuggers allow you to set pause triggers that temporarily stop the debugger at a specific point in a script
* and allow you to inspect the current execution state of the script.
*/
pausable?: boolean;
};

Examples:

Create a pausable debugger
const debug = await os.createDebugger({
pausable: true
});

// Register a listener that gets called whenever a pause happens in this debugger.
debug.onPause(pause => {
// Get the current stack frame from the pause
const currentFrame = pause.callStack[pause.callStack.length - 1];

// Set the abc variable to 999
currentFrame.setVariableValue('abc', 999);

// Resume execution after the pause.
debug.resume(pause);
});

// Because the debugger is pausable, the create() function returns a promise
// because it calls @onCreate which could cause a pause trigger to be hit.
const debuggerBot = await debug.create({
test: '@let abc = 123; os.toast(abc);'
});

// Set a pause trigger in the "test" script of the bot we just created
// at line 1 column 16
const trigger = debug.setPauseTrigger(debuggerBot, 'test', {
lineNumber: 1,
columnNumber: 16
});

// Send a shout. Just like the create() function above, we recieve a promise that we can await.
await debug.shout('test');

// Get the resulting actions from the debugger
// and perform the first one. This should be the os.toast(), but instead of printing 123,
// it should print 999 because we changed the value of abc during the debugger pause.
const actions = debug.getCommonActions();
action.perform(actions[0]);
Create a normal debugger and copy this bot into it.
// Note: variables cannot be named "debugger" so we use the name "debug" instead.
const debug = await os.createDebugger();
const debuggerBot = debug.create(thisBot);
Test a script in the debugger
const debug = await os.createDebugger();
const debuggerBot = debug.create({
test: '@tags.hit = true;'
});
debug.shout('test');

if (debuggerBot.tags.hit) {
os.toast('Success!');
} else {
os.toast('Failed!');
}
Find out what actions a script performs
const debug = await os.createDebugger();
const debuggerBot = debug.create({
test: '@os.toast("hello!")'
});
debug.shout('test');

const actions = debug.getCommonActions();
os.toast(actions);
Create a debugger with a custom configBot
const debug = await os.createDebugger({
configBot: {
test: '@console.log("Hello, World!");'
}
});
debug.shout('test');
Mask the web.get() function.
const debug = await os.createDebugger();
let url = "https://upload.wikimedia.org/wikipedia/commons/thumb/9/90/The_star_formation_region_Messier_17.jpg/1200px-The_star_formation_region_Messier_17.jpg";
const debuggerBot = debug.create({
url,
test: '@return await web.get(tags.url)'
});

debug.web.get.mask(url)
.returns({
data: 'test data',
status: 200
});

const [result] = debug.shout('test');

assertEqual(result, {
data: 'test data',
status: 200
});
os.toast("Success!");

os.getExecutingDebugger()

Gets the debugger that is currently executing the script. Returns null if the script is not running in a debugger.

Examples:

Get the debugger that this script is running in
const debug = os.getExecutingDebugger();
console.log(debug);

os.attachDebugger(debug, options?)

Attaches the given debugger to the CasualOS frontend. This causes the given debugger to be treated like another inst that has been loaded simultaneously with the current inst. This feature makes it useful for inspecting the bots in a debugger or even for setting up a sandbox that you control.

Note that because debuggers are entirely separate environments, the debugger gets its own configBot and portal bots. This means that in order for bots to show up in the portals, you need to set the corresponding portal on the debugger's configBot. For portals that are stored in the URL (like the gridPortal), this is done automatically. But for other portals (like the miniGridPortal or the wrist portals), you need to manage this manually.

Returns a promise that resolves when the debugger has been attached.

The first parameter is the debugger that you want to be attached to the runtime.

The second paramter is optional and are the options that should be used to attach the debugger. It should be an object with the following structure:

let options: {
/**
* Gets the tag name mapper that should be used.
* This is useful for ensuring that the debugger objects utilize different tag names for the front end.
*/
tagNameMapper?: TagMapper;
}

/**
* Defines an interface for a tag mapper.
*/
export interface TagMapper {
/**
* Maps a tag name from its internal name to the name that should be used by the frontend.
*/
forward: (name: string) => string;

/**
* Maps a tag name from its frontend name to the name that is used internally.
*/
reverse: (name: string) => string;
}

Examples:

Create and attach a debugger
const debug = await os.createDebugger();

// Create a bot in the debugger.
debug.create({
home: true
label: 'Test'
});

// Attach the debugger to CasualOS.
await os.attachDebugger(debug);
Attach a debugger with a tag mapper that renames "home" tags to "testHome"
const debug = await os.createDebugger();

// Create a bot in the debugger.
debug.create({
home: true
label: 'Test'
});

// Attach the debugger to CasualOS.
// Because we're providing a tag mapper, the frontend won't see the "home" tag in debugger bots,
// instead it will see "testHome" tags.
await os.attachDebugger(debug, {
tagNameMapper: {
forward: (tag) => {
if (tag.startsWith('home')) {
return `testHome${tag.slice('home'.length)}`;
}

return tag;
},
reverse: (tag) => {
if (tag.startsWith('testHome')) {
return tag.slice('testHome'.length);
}

return tag;
}
}
});

os.detachDebugger(debug)

Detaches the given debugger from the CasualOS frontend. Returns a promise that resolves when the debugger has been detached.

The first parameter is the debugger that should be detached.

Examples:

Detach a debugger
const debug = await os.createDebugger();

// Create a bot in the debugger.
debug.create({
home: true
label: 'Test'
});

// Attach the debugger to CasualOS.
await os.attachDebugger(debug);

// Wait for 4 seconds
await os.sleep(4000);

await os.detachDebugger(debug);

assert(condition, message?)

Verifies that the given condition is true. If it is not, then an error is thrown with the given message. This function is useful for automated testing since tests should ideally throw an error if the test fails. It can also be useful to make sure that some important code is only run if a precondition is met.

The first paramater is the condition that should be verified.

The second parameter is optional and is the message that should be included in the error.

Examples

Assert that the tag color is "blue"
assert(tags.color === "blue", "The tag color is not blue!");

assertEqual(received, expected)

Verifies that the given values are equal to each other. If they are not, then an error is thrown. This function is useful for automated testing since tests should ideally throw an error if the test fails. It can also be useful to make sure that some important code is only run if a precondition is met.

Examples

Assert that the tag color is "blue"
assertEqual(tags.color, "blue");
Assert that the bot contains some specific tag values
assertEqual(tags, {
color: "blue",
home: true,
homeX: 0,
homeY: 0
});

getAllActions()

Gets the list of action objects that have been performed by bots in the current debugger. Action objects are used by CasualOS to represent changes to bots or external effects that should be performed. Examples of this are create(...mods), os.toast(message, duration?) and os.enableVR().

This function is useful for automated testing because you can use it to validate the actions that a script has performed.

Only available inside a debugger that was created using os.createDebugger(options?).

Examples:

Get the list of bot changes and actions that have been performed in a debugger
const debug = await os.createDebugger();
debug.create({
test: '@os.toast("Hello")'
});
debug.shout("test");

const actions = debug.getAllActions();

assertEqual(actions, [
{
type: 'add_bot',
id: 'uuid-1',
bot: {
id: 'uuid-1',
tags: {
test: '@os.toast("Hello")'
}
}
},
{
type: 'show_toast',
message: 'Hello',
duration: 2000
}
]);

getCommonActions()

Gets the list of common action objects that have been performed by bots in the current debugger. Action objects are used by CasualOS to represent changes to bots or external effects that should be performed. Common actions are actions that do not immediately change bots or bot tags or masks.

Examples of common actions are os.toast(message, duration?) and os.enableVR().

Only available inside a debugger that was created using os.createDebugger(options?).

Examples:

Get the list of actions that have been performed in a debugger
const debug = await os.createDebugger();
debug.create({
test: '@os.toast("Hello")'
});
debug.shout("test");

const actions = debug.getCommonActions();

assertEqual(actions, [
{
type: 'show_toast',
message: 'Hello',
duration: 2000
}
]);

getBotActions()

Gets the list of bot actions that have been performed by bots in the current debugger. Action objects are used by CasualOS to represent changes to bots or external effects that should be performed. Bot actions are actions that immediately change bots or bot tags or masks.

Examples of bot actions are create(...mods), destroy(bot) or setTagMask(bot, tag, value, space?).

Only available inside a debugger that was created using os.createDebugger(options?).

Examples:

Get the list of bot changes that have been performed in a debugger
const debug = await os.createDebugger();
debug.create({
test: '@os.toast("Hello")'
});
debug.shout("test");

const actions = debug.getBotActions();

assertEqual(actions, [
{
type: 'add_bot',
id: 'uuid-1',
bot: {
id: 'uuid-1',
tags: {
test: '@os.toast("Hello")'
}
}
},
]);

getErrors()

Gets the list of errors that have occurred in the current debugger. Errors occur when an exceptional event happens in a script and prevents the rest of the script from executing.

Debuggers capture these errors and let you inspect them afterwards. Only available inside a debugger that was created using os.createDebugger(options?).

Examples:

Get the list of errors that have happened in a debugger
const debug = await os.createDebugger();
debug.create({
test: '@throw new Error("My Error")'
});
debug.shout("test");

const errors = debug.getErrors();

assertEqual(errors.length, 1);
assertEqual(errors[0].error, new Error("My Error"));
assertEqual(errors[0].tag, "test");

onPause(handler)

Registers the given function to be called whenever the debugger is paused by hitting a pause trigger.

The first argument is the function that should be called when the debugger is paused. It is called with a single argument that represents the current paused state of the debugger:

interface DebuggerPause {
/**
* The ID of the pause.
*/
pauseId: string | number;

/**
* The pause trigger that started this pause.
*/
trigger: PauseTrigger;

/**
* The state of the pause.
* Indicates whether the pause is before or after the node was executed.
*/
state: 'before' | 'after';

/**
* The result of the node evaluation.
* Only included for "after" pause states.
*/
result?: any;

/**
* The call stack that the debugger currently has.
*/
callStack: DebuggerCallFrame[];
}

/**
* Defines an interface that contains information about a single call stack frame.
*/
export interface DebuggerCallFrame {
/**
* The location that was last evaluated in this frame.
*/
location: DebuggerFunctionLocation;

/**
* Gets the list of variables that are avaiable from this frame.
*/
listVariables(): DebuggerVariable[];

/**
* Sets the given variable name to the given value.
* @param variableName The name of the variable to set.
* @param value The value to set in the variable.
*/
setVariableValue(variableName: string, value: any): void;
}

/**
* Defines an interface that represents a location in a debugger.
*/
export interface DebuggerFunctionLocation {
/**
* The name of the function.
*/
name?: string;

/**
* The ID of the bot that this function is defined in.
*/
botId?: string;

/**
* The name of the tag that this function is defined in.
*/
tag?: string;

/**
* The line number that this function is defined at.
*/
lineNumber?: number;

/**
* The column number that this function is defined at.
*/
columnNumber?: number;
}

/**
* Defines an interface that represents a debugger variable.
*/
export interface DebuggerVariable {
/**
* The name of the variable.
*/
name: string;

/**
* The value contained by the variable.
*/
value: any;

/**
* The scope that the variable exists in.
*
* "block" indicates that the variable was defined in and exists only in the current block.
* "frame" indicates that the variable was defined in and exists in the current stack frame.
* "closure" indicates that the variable was inherited from a parent stack frame.
*/
scope: 'block' | 'frame' | 'closure';

/**
* Whether the variable value can be overwriten.
*/
writable: boolean;

/**
* Whether this variable has been initialized.
*/
initialized?: boolean;
}

Examples:

Listen for pauses on a debugger
const debug = await os.createDebugger({
pausable: true
});

debug.onPause(pause => {
console.log('pause happened!', pause);
});

setPauseTrigger(botOrIdOrTrigger, tag, options)

Registers or updates a pause trigger with a debugger. Returns the newly created trigger.

Pause triggers can be used to tell the debugger where you want it to temporarily stop execution. You specify the bot, tag, line and column numbers, and the debugger will stop before it executes the code at that location. Additionally, the debugger will call all handlers that have been registered with onPause(handler).

The first parameter is the bot, bot ID, or trigger object that should be registered. If it is a bot or a bot ID, then a tag and options must be specified. If it is a trigger object, then it should have the following properties:

/**
* Defines an interface that represents a pause trigger.
*/
export interface PauseTrigger {
/**
* The line number that the trigger starts at.
* Numbers should be one-based.
*/
lineNumber: number;

/**
* The column number that the trigger starts at.
* Numbers should be one-based, and the @ symbol in listeners is ignored.
*/
columnNumber: number;

/**
* The states that the trigger should use.
* Defaults to ["before"] if not specified.
*/
states?: Breakpoint['states'];

/**
* Whether the trigger is enabled.
* Defaults to true.
*/
enabled?: boolean;

/**
* The ID of the trigger.
*/
triggerId: string;

/**
* The ID of the bot that the trigger is set on.
*/
botId: string;

/**
* The tag that the trigger is set on.
*/
tag: string;
}

The second parameter is the name of the tag that the trigger should be set on. It is ignored if a trigger object is specified for the first parameter.

The third paramter is the options that the trigger should use. It is ignored if a trigger object is specified for the first parameter. It should be an object with the following properties:

export interface PauseTriggerOptions {
/**
* The line number that the trigger starts at.
* Numbers should be one-based.
*/
lineNumber: number;

/**
* The column number that the trigger starts at.
* Numbers should be one-based, and the @ symbol in listeners is ignored.
*/
columnNumber: number;

/**
* The states that the trigger should use.
* Defaults to ["before"] if not specified.
*/
states?: Breakpoint['states'];

/**
* Whether the trigger is enabled.
* Defaults to true.
*/
enabled?: boolean;
}

Examples:

Set a pause trigger on a script
const debug = await os.createDebugger({
pausable: true
});

const b = await debug.create({
test: '@os.toast("Hello, World!")'
});

const trigger = debug.setPauseTrigger(b, 'test', {
lineNumber: 1,
columnNumber: 1
});
Update a pause trigger on a script
const debug = await os.createDebugger({
pausable: true
});

const b = await debug.create({
test: '@os.toast("Hello, World!")'
});

let trigger = debug.setPauseTrigger(b, 'test', {
lineNumber: 1,
columnNumber: 1
});

trigger = debug.setPauseTrigger({
...trigger,
states: ['before', 'after']
});

removePauseTrigger(triggerOrId)

Removes the given trigger from the debugger.

The first parameter is the trigger or the ID of the trigger that should be removed.

Examples:

Remove a pause trigger
const debug = await os.createDebugger({
pausable: true
});

const b = await debug.create({
test: '@os.toast("Hello, World!")'
});

const trigger = debug.setPauseTrigger(b, 'test', {
lineNumber: 1,
columnNumber: 1
});

debug.removePauseTrigger(trigger);

enablePauseTrigger(triggerOrId)

Enables the given pause trigger.

The first parameter is the trigger or ID of the trigger that should be enabled.

Examples:

Enable a pause trigger
const debug = await os.createDebugger({
pausable: true
});

const b = await debug.create({
test: '@os.toast("Hello, World!")'
});

const trigger = debug.setPauseTrigger(b, 'test', {
lineNumber: 1,
columnNumber: 1,
enabled: false
});

debug.enablePauseTrigger(trigger);

disablePauseTrigger(triggerOrId)

Disables the given pause trigger. Disabled pause triggers will continue to be listed with listPauseTriggers(), but will not cause a pause to happen while they are disabled.

The first parameter is the trigger or ID of the trigger that should be disabled.

Examples:

Disable a pause trigger
const debug = await os.createDebugger({
pausable: true
});

const b = await debug.create({
test: '@os.toast("Hello, World!")'
});

const trigger = debug.setPauseTrigger(b, 'test', {
lineNumber: 1,
columnNumber: 1
});

debug.disablePauseTrigger(trigger);

listPauseTriggers()

Gets the list of pause triggers that have been registered with the debugger.

Examples:

List the triggers that are set on this debugger
const debug = await os.createDebugger({
pausable: true
});

const b = await debug.create({
test: '@os.toast("Hello, World!")'
});

const trigger = debug.setPauseTrigger(b, 'test', {
lineNumber: 1,
columnNumber: 1,
enabled: false
});

const triggers = debug.listPauseTriggers();

listCommonPauseTriggers(botOrId, tag)

Gets a list of common trigger locations for the specified tag on the specified bot. Returns an array containing the list of possible pause trigger locations.

Only available inside a debugger that was created using os.createDebugger(options?).

The first parameter is the bot or bot ID that the locations should be listed for.

The second parameter is the name of the tag that the locations should be listed for.

Examples:

List common trigger locations for a script
const debug = await os.createDebugger({
pausable: true
});

const b = await debug.create({
test: '@os.toast("Hello, World!")'
});

const triggerLocations = debug.listCommonPauseTriggers(b, 'test');
Register a trigger from a common location
const debug = await os.createDebugger({
pausable: true
});

const b = await debug.create({
test: '@os.toast("Hello, World!")'
});

const triggerLocations = debug.listCommonPauseTriggers(b, 'test');

const trigger = debug.setPauseTrigger(b, 'test', {
lineNumber: triggerLocations[0].lineNumber,
columnNumber: triggerLocations[0].columnNumber,
states: triggerLocations[0].possibleStates
});

resume(pause)

Resumes the debugger's execution from the given pause.

Only available inside a debugger that was created using os.createDebugger(options?).

The first parameter is the debugger pause that was passed to the handler of onPause(handler).

Examples:

Resume execution on a debugger
const debug = await os.createDebugger({
pausable: true
});

// Register a listener that gets called whenever a pause happens in this debugger.
debug.onPause(pause => {
// Get the current stack frame from the pause
const currentFrame = pause.callStack[pause.callStack.length - 1];

// Set the abc variable to 999
currentFrame.setVariableValue('abc', 999);

// Resume execution after the pause.
debug.resume(pause);
});

// Because the debugger is pausable, the create() function returns a promise
// because it calls @onCreate which could cause a pause trigger to be hit.
const debuggerBot = await debug.create({
test: '@let abc = 123; os.toast(abc);'
});

// Set a pause trigger in the "test" script of the bot we just created
// at line 1 column 16
const trigger = debug.setPauseTrigger(debuggerBot, 'test', {
lineNumber: 1,
columnNumber: 16
});

// Send a shout. Just like the create() function above, we recieve a promise that we can await.
await debug.shout('test');

// Get the resulting actions from the debugger
// and perform the first one. This should be the os.toast(), but instead of printing 123,
// it should print 999 because we changed the value of abc during the debugger pause.
const actions = debug.getCommonActions();
action.perform(actions[0]);

onScriptActionEnqueued(handler)

Registers the given handler function to be called by the debugger whenever a script enqueues an action. This occurrs for common actions like os.toast(message, duration?) and os.showInput(value?, options?).

Every action that is enqueued ends up being performed.

Only available inside a debugger that was created using os.createDebugger(options?).

The first parameter is the function that should be called whenever an action is scheduled to be performed. The first parameter of the function is the action that was enqueued.

Examples:

Listen for actions to be enqueued in a debugger
const debug = await os.createDebugger({
pausable: true
});

// Register a listener that gets called whenever an action is scheduled to be performed.
debug.onScriptActionEnqueued(action => {
console.log('action enqueued', action);
});

// Because the debugger is pausable, the create() function returns a promise
// because it calls @onCreate which could cause a pause trigger to be hit.
const debuggerBot = await debug.create({
test: '@let abc = 123; os.toast(abc);'
});

// Send a shout. Just like the create() function above, we recieve a promise that we can await.
await debug.shout('test');

onAfterScriptUpdatedTag(handler)

Registers the given handler function to be called after any tag is updated in the debugger.

Only available inside a debugger that was created using os.createDebugger(options?).

The first parameter is the function that should be called when a tag is updated. The first parameter of the function is an object that contains information about the update.

Examples:

Listen for tag updates in a debugger
const debug = await os.createDebugger({
pausable: true
});

// Register a listener that gets called whenever a tag is updated.
debug.onAfterScriptUpdatedTag(update => {
console.log('tag updated', update);
});

// Because the debugger is pausable, the create() function returns a promise
// because it calls @onCreate which could cause a pause trigger to be hit.
const debuggerBot = await debug.create({
test: '@tags.message = "hello, world";'
});

// Send a shout. Just like the create() function above, we recieve a promise that we can await.
await debug.shout('test');

onAfterScriptUpdatedTagMask(handler)

Registers the given handler function to be called after any tag mask is updated in the debugger.

Only available inside a debugger that was created using os.createDebugger(options?).

The first parameter is the function that should be called when a tag mask is updated. The first parameter of the function is an object that contains information about the update.

Examples:

Listen for tag updates in a debugger
const debug = await os.createDebugger({
pausable: true
});

// Register a listener that gets called whenever a tag mask is updated.
debug.onAfterScriptUpdatedTagMask(update => {
console.log('tag mask updated', update);
});

// Because the debugger is pausable, the create() function returns a promise
// because it calls @onCreate which could cause a pause trigger to be hit.
const debuggerBot = await debug.create({
test: '@masks.message = "hello, world";'
});

// Send a shout. Just like the create() function above, we recieve a promise that we can await.
await debug.shout('test');

onBeforeUserAction(handler)

Registers the given handler function to be called before a user action is performed in the debugger.

User actions are like normal actions, except they are generated by the CasualOS frontend. Generally, this only happens for built-in shouts and whispers. Additionally, these actions can only be automatically created for debuggers that are attached using os.attachDebugger(debug, options?).

Only available inside a debugger that was created using os.createDebugger(options?).

The first parameter is the function that should be called before a user action is performed. The first parameter of the function is an object that contains the action that will be performed.

Examples:

Listen for tag updates in a debugger
const debug = await os.createDebugger({
pausable: true
});

// Register a listener that gets called whenever a user action is about to be performed.
debug.onBeforeUserAction(update => {
console.log('user action', update);
});

// Because the debugger is pausable, the create() function returns a promise
// because it calls @onCreate which could cause a pause trigger to be hit.
const debuggerBot = await debug.create({
home: true,
});

// Attach the debugger to the front end
await os.attachDebugger(debug);

performUserAction(...actions)

Performs the given actions in order as if they were user actions.

This function works similarly to action.perform(action) except that actions performed with it will also call handlers registered with onBeforeUserAction(handler).

Only available inside a debugger that was created using os.createDebugger(options?).

Each parameter is an action that should be performed.

getCallStack()

Gets the current call stack for the debugger. Call stacks are useful for determining program flow and how scripts interact with each other.

Only available inside a debugger that was created using os.createDebugger(options?). Additionally, this function is only available on pausable debuggers.

Returns an array with the following structure:

let callStack: DebuggerCallFrame[];

/**
* Defines an interface that contains information about a single call stack frame.
*/
interface DebuggerCallFrame {
/**
* The location that was last evaluated in this frame.
*/
location: DebuggerFunctionLocation;

/**
* Gets the list of variables that are avaiable from this frame.
*/
listVariables(): DebuggerVariable[];

/**
* Sets the given variable name to the given value.
* @param variableName The name of the variable to set.
* @param value The value to set in the variable.
*/
setVariableValue(variableName: string, value: any): void;
}

/**
* Defines an interface that represents a location in a debugger.
*/
interface DebuggerFunctionLocation {
/**
* The name of the function.
*/
name?: string;

/**
* The ID of the bot that this function is defined in.
*/
botId?: string;

/**
* The name of the tag that this function is defined in.
*/
tag?: string;

/**
* The line number that this function is defined at.
*/
lineNumber?: number;

/**
* The column number that this function is defined at.
*/
columnNumber?: number;
}

/**
* Defines an interface that represents a debugger variable.
*/
interface DebuggerVariable {
/**
* The name of the variable.
*/
name: string;

/**
* The value contained by the variable.
*/
value: any;

/**
* The scope that the variable exists in.
*
* "block" indicates that the variable was defined in and exists only in the current block.
* "frame" indicates that the variable was defined in and exists in the current stack frame.
* "closure" indicates that the variable was inherited from a parent stack frame.
*/
scope: 'block' | 'frame' | 'closure';

/**
* Whether the variable value can be overwriten.
*/
writable: boolean;

/**
* Whether this variable has been initialized.
*/
initialized?: boolean;
}

Examples:

Get the call stack from a debugger
const debug = os.createDebugger({
pausable: true
});

const callStack = debug.getCallStack();

Math Actions

math.sum(list)

Calculates the numerical sum of the given values.

The first parameter is the list of values that should be summed up. If any value in the list is not a number, it will be converted to one. If the list is not actually a list, then it will be converted to a number and returned.

Examples:

  1. Calculate the sum of a list of numbers.
const total = math.sum([92, 123, 21]);
  1. Calculate the total #age of all the bots.
const totalAge = math.sum(getBotTagValues('#age'));

math.avg(list)

Calculates the arithmetic mean of the given list of values. That is, the sum of the values divided by the number of values.

The first parameter is the list of values that average should be calculated for.

Examples:

  1. Calculate the average of a list of numbers.
const average = math.avg([4, 54.2, 31]);
  1. Calculate the average #age of all the bots.
const averageAge = math.avg(getBotTagValues('#age'));

math.sqrt(value)

Calculates the square root of the given value.

The first parameter is the value that the square root should be calculated for.

Examples:

  1. Calculate the square root of 4.
const rootOf4 = math.sqrt(4);

math.abs(number)

Calculates the absolute value of the given number.

The first parameter is the number that the absolute value should be calculated for.

Examples:

  1. Calculate the absolute value for the number -42.
const _42 = math.abs(-42);

math.stdDev(list)

Calculates the standard deviation for the given list of values.

The first parameter is the list of values that the standard deviation should be calculated for.

Examples:

  1. Calculate the standard deviation of a list of numbers.
const standardDeviation = math.stdDev([2, 97, 745]);
  1. Calculate the standard deviation of the #age of all the bots.
const ageDeviation = math.stdDev(getBotTagValues('#age'));

math.getSeededRandomNumberGenerator(seed?)

Creates a new random number generator from the given seed and returns it. Because of how random number generators work, generators created with the same seed will return the same sequence of random numbers.

The first parameter is optional and is the number or string that should be used as the seed value for the random number generator. If omitted, then a seed will be chosen in a somewhat unpredictable manner.

Returns an object with the following properties:

let result: {
/**
* The seed that was used to create this random number generator.
*/
seed: number | string;

/**
* Generates a random real number between the given minimum and maximum values.
*/
random(min?: number, max?: number): number;

/**
* Generates a random integer between the given minimum and maximum values.
*/
randomInt(min: number, max: number): number;
};

Examples:

Create two random number generators with the same seed.
let random1 = math.getSeededRandomNumberGenerator(123);
let random2 = math.getSeededRandomNumberGenerator(123);

os.toast(random1.randomInt(0, 10) + ' == ' + random2.randomInt(0, 10) + ' == 9');
Create a random number generator and store it for later
let randomNumberGenerator = math.getSeededRandomNumberGenerator(123);

// Store it in the bot variables so it can be used in other scripts.
bot.vars.randomNumberGenerator = randomNumberGenerator;

math.setRandomSeed(seed)

Sets the seed that should be used for the random numbers generated with math.randomInt(min, max) and math.random(min, max).

The first parameter is the number or string that should be used as the seed value for the internal random number generator. If null is provided, then a seed will be chosen in a somewhat unpredictable manner.

Examples:

Set the random seed for math.random() and math.randomInt().
math.setRandomSeed(123);

expect(math.randomInt(0, 10)).toBe(9);
expect(math.random()).toBe(0.36078753814001446);
Clear the random seed.
math.setRandomSeed(null);

math.randomInt(min, max)

Generates a random integer number between the given minimum and maximum values.

The first parameter is the smallest allowed value that can be generated.

The second parameter is the largest allowed value that can be generated.

Examples:

  1. Generate a random number between 5 and 10.
const number = math.randomInt(5, 10);

math.random(min, max)

Generates a random number between the given minimum and maximum values.

The first parameter is the smallest allowed value that can be generated.

The second parameter is the largest allowed value that can be generated.

Examples:

  1. Generate a random number between 0 and Math.PI.
const number = math.random(0, Math.PI);

math.degreesToRadians(degrees)

Converts the given number of degrees to radians and returns the result.

This operation is equivalent to radians = degrees * (Math.PI / 180).

The first parameter is the number of degrees that should be converted to radians.

Examples

Get the number of radians for a 90 degree angle
const radians = math.degreesToRadians(90);

math.radiansToDegrees(radians)

Converts the given number of radians to degrees and returns the result.

This operation is equivalent to degrees = radians * (180 / Math.PI).

The first parameter is the number of radians that should be converted to degrees.

Examples

Get the number of degrees for a Math.PI / 2 angle
const degrees = math.radiansToDegrees(Math.PI / 2);

math.getForwardDirection(rotation)

Gets the forward direction for the given rotation.

Useful for finding where a bot would be pointing if it has a custom rotation.

The first parameter is an object containing the x, y, and z of the rotation in radians.

Examples:

  1. Get the direction that a pointer is pointing.
const pointerRotation = os.getPointerRotation('mouse');
const pointerDirection = math.getForwardDirection(pointerRotation);
os.toast(pointerDirection);

math.intersectPlane(origin, direction, planeNormal?, planeOrigin?)

Calculates the 3D point that a ray starting at the given origin point and traveling in the given direction intersects the grid portal ground plane. Returns null if the ray does not intersect the ground plane.

Useful for calculating where on the ground something is pointing.

The first parameter is the 3D point that the ray should start at.

The second parameter is the direction that the ray is traveling along.

The third parameter is optional and is the normal vector that the plane should use. For 2D planes, the normal vector is the 3D direction that is perpendicular to the the surface of the plane. For example, a plane that covers the entire XY surface has a normal vector equal to ➡️0,0,1, while a plane that covers the YZ surface has a normal vector equal to ➡️1,0,0. This parameter defaults to ➡️0,0,1.

The fourth parameter is optional and is the 3D position that the center of the plane should travel through. Defaults to ➡️0,0,0.

Examples:

  1. Get the spot on the ground that a pointer is pointing at.
const pointerPosition = os.getPointerPosition('mouse');
const pointerRotation = os.getPointerRotation('mouse');
const pointerDirection = math.getForwardDirection(pointerRotation);
const groundPoint = math.intersectPlane(pointerPosition, pointerDirection);
os.toast(groundPoint);

math.getAnchorPointOffset(anchorPoint)

Calculates the 3D position offset for the given anchor point and returns it. This is essentially experiment.getAnchorPointPosition(bot, dimension, anchorPoint) but without the bot's position/scale applied.

The first parameter is the anchor point that should be calculated. Can be any valid #anchorPoint value.

Examples:

  1. Calculate the anchor point offset for "bottom".
const offset = math.getAnchorPointOffset("bottom");
os.toast(offset);

math.addVectors(...vectors)

Mathematically adds the given vectors to each other and returns the sum result.

A vector is a group of numbers which represents a specific point in 2D/3D/4D/etc. space. For example, the vector { x: 1, y: 2, z: 3 } represents the point (1, 2, 3) in 3D space where x, y, and z are the names of the dimensions (or axes).

Each parameter is an object that contains the numerical properties that should be added together.

Examples:

  1. Add two 3D points together.
const result = math.addVectors(
{ x: 1, y: 2, z: 3 },
{ x: 5, y: 6, z: 7 }
);

os.toast(result); // { x: 6, y: 8, z: 10 }
  1. Add arbitrary numbers together.
const result = math.addVectors(
{ salary: 1000, tax: 50 },
{ salary: 5000, tax: 250 },
{ salary: 750, tax: 37.5 },
);

os.toast(result); // { salary: 6750, tax: 337.5 }

math.subtractVectors(...vectors)

Mathematically subtracts the given vectors from each other and returns the result.

A vector is a group of numbers which represents a specific point in 2D/3D/4D/etc. space. For example, the vector { x: 1, y: 2, z: 3 } represents the point (1, 2, 3) in 3D space where x, y, and z are the names of the dimensions (or axes).

Each parameter is an object that contains the numerical properties that should be added together.

Examples:

  1. Subtract two 3D points from each other.
const result = math.addVectors(
{ x: 5, y: 6, z: 7 },
{ x: 1, y: 2, z: 3 },
);

os.toast(result); // { x: 4, y: 4, z: 4 }

math.negateVector(vector)

Mathematically negates the given vector and returns the result.

A vector is a group of numbers which represents a specific point in 2D/3D/4D/etc. space. For example, the vector { x: 1, y: 2, z: 3 } represents the point (1, 2, 3) in 3D space where x, y, and z are the names of the dimensions (or axes).

The first parameter is the object whose mathematical properties should be negated.

Examples:

  1. Negate a 3D point.
const result = math.negateVector(
{ x: 5, y: 6, z: 7 }
);

os.toast(result); // { x: -5, y: -6, z: -7 }

math.normalizeVector(vector)

Normalizes the given vector. The result is a vector that has the same direction as the given vector but has a length/magnitude of 1.

Mathemematically, this is the same as finding the math.vectorLength(vector) and dividing each component in the vector by it.

A vector is a group of numbers which represents a specific point in 2D/3D/4D/etc. space. For example, the vector { x: 1, y: 2, z: 3 } represents the point (1, 2, 3) in 3D space where x, y, and z are the names of the dimensions (or axes).

The first parameter is the object whose mathematical properties should be normalized.

Examples:

Normalize a 3D point
const result = math.normalizeVector(
{ x: 1, y: 2, z: 3 }
);

os.toast(result);
// x: 0.2672612419124244
// y: 0.5345224838248488
// z: 0.8017837257372732

math.vectorLength(vector)

Calculates the length (i.e. magnitude) of the given vector.

Mathemematically, this is equivalent to length = sqrt(sum(components.map(c => c * c))). As a consequence, vectors that are normalized always have a length of 1.

A vector is a group of numbers which represents a specific point in 2D/3D/4D/etc. space. For example, the vector { x: 1, y: 2, z: 3 } represents the point (1, 2, 3) in 3D space where x, y, and z are the names of the dimensions (or axes).

The first parameter is the object whose mathematical properties should be normalized.

Examples:

Calculate the length of a 3D point
const result = math.vectorLength(
{ x: 1, y: 2, z: 3 }
);

os.toast(result); // 3.7416573867739413

math.scaleVector(vector, scale)

Multiplies each property of the given vector by the given scale and returns the result.

A vector is a group of numbers which represents a specific point in 2D/3D/4D/etc. space. For example, the vector { x: 1, y: 2, z: 3 } represents the point (1, 2, 3) in 3D space where x, y, and z are the names of the dimensions (or axes).

The first parameter is the object whose mathematical properties should be scaled.

Examples:

  1. Scale a 3D point by 5.
const result = math.scaleVector(
{ x: 5, y: 6, z: 7 },
5
);

os.toast(result); // { x: 25, y: 30, z: 35 }

math.areClose(first, second)

Determines if the given numbers are within 2 decimal places of each other.

Because JavaScript numbers have limited precision, some calculations cannot be represented like they can in normal math. For example, 1/3 is 0.3333... but in JavaScript 1/3 gives 0.33333333333333331483. This inaccuracy can cause problems when many calculations are done, which can cause numbers that appear to be the same to actually be different.

The solution is to check the difference between two numbers to see if it is below some arbitrary threshold. In this case, the threshold is 0.005.

The first parameter is the first number that should be checked.

The second parameter is the second number that should be checked.

Examples:

  1. Determine 0.1 + 0.2 is close to 0.3.
const first = 0.1 + 0.2;
const second = 0.3;
const result = math.areClose(first, second);
const areEqual = first === second;
os.toast("Equal: " + areEqual + ", Close: " + result); // Equal: false, Close: true

Mod Actions

Mod actions are actions that can be used to create mods and transform some mods into other mods.

mod.cameraPositionOffset(position)

Creates a mod that sets the #cameraPositionOffset tags to the given 3D position.

The first parameter is the 3D position that should be made into a mod.

Examples:

  1. Get a mod that sets the camera position offset.
let mod = mod.cameraPositionOffset({
x: 4,
y: 5,
z: 6
});

mod.cameraRotationOffset(rotation)

Creates a mod that sets the #cameraRotationOffset tags to the given 3D position.

The first parameter is the 3D rotation that should be made into a mod.

Examples:

  1. Get a mod that sets the camera rotation offset.
let mod = mod.cameraRotationOffset({
x: 4,
y: 5,
z: 6
});

Crypto Actions

crypto.hash(algorithm, format, ...data)

Calculates the hash of the given data using the specified algorithm and returns the result in the specified format. Returns a hexadecimal string, Base64 string, or Uint8Array based on the specified format.

Hashes are generally useful for validating that a piece of data did not change or for checking to see if two values are the same thing.

Supports calculating hashes of strings, numbers, booleans, objects, arrays, and bots.

The first parameter is a string indicating which algorithm should be used for calculating the hash. The following algorithms are supported:

The second parameter is a string indicating which format the hash should be output as. The following formats are supported:

  • hex - The output should be a hexadecimal string.
  • base64 - The output should be a Base64 string.
  • raw - The output should be a Uint8Array.

The other parameters are the pieces of data that should be included in the hash. If multiple pieces of data are included, they will be concatenated.

Examples

Calculate the SHA-256 hex hash of a string
const hash = crypto.hash("sha256", "hex", "hello, world");
os.toast(hash);
Calculate the SHA-256 base64 hash of a string
const hash = crypto.hash("sha256", "base64", "hello, world");
os.toast(hash);
Calculate the SHA-256 raw hash of a string
const hash = crypto.hash("sha256", "raw", "hello, world");
console.log(hash);
Calculate the SHA-512 hex hash of a string
const hash = crypto.hash("sha512", "hex", "hello, world");
os.toast(hash);
Calculate the SHA-1 hex hash of a string
const hash = crypto.hash("sha1", "hex", "hello, world");
os.toast(hash);

crypto.sha256(...data)

Calculates the SHA-256 hash of the given data. Returns a hexadecimal string that represents the computed hash.

Hashes are generally useful for validating that a piece of data did not change or for checking to see if two values are the same thing.

Supports calculating hashes of strings, numbers, booleans, objects, arrays, and bots.

Each parameter is a piece of data that should be included in the hash. If multiple pieces of data are included, they will be concatenated.

Examples

  1. Calculate the hash of a string.
const hash = crypto.sha256("hello, world");
os.toast(hash);
  1. Calculate the hash of an object.
const hash = crypto.sha256({
abc: "def"
});
os.toast(hash);

crypto.sha512(...data)

Calculates the SHA-512 hash of the given data. Returns a hexadecimal string that represents the computed hash.

Hashes are generally useful for validating that a piece of data did not change or for checking to see if two values are the same thing.

Supports calculating hashes of strings, numbers, booleans, objects, arrays, and bots.

Each parameter is a piece of data that should be included in the hash. If multiple pieces of data are included, they will be concatenated.

Examples

  1. Calculate the hash of a string.
const hash = crypto.sha512("hello, world");
os.toast(hash);
  1. Calculate the hash of an object.
const hash = crypto.sha512({
abc: "def"
});
os.toast(hash);

crypto.hmac(algorithm, format, key, ...data)

Calculates the HMAC hash of the given data using the specified algorithm and returns the result in the specified format. Returns a hexadecimal string, Base64 string, or Uint8Array based on the specified format.

HMAC hashes are generally useful for validating that a piece of data was sent from someone else who has a particular secret key.

Supports calculating hashes of strings, numbers, booleans, objects, arrays, and bots.

The first parameter is a string indicating which algorithm should be used for calculating the hash. The following algorithms are supported:

The second parameter is a string indicating which format the hash should be output as. The following formats are supported:

  • hex - The output should be a hexadecimal string.
  • base64 - The output should be a Base64 string.
  • raw - The output should be a Uint8Array.

The third parameter is the secret key that should be used to create the HMAC.

The other parameters are the data that should be included in the hash. If multiple pieces of data are included, they will be concatenated.

Examples

Calculate the hexadecimal HMAC-SHA256 of a string with a key
const hash = crypto.hmac("hmac-sha256", "hex", "key", "hello, world");
os.toast(hash);
Calculate the Base64 HMAC-SHA256 of a string with a key
const hash = crypto.hmac("hmac-sha256", "base64", "key", "hello, world");
os.toast(hash);
Calculate the raw HMAC-SHA256 of a string with a key
const hash = crypto.hmac("hmac-sha256", "raw", "key", "hello, world");
console.log(hash);
Calculate the hexadecimal HMAC-SHA512 of a string with a key
const hash = crypto.hmac("hmac-sha512", "hex", "key", "hello, world");
os.toast(hash);
Calculate the hexadecimal HMAC-SHA1 of a string with a key
const hash = crypto.hmac("hmac-sha1", "hex", "key", "hello, world");
os.toast(hash);

crypto.hmacSha256(key, ...data)

Calculates the HMAC SHA-256 hash of the given data. Returns a hexadecimal string that represents the computed hash.

HMAC hashes are generally useful for validating that a piece of data was sent from someone else who has a particular secret key.

Supports calculating hashes of strings, numbers, booleans, objects, arrays, and bots.

The first parameter is the secret key that should be used to create the HMAC.

The other parameters are the data that should be included in the hash. If multiple pieces of data are included, they will be concatenated.

Examples

  1. Calculate the HMAC of a string with a key.
const hash = crypto.hmacSha256("key", "hello, world");
os.toast(hash);
  1. Calculate the HMAC of an object.
const hash = crypto.hmacSha256("key", {
abc: "def"
});
os.toast(hash);

crypto.hmacSha512(key, ...data)

Calculates the HMAC SHA-512 hash of the given data. Returns a hexadecimal string that represents the computed hash.

HMAC hashes are generally useful for validating that a piece of data was sent from someone else who has a particular secret key.

Supports calculating hashes of strings, numbers, booleans, objects, arrays, and bots.

The first parameter is the secret key that should be used to create the HMAC.

The other parameters are the data that should be included in the hash. If multiple pieces of data are included, they will be concatenated.

Examples

  1. Calculate the HMAC of a string with a key.
const hash = crypto.hmacSha512("key", "hello, world");
os.toast(hash);
  1. Calculate the HMAC of an object.
const hash = crypto.hmacSha512("key", {
abc: "def"
});
os.toast(hash);

crypto.encrypt(secret, data)

Encrypts the given data using the given secret key (also commonly known as a password) and returns the result.

Use the crypto.decrypt(key, data) function to decrypt the data.

Always use a strong and unique secret key. Use a password manager such as LastPass or 1Password to help you create and keep track of them.

Assuming a strong secret, this method will return a string of encrypted data that is confidential (unreadable without the key), reliable (the encrypted data cannot be changed without making it unreadable), and authentic (decryptability proves that this specific key was used to encrypt the data).

As a consequence, encrypting the same data with the same key will produce different results. This is to ensure that an attacker cannot correlate different pieces of data to potentially deduce the original plaintext.

Encrypts the given data using an authenticated encryption mechanism based on XSalsa20 (An encryption cipher) and Poly1305 (A message authentication code). Additionally uses scrypt for password-based key derivation.

The first parameter is the secret that should be used to encrypt the data. Use a strong an unique secret for maximum security.

The second parameter is the string data that should be encrypted.

Examples

  1. Encrypt the given data and toast it.
const encrypted = crypto.encrypt("key", "hello, world");
os.toast(encrypted);

crypto.decrypt(secret, data)

Decrypts the given data using the given secret key (also commonly known as a password) and returns the result.

Use the crypto.encrypt(key, data) function to encrypt the data.

The first parameter is the secret that should be used to decrypt the data. This should be the same key that was used to encrypt the data.

The second parameter is the data from crypto.encrypt(key, data) that should be decrypted.

Examples

  1. Decrypt the given data and toast it.
const decrypted = crypto.decrypt("key", "v1.vWUhsdfiKkxXi9Rt+BBNbcP/TiHZpxUL.iikPvWN6rNncY3j045gM0268MoRi0NNf.IpWYgzXQmjRea4MNLDXB1GmrinWLSSOMw+NfqeE=");
os.toast(decrypted);

crypto.isEncrypted(cyphertext)

Determines if the given value has been encrypted using crypto.encrypt(secret, data). Returns true if the data is encrypted and false otherwise.

The first parameter is the value that should be tested to see if it has been encrypted.

Examples

  1. Determine if a value is encrypted.
const encrypted = crypto.isEncrypted("hello, world");
os.toast('Is it encrypted? ' + encrypted);

crypto.keypair(secret)

Creates a keypair that can be used to digitially sign and verify data.

Use crypto.sign(keypair, secret, data) and crypto.verify(keypair, signature, data) to sign and verify the data.

Keypairs are made up of a private key and a public key. The private key is a special value that can be used to create digital signatures and the public key is a related value that can be used to verify that a digitital signature was created by the private key.

The private key is called "private" because it is encrypted using the given secret while the public key is called "public" because it is not encrypted so anyone can use it if they have access to it.

Note that both the private and public keys are randomly generated, so while the public is unencrypted, it won't be able to be used by someone else unless they have access to it.

The first parameter is the secret that should be used to encrypt the private key of the keypair.

Examples:

  1. Create a keypair and toast it.
const keypair = crypto.keypair("my secret");
os.toast(keypair);

crypt.sign(keypair, secret, data)

Calculates the digital signature for the given data using the given keypair and secret (also commonly known as a password).

Use crypto.keypair(secret) to create a keypair that can be used to create signatures.

Use crypto.verify(keypair, signature, data) to validate signatures.

Digital signatures are used to verifying the authenticity and integrity of data.

This works by leveraging asymmetric encryption but in reverse.

If we can encrypt some data such that only the public key of a keypair can decrypt it, then we can prove that the data was encrypted (i.e. signed) by the corresponding private key.

And since the public key is available to everyone but the private key is only usable when you have the secret, we can use this to prove that a particular piece of data was signed by whoever knows the secret.

Note that because of how digital signatures work, signing the same data with the same keypair will produce the same signature.

The first parameter is the keypair that should be used to sign the data.

The second parameter is the secret that was used to encrypt the private key of the keypair.

The third parameter is the string data that should be signed.

Examples:

  1. Create a signature for the string "hello".
// Returned from crypto.keypair()
const keypair = "vK1.ugqz8HzhaQhfORc8Coc6WVHTciMrcmfSUuw99KLRJYk=.djEuak1QNkF5MHFzMTBFMXRHamR1ZFhqTmRTV3AycjVyZUsudzFjSWZWVUFQVUdqK3hTM000NUduYUlNQ094SUhCTUEuanYrZEQwNVJFVGo3UzRPSklQQUkxc3U0anZjUmxrTEM2OW1BajkyMkxxdTFZd2sxNzV5QW9Dc3gwU3RENlQ0cmtNTVk4b2Zna2JRVTIrQmp5OUIrTTJsaFI2ajcyb0lJdmdSWkRXRU9lZE09";

const signature = crypto.sign(keypair, "my secret", "hello");
os.toast(signature);

crypto.verify(keypair, signature, data)

Validates that the given signature was created by the given keypair for the given data. Returns true if the signature is valid. Returns false otherwise.

Use crypto.keypair(secret) to create a keypair that can be used to create signatures.

Use crypto.sign(keypair, secret, data) to create signatures.

The first parameter is the keypair that was used to create the signature.

The second parameter is the signature that was returned from crypto.sign(keypair, secret, data).

The third parameter is the data that was used in the call to crypto.sign(keypair, secret, data).

Examples:

  1. Validate a signature.
// Returned from crypto.keypair()
const keypair = "vK1.ugqz8HzhaQhfORc8Coc6WVHTciMrcmfSUuw99KLRJYk=.djEuak1QNkF5MHFzMTBFMXRHamR1ZFhqTmRTV3AycjVyZUsudzFjSWZWVUFQVUdqK3hTM000NUduYUlNQ094SUhCTUEuanYrZEQwNVJFVGo3UzRPSklQQUkxc3U0anZjUmxrTEM2OW1BajkyMkxxdTFZd2sxNzV5QW9Dc3gwU3RENlQ0cmtNTVk4b2Zna2JRVTIrQmp5OUIrTTJsaFI2ajcyb0lJdmdSWkRXRU9lZE09";

// Returned from crypto.sign()
const signature = "vS1.uF93ErJBhdI/vqRF2XD2zgRAO96vKc9mx8crn6Kasijmx92px36B/alLGluU22tgCav/nNQEHdV2zZoHPgy7Dg==";

const valid = crypto.verify(keypair, signature, "hello");
os.toast(valid);

crypto.asymmetric.keypair(secret)

Creates a keypair that can be used to encrypt and decrypt data.

Use crypto.asymmetric.encrypt(keypair, data) and crypto.asymmetric.decrypt(keypair, secret, data) to encrypt and decrypt the data.

Always use a strong and unique secret key. Use a password manager such as LastPass or 1Password to help you create and keep track of them.

Keypairs are made up of a private key and a public key The public key is a special value that can be used to encrypt data and the private key is a related value that can be used to decrypt data that was encrypted by the private key.

The private key is called "private" because it is encrypted using the given secret while the public key is called "public" because it is not encrypted so anyone can use it if they have access to it.

Note that both the private and public keys are randomly generated, so while the public is unencrypted, it won't be able to be used by someone else unless they have access to it.

The first parameter is the secret that should be used to encrypt the private key of the keypair.

Examples:

  1. Create a keypair and toast it.
const keypair = crypto.asymmetric.keypair("my secret");
os.toast(keypair);

crypto.asymmetric.isKeypair(keypair)

Determines if the given value is a keypair generated using crypto.asymmetric.keypair(secret). Returns true if the data is a keypair and false otherwise.

The first parameter is the value that should be tested to see if it is a keypair.

Examples

  1. Determine if a value is a keypair.
const encrypted = crypto.asymmetric.isKeypair("hello, world");
os.toast('Is it a keypair? ' + encrypted);

crypto.asymmetric.encrypt(keypair, data)

Encrypts the given data using the given keypair's public key and returns the result.

Use the crypto.asymmetric.decrypt(keypair, secret, data) function to decrypt the data.

This method will return a string of encrypted data that is confidential (unreadable without the keypair and secret used to encrypt it), reliable (the encrypted data cannot be changed without making it unreadable), and authentic (decryptability proves that the keypair was used to encrypt the data).

As a consequence, encrypting the same data with the same keypair will produce different results. This is to ensure that an attacker cannot correlate different pieces of data to potentially deduce the original plaintext.

Encrypts the given data using an asymmetric authenticated encryption mechanism based on x25519 (A key-exchange mechanism), XSalsa20 (An encryption cipher) and Poly1305 (A message authentication code).

You may notice that this function does not need a secret to decrypt the keypair. This is because the public key of the keypair is used to encrypt the data. Due to how asymmetric encryption works, only the encrypted private key will be able to decrypt the data.

Encrypts the given data using an authenticated encryption mechanism based on x25519, XSalsa20 (An encryption cipher) and Poly1305 (A message authentication code).

The first parameter is the keypair that should be used to encrypt the data.

The second parameter is the string data that should be encrypted.

Examples

  1. Encrypt the given data and toast it.
const keypair = 'vEK1.UoNnUjLz7FdgjJ52P+f/sNw1VDsKwyX0kI+Bt7ivoF4=.djEuZmFvL0tOa1RJL3ByVm8wZ2QxYTk5clV4OXZUTk0wMnUuUHpZQUM1aVlYOUUra09vZ2hmamdyNll6T0tJS0ZjQjUuMGx2VGR5UmR2dloxUklWam5OODMrN09ibnk0c2MzbjNKYzZtSmFPYzc0ZXJXMlhHQzJsWW1vWGdFdzBRM2xkSg==';
const encrypted = crypto.asymmetric.encrypt(keypair, "hello, world");
os.toast(encrypted);

crypto.asymmetric.decrypt(keypair, secret, data)

Decrypts the given data with the given keypair and secret and returns the result. If the data was unable to be decrypted, null will be returned.

Use the crypto.asymmetric.encrypt(keypair, data) function to encrypt the data.

The first parameter is the keypair that should be used to decrypt the data.

The second parameter is the secret that should be used to decrypt the keypair's private key.

The third parameter is the data that should be decrypted.

Examples:

  1. Decrypt the given data and toast it.
const keypair = 'vEK1.UoNnUjLz7FdgjJ52P+f/sNw1VDsKwyX0kI+Bt7ivoF4=.djEuZmFvL0tOa1RJL3ByVm8wZ2QxYTk5clV4OXZUTk0wMnUuUHpZQUM1aVlYOUUra09vZ2hmamdyNll6T0tJS0ZjQjUuMGx2VGR5UmR2dloxUklWam5OODMrN09ibnk0c2MzbjNKYzZtSmFPYzc0ZXJXMlhHQzJsWW1vWGdFdzBRM2xkSg==';
const encrypted = 'vA1.3CC1r0fJP2tPS09C8YrTDQCJmgFczxprNEcMOzY4JD4=.3oiC7nG6N4jblFhBd4usrdid/w4Phwg/.X/9mbZYOGBjRX7YAO4D2zYJvZ3c=';
const decrypted = crypto.asymmetric.decrypt(keypair, 'password', encrypted);
os.toast(decrypted);

crypto.asymmetric.isEncrypted(cyphertext)

Determines if the given value was encrypted using crypto.asymmetric.encrypt(keypair, data). Returns true if the data is a keypair and false otherwise.

The first parameter is the value that should be tested to see if it is encrypted.

Examples

  1. Determine if a value is encrypted with asymmetric encryption.
const encrypted = crypto.asymmetric.isEncrypted("hello, world");
os.toast('Is it encrypted? ' + encrypted);

crypto.createCertificate(certificate, secret, keypair)

Creates a new certified bot (also known as a certificate) from the given keypair that is signed by the given certified bot using the given secret (also commonly known as a password). Returns a promise that resolves with the new bot.

Certificates are useful for creating signatures for tag values that CasualOS is aware of and will validate for you.

Certificates are similar to keypairs except that they themselves are signed by another certificate. This creates a chain of trust that can be used to establish the validity of any arbitrary certificate. The certificate that created the signature is called the "signing/signer certificate" and the certificate that recieved the signature is called the "signee certificate".

Each certificate contains the following information:

  • A keypair.
  • A reference to the signing certificate.
  • A signature from the signing certificate.

In CasualOS, there are two types of certificates:

  1. Root certificates.
  2. Non-root certificates.

Root certificates are certificates that are both signee and signer. This means that the certificate used its own keypair to create the signature. As such, the validity of the certificate cannot be checked apart from simply trusting it. Only one root certificate is allowed per inst on a first-come first-serve basis. Once a root certificate is created for a inst, another cannot be created.

Non-root certificates are certificates that are signed by another certificate. This means that another certificate's keypair was used to create the signature. As such, the validity of the certificate can be checked by following the chain of trust back to the root certificate. If the chain does not end at the root certificate for the inst, then the certificate is invalid and any signatures created by it will also be invalid.

Use crypto.keypair(secret) to create a keypair that can be used to create signatures.

Use crypto.signTag(certificate, secret, bot, tag) to create signatures for a certificate.

The first parameter is the certified bot that should be used to sign the new certificate. If given null, then the new bot will be self-signed.

The second parameter is the secret that should be used to decrypt the private key. If the first parameter is null, then this should be the secret for the keypair.

The third parameter is the keypair that the new certificate should have.

Examples:

  1. Create a root certificate and toast the Bot ID:
const keypair = await crypto.keypair('secretForRootCert');
const cert = await crypto.createCertificate(null, 'secretForRootCert', keypair);

os.toast(getID(cert));
  1. Create a non-root certificate and toast the Bot ID:
const rootKeypair = getBot('id', rootCertID);

const nonRootKeypair = await crypto.keypair('secretForNonRootCert');
const nonRoot = await crypto.createCertificate(rootCert, 'secretForRootCert', nonRootKeypair);

os.toast(getID(nonRoot));

crypto.signTag(certificate, secret, bot, tag)

Creates a signature for the given bot, tag, and current value using the given certificate and secret. Returns a promise that resolves once the tag value has been signed.

When a signature is created for a tag value, the value is considered valid until it is changed or the certificate is revoked.

The first parameter is the certificate bot that should be used to create the signature.

The second parameter is the secret used to decrypt the private key of the certificate.

The third parameter is the bot whose tag value should be signed.

The fourth parameter is the tag whose value should be signed.

Use crypto.createCertificate(certificate, secret, keypair) to create certificates that can be used with this function.

Use crypto.verifyTag(bot, tag) to verify that a tag has a valid signature.

Examples:

  1. Sign the @onClick script on a bot.
const cert = getBot('id', certID);
await crypto.signTag(cert, 'secretForCert', bot, 'onClick');

crypto.verifyTag(bot, tag)

Validates that the tag value stored in the given tag on the given bot has been signed by a valid certificate. Returns true if the tag value is valid. Returns false otherwise.

The first parameter is the bot whose tag value should be checked.

The second parameter is the tag whose value should be checked.

Examples:

  1. Check if the @onClick script is signed.
const valid = crypto.verifyTag(bot, 'onClick');

if (valid) {
os.toast('onClick is valid!');
} else {
os.toast('onClick is not valid.');
}

crypto.revokeCertificate(certificate, secret, signer?)

Revokes the given certificate and any signatures that it has created. In effect, this deletes the certificate bot from the inst. Additionally, any tags signed with the given certificate will no longer be verified.

Returns a promise that resolves when the certificate has been revoked.

Revoking a certificate works by creating another record (called a revocation) that is signed by either the original certificate or an ancestor of the original certificate. This record is then stored in the shared space and lets everyone see that the certificate is no longer valid.

The first parameter is the certificate that should be revoked.

The second parameter is the secret that should be used to decrypt the corresponding certificate's private key. If the signer parameter is specified, then this is the secret for the signer certificate. If the signer parameter is omitted, then this is the secret for the certificate that is being revoked.

The third parameter is optional and is the certificate that should be used to perform the revocation process. If not specified, then the revocation will be signed by the revoked certificate (self-signed revocation). If specified, then the revocation will be signed using the given certificate. Note that any certificate that is specified must either be the original certificate or an ancestor of the original certificate.

Examples:

  1. Revoke a certificate with itself.
const cert = getBot('id', certificateId);
await crypto.revokeCertificate(cert, 'secretForCert');

os.toast('Certificate revoked!');
  1. Revoke a certificate using another certificate.
const certToRevoke = getBot('id', certToRevokeId);
const signingCert = getBot('id', signingCertId);

await crypto.revokeCertificate(certToRevoke, 'secretForSigningCert', signingCert);

os.toast('Certificate revoked!');

Bytes Actions

Bytes actions are functions that make it easier to work with arrays of bytes and transform them into different formats.

bytes.toBase64String(bytes)

Formats the given bytes into a string that contains the Base64 representation of the given data. Returns the Base64 string.

The first parameter is the Uint8Array of bytes that should be formatted into Base64.

Examples:

Format a byte array into Base64
os.toast(bytes.toBase64String(new Uint8Array([ 255, 254, 253 ])));

bytes.fromBase64String(base64)

Converts the given Base64 string into a byte array that contains the data represented by the string. Returns the new Uint8Array array.

The first parameter is the Base64 formatted string that should be converted to a Uint8Array byte array.

Examples:

Convert a Base64 string into bytes
const data = bytes.fromBase64String('aGVsbG8='); // "hello" encoded in Base64

bytes.toHexString(bytes)

Formats the given bytes into a string that contains the hexadecimal representation of the given data. Returns the hex string.

The first parameter is the Uint8Array of bytes that should be formatted into hexadecimal.

Examples:

Format a byte array into hexadecimal
os.toast(bytes.toHexString(new Uint8Array([ 255, 254, 253 ]))); // fffefd in bytes

bytes.fromHexString(hex)

Converts the given hexadecimal string into a byte array that contains the data represented by the string. Returns the new Uint8Array array.

The first parameter is the hexadecimal string that should be converted to a byte array.

Examples:

Convert a hex string into bytes
const data = bytes.fromHexString('fffefd'); // 255, 254, 253 in hex

App Actions

App actions are a way to register and display customized apps inside CasualOS. They work in tandem with listen tags and bots to create arbitrarily complex experiences that interface with the CasualOS frontend.

Apps work by utilizing a subset of HTML that works in the CasualOS middle-end and can be synced to the CasualOS front-end. This allows apps to leverage all the power of bots, tags, and tag masks while at the same time being able to seamlessly integrate with the front-end.

os.registerApp(appId, bot)

Registers a app with the given ID, bot, and options. Returns a promise that resolves when the app has been registered. Can be called multiple times with new options to override previous options.

Once setup, CasualOS will send a @onAppSetup whisper to the given bot. At this point, you can call os.compileApp(appId, content) to set what the app displays.

CasualOS will also define a global variable {app}Bot that points to the given bot.

The first parameter is the ID that the app should have.

The second parameter is the bot that should represent the app. This is the bot that recieves the @onAppSetup whisper and should generally be in charge of calling os.compileApp(appId, content).

Apps work by running the HTML you give it by calling os.compileApp(appId, content) with the HTML you want the app to show. Since JavaScript does not natively support HTML, we are using a special extension called JSX that adds HTML-like syntax to JavaScript. At the most basic, JSX is like writing HTML inside JavaScript:

let htmlData = <div>
<h1>Hello World</h1>
</div>;

See this article for more information: Introducing JSX

CasualOS also includes a helper called html that can be used to make HTML objects out of a string. You can use it to convert a string into HTML by adding it before a string that uses backticks, like this:

let htmlData = html`
<div>
<h1>Hello World</h1>
</div>
`;

JSX is the preferred way to write HTML inside JavaScript since CasualOS can properly detect it and add helpful features like syntax highlighting and error messages.

Examples:

Setup a basic app
await os.registerApp('basicApp', thisBot);

os.compileApp('basicApp', <h1>Hello World!</h1>);
Setup an app with a button
await os.registerApp('buttonApp', thisBot);

os.compileApp('buttonApp',
<button onClick={ () => os.toast("You clicked the button!") }>
Click Me!
</button>
);
Setup an app with an input box
await os.registerApp('inputApp', thisBot);

os.compileApp('inputApp',
<input onInput={ (e) => { tags.label = e.target.value } }/>
);

os.compileApp(appId, content)

Compiles the app with the given ID to display the given content. Each time this function is called, the app will be cleared and will display the specified content.

Used in tandem with os.registerApp(appId, bot) to create custom apps.

The first parameter is the ID of the app.

The second parameter is the content that the app should display.

Examples:

Display a header
os.compileApp('myApp', <h1>Hello World!</h1>);
Display a button
os.compileApp('myApp', 
<button onClick={ () => os.toast("You clicked the button!")}>
Click Me!
</button>
);
Display an input box
os.compileApp('myApp', 
<input onInput={ (e) => { tags.label = e.target.value } } />
);
Display a slider input
os.compileApp('myApp', 
<input type="range" min="0" max="100" onInput={ (e) => { tags.label = e.target.value } } />
);

os.unregisterApp(appId)

Unregisters and removes the app with the given ID. Returns a promise that resolves when the app has been removed.

The first parameter is the ID of the app.

Examples

Unregister an app
await os.unregisterApp('myApp');

os.appHooks

An object that contains hooks that make programming custom apps easier. See the preact documentation for more information.

Examples

Create a counter
const { useState, useCallback } = os.appHooks;

function Counter() {
const [value, setValue] = useState(0);
const increment = useCallback(() => {
setValue(value + 1)
}, [value]);

return (
<div>
Counter: {value}
<button onClick={increment}>Increment</button>
</div>
);
}

await os.registerApp('myapp', thisBot);
await os.compileApp('myapp', <Counter/>);
Render an app to the document without using os.compileApp()
const { useState, useCallback, render } = os.appHooks;

function Counter() {
const [value, setValue] = useState(0);
const increment = useCallback(() => {
setValue(value + 1)
}, [value]);

return (
<div>
Counter: {value}
<button onClick={increment}>Increment</button>
</div>
);
}

render(<Counter/>, document.body);

os.listBuiltinTags()

Gets the list of tag names that are built-in to CasualOS.

Includes tags like #color and #gridPortal, but not user-defined ones like #[dimension].

Examples

Get the list of built-in tags
const builtinTags = os.listBuiltinTags();
os.toast(builtinTags);

os.registerTagPrefix(prefix, options?)

Specifies that the given prefix should be used to indicate that the tag contains script content. Use this function to specify custom prefixes that function similarly to @ or 🧬.

The first parameter is the prefix that should indicate that the rest of the tag value is a script.

The second parameter is optional and is the options that should be used for the prefix. It is an object and should have the following structure:

let options: {

/**
* The language that scripts with the prefix should be interpreted as.
*
* "javascript" and "typescript" can be used for general purpose programming.
*
* "jsx" and "tsx" are extensions to JavaScript and TypeScript which includes the ability
* to write HTML-like code that gets converted to JavaScript/TypeScript code.
*
* "json" can be used to interpret the data as JSON (like 🧬).
*
* "text" can be used to interpret the data as plain text.
*
* Defaults to "javascript".
*/
language?: "javascript" | "typescript" | "json" | "jsx" | "tsx" | "text";

/**
* The name of the prefix.
*/
name?: string;
};

Examples:

  1. Add 📖 as an script prefix.
await os.registerTagPrefix("📖");
  1. Register some arbitrary text as a prefix.
await os.registerTagPrefix("myPrefix");
  1. Register a prefix as JSX code.
await os.registerTagPrefix("🔺", {
language: "jsx"
});
  1. Register a prefix with a name.
await os.registerTagPrefix("🔺", {
language: "jsx"
name: 'Triangle'
});

Experimental Actions

experiment.localFormAnimation(bot, animation)

Locally plays the given animation on the given bot.

If an animation is already playing, it will be interrupted. When the given animation is finished playing, the interrupted animation will be restored.

The first parameter is the Bot or Bot ID that the animation should be played on.

The second parameter is the name or index of the animation that should be played.

Examples

  1. Play the "jump" animation on this bot.
experiment.localFormAnimation(this, "jump");

experiment.localPositionTween(bot, dimension, position, easing?)

Locally plays a tween that moves the given bot in the given dimension to the given position. Optionally allows customizing the easing of the tween.

Returns a promise that resolves when the tween is finished.

While the tween is playing, any updates to the bot's position and rotation are ignored. Once the tween is done playing, any change to the bot will reset the position/rotation.

The first parameter is the bot or ID of the bot that should be tweened.

The second parameter is the dimension that the bot should be tweened in. Note that the tween will only work if the given dimension is currently in the grid portal or miniGridPortal.

The third parameter is the position that the bot should be tweened to. If you exclude a dimension (like x, y, or z), then it will remain unchanged.

The fourth parameter is optional and is the options that should be used. It is an object with the following properties:

let options: {

/**
* The amount of time that the tween takes to complete in seconds.
* The maximum duration is 24 hours (86,400 seconds).
* The minimum duration is 0.
* Defaults to 1 if not specified.
*/
duration?: number;

/**
* The options for easing.
* Defaults to "linear" "inout" if not specified.
*/
easing?: {
/**
* The type of easing.
*/
type: 'linear'
| 'quadratic'
| 'cubic'
| 'quartic'
| 'quintic'
| 'sinusoidal'
| 'exponential'
| 'circular'
| 'elastic';

/**
* Whether to apply the easing at the
* start (in), end (out), or start and end (inout) of the tween.
*/
mode: 'in' | 'out' | 'inout';
}
};

Examples:

  1. Tween the bot to X = 10 in the home dimension.
experiment.localPositionTween(
this,
'home',
{
x: 10,
});
  1. Tween the bot over 5 seconds.
experiment.localPositionTween(
this,
'home',
{
x: 10,
},
{
duration: 5
});
  1. Tween the bot with quadratic easing.
experiment.localPositionTween(
this,
'home',
{
x: 10,
},
{
easing: {
type: 'quadratic',
mode: 'inout'
}
});

experiment.localRotationTween(bot, dimension, rotation, easing?)

Locally plays a tween that rotates the given bot in the given dimension to the given rotation. Optionally allows customizing the easing of the tween.

Returns a promise that resolves when the tween is finished.

While the tween is playing, any updates to the bot's position and rotation are ignored. Once the tween is done playing, any change to the bot will reset the position/rotation.

The first parameter is the bot or ID of the bot that should be tweened.

The second parameter is the dimension that the bot should be tweened in. Note that the tween will only work if the given dimension is currently in the grid portal or miniGridPortal.

The third parameter is the rotation that the bot should be tweened to in radians. If you exclude a dimension (like x, y, or z), then it will remain unchanged.

The fourth parameter is optional and is the options that should be used. It is an object with the following properties:

let options: {

/**
* The amount of time that the tween takes to complete in seconds.
* The maximum duration is 24 hours (86,400 seconds).
* The minimum duration is 0.
* Defaults to 1.
*/
duration?: number;

/**
* The options for easing.
* Defaults to "linear" "inout" if not specified.
*/
easing?: {
/**
* The type of easing.
*/
type: 'linear'
| 'quadratic'
| 'cubic'
| 'quartic'
| 'quintic'
| 'sinusoidal'
| 'exponential'
| 'circular'
| 'elastic';

/**
* Whether to apply the easing at the
* start (in), end (out), or start and end (inout) of the tween.
*/
mode: 'in' | 'out' | 'inout';
}
};

Examples:

  1. Tween the bot 90 degrees around the Z axis in the home dimension.
experiment.localRotationTween(
this,
'home',
{
z: Math.PI / 2,
});
  1. Tween the bot for 5 seconds.
experiment.localRotationTween(
this,
'home',
{
z: Math.PI / 2,
},
{
duration: 5
});
  1. Tween the bot with quadratic easing.
experiment.localRotationTween(
this,
'home',
{
z: Math.PI / 2,
},
{
easing: {
type: 'quadratic',
mode: 'inout'
}
});

experiment.getAnchorPointPosition(bot, dimension, anchorPoint)

Gets the absolute position in the given dimension that the center of the given bot would be placed at if the bot was using the given anchor point.

The first parameter is the bot that the anchor point position should be calculated for.

The second parameter is the dimension that the anchor point position should be calculated in.

The third parameter is the anchor point that should be calculated. Can be any valid #anchorPoint value.

Examples:

  1. Get the top anchor point of the current bot in the "home" dimension.
const point = experiment.getAnchorPointPosition(bot, "home", "top");
os.toast(point);
  1. Get the back right anchor point of the current bot in the "home" dimension.
const point = experiment.getAnchorPointPosition(bot, "home", [ 0.5, -0.5, 0 ]);
os.toast(point);
  1. Place bots at each of the anchor points.
let points = [
'top',
'bottom',
'front',
'back',
'left',
'right',
'center',
];

for(let point of points) {
let pos = experiment.getAnchorPointPosition(bot, os.getCurrentDimension(), point);
create({
space: 'tempShared',
color: 'green',
[os.getCurrentDimension()]: true,
[os.getCurrentDimension() + "X"]: pos.x,
[os.getCurrentDimension() + "Y"]: pos.y,
[os.getCurrentDimension() + "Z"]: pos.z,
anchorPoint: 'center',
targetAnchorPoint: point,
scale: 0.1,
});
}

experiment.beginRecording(options?)

Starts a new recording. Returns a promise that resolves when recording has started. The returned promise will throw an error if recording could not be started. Reasons for this include insufficient permissions and not having a microphone.

The first parameter should be an object and contains the options that should be used for the recording. It should have the following structure:

let options: {
/**
* Whether the audio should be recorded.
* If the computer does not have an audio device attached, then setting this to true
* will cause an error.
*
* Defaults to true.
*
* If an array is specified, only the specified audio sources will be recorded.
*/
audio: boolean | ('screen' | 'microphone')[];

/**
* Whether video from a video camera should be recorded.
*
* If the computer does not have a video device attached (like a web cam),
* then setting this to true will cause an error.
*
* Defaults to true.
*/
video: boolean;

/**
* Whether the screen should be recorded.
*
* Defaults to false.
*/
screen: boolean;
};

Examples:

  1. Record for 10 seconds and download the files.
await experiment.beginRecording({
audio: true,
video: true,
screen: false
});
await os.sleep(10000);
const data = await experiment.endRecording();
let index = 0;
for(let file of data.files) {
os.download(file.data, `file-${index}`);
index += 1;
}
  1. Record the screen with microphone audio.
await experiment.beginRecording({
audio: ['microphone'],
video: false,
screen: true
});
await os.sleep(10000);
const data = await experiment.endRecording();
let index = 0;
for(let file of data.files) {
os.download(file.data, `file-${index}`);
index += 1;
}

experiment.endRecording()

Stops the recording that is in progress. Returns a promise that resolves with the recorded data.

The resolved data is an object and has the following structure:

let recording: {
files: {
containsAudio: boolean;
containsVideo: boolean;
containsScreen: boolean;
data: Blob;
}[];
};

Examples:

  1. Record for 10 seconds and download the files.
await experiment.beginRecording({
audio: true,
video: true,
screen: false
});
await os.sleep(10000);
const data = await experiment.endRecording();
let index = 0;
for(let file of data.files) {
os.download(file.data, `file-${index}`);
index += 1;
}

experiment.getVoices()

Gets the list of synthetic voices that are supported by the system. Returns a promise that resolves with the list. Each item in the list is an object with the following properties:

let voice: {
/**
* Whether this voice is the default synthetic voice.
*/
default: boolean;

/**
* The language that this voice can speak.
* This is the BCP 47 tag indicating which language and which region the language is for.
* For example, "en-US" represents English for the United States locale.
*/
language: string;

/**
* The name of the voice.
*/
name: string;
};

Examples:

  1. Toast the list of voices that are supported.
const voices = await experiment.getVoices();
os.toast(voices);
  1. Get the first US English voice.
const voices = await experiment.getVoices();
const usEnglish = voices.find(v => v.language === "en-US");
os.toast(usEnglish);

experiment.speakText(text, options?)

Speaks the given text using a synthetic voice and options. Note that this is a local effect. The gererated sounds are only played in the current session.

Returns a promise that resolves when the text has been spoken.

The first parameter is the text that should be spoken.

The second parameter is optional and are the options that should be used to speak the text. It should be an object with the following properties:

let options: {
/**
* The voice that the text should be spoken with.
* This can be the voice object or the name of a voice.
* Note that not all browsers support the same voices.
*/
voice?: string | object;

/**
* The rate that the text should be spoken at.
* This can be any positive number.
*/
rate?: number;

/**
* The pitch that the text should be spoken at.
* This can be any positive number.
*/
pitch?: number;
};

Examples:

  1. Say "hello".
await experiment.speakText("hello");
os.toast("We said hello!");
  1. Say "hello" using the first US English voice.
const voices = await experiment.getVoices();
const usEnglish = voices.find(v => v.language === "en-US");

await experiment.speakText("hello", {
voice: usEnglish
});
os.toast("Spoken!");

perf.getStats()

Gets an object that contains statistics about the performance of the inst.

The returned object has the following structure:

let stats: {
/**
* The number of bots in the inst.
*/
numberOfBots: number,

/**
* A list shouts and their associated execution time (in miliseconds).
* Sorted from largest time to smallest.
*/
shoutTimes: {
tag: string,
timeMs: number
}[];

/**
* The total number of active setTimeout() and setInterval() timers that are active.
*/
numberOfActiveTimers: number;

/**
* An object containing information about the load performance of various pieces of CasualOS.
*/
loadTimes: {
[key: string]: number;
}
};

Examples:

  1. Get the 5 slowest listen tags.
const stats = perf.getStats();
const slowestTags = stats.shoutTimers.slice(0, 5).map(timer => timer.tag)

os.toast(slowestTags.join());

Server Actions

server.backupToGithub(auth)

Saves all the instances to GitHub as a private Gist using the given authentication token.

Just like server.shell(script), you need

The first parameter is the Github Personal Access Token that should be used to grant access to your Github account. See https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line

Examples:

  1. Backup all the instances to a Github Gist.
server.backupToGithub('your auth token');

server.backupAsDownload(target)

Saves all the instances to a zip file and downloads it to the session matching the given target.

The first parameter is an object that indicates which session the zip file should be downloaded to.

Examples:

  1. Backup and download to this tab.
server.backupAsDownload({
session: getID(configBot)
});

server.finishCheckout(options)

Finishes the checkout process by charging payment to the player. Best used during the @onCheckout shout.

The first parameter are the options needed to finish the checkout process.

Examples:

  1. Finish the checkout process.
server.finishCheckout({
secretKey: 'YOUR_SECRET_API_KEY',

token: 'token from onCheckout',

// 1000 cents == $10.00
amount: 1000,
currency: 'usd',
description: 'Description for purchase'
});

server.rpioInit(options)

Initialise the bcm2835 library. This will be called automatically by .open() using the default option values if not called explicitly.
The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when rpio has been initialized.

The first parameter is an object with the settings to initialize with.

gpiomem can be either true or false. mapping can be either gpio or physical. mock can be any of raspi-b-r1 or raspi-a or raspi-b or raspi-a+ or raspi-b+ or raspi-2 or raspi-3 or raspi-zero or raspi-zero-w. close_on_exit can be true or false. It is recommended to always be true.

Examples:

  1. Initialize rpio with the default options explicitly stated.
let options = {
gpiomem: true, /* Use /dev/gpiomem */
mapping: 'physical', /* Use the P1-P40 numbering scheme */
mock: undefined, /* Emulate specific hardware in mock mode */
close_on_exit: true, /* On node process exit automatically close rpio */
}

server.rpioInit(options);

server.rpioExit()

Shuts down the rpio library, unmapping and clearing all memory maps. By default this will happen automatically. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when rpio has been exited.

Examples:

  1. Manually cleanup rpio.
server.rpioExit();

server.rpioOpen(pin, mode, options)

Open a pin for input or output. For input pins, options can be used to configure the internal pullup or pulldown resistors. For output pins, options defines the initial state of the pin, rather than having to issue a separate .write() call. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when the pin has been configured.

The first parameter is the pin on the physical server.

The second parameter is 'INPUT', 'OUTPUT', or 'PWM' to set the pin as an input pin, an output pin, or for use with PWM.

The third parameter is optional and either 'HIGH', 'LOW', 'PULL_OFF', 'PULL_DOWN', or 'PULL_UP' to set the pin state.

Examples:

  1. Configure pin 11 as output.
let led_pin = 11;
server.rpioOpen(led_pin, 'OUTPUT');
  1. Configure pin 11 as output and initialize the pin as 'LOW'.
let led_pin = 11;
server.rpioOpen(led_pin, 'OUTPUT', 'LOW');
  1. Configure pin 11 as input and initialize the pin as 'PULL_DOWN'.
let led_pin = 11;
server.rpioOpen(led_pin, 'INPUT', 'PULL_DOWN');

server.rpioMode(pin, mode, options)

Switch a pin that has already been opened in one mode to a different mode. This is provided primarily for performance reasons, as it avoids some of the setup work done by .open(). The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when the pin has been configured.

The first parameter is the pin on the physical server.

The second parameter is 'INPUT', 'OUTPUT', or 'PWM' to set the pin as an input pin, an output pin, or for use with PWM.

The third parameter is optional and either 'HIGH', 'LOW', 'PULL_OFF', 'PULL_DOWN', or 'PULL_UP' to set the pin state.

Examples:

  1. Change pin 11 mode to output and initialize the pin as 'LOW'.
let led_pin = 11;
server.rpioOpen(led_pin, 'INPUT');
server.rpioMode(led_pin, 'OUTPUT', 'LOW');
  1. Change pin 11 mode to input and initialize the pin as 'PULL_DOWN'.
let led_pin = 11;
server.rpioOpen(led_pin, 'OUTPUT');
server.rpioMode(led_pin, 'INPUT', 'PULL_DOWN');

server.rpioRead(pin)

Read the current value of pin, returning either 1 (high) or 0 (low). The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when the pin has been read.

The first parameter is the pin on the physical server.

Examples:

  1. Shout the state of pin 11.
var led_pin = 11;

server.rpioOpen(led_pin, 'OUTPUT');
let state = await server.rpioRead(led_pin);

os.shout(state);

server.rpioReadSequence(pin, length)

Read length bits from pin into buffer as fast as possible. This is useful for devices which send out information faster than the JavaScript function call overhead can handle, e.g. if you need microsecond accuracy. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when the pin has been read.

The first parameter is the pin on the physical server.

The second parameter is the length of the buffer to read.

Examples:

  1. Read the value of Pin 16 10 times in a row
server.rpioReadSequence(16, 10);

server.rpioWrite(pin, value)

Set the specified pin either high or low. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when the pin has been set.

The first parameter is the pin on the physical server.

The second parameter is 'HIGH' or 'LOW' to set the pin as an HIGH or LOW.

Examples:

  1. Set pin 11 to HIGH.
var led_pin = 11;

server.rpioOpen(led_pin, 'OUTPUT', 'LOW');
server.rpioWrite(led_pin, 'HIGH');

server.rpioWriteSequence(pin, buffer)

Write length bits to pin from buffer as fast as possible. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when the pin has been written to.

The first parameter is the pin on the physical server.

The second parameter is array of numbers.

Examples:

  1. Write a sequence of numbers to Pin 13

server.rpioWriteSequence(13, [10, 10]);

server.rpioReadpad(group, bitmask)

Read the current state of the GPIO pad control for the specified GPIO group. On current models of Raspberry Pi there are three groups with corresponding defines:

PAD_GROUP_0_27: GPIO0 - GPIO27. Use this for the main GPIO header. PAD_GROUP_28_45: GPIO28 - GPIO45. Use this to configure the P5 header. PAD_GROUP_46_53: GPIO46 - GPIO53. Internal, you probably won't need this. The action is only executed if @onAnyAction has been configured to perform events in device actions.

The value returned will be true/false for 'slew' and 'hysteresis'. The value returned will be the drive current in mA for 'current'.

The first parameter is the GPIO group you want to read.

The second parameter is the bitmask you want to check.

Examples:

  1. Check if slew is unlimited or limited on gpio group 0-27.
await server.rpioReadPad('PAD_GROUP_0_27', 'slew'); // Returns true/false which is unlimited/limited
  1. Check if hysteresis is enabled or disabled on gpio group 0-27.
await server.rpioReadPad('PAD_GROUP_0_27', 'hysteresis'); // Returns true/false which is enabled/disabled
  1. Check the drive current in mA on gpio group 0-27.
await server.rpioReadPad('PAD_GROUP_0_27', 'current'); // Returns an even number 2-16 in mA

server.rpioWritepad(group, slew?, hysteresis?, current?)

Write the state of the GPIO pad control for the specified GPIO group. On current models of Raspberry Pi there are three groups with corresponding defines:

PAD_GROUP_0_27: GPIO0 - GPIO27. Use this for the main GPIO header. PAD_GROUP_28_45: GPIO28 - GPIO45. Use this to configure the P5 header. PAD_GROUP_46_53: GPIO46 - GPIO53. Internal, you probably won't need this. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when the pad control has been written to.

The first parameter is the GPIO group you want to read.

The second parameter is a boolean to set the slew rate to unlimited or limited.

The third parameter is a boolean to enable or disable hysteresis.

The fourth parameter is an even number between 2-16 to set the drive current.

Examples:

  1. Change the gpio group 0-27 to enable hysteresis and set the drive current to 12mA. Slew rate is unchanged.
server.rpioWritepad('PAD_GROUP_0_27', undefined, true, 12);

server.rpioPud(pin, state)

Configure the pin's internal pullup or pulldown resistors. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when the pin has been configured.

The first parameter is the pin on the physical server.

The second parameter is 'PULL_OFF', 'PULL_DOWN' or 'PULL_UP' and can be used to configure the pin's resistors.

Examples:

  1. Configure pin 11 to enable the pulldown resistor.
var led_pin = 11;
server.rpioPud(led_pin, 'PULL_DOWN');
  1. Disable configured resistors on pin 11.
var led_pin = 11;
server.rpioPud(led_pin, 'PULL_OFF');

server.rpioPoll(pin, cb, options)

Watch pin for changes and execute the callback cb() on events. To stop watching for pin changes, call .rpioPoll() again, setting the callback to null (or anything else which isn't a function). The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when

The first parameter is the pin on the physical server.

The second parameter is the callback executed on events.

The third parameter is 'POLL_LOW', 'POLL_HIGH' or 'POLL_BOTH' and can be optionally used to watch for specific events.

Examples:

  1. Poll pin 15 forever, and poll pin 16 to stop all polling.
function nuke_button(pin) {
console.log('Nuke button on pin %d pressed', pin);
/* No need to nuke more than once. */
server.rpioPoll(pin, null);
}

function regular_button(pin) {
/* Watch pin 15 forever. */
console.log('Button event on pin %d, is now %d', pin, server.rpioRead(pin));
}

/*
* Pin 15 watches for both high and low transitions. Pin 16 only watches for
* high transitions (e.g. the nuke button is pushed).
*/
server.rpioPoll(15, regular_button);
server.rpioPoll(16, nuke_button, 'POLL_HIGH');

server.rpioClose(pin, options)

Indicate that the pin will no longer be used, and clear any poll events associated with it. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when the pin has been closed.

The first parameter is the pin on the physical server.

The second parameter is 'PIN_RESET' or 'PIN_PRESERVE' and can be used to configure the state that pin will be left in after close.

Examples:

  1. Close pin 11 and let the state reset by default.
var led_pin = 11;
server.rpioOpen(led_pin, 'OUTPUT', 'LOW');
server.rpioClose(led_pin);
  1. Close pin 11 and preserve the state.
var led_pin = 11;
server.rpioOpen(led_pin, 'OUTPUT', 'LOW');
server.rpioClose(led_pin, 'PIN_PRESERVE');

server.rpioI2CBegin()

Initializes i²c for use. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when i²c has been initialized.

Examples:

  1. Initialize i²c.
server.rpioI2CBegin();

server.rpioI2CSetSlaveAddress()

Configure the slave address. This is between 0 - 0x7f. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when the slave address has been set.

The first parameter is a number. The slave address to set.

Examples:

  1. Set the slave address.
server.rpioI2CSetSlaveAddress(0x20);

server.rpioI2CSetBaudRate(rate)

Set the baud rate. Directly set the speed in hertz. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when rate has been set.

The first parameter is the i2c refresh rate in hertz.

Examples:

  1. Set the rate to 100kHz.
server.rpioI2CSetBaudRate(100000);

server.rpioI2CSetClockDivider(rate)

Set the baud rate. Set it based on a divisor of the base 250MHz rate. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when rate has been set.

The first parameter is the i2c refresh rate based on a divisor of the base 250MHz rate.

Examples:

  1. Set the rate to 100kHz. (250MHz / 2500 = 100kHz)
server.rpioI2CSetClockDivider(2500);

server.rpioI2CRead(rx, length?)

Set the baud rate. Set it based on a divisor of the base 250MHz rate. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when rate has been set.

The first parameter is the buffer to read.

The second parameter is the length of the buffer.

Examples:

  1. Reads 16 bytes.
await server.rpioI2CRead([32], 16);

server.rpioI2CWrite(tx, length?)

Set the baud rate. Set it based on a divisor of the base 250MHz rate. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when rate has been set.

The first parameter is the buffer to write.

The second parameter is the length of the buffer.

Examples:

  1. Sends 4 bytes.
server.rpioI2CWrite([0x0b, 0x0e, 0x0e, 0x0f]);

server.rpioI2CEnd()

Turn off the i²c interface and return the pins to GPIO. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when i²c has been turned off.

Examples:

  1. Turn off i²c.
server.rpioI2CEnd();

server.rpioPWMSetClockDivider(rate)

Set the PWM refresh rate. This is a power-of-two divisor of the base 19.2MHz rate, with a maximum value of 4096 (4.6875kHz). The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when the rate has been set.

The first parameter is a power-of-two divisor.

Examples:

  1. Set PWM refresh rate to 300kHz
server.rpioOpen(12, 'PWM');
server.rpioPWMSetClockDivider(64);

server.rpioPWMSetRange(pin, range)

Set the PWM range for a pin. This determines the maximum pulse width. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when maximum width has been set.

The first parameter is the pin on the physical server.

The second parameter is the maximum width of your modulation.

Examples:

  1. Set the max width to 1024.
server.rpioOpen(12, 'PWM');
server.rpioPWMSetRange(12, 1024);

server.rpioPWMSetData(pin, width)

Set the PWM width for a pin. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when the width has been set.

The first parameter is the pin on the physical server.

The second parameter is the width of your modulation.

Examples:

  1. Set the current width to 512.
server.rpioOpen(12, 'PWM');
server.rpioPWMSetData(12, 512);

server.rpioSPIBegin()

Initiate SPI mode. Once SPI is enabled, the SPI pins are unavailable for GPIO use until server.rpioSPIEnd() is called. SPI requires gpiomem: false and root privileges. server.rpioSPIBegin() will call server.rpioInit() with the appropriate values if you do not explicitly call it yourself. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when SPI mode has been initiated.

Examples:

  1. Initiate SPI mode.
server.rpioSPIBegin();

server.rpioSPIChipSelect(value)

Choose which of the chip select / chip enable pins to control.

ValuePin
0SPI_CE0 (24 / GPIO8)
1SPI_CE1 (26 / GPIO7)
2Both
The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when SPI pin(s) have been enabled.

The first parameter is the value that corresponds to the pin set you want.

Examples:

  1. Enable SPI_CE0.
server.rpioSPIChipSelect(0);

server.rpioSPISetCSPolarity(value, polarity)

If your device's CE pin is active high, use this to change the polarity.

ValuePin
0SPI_CE0 (24 / GPIO8)
1SPI_CE1 (26 / GPIO7)
2Both

Setting the polarity to 'HIGH' means it will activate on 'HIGH'. Setting the polarity to 'LOW' means it will activate on 'LOW'. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when polarity has been set.

The first parameter is the value that corresponds to the pin set you want.

The second parameter is the polarity the pin will activate on.

Examples:

  1. Set SPI_CE0 HIGH to activate.
server.rpioSPISetCSPolarity(0, 'HIGH');

server.rpioSPISetClockDivider(rate)

Set the SPI clock speed. The rate is an even divisor of the base 250MHz rate ranging between 0 and 65536. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when the clock speed has been set.

The first parameter is an even divisor of the base 250MHz rate.

Examples:

  1. Set SPI speed to 1.95MHz
server.rpioSPISetClockDivider(128);

server.rpioSPISetDataMode(mode)

Set the SPI Data Mode.

ModeCPOLCPHA
000
101
210
311

The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when a data mode has been set.

The first parameter is the data mode you want to set.

Examples:

  1. Set the data mode to 0.
server.rpioSPISetDataMode(0);

server.rpioSPITransfer(tx)

Send and recieve data via SPI. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a buffer the same size as the buffer sent.

The first parameter is an array of 8bit chunks (bytes) of information to send.

Examples:

  1. Send the bytes [0x01, 0x01] and recieve the response from the server.
await server.rpioSPITransfer([1,1]);

server.rpioSPIWrite(tx)

Send data via SPI. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when the buffer has been sent.

The first parameter is an array of 8bit chunks (bytes) of information to send.

Examples:

  1. Send the bytes [0x01, 0x01].
server.rpioSPIWrite([1,1]);

server.rpioSPIEnd()

Release the pins back to general purpose use. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves when the clock speed has been set.

Examples:

  1. Release the pins back to general purpose use.
server.rpioSPIEnd();

server.serialConnect()

Establish the connection to the bluetooth serial device. Currently only one device is supported at a time. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves on the 'open' event.

The first parameter is a friendly device name. The second parameter is a string with the path to the device. The third parameter is an object with the options you want to connect to the device with. {boolean} [autoOpen=true] Automatically opens the port on nextTick. {number} [baudRate=9600] The baud rate of the port to be opened. This should match one of the commonly available baud rates, such as 110, 300, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 57600, or 115200. Custom rates are supported best effort per platform. The device connected to the serial port is not guaranteed to support the requested baud rate, even if the port itself supports that baud rate. {number} [dataBits=8] Must be one of these: 8, 7, 6, or 5. {number} [highWaterMark=65536] The size of the read and write buffers defaults to 64k. {boolean} [lock=true] Prevent other processes from opening the port. Windows does not currently support false. {number} [stopBits=1] Must be one of these: 1 or 2. {string} [parity=none] Must be one of these: 'none', 'even', 'mark', 'odd', 'space'. {boolean} [rtscts=false] flow control setting {boolean} [xon=false] flow control setting {boolean} [xoff=false] flow control setting {boolean} [xany=false] flow control setting {object} bindingOptions sets binding-specific options {Binding} Binding The hardware access binding. Bindings are how Node-Serialport talks to the underlying system. Will default to the static property Serialport.Binding. {number} [bindingOptions.vmin=1] see man termios LinuxBinding and DarwinBinding {number} [bindingOptions.vtime=0] see man termios LinuxBinding and DarwinBinding

Examples:

  1. Connect to the device '/dev/rfcomm0' with the baudRate option set to 9600. Give it the name "device01" so the server can keep track of it.
await server.serialConnect("device01", "/dev/rfcomm0", {
baudRate: 9600,
});

server.serialStream()

Parses and returns the serial stream to the event tag @onSerialData. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Shouts data to the @onSerialData event tag.

The first parameter is the bot id of the bot you want to stream the data to. The second parameter is a friendly device name.

Examples:

  1. In the first tag, create the serial connection and stream the data. Pass the name "device01" so the server can find the device.

await server.serialConnect("device01", "/dev/rfcomm0", {
baudRate: 9600,
});
server.serialStream("1a2b3", "device01");
  1. In the second tag, see the data update. This must be an @onSerialData event tag.
tags.data=that;

server.serialOpen()

Opens the serial connection if you set the option in serialConnect to {autoOpen: false} The action is only executed if @onAnyAction has been configured to perform events in device actions.

The first parameter is a friendly device name.

Returns a promise that resolves on the 'open' event.

Examples:

  1. Create the serial connection with autoOpen false and manually open it afterwards. Give it the name "device01" so the server can keep track of it.
await server.serialConnect("device01", "/dev/rfcomm0", {
baudRate: 9600,
autoOpen: false
});

await server.serialOpen();

server.serialUpdate()

Updates the SerialPort object with a new baudRate. The action is only executed if @onAnyAction has been configured to perform events in device actions.

The first parameter is a friendly device name. The second parameter is an object with the baudRate you want to update the connection with. The third parameter is a callback.

Examples:

  1. Create the serial connection, then update the baudRate.
await server.serialConnect("device01", "/dev/rfcomm0", {
baudRate: 9600,
});

await server.serialUpdate("device01", {baudRate: 14400});

server.serialWrite()

Writes the provided data/command to the device. Might be single-quote/double-quote sensitive. The action is only executed if @onAnyAction has been configured to perform events in device actions.

The first parameter is a friendly device name. The second parameter is a string with the data/command to send. The third parameter is the encoding, if chunk is a string. Defaults to 'utf8'. Also accepts 'utf16le', 'latin1', 'ascii', 'base64', 'binary', 'ucs2', and 'hex' The fourth parameter is a callback.

Examples:

  1. Create the serial connection. Send some data encoded as utf8.
await server.serialConnect(""device01", /dev/rfcomm0", {
baudRate: 9600,
});

await server.serialWrite("device01", '#READ:0', 'utf8');

server.serialRead()

Request a number of bytes from the device. The action is only executed if @onAnyAction has been configured to perform events in device actions.

If no data is available to be read, null is returned.

The first parameter is a friendly device name. The second parameter is the number of bytes to read.

Examples:

  1. Create the serial connection. Read 8 bytes of data.
await server.serialConnect("device01", "/dev/rfcomm0", {
baudRate: 9600,
});

await server.serialRead("device01", 8);

server.serialClose()

Closes an open connection. The action is only executed if @onAnyAction has been configured to perform events in device actions.

Returns a promise that resolves on the 'close' event.

The first parameter is a friendly device name. The second parameter is a callback.

Examples:

  1. Create the serial connection. Close the serial connection.
await server.serialConnect("device01", "/dev/rfcomm0", {
baudRate: 9600,
});

await server.serialClose("device01");

server.serialFlush()

Flush discards data that has been received but not read, or written but not transmitted by the operating system. The action is only executed if @onAnyAction has been configured to perform events in device actions.

The first parameter is a friendly device name.

Returns a promise that resolves once the data has been flushed.

Examples:

  1. Create the serial connection. Flush the serial connection.
await server.serialConnect("device01", "/dev/rfcomm0", {
baudRate: 9600,
});

await server.serialFlush("device01");

server.serialDrain()

Waits until all output data is transmitted to the serial port. After any pending write has completed, it calls tcdrain() or FlushFileBuffers() to ensure it has been written to the device. The action is only executed if @onAnyAction has been configured to perform events in device actions.

The first parameter is a friendly device name.

Returns a promise that resolves once the data has been drained.

Examples:

  1. Create the serial connection. Drain the serial connection.
await server.serialConnect("device01", "/dev/rfcomm0", {
baudRate: 9600,
});

await server.serialDrain("device01");

server.serialPause()

Causes a stream in flowing mode to stop emitting 'data' events, switching out of flowing mode. Any data that becomes available remains in the internal buffer. The action is only executed if @onAnyAction has been configured to perform events in device actions.

The first parameter is a friendly device name.

Examples:

  1. Create the serial connection. Pause the serial connection.
await server.serialConnect("device01", "/dev/rfcomm0", {
baudRate: 9600,
});

await server.serialPause("device01");

server.serialResume()

Causes an explicitly paused, Readable stream to resume emitting 'data' events, switching the stream into flowing mode. The action is only executed if @onAnyAction has been configured to perform events in device actions.

The first parameter is a friendly device name.

Examples:

  1. Create the serial connection. Pause the serial connection. Resume the serial connection.
await server.serialConnect("device01", "/dev/rfcomm0", {
baudRate: 9600,
});

await server.serialPause("device01");

await server.serialResume("device01");

server.browseHistory()

Loads the history space into the current inst. The history space is read-only and contains all the marks that have been created for the inst. Each mark is a bot that is placed in the #history dimension.

Returns a promise that resolves when the history bots are loaded.

Examples:

  1. Load the history space.
await server.browseHistory();

server.markHistory(options)

Marks the current state as a save point in history. This save point can be restored by using the server.restoreHistoryMark(mark) action. Note that this only saves bots in the shared space. local and tempLocal bots are unaffected.

Returns a promise that resolves when the history mark has been created.

The first parameter are the options that should be used to mark the history point. It should be an object with the following properties:

  • message - The message that the new mark should have. Use this as a way to communicate what was special about this save point.

Examples:

  1. Save the current state of the shared space.
await server.markHistory({
message: 'First Version of my AUX'
});

server.restoreHistoryMark(mark)

Restores the current state to the state that was saved by the given mark. This will create a new mark with any unsaved changes and another mark with the state that was saved by the given mark.

Returns a promise that resolves when the history mark has been restored.

The first parameter is the bot or bot ID of the mark that should be restored. You can find available marks in the current inst by using the server.browseHistory() action.

Examples:

  1. Restore the state to a given mark.
// Find a random mark that was loaded by server.browseHistory()
let mark = getBot(byTag("#history", true));

// Restore the current state to the given mark.
await server.restoreHistoryMark(mark);

server.restoreHistoryMarkToInst(mark, inst)

Restores the state in the given inst to the state that was saved by the given mark. This will create a new mark with any unsaved changes in the inst and another mark with the state that was saved by the given mark.

Returns a promise that resolves when the history mark has been restored.

The first parameter is the bot or bot ID of the mark that should be restored. You can find available marks in the current inst by using the server.browseHistory() action.

The second parameter is the inst that the state should be restored to. If null or an empty string, then the current inst will be restored.

Examples:

  1. Restore the state of the test inst to a given mark.
// Find a random mark that was loaded by server.browseHistory()
let mark = getBot(byTag("#history", true));

// Restore the current state to the given mark.
await server.restoreHistoryMarkToInst(mark, "test");

server.shell(script)

Executes the given script on the server.

The first parameter is the shell script that should be executed.

server.loadFile(path, options?)

Loads a file from the server at the given path.

Note that on a Raspberry PI, all USB storage devices are mapped into the /drives directory based on the port they were plugged into. Loading a file from a USB drive is as simple as specifying the file name. If multiple USB drives are plugged in and have files with the same name, then the file from the USB drive in the smallest numbered port is used.

Returns a promise that resolves with the data in the file.

The first parameter is the path that the file should be loaded from. This is usually just the full name of the file to load. (name + file extension)

The second parameter are the options that should be used for loading the file.

Examples:

  1. Load a file named "book.txt" and trigger a @onBookLoaded shout when it is loaded.
server.loadFile('book.txt', {
callbackShout: 'onBookLoaded'
});
  1. Load a file named "book.txt" from drive 2 and trigger a @onBookLoaded shout when it is loaded.
server.loadFile('/2/book.txt', {
callbackShout: 'onBookLoaded'
});
  1. Load a file named "book.txt" and toast the contents.
const result = await server.loadFile('book.txt');
os.toast(result.data);

server.saveFile(path, data, options?)

Saves a file at the given path with the given data. If the file already exists, then the options are used to determine if the file should be overwritten. By default the file will not be overwritten.

Note that on a Raspberry PI, all USB storage devices are mapped into the /drives directory based on the port they were plugged into. Saving a file to a USB drive is as simple as specifying the file name. If multiple USB drives are plugged in and a drive is not specified, then the file will be saved to the first drive.

Returns a promise that resolves when the file has been saved.

The first parameter is the path that the file should be saved to. This is usually just the full name of the file to save. (name + file extension)

The second parameter is the data that should be saved into the file.

The third parameter are the options that should be used for saving the file.

Examples:

  1. Save a file named "book.txt" and trigger a @onBookSaved shout when it is saved.
server.saveFile('book.txt', 'My memoirs', {
callbackShout: 'onBookSaved'
});
  1. Save a file named "book.txt" to drive 2 and trigger a @onBookSaved shout when it is loaded.
server.saveFile('/2/book.txt', 'My memoirs', {
callbackShout: 'onBookSaved',
overwriteExistingFile: true
});
  1. Save a file named "book.txt" and send a toast when it is finished.
await server.saveFile('/2/book.txt', 'My memoirs', {
overwriteExistingFile: true
});

os.toast("File Saved!");

Admin Actions

adminSpace.unlock(password)

Unlocks the admin space using the given password. Returns a Promise that resolves once the space is unlocked. The promise will be rejected if the space was unable to be unlocked.

If given the correct password, admin space will be unlocked and become editable.

The first parameter is the password that should be used to unlock admin space.

Examples

  1. Unlock admin space.
try {
await adminSpace.unlock("my-password");
os.toast("Admin Space Unlocked!");
} catch(err) {
os.toast("Failed to unlock admin space " + err);
}

adminSpace.setPassword(oldPassword, newPassword)

Sets the password that should be used to unlock admin space. Returns a Promise that resolves once the password is changed.

If given the correct password, admin space will use the new password.

The first parameter is the password that is currently used to unlock admin space.

The second parameter is the password that should be used to unlock admin space.

Examples

  1. Change the admin space password.
try {
await adminSpace.setPassword("old-password", "new-password");
os.toast("Admin Space Password Changed!");
} catch(err) {
os.toast("Failed to change the password " + err);
}

Analytics Actions

Analytics actions are actions that record events to Simple Analytics.

analytics.recordEvent(name, metadata?)

Records the given event to Simple Analytics using their Events API. Returns a promise that resolves when the event has been recorded.

The first parameter is the name of the event that should be recorded. Must consist of only alphanumeric characters and underscores.

The second parameter is optional and should be an object containing the metadata that should be collected with the event. (See metadata for more information)

Examples

Record an analytics event
await analytics.recordEvent('my_event');
Record an analytics event with some metadata
await analytics.recordEvent('my_event', {
myNumber: 1
});