Last updated: June 21, 2026
Purl Syntax Reference
All scripting syntax in one table. Use search at the top of the page.
| Category | Name | Syntax | Details |
|---|---|---|---|
| EVENTS | |||
| Event | onEnter | onEnter: |
Cell or object — fires when player enters cell. All handlers run concurrently (repeat/wait loops don't block other objects' init). Cross-object dependencies: use onMessage |
| Event | onExit | onExit: |
Cell or object — fires when player leaves cell |
| Event | onClick | onClick: |
Cell or object — object fires when clicked, cell fires on background clicks (pointer up over empty canvas). clicked = the object actually under the cursor (useful when a component absorbs clicks on its children) |
| Event | onKeyDown | onKeyDown "Key": |
Cell or object — fires when key pressed. Fires on the cell script and on every non-template object; there's no focus, so every matching handler runs per press. Key names are case-insensitive. Keys: Escape, Space, ArrowUp, ArrowDown, ArrowLeft, ArrowRight, a-z, 0-9. Gamepad — single-controller alias: gamepad-a (Space), gamepad-b (Escape), gamepad-x (e), gamepad-y (q), gamepad-up/down/left/right (arrows). Multi-controller: gamepad-N-a/b/x/y/up/down/left/right with N = 1-based pad index (e.g. gamepad-1-a, gamepad-2-a). Pad 1 fires both indexed and unindexed names (back-compat); pads 2+ only fire indexed names. Ctrl+Escape exits to build mode |
| Event | onKeyUp | onKeyUp "Key": |
Cell or object — fires when key released. Same scope, case-insensitivity, and keys as onKeyDown including gamepad and multi-controller forms |
| Event | onHover | onHover: |
Object — mouse enters bounds |
| Event | onHoverEnd | onHoverEnd: |
Object — mouse leaves bounds |
| Event | onDragStart | onDragStart: |
Cell or object — fires when a drag gesture begins past the threshold. Object scope: drag on this object (auto-moves if draggable). Cell scope: drag on empty canvas or on a non-draggable object with no drag handlers (marquee, lasso, slice, swipe) |
| Event | onDrag | onDrag: |
Cell or object — fires each frame while dragging. Use clickX/clickY for current pointer, dragStartX/dragStartY for drag origin |
| Event | onDragEnd | onDragEnd: |
Cell or object — fires once when pointer is released. clickX/clickY is release position; dragStartX/dragStartY is drag origin; dragDuration is total ms |
| Event | onScroll | onScroll: |
Cell or object — mouse-wheel / trackpad scroll. Fires on the object under the pointer if it has a handler, otherwise on the cell (bubbles to an ancestor component). scrollY = vertical amount (mouse notch ≈ ±1, fractional on trackpads; >0 = down/toward you), scrollX = horizontal; clickX/clickY = pointer world position. One scroll = one event (no start/end). Apply zoom multiplicatively |
| Event | onTap | onTap: |
Plotter (chart) — fires when tapped. dataX/dataY = tapped point in the chart's data values; datum = the data row of the nearest marker, or 0 if none; tapLayer = which layer it came from. Use for click-to-locate or selecting a marker |
| Event | onPan | onPan: |
Plotter — fires while you drag to pan an interactive chart. viewMinX/viewMaxX = the new visible data range. e.g. turn off auto-follow when the user pans by hand |
| Event | onZoom | onZoom: |
Plotter — fires when you wheel-zoom an interactive chart. viewMinX/viewMaxX = new visible range (span = viewMaxX - viewMinX) |
| Event | onOverlap | onOverlap: |
Object — starts overlapping another. Requires sensor on one object. Use other to reference |
| Event | onOverlapEnd | onOverlapEnd: |
Object — stops overlapping |
| Event | onCollide | onCollide: |
Object — hits a blocker. Use other to reference blocker |
| Event | onMove | onMove: or onMove "dir": |
Object — movement starts. Directions: up, down, left, right |
| Event | onRotate | onRotate: or onRotate "dir": |
Object — rotation starts/changes. Directions: cw (clockwise), ccw (counter-clockwise) |
| Event | onStop | onStop: |
Object — movement stops (any reason: wall hit, input released, path bend) |
| Event | onArrive | onArrive: |
Object — reached moveTo/click-to-move target. Use for waypoint patrol instead of onStop |
| Event | onTick | onTick: |
Object — fires every physics frame (~60fps). deltaTime variable available (seconds). Use for continuous logic |
| Event | onJump | onJump: |
Object — jump triggered. Requires jumpable |
| Event | onLanding | onLanding: |
Object — lands on surface |
| Event | onBounds | onBounds: |
Object — fires when object crosses cell boundary. Optional direction filter: onBounds "left", "right", "top", "bottom". Fires once per crossing. Movable objects only |
| Event | onAudioEnd | onAudioEnd: |
Audio object — fires when non-looping playback finishes. Use for sequencing tracks |
| Event | onSpawn | onSpawn: |
Object — fires when spawned at runtime |
| Event | onDestroy | onDestroy: |
Object — fires before destruction |
| Event | onSubmit | onSubmit: |
Object — fires when Enter pressed in editable text. self.content has the submitted text |
| Event | onDefocus | onDefocus: |
Object — fires when editable text loses focus (click elsewhere or Escape) |
| Event | onBreak | onBreak: |
Peg — fires when constraint breaks (force exceeds breakForce) |
| Event | onMessage | onMessage "MSG": |
Cell or object — receives shout. Top-level only — cannot be nested inside repeat, if, or other blocks. Runs concurrently with other handlers. To react to a message inside a loop, set a variable in the handler and check it in the loop |
| Event | onMessageFrom | onMessageFrom "Source" "MSG": |
Cell or object — receives shout from specific sender. Same top-level restriction as onMessage |
| Event | Combined | onClick | onKeyDown "Space": |
Multiple events trigger same code |
| COMMANDS | |||
| Command | goto | goto "CellName" |
Navigate to cell. Directions: north, east, south, west. Transitions: with fade, with slide-up, etc. Reset: clean (reset objects, keep vars), fresh (reset all) |
| Command | goto transition | goto "Room" with fade 500 |
Navigate with transition animation. Duration in ms or expression: random(200,500) |
| Command | goto reset | goto "Room" clean or goto "Room" fresh |
Navigate with reset level. Combinable: goto "Room" clean with fade |
| Command | restart | restart |
Go to start cell + full reset. restart cell restarts current cell |
| Command | endGame | endGame |
Exit play mode. In studio returns to build mode, in player stops the game |
| Command | show | show X or show X with fade 300 |
Make object visible. Transitions: fade, scale, slide-up, slide-down. Text-only: typewriter, word, scramble, redact. Duration in ms or expression: random(200,500) |
| Command | hide | hide X or hide X with fade 300 |
Make object invisible. Transitions: fade, scale, slide-up, slide-down. Text-only: typewriter, word, scramble, redact. Duration in ms or expression: random(200,500) |
| Command | spawn | spawn "Template" {params} |
Create object at runtime from a template (quoted name). Params: x, y, cellX, cellY, custom |
| Command | spawn type | spawn shape "Name" {params} |
Create a fresh object from a prime type — no template needed. Types: shape, text, line, grid, audio, emitter, mask, peg, viewport, data, component; shape sugar: rect/rectangle, circle, ellipse, polygon, path. Params set properties (and reach onSpawn); fully scriptable, destroy-able. For data-driven visuals/HUDs |
| Command | spawn at | spawn "Template" at AnchorName |
Spawn at anchor position/rotation. If anchor is inside a component, spawned object becomes a child |
| Command | destroy | destroy X or destroy X with fade 300 |
Remove object from scene. Works on spawned and design-time objects. Design-time objects reappear on reset. Transitions: fade, scale, slide-up, slide-down. Duration in ms or expression. Targets: name, self, other, parent, siblings, children, #tag |
| Command | addTag | addTag self #robot |
Add tag to object at runtime. Targets: name, self, other, #tag, all type. No-op if tag already exists |
| Command | removeTag | removeTag self #robot |
Remove tag from object at runtime. Same targets as addTag. No-op if tag not present |
| Command | set variable | set score 10 |
Create/update variable |
| Command | set property | set X.opacity 0.5 |
Change object property. Position writes (set X.x, set X.y) and visual writes (rotation, opacity, etc.) are this-frame. Motion writes (velocityX/Y, angularVelocity, gravityScale, etc.) take effect at the next physics tick |
| Command | set property (tween) | set X.opacity 0 over 500 |
Smooth transition over duration (ms). Optional easing |
| Command | set property (easing) | set X.x 0.8 over 300 ease-out |
Easing: linear, ease-in, ease-out, ease-in-out, ease-in-cubic, ease-out-cubic, ease-in-out-cubic |
| Command | set state (tween) | set X.state "RED" over 500 |
Tween from current to target state over N ms |
| Command | set state (tween+mod) | set X.state "RED" position over 300 cw |
Modifiers before over. Optional cw/ccw for rotation direction |
| Command | set (expression) | set self.visible sandbags >= 1 |
The value side accepts any expression — arithmetic (a + b), comparisons (>=, <, ==, !=), boolean ops (and, or, not X), property access, function calls. The expression is evaluated and the result assigned. |
| Command | set (toggle) | set X.visible not X.visible |
Idiom for flipping a boolean property — reads current value, negates it, writes it back. |
| Command | set (array literal) | set scores [10, 20, 30] |
Assign an array literal. Elements can be any expression. |
| Command | set (map literal) | set cfg {alt: 30000, fuel: 100} |
Assign a map literal. Keys are identifiers; values are any expression. |
| Command | set (indexed) | set arr[0] 99 or set Data.value[0].field x |
Replace at index, optionally drilled into a field. Auto-grows arrays with null on out-of-bounds writes. |
| Command | set (deep nested) | set cfg.weather.wind.gust 5 |
Drill into nested maps and set the leaf. Sibling slots stay untouched. |
| Command | push | push items 5 |
Append to the end of an array. |
| Command | push first | push first items 99 |
Prepend to the front of an array. |
| Command | insert | insert items at 2 99 |
Insert at a specific index, shifting subsequent elements. Index out of range is a no-op + console error. |
| Command | remove (index) | remove items[3] |
Remove an array element at index, shifting remaining elements down. |
| Command | remove (key) | remove cfg.foo |
Remove a key from a map (last dotted segment is the key). |
| Command | enable | enable X movable |
Enable capability (movable, jumpable, draggable, keyboard, click, gamepad, subject, follow, avoid). Target: name, self, other, self.Child, parent, siblings, children, #tag |
| Command | disable | disable X movable |
Disable capability. Same targets as enable |
| Command | clear grid | clear Grid |
Clear all cell data |
| Command | clear cell | clear Grid.cell[x][y] |
Clear one cell's data |
| Command | shout | shout "MSG" {key: val} |
Send message to current cell listeners. Params optional, accessed as variables in handler |
| Command | shout global | shout "MSG" global |
Send message to ALL cells' listeners (cross-cell broadcast) |
| Command | shout to | shout to X "MSG" {key: val} |
Send message to specific object or #tag. Params optional |
| Command | reset | reset session |
Reset variables. Scopes: session, game, all, objects (reset objects, keep vars), fresh (reset objects + vars), visits (reset current cell visit count) |
| Command | reset script | reset script |
Reset sequential onClick counter |
| Command | wait time | wait 500ms or wait 2s |
Pause execution. Accepts expressions: wait delay, wait random(1000,3000), wait (baseTime * 2) |
| Command | wait movement | wait movement |
Pause until all movement settles |
| Command | wait movement (target) | wait movement self |
Pause until specific object stops. Also: wait movement ObjName |
| Command | sync | sync |
Synchronize parallel scripts |
| Command | copy | copy value |
Copy to clipboard. Only works from user events (onClick, onKeyDown) |
| Command | log | log "text" value |
Debug output to console |
| Command | openUrl | openUrl url [newTab] |
Open URL in browser. newTab opens in new tab instead of current window |
| Command | post | post url {data} |
HTTP POST request |
| Command | fetch | fetch url into var |
HTTP GET into variable |
| Command | transition | transition fade 500 |
Cell entrance animation. Types: fade, slide-up, slide-down, slide-left, slide-right, zoom |
| Command | return | return or return expr |
Exit the current action, function, or onTick: block early. Inside a function, return expr gives back the value |
| Command | break | break |
Exit current loop |
| Command | save | save "checkpoint" |
Save game state to named slot. Stores all variables, object states, visited cells, spawned objects, physics positions/velocities, and current cell |
| Command | load | load "checkpoint" |
Restore game state from named slot and navigate to saved cell. Sets newGame to false. Silently ignored if slot doesn't exist |
| Command | delete save | delete save "checkpoint" |
Delete a save slot |
| Command | reveal | reveal Mask1 0.5 0.5 |
Punch transparent hole in mask. Args: mask name, x, y (mask-relative coords). Optional: radius, fade. reveal Mask1 self.x self.y 0.05 0.02 |
| Command | rehide | rehide Mask1 |
Reset mask fog to fully opaque. Resets base canvas + all revealer layers. rehide Mask1 Player resets only Player's revealer layer. Target accepts names, dotted paths, self/other, and special refs (parent, siblings, root) — e.g. rehide self.Cup.Mask |
| Command | inject | inject Source above Target or inject Source below Target |
Render Source at Target's slot in the draw order, regardless of which component owns either one. Source keeps its parent, transforms, scripts, lifetime — only its render position moves. Both Source and Target accept names, dotted paths (Compo.Child), self, other, and special refs (parent, siblings, root) — including mid-path forms like self.X.children.Y. One injection per object — repeated inject replaces the previous anchor. Runtime-only (volatile per play session) |
| Command | clear inject | clear inject Source |
Remove the injection anchor — Source returns to rendering at its authored position. Common idiom: clear inject self |
| ANIMATION | |||
| Animate | group | animate X "group" loop |
Play state group animation. Modes: loop, once, pingpong |
| Animate | group fps | animate X "group" fps 12 once |
Frame mode with custom FPS |
| Animate | group duration | animate X "group" duration 500 loop |
Tween mode with duration per step (ms) |
| Animate | group easing | animate X "group" duration 300 ease-in-out |
Tween easing. Values below |
| Animate | group resume | animate X "group" loop resume |
Don't restart if running; smooth entry when starting |
| Animate | group cw/ccw | animate X "group" loop cw |
Force clockwise rotation interpolation (ccw for counter-clockwise) |
| Animate | group exclusive | animate X "group" loop exclusive |
Stop all other group animations on this object before starting |
| Animate | stop | stop animate X |
Stop all group animations on object |
| Animate | shake | shake X 300 |
Horizontal oscillation (duration in ms) |
| Animate | vibrate | vibrate X 300 or vibrate X loop |
Rapid micro-jitter. Optional intensity (default: 2) |
| Animate | pulse | pulse X 300 or pulse X loop |
Scale breathe effect. Optional scale (default: 1.15) |
| Animate | squeeze | squeeze X 300 |
Squash & stretch. Optional direction: horizontal, vertical |
| Animate | bounce | bounce X 300 |
Vertical hop with squash. Optional height (default: 20) |
| Animate | spin | spin X 300 |
360° rotation. Optional direction: cw, ccw. On components, rotates as a unit; add children for per-child effect |
| Animate | glow | glow X 1000 or glow X 500 loop |
Pulsing glow effect. Optional color: glow X 1500 loop "#ff0000" |
| Animate | sway | sway X 5 1.2 rotation |
Continuous wobble around pivot. Args: amplitude period [axis]. Period in seconds; axis: rotation (default), x, y. Always loops; each instance gets a phase offset so tagged groups don't move in lockstep. Stop with stop X sway |
| Animate | stop effects | stop X |
Stop fire-and-forget effects on object |
| Animate | screenshake | screenshake 300 |
Camera/viewport shake. Optional intensity (default 3): screenshake 200 5. Intensity range: screenshake 2000 1-5 (ramps from 1 to 5). Add loop to repeat. Non-looping damps to zero |
| Animate | stop screenshake | stop screenshake |
Stop camera shake |
| COLOR | |||
| Color | saturate | saturate X or saturate X 30 |
Boost saturation of object's colors (fillLayers, strokeColor, textColor). Amount 0–100 HSB units (default 20). Persists. Works on names, self, #tag, all <type>, or scene |
| Color | desaturate | desaturate X or desaturate X 60 |
Reduce saturation. Same args/scope as saturate. desaturate scene 100 = entire viewport b&w via CSS filter; desaturate scene 0 clears |
| Color | huerotate | huerotate X 90 |
Rotate hue in degrees (default 30). Negative reverses. Same target scope |
| Color | lighten | lighten X 15 |
Lighten colors toward white (HSB 0–100, default 20). Stack to ramp |
| Color | darken | darken X 20 |
Darken colors toward black (HSB 0–100, default 20). Stack to ramp |
| Color | invert | invert X |
Invert each color to its complement. No amount |
| AUDIO | |||
| Audio | play | play Music |
Start or resume playback |
| Audio | play loop | play Music loop |
Play with looping |
| Audio | play fadeIn | play Music fadeIn 2000 |
Play with volume fade-in (ms) |
| Audio | play tag | play #music fadeIn 500 |
Fan out to every audio object carrying the tag. Combine with loop / fadeIn. Starts a fresh shared player if none was running yet |
| Audio | pause | pause Music |
Pause; next play resumes from where it stopped. Halts even if autoplay or another script is also playing the audio |
| Audio | pause fadeOut | pause Music fadeOut 1000 |
Fade out then pause (ms) |
| Audio | pause tag | pause #music fadeOut 500 |
Fan out to every audio object carrying the tag |
| Audio | stop | stop Music |
Stop and rewind to start. Halts even if autoplay or another script is also playing the audio |
| Audio | stop fadeOut | stop Music fadeOut 2000 |
Fade out then stop (ms) |
| Audio | onAudioEnd | onAudioEnd: |
Fires when non-looping audio finishes playing |
| Audio | volume | set Music.volume 0.5 |
Set volume (0-1) |
| Audio | loop | set Music.loop true |
Set loop property |
| Audio | startMarker | set Music.startMarker 5 |
Start position in seconds |
| Audio | duration | set Music.duration 10 |
Playback duration from start marker in seconds |
| Audio | autoplay | Object property | Auto-play on cell enter |
| Audio | extend | Object property | Keep playing across cell transitions |
| Audio | buffered | Object property | Independent playback per instance (default: true for SFX) |
| Audio | spatial | Object property | Distance-based volume from camera subject |
| Audio | spatialRange | Object property | Distance (0-1) where volume reaches 0 (default: 1.0) |
| EMITTER | |||
| Emitter | emitterShape | Object property | Emit shape: "circle" (outward) or "rectangle" (top edge inward) |
| Emitter | emitterRate | Object property | Particles per second (default: 10) |
| Emitter | emitterBurst | Object property | Set to N to emit N particles instantly (resets to 0) |
| Emitter | particleLifetime | Object property | Particle lifetime in ms (default: 1000) |
| Emitter | particleSpeedMin | Object property | Min speed canvas-units/sec (default: 0.1) |
| Emitter | particleSpeedMax | Object property | Max speed canvas-units/sec (default: 0.3) |
| Emitter | particleSpread | Object property | Emission arc degrees — circle: cone width, rectangle: deviation (default: 30) |
| Emitter | particleShape | Object property | Particle shape: "circle", "square", or "line" |
| Emitter | particleTrailLength | Object property | Trail positions (0=off, default: 0) |
| Emitter | particleSizeStart | Object property | Starting size px (default: 6) |
| Emitter | particleSizeEnd | Object property | Ending size px (default: 2) |
| Emitter | particleOpacityStart | Object property | Starting opacity 0-1 (default: 1) |
| Emitter | particleOpacityEnd | Object property | Ending opacity 0-1 (default: 0) |
| Emitter | particleColorA | Object property | Spawn color range start (default: #ffffff) |
| Emitter | particleColorB | Object property | Spawn color range end (default: #ffffff) |
| Emitter | particleColorEnd | Object property | Optional fade-to color over lifetime |
| Emitter | particleGravityX | Object property | World gravity X (default: 0) |
| Emitter | particleGravityY | Object property | World gravity Y (default: 0) |
| Emitter | particleDrag | Object property | Velocity damping 0-1/sec (default: 0) |
| Emitter | emitterGlow | Object property | Halo glow intensity 0-1 (default: 0) |
| Emitter | emitterGlowSize | Object property | Halo size multiplier (default: 1.5) |
| Emitter | emitterGlowFlicker | Object property | Halo flicker amplitude 0-1 (default: 0) |
| CONTROL FLOW | |||
| Control | if | if condition: |
Conditional block |
| Control | else | else: |
Alternative block |
| Control | else if | else if condition: |
Chained conditional |
| Control | foreach | foreach item in list: |
Iterate over array or tagged objects |
| Control | repeat | repeat: |
Infinite loop — runs until break or cell exit. Use wait for pacing. Reads live variables each iteration |
| Control | repeat N | repeat 5: |
Loop N times |
| Control | first | first #tag where .x > 0: |
Find first matching object |
| Control | action | action name: or action name {a, b, c: default}: |
Reusable named block. Call with do. Params optional; ones with : default can be omitted at the call site. Use for anything that takes time or changes things in the world |
| Control | do | do actionName or do actionName {a: 1, b: x+2} |
Run a custom action. Pass args in braces |
| Control | function | function name(a, b, c): |
Reusable inline calculation. Body uses only set, if/else, and return. Use for things you compute. The editor flags wait/spawn/play etc. and points you at action |
| Control | call function | name(arg1, arg2) |
Use a function's result inline: set d distance(HAB.x, HAB.y, Goose.x, Goose.y) |
| BACKGROUND TASKS | |||
| Task | start | start actionName or start actionName {a: 1} as "name" |
Run an action in the background, spread out over time, so a big job doesn't freeze the game. Returns immediately and your script keeps going (unlike do, which runs it now and waits). as "name" makes it a singleton — starting the same name while it's still running does nothing. Signal completion by shout-ing a message at the end |
| Task | budget | budget 5ms: |
Run the body in small slices instead of all at once — does a sliver of work, lets the game breathe, then picks up a moment later. The smooth-vs-fast dial: smaller = smoother but slower to finish. Only loops get sliced |
| Task | yield | yield |
Inside a loop, hand control back by hand until a moment later. Rarely needed — budget does this for you |
| Task | cancel | cancel "name" |
Stop a named task. Tasks also stop on their own on cell exit or when the object is destroyed |
| TARGETING | |||
| Target | By name | ObjectName |
Direct reference |
| Target | By tag | #tagname |
All objects with tag |
| Target | By type | all shapes |
All objects of type |
| Target | self | self |
Current object |
| Target | self property | self.name, self.x |
Read/write property on current object |
| Target | parent | parent |
Containing component |
| Target | parent property | parent.name, parent.x |
Read/write property on parent component |
| Target | root | root |
Outermost ancestor — walks the parent chain to the top. Returns the object itself when there is no parent, so writes are always safe |
| Target | root property | root.x, other.root.hit |
Read/write property on the outermost ancestor. Useful from a deeply-nested child that needs to talk to the whole component (e.g. a collision-shape sensor reaching the player) |
| Target | siblings | siblings |
Objects at same level |
| Target | children | children |
Contained objects |
| Target | children property | children.opacity |
Read/write property on all children |
| Target | other | other |
Other object in overlap/collision |
| Target | other property | other.name, other.x |
Read property on the other object in overlap/collision |
| Target | Component child | Component.Child |
Child inside component |
| Target | Self child | self.Child.property |
Access child of current component. Read/write: self.Turret.rotation. Mid-path special refs also work: self.Group1.children.visible, parent.X.children.Y |
| Target | Cross-cell | @Cell.Object |
Object in different cell |
| Target | Cross-cell prop | @Cell.Object.property |
Read property from another cell |
| Target | Cross-cell index | @Cell.Data.dataValue.points[i] |
Drill a dotted path and index it in one expression — no need to cache the cross-cell reference into a variable first |
| Target | State read | X.states.StateName.property |
Read property from a named state |
| Target | Cross-cell state | @Cell.Object.states.State.prop |
Read state property from another cell |
| PROPERTIES | |||
| Property | name | X.name |
Object name (read-only) |
| Property | id | X.id |
Object ID (read-only, unique identifier) |
| Property | x | X.x |
Horizontal position (0-1) |
| Property | y | X.y |
Vertical position (0-1) |
| Property | width | X.width |
Width (0-1) |
| Property | height | X.height |
Height (0-1) |
| Property | area | X.area |
Geometric area in cell units² (read-only). Handles rectangle, ellipse, polygon, and curved paths (Bezier sampled). Lines return 0 |
| Property | visible | X.visible |
Boolean visibility |
| Property | clickable | X.clickable |
Boolean — accepts clicks |
| Property | opacity | X.opacity |
Transparency (0-1) |
| Property | blendMode | X.blendMode |
Compositing blend mode: normal, multiply, screen, overlay, darken, lighten, color-dodge, color-burn |
| Property | rotation | X.rotation |
Angle in degrees (0-360) |
| Property | flipX | X.flipX |
Horizontal flip |
| Property | flipY | X.flipY |
Vertical flip |
| Property | zIndex | X.zIndex |
Layer order (higher = on top) |
| Property | content | X.content |
Text content |
| Property | textColor | X.textColor |
Text color |
| Property | fontSize | X.fontSize |
Font size (rem) |
| Property | fontFamily | X.fontFamily |
Font family |
| Property | fontWeight | X.fontWeight |
Font weight (normal, bold, etc.) |
| Property | fontStyle | X.fontStyle |
Font style (normal, italic) |
| Property | textDecoration | X.textDecoration |
Text decoration (none, underline, etc.) |
| Property | textAlign | X.textAlign |
Text alignment (left, center, right) |
| Property | textPadding | X.textPadding |
Text padding |
| Property | lineHeight | X.lineHeight |
Line spacing multiplier (textbox only, default 1.3) |
| Property | verticalAlign | X.verticalAlign |
Vertical text alignment: top, center, bottom (textbox only) |
| Property | editable | X.editable |
Allow typing at runtime (text only). Click to focus, Enter to submit, Escape to revert |
| Property | fillColor | X.fillColor |
Fill color (read/write shorthand) |
| Property | color.color | X.color.color |
Fill color (layer path) |
| Property | color.opacity | X.color.opacity |
Color layer opacity (0-1) |
| Property | fill.color | X.fill.color |
Fill color (alias for color.color) |
| Property | strokeColor | X.strokeColor |
Border color |
| Property | strokeWidth | X.strokeWidth |
Border width |
| Property | strokeStyle | X.strokeStyle |
Border style (solid, dashed, dotted) |
| Property | cornerRadius | X.cornerRadius |
Corner rounding |
| Property | shadowX | X.shadowX |
Shadow horizontal offset |
| Property | shadowY | X.shadowY |
Shadow vertical offset |
| Property | shadowBlur | X.shadowBlur |
Shadow blur radius |
| Property | shadowColor | X.shadowColor |
Shadow color |
| Property | glowBlur | X.glowBlur |
Glow spread radius |
| Property | glowColor | X.glowColor |
Glow color |
| Property | glowIntensity | X.glowIntensity |
Glow intensity (1-10, higher = more solid) |
| Property | tags | set X.tags ["a", "b"] |
Object tags (array of strings) |
| Property | spriteFrame | X.spriteFrame |
Current sprite sheet frame (0-based). Requires sprite image fill |
| Property | state | X.state |
Current state name (any object) |
| Property | set state | set X.state "RED" |
Apply state (composable — patches delta onto current) |
| Property | set state next | set X.state next |
Cycle to next available state. Wraps around. No-op if object has 0 or 1 states |
| Property | state modifier: none | set X.state "Y" none |
Skip spatial properties (position, size, rotation, flip) |
| Property | state modifier: position | set X.state "Y" position |
Apply only position + non-spatial |
| Property | state modifier: rotate | set X.state "Y" rotate |
Apply only rotation/flip + non-spatial |
| Property | state modifier: scale | set X.state "Y" scale |
Apply only size + non-spatial |
| Property | state combined | set X.state "Y" position rotate |
Modifiers combine: position + rotation filter |
| Property | mass | X.mass |
Object mass (affects forces) |
| Property | gravityScale | X.gravityScale |
Gravity multiplier (0=weightless, 1=normal, 2=heavy) |
| Property | windScale | X.windScale |
Wind multiplier (0=immune, 1=normal, 2=extra) |
| Property | dragScale | X.dragScale |
Drag multiplier (0=no drag, 1=normal, 2=heavy) |
| Property | rotatable | X.rotatable |
Enable angular physics (tipping, torque) |
| Property | level | X.level |
Elevation level (integer, default 0). Objects at different levels don't collide, aren't detected by sensors, and are excluded from nearby(). Set to ALL (-999) to collide at every level |
| Property | ghost | X.ghost |
Invisible to blocking collision. Sensors are auto-ghost |
| Property | perspectiveX | X.perspectiveX |
Perspective scroll factor X (0=stationary, 1=full scroll) |
| Property | perspectiveY | X.perspectiveY |
Perspective scroll factor Y (0=stationary, 1=full scroll) |
| Property | mask | X.mask |
Boolean — treat this shape as a mask. The shape becomes the visible covering, revealers punch holes through it. Mutually exclusive with revealer |
| Property | revealRadius | X.revealRadius |
Mask default — radius used by revealers carving through this mask (revealer can override) |
| Property | revealFade | X.revealFade |
Mask default — edge fade width (revealer can override) |
| Property | revealNoise | X.revealNoise |
Mask default — edge noise 0–1 (revealer can override) |
| Property | revealer | X.revealer |
Boolean — auto-reveal overlapping masks as object moves. Mutually exclusive with mask |
| Property | revealerRadius | X.revealerRadius |
Reveal radius in mask-relative units |
| Property | revealerFade | X.revealerFade |
Reveal edge fade (blur width, mask-relative units) |
| Property | revealerNoise | X.revealerNoise |
Reveal edge noise (0=smooth, 1=max) |
| Property | revealerShape | X.revealerShape |
Reveal shape: circle or rect |
| Property | revealTags | set X.revealTags ["mask1"] |
Only reveal masks with matching tags (empty = all masks) |
| Property | revealerRehide | X.revealerRehide |
Boolean — fog returns when revealer moves away |
| Property | revealerRehideSpeed | X.revealerRehideSpeed |
Delay before fog starts regrowing (seconds) |
| Property | revealerRehideGrowth | X.revealerRehideGrowth |
Regrowth time — how long each stamp takes to close (seconds, 0=instant) |
| Property | revealerRehideRate | X.revealerRehideRate |
Rehide speed multiplier (1=normal, 2=twice as fast) |
| Property | revealerRehideStopThreshold | X.revealerRehideStopThreshold |
Pause rehide when stopped briefly (seconds, 0=disabled) |
| Property | invert | X.invert |
Mask only — when true, the mask shape is hidden by default and the revealer paints it in (fill mode, e.g. cup-fill, gauges). When false (default), the mask shape is the visible covering and the revealer erases it (fog-of-war mode) |
| Property | polygonPoints | set Shape.polygonPoints[0].x 0.5 |
Polygon vertex (0–1 bbox-local, NOT world). Index from hover tooltip on vertex. World pos = obj.x − obj.pivot.x·obj.width + vertex.x·obj.width (then rotation/flip applied). Triggers re-render |
| Property | pathSegments | set Shape.pathSegments[2].cp1y 0.3 |
Path segment fields (0–1 bbox-local). Each segment has x,y (anchor) plus cp1x,cp1y,cp2x,cp2y (cubic control points for C segments) |
| Property | trail | X.trail |
Enable motion trail (boolean) |
| Property | trailLength | X.trailLength |
Trail distance in world units (default 0.3) |
| Property | trailOpacity | X.trailOpacity |
Trail starting opacity (default 0.3) |
| Property | trailColor | X.trailColor |
Trail color (default: object fill) |
| Property | trailScale | X.trailScale |
Trail taper — tail/head width ratio (default 0.3, 0=pointed, 1=uniform) |
| Property | trailWidth | X.trailWidth |
Trail width multiplier of min(width, height) (default: 1) |
| Property | lineX1 | X.lineX1 |
Line start X coordinate |
| Property | lineY1 | X.lineY1 |
Line start Y coordinate |
| Property | lineX2 | X.lineX2 |
Line end X coordinate |
| Property | lineY2 | X.lineY2 |
Line end Y coordinate |
| Property | lineStartMarker | X.lineStartMarker |
Line start marker: none, arrow, circle, square, diamond |
| Property | lineEndMarker | X.lineEndMarker |
Line end marker: none, arrow, circle, square, diamond |
| Property | lineCap | X.lineCap |
Line cap style: butt, round, square |
| Property | pegType | X.pegType |
Peg constraint type: pin (hinge) or weld (rigid) |
| Property | driver | X.driver |
Kinematic driver: set true to make this body's whole peg assembly kinematic — solved geometrically to follow the driver (welds stay rigid, no physics fighting) instead of simulated by physics. Set false to return the assembly to physics. Takes effect immediately, on or off, at any time. The driver itself may move by any means (script, input, drag, even physics) |
| Property | pegDamping | X.pegDamping |
Swing friction (0 = swings forever, 1 = stops quickly) |
| Property | pegBreakForce | X.pegBreakForce |
Force threshold to break the peg connection |
| Property | springStiffness | X.springStiffness |
Spring stiffness (0 = rigid rod, higher = more elastic). Spring objects only |
| Property | springDamping | X.springDamping |
Spring energy dissipation. Spring objects only |
| Property | springBreakForce | X.springBreakForce |
Force threshold to break the spring |
| Property | gradient.angle | X.gradient.angle |
Gradient rotation (0-360) |
| Property | gradient.gradientType | X.gradient.gradientType |
Gradient type: linear or radial |
| Property | gradient.opacity | X.gradient.opacity |
Gradient layer opacity (0-1) |
| Property | pattern.pattern | X.pattern.pattern |
Pattern type name |
| Property | pattern.scale | X.pattern.scale |
Pattern scale |
| Property | pattern.color | X.pattern.color |
Pattern color |
| Property | pattern.opacity | X.pattern.opacity |
Pattern layer opacity (0-1) |
| Property | noise.noiseType | X.noise.noiseType |
Noise type: fractalNoise or turbulence |
| Property | noise.scale | X.noise.scale |
Noise scale |
| Property | noise.intensity | X.noise.intensity |
Noise intensity (0-1) |
| Property | noise.monochrome | X.noise.monochrome |
Grayscale noise (boolean) |
| Property | noise.opacity | X.noise.opacity |
Noise layer opacity (0-1) |
| Property | image.mode | X.image.mode |
Image mode: fill, fit, or tile |
| Property | image.scale | X.image.scale |
Image scale |
| Property | image.opacity | X.image.opacity |
Image layer opacity (0-1) |
| Property | innerShadow.color | X.innerShadow.color |
Inner shadow color |
| Property | innerShadow.blur | X.innerShadow.blur |
Inner shadow blur radius (px) |
| Property | innerShadow.offsetX | X.innerShadow.offsetX |
Inner shadow X offset (px) |
| Property | innerShadow.offsetY | X.innerShadow.offsetY |
Inner shadow Y offset (px) |
| Property | innerShadow.opacity | X.innerShadow.opacity |
Inner shadow layer opacity (0-1) |
| TIME SCALE | |||
| Time Scale | Object | set self.timeScale 0 |
Per-object time scale override (0=frozen, 0.5=half, 1=normal, 2=double). Overrides Cell.timeScale for this object |
| Time Scale | Cell | set Cell.timeScale 0 |
Time scale for all objects in the cell. Per-object timeScale overrides this. Supports over: set Cell.timeScale 0 over 500 |
| OBJECT VARIABLES | |||
| Object var | set | set self.energy 100 |
Per-object variable (any name not a built-in property) |
| Object var | read | self.energy |
Read object variable in expressions |
| Object var | tag set | set #robots.energy 50 |
Set on each tagged object independently |
| Object var | children | set children.speed 3 |
Set on each child independently |
| Object var | foreach | foreach r in #robots: set r.score r.score + 1 |
Per-object in loops |
| Object var | nested dict | set self.cupData.waterMass 0 |
Custom dict on an object — writes preserve sibling fields; reads walk the dict |
| MOVEMENT | |||
| Movement | cellX | X.cellX |
Grid column (0-based). Writable: set X.cellX 2 |
| Movement | cellY | X.cellY |
Grid row (0-based). Writable: set X.cellY 3 |
| Movement | cellXTo | X.cellXTo |
Destination column during a transport-to-cell movement. Returns undefined when no cell movement is in flight (cellX/cellY are then authoritative). Read-only |
| Movement | cellYTo | X.cellYTo |
Destination row during a transport-to-cell movement. Returns undefined when no cell movement is in flight (cellX/cellY are then authoritative). Read-only |
| Movement | moving | X.moving |
Boolean — is moving. Read-only |
| Movement | direction | X.direction |
up, down, left, right, none. Read-only |
| Movement | velocityX | X.velocityX |
Horizontal velocity. Writable: set X.velocityX 0.5 sets absolute velocity. Reading is this-frame; the new value is applied at the next physics tick (next-frame motion change) |
| Movement | velocityY | X.velocityY |
Vertical velocity. Writable: set X.velocityY -0.3 sets absolute velocity. Same next-frame timing as velocityX |
| Movement | moveAngle | X.moveAngle |
Movement angle in degrees (0=right, 90=down, -1=stopped). Read-only |
| Movement | moveSpeed | X.moveSpeed |
Movement speed magnitude. Read-only |
| Movement | movedSinceSpawnX | X.movedSinceSpawnX |
Signed horizontal displacement since spawn / cell entry (current x − spawn x). Negative when moved left. Returns to 0 if object returns to spawn. Read-only |
| Movement | movedSinceSpawnY | X.movedSinceSpawnY |
Signed vertical displacement since spawn / cell entry. Negative when moved up. Read-only |
| Movement | distanceTraveled | X.distanceTraveled |
Cumulative engine-integrated path length since spawn. Always grows. Excludes teleports (set self.x / set self.y jumps). Read-only |
| Movement | angularVelocity | X.angularVelocity |
Rotation speed in deg/sec (requires rotatable). Writable: set X.angularVelocity 30 spins object next frame. Same next-frame timing as velocityX/Y |
| Movement | followDistance | X.followDistance |
Current follow/avoid distance. Read/write. Only available when follow/avoid is enabled |
| MOVABLE | |||
| Movable | Enable | enable X movable |
Enable with defaults |
| Movable | speed | enable X movable speed 0.5 |
Max velocity (default: 0.3) |
| Movable | acceleration | enable X movable acceleration 0.5 |
Seconds to reach max speed (0=instant, default: 0) |
| Movable | deceleration | enable X movable deceleration 1 |
Seconds to stop from max speed (0=instant, default: 0.3) |
| Movable | style | enable X movable style slide |
Animation: teleport, slide, jump, fade (default: teleport) |
| Movable | axis | enable X movable axis x |
Constrain to one axis: x (horizontal only), y (vertical only), or forward (steering mode) |
| Movable | steer | enable X movable axis forward steer 1.5 |
Steering turn rate multiplier (default 1). Only with axis forward |
| Movable | path | enable X movable speed 0.3 path Track |
Constrain movement along a named path (line, curve, or polygon). Object moves forward/back along the path instead of freely. Combine with speed, steer, etc. |
| Movable | path reverse | enable X movable path Track reverse |
Reverses path direction — flips what "forward" means |
| Movable | path span | enable X movable path Track span 0.8 |
Two-point path binding: front/rear contact points separated by object width × span factor (default 1.0). Requires steer or faceTravel. Object straddles curves naturally |
| Movable | faceTravel | enable X movable path Track faceTravel |
Face direction of travel on path. Flips 180° when reversing. Implies steer |
| Movable | turnaround | enable X movable path Track faceTravel turnaround |
Smooth rotation when direction changes (uses steerRate). Modifier for faceTravel |
| Movable | facing | enable X movable facing |
Auto-rotate to face movement direction (smooth lerp). The right side of the object (0°) is treated as the front. Mutually exclusive with rotatable and axis forward |
| Movable | stable | set X.stable true |
Geometric collision (default off). When on: no momentum transfer between movers. Use for vehicles in top-down games where movers should stop cleanly on contact. Also: enable X movable stable |
| Movable | dodge | enable X movable dodge |
Steer around other moving objects (axis=forward only). On/off toggle |
| Movable | Combined | enable X movable speed 0.5 axis x deceleration 0.1 |
Multiple params |
| Movable | Disable | disable X movable |
Turn off |
| INPUT | |||
| Input | keyboard | enable X keyboard |
WASD + arrow keys control |
| Input | click | enable X click |
Click-to-move control |
| Input | gamepad | enable X gamepad |
Gamepad left stick + D-pad (pad 1 by default) |
| Input | gamepad-index | enable X gamepad index N |
Route a specific connected pad (1-based: 1 = first, 2 = second, …). Use to drive separate objects from separate controllers in local multiplayer |
| Input | script | enable X script |
Script input — responds to press/release commands only, not physical keyboard. Use for AI-controlled objects, virtual buttons, automation |
| Input | multi-input | enable X keyboard then enable X gamepad |
Multiple inputs combine — keyboard + gamepad are additive, click is fallback |
| Input | Disable | disable X keyboard |
Remove specific input type |
| Input | none | (default) | Physics only, no player control |
| JUMPABLE | |||
| Jumpable | Enable | enable X jumpable |
Enable with defaults |
| Jumpable | height | enable X jumpable height 0.8 |
Jump impulse (default: 0.5) |
| Jumpable | multijump | enable X jumpable multijump 2 |
Max jumps before landing (default: 1) |
| Jumpable | key | enable X jumpable key "w" |
Custom jump key (default: Space) |
| Jumpable | Combined | enable X jumpable height 0.6 multijump 2 |
Multiple params |
| Jumpable | Disable | disable X jumpable |
Turn off |
| Jumpable | jump | jump X |
Trigger jump impulse from script. Bypasses key input and multi-jump counter |
| Jumpable | jump height | jump X height 0.8 |
Jump with height override. Accepts expressions: jump self height random(0.3, 0.8) |
| IMPULSE | (motion writes — applied at the next physics tick) | ||
| Impulse | impulse | impulse X vx vy |
Add velocity to object. Additive — accumulates with existing velocity. Next-frame |
| Impulse | impulse expr | impulse self random(-0.2, 0.2) -0.5 |
Accepts expressions for both vx and vy |
| Impulse | set velocity | set X.velocityX 0.5 |
Set absolute velocity (not additive). Also: velocityY, vx, vy. Next-frame |
| TRANSPORT | (next-frame start — first tween sample is processed at the next physics tick) | ||
| Transport | basic | transport X to 0.5 0.5 over 1000 |
Smoothly move to (x, y) over duration (ms). Real position updates each frame |
| Transport | easing | transport X to 0.5 0.5 over 500 ease-in-out |
With easing: ease-in, ease-out, ease-in-out, ease-in-cubic, ease-out-cubic, ease-in-out-cubic |
| Transport | dynamic | transport X to Player.x Player.y over 300 |
Target can be any expression (evaluated at call time) |
| Transport | multi | transport #tag to 0.5 0.5 over 500 |
Transport all tagged objects. Also: self, siblings, children |
| Transport | to cell | transport X to cell 5 0 over 400 |
Resolve (col, row) on the target's snapToGrid to world coords and run as a transport. During the movement self.cellX/cellY stay at the source cell and self.cellXTo/cellYTo hold the destination; on arrival the engine commits the destination into cellX/cellY and clears cellXTo/cellYTo. Target without snapToGrid is warned and skipped. |
| Transport | notes | No collision, no movable required. Physics bypassed during transit. Fires onMove/onStop events. New transport replaces old. set X.x cancels |
|
| MOVETO | (next-frame start — first steering correction is applied at the next physics tick) | ||
| MoveTo | basic | moveTo X 0.5 0.5 |
Move to position using movable speed. Obeys physics — collides with blockers, affected by gravity |
| MoveTo | self | moveTo self 0.5 0.5 |
Move current object to position |
| MoveTo | dynamic | moveTo self Player.x Player.y |
Target can be any expression |
| MoveTo | multi | moveTo #robots Player.x Player.y |
Move all tagged objects. Also: self, other, siblings, children |
| MoveTo | notes | Requires movable. Uses object's speed/acceleration. Uses A* pathfinding around static obstacles. Fires onArrive on arrival (use instead of onStop for waypoint logic). Keyboard/gamepad overrides direction. New moveTo replaces old target |
|
| SYNTHETIC KEYS | |||
| Press | basic | press "q" |
Send a script key-down to the current object. Fires onKeyDown handlers. Objects need Script input enabled to respond |
| Press | target | press "Space" on Tank |
Inject key-down on a specific object. Key is stored per-object — does not affect other objects' input |
| Press | movement | press "ArrowLeft" |
Also updates the input system — movable+script objects will start moving |
| Release | basic | release "q" |
Send a script key-up to the current object. Fires onKeyUp handlers |
| Release | target | release "Space" on Tank |
Inject key-up on a specific object |
| Release | movement | release "ArrowLeft" |
Clears the key from the input system |
| Script Keys | cell context | press "Space" |
When called from a cell script, injects globally — all objects with Script input respond |
| Script Keys | per-object | press "ArrowUp" on "CarAI" |
Only CarAI sees this key. Physical keyboard and other objects' synthetic keys are independent |
| Script Keys | hold pattern | press without matching release keeps the key held. Standard pattern: press "q" → (wait or tick logic) → release "q" |
|
| Script Keys | use case | AI control: sense target → calculate bearing → press "q" to rotate → press "Space" to fire. Also powers virtual buttons and automated movement |
|
| KEY REMAPPING | |||
| Keys | remap direction | set self.keys.up "w" |
Remap a movement direction to a different key. Directions: up, down, left, right |
| Keys | disable direction | set self.keys.down "none" |
Disable a movement direction — no key will trigger it |
| Keys | remap jump | set self.keys.jump "w" |
Remap the jump key |
| Keys | read | self.keys.up |
Read current key mapping for a direction. Returns "none" if disabled |
| FOLLOW / AVOID | |||
| Follow | follow | enable Dog follow "Player" |
Object moves toward target. Requires movable. Target can be a variable: enable self follow myTarget |
| Follow | distance | enable Dog follow "Player" distance 0.2 |
Maintain distance from target (default: 0 = reach target). Negative = overlap. Distance is edge-to-edge by default |
| Follow | followDistance | set Dog.followDistance 0.1 |
Read/write follow distance at runtime without re-specifying target. Only works when follow/avoid is active |
| Follow | center | enable Dog follow "Player" distance 0.2 center |
Measure distance center-to-center instead of edge-to-edge |
| Follow | rigid | enable self follow leader distance 0.05 rigid |
Deterministic trail follow. Follower traces target's exact position history at fixed arc-length offset. No breadcrumb intelligence — pure position replay. Ideal for snake-like chains |
| Follow | tag | enable #robots follow "Player" |
All tagged objects follow target |
| Follow | avoid | enable Dog avoid "Player" |
Object moves away from target |
| Follow | avoid distance | enable Dog avoid "Player" distance 0.3 |
Flee only when closer than distance |
| Follow | deadZone | enable Dog follow "Player" deadZone 0.02 |
Stop within this distance of target (default: 0.015). Prevents fidgeting |
| Follow | arrival | enable Dog follow "Player" arrival 0.15 |
Begin decelerating within this distance (default: 0.08). Larger = smoother |
| Follow | steering | enable Tank follow "Player" |
Steered objects (axis forward) automatically turn toward target and drive forward |
| Follow | pathfinding | enable Dog follow "Player" pathfinding |
A* pathfinding around static obstacles when stuck. Follower routes around blockers to reach breadcrumb waypoints |
| Follow | disable | disable Dog follow |
Stop following or avoiding |
| Follow | priority | Manual input (keyboard, gamepad) overrides follow direction | |
| PHYSICS ZONES | |||
| Zone | enable | enable WaterRegion zone gravity 0.3 drag 0.8 |
Object becomes a physics zone — overrides cell physics for contained objects |
| Zone | gravity | enable X zone gravity 0 |
Override gravity (0 = weightless) |
| Zone | wind | enable X zone wind 5 windAngle 0 |
Override wind magnitude and direction (degrees, 0=right, 90=down) |
| Zone | drag | enable X zone drag 0.8 |
Override drag coefficient (0=vacuum, 1=thick) |
| Zone | flow | enable X zone flowX 0.3 |
Constant drift (mass-independent, like conveyor/current). Also: flowY |
| Zone | combined | enable X zone gravity 0 drag 0 |
Multiple overrides. Omitted params use cell defaults |
| Zone | affects | enable X zone gravity 0.3 affects #swimmer |
Only affect objects with matching tag. Multiple tags use OR logic: affects #light #paper. Omit for all objects (default) |
| Zone | disable | disable X zone |
Deactivate zone — physics reverts to cell defaults |
| Zone | containment | Object is "in" zone when its center point is inside the zone's collision shape | |
| Zone | priority | Smallest zone wins when multiple zones overlap | |
| SPAWN PARAMS | |||
| Spawn | position | spawn "T" {x: 0.5, y: 0.3} |
Spawn at specific position |
| Spawn | velocity | spawn "T" {vx: 2, vy: -1} |
Spawn with initial velocity |
| Spawn | combined | spawn "T" {x: self.x, y: self.y, vx: 2, vy: -1} |
Position + velocity. Other params pass to onSpawn |
| Spawn | at anchor | spawn "T" at MuzzlePoint |
Spawn at anchor's position and rotation |
| Spawn | at + params | spawn "T" at MuzzlePoint {vx: 1} |
Anchor position + custom params |
| DRAGGABLE | |||
| Draggable | Enable | enable X draggable |
Enable basic drag |
| Draggable | once | enable X draggable once |
Can only drag one time |
| Draggable | collision | enable X draggable collision |
Respect blockers while dragging |
| Draggable | discrete | enable X draggable discrete |
Grid objects move cell-by-cell |
| Draggable | discrete occupy | enable X draggable discrete occupy |
Reject drop if cell occupied |
| Draggable | Combined | enable X draggable discrete occupy collision |
Multiple options |
| Draggable | Disable | disable X draggable |
Turn off |
| COLLISION | |||
| Collision | enable blocking | enable X blocking |
Enable collision blocking. Optional affects #tag to only block tagged movers |
| Collision | disable blocking | disable X blocking |
Disable collision blocking |
| Collision | blocking expr | set X.blocking "self.color != other.color" |
Conditional blocking expression |
| Collision | enable sensor | enable X sensor |
Enable overlap detection. Optional affects #tag to only detect tagged objects |
| Collision | disable sensor | disable X sensor |
Disable overlap detection |
| Collision | enable phase | enable X phase affects #tag |
Phase through blockers. Without affects, phases through all. With affects #tag, only phases through tagged blockers |
| Collision | disable phase | disable X phase |
Disable phasing (resume normal collisions) |
| Collision | ghost | set X.ghost true |
Invisible to blocking collision. Sensors are auto-ghost |
| Collision | oneWay | set X.oneWay true |
One-way platform (pass through from below) |
| Collision | pullable | set X.pullable true |
Can be pulled by other objects |
| Collision | friction | set X.friction 0.5 |
Surface friction (0-1) |
| Collision | restitution | set X.restitution 0.5 |
Bounciness (-1 to 1). Negative absorbs bounce (sticky surface) |
| GRID | |||
| Grid | snapToGrid | set X.snapToGrid "GridName" |
Attach object to grid |
| Grid | cellX | set X.cellX 2 |
Set grid column |
| Grid | cellY | set X.cellY 3 |
Set grid row |
| Grid | cell data write | set Grid.cell[x][y].prop value |
Store metadata |
| Grid | cell data read | Grid.cell[x][y].prop |
Read metadata |
| DATA | |||
| Data | dataValue | MyData.dataValue |
The DATA prime's content. Any ScriptValue (scalar, array, map, nested). Read or replace as a whole, or use any of the structured-data commands above (set/push/insert/remove, indexed/dotted paths) |
| Data | nested read | MyData.dataValue[2].field or MyData.dataValue.config.maxAlt |
Drill into arrays / maps with bracket index + dot path |
| Data | nested write | set MyData.dataValue[0].score 99 |
Replace at a path. Auto-grows arrays with null on out-of-bounds writes |
| Data | dynamic map key | set MyData.dataValue[key] value |
Bracket index can be a variable: a number indexes a list, anything else is a map key. Seed the container as a map first (set MyData.dataValue {}) — an undefined start is treated as a list |
| Data | in-place loop edit | foreach p in MyData.dataValue: set p.field x |
Mutate list elements in place — O(N) and the changes stick. Prefer over rewriting whole entries by index (set arr[i] {...}) in a loop, which gets slow on large lists |
| Data | append | push MyData.dataValue 99 |
Append to array at any nested path: push MyData.dataValue.records {...} |
| Data | length | length(MyData.dataValue) |
Array length, map key count, or string character count |
| Data | replace whole | set MyData.dataValue {fresh: "shape"} |
Replace the entire content with a new value |
| Data | dataLive | set MyData.dataLive true |
Storage selector: false (default) = baked into project file, resets each Play; true = stored on this device, mutates across plays. Toggling migrates the data between the two stores |
| Data | cross-cell read | @OtherCell.MyData.dataValue |
Read a Data prime in a different cell |
| CAMERA | |||
| Camera | subject | enable X subject |
Camera follows this object |
| Camera | disable subject | disable X subject |
Stop camera following |
| Camera | canvasDraggable | set Cell.canvasDraggable false |
Disable manual panning |
| Camera | zoom | set Camera.zoom 2 |
Zoom level (1 = default, 2 = 2x closer). Read/write: Camera.zoom returns current value |
| Camera | x | set Camera.x 1.5 |
Viewport center X in world coordinates. Read/write. Clamped to cell bounds |
| Camera | y | set Camera.y 0.5 |
Viewport center Y in world coordinates. Read/write. Clamped to cell bounds |
| Camera | aspectRatio | set Camera.aspectRatio 1.78 |
Viewport aspect ratio (width/height). Read/write. Set to Screen.aspectRatio to fill screen |
| Camera | viewportWidth | Camera.viewportWidth |
Visible width in world units (read-only) |
| Camera | viewportHeight | Camera.viewportHeight |
Visible height in world units (read-only) |
| Camera | subjectTransition | set Camera.subjectTransition 500 |
Duration (ms) for smooth pan when switching subjects. 0 = snap (default) |
| SCREEN | |||
| Screen | aspectRatio | Screen.aspectRatio |
Actual device/window aspect ratio (read-only) |
| Screen | width | Screen.width |
Window width in pixels (read-only) |
| Screen | height | Screen.height |
Window height in pixels (read-only) |
| CELL PROPERTIES | |||
| Cell | width | Cell.width |
Cell width in screens (read-only) |
| Cell | height | Cell.height |
Cell height in screens (read-only) |
| Cell | gravity | set Cell.gravity 1.5 |
Vertical acceleration (-10 to 10) |
| Cell | wind | set Cell.wind 0.3 |
Wind magnitude (-10 to 10) |
| Cell | windAngle | set Cell.windAngle 90 |
Wind direction (0=right, 90=down) |
| Cell | drag | set Cell.drag 0.1 |
Air drag |
| Cell | timeScale | set Cell.timeScale 0 |
Time scale for all objects (0=paused, 0.5=half, 1=normal, 2=double). Supports over for smooth transition: set Cell.timeScale 0 over 500 |
| Cell | backgroundColor | set Cell.backgroundColor "#ff0000" |
Cell background color |
| Cell | backgroundPattern | set Cell.backgroundPattern "grid" |
Cell background pattern |
| Cell | patternColor | set Cell.patternColor "rgba(0,0,0,0.2)" |
Pattern overlay color |
| Cell | patternScale | set Cell.patternScale 1.5 |
Pattern scale (0.5-2) |
| FUNCTIONS | |||
| Math | random | random(1, 6) |
random() returns 0-1 float. random(min, max) returns integer when both args are integers, float when either has decimals. random(1, 6, float) forces float mode |
| Math | floor | floor(x) |
Round down |
| Math | ceil | ceil(x) |
Round up |
| Math | round | round(x) |
Round to nearest |
| Math | abs | abs(x) |
Absolute value |
| Math | min | min(a, b) |
Smaller value |
| Math | max | max(a, b) |
Larger value |
| Math | hash | hash(values...) |
Hash from any number of values. hash(x, y), hash(#tag.prop). Deterministic — same inputs always give same result |
| Math | sin | sin(degrees) |
Sine of angle in degrees. sin(90) → 1 |
| Math | cos | cos(degrees) |
Cosine of angle in degrees. cos(0) → 1 |
| Math | atan2 | atan2(y, x) |
Angle in degrees from coordinates. atan2(1, 0) → 90 |
| Math | cardinal | cardinal(angle) |
Angle to direction: right, down, left, up |
| Arrays | length | length(arr) |
Array element count, string character count, or map key count. Returns 0 for any other value |
| Arrays | index | arr[i] |
Element at index. Strings supported too: "hello"[1] → "e". Out-of-range or non-indexable returns 0. |
| Arrays | range | range(5) or range(0, 5) |
range(n) returns [0..n-1]. range(min, max) returns [min..max] inclusive |
| Arrays | shuffle | shuffle(arr) |
Randomize array order |
| Arrays | pick | pick(arr) |
Random element from array |
| Conditions | visited | visited("Cell") |
Boolean — has cell been visited |
| Conditions | visits | visits("Cell") |
Number of times cell was visited |
| Conditions | hasObject | hasObject("Name") |
Boolean — does object exist in current cell |
| Conditions | hasSave | hasSave("checkpoint") |
Boolean — does save slot exist |
| Conditions | get | get("scope.key") |
Read variable value (returns undefined if unset) |
| Grid | isEmpty | isEmpty("Grid", x, y) |
Check if grid cell has no object |
| Grid | emptyCells | emptyCells("Grid") |
Array of {x, y} for empty cells |
| Grid | cellsWhere | cellsWhere("Grid", "prop", "==", val) |
Find cells by metadata |
| Grid | floodfill | floodfill("Grid", x, y, "prop", val, connectivity) |
Find connected cells. Connectivity: 4 (cardinal) or 8 (default, + diagonal) |
| Grid | minimax | minimax("Grid", "prop", "AI", "Human", depth, empty, winLen) |
AI best move for N-in-a-row games. Returns {x, y} or 0 |
| SPATIAL | |||
| Spatial | distance | distance(self, Target) |
Euclidean distance between two objects (0–1 coords). Works with self, other, or object names |
| Spatial | nearby | nearby(self, 0.2) or nearby(self, 0.2, #tag) |
Objects within radius, sorted by distance. Returns [{name, x, y, distance}]. Optional tag filter. Level-filtered: only returns objects at the same level as the reference (ALL level sees everything) |
| Spatial | nearest | nearest(self, #coin) |
Closest object to reference. Filter by #tag, name, or "sibling". Also: nearest(x, y, #tag) from coordinates. Add rank for Nth nearest: nearest(self, #robot, 2). Returns {name, x, y, distance} or 0. Level-filtered (same as nearby). Store in a variable to read fields: set t nearest(...) then t.x, t.y, t.name, t.distance. To store per-object, copy to properties: set self.tx t.x |
| Spatial | intersects | intersects(Paddle, Target) |
SAT collision test. Also: intersects(self, #tag) — true if any tagged object overlaps. Level-filtered: objects at different levels never intersect (ALL level intersects everything) |
| Spatial | randomFree | randomFree(self, 0.3) or randomFree(x, y, 0.3) |
Random unblocked position within radius. Uses pathfinding bitmap. Returns {x, y} or 0. Two forms: object ref (current position as center) or coordinates (fixed point for patrol). Level-filtered |
| Spatial | canSee | canSee("Grid", x1, y1, x2, y2, "wall") |
Line of sight via Bresenham. Blocked by cells where the given property is truthy. Default prop: "wall" |
| Spatial | pathfind | pathfind("Grid", x1, y1, x2, y2, "wall") |
A* pathfinding. Returns [{x, y}] waypoints (excl. start, incl. goal). Default blocker: "wall" |
| Spatial | generateMaze | generateMaze("Grid", "wall") |
Recursive backtracker maze. Sets cell data: true = wall, false = passage. Best with odd-dimension grids |
| CHART (PLOTTER) | |||
| Chart | viewMinX / viewMaxX | set Chart.viewMinX 0 |
The chart's visible x-range, in data values. Pan = shift both; zoom = scale them; follow = set them from a value each frame (no per-point redraw — it's just two numbers). Also viewMinY/viewMaxY, autoY, zoomMin/zoomMax, interactive, inertia |
| Chart | plotterLayers | set Chart.plotterLayers [...] |
The chart's series + markers (each: a data source, x/y fields, a mark type — line/area/band/glyph — and style). Set from script to build or reconfigure a chart |
| Chart | dataToScreenX | dataToScreenX(Chart, value) |
A data x-value → screen position (0–1 world coords), e.g. to place a popup over a point. dataToScreenY for y (needs a fixed y-range) |
| Chart | screenToDataX | screenToDataX(Chart, clickX) |
A screen x → its data value. screenToDataY for y |
| BUILT-IN VARIABLES | |||
| Variable | random | random |
Fresh random number 0-1 each access |
| Variable | currentCell | currentCell |
Name of the current cell |
| Variable | clicks | clicks |
How many times current object was clicked |
| Variable | clickX | clickX |
Pointer X in world units when the current event fired. Available in onClick, onDrag*, onHover* |
| Variable | clickY | clickY |
Pointer Y in world units when the current event fired. Available in onClick, onDrag*, onHover* |
| Variable | dragStartX | dragStartX |
Pointer X in world units when the current drag began. Available in onDragStart, onDrag, onDragEnd (cell + object). Combine with clickX to measure drag extent |
| Variable | dragStartY | dragStartY |
Pointer Y in world units when the current drag began. Available in onDragStart, onDrag, onDragEnd (cell + object) |
| Variable | dragDuration | dragDuration |
Milliseconds since the current drag began. Available in onDrag, onDragEnd. Use with distance to detect swipes |
| Variable | scrollX / scrollY | scrollY |
Wheel/trackpad scroll amount in onScroll. deltaMode-normalized (mouse notch ≈ ±1, fractional on trackpads). scrollY > 0 = down/toward you; scrollX > 0 = right. Direction + proportionality are stable; absolute magnitude is device-dependent |
| Variable | shiftKey / ctrlKey / altKey / metaKey | shiftKey |
Boolean — was that modifier held when the current pointer gesture began. Snapshot at pointer-down, so it holds through onClick / onDragStart / onDrag / onDragEnd of one gesture. metaKey = Cmd (macOS) / Win; prefer ctrlKey for cross-platform shortcuts |
| Variable | clicked | clicked |
In onClick, the object actually under the cursor — even when a parent component absorbs the click. Read props (clicked.name) and tags (if clicked is #place). Mirrors other from collisions |
| Variable | deltaTime | deltaTime |
Frame time in seconds. Available in onTick. Multiply speeds by this for frame-rate independence |
| Variable | newGame | newGame |
True on normal cell entry, false when restored from a save (load command or auto-save resume). Use if newGame: to guard variable initialization |
| OPERATORS | |||
| Operator | Arithmetic | + - * / % |
Math operations (% is modulo) |
| Operator | Comparison | == != > < >= <= |
Compare values |
| Operator | Logical | and or not |
Boolean logic |
| Operator | Tag check | X is #tag |
Check if object has tag |
| Operator | Tag check (negated) | X is not #tag |
Check if object does NOT have tag |
| Operator | Array access | arr[i] or arr[i].prop |
Get element or property |
| AGGREGATES | |||
| Aggregate | all | all #tag.prop == value |
True if every tagged object matches |
| Aggregate | any | any #tag.prop == value |
True if at least one matches |
| Aggregate | count | count #tag.prop == value |
Number of tagged objects that match |
| Aggregate | count (simple) | count #tag |
Number of objects with tag (no condition) |
| BLOCK STYLES | |||
| Syntax | Colon | onClick: + indented block |
Indentation-based |
| Syntax | Braces | onClick { ... } |
Brace-delimited |
| Syntax | Single-line | onClick: show Panel |
One-liner |