MotionScript

@motion-script/core


@motion-script/core / Node

Class: Node<P>

Defined in: nodes/base/node.ts:266

Base class for all scene-graph nodes.

Every visible or structural element in a scene extends Node. It wires together three orthogonal systems:

Reactive properties — fields declared with @property() are backed by Signals. Reading them inside a reactive context (e.g. a render pass) creates a subscription; writing them propagates the change automatically. Use set to update one or more props imperatively, or pass a callback () => expr to bind the prop to a derived value.

Tweening*to(props, duration, ease?) is a generator that animates one or more props to target values over the given duration (in seconds). Numeric props are interpolated; props that register a custom tween fn (via @property({ tween })) can animate any value type. The convenience helpers moveTo, moveX, moveY, fadeTo, rotateTo, and scaleTo wrap to for the most common single-property animations.

Layoutmeasure() is called top-down to resolve sizes, then layout() places the node in its allocated BoxBounds. Children are measured and laid out by the parent; the base class just stores the rect.

Built-in visual props

propdefaultunit / notes
x0horizontal offset in scene pixels
y0vertical offset (positive = up)
width'fill'SizeInput: px, 'fill', 'auto'
height'fill'same
sizesugar: sets width and height together
scale1uniform scale factor
rotate0degrees, clockwise
opacity10–1
blend'pass-through'layer blend mode (NodeBlendMode)
effects[]post-process / blend effects
padding0inner spacing, all four edges

Extended by

Type Parameters

P

P extends NodeProps = NodeProps

Implements

Constructors

Constructor

new Node<P>(props?): Node<P>

Defined in: nodes/base/node.ts:389

Parameters

props?

NodeConfig<any, P>

Returns

Node<P>

Properties

__mappers?

optional __mappers?: Map<string, (ext, prev?) => any>

Defined in: nodes/base/node.ts:325

Maps external prop value → internal cell value for fields that need it.

Implementation of

SignalHost.__mappers


__signals?

optional __signals?: Map<string, Signal<any>>

Defined in: nodes/base/node.ts:321

Implementation of

SignalHost.__signals


__tweens?

optional __tweens?: Map<string, TweenFn<any>>

Defined in: nodes/base/node.ts:323

Implementation of

SignalHost.__tweens


__upgraders?

optional __upgraders?: Map<string, () => Signal<any>>

Defined in: nodes/base/node.ts:322

Implementation of

SignalHost.__upgraders


_children

protected _children: Node<NodeProps>[] = []

Defined in: nodes/base/node.ts:387


_lastScope?

optional _lastScope?: MeasureScope

Defined in: nodes/base/node.ts:373

The MeasureScope threaded through the last measure pass, retained so off-tree work (e.g. the animated child-insert in node-lifecycle.ts) can measure a not-yet-attached child in isolation — measuring its natural size without adding it to this node's layout flow, so siblings don't shift for a frame. Undefined until this node is first measured. @internal.


_props?

protected optional _props?: NodeConfig<any, P>

Defined in: nodes/base/node.ts:298

The raw props this node was constructed with, retained past construction so a provider's provideContext can see which keys the author explicitly passed on every bind walk (e.g. DefaultTextStyle contributes only the style keys it was given). Authored identity — deliberately kept through dispose so a reused instance re-derives context from the next walk.


_stateStack

_stateStack: Map<string, SignalSnapshot<any>>[] = []

Defined in: nodes/base/node.ts:910

Internal

LIFO stack of save() snapshot layers. Underscore-internal so the reactive companion can read it; not authoring surface.


blend

blend: "color" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "luminosity" | "normal" | "pass-through"

Defined in: nodes/base/node.ts:336


clip

clip: boolean

Defined in: nodes/base/node.ts:344

When true, content drawn by this node's children is clipped to its outline (see clipSelf).


colSpan

colSpan: number

Defined in: nodes/base/node.ts:359


column

column: number | undefined

Defined in: nodes/base/node.ts:357


constraints

protected constraints: SizeConstraints

Defined in: nodes/base/node.ts:363


effects

effects: Effect

Defined in: nodes/base/node.ts:337


flex

flex: number

Defined in: nodes/base/node.ts:346


gapScale

gapScale: number

Defined in: nodes/base/node.ts:356

Per-child weight for the flex gap this node contributes to its parent's main axis, in [0, 1]. Default 1 = a full gap on each side (normal layout). Driven 0 → 1 (insert) / 1 → 0 (remove) by the animated addChildAt/removeChildAt overloads so the surrounding gap opens/closes in lockstep with the child's box instead of popping — see addChildAtAnimated. Read only by flex containers off their children; authors have no reason to set it directly. @internal.


height

height: SizeInput

Defined in: nodes/base/node.ts:332


id

readonly id: string

Defined in: nodes/base/node.ts:319


opacity

opacity: number

Defined in: nodes/base/node.ts:335


padding

padding: Insets

Defined in: nodes/base/node.ts:338


pivot

readonly pivot: Anchor

Defined in: nodes/base/node.ts:341


random

readonly random: Random

Defined in: nodes/base/node.ts:317

Per-node seeded randomness, available to every subclass without threading a Random in from the stage. Defaults to seed 0; set the origin via the NodeProps.seed prop, or re-seed in the constructor with this.random.reset(seed) / this.random.seed = seed.

Draws are reproducible across scrub/precomp/HMR out of the box: the runtime rebuilds a fresh node (and thus a fresh source at its constructor-set seed) on every playback pass rather than reusing a source that has advanced — so a draw taken during construction always starts from the seed head, no per-pass rewind needed.


rotation

rotation: number

Defined in: nodes/base/node.ts:334


row

row: number | undefined

Defined in: nodes/base/node.ts:358


rowSpan

rowSpan: number

Defined in: nodes/base/node.ts:360


scale

scale: number

Defined in: nodes/base/node.ts:333


width

width: SizeInput

Defined in: nodes/base/node.ts:331


x

x: number

Defined in: nodes/base/node.ts:329


y

y: number

Defined in: nodes/base/node.ts:330

Accessors

assets

Get Signature

get assets(): AssetCatalog

Defined in: nodes/base/node.ts:274

Returns

AssetCatalog


bottomCenter

Get Signature

get bottomCenter(): Vector2

Defined in: nodes/base/node.ts:1264

Returns

Vector2


bottomLeft

Get Signature

get bottomLeft(): Vector2

Defined in: nodes/base/node.ts:1249

Returns

Vector2


bottomRight

Get Signature

get bottomRight(): Vector2

Defined in: nodes/base/node.ts:1254

Returns

Vector2


center

Get Signature

get center(): Vector2

Defined in: nodes/base/node.ts:1235

Center of the node — equivalent to its x/y position (0,0 is the center of the layout cell).

Returns

Vector2


centerLeft

Get Signature

get centerLeft(): Vector2

Defined in: nodes/base/node.ts:1269

Returns

Vector2


centerRight

Get Signature

get centerRight(): Vector2

Defined in: nodes/base/node.ts:1274

Returns

Vector2


children

Get Signature

get children(): Node<NodeProps>[]

Defined in: nodes/base/node.ts:1375

Returns

Node<NodeProps>[]


clock

Get Signature

get clock(): Readonly<NodeClock>

Defined in: nodes/base/node.ts:970

Internal timing state.

Returns

Readonly<NodeClock>


global

Get Signature

get global(): WorldTransform

Defined in: nodes/base/node.ts:1339

Resolved world-space transform — the same anchor points and metrics as the local getters (center, topRight, rotation, …) but folded through the full ancestor chain, so values are absolute scene coordinates rather than parent-relative ones. See WorldTransform. Every field is reactive.

Examples
// Read another node's absolute corner, regardless of its parent:
const p = other.global.topRight;   // world-space {x, y}

### Reading vs. placing
`global` is for *reading* world coordinates. `x`/`y` (and the anchor props)
are **parent-relative**, so assigning a world value to them does not by
itself place this node in world space — it offsets it from this node's own
parent. To land exactly on another node regardless of either parent,
subtract this node's parent's world contribution:
// Place this node's origin exactly on `other`, any parent:
new Rect({
  x: () => other.global.x - (myParent.global.x),
  y: () => other.global.y - (myParent.global.y),
});

When both nodes share the same parent origin (e.g. both at the scene root),
`x: () => other.global.x` already lands on target with no compensation.
Returns

WorldTransform


layoutRect

Get Signature

get protected layoutRect(): BoxBounds

Defined in: nodes/base/node.ts:376

The allocated bounding box from the last layout pass. Reactive — reads inside callbacks are tracked.

Returns

BoxBounds


measuredHeight

Get Signature

get measuredHeight(): number

Defined in: nodes/base/node.ts:1221

Returns

number


measuredRect

Get Signature

get measuredRect(): BoxBounds

Defined in: nodes/base/node.ts:385

Internal

Returns

BoxBounds


measuredWidth

Get Signature

get measuredWidth(): number

Defined in: nodes/base/node.ts:1217

Returns

number


name

Get Signature

get name(): string

Defined in: nodes/base/node.ts:584

Returns

string


parent

Get Signature

get parent(): Node<NodeProps> | null

Defined in: nodes/base/node.ts:270

Returns

Node<NodeProps> | null


properties

Get Signature

get properties(): P

Defined in: nodes/base/node.ts:580

Returns

P


topCenter

Get Signature

get topCenter(): Vector2

Defined in: nodes/base/node.ts:1259

Returns

Vector2


topLeft

Get Signature

get topLeft(): Vector2

Defined in: nodes/base/node.ts:1239

Returns

Vector2


topRight

Get Signature

get topRight(): Vector2

Defined in: nodes/base/node.ts:1244

Returns

Vector2

Methods

_cameraScope()

_cameraScope(): CameraScope | null

Defined in: nodes/base/node.ts:1594

Internal

Returns

CameraScope | null


_confinesChildren()

_confinesChildren(): boolean

Defined in: nodes/base/node.ts:1606

Internal

Returns

boolean


_hitTestSelf()

_hitTestSelf(local, tolerance): boolean

Defined in: nodes/base/node.ts:1661

Internal

Dispatch seam so node-picking.ts can reach the protected override.

Parameters

local

Vector2

tolerance

number

Returns

boolean


_localBounds()

_localBounds(): BoxBounds

Defined in: nodes/base/node.ts:1656

Internal

Returns

BoxBounds


_localMatrix()

_localMatrix(): Matrix2D

Defined in: nodes/base/node.ts:1293

Internal

Composed with the camera scopes in between by runtime/node-picking.ts.

Returns

Matrix2D


_prepareStep()

_prepareStep(to, duration, easing?): TweenStepper

Defined in: nodes/base/node.ts:617

Resolve a single to() step into a flat TweenStepper — all the per-key setup (anchor handling, mapper, numeric-vs-custom routing) happens once here, then advance(dt) is allocation-free. Used by both the generator path (_toGen) and the batched parallel path.

Parameters

to

Partial<P>

duration

number

easing?

EasingFunction

Returns

TweenStepper


_sampleMotion()

protected _sampleMotion(): void

Defined in: nodes/base/node.ts:1514

Compute this frame's motion (velocity/direction/speed/angular/scale) into _renderState as a backward difference against the previous frame, and roll the history forward. Velocity is 0/{0,0} when no trustworthy delta exists — the first frame, or after a non-monotonic time jump (only 0 < dt <= MAX is trusted, so a scrub that resets the clock reads as "unknown" rather than a spurious huge velocity). The world position matches applyTransform (layoutRect + x, layoutRect - y, y-down). Called via sample every frame; layout-dependent fields (rects/elapsed) are filled in by beforeRender at draw time.

Returns

void


_spaceRects()

protected _spaceRects(): SpaceRects

Defined in: nodes/base/node.ts:1777

Reference rects for fills with space:'parent', expressed in this node's local space (origin = this node's positioned centre, y-down to match the canvas). The viewport (space:'global') is resolved by the renderer, which knows the surface size. Rotation/scale of this node are not folded in — the rect is the axis-aligned parent box, which is what gradients expect.

Returns

SpaceRects


_toGen()

_toGen(to, duration, easing?): FrameGenerator

Defined in: nodes/base/node.ts:697

Parameters

to

Partial<P>

duration

number

easing?

EasingFunction

Returns

FrameGenerator


_writeProp()

_writeProp(field, value): void

Defined in: nodes/base/node.ts:567

Internal

Hot-path prop write (mapper- and binding-aware). Public-but-underscored like _toGen/_prepareStep so reactive companions in this directory can call it; not part of the authoring surface.

Parameters

field

string

value

unknown

Returns

void


add()

add(child): void

Defined in: nodes/base/node.ts:1398

Compose this node's internal children — the constructor-friendly entry point a custom composite calls to build its own subtree (a single node or an array, JSX included). Sugar over addChild/addChildren: it works the same before the node is linked into the tree (in the constructor) as after, so a composite builds its structure from props right in its constructor — no init-style hook, no idempotency guard, since the constructor runs once.

Accepts the same shape as the children prop — a single node, or an arbitrarily-nested array (.flat(Infinity)), with non-Node entries (false/null/undefined from cond && <Node/>) filtered out — so this.add(items.map(...)) or this.add(cond && <Text/>) work directly.

Parameters

child

NodeChildren

Returns

void

Example

constructor(props?) {
  super(props);
  this.add(<Rect ref={this.rowRef} group="row">{…}</Rect>);
}

addChild()

addChild(child): void

Defined in: nodes/base/node.ts:1408

Parameters

child

Node

Returns

void


addChildAt()

Call Signature

addChildAt(child, index): void

Defined in: nodes/base/node.ts:1437

Parameters
child

Node

index

number

Returns

void

Call Signature

addChildAt(child, index, duration, easing?): FrameGenerator

Defined in: nodes/base/node.ts:1438

Parameters
child

Node

index

number

duration

number

easing?

EasingFunction

Returns

FrameGenerator


addChildren()

addChildren(children): void

Defined in: nodes/base/node.ts:1424

Parameters

children

Node<NodeProps>[]

Returns

void


adoptDetached()

protected adoptDetached(node): void

Defined in: nodes/base/node.ts:1105

Adopt a detached node for binding only — its asset catalog, inherited context and clock — without making it a child.

Tree membership supplies three things a node cannot work without: the asset catalog (a webfont never shapes and an <Image> never loads without it), the resolved context map (theme tokens), and a ticking clock. Layout and painting are not among them. So a node used purely as a source of pixels — a Tex.surface(...) subtree rasterized onto 3D geometry — can be bound by whatever consumes it and laid out on demand, instead of having to sit in a particular place in the tree.

Safe to call every frame: bindAssets short-circuits on an unchanged catalog, resolveContext is fired only on the adoptee's first bind, and ellapse is idempotent for a repeated time.

Parameters

node

Node

Returns

void


afterRender()

afterRender(ctx): void

Defined in: nodes/base/node.ts:1781

Parameters

ctx

RenderContext

Returns

void


applyClip()

protected applyClip(ctx): boolean

Defined in: nodes/base/node.ts:1681

Open clipSelf()'s outline as a clip scope, confining whatever is drawn until the matching ctx.endClip() to the shape. Returns true when a clip was actually opened (so the caller knows to close it) and false when the node has no outline (the default).

Parameters

ctx

RenderContext

Returns

boolean


applyDefaultSize()

protected applyDefaultSize(props?): void

Defined in: nodes/base/node.ts:492

Figma-style smart default for width/height: hug-to-content when the node is given children, fill-the-parent when it's empty — so a plain new Rect({ children: [...] }) shrink-wraps like a Figma auto-layout frame, while an empty one behaves like a background/spacer. Called once from the constructor (skipped when flex is set, since that already implies 'fill'), so it's the baseline every Node gets for free.

Subclasses with their own sizing convention (Text hugs single-line text but fills when wrapping/autofit; Path/RichText always hug; FlexNode always hugs) override this — typically a one-line replacement — instead of duplicating the children-check in their constructor.

Parameters

props?

NodeConfig<any, P>

Returns

void


applyProp()

protected applyProp<Ext, Int>(field, initial, options?): void

Defined in: nodes/base/node.ts:558

Declare a reactive prop on this node. Creates a Signal-backed accessor for field, applies an initial value (callback → reactive binding; otherwise constant), and registers optional tween/mapper metadata used by set() and to().

Subsequent calls for the same field reuse the existing cell and act as a value assignment, so subclasses can override a parent's default by calling applyProp again without losing the cell or its bindings.

Type Parameters

Ext

Ext

Int

Int = Ext

Parameters

field

string

initial

Ext | (() => Ext) | undefined

options?

PropOptions<Ext, Int>

Returns

void


applyTransform()

protected applyTransform(ctx): void

Defined in: nodes/base/node.ts:1524

Push this node's transform (position, scale, rotate, opacity, effects).

Parameters

ctx

RenderContext

Returns

void


beforeRender()

beforeRender(ctx): void

Defined in: nodes/base/node.ts:1757

Parameters

ctx

RenderContext

Returns

void


bindAssets()

bindAssets(context): void

Defined in: nodes/base/node.ts:1011

Parameters

context

AssetCatalog

Returns

void


bindContext()

bindContext(parent, runResolve): void

Defined in: nodes/base/node.ts:1074

Push inherited context down this subtree, mirroring bindAssets.

runResolve separates the two responsibilities the walk has:

  • true (first bind of this instance / a freshly-added child): also invoke resolveContext, which applies inherited context values to the already-built structure. It runs once per instance (the runtime rebuilds rather than replaying), so it must not depend on being re-fired.
  • false (per-frame structural re-push): only refresh _context so subtrees added this frame inherit it — must not re-fire resolveContext, which would clobber an in-flight tween's value every frame.

Parameters

parent

ContextMap

runResolve

boolean

Returns

void


clearChildren()

clearChildren(): void

Defined in: nodes/base/node.ts:1432

Returns

void


clipPathSelf()

protected clipPathSelf(): Clip | null

Defined in: nodes/base/node.ts:1673

An optional clip path that cuts through this node's own content and its children — unlike clip, which only confines children to the node's outline and leaves the node's own fill/stroke untouched. Returning null (the default) applies no such cut. Media nodes (Image, Video) expose this as an author-facing clipPath prop so a path can carve the painted frame and everything stacked on it as one.

Returns

Clip | null


clipSelf()

protected clipSelf(): Clip | null

Defined in: nodes/base/node.ts:1580

This node's outline as a Clip command list — the single source of truth for every clip the node needs: its clip boundary (when clip is true) and the silhouette its backdrop effects (backdrop-flagged filters, magnify) are confined to. Returning null (the default) means the node has no clip outline, so its children render unclipped and it gets no backdrop effects. Nodes with a definite box (shapes via ShapeNode, layout containers like FlexNode) override this to describe their geometry — and so behave the same way for clip and effect area.

Returns

Clip | null


dispose()

dispose(): void

Defined in: nodes/base/node.ts:1912

Returns

void


ellapse()

ellapse(totalTime): void

Defined in: nodes/base/node.ts:974

Parameters

totalTime

number

Returns

void


fadeTo()

fadeTo(opacity, duration, ease?): FrameGenerator

Defined in: nodes/base/node.ts:747

Animate opacity to the target value.

Parameters

opacity

number

Target opacity in the range [0, 1].

duration

number

ease?

EasingFunction

Returns

FrameGenerator

Example

yield* node.fadeTo(0, 0.3);   // fade out
yield* node.fadeTo(1, 0.3);   // fade in

hitTestSelf()

protected hitTestSelf(local, tolerance): boolean

Defined in: nodes/base/node.ts:1628

Whether local — a point in this node's local space (centred on the node, y-up, rotation and scale already removed) — is inside the node, within tolerance scene units of its edge.

The default is the layout box, which is the right answer for containers, text, and media: their box is their extent. ShapeNode narrows it to the node's declared clipSelf outline. Custom nodes that draw their own content can override this so selection follows what they actually paint.

tolerance is grab-slop, applied outward. An editor passes its zoom-corrected pixel slop so the grab area stays constant on screen regardless of preview zoom.

Parameters

local

Vector2

tolerance

number

Returns

boolean


isAutoSize()

isAutoSize(axis): boolean

Defined in: nodes/base/node.ts:1365

Parameters

axis

"width" | "height"

Returns

boolean


layout()

layout(rect, scope): void

Defined in: nodes/base/node.ts:1810

Default layout: record rect, then stack-layout children (see layoutChildren). This is what makes a plain Node — and any ShapeNode leaf (Ellipse, Polygon, …) that doesn't override layout — able to nest children out of the box, the same way Image (via Rect) does, just with simple centered stacking instead of flex/stack. Subclasses with their own child-layout (Rect, MaskGroup, Camera, BooleanGroup) override this and call setLayoutRect instead, so children aren't laid out twice.

Parameters

rect

BoxBounds

scope

MeasureScope

Returns

void


layoutChildren()

protected layoutChildren(rect, scope): void

Defined in: nodes/base/node.ts:1824

Stack-layout this node's children, centered within rect's content area: each child is measured against the padded inner box and given a BoxBounds centered on it (sized to its own measured size, capped to the content area), offsetting from center via its own x/y. Called by the default layout; nodes that run their own child-layout (Rect's flex/stack, Camera's viewport, …) override layout instead and don't call this.

Parameters

rect

BoxBounds

scope

MeasureScope

Returns

void


measure()

measure(constraints, scope): Partial<Size2D>

Defined in: nodes/base/node.ts:1841

Default measure: resolve width/height, hugging children stack-style on any "hug" axis. A "hug" axis shrink-wraps to the largest child extent on that axis (children overlap and are centered — they don't sum), plus this node's padding — the same content size layoutChildren lays them out in. A fixed or "fill" axis resolves as before.

This is what lets a plain Node — and any ShapeNode leaf (Ellipse, Polygon, Camera, …) that doesn't override measure — hug its children out of the box, matching how Rect's "stack" mode measures rather than collapsing to 0 (which resolving "hug" against a content size of 0 used to do, so a hugging non-Rect container rendered nothing).

Parameters

constraints

SizeConstraints

scope

MeasureScope

Returns

Partial<Size2D>


moveTo()

moveTo(x, y, duration, ease?): FrameGenerator

Defined in: nodes/base/node.ts:715

Animate both x and y to the given position.

Parameters

x

number

y

number

duration

number

ease?

EasingFunction

Returns

FrameGenerator

Example

yield* node.moveTo(200, 100, 0.5, ease.outCubic);

moveX()

moveX(x, duration, ease?): FrameGenerator

Defined in: nodes/base/node.ts:725

Animate only the horizontal position (x).

Parameters

x

number

duration

number

ease?

EasingFunction

Returns

FrameGenerator

Example

yield* node.moveX(300, 0.4);

moveY()

moveY(y, duration, ease?): FrameGenerator

Defined in: nodes/base/node.ts:735

Animate only the vertical position (y).

Parameters

y

number

duration

number

ease?

EasingFunction

Returns

FrameGenerator

Example

yield* node.moveY(-50, 0.4);

onRender()

onRender(ctx): void

Defined in: nodes/base/node.ts:1731

Parameters

ctx

RenderContext

Returns

void


prepareAudio()

prepareAudio(_tracker): void

Defined in: nodes/base/node.ts:1197

Register this node's audio scheduling needs on the timeline — the one asset concern that's neither drawable (like images/video/paint, inferred via TrackRenderContext) nor a simple async load (see prepareLayout): a playing clip has to be declared into the frame-ranged timeline AssetManager/AudioDevice use to keep audio in sync while scrubbing. No-op by default; Video overrides it.

Parameters

_tracker

AssetTracker

Returns

void


prepareAudioAssets()

prepareAudioAssets(tracker, path?): void

Defined in: nodes/base/node.ts:1207

Walk the subtree registering each node's audio requests (see prepareAudio). Stamps the owning node's structural path onto any audio requests emitted, so the timeline can draw each clip on its own bar — purely for display, playback ignores ownerPath.

Parameters

tracker

AssetTracker

path?

string = ""

Returns

void


prepareLayout()

prepareLayout(): void | Promise<void | Disposer>

Defined in: nodes/base/node.ts:1130

Opaque async setup needed before layout — e.g. Code's syntax grammar, which tokenization/measurement depends on. Runs in the precomp pass ahead of layout, so the node cannot read its layoutRect here (it hasn't been laid out yet). Image/video/paint and font requests are no longer declared here — they're inferred automatically from the same render()/layout() calls a node already makes (see TrackRenderContext/TrackMeasureScope). No-op by default.

The framework does not await the returned promise inline (precomp stays fully synchronous) — it's fired once per frame and, when nothing changed, should return synchronously (void). Memoize like Video's syncVideo() does: key off whatever prop drives the async work and skip re-running when the key is unchanged. When the promise resolves to a Disposer, it replaces (and disposes) any previous one for this node+phase, and runs when this node is disposed.

Returns

void | Promise<void | Disposer>


prepareLayoutAssets()

prepareLayoutAssets(): void

Defined in: nodes/base/node.ts:1154

Walk the subtree firing each node's pre-layout async setup (see prepareLayout). Fire-and-forget: does not block precomp's synchronous per-frame pass.

Returns

void


prepareRender()

prepareRender(): void | Promise<void | Disposer>

Defined in: nodes/base/node.ts:1141

Opaque async setup needed before render, with the node's layoutRect available (runs after layout). No-op by default — no built-in node currently needs this timing, but it's kept symmetric with prepareLayout for custom nodes whose async setup depends on knowing their rendered size. See prepareLayout for the contract.

Returns

void | Promise<void | Disposer>


prepareRenderAssets()

prepareRenderAssets(): void

Defined in: nodes/base/node.ts:1174

Walk the subtree firing each node's pre-render async setup (see prepareRender). Fire-and-forget: does not block precomp's synchronous per-frame pass.

Returns

void


provideContext()

protected provideContext(parent): ContextMap

Defined in: nodes/base/node.ts:1058

Providers override this to attach their token(s) to the ContextMap handed to descendants. Base passes the parent's map through unchanged.

Parameters

parent

ContextMap

Returns

ContextMap


reinit()

reinit(force?): void

Defined in: nodes/base/node.ts:544

Public entry point to reinitProps. A Scene owns its root node by composition (it no longer is a node), so it can't reach the protected reinitProps directly — it calls this on its root before a rebuild to restore default-baseline signals after a prior dispose, and with force to also reset live-but-tweened props back to their defaults.

Parameters

force?

boolean = false

Returns

void


reinitProps()

protected reinitProps(force?): void

Defined in: nodes/base/node.ts:532

Re-create this node's reactive signals from their

Parameters

force?

boolean = false

Returns

void


removeChild()

removeChild(child): Node<NodeProps> | null

Defined in: nodes/base/node.ts:1416

Parameters

child

Node

Returns

Node<NodeProps> | null


removeChildAt()

Call Signature

removeChildAt(index): Node<NodeProps> | null

Defined in: nodes/base/node.ts:1451

Parameters
index

number

Returns

Node<NodeProps> | null

Call Signature

removeChildAt(index, duration, easing?): FrameGenerator

Defined in: nodes/base/node.ts:1452

Parameters
index

number

duration

number

easing?

EasingFunction

Returns

FrameGenerator


render()

render(ctx): void

Defined in: nodes/base/node.ts:1785

Parameters

ctx

RenderContext

Returns

void


renderChildren()

renderChildren(ctx): void

Defined in: nodes/base/node.ts:1753

Parameters

ctx

RenderContext

Returns

void


renderContentWithEffects()

protected renderContentWithEffects(ctx, body): void

Defined in: nodes/base/node.ts:1726

Run body (this node's own painting + children) inside the node's effect and clip-path scopes — the shared content-rendering envelope every node uses so effects behave identically regardless of how a node draws. The caller is expected to have already pushed the node's transform (applyTransform). The envelope, outermost-first:

  1. applyBackdropEffects — filters/warps the backdrop beneath the node, confined to its clipSelf silhouette.
  2. A foreground effect scope (posterize wrapping bulge) capturing everything body paints, so those shader effects warp/band the lot.
  3. A clipPathSelf clip cutting through both the node's own paint and its children.

Nodes with a bespoke onRender (boolean, mask, …) call this with their custom body to gain the same effect support as a standard shape, instead of duplicating the scope bookkeeping.

Parameters

ctx

RenderContext

body

() => void

Returns

void


renderOverlay()

protected renderOverlay(ctx): void

Defined in: nodes/base/node.ts:1558

Paint the node's overlay layer — over its own fill and its children, but under the stroke — clipped to the node's silhouette. Called from onRender after children render and before renderStroke. No-op by default; ShapeNode paints the resolved overlay as a fill of its silhouette so a texture (e.g. VHS grain) sits over the whole subtree.

Parameters

ctx

RenderContext

Returns

void


renderSelf()

protected renderSelf(ctx): void

Defined in: nodes/base/node.ts:1548

Hook for custom nodes that draw their own content (raw Graphics commands, etc.) without subclassing ShapeNode. Called from onRender between the transform push and the children render, the same slot ShapeNode.renderSelf occupies. No-op by default — drawing nothing here doesn't change the render flow at all.

Parameters

ctx

RenderContext

Returns

void


renderStroke()

protected renderStroke(ctx): void

Defined in: nodes/base/node.ts:1568

Paint the node's stroke last — over its fill, children, and overlay. Deferred out of renderSelf (which now draws only shadow+fill) so the stroke frames the whole subtree and sits above any overlay. Called from onRender after renderOverlay. No-op by default; ShapeNode strokes its silhouette.

Parameters

ctx

RenderContext

Returns

void


reparent()

Call Signature

reparent(newParent): void

Defined in: nodes/base/node.ts:1886

Parameters
newParent

Node

Returns

void

Call Signature

reparent(newParent, duration, easing?): FrameGenerator

Defined in: nodes/base/node.ts:1887

Parameters
newParent

Node

duration

number

easing?

EasingFunction

Returns

FrameGenerator


resolveContext()

protected resolveContext(_ctx): void

Defined in: nodes/base/node.ts:1052

Hook for applying inherited context values to this node, once, after the node is linked into the tree and the context walk has resolved its ancestors' providers — the first moment useContext returns real values (the constructor runs before the node is linked, so it can't read context).

Runs exactly once per node instance: the runtime rebuilds the subtree on every reset/scrub/precomp rather than replaying this hook, so there is no "each pass" re-entry to guard against — never call clearChildren or write idempotency ceremony here.

Composition rule

Structure (which children exist, and how many) is built in the constructor via add from props — never here, and never from context. This hook applies context-derived values only: read the resolved value from ctx (or useContext) and write it onto the already-built structure, typically through refs captured in the constructor.

Parameters

_ctx

ContextMap

Returns

void

Example

// constructor: this.add(<Rect ref={this.accent} … />)   // structure from props
protected override resolveContext(ctx: ContextMap): void {
  this.accent().set({ fill: ctx.get(ThemeToken).accent }); // value from context
}

resolveSizeInput()

resolveSizeInput(sizeInput, availableSize, childrenSize): number

Defined in: nodes/base/node.ts:1369

Parameters

sizeInput

SizeInput

availableSize

number

childrenSize

number

Returns

number


restore()

Call Signature

restore(): void

Defined in: nodes/base/node.ts:945

Pop the most recent save snapshot and roll this node back to it.

Called with no duration (or 0), every prop is reapplied instantly — plain values are set, reactive bindings are re-bound. Called with a positive duration, the numeric props (and any with a custom tween) animate toward their saved values over that many seconds; once the tween finishes the full snapshot is reapplied, which re-binds any reactive props and snaps non-tweenable props (e.g. strings) to their saved values.

A no-op (returns immediately) if there is nothing on the stack.

Returns

void

Call Signature

restore(duration, easing?): FrameGenerator

Defined in: nodes/base/node.ts:946

Pop the most recent save snapshot and roll this node back to it.

Called with no duration (or 0), every prop is reapplied instantly — plain values are set, reactive bindings are re-bound. Called with a positive duration, the numeric props (and any with a custom tween) animate toward their saved values over that many seconds; once the tween finishes the full snapshot is reapplied, which re-binds any reactive props and snaps non-tweenable props (e.g. strings) to their saved values.

A no-op (returns immediately) if there is nothing on the stack.

Parameters
duration

number

Seconds to animate the rollback over. Omit for an instant restore.

easing?

EasingFunction

Optional easing for the animated restore.

Returns

FrameGenerator


rotateTo()

rotateTo(rotation, duration, ease?): FrameGenerator

Defined in: nodes/base/node.ts:757

Animate rotate to the target angle (degrees, clockwise).

Parameters

rotation

number

duration

number

ease?

EasingFunction

Returns

FrameGenerator

Example

yield* node.rotateTo(180, 0.6, ease.inOutQuad);

sample()

sample(): void

Defined in: nodes/base/node.ts:999

Per-frame sampling of derived render state (currently motion). Recurses to children so the whole subtree is sampled in one pass. Called from ellapse every frame; kept as a named seam so the priming path can seed the same state without a full ellapse (see StateEvaluator.resetSlot).

Returns

void


save()

save(): void

Defined in: nodes/base/node.ts:926

Push a snapshot of this node's current state onto its save stack.

Every reactive prop (x, y, scale, opacity, fill, …) is captured, preserving reactive bindings — a prop bound to () => other().x is saved as the binding, not just its resolved value, so restore re-binds it rather than freezing the value. Calls stack: each save() pushes a new layer, and each restore pops the most recent one.

Returns

void

Example

node.save();
yield* node.moveTo(200, 0, 1);
yield* node.restore(1);   // animate back to where it was saved

scaleTo()

scaleTo(scale, duration, ease?): FrameGenerator

Defined in: nodes/base/node.ts:768

Animate scale to the target factor.

Parameters

scale

number

duration

number

ease?

EasingFunction

Returns

FrameGenerator

Example

yield* node.scaleTo(1.5, 0.4);   // grow
yield* node.scaleTo(0,   0.3);   // shrink to nothing

set()

set(props): void

Defined in: nodes/base/node.ts:588

Parameters

props

{ [K in string | number | symbol]?: P[K] | (() => P[K]) }

Returns

void


setLayoutRect()

protected setLayoutRect(rect): void

Defined in: nodes/base/node.ts:1796

Record this node's allocated bounds without touching children. Used by subclasses that run their own child-layout pass (e.g. Rect's flex/stack) and so skip layoutChildren.

Parameters

rect

BoxBounds

Returns

void


tick()

tick(_globalTime): void

Defined in: nodes/base/node.ts:965

Parameters

_globalTime

number

Returns

void


to()

to(to, duration, easing?): AnimationBuilder<P>

Defined in: nodes/base/node.ts:607

Parameters

to

Partial<P>

duration

number

easing?

EasingFunction

Returns

AnimationBuilder<P>


tryAssets()

protected tryAssets(): AssetCatalog | null

Defined in: nodes/base/node.ts:280

Returns the bound asset catalog, or null if this node hasn't been bound yet.

Returns

AssetCatalog | null


useContext()

useContext<T>(ctx): T

Defined in: nodes/base/node.ts:301

Read the nearest ancestor provider's value for ctx (or its default).

Type Parameters

T

T

Parameters

ctx

Context<T>

Returns

T


wiggle()

wiggle(amplitudes, duration, options?): FrameGenerator

Defined in: nodes/base/node.ts:831

Continuously jitter one or more numeric props around their current values for duration seconds, then settle them back exactly where they started.

The target reads like to — an object of prop → amplitude rather than prop → target — so you name props as typed object keys, never string arguments, and can jitter several at once: wiggle({ x: 8, rotation: 2 }, 0.6). Each value is the peak offset from that prop's base, in the prop's own units. Call-wide shaping (frequency, settle) goes in the trailing WiggleOptions bag, mirroring how TweenOptions bundles its knobs.

Unlike to(), which drives a prop to a target, wiggle adds an organic offset on top of a fixed base — each prop's value at the moment the generator starts. Offsets are drawn from this node's seeded random noise field, so they are correlated over time (nearby frames get nearby offsets) rather than the jagged jumps independent draws would give — the difference that makes it read as hand-held shake / drift rather than static. Because the source is seeded per node, the motion is reproducible across scrub / precomp / HMR out of the box.

The offset rides on each prop's stored numeric value, so raw props (x, rotation, …) and mapped props that resolve to a plain number both wiggle correctly. A prop whose stored value isn't a number — width: 'fill', or a per-corner cornerRadius object — has no scalar to offset, so it's skipped with a dev-time warning rather than producing NaN.

The bases are captured once, so wiggle composes: run it inside parallel alongside a to() on other props, or give sibling nodes distinct seeds (via the NodeProps.seed prop) so a crowd wiggles out of phase. Every prop's offset eases to zero over the final settle fraction so it lands back on its base without a visible snap.

Parameters

amplitudes

{ [K in string | number | symbol]?: number }

Map of prop → peak offset from its base, in the prop's own units. Same key shape as to's target ({ x, y, rotation, … }).

duration

number

Seconds to wiggle for. Pass Infinity inside a parallel for an endless jitter bounded by its siblings (no settle is applied to an infinite wiggle).

options?

WiggleOptions

Call-wide WiggleOptions: frequency (default 4) and settle. frequency applies to every prop; for a per-prop rate, use a second wiggle in the same parallel.

Returns

FrameGenerator

Examples

// Shake horizontally for a beat, then rest exactly where it began:
yield* node.wiggle({ x: 8 }, 0.6);
// A faster shake with a hard cut (no ease-out) at the end:
yield* node.wiggle({ x: 12, y: 12 }, 1, { frequency: 8, settle: 0 });
// Hand-held drift while it moves across (offset composes with the move):
yield* parallel(
  node.moveX(400, 2),
  node.wiggle({ y: 6, rotation: 2 }, 2, { frequency: 3 }),
);

worldMatrix()

protected worldMatrix(): Matrix2D

Defined in: nodes/base/node.ts:1306

This node's full transform in canvas (y-down) world space — the product of every ancestor's local matrix from the root down to this node. Reactive: walks the live parent chain and reads each node's transform signals.

Returns

Matrix2D


flattenChildrenProp()

protected static flattenChildrenProp(props): Node<NodeProps>[]

Defined in: nodes/base/node.ts:462

Flatten a constructor's raw children prop into the Node instances it contains, without mutating or adding them — the same normalisation the constructor applies before addChildren, exposed standalone so applyDefaultSize overrides can inspect children's own resolved width/height before they're attached (JSX children are constructed, defaults and all, before being passed in as props).

Parameters

props

{ children?: unknown; } | undefined

Returns

Node<NodeProps>[]


hasFillChild()

protected static hasFillChild(children, axis): boolean

Defined in: nodes/base/node.ts:475

True if any of children requests "fill" on axis — the signal a container's applyDefaultSize override uses to decide whether its own hug default on that axis would strand the child with no space to fill into (see Rect/FlexNode overrides).

Parameters

children

Node<NodeProps>[]

axis

"width" | "height"

Returns

boolean