@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.
Layout — measure() 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
| prop | default | unit / notes |
|---|---|---|
x | 0 | horizontal offset in scene pixels |
y | 0 | vertical offset (positive = up) |
width | 'fill' | SizeInput: px, 'fill', 'auto' |
height | 'fill' | same |
size | — | sugar: sets width and height together |
scale | 1 | uniform scale factor |
rotate | 0 | degrees, clockwise |
opacity | 1 | 0–1 |
blend | 'pass-through' | layer blend mode (NodeBlendMode) |
effects | [] | post-process / blend effects |
padding | 0 | inner 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
__signals?
optional__signals?:Map<string,Signal<any>>
Defined in: nodes/base/node.ts:321
Implementation of
__tweens?
optional__tweens?:Map<string,TweenFn<any>>
Defined in: nodes/base/node.ts:323
Implementation of
__upgraders?
optional__upgraders?:Map<string, () =>Signal<any>>
Defined in: nodes/base/node.ts:322
Implementation of
_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?
protectedoptional_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
protectedconstraints: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
readonlyid: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
readonlypivot:Anchor
Defined in: nodes/base/node.ts:341
random
readonlyrandom: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
bottomCenter
Get Signature
get bottomCenter():
Vector2
Defined in: nodes/base/node.ts:1264
Returns
bottomLeft
Get Signature
get bottomLeft():
Vector2
Defined in: nodes/base/node.ts:1249
Returns
bottomRight
Get Signature
get bottomRight():
Vector2
Defined in: nodes/base/node.ts:1254
Returns
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
centerLeft
Get Signature
get centerLeft():
Vector2
Defined in: nodes/base/node.ts:1269
Returns
centerRight
Get Signature
get centerRight():
Vector2
Defined in: nodes/base/node.ts:1274
Returns
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
layoutRect
Get Signature
get
protectedlayoutRect():BoxBounds
Defined in: nodes/base/node.ts:376
The allocated bounding box from the last layout pass. Reactive — reads inside callbacks are tracked.
Returns
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
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
topLeft
Get Signature
get topLeft():
Vector2
Defined in: nodes/base/node.ts:1239
Returns
topRight
Get Signature
get topRight():
Vector2
Defined in: nodes/base/node.ts:1244
Returns
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
tolerance
number
Returns
boolean
_localBounds()
_localBounds():
BoxBounds
Defined in: nodes/base/node.ts:1656
Internal
Returns
_localMatrix()
_localMatrix():
Matrix2D
Defined in: nodes/base/node.ts:1293
Internal
Composed with the camera scopes in between by runtime/node-picking.ts.
Returns
_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?
Returns
_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
_toGen()
_toGen(
to,duration,easing?):FrameGenerator
Defined in: nodes/base/node.ts:697
Parameters
to
Partial<P>
duration
number
easing?
Returns
_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
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?
Returns
addChildren()
addChildren(
children):void
Defined in: nodes/base/node.ts:1424
Parameters
children
Node<NodeProps>[]
Returns
void
adoptDetached()
protectedadoptDetached(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
Returns
void
applyClip()
protectedapplyClip(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
Returns
boolean
applyDefaultSize()
protectedapplyDefaultSize(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()
protectedapplyProp<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()
protectedapplyTransform(ctx):void
Defined in: nodes/base/node.ts:1524
Push this node's transform (position, scale, rotate, opacity, effects).
Parameters
ctx
Returns
void
beforeRender()
beforeRender(
ctx):void
Defined in: nodes/base/node.ts:1757
Parameters
ctx
Returns
void
bindAssets()
bindAssets(
context):void
Defined in: nodes/base/node.ts:1011
Parameters
context
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_contextso subtrees added this frame inherit it — must not re-fire resolveContext, which would clobber an in-flight tween's value every frame.
Parameters
parent
runResolve
boolean
Returns
void
clearChildren()
clearChildren():
void
Defined in: nodes/base/node.ts:1432
Returns
void
clipPathSelf()
protectedclipPathSelf():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()
protectedclipSelf():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?
Returns
Example
yield* node.fadeTo(0, 0.3); // fade out
yield* node.fadeTo(1, 0.3); // fade in
hitTestSelf()
protectedhitTestSelf(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
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
scope
Returns
void
layoutChildren()
protectedlayoutChildren(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
scope
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
scope
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?
Returns
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?
Returns
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?
Returns
Example
yield* node.moveY(-50, 0.4);
onRender()
onRender(
ctx):void
Defined in: nodes/base/node.ts:1731
Parameters
ctx
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
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
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()
protectedprovideContext(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
Returns
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()
protectedreinitProps(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?
Returns
render()
render(
ctx):void
Defined in: nodes/base/node.ts:1785
Parameters
ctx
Returns
void
renderChildren()
renderChildren(
ctx):void
Defined in: nodes/base/node.ts:1753
Parameters
ctx
Returns
void
renderContentWithEffects()
protectedrenderContentWithEffects(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:
- applyBackdropEffects — filters/warps the backdrop beneath the node, confined to its clipSelf silhouette.
- A
foregroundeffect scope (posterize wrapping bulge) capturing everythingbodypaints, so those shader effects warp/band the lot. - 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
body
() => void
Returns
void
renderOverlay()
protectedrenderOverlay(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
Returns
void
renderSelf()
protectedrenderSelf(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
Returns
void
renderStroke()
protectedrenderStroke(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
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?
Returns
resolveContext()
protectedresolveContext(_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
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?
Optional easing for the animated restore.
Returns
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?
Returns
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?
Returns
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()
protectedsetLayoutRect(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
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?
Returns
tryAssets()
protectedtryAssets():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?
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
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()
protectedworldMatrix():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
flattenChildrenProp()
protectedstaticflattenChildrenProp(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()
protectedstatichasFillChild(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