MotionScript

@motion-script/core


@motion-script/core / Scene

Class: Scene

Defined in: nodes/scene/scene-node.ts:85

A self-contained unit of a project's timeline.

A scene is not a node and is not composed. It owns a root Rect (a viewport-sized world container) and a generator that builds into it. This is what makes scene-level hot reloading work: each scene file is its own HMR boundary (import scene from './scene?scene'), and a scene can be swapped in place without rebuilding the rest of the timeline.

Authored with createScene — you never construct one directly:

// scenes/intro.tsx export default createScene(function* (stage) { stage.set({ fill: 'bg' }); stage.add(<Rect … />); yield* …; });

The runtime drives a scene through reset → bindAssets → ellapse → build → prepareLayoutAssets → layout → prepareRenderAssets → prepareAudioAssets → render → dispose, each forwarding to the root. Image/video/paint and font assets are no longer hand-declared — they're inferred automatically from the same render()/layout() calls (TrackRenderContext/TrackMeasureScope, see Precomp.precompScene). prepareLayoutAssets/prepareRenderAssets remain only for opaque async setup (e.g. Code's syntax grammar); prepareAudioAssets is the one asset concern that's neither drawable nor a simple async load — a playing clip's frame-ranged timeline registration.

The scene's authoring methods (add/set/to/camera/paint/sounds) all act on its RootNode root. They're merged with a BuildStage into the Stage a generator receives — see Scene.build.

Constructors

Constructor

new Scene(generator): Scene

Defined in: nodes/scene/scene-node.ts:133

Parameters

generator

SceneGenerator

Returns

Scene

Properties

__precompKey?

optional __precompKey?: string

Defined in: nodes/scene/scene-node.ts:121

Identity of this scene's content, for a PrecompCache.

Distinct from __sceneHotId, which identifies the timeline slot a scene belongs to and therefore stays the same across an edit — that is exactly what hot replacement needs, and exactly what a measurement cache must not key on, since it would serve the pre-edit frame count forever.

A host that sets this should derive it from everything the pass depends on — the scene's own content, the viewport, and the fps — so that equal keys really do imply equal passes. Because it travels on the scene instance, a pass that completes after the host has moved on is still recorded against the build it actually measured, rather than whatever is current when it lands.

Falls back to __sceneHotId when unset (see storeKeyOf), which is the right key for the Vite plugin's store — it validates entries by re-hashing each one's recorded source dependencies instead.


__sceneHotId?

optional __sceneHotId?: string

Defined in: nodes/scene/scene-node.ts:100

Stable identity of the scene's source module, stamped by the ?scene Vite transform (the scene file's path relative to the project root). Used to route a hot update back to the right timeline slot. undefined outside the dev-server ?scene pipeline.


name

name: string = "Scene"

Defined in: nodes/scene/scene-node.ts:125

Human-readable name for the timeline/errors. Defaults to "Scene"; the ?scene transform overrides it with the file's basename.


root

readonly root: RootNode

Defined in: nodes/scene/scene-node.ts:89

The world container this scene builds into. Viewport-sized, top-level. A RootNode: a layouting Rect that also acts as the scene camera.

Accessors

align

Get Signature

get align(): Anchor

Defined in: nodes/scene/scene-node.ts:227

Alignment of the root's children within the viewport.

Returns

Anchor

Set Signature

set align(value): void

Defined in: nodes/scene/scene-node.ts:228

Parameters
value

Anchor

Returns

void


assets

Get Signature

get assets(): AssetCatalog

Defined in: nodes/scene/scene-node.ts:254

The asset catalog bound to the scene (via bindAssets).

Returns

AssetCatalog


clock

Get Signature

get clock(): Readonly<NodeClock>

Defined in: nodes/scene/scene-node.ts:249

Internal timing state of the root (scene-relative clock).

Returns

Readonly<NodeClock>


fill

Get Signature

get fill(): Fill

Defined in: nodes/scene/scene-node.ts:210

The root's background fill.

Returns

Fill

Set Signature

set fill(value): void

Defined in: nodes/scene/scene-node.ts:211

Parameters
value

Fill

Returns

void


flow

Get Signature

get flow(): FlowMode

Defined in: nodes/scene/scene-node.ts:220

The root's layout mode for children: horizontal / vertical / freeform.

Returns

FlowMode

Set Signature

set flow(value): void

Defined in: nodes/scene/scene-node.ts:221

Parameters
value

FlowMode

Returns

void


gap

Get Signature

get gap(): GapSize

Defined in: nodes/scene/scene-node.ts:224

Spacing between the root's children along the layout's main axis. Set via stage.set({ gap }).

Returns

GapSize


heading

Get Signature

get heading(): number

Defined in: nodes/scene/scene-node.ts:245

Camera view rotation in degrees (clockwise).

Returns

number

Set Signature

set heading(value): void

Defined in: nodes/scene/scene-node.ts:246

Parameters
value

number

Returns

void


origin

Get Signature

get origin(): Vector2

Defined in: nodes/scene/scene-node.ts:241

World-space point that maps to the centre of the viewport.

Returns

Vector2

Set Signature

set origin(value): void

Defined in: nodes/scene/scene-node.ts:242

Parameters
value

Vector2

Returns

void


overlay

Get Signature

get overlay(): Fill

Defined in: nodes/scene/scene-node.ts:214

The root's overlay.

Returns

Fill

Set Signature

set overlay(value): void

Defined in: nodes/scene/scene-node.ts:215

Parameters
value

Fill

Returns

void


padding

Get Signature

get padding(): Insets

Defined in: nodes/scene/scene-node.ts:231

Inner spacing between the viewport edges and the root's children.

Returns

Insets

Set Signature

set padding(value): void

Defined in: nodes/scene/scene-node.ts:232

Parameters
value

Insets

Returns

void


viewportSize

Get Signature

get viewportSize(): Size2D | null

Defined in: nodes/scene/scene-node.ts:145

The full viewport this scene renders its world against.

Returns

Size2D | null


zoom

Get Signature

get zoom(): number

Defined in: nodes/scene/scene-node.ts:237

Camera magnification factor. > 1 zooms in; < 1 zooms out.

Returns

number

Set Signature

set zoom(value): void

Defined in: nodes/scene/scene-node.ts:238

Parameters
value

number

Returns

void

Methods

add()

add(node): void

Defined in: nodes/scene/scene-node.ts:162

Add a node (or array of nodes) as a child of the scene's root.

Parameters

node

Node<NodeProps> | Node<NodeProps>[]

Returns

void


bindAssets()

bindAssets(context): void

Defined in: nodes/scene/scene-node.ts:338

Bind the asset catalog to the scene's whole node subtree.

Parameters

context

AssetCatalog

Returns

void


bindContext()

bindContext(context, runInit): void

Defined in: nodes/scene/scene-node.ts:348

Push inherited context (theme/data/seed/text-style and user tokens) down the scene's whole subtree. runInit true at start-of-pass (also fires each node's init); false for the per-frame structural re-push. Mirrors bindAssets. See Node.bindContext.

Parameters

context

ContextMap

runInit

boolean

Returns

void


build()

build(stage): FrameGenerator

Defined in: nodes/scene/scene-node.ts:313

Produce this scene's frame generator. The generator is handed a single Stage object that exposes both surfaces: this scene's authoring methods (add/set/to/zoomTo/sounds/…) and the build stage's determinism (viewport/fps/random/noise/seed).

The merge is a view created with the scene as its prototype (so authoring resolves to real Scene members) overlaid with the stage's own properties and its methods bound to the stage (so determinism keeps the stage's this). One view is built per build pass.

Parameters

stage

BuildStage<Scene>

Returns

FrameGenerator


dispose()

dispose(): void

Defined in: nodes/scene/scene-node.ts:401

Returns

void


ellapse()

ellapse(totalTime): void

Defined in: nodes/scene/scene-node.ts:353

Advance the scene's clock and per-frame sampling for the whole subtree.

Parameters

totalTime

number

Returns

void


fillTo()

fillTo(to, duration, options?): FrameGenerator

Defined in: nodes/scene/scene-node.ts:200

Animate the root fill (the scene-wide background).

Parameters

to

Fill

duration

number

options?

TweenOptions<FillResolved[]>

Returns

FrameGenerator


headingTo()

headingTo(heading, duration, ease?): FrameGenerator

Defined in: nodes/scene/scene-node.ts:193

Animate the camera view rotation (heading) in degrees.

Parameters

heading

number

duration

number

ease?

EasingFunction

Returns

FrameGenerator


layout()

layout(rect, scope): void

Defined in: nodes/scene/scene-node.ts:364

Lay the scene's world out against the given (full-viewport) bounds.

Parameters

rect

BoxBounds

scope

MeasureScope

Returns

void


overlayTo()

overlayTo(to, duration, options?): FrameGenerator

Defined in: nodes/scene/scene-node.ts:205

Animate the root overlay (painted over fill + children, viewport-wide).

Parameters

to

Fill

duration

number

options?

TweenOptions<FillResolved[]>

Returns

FrameGenerator


panTo()

panTo(lookAt, duration, ease?): FrameGenerator

Defined in: nodes/scene/scene-node.ts:188

Animate the camera focus point (lookAt) — the world point at viewport centre.

Parameters

lookAt

Vector2

duration

number

ease?

EasingFunction

Returns

FrameGenerator


playSound()

playSound(src, opts?): FrameGenerator

Defined in: nodes/scene/scene-node.ts:285

Play a sound on the scene's audio timeline. Blocks for the clip's duration. Use as yield* stage.playSound(...) inside a scene generator.

Parameters

src

string | Sound

opts?

Omit<SoundProps, "src">

Returns

FrameGenerator


prepareAudioAssets()

prepareAudioAssets(tracker): void

Defined in: nodes/scene/scene-node.ts:396

Collect the scene's audio-scheduling requests — nodes with a playing clip (e.g. Video) and managed sounds (startSound/ playSound). Has no layout dependency, so it can run either side of layout; kept after by convention.

Parameters

tracker

AssetTracker

Returns

void


prepareLayoutAssets()

prepareLayoutAssets(): void

Defined in: nodes/scene/scene-node.ts:378

Fire the scene's pre-layout async setup (e.g. Code's syntax grammar). Called before layout; fire-and-forget, see Node.prepareLayoutAssets.

Returns

void


prepareRenderAssets()

prepareRenderAssets(): void

Defined in: nodes/scene/scene-node.ts:386

Fire the scene's pre-render async setup. Called after layout; fire-and-forget, see Node.prepareRenderAssets.

Returns

void


render()

render(context): void

Defined in: nodes/scene/scene-node.ts:369

Render the scene's world into context.

Parameters

context

RenderContext

Returns

void


reset()

reset(): void

Defined in: nodes/scene/scene-node.ts:321

Clear all dynamically-added children and managed sounds, and reset the clock.

Returns

void


sample()

sample(): void

Defined in: nodes/scene/scene-node.ts:359

Seed per-frame derived state (motion) without a full ellapse.

Returns

void


set()

set(props): void

Defined in: nodes/scene/scene-node.ts:171

Set one or more reactive props on the root container.

Parameters

props
align?

Anchor | (() => Anchor)

Alignment of children within the content box: a named position ('center', 'topLeft', …) or an explicit per-axis pivot Vector2 (x: -1 left … +1 right, y: -1 bottom … +1 top).

blend?

"color" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "luminosity" | "normal" | "pass-through" | (() => "color" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "luminosity" | "normal" | "pass-through")

Layer blend mode. 'pass-through' (default) does not isolate the node — its opacity scales each child/fill while they blend against the backdrop. Any other mode isolates the node and blends its flattened result against the backdrop.

bottomCenter?

Vector2 | (() => Vector2) | (() => Vector2 | (() => Vector2))

bottomLeft?

Vector2 | (() => Vector2) | (() => Vector2 | (() => Vector2))

bottomRight?

Vector2 | (() => Vector2) | (() => Vector2 | (() => Vector2))

center?

Vector2 | (() => Vector2) | (() => Vector2 | (() => Vector2))

centerLeft?

Vector2 | (() => Vector2) | (() => Vector2 | (() => Vector2))

centerRight?

Vector2 | (() => Vector2) | (() => Vector2 | (() => Vector2))

childPositioning?

ChildPositioning | (() => ChildPositioning)

Frame of reference this node lays its children out in. 'relative' (default) positions them inside this node's own content box; 'absolute' pins them to the stage instead, so their x/y are scene-root coordinates and this node's flow/gap/padding no longer place them. Overridden per child by relativeToParent.

children?

NodeChildren | (() => NodeChildren)

Child nodes. A single Node, or an arbitrarily-nested array of them — the constructor flattens nesting (.flat(Infinity)), so .map() results can be dropped in directly as a child without spreading, like React.

clip?

boolean | (() => boolean)

When true, content drawn outside this node's outline is clipped away (see Node.clipSelf).

colSpan?

number | (() => number)

How many grid columns this child spans. Default 1.

column?

number | (() => number)

1-based column index for explicit grid placement. Undefined = auto-placed.

effects?

Effect | (() => Effect)

fill?

Fill | (() => Fill)

Background fill layer(s). Each item can be a CSS color string, a fill prop object, an already-resolved fill, or a FillChain from the Fills builder. Painted behind the scene's children.

flex?

number | (() => number)

Proportional share of the free space along the parent's main axis, relative to sibling fill children (like Flutter's Expanded(flex:)). Only meaningful when this node fills the main axis — in a row that's width:'fill', in a column height:'fill'. Two siblings with flex 2 and 1 split the free space 2:1. Defaults to 1. Specifying flex without an explicit width/height defaults both to 'fill'.

flow?

FlowMode | (() => FlowMode)

Layout mode for children: flex horizontal / vertical, or overlapping freeform.

gap?

GapSize | (() => GapSize)

Spacing between children along the layout's main axis.

heading?

number | (() => number)

Rotation of the camera view in degrees (clockwise).

height?

SizeInput | (() => SizeInput)

lookAt?

Vector2 | (() => Vector2)

World-space point that maps to the centre of the viewport.

opacity?

number | (() => number)

overlay?

Fill | (() => Fill)

Overlay layer(s) — same loose values as fill, but painted over the fill and the children (clipped to the viewport). Use for textures laid across the whole scene, e.g. a VHS-grain image or video.

padding?

Insets | (() => Insets)

Inner spacing between this node's edges and its content/children.

pivot?

Anchor | (() => Anchor)

Pivot point for rotation and scale. Either a named anchor ('center', 'topRight', 'bottomLeft', … — the node align vocabulary) or an explicit Vector2: (0,0)=center, (-1,1)=top-left, (1,-1)=bottom-right. Set automatically when an anchor positioning prop is used.

relativeToParent?

RelativeToParent | (() => RelativeToParent)

This node's own override of its parent's childPositioning. 'inherit' (default) takes whatever the parent declared; 'relative' and 'absolute' opt this one node in or out regardless.

rotation?

number | (() => number)

row?

number | (() => number)

1-based row index for explicit grid placement. Undefined = auto-placed.

rowSpan?

number | (() => number)

How many grid rows this child spans. Default 1.

scale?

number | (() => number)

seed?

string | number | (() => string | number)

Origin seed for this node's Node.random source. Defaults to 0. Set it to give the node a reproducible-but-distinct random stream without re-seeding by hand. The constructor adopts it as random's origin, and the runtime rebuilds the node each playback pass, so draws stay reproducible across scrub/precomp/HMR.

size?

SizeInput | (() => SizeInput)

Sets width and height to the same value in one go. Pure sugar: at construction time, an author-facing size is expanded into width/ height before either is applied. Explicit width or height takes precedence over size (mirroring padding's side-vs-shorthand rule), so { size: 200, width: 100 } yields width: 100, height: 200. Reactive bindings and to()/set() targets both work the same as width/heightsize: 'fill', size: () => ..., or node.to({ size: 300 }, 0.5) are all valid.

topCenter?

Vector2 | (() => Vector2) | (() => Vector2 | (() => Vector2))

topLeft?

Vector2 | (() => Vector2) | (() => Vector2 | (() => Vector2))

topRight?

Vector2 | (() => Vector2) | (() => Vector2 | (() => Vector2))

width?

SizeInput | (() => SizeInput)

x?

number | (() => number)

y?

number | (() => number)

zoom?

number | (() => number)

Camera magnification factor. Values > 1 zoom in; < 1 zoom out.

Returns

void


setViewport()

setViewport(size): void

Defined in: nodes/scene/scene-node.ts:150

Record the full viewport (called by the playback engine).

Parameters

size

Size2D

Returns

void


startSound()

startSound(src, opts?): Sound

Defined in: nodes/scene/scene-node.ts:262

Start a sound on the scene's audio timeline without blocking, and return the Sound handle. Pair with stopSound to end playback.

Parameters

src

string | Sound

opts?

Omit<SoundProps, "src">

Returns

Sound


stopSound()

stopSound(sound): void

Defined in: nodes/scene/scene-node.ts:276

Stop a sound started via startSound. No-op if it isn't playing.

Parameters

sound

Sound

Returns

void


to()

to(props, duration, easing?): AnimationBuilder<RootProps>

Defined in: nodes/scene/scene-node.ts:176

Animate any root props in one call — yield* stage.to({ zoom: 2, fill: 'red' }, 1).

Parameters

props

Partial<RootProps>

duration

number

easing?

EasingFunction

Returns

AnimationBuilder<RootProps>


zoomTo()

zoomTo(zoom, duration, ease?): FrameGenerator

Defined in: nodes/scene/scene-node.ts:183

Animate the camera magnification (zoom). > 1 zooms in; < 1 zooms out.

Parameters

zoom

number

duration

number

ease?

EasingFunction

Returns

FrameGenerator