Formula globals
A handful of values are available in every formula, event handler, and method, not properties on any specific object, just always-there context you can reference directly.
Mouse
mouse.x and mouse.y track cursor position, and mouse.down tracks whether the primary button is held - all three are reactive, so a formula referencing them recalculates the moment the mouse moves or the button state changes.
this.x = mouse.x // follow cursor horizontally
this.y = mouse.y // follow cursor vertically
this.opacity = mouse.down ? 0.5 : 1 // dim while pressedKeys
keys.<KeyName> reports whether a specific key is currently held, using the same names JavaScript's own KeyboardEvent.key uses - a, Shift, Control, Enter, ArrowRight, and so on.
// Move with arrow keys
this.x = this.x + (keys.ArrowRight ? 3 : 0) - (keys.ArrowLeft ? 3 : 0)
this.y = this.y + (keys.ArrowDown ? 3 : 0) - (keys.ArrowUp ? 3 : 0)
// Sprint with Shift
speed = keys.Shift ? 6 : 3
this.x = this.x + (keys.ArrowRight ? speed : 0) - (keys.ArrowLeft ? speed : 0)Time, frame, and dt
Three related but distinct globals track playback: time (seconds since play started), frame (an incrementing frame counter), and dt (seconds since the last frame, small and variable, not a fixed step).
// Smooth rotation — genuinely 45 degrees per second, not radians:
// a formula writing to .rotation converts the same way the properties
// panel does, even though the value is stored in radians internally.
this.rotation = time * 45
// Oscillation
this.x = 200 + Math.sin(time * 2) * 100
// Frame counter — blink every 0.5 seconds at 60fps
this.opacity = frame % 60 < 30 ? 1 : 0.5Why dt matters. Without it, movement speed silently depends on frame rate, a device running at 30fps moves half as fast per second as one running at 60fps, for identical formula code. Multiplying by dt fixes that:
// Framerate-dependent — moves at a different real-world speed on different devices
this.x = this.x + 5
// Framerate-independent — 300 pixels per second, regardless of framerate
this.x = this.x + 300 * dtTag
Tag.<name> resolves to a live array of every node currently carrying that tag, and it's genuinely reactive: add, remove, or destroy a tagged node, and every formula reading that tag recalculates automatically.
// Win condition — no bricks left
WinText.visible = Tag.brick.length === 0
// Score display
ScoreBox.width = Tag.coin.length * 20
// Point toward the first enemy
Arrow.rotation = Math.atan2(Tag.enemy[0].y - this.y, Tag.enemy[0].x - this.x) * 180 / Math.PISince it's a plain array under the hood, ordinary array access and .length work exactly as you'd expect, no special tag-query syntax to learn beyond that.
Console
console.log(...) is available and genuinely useful for debugging a formula or event handler mid-development - open your browser's DevTools (F12) to see the output.
console.log("Hit:", event.target.name, "at", event.point.x, event.point.y)Math
The full set of standard Math methods is available directly.
// Distance between two nodes
distance = Math.sqrt((A.x - B.x) ** 2 + (A.y - B.y) ** 2)
// Angle from this node toward the mouse
angle = Math.atan2(mouse.y - this.y, mouse.x - this.x)
// Clamp a value into a range
value = Math.max(0, Math.min(100, rawValue))This list covers the always-available globals - for reading and binding an individual object's own properties, see Reactive properties and formulas; for the click/collision/tick events that run code (rather than just compute a value), see Events and methods.