MotionScript

@motion-script/core


@motion-script/core / TrackRenderContext

Class: TrackRenderContext

Defined in: render/track-render-context.ts:48

A RenderContext that never draws anything — it walks the same Graphics command lists a node's real render() already builds and registers any image/video fill (and any font used by a raw text/richText shape op) into an AssetTracker, instead of rasterizing.

This is what lets asset discovery for images/video/paint be inferred automatically rather than hand-declared in a prepareRender override: the precomp pass calls scene.render(trackRenderContext) in place of a dedicated declaration step (see Precomp.precompScene), and every node's existing renderSelf/renderOverlay/renderStroke — built from the exact same Graphics/fill objects used for real painting — drives this for free.

Sizing: unlike the old hand-written prepareRender (which always sized requests off the node's layoutRect), this derives width/height from the most recently declared shape op in the same draw() call — the shape a fill/stroke/shadow op actually paints. In every built-in node this coincides with layoutRect (Image/Video/ShapeNode all build their shape from it), and it's a better match for custom nodes that intentionally size a fill differently from their own layout box (e.g. a chart bar sized to its bar rect, not the chart's outer bounds). path/line descriptors default width/height to 0 (a path's extent isn't implied by its command list), so a node painting an image/video fill on a raw path/line needs to pass explicit width/height for it to size correctly — e.g. a donut chart slice would do PathBuilder.toPathState({ width, height, centerBounds }).

Extends

Constructors

Constructor

new TrackRenderContext(tracker): TrackRenderContext

Defined in: render/track-render-context.ts:67

Parameters

tracker

AssetTracker

Returns

TrackRenderContext

Overrides

RenderContext.constructor

Properties

currentNodeStack

protected currentNodeStack: string[] = []

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

Stack of node ids currently being drawn, innermost last.

Inherited from

RenderContext.currentNodeStack


drawsVisibleOnly

readonly drawsVisibleOnly: boolean = false

Defined in: render/track-render-context.ts:65

Discovery is about what a frame references, not what it shows.

A node at zero opacity still names a font, an image, a video. If this walk skipped it the asset would never be requested, and the frame it fades in on would render blank — a bug that appears two seconds after the thing that caused it and reproduces only on a cold load. So the invisible-subtree skip is refused here, and only here.

Overrides

RenderContext.drawsVisibleOnly


readsSpaceRects

readonly readsSpaceRects: false = false

Defined in: render/track-render-context.ts:54

Asset discovery never resolves a space:'parent' fill against its reference rect — it only needs to know which asset a fill names. Declaring that lets every node skip computing those rects during the precomp pass.

Overrides

RenderContext.readsSpaceRects


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.

Inherited from

RenderContext.renderStateStack

Methods

applyMask()

applyMask(): void

Defined in: render/track-render-context.ts:288

Returns

void

Overrides

RenderContext.applyMask


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

Inherited from

RenderContext.begin


beginBoolean()

beginBoolean(_op): void

Defined in: render/track-render-context.ts:284

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

Overrides

RenderContext.beginBoolean


beginCamera()

beginCamera(_viewport, _centerOn, _zoom, _heading): void

Defined in: render/track-render-context.ts:294

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
height

number

width

number

x

number

y

number

_centerOn

Vector2

_zoom

number

_heading

number

Returns

void

Overrides

RenderContext.beginCamera


beginClip()

beginClip(_clip): void

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

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

Overrides

RenderContext.beginClip


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

Inherited from

RenderContext.beginEffectScope


beginMask()

beginMask(_options?): void

Defined in: render/track-render-context.ts:287

Parameters

_options?

MaskOptions

Returns

void

Overrides

RenderContext.beginMask


currentNodeId()

protected currentNodeId(): string

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

Returns the id of the innermost node currently being drawn.

Returns

string

Inherited from

RenderContext.currentNodeId


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

Inherited from

RenderContext.currentRenderState


currentSpaceRects()

protected currentSpaceRects(): SpaceRects

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

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

Returns

SpaceRects

Inherited from

RenderContext.currentSpaceRects


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

Inherited from

RenderContext.defaultTextStyle


dispose()

dispose(): void

Defined in: render/track-render-context.ts:243

Returns

void

Overrides

RenderContext.dispose


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

Inherited from

RenderContext.draw


drawGraphics()

protected drawGraphics(graphics): void

Defined in: render/track-render-context.ts:153

render() is only ever driven from within Precomp.precompScene's bracketed loop today, unlike TrackMeasureScope (see its doc comment for the detached-measurement path that hits this for real) — but it hits the exact same ensureFrame() throw if a future caller ever invokes it unbracketed, so guard it the same way defensively.

Parameters

graphics

Graphics

Returns

void

Overrides

RenderContext.drawGraphics


end()

end(): void

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

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

Returns

void

Inherited from

RenderContext.end


endBoolean()

endBoolean(): void

Defined in: render/track-render-context.ts:285

Returns

void

Overrides

RenderContext.endBoolean


endCamera()

endCamera(): void

Defined in: render/track-render-context.ts:300

Returns

void

Overrides

RenderContext.endCamera


endClip()

endClip(): void

Defined in: render/track-render-context.ts:292

Pop the most-recently pushed clip region.

Returns

void

Overrides

RenderContext.endClip


endEffectScope()

endEffectScope(): void

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

Returns

void

Inherited from

RenderContext.endEffectScope


endMask()

endMask(): void

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

Returns

void

Overrides

RenderContext.endMask


execute()

execute(callback): void

Defined in: render/track-render-context.ts:247

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

Overrides

RenderContext.execute


isDisposed()

isDisposed(): boolean

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

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

Returns

boolean

Inherited from

RenderContext.isDisposed


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

Inherited from

RenderContext.layoutTextBlock


measureText()

measureText(): number

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

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

Returns

number

Advance width in pixels.

Overrides

RenderContext.measureText


popTextStyle()

popTextStyle(): void

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

Close the innermost scope opened by pushTextStyle.

Returns

void

Inherited from

RenderContext.popTextStyle


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

Inherited from

RenderContext.pushTextStyle


rasterizeOffscreen()

rasterizeOffscreen(_width, _height, draw): null

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

Nothing is rasterized here, but draw still has to run — a caller that rasterizes a subtree only exposes that subtree's fonts and image fills by walking it. Skipping the callback would leave a <Text> unshaped and an <Image> unloaded.

Parameters

_width

number

_height

number

draw

() => void

Returns

null

Overrides

RenderContext.rasterizeOffscreen


screenshot()

screenshot(): string | undefined

Defined in: render/track-render-context.ts:251

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

Returns

string | undefined

Overrides

RenderContext.screenshot


transform()

transform(state): RenderContext

Defined in: render/track-render-context.ts:272

Node-level effects arrive here rather than as a graphics op, so this is no longer a pure no-op: a texture effect on a node must get its image requested during precomp, or the renderer's synchronous lookup finds nothing and the effect silently has no texture to draw.

Parameters

state

Partial<TransformState>

Returns

RenderContext

Overrides

RenderContext.transform


unmount()

unmount(): void

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

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

Returns

void

Overrides

RenderContext.unmount