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 pressed

Keys

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.5

Why 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 * dt

Tag

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.PI

Since 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.

On this page

Formo

The browser studio where drawings become animations, toys, and games. Your files, open HTML export, nothing to install.