MotionScript

@motion-script/core


@motion-script/core / RenderContext

Abstract Class: RenderContext

Defined in: render/render-context.ts:127

The full rendering context passed to every scene-graph node when it draws itself. Combines shape drawing (Render2DContext), text measurement (MeasureScope), and higher-level scoping operations (transforms, masks, clips, camera, boolean ops, backdrop effects).

begin(id) / end() bracket each node's draw call so the context can track which node is active and look up per-node state (space rects, etc.). The concrete implementations (CanvasKitRenderContext, SvgRenderContext, …) translate these abstract calls into renderer-specific drawing commands.

Extends

Extended by

Implements

Constructors

Constructor

new RenderContext(): RenderContext

Returns

RenderContext

Inherited from

Render2DContext.constructor

Properties

currentNodeStack

protected currentNodeStack: string[] = []

Defined in: render/render-context.ts:225

Stack of node ids currently being drawn, innermost last.


drawsVisibleOnly

readonly drawsVisibleOnly: boolean = true

Defined in: render/render-context.ts:402

Whether this context only cares about visible output.

True for anything that paints: a subtree at zero opacity contributes no pixels, so walking it produces draw calls the rasterizer will discard.

False for TrackRenderContext, and that is the whole reason this is a capability rather than an unconditional check. The tracking walk exists to discover which images, videos, fonts and effects a frame references — regardless of whether they can be seen. An invisible node's font still has to load, because it may fade in two frames later and glyphs that were never registered never paint. Skipping it there is not an optimisation, it is a missing asset.

Same shape and same reasoning as readsSpaceRects: the context declares what it needs, and nodes check before doing work that would be thrown away. See Node.render.


readsSpaceRects

readonly readsSpaceRects: boolean = true

Defined in: render/render-context.ts:382

Whether this context ever reads NodeRenderState.rects.

True for anything that actually paints, since a fill with space:'parent' resolves against them. A context that only inspects what would be drawn — TrackRenderContext, which walks the same op lists to discover assets — never looks at them, and computing them costs an object allocation per node per frame. Nodes check this before doing that work; see Node.beforeRender.


renderStateStack

protected renderStateStack: NodeRenderState[] = []

Defined in: render/render-context.ts:371

Per-node render state for each node on the draw stack, in push order (innermost last). Kept parallel to currentNodeStack so fills with space: 'parent' can resolve their reference rect and so motion-driven effects can read the current node's velocity.

Methods

applyMask()

abstract applyMask(): void

Defined in: render/render-context.ts:290

Returns

void


begin()

begin(state): void

Defined in: render/render-context.ts:411

Open a node draw scope. Must be paired with end(). Pushes the node's id and NodeRenderState (gradient-space rects + per-frame motion) for the duration of the scope.

Parameters

state

NodeRenderState

Identity, reference rects, and sampled motion for this node.

Returns

void


beginBoolean()

abstract beginBoolean(op): void

Defined in: render/render-context.ts:270

Open a boolean-path collection scope. Shapes drawn until endBoolean() are gathered (fills/strokes suppressed) and combined with op. After endBoolean() the merged path is left as the active surface, so a paint-only Graphics (new Graphics().fill(...).stroke(...)) submitted via draw() styles the combined result.

Parameters

op

BooleanOperation

Returns

void


beginCamera()

abstract beginCamera(viewport, lookAt, zoom, heading): void

Defined in: render/render-context.ts:362

Push a camera viewport. Clips to viewport (canvas-space, centred coords) and applies the inverse camera transform so children render as seen through the lens. heading rotates the world counter to the camera angle. Paired with endCamera().

Parameters

viewport

Bounding rect of the camera node in canvas space.

height

number

width

number

x

number

y

number

lookAt

Vector2

World-space point the camera looks at.

zoom

number

Uniform scale applied around lookAt.

heading

number

Camera rotation in degrees.

Returns

void


beginClip()

abstract beginClip(clip): void

Defined in: render/render-context.ts:301

Push a clip region built from a Clip command list. The clip's shapes are unioned (with cut()s subtracted) into a single path and intersected with the active clip, so children are confined to that compound outline — any silhouette, not just a rect or ellipse. Used both for a node's clip boundary and to confine backdrop effects (blur, magnify) to the node's exact shape. Paired with endClip().

Parameters

clip

Clip

Returns

void


beginEffectScope()

beginEffectScope(_effects, _target, _width, _height): void

Defined in: render/render-context.ts:323

Open an effect scope over the node, applying effects to either the node's own content or the content beneath it. Paired with endEffectScope.

target:

  • 'foreground' — warps/filters the node's own drawing (its fill, stroke and children captured between begin/end), like blur. Used for bulge and foreground posterize.
  • 'backdrop' — warps/filters the canvas content already painted beneath the node, clipped to the active silhouette clip, so the node's own edges stay sharp (Figma-style). Used for backdrop-flagged filters (blur, grayscale, pixelate, …), magnify, backdrop posterize, and backdrop SkSL.

The renderer decides per effect whether to compose it as an ImageFilter or run it as a snapshot/redraw shader — callers never route by effect type. width/height are the node's logical size, for size-relative effects (e.g. pixelate) and shader lens boxes. No-op by default.

Parameters

_effects

SceneEffect[]

_target

EffectTarget

_width

number

_height

number

Returns

void


beginMask()

abstract beginMask(options?): void

Defined in: render/render-context.ts:289

Parameters

options?

MaskOptions

Returns

void


currentNodeId()

protected currentNodeId(): string

Defined in: render/render-context.ts:228

Returns the id of the innermost node currently being drawn.

Returns

string


currentRenderState()

protected currentRenderState(): NodeRenderState | undefined

Defined in: render/render-context.ts:428

Full render state (incl. velocity) for the node currently being drawn, if any.

Returns

NodeRenderState | undefined


currentSpaceRects()

protected currentSpaceRects(): SpaceRects

Defined in: render/render-context.ts:423

Reference rects for the node currently being drawn (parent / viewport).

Returns

SpaceRects


defaultTextStyle()

defaultTextStyle(): TextStyle

Defined in: render/render-context.ts:190

The text-style defaults in effect right now: the innermost pushTextStyle scope, or the project's theme.typography.default when no scope is open — the same preset a Text node falls back to, so a drawn label and a node label agree on the project's base typography.

Carries all ten TEXT_STYLE_KEYS, but only the shaping ones reach a Graphics op; see TEXT_SHAPING_KEYS for why fill/stroke/ shadow stay a node-level concern.

Returns

TextStyle


dispose()

dispose(): void

Defined in: render/render-context.ts:244

Returns

void


draw()

draw(graphics): void

Defined in: render/render-context.ts:205

Replay a built Graphics against this context.

Final by convention — it resolves the ambient text defaults onto the op list and hands the result to drawGraphics, which is where a backend does its actual drawing. Owning this step here rather than in each backend is what keeps the real renderer and the precomp pass's asset walk agreeing on which font an under-specified text op shapes with: a family that one resolves and the other doesn't is a font that never loads and glyphs that never paint.

Parameters

graphics

Graphics

Returns

void

Overrides

Render2DContext.draw


drawGraphics()

abstract protected drawGraphics(graphics): void

Defined in: render/render-context.ts:211

Paint a Graphics whose text ops have already been resolved against the ambient defaults. Backends implement this instead of draw.

Parameters

graphics

Graphics

Returns

void


end()

end(): void

Defined in: render/render-context.ts:417

Close the innermost node draw scope opened by begin().

Returns

void


endBoolean()

abstract endBoolean(): void

Defined in: render/render-context.ts:271

Returns

void


endCamera()

abstract endCamera(): void

Defined in: render/render-context.ts:363

Returns

void


endClip()

abstract endClip(): void

Defined in: render/render-context.ts:303

Pop the most-recently pushed clip region.

Returns

void


endEffectScope()

endEffectScope(): void

Defined in: render/render-context.ts:324

Returns

void


endMask()

abstract endMask(): void

Defined in: render/render-context.ts:291

Returns

void


execute()

abstract execute(callback): void

Defined in: render/render-context.ts:252

Execute callback, which issues shape/paint calls, and flush the result to the underlying render target (canvas, SVG document, etc.).

Parameters

callback

() => void

Returns

void


isDisposed()

isDisposed(): boolean

Defined in: render/render-context.ts:241

true after dispose() — the context must not be used after this point.

Returns

boolean


layoutTextBlock()

layoutTextBlock(state): TextBlockLayout | null

Defined in: render/render-context.ts:219

See MeasureScope.layoutTextBlock. Concrete rather than abstract, and null by default, so a backend that has no need to report glyph positions is unaffected — the only thing it gives up is on-canvas text editing in a host built on it.

Parameters

state

Partial<TextState>

Returns

TextBlockLayout | null

Implementation of

MeasureScope.layoutTextBlock


measureText()

abstract measureText(text, fontSize, fontFamily, fontWeight?, letterSpacing?, fontStyle?): number

Defined in: render/render-context.ts:128

Returns the advance width (in pixels) of text rendered at the given fontSize with the specified font properties.

Parameters

text

string

The string to measure.

fontSize

number

Size in pixels.

fontFamily

string

CSS-style family name (e.g. "Inter").

fontWeight?

number

Numeric weight (100–900). Defaults to 400 when omitted.

letterSpacing?

number

Extra inter-glyph spacing in pixels. Defaults to 0.

fontStyle?

FontStyle

Italic / oblique variant. Defaults to normal.

Returns

number

Advance width in pixels.

Implementation of

MeasureScope.measureText


popTextStyle()

popTextStyle(): void

Defined in: render/render-context.ts:176

Close the innermost scope opened by pushTextStyle.

Returns

void


pushTextStyle()

pushTextStyle(style): void

Defined in: render/render-context.ts:162

Set text-style defaults for everything drawn until the matching popTextStyle — the drawn-graphics half of <DefaultTextStyle>.

style is merged onto the defaults already in effect, per key, so nesting accumulates the way the node channel does: an outer scope's fontFamily and an inner scope's fontSize both apply, and a key set by both takes the inner value. Values are resolved (a tweened fontSize arrives as this frame's number), not callbacks.

Pass null to open a scope that inherits nothing — not the enclosing defaults and not the project's theme.typography.default. That is for a node whose text is its own vocabulary rather than the document's: Code does it so a scene-wide serif face doesn't reflow a monospaced code block.

Always pair with popTextStyle() in a finally; the stack is shared with every sibling drawn afterwards.

Parameters

style

TextStyle | null

Returns

void


rasterizeOffscreen()

rasterizeOffscreen(_width, _height, _draw, _pixelRatio?): RasterizedSurface | null

Defined in: render/render-context.ts:342

Draw draw into an offscreen buffer instead of onto the canvas, and hand back its pixels. The buffer is width × height logical px with its origin at the centre, matching the space a node draws in — so draw can be an ordinary render() call on a node subtree and needs no special casing.

This is what backs SurfaceTexture3D: View3D rasterizes each of its Surface2D children through here, then hands the pixels to the 3D backend as a texture. It runs inside the frame that consumes it, so a scrubbed frame is identical to a played one.

Returns null by default — a backend that cannot rasterize offscreen simply produces no texture, and the material renders without that map. pixelRatio is a ceiling on the buffer's device-pixel scale, not a guarantee; the renderer may clamp it.

Parameters

_width

number

_height

number

_draw

() => void

_pixelRatio?

number

Returns

RasterizedSurface | null


screenshot()

abstract screenshot(): string | undefined

Defined in: render/render-context.ts:254

Capture the current frame as a base-64 PNG data URL, or undefined if unsupported.

Returns

string | undefined


transform()

abstract transform(state): RenderContext

Defined in: render/render-context.ts:261

Push a transform (position, rotation, scale, opacity, …) and return this so subsequent draw calls are issued in the transformed space. The transform is popped when end() is called for the node that pushed it.

Parameters

state

Partial<TransformState>

Returns

RenderContext


unmount()

abstract unmount(): void

Defined in: render/render-context.ts:237

Remove all renderer-side resources for the current node (called on unmount).

Returns

void