Scripting
The script lifecycle, the ctx global, and how to read input, move objects, and find things in the scene.
Core concepts introduced scripts in a paragraph. This page is the reference: the lifecycle, the ctx global, and the shapes you'll reach for most.
The lifecycle
A script is JavaScript attached to an object. The engine calls three functions, each optional:
| Function | When it runs |
|---|---|
init() | Once, when the game starts. |
update() | Every frame — movement, input, game logic. |
onMessage(message) | When the object receives an event or message. |
/** @type {ScriptInit} */
function init() {
// set things up
}
/** @type {ScriptUpdate} */
function update() {
// runs ~60 times a second
}
/** @type {ScriptOnMessage} */
function onMessage(message) {
// react to collisions, triggers, or messages from other scripts
}The functions take no ctx parameter. ctx is a global that's always available inside any of them — there's nothing to pass around.
The ctx object
ctx is your handle to the engine. The pieces you'll reach for most:
| Member | What it gives you |
|---|---|
ctx.entity | The object this script is attached to (its components, name, id, children). |
ctx.scene | The scene the object lives in. |
ctx.input | Keyboard and mouse state this frame. |
ctx.time | delta (seconds since last frame) and elapsed (total time). |
ctx.viewport | Current viewport width and height. |
ctx.objects | Find, add, and remove objects in the scene. |
ctx.variables | A shared key/value store every script can read and write. |
ctx.send | Send a message to the engine or other scripts: ctx.send(type, payload). |
ctx.watch | Run a callback when a watched value changes (also ctx.watchKey). |
A few exact shapes worth remembering:
// Read input
ctx.input.keyboard.held["KeyW"]; // true while W is held
ctx.input.pointer.delta; // { x, y } pointer movement this frame
// Read/write this object's position
ctx.entity.components.transform.position.x;
// Find another object
ctx.objects.getById("some-id");
ctx.objects.getAll().find((o) => o.name === "Player");Fields from JSDoc
The JSDoc annotations (/** @type {ScriptInit} */ and friends) are optional but worth keeping — the script editor uses them to give you full autocomplete for ctx and message payloads.
JSDoc also powers fields: declare a variable with @type and @default and it shows up in the Inspector, editable per object without touching code:
/**
* @type {number}
* @default 5
*/
let speed;