Skip to main content

Runtime API

Runtime (scratch-vm/src/engine/runtime.js) is the engine that actually runs a project. The VirtualMachine owns one and exposes it as vm.runtime; extensions get it as Scratch.vm.runtime. It holds every target, steps the threads, routes input through IO devices, and emits the events the editor listens to.

Runtime extends Node's EventEmitter, so runtime.on(name, handler) and runtime.emit(...) work directly. The VM re-emits most runtime events under the same name, so UI code usually listens on vm; extensions and internal code that want the raw stream listen on runtime.

This page covers the runtime surface an extension or the window.vm console can safely reach. Anything prefixed with _ is internal and not covered here.

Targets

A "target" is a sprite or the stage (a RenderedTarget). The runtime keeps them in execution order.

  • runtime.targets: the array of all targets, including clones, in layer/execution order.
  • runtime.getTargetForStage(): the stage target, or undefined if there is none.
  • runtime.getSpriteTargetByName(name): the first original (non-clone) sprite with that name.
  • runtime.getTargetById(id): a target by its ID (uses an internal cache).
  • runtime.getTargetByDrawableId(drawableID): the target owning a given renderer drawable.
  • runtime.getEditingTarget(): the target currently selected in the editor, or undefined.
// In the editor console:
window.vm.runtime.getTargetForStage();
window.vm.runtime.getSpriteTargetByName('Sprite1');

Clones

  • runtime.clonesAvailable(): whether another clone may be created (false once the count hits runtimeOptions.maxClones).
  • runtime.changeCloneCounter(delta): adjust the live clone count. The clone/delete blocks call this; you rarely need it directly.

Clones are ordinary targets in runtime.targets; stopAll() disposes every non-original one.

IO devices

runtime.ioDevices groups the virtual input devices. Blocks read them; the host feeds them through vm.postIOData(device, data).

DeviceSourceNotable reads
keyboardio/keyboard.jsgetKeyIsDown(key)
mouseio/mouse.jsgetScratchX(), getScratchY(), getIsDown(), getButtonIsDown(button)
mouseWheelio/mouse-wheel.jsscroll deltas
clockio/clock.jsprojectTimer(), resetProjectTimer()
cloudio/cloud.jscloud-variable requests
userDataio/user_data.jsgetUsername()
videoio/video.jscamera frames for the video-sensing extension

The project timer

The Scratch timer block reads runtime.ioDevices.clock:

  • runtime.ioDevices.clock.projectTimer(): seconds since the timer was last reset.
  • runtime.ioDevices.clock.resetProjectTimer(): reset it to zero. greenFlag() and dispose() do this automatically.

Green flag and stopping

  • runtime.greenFlag(): stop everything, reset the project timer, fire event_whenflagclicked hats. Emits PROJECT_START. This is what vm.greenFlag() calls.
  • runtime.stopAll(): stop every thread, dispose all clones, and clear the thread list. Emits PROJECT_STOP_ALL.

Starting threads (hats)

  • runtime.startHats(requestedHatOpcode, optMatchFields, optTarget): start a thread for every script whose top block is a hat with requestedHatOpcode. optMatchFields filters by field value (uppercased before comparison, so broadcasts and key presses only fire the right scripts); optTarget limits it to one target. Returns the array of new threads. It honors the hat's restartExistingThreads metadata: true restarts a matching running thread, false skips starting if one is already running. This is how extensions with HAT/EVENT blocks make their hats fire. See Block registration.
  • runtime.allScriptsDo(fn, optTarget) / runtime.allScriptsByOpcodeDo(opcode, fn, optTarget): iterate over every top-level script (optionally filtered by top-block opcode). startHats is built on the second one.
  • runtime.toggleScript(topBlockId, opts): start (or, for a click already running, stop) a script from its top block, as clicking it in the editor does.

There is no startHatsWithParams method in this engine; pass field matchers through startHats's optMatchFields instead.

Events

Runtime emits a large set of events; the ones extensions and hosts use most:

EventFires when
PROJECT_STARTThe green flag was pressed.
PROJECT_STOP_ALLThe stop button was hit (or stopAll() ran).
PROJECT_RUN_STARTThreads went from idle to active this tick.
PROJECT_RUN_STOPThe last non-monitor thread finished this tick.
PROJECT_LOADEDA project finished loading.
PROJECT_CHANGEDThe project was edited in a serialization-affecting way.
TURBO_MODE_ON / TURBO_MODE_OFFTurbo mode toggled.

PROJECT_RUN_START / PROJECT_RUN_STOP are edge-triggered off the non-monitor thread count, so they fire once per idle/active transition, not once per thread. See the full list in Events.

Monitors

Monitors are the value watchers shown on the stage. The runtime holds their state and the editor renders it from the MONITORS_UPDATE event.

  • runtime.requestAddMonitor(monitorRecord): add a monitor (updates in place if the ID exists).
  • runtime.requestUpdateMonitor(delta): patch an existing monitor by ID; returns whether it existed.
  • runtime.requestRemoveMonitor(id): remove one.
  • runtime.requestShowMonitor(id) / runtime.requestHideMonitor(id): toggle visibility; each returns whether the monitor existed.
  • runtime.getMonitorState(): the current monitor state map.

Visual report

  • runtime.visualReport(target, blockId, value): show a value bubble next to a clicked reporter block. Only reports when target is the editing target; emits VISUAL_REPORT. Called for you when a reporter is clicked in the workspace.

Redraw

  • runtime.requestRedraw(): mark that the screen must repaint before the sequencer runs more work this frame. A block that changes something visible calls this; the sequencer stops stepping for the frame once a redraw is requested (unless turbo mode is on). See Threads: the sequencer.

Turbo and compiler flags

These are read by the engine and set through the VM's setters (which also emit change events):

  • runtime.turboMode: true when loops run without yielding to redraw. Set via vm.setTurboMode.
  • runtime.runtimeOptions: {maxClones, miscLimits, fencing, caseSensitiveLists, unsafeOptimisations}. Set via vm.setRuntimeOptions.
  • runtime.compilerOptions: {enabled, warpTimer}. Set via vm.setCompilerOptions. enabled is the on/off switch for the JavaScript compiler; warpTimer makes warp loops honor the warp timeout even outside warp mode.

See also