Zoetrope

Scripting

Scripts are modern JavaScript with a small, Flash-like API. They run the same way in the preview and in exported pages, in a sandbox that keeps your project and the viewer safe.

The Bee Catcher frame script in the large script editor

Where scripts go

KindAttach it…It runs…this is…
Frame scriptClick a keyframe, then Label & script in Properties (⤢ opens a large editor).each time the playhead enters that keyframethe timeline (the main timeline, or the movie clip)
Symbol scriptSelect a symbol in the Library and click { }.once for every instance, when it appearsthe instance

The script editor

  • Suggestions appear as you type: the scripting API, the instance names on the timeline, variables already in the script, frame labels inside gotoAndPlay("…"), event names inside stage.addEventListener("…") and keys inside Key.isDown("…"). ↑/↓ choose, ↵ or Tab insert, Esc closes, Ctrl+Space opens the list anywhere. Picking an event such as onEnterFrame writes the whole handler for you.
  • Errors are checked as you type, with the same compiler playback uses: the problem is underlined, its line number turns red, and the message appears under the editor. Click it to jump there.
  • ↵ keeps the indentation (and indents after {), Tab / ⇧Tab indent or outdent the selected lines, ⌘/ / Ctrl+/ comments them out or back in, and ⌘Z undoes typing inside the editor.
  • ⌘↵ / Ctrl+Enter or Apply applies the script (one undo step in the project), and Esc reverts unapplied edits.

Names and scope

Give objects an instance name in Properties, and use it directly. Free names resolve against the timeline, as in Flash:

stop();                    // this timeline
bee.x = 200;               // the child named "bee"
title.text = "Hello";      // a named text
var lives = 3;             // becomes this.lives, shared by this timeline's scripts
let local = 1;             // stays local to this script

Display objects

MemberNotes
x, y, rotation, scaleX, scaleY, alpha, visibleRead and write. Writing takes that property over from the timeline.
textText objects only.
currentFrame, totalFrames, isPlayingThe main timeline and movie clips. Frames count from 1.
play(), stop(), gotoAndPlay(f), gotoAndStop(f), nextFrame(), prevFrame()f is a frame number or a frame label.
hitTestObject(other), hitTestPoint(x, y, shape), getBounds()Collisions and bounds in stage coordinates.
name, kind, parent, root, getChildByName(n), getChildren()Finding your way around.

Events

this.onEnterFrame = function () { … };          // every frame
playButton.onClick = function () { play(); };    // buttons: onPress, onRelease, onClick
stage.addEventListener("keyDown", function (e) { trace(e.key); });
if (Key.isDown("ArrowLeft")) { … }               // keyboard state
trace(Mouse.x, Mouse.y);                         // pointer, in stage coordinates

Stage events are enterFrame, keyDown, keyUp, mouseDown, mouseUp, mouseMove and click. Within a frame, the order is: timelines advance, new instances run their symbol scripts, entered frames run their frame scripts, then onEnterFrame handlers run.

Debugging

  • trace(…) prints to the Output panel (status bar → Output). In exported pages it goes to the browser console.
  • Errors show their location and line, e.g. Scene 1 › Actions › frame 1: TypeError: not a function (line 5). The movie keeps running.
  • Math.random() is seeded per session, which makes tests and comparisons repeatable.

The sandbox

Scripts run in a separate JavaScript engine (QuickJS, compiled to WebAssembly) with no access to the page, the network or files: there's no window, document, fetch or setTimeout. Count frames in onEnterFrame for timing. Each script entry may run for 250 ms, and memory is capped at 64 MB, so an endless loop is stopped and reported instead of freezing the app.

The complete reference, with every property, the exact timing rules and more examples, is in docs/SCRIPTING.md.