@motion-script/core / PlaybackController
Class: PlaybackController
Defined in: runtime/playback-controller.ts:76
Orchestrates playback of a compiled motion-script project.
On construction it runs the precomp pass (Precomp.run()) to build the
global asset timeline and node lifespans, then wires the master clock to
the audio device and render pipeline so every tick:
- Loads assets required at the current frame (
AssetManager.loadAt). - Evaluates scene state and lays out nodes (
StateEvaluator). - Renders the frame to the render context.
- Prefetches assets for upcoming frames.
External callers interact via play, pause, seek, seekWhilePlaying,
screenshot, getTreeState, and getNodeState.
Constructors
Constructor
new PlaybackController(
params):PlaybackController
Defined in: runtime/playback-controller.ts:156
Parameters
params
Returns
PlaybackController
Properties
fps
readonlyfps:number
Defined in: runtime/playback-controller.ts:109
precomp
precomp:
PrecompResult
Defined in: runtime/playback-controller.ts:120
Latest assembled precomp result. Swapped wholesale on a scene replace.
viewport
readonlyviewport:Size2D
Defined in: runtime/playback-controller.ts:110
Accessors
buildErrors
Get Signature
get buildErrors():
BuildError[]
Defined in: runtime/playback-controller.ts:138
Errors collected during the precomp pass (one entry per failing scene).
Returns
currentFrame
Get Signature
get currentFrame():
number
Defined in: runtime/playback-controller.ts:291
Current playback position in frames (float).
Returns
number
currentTime
Get Signature
get currentTime():
number
Defined in: runtime/playback-controller.ts:286
Current playback position in seconds.
Returns
number
globalAudio
Get Signature
get globalAudio():
WaveformInfo[]
Defined in: runtime/playback-controller.ts:148
The project's audio beds as timeline clips, in absolute seconds — already bounded by the measured duration, so re-read them whenever it grows. Exposed for the timeline's global track rows; playback schedules the underlying requests itself.
Returns
isPlaying
Get Signature
get isPlaying():
boolean
Defined in: runtime/playback-controller.ts:281
Returns
boolean
totalDuration
Get Signature
get totalDuration():
number
Defined in: runtime/playback-controller.ts:133
Total playback duration in seconds.
Returns
number
totalFrames
Get Signature
get totalFrames():
number
Defined in: runtime/playback-controller.ts:128
Total frame count across all scenes.
Returns
number
tracks
Get Signature
get tracks():
number[]
Defined in: runtime/playback-controller.ts:123
Per-scene frame counts in timeline order, used to build the track list.
Returns
number[]
Methods
clearNodeOverrides()
clearNodeOverrides(
path?):void
Defined in: runtime/playback-controller.ts:656
Drop one node's overrides, or all of them when path is omitted, and
repaint so the node snaps back to its scene-authored state.
An override is written straight onto a live signal, so simply forgetting it
would leave the last dragged value on screen. The value can only come back
from the generator that authored it, which means replaying the current
scene — so this rebuilds that scene's node tree (node ids change; keep
keying on paths). Cheap enough for a pointer-up, which is the only place
it belongs; never call it per pointermove.
Parameters
path?
string
Returns
void
dispose()
dispose():
void
Defined in: runtime/playback-controller.ts:707
Returns
void
getNodeBox()
getNodeBox(
path):NodeBox|null
Defined in: runtime/playback-controller.ts:569
The on-screen box of one node at the current frame, or null when the path
does not resolve (or no scene is active). See NodeBox.
Parameters
path
string
Structural path from TreeState.path.
Returns
NodeBox | null
getNodeBoxes()
getNodeBoxes():
NodeBox[]
Defined in: runtime/playback-controller.ts:581
Every visible node's box in draw order — for hover highlights, marquee selection, and snap guides. One tree walk instead of N getNodeBox calls.
Returns
NodeBox[]
getNodeState()
getNodeState(
nodeId):NodeState|null
Defined in: runtime/playback-controller.ts:551
Parameters
nodeId
string
Returns
NodeState | null
getTextLayout()
getTextLayout(
path):NodeTextLayout|null
Defined in: runtime/playback-controller.ts:599
Where a Text node's caret slots landed on screen, or null when the path
doesn't resolve, the node isn't text, or the shape has no caret model (see
MeasureScope.layoutTextBlock). See NodeTextLayout.
Measured on demand rather than carried with every frame: a host wants this only while a text edit is open, and only for the node being edited.
Parameters
path
string
Structural path from TreeState.path.
Returns
NodeTextLayout | null
getTreeState()
getTreeState():
TreeState|null
Defined in: runtime/playback-controller.ts:527
Return the full node tree for the current scene, with lifespan frame
ranges and waveform data attached. Used by the timeline UI.
Returns null when no scene is active.
Returns
TreeState | null
onPause()
onPause(
cb):void
Defined in: runtime/playback-controller.ts:306
Register a callback that fires when playback pauses.
Parameters
cb
() => void
Returns
void
onPlay()
onPlay(
cb):void
Defined in: runtime/playback-controller.ts:301
Register a callback that fires when playback starts.
Parameters
cb
() => void
Returns
void
onTime()
onTime(
cb):void
Defined in: runtime/playback-controller.ts:296
Register a callback that fires on every clock tick with the current time.
Parameters
cb
TimeCallback
Returns
void
pause()
pause():
void
Defined in: runtime/playback-controller.ts:697
Returns
void
pickNode()
pickNode(
point,tolerance?):NodeBox|null
Defined in: runtime/playback-controller.ts:612
The topmost node under a viewport-space point (origin at the viewport
centre, y-up), or null. tolerance is grab-slop in scene units —
pass the host's pixel slop divided by its preview zoom so the grab area
stays constant on screen. See pickNode.
Parameters
point
tolerance?
number = 0
Returns
NodeBox | null
play()
play(
speed?,reverse?):void
Defined in: runtime/playback-controller.ts:686
Parameters
speed?
number = 1
reverse?
boolean = false
Returns
void
repaint()
repaint():
void
Defined in: runtime/playback-controller.ts:672
Re-lay-out and repaint the current frame without re-running any generator.
Cheap enough for a pointer-rate drag loop: stateAt early-returns for the
frame that is already current, so this is layout + draw only.
Returns
void
replaceScene()
replaceScene(
newScene):number
Defined in: runtime/playback-controller.ts:436
Hot-reload a single scene in place.
Re-runs only the edited scene's precomp (reusing every other scene's cached pass), swaps it into the state evaluator's matching slot, and refreshes the asset manager and clock duration. Untouched scenes keep their cached generators, so editing scene N never re-runs scenes ≠ N.
The render context is never torn down, so the next render paints the new frame over the old with no blank flash. Returns the resolved scene index, or -1 if no slot matched (caller can fall back to a full reload).
The edited scene's precomp re-runs a fresh asset pass, so any asset the
edit added (a new image/video/font) is now in the global asset map — but
it isn't loaded yet. We repaint synchronously for a no-flash swap of what's
already warm, then kick off an async loadAt for the current frame and
re-render once the new assets are ready, so the added asset actually shows
up. The async pass is generation-guarded so a concurrent seek/tick wins.
Parameters
newScene
The edited scene instance (carries __sceneHotId).
Returns
number
screenshot()
screenshot():
string|undefined
Defined in: runtime/playback-controller.ts:517
Capture the current frame as a base-64 PNG data URL. Forces a fresh
render before snapshotting because the WebGL drawing buffer may have
been cleared since the last tick (we don't set preserveDrawingBuffer).
Uses stateEvaluator.currentFrame (integer) rather than the clock's
float so stateAt always hits its early-return and never resets scene state.
Returns
string | undefined
seek()
seek(
frame):Promise<void>
Defined in: runtime/playback-controller.ts:383
Jump to frame, pausing playback first. Waits for required assets to
load before rendering, then prefetches upcoming frames.
This is the scrub path, so its state replay runs interruptibly — a fast backward drag supersedes each in-flight seek instead of queueing a full replay per mouse move.
Parameters
frame
number
Returns
Promise<void>
seekWhilePlaying()
seekWhilePlaying(
frame):void
Defined in: runtime/playback-controller.ts:502
Reposition the clock to frame without interrupting playback.
Parameters
frame
number
Returns
void
setMuted()
setMuted(
muted):void
Defined in: runtime/playback-controller.ts:703
Parameters
muted
boolean
Returns
void
setNodeOverride()
setNodeOverride(
path,props):void
Defined in: runtime/playback-controller.ts:639
Layer transient prop values over a node, on top of whatever the scene's generators evaluate to. Re-applied after every state evaluation and before layout, so they hold across frame changes and backward-seek replays until cleared.
This exists for direct manipulation: an editor dragging a node needs the
rendered node to follow the pointer at pointer rate, and rebuilding the
Scene for that is not viable — a host's scenes array is an input to the
player's mount effect, so a rebuild disposes and re-creates the render
surface. Overrides move the live node instead: no precomp, no teardown.
They are not persistence. The host commits the value to its own model on drop and clears the override; the next rebuild carries the same value in through the scene, and nothing is left behind.
Parameters
path
string
Structural path from TreeState.path (stable across rebuilds, unlike a node id).
props
Any props the node accepts — { x, y }, { rotation },
{ width, height }. Merged over any existing override.
Returns
void