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