Skip to content
MotionActor
Esc
↑↓navigate↵open⌘Jpreview
On this page

Renderers

A renderer draws one actor class on one backend from the resolved state of one frame.

A renderer is a function from one resolved actor to what a backend draws. It declares the backend it draws for and the classes it handles, and it gets everything else from the frame.

import { class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor, 
function signal<T>(): RequiredSignal<T> (+1 overload)
module signal
A timeline value on an actor, and an input to every spawn of it. Without an initial value the signal is required: `ctx.spawn` must supply it.
signal
} from "@motionactor/core";
import { const dom: StagedBackend<React.FC<ReactBackendHostProps>, "dom", React.ReactNode>
The React DOM backend, and the `dom` binding code names: `dom.render(Box, …)`, `createRenderRuntime({ backends: [dom] })`.
dom
} from "@motionactor/dom/react";
export class class BadgeBadge extends class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor { Badge.label: ActorFieldSignal<string>label = signal<string>(initial: string): ActorFieldSignal<string> (+1 overload)
A timeline value on an actor, and an input to every spawn of it. Without an initial value the signal is required: `ctx.spawn` must supply it.
signal
("New");
Badge.hue: ActorFieldSignal<number>hue = signal<number>(initial: number): ActorFieldSignal<number> (+1 overload)
A timeline value on an actor, and an input to every spawn of it. Without an initial value the signal is required: `ctx.spawn` must supply it.
signal
(190);
} export const const badge: BackendRendererDefinition<readonly [typeof Badge], "dom">badge = const dom: StagedBackend<React.FC<ReactBackendHostProps>, "dom", React.ReactNode>
The React DOM backend, and the `dom` binding code names: `dom.render(Box, …)`, `createRenderRuntime({ backends: [dom] })`.
dom
.render: <typeof Badge>(blueprint: typeof Badge, render: ActorRendererForBlueprints<readonly [typeof Badge], "dom">, options?: ActorRendererRegistrationOptions) => BackendRendererDefinition<readonly [typeof Badge], "dom"> (+1 overload)render(class BadgeBadge, ({
actor: ResolvedActor & Omit<ResolvedActor, "signals" | "channels"> & {
    compositing: {
        blend: "source-over" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity" | "plus-lighter";
        isolate: boolean;
        clip: number | null;
    };
    measuredBox: Rect | undefined;
    layout: {
        x: LayoutValue;
        y: LayoutValue;
        width: number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>;
        height: number | ... 1 more ... | Readonly<...>;
    };
    ... 7 more ...;
    label: string;
} & {
    ...;
}
The actor. Reading it makes the renderer depend on all of it.
actor
}) => (
<React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>span React.HTMLAttributes<HTMLSpanElement>.style?: React.CSSProperties | undefinedstyle={{ StandardShorthandProperties<string | number, string & {}>.background?: Property.Background<string | number> | undefined
This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015. **Syntax**: `<bg-layer>#? , <final-bg-layer>` | Chrome | Firefox | Safari | Edge | IE | | :----: | :-----: | :----: | :----: | :---: | | **1** | **1** | **1** | **12** | **4** |
@seehttps://developer.mozilla.org/docs/Web/CSS/Reference/Properties/background
background
: `hsl(${
actor: ResolvedActor & Omit<ResolvedActor, "signals" | "channels"> & {
    compositing: {
        blend: "source-over" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity" | "plus-lighter";
        isolate: boolean;
        clip: number | null;
    };
    measuredBox: Rect | undefined;
    layout: {
        x: LayoutValue;
        y: LayoutValue;
        width: number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>;
        height: number | ... 1 more ... | Readonly<...>;
    };
    ... 7 more ...;
    label: string;
} & {
    ...;
}
The actor. Reading it makes the renderer depend on all of it.
actor
.
signals: Readonly<Record<string, unknown>> & {
    compositing: {
        blend: "source-over" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity" | "plus-lighter";
        isolate: boolean;
        clip: number | null;
    };
    measuredBox: Rect | undefined;
    layout: {
        x: LayoutValue;
        y: LayoutValue;
        width: number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>;
        height: number | ... 1 more ... | Readonly<...>;
    };
    ... 7 more ...;
    label: string;
}
signals
.hue: numberhue} 80% 45%)` }}>
{
actor: ResolvedActor & Omit<ResolvedActor, "signals" | "channels"> & {
    compositing: {
        blend: "source-over" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity" | "plus-lighter";
        isolate: boolean;
        clip: number | null;
    };
    measuredBox: Rect | undefined;
    layout: {
        x: LayoutValue;
        y: LayoutValue;
        width: number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>;
        height: number | ... 1 more ... | Readonly<...>;
    };
    ... 7 more ...;
    label: string;
} & {
    ...;
}
The actor. Reading it makes the renderer depend on all of it.
actor
.
signals: Readonly<Record<string, unknown>> & {
    compositing: {
        blend: "source-over" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity" | "plus-lighter";
        isolate: boolean;
        clip: number | null;
    };
    measuredBox: Rect | undefined;
    layout: {
        x: LayoutValue;
        y: LayoutValue;
        width: number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>;
        height: number | ... 1 more ... | Readonly<...>;
    };
    ... 7 more ...;
    label: string;
}
signals
.label: stringlabel}
</React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>span> ));

actor.signals is typed from the class, so hue is a number and label a string here. The renderer never sees a signal object, only that signal’s value at this frame.

A renderer that reads actor draws again whenever anything about the actor changes. One that reads signals instead draws again only when a key it read changes, so moving, scaling or fading the badge leaves it alone:

import { class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor, 
function signal<T>(): RequiredSignal<T> (+1 overload)
module signal
A timeline value on an actor, and an input to every spawn of it. Without an initial value the signal is required: `ctx.spawn` must supply it.
signal
} from "@motionactor/core";
import { const dom: StagedBackend<React.FC<ReactBackendHostProps>, "dom", React.ReactNode>
The React DOM backend, and the `dom` binding code names: `dom.render(Box, …)`, `createRenderRuntime({ backends: [dom] })`.
dom
} from "@motionactor/dom/react";
export class class BadgeBadge extends class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor { Badge.label: ActorFieldSignal<string>label = signal<string>(initial: string): ActorFieldSignal<string> (+1 overload)
A timeline value on an actor, and an input to every spawn of it. Without an initial value the signal is required: `ctx.spawn` must supply it.
signal
("New");
Badge.hue: ActorFieldSignal<number>hue = signal<number>(initial: number): ActorFieldSignal<number> (+1 overload)
A timeline value on an actor, and an input to every spawn of it. Without an initial value the signal is required: `ctx.spawn` must supply it.
signal
(190);
} export const const badge: BackendRendererDefinition<readonly [typeof Badge], "dom">badge = const dom: StagedBackend<React.FC<ReactBackendHostProps>, "dom", React.ReactNode>
The React DOM backend, and the `dom` binding code names: `dom.render(Box, …)`, `createRenderRuntime({ backends: [dom] })`.
dom
.render: <typeof Badge>(blueprint: typeof Badge, render: ActorRendererForBlueprints<readonly [typeof Badge], "dom">, options?: ActorRendererRegistrationOptions) => BackendRendererDefinition<readonly [typeof Badge], "dom"> (+1 overload)render(class BadgeBadge, ({
signals: Readonly<Record<string, unknown>> & {
    compositing: {
        blend: "source-over" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity" | "plus-lighter";
        isolate: boolean;
        clip: number | null;
    };
    measuredBox: Rect | undefined;
    layout: {
        x: LayoutValue;
        y: LayoutValue;
        width: number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>;
        height: number | `${number}%` | Readonly<...>;
    };
    ... 7 more ...;
    label: string;
}
The actor's signals. Reading them in place of `actor` makes the renderer depend only on the keys it reads, wherever it reads them: a memoized child or an effect handed `signals` reads through it too.
signals
}) => (
<React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>span React.HTMLAttributes<HTMLSpanElement>.style?: React.CSSProperties | undefinedstyle={{ StandardShorthandProperties<string | number, string & {}>.background?: Property.Background<string | number> | undefined
This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015. **Syntax**: `<bg-layer>#? , <final-bg-layer>` | Chrome | Firefox | Safari | Edge | IE | | :----: | :-----: | :----: | :----: | :---: | | **1** | **1** | **1** | **12** | **4** |
@seehttps://developer.mozilla.org/docs/Web/CSS/Reference/Properties/background
background
: `hsl(${
signals: Readonly<Record<string, unknown>> & {
    compositing: {
        blend: "source-over" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity" | "plus-lighter";
        isolate: boolean;
        clip: number | null;
    };
    measuredBox: Rect | undefined;
    layout: {
        x: LayoutValue;
        y: LayoutValue;
        width: number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>;
        height: number | `${number}%` | Readonly<...>;
    };
    ... 7 more ...;
    label: string;
}
The actor's signals. Reading them in place of `actor` makes the renderer depend only on the keys it reads, wherever it reads them: a memoized child or an effect handed `signals` reads through it too.
signals
.hue: numberhue} 80% 45%)` }}>{
signals: Readonly<Record<string, unknown>> & {
    compositing: {
        blend: "source-over" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity" | "plus-lighter";
        isolate: boolean;
        clip: number | null;
    };
    measuredBox: Rect | undefined;
    layout: {
        x: LayoutValue;
        y: LayoutValue;
        width: number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>;
        height: number | `${number}%` | Readonly<...>;
    };
    ... 7 more ...;
    label: string;
}
The actor's signals. Reading them in place of `actor` makes the renderer depend only on the keys it reads, wherever it reads them: a memoized child or an effect handed `signals` reads through it too.
signals
.label: stringlabel}</React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>span>
));

The keys are recorded wherever they are read: destructured, in a memoized component or an effect handed signals. A spread reads every key. The React binding tracks keys; Vue and Svelte update the content on any change to the actor.

Matching

backend.render(classes, render, options?) takes one class or an array of them. A renderer matches an actor whose class is one of those classes or extends one, so a renderer for Badge also draws class Pill extends Badge until something more specific claims it.

When several renderers match, the first one wins. A render runtime orders them as listed in renderers, then each backend’s own primitives, so an app renderer for a subclass always comes before the backend’s renderer for its base. A renderer that returns null passes the actor on to the next match.

import { 
function signal<T>(): RequiredSignal<T> (+1 overload)
module signal
A timeline value on an actor, and an input to every spawn of it. Without an initial value the signal is required: `ctx.spawn` must supply it.
signal
} from "@motionactor/core";
import { const createRenderRuntime: (input: CreateRenderRuntimeInput<ReactBackendHost, React.ReactNode>) => ReactRenderRuntime
The floor's `createRenderRuntime` for React: every backend's host is a React component and its stages wrap React nodes, so mixed backends (each with its own host props) compose without naming a type.
createRenderRuntime
, function createRendererRegistry(...entries: RendererRegistryEntry[]): RendererRegistry (+1 overload)createRendererRegistry } from "@motionactor/renderers/react";
import { const dom: StagedBackend<React.FC<ReactBackendHostProps>, "dom", React.ReactNode>
The React DOM backend, and the `dom` binding code names: `dom.render(Box, …)`, `createRenderRuntime({ backends: [dom] })`.
dom
} from "@motionactor/dom/react";
import { class BadgeBadge, const badge: BackendRendererDefinition<readonly [typeof Badge], "dom">badge } from "./badge"; class class PillPill extends class BadgeBadge { Pill.muted: ActorFieldSignal<boolean>muted = signal<boolean>(initial: boolean): ActorFieldSignal<boolean> (+1 overload)
A timeline value on an actor, and an input to every spawn of it. Without an initial value the signal is required: `ctx.spawn` must supply it.
signal
(false);
} // Draws muted pills and passes the rest on to `badge`. const const mutedPill: BackendRendererDefinition<readonly [typeof Pill], "dom">mutedPill = const dom: StagedBackend<React.FC<ReactBackendHostProps>, "dom", React.ReactNode>
The React DOM backend, and the `dom` binding code names: `dom.render(Box, …)`, `createRenderRuntime({ backends: [dom] })`.
dom
.render: <typeof Pill>(blueprint: typeof Pill, render: ActorRendererForBlueprints<readonly [typeof Pill], "dom">, options?: ActorRendererRegistrationOptions) => BackendRendererDefinition<readonly [typeof Pill], "dom"> (+1 overload)render(class PillPill, ({
actor: ResolvedActor & Omit<ResolvedActor, "signals" | "channels"> & {
    compositing: {
        blend: "source-over" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity" | "plus-lighter";
        isolate: boolean;
        clip: number | null;
    };
    measuredBox: Rect | undefined;
    layout: {
        x: LayoutValue;
        y: LayoutValue;
        width: number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>;
        height: number | ... 1 more ... | Readonly<...>;
    };
    ... 8 more ...;
    muted: boolean;
} & {
    ...;
}
The actor. Reading it makes the renderer depend on all of it.
actor
}) =>
actor: ResolvedActor & Omit<ResolvedActor, "signals" | "channels"> & {
    compositing: {
        blend: "source-over" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity" | "plus-lighter";
        isolate: boolean;
        clip: number | null;
    };
    measuredBox: Rect | undefined;
    layout: {
        x: LayoutValue;
        y: LayoutValue;
        width: number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>;
        height: number | ... 1 more ... | Readonly<...>;
    };
    ... 8 more ...;
    muted: boolean;
} & {
    ...;
}
The actor. Reading it makes the renderer depend on all of it.
actor
.
signals: Readonly<Record<string, unknown>> & {
    compositing: {
        blend: "source-over" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity" | "plus-lighter";
        isolate: boolean;
        clip: number | null;
    };
    measuredBox: Rect | undefined;
    layout: {
        x: LayoutValue;
        y: LayoutValue;
        width: number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>;
        height: number | ... 1 more ... | Readonly<...>;
    };
    ... 8 more ...;
    muted: boolean;
}
signals
.muted: booleanmuted ? (
<React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>span React.HTMLAttributes<HTMLSpanElement>.className?: string | undefinedclassName="pill">{
actor: ResolvedActor & Omit<ResolvedActor, "signals" | "channels"> & {
    compositing: {
        blend: "source-over" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity" | "plus-lighter";
        isolate: boolean;
        clip: number | null;
    };
    measuredBox: Rect | undefined;
    layout: {
        x: LayoutValue;
        y: LayoutValue;
        width: number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>;
        height: number | ... 1 more ... | Readonly<...>;
    };
    ... 8 more ...;
    muted: boolean;
} & {
    ...;
}
The actor. Reading it makes the renderer depend on all of it.
actor
.
signals: Readonly<Record<string, unknown>> & {
    compositing: {
        blend: "source-over" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity" | "plus-lighter";
        isolate: boolean;
        clip: number | null;
    };
    measuredBox: Rect | undefined;
    layout: {
        x: LayoutValue;
        y: LayoutValue;
        width: number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>;
        height: number | ... 1 more ... | Readonly<...>;
    };
    ... 8 more ...;
    muted: boolean;
}
signals
.label: stringlabel}</React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>span>
) : null, ); export const const badges: RendererRegistrybadges = function createRendererRegistry(...entries: RendererRegistryEntry[]): RendererRegistry (+1 overload)createRendererRegistry(const mutedPill: BackendRendererDefinition<readonly [typeof Pill], "dom">mutedPill, const badge: BackendRendererDefinition<readonly [typeof Badge], "dom">badge); export const const runtime: ReactRenderRuntimeruntime = function createRenderRuntime(input: CreateRenderRuntimeInput<ReactBackendHost, React.ReactNode>): ReactRenderRuntime
The floor's `createRenderRuntime` for React: every backend's host is a React component and its stages wrap React nodes, so mixed backends (each with its own host props) compose without naming a type.
createRenderRuntime
({
backends: readonly AnyBackend<ReactBackendHost, React.ReactNode>[]backends: [const dom: StagedBackend<React.FC<ReactBackendHostProps>, "dom", React.ReactNode>
The React DOM backend, and the `dom` binding code names: `dom.render(Box, …)`, `createRenderRuntime({ backends: [dom] })`.
dom
],
renderers?: readonly RendererRegistryEntry[] | undefined
Family and project renderers, for any backend. Each routes to the backend it names (`three.render(…)`); one naming a backend missing from `backends` throws.
renderers
: [const badges: RendererRegistrybadges],
});

A registry is a reusable, ordered group of renderers. Registries nest, and createRendererRegistry(base, { overrides: [...] }) puts the overrides ahead of everything in base, the last override first. Pass a registry wherever a renderer list is expected.

An actor with renderers on several backends gets the one for the layer it is in. The runtime routes each renderer to the backend it names and throws when it lists a renderer for a backend it does not have.

The render context

Field What it holds
actor The resolved actor: signals, localLayout, worldLayout, effects, compositing, channels
state The whole FrameState, for reading other actors with state.findActor(Class)
frame, fps The frame being drawn and the build’s frame rate
compiled The compiled scene, when the host has one
slots Hosted children by slot name, each as { actor, element }; a multiple slot is an array. Painting an element does not read its child; reading actor makes the renderer draw again when that child changes
targets The actor’s declared effect targets, the same identities scene code applies effects to
refs DOM: ref callbacks for those targets, so an effect can find the element, and the bindings refs.<child> and refs.self. Three: the bindings alone
renderChild Draws a child actor through the same registry: a slot entry’s actor, or a copy derived from it. DOM: renderChild(actor, { flow }) places it in the element’s flow instead of at its layout box

Slots

A slot is a place in an actor that other actors are spawned into. The renderer decides where each child’s element goes; the child’s own renderer draws the child.

import { function createScene<TSceneExports, const I extends SceneInputs = Readonly<Record<never, SceneInput>>, const L extends SceneLayers = Readonly<Record<never, SceneLayer<BackendRef<string>>>>>(script: SceneScript<I, L, TSceneExports>, options?: SceneDefinitionOptions<I, L>): SceneDefinition<I, L, TSceneExports>
Declare a scene. Nothing compiles until a host builds it: `scene.build({ viewport, fps, inputs })` runs the script as `(ctx, inputs, viewport, layers)` and returns the compiled scene. `ctx.spawn` places a root actor in the default layer; `layers.<key>.spawn` places it in a declared one. `ctx.stage` stages another scene on this scene's clock, and a staged scene may stage again.
createScene
, class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor,
function signal<T>(): RequiredSignal<T> (+1 overload)
module signal
A timeline value on an actor, and an input to every spawn of it. Without an initial value the signal is required: `ctx.spawn` must supply it.
signal
,
function slot<const TAccepts extends SlotAccepts>(options: {
    accepts: TAccepts;
    multiple?: false;
}): OnePlaceField<TAccepts> (+1 overload)
Declare a place: a named position this actor's children are hosted in. Written as a field; the field reads as a handle once the actor spawns. ```ts screen = slot({ accepts: LayoutActor }); // this.screen.current letters = slot({ accepts: Letter, multiple: true }); // this.letters.all() ```
slot
} from "@motionactor/core";
import { const dom: StagedBackend<React.FC<ReactBackendHostProps>, "dom", React.ReactNode>
The React DOM backend, and the `dom` binding code names: `dom.render(Box, …)`, `createRenderRuntime({ backends: [dom] })`.
dom
} from "@motionactor/dom/react";
class class TagTag extends class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor { Tag.text: ActorFieldSignal<string>text = signal<string>(initial: string): ActorFieldSignal<string> (+1 overload)
A timeline value on an actor, and an input to every spawn of it. Without an initial value the signal is required: `ctx.spawn` must supply it.
signal
("");
} class class CardCard extends class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor { Card.title: ActorFieldSignal<string>title = signal<string>(initial: string): ActorFieldSignal<string> (+1 overload)
A timeline value on an actor, and an input to every spawn of it. Without an initial value the signal is required: `ctx.spawn` must supply it.
signal
("Untitled");
Card.tags: ManyPlaceField<typeof Tag>tags =
slot<typeof Tag>(options: {
    accepts: typeof Tag;
    multiple: true;
}): ManyPlaceField<typeof Tag> (+1 overload)
Declare a place: a named position this actor's children are hosted in. Written as a field; the field reads as a handle once the actor spawns. ```ts screen = slot({ accepts: LayoutActor }); // this.screen.current letters = slot({ accepts: Letter, multiple: true }); // this.letters.all() ```
slot
({ accepts: typeof Tagaccepts: class TagTag, multiple: truemultiple: true });
} export const
const compiled: CompiledScene<{
    card: Card;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
=
createScene<{
    card: Card;
}, Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>>(script: SceneScript<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, {
    card: Card;
}>, options?: SceneDefinitionOptions<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>> | undefined): SceneDefinition<...>
Declare a scene. Nothing compiles until a host builds it: `scene.build({ viewport, fps, inputs })` runs the script as `(ctx, inputs, viewport, layers)` and returns the compiled scene. `ctx.spawn` places a root actor in the default layer; `layers.<key>.spawn` places it in a declared one. `ctx.stage` stages another scene on this scene's clock, and a staged scene may stage again.
createScene
(function* (ctx: SceneContextctx) {
const const card: Cardcard = ctx: SceneContextctx.
CompileContext.spawn<Card>(definition: ActorClass<Card>, overrides?: {
    id?: undefined;
    localLayout?: undefined;
    worldLayout?: undefined;
    compositing?: {
        blend?: SignalInputValue<"source-over" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity" | "plus-lighter"> | undefined;
        isolate?: SignalInputValue<boolean> | undefined;
        clip?: SignalInputValue<number | null> | undefined;
    } | undefined;
    ... 19 more ...;
    title?: SignalInputValue<...> | undefined;
} | undefined, options?: {
    ...;
} | undefined): Card (+1 overload)
spawn
(class CardCard, { title?: SignalInputValue<string> | undefinedtitle: "Release notes" });
const card: Cardcard.Card.tags: ManyPlaceField<typeof Tag>tags.
spawn<typeof Tag>(blueprint: typeof Tag, overrides?: {
    id?: undefined;
    localLayout?: undefined;
    worldLayout?: undefined;
    compositing?: {
        blend?: SignalInputValue<"source-over" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity" | "plus-lighter"> | undefined;
        isolate?: SignalInputValue<boolean> | undefined;
        clip?: SignalInputValue<number | null> | undefined;
    } | undefined;
    ... 19 more ...;
    text?: SignalInputValue<...> | undefined;
} | undefined): Tag (+1 overload)
Host a child of `blueprint`, which must be an accepted class.
spawn
(class TagTag, { text?: SignalInputValue<string> | undefinedtext: "2.0" });
const card: Cardcard.Card.tags: ManyPlaceField<typeof Tag>tags.
spawn<typeof Tag>(blueprint: typeof Tag, overrides?: {
    id?: undefined;
    localLayout?: undefined;
    worldLayout?: undefined;
    compositing?: {
        blend?: SignalInputValue<"source-over" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity" | "plus-lighter"> | undefined;
        isolate?: SignalInputValue<boolean> | undefined;
        clip?: SignalInputValue<number | null> | undefined;
    } | undefined;
    ... 19 more ...;
    text?: SignalInputValue<...> | undefined;
} | undefined): Tag (+1 overload)
Host a child of `blueprint`, which must be an accepted class.
spawn
(class TagTag, { text?: SignalInputValue<string> | undefinedtext: "breaking" });
return { card: Cardcard }; }).
SceneDefinition<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, { ...; }>.build(args: SceneBuildInput<Readonly<Record<never, SceneInput>>>): CompiledScene<{
    card: Card;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
build
({ viewport: SceneViewportviewport: { SceneViewport.width: numberwidth: 1920, SceneViewport.height: numberheight: 1080 }, fps: numberfps: 30 });
export const const card: BackendRendererDefinition<readonly [typeof Card], "dom">card = const dom: StagedBackend<React.FC<ReactBackendHostProps>, "dom", React.ReactNode>
The React DOM backend, and the `dom` binding code names: `dom.render(Box, …)`, `createRenderRuntime({ backends: [dom] })`.
dom
.render: <typeof Card>(blueprint: typeof Card, render: ActorRendererForBlueprints<readonly [typeof Card], "dom">, options?: ActorRendererRegistrationOptions) => BackendRendererDefinition<readonly [typeof Card], "dom"> (+1 overload)render(class CardCard, ({
actor: ResolvedActor & Omit<ResolvedActor, "signals" | "channels"> & {
    compositing: {
        blend: "source-over" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity" | "plus-lighter";
        isolate: boolean;
        clip: number | null;
    };
    measuredBox: Rect | undefined;
    layout: {
        x: LayoutValue;
        y: LayoutValue;
        width: number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>;
        height: number | ... 1 more ... | Readonly<...>;
    };
    ... 6 more ...;
    title: string;
} & {
    ...;
}
The actor. Reading it makes the renderer depend on all of it.
actor
,
slots: {
    tags: {
        actor: ResolvedActorOfInstance<Tag>;
        element: RenderNode | null;
    }[];
}
The actor's hosted children by field, each `{ actor, element }`. Reading an `element` does not read its child; reading an `actor` makes the renderer depend on it.
slots
}) => (
<React.JSX.IntrinsicElements.article: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>article> <React.JSX.IntrinsicElements.h2: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>h2>{
actor: ResolvedActor & Omit<ResolvedActor, "signals" | "channels"> & {
    compositing: {
        blend: "source-over" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity" | "plus-lighter";
        isolate: boolean;
        clip: number | null;
    };
    measuredBox: Rect | undefined;
    layout: {
        x: LayoutValue;
        y: LayoutValue;
        width: number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>;
        height: number | ... 1 more ... | Readonly<...>;
    };
    ... 6 more ...;
    title: string;
} & {
    ...;
}
The actor. Reading it makes the renderer depend on all of it.
actor
.
signals: Readonly<Record<string, unknown>> & {
    compositing: {
        blend: "source-over" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity" | "plus-lighter";
        isolate: boolean;
        clip: number | null;
    };
    measuredBox: Rect | undefined;
    layout: {
        x: LayoutValue;
        y: LayoutValue;
        width: number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>;
        height: number | ... 1 more ... | Readonly<...>;
    };
    ... 6 more ...;
    title: string;
}
signals
.title: stringtitle}</React.JSX.IntrinsicElements.h2: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>h2>
<React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> {
slots: {
    tags: {
        actor: ResolvedActorOfInstance<Tag>;
        element: RenderNode | null;
    }[];
}
The actor's hosted children by field, each `{ actor, element }`. Reading an `element` does not read its child; reading an `actor` makes the renderer depend on it.
slots
.
tags: {
    actor: ResolvedActorOfInstance<Tag>;
    element: RenderNode | null;
}[]
tags
.
Array<{ actor: ResolvedActorOfInstance<Tag>; element: RenderNode | null; }>.map<JSX.Element>(callbackfn: (value: {
    actor: ResolvedActorOfInstance<Tag>;
    element: RenderNode | null;
}, index: number, array: {
    actor: ResolvedActorOfInstance<Tag>;
    element: RenderNode | null;
}[]) => JSX.Element, thisArg?: any): JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
(({ actor: ResolvedActorOfInstance<Tag>actor, element: React.ReactNodeelement }) => (
<React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li React.Attributes.key?: React.Key | null | undefinedkey={actor: ResolvedActorOfInstance<Tag>actor.id: stringid}>{element: React.ReactNodeelement}</React.JSX.IntrinsicElements.li: React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>li> ))} </React.JSX.IntrinsicElements.ul: React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>ul> </React.JSX.IntrinsicElements.article: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>article> ));

Bindings

A DOM renderer can paint a child(...) actor onto a node of its own markup instead of the child’s element: refs.<child> binds the node to that child, and refs.self binds it to the actor itself. The node keeps its place in the markup’s flow, and each frame the scope writes the actor’s style onto it with no render of the view.

import { function child<TBlueprint extends ActorClass<object>, TOwner extends object = object>(blueprint: TBlueprint, ...[overrides]: ChildOverridesArg<TBlueprint, TOwner>): ChildField<TBlueprint, TOwner>child, function createScene<TSceneExports, const I extends SceneInputs = Readonly<Record<never, SceneInput>>, const L extends SceneLayers = Readonly<Record<never, SceneLayer<BackendRef<string>>>>>(script: SceneScript<I, L, TSceneExports>, options?: SceneDefinitionOptions<I, L>): SceneDefinition<I, L, TSceneExports>
Declare a scene. Nothing compiles until a host builds it: `scene.build({ viewport, fps, inputs })` runs the script as `(ctx, inputs, viewport, layers)` and returns the compiled scene. `ctx.spawn` places a root actor in the default layer; `layers.<key>.spawn` places it in a declared one. `ctx.stage` stages another scene on this scene's clock, and a staged scene may stage again.
createScene
, class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor,
function signal<T>(): RequiredSignal<T> (+1 overload)
module signal
A timeline value on an actor, and an input to every spawn of it. Without an initial value the signal is required: `ctx.spawn` must supply it.
signal
} from "@motionactor/core";
import { const dom: StagedBackend<React.FC<ReactBackendHostProps>, "dom", React.ReactNode>
The React DOM backend, and the `dom` binding code names: `dom.render(Box, …)`, `createRenderRuntime({ backends: [dom] })`.
dom
} from "@motionactor/dom/react";
class class TitleTitle extends class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor {} class class CardCard extends class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor { Card.label: ActorFieldSignal<string>label = signal<string>(initial: string): ActorFieldSignal<string> (+1 overload)
A timeline value on an actor, and an input to every spawn of it. Without an initial value the signal is required: `ctx.spawn` must supply it.
signal
("Quarterly");
Card.title: ChildField<typeof Title, object>title = child<typeof Title, object>(blueprint: typeof Title, overrides?: ChildOverrides<typeof Title, object> | undefined): ChildField<typeof Title, object>child(class TitleTitle); } export const
const compiled: CompiledScene<{
    card: Card;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
=
createScene<{
    card: Card;
}, Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>>(script: SceneScript<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, {
    card: Card;
}>, options?: SceneDefinitionOptions<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>> | undefined): SceneDefinition<...>
Declare a scene. Nothing compiles until a host builds it: `scene.build({ viewport, fps, inputs })` runs the script as `(ctx, inputs, viewport, layers)` and returns the compiled scene. `ctx.spawn` places a root actor in the default layer; `layers.<key>.spawn` places it in a declared one. `ctx.stage` stages another scene on this scene's clock, and a staged scene may stage again.
createScene
(function* (ctx: SceneContextctx) {
const const card: Cardcard = ctx: SceneContextctx.
CompileContext.spawn<Card>(definition: ActorClass<Card>, overrides?: {
    id?: undefined;
    localLayout?: undefined;
    worldLayout?: undefined;
    compositing?: {
        blend?: SignalInputValue<"source-over" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity" | "plus-lighter"> | undefined;
        isolate?: SignalInputValue<boolean> | undefined;
        clip?: SignalInputValue<number | null> | undefined;
    } | undefined;
    ... 20 more ...;
    label?: SignalInputValue<...> | undefined;
} | undefined, options?: {
    ...;
} | undefined): Card (+1 overload)
spawn
(class CardCard);
yield* const card: Cardcard.Card.title: ChildField<typeof Title, object>title.
LayoutActor<{}>.transform: {
    scale: TypedFieldSignal<number, number>;
    rotation: TypedFieldSignal<number, number>;
} & SignalGroupDefinition
transform
.scale: TypedFieldSignal<number, number>scale.function tween(target: number, options: number | SignalTweenOptions<number>): Generator<Frame, void, unknown>
Tween to target over authored seconds — must yield*
tween
(1.2, 0.4);
return { card: Cardcard }; }).
SceneDefinition<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, { ...; }>.build(args: SceneBuildInput<Readonly<Record<never, SceneInput>>>): CompiledScene<{
    card: Card;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
build
({ viewport: SceneViewportviewport: { SceneViewport.width: numberwidth: 1920, SceneViewport.height: numberheight: 1080 }, fps: numberfps: 30 });
export const const card: BackendRendererDefinition<readonly [typeof Card], "dom">card = const dom: StagedBackend<React.FC<ReactBackendHostProps>, "dom", React.ReactNode>
The React DOM backend, and the `dom` binding code names: `dom.render(Box, …)`, `createRenderRuntime({ backends: [dom] })`.
dom
.render: <typeof Card>(blueprint: typeof Card, render: ActorRendererForBlueprints<readonly [typeof Card], "dom">, options?: ActorRendererRegistrationOptions) => BackendRendererDefinition<readonly [typeof Card], "dom"> (+1 overload)render(class CardCard, ({
signals: Readonly<Record<string, unknown>> & {
    compositing: {
        blend: "source-over" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity" | "plus-lighter";
        isolate: boolean;
        clip: number | null;
    };
    measuredBox: Rect | undefined;
    layout: {
        x: LayoutValue;
        y: LayoutValue;
        width: number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>;
        height: number | `${number}%` | Readonly<...>;
    };
    ... 7 more ...;
    label: string;
}
The actor's signals. Reading them in place of `actor` makes the renderer depend only on the keys it reads, wherever it reads them: a memoized child or an effect handed `signals` reads through it too.
signals
,
refs: TargetRefs<{}> & {
    readonly title: BoundElementRef;
} & {
    readonly self: BoundElementRef;
}
refs
}) => (
<React.JSX.IntrinsicElements.article: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>article> <React.JSX.IntrinsicElements.h1: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>h1 React.RefAttributes<HTMLHeadingElement>.ref?: React.Ref<HTMLHeadingElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={
refs: TargetRefs<{}> & {
    readonly title: BoundElementRef;
} & {
    readonly self: BoundElementRef;
}
refs
.title: BoundElementReftitle}>{
signals: Readonly<Record<string, unknown>> & {
    compositing: {
        blend: "source-over" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity" | "plus-lighter";
        isolate: boolean;
        clip: number | null;
    };
    measuredBox: Rect | undefined;
    layout: {
        x: LayoutValue;
        y: LayoutValue;
        width: number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>;
        height: number | `${number}%` | Readonly<...>;
    };
    ... 7 more ...;
    label: string;
}
The actor's signals. Reading them in place of `actor` makes the renderer depend only on the keys it reads, wherever it reads them: a memoized child or an effect handed `signals` reads through it too.
signals
.label: stringlabel}</React.JSX.IntrinsicElements.h1: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>h1>
</React.JSX.IntrinsicElements.article: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>article> ));

Vue binds with the v-actor directive from @motionactor/dom/vue (<h1 v-actor="refs.title">), and Svelte with an attachment (<h1 {@attach refs.title}>).

While bound The node gets
The actor is present transform: scale() rotate() about the node’s own origin, opacity, blend mode, isolation and clip, and shape.radius as border-radius with overflow: hidden
It gets an inline effect What the effect’s stage paints on an element’s wrapper, folded in: its filter, its transform after the actor’s own, its opacity multiplied, its clip-path. The effect’s box is the node’s own untransformed size, measured once and again when the node resizes
The actor is absent visibility: hidden, so it keeps its space
The node unbinds Markup’s own inline values for those properties back, as they were when it bound

The markup places and sizes the node: the actor’s x, y, width and height are not written. Whatever writes one of those properties into the node’s style (the view re-rendering, a component’s own state, a script), the node takes the actor’s value back before paint. Its measuredBox is published on demand, untransformed, against the element of the actor whose view holds it, so a rotated node measures the box it was laid out in. An outlet rendered inside a bound node is placed against that node, where flow put it, and follows it when flow moves it: on every frame the scope presents, held or repeated, when the node resizes, and when fonts load. Each node bound is its own instance: a view that binds a child and also renders its outlet paints it twice.

Only HTML elements bind: refs.<child> and refs.self take HTMLElement | null. A binding throws a BoundElementError at bind, in every build, naming the actor and the field, when the actor’s content is transformed (contentTransform), when it gets an offscreen effect that does not clip or that no actor element encloses, an effect whose stage paints only actor elements, when an effect needs an overlay or a second clip, or for refs.self inside the actor’s own element, which already paints it; a refused node registers nothing, so the view has nothing to release. An effect the binding could not see at bind (an overlay a later frame starts, or any effect when the render context carries no compiled scene) throws as the frame that brings it writes the node: the binding lets go of the node first, back to its markup, and the frame’s other nodes still paint. A target whose name a binding also uses is a type error on refs.

Offscreen effects

A bound node takes a glShader or canvasPaint effect when the effect’s target contract clips (clips: true): its handler paints inside the target’s rect and leaves the rest of the canvas as it was. The node registers in the capture of the actor element whose view binds it, and that element mounts its canvas for the effect and runs it over the node’s rect. An effect without target paints its whole canvas, the element around the node, so binding a node to an actor that gets one throws a BoundElementError, in every build, before the node registers.

import { function child<TBlueprint extends ActorClass<object>, TOwner extends object = object>(blueprint: TBlueprint, ...[overrides]: ChildOverridesArg<TBlueprint, TOwner>): ChildField<TBlueprint, TOwner>child, function createScene<TSceneExports, const I extends SceneInputs = Readonly<Record<never, SceneInput>>, const L extends SceneLayers = Readonly<Record<never, SceneLayer<BackendRef<string>>>>>(script: SceneScript<I, L, TSceneExports>, options?: SceneDefinitionOptions<I, L>): SceneDefinition<I, L, TSceneExports>
Declare a scene. Nothing compiles until a host builds it: `scene.build({ viewport, fps, inputs })` runs the script as `(ctx, inputs, viewport, layers)` and returns the compiled scene. `ctx.spawn` places a root actor in the default layer; `layers.<key>.spawn` places it in a declared one. `ctx.stage` stages another scene on this scene's clock, and a staged scene may stage again.
createScene
,
function defineEffect<const TName extends string, const P extends EffectParamDeclarations, TKind extends AnyEffectKind, TTarget = unknown, const TTime extends boolean = false, TNative = unknown, const TApplies extends EffectApplication | undefined = undefined>(kind: TKind, spec: EffectSpec<TName, P, TTarget, TTime> & {
    readonly params: NoPlaybackParams;
    readonly applies?: TApplies;
} & EffectNativeSite<TNative> & EffectKindSpec<EffectKindTypesOf<TKind>, EffectRenderParams<P, TTime>, TTarget, TNative>): EffectDefinition<EffectKindBackendOf<TKind>, TName, P, TKind, TTarget, EffectKindRuntime<EffectKindTypesOf<TKind>, EffectRenderParams<P, TTime>, TTarget, TNative>, TTime, EffectDefinitionApplies<TApplies, TTarget, TKind>>
Define an effect: one value of one kind, on the kind's backend. The spec is the core fields plus the kind's own, typed from `params`: export const glow = defineEffect(domStyle, { name: "glow", params: { color: signal.of(colorType, color("#22d3ee")), spread: signal(18) }, style: ({ color, spread }) => ({ filter: `drop-shadow(0 0 ${spread}px ${color})` }), }); declare module "@motionactor/core" { interface ActorEffects { "dom:glow": typeof glow } } registerEffects([glow]); card.fx.glow({ spread: 24 });
defineEffect
, const effectTargetContract: <TTarget>(contract: EffectTargetContractFor<TTarget>) => TypedEffectTargetContract<TTarget>
A target contract that carries the target type its effect's render reads. `dataKinds` and `geometry` are checked against that type.
effectTargetContract
, class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor, function registerEffects(definitions: readonly AnyEffectDefinition[]): void
Install effects by wire id. Call it in the effect's own module, after its `defineEffect(...)` (and beside its `ActorEffects` augmentation when it applies to an actor), so importing the effect installs it. Every effect registers. One that can apply to an actor is also on every actor's `fx`; one that cannot (a layer application, or one needing target data) stays off `fx` and applies with `ctx.apply` on a target. A later registration at a wire id replaces the earlier one. An actor effect named `for` throws: `fx.for` is taken.
registerEffects
,
function signal<T>(): RequiredSignal<T> (+1 overload)
module signal
A timeline value on an actor, and an input to every spawn of it. Without an initial value the signal is required: `ctx.spawn` must supply it.
signal
} from "@motionactor/core";
import {
const glShader: EffectKind<"dom", "shader", GlShaderTypes, {
    readonly kind: "offscreen";
    readonly scope: "actor";
}, "actor">
The kind of effect that runs a WebGL pass over its actor's rasterized subtree. The short form names uniforms by what they are: export const halftone = defineEffect(glShader, { name: "halftone", params: { dotSize: signal(6) }, shader: { fs: HALFTONE_FS }, // vs defaults to the fullscreen quad uniforms: ({ dotSize }, { progress }) => ({ dotSize: 1 + (dotSize - 1) * progress }), }); `tex`, `resolution`, `progress` and `time` are bound by the kind when the shader declares them; an effect's own value wins. A pass that draws itself (several passes, extra textures, depth) supplies `paint(state, ctx)` in place of `uniforms`.
glShader
,
const targetRegionUniforms: (target: ResolvedCanvasEffectTarget | undefined) => {
    readonly hasRegion: boolean;
    readonly regionRect: readonly [number, number, number, number];
}
The `u_hasRegion` / `u_regionRect` pair a region-scoped shader reads: the target's first rect or quad bounds in canvas UV, or the whole canvas for a pass with no target. A pass whose target has no area never paints (the pipeline skips it), so it never reads the whole canvas.
targetRegionUniforms
, type
type CanvasTargetContract<TData, TGeometryKind extends CanvasTargetGeometryKind, TClips extends boolean = false> = {
    readonly data: TData;
    readonly geometry: TGeometryKind;
    readonly clips: TClips;
}
CanvasTargetContract
} from "@motionactor/dom";
import { const dom: StagedBackend<React.FC<ReactBackendHostProps>, "dom", React.ReactNode>
The React DOM backend, and the `dom` binding code names: `dom.render(Box, …)`, `createRenderRuntime({ backends: [dom] })`.
dom
} from "@motionactor/dom/react";
const const FROST_FS: "#version 300 es\nprecision highp float;\nuniform sampler2D u_tex;\nuniform bool u_hasRegion;\nuniform vec4 u_regionRect;\nuniform float u_amount;\nin vec2 v_uv;\nout vec4 color;\nvoid main() {\n vec4 source = texture(u_tex, v_uv);\n vec2 local = (vec2(v_uv.x, 1.0 - v_uv.y) - u_regionRect.xy) / u_regionRect.zw;\n bool inside = all(greaterThanEqual(local, vec2(0.0))) && all(lessThanEqual(local, vec2(1.0)));\n color = u_hasRegion && !inside ? source : mix(source, vec4(1.0), u_amount);\n}"FROST_FS = `#version 300 es precision highp float; uniform sampler2D u_tex; uniform bool u_hasRegion; uniform vec4 u_regionRect; uniform float u_amount; in vec2 v_uv; out vec4 color; void main() { vec4 source = texture(u_tex, v_uv); vec2 local = (vec2(v_uv.x, 1.0 - v_uv.y) - u_regionRect.xy) / u_regionRect.zw; bool inside = all(greaterThanEqual(local, vec2(0.0))) && all(lessThanEqual(local, vec2(1.0))); color = u_hasRegion && !inside ? source : mix(source, vec4(1.0), u_amount); }`; /** Any rect it clips to: a target, or the node a view binds. */ type
type ClippedRect = {
    readonly data: unknown;
    readonly geometry: "rect";
    readonly clips: true;
}
Any rect it clips to: a target, or the node a view binds.
ClippedRect
=
type CanvasTargetContract<TData, TGeometryKind extends CanvasTargetGeometryKind, TClips extends boolean = false> = {
    readonly data: TData;
    readonly geometry: TGeometryKind;
    readonly clips: TClips;
}
CanvasTargetContract
<unknown, "rect", true>;
export const
const frost: EffectDefinition<"dom", "frost", {
    readonly amount: ActorFieldSignal<number>;
}, EffectKind<"dom", "shader", GlShaderTypes, {
    readonly kind: "offscreen";
    readonly scope: "actor";
}, "actor">, ClippedRect, GlShaderRuntime<EffectParamValues<{
    readonly amount: ActorFieldSignal<number>;
}>, ResolvedCanvasEffectTargetFor<unknown, "rect">>, false, "target">
frost
=
defineEffect<"frost", {
    readonly amount: ActorFieldSignal<number>;
}, EffectKind<"dom", "shader", GlShaderTypes, {
    readonly kind: "offscreen";
    readonly scope: "actor";
}, "actor">, ClippedRect, false, unknown, undefined>(kind: EffectKind<"dom", "shader", GlShaderTypes, {
    readonly kind: "offscreen";
    readonly scope: "actor";
}, "actor">, spec: EffectSpec<"frost", {
    readonly amount: ActorFieldSignal<number>;
}, ClippedRect, false> & ({
    ...;
} & GlShaderSpec<...>)): EffectDefinition<...>
Define an effect: one value of one kind, on the kind's backend. The spec is the core fields plus the kind's own, typed from `params`: export const glow = defineEffect(domStyle, { name: "glow", params: { color: signal.of(colorType, color("#22d3ee")), spread: signal(18) }, style: ({ color, spread }) => ({ filter: `drop-shadow(0 0 ${spread}px ${color})` }), }); declare module "@motionactor/core" { interface ActorEffects { "dom:glow": typeof glow } } registerEffects([glow]); card.fx.glow({ spread: 24 });
defineEffect
(
const glShader: EffectKind<"dom", "shader", GlShaderTypes, {
    readonly kind: "offscreen";
    readonly scope: "actor";
}, "actor">
The kind of effect that runs a WebGL pass over its actor's rasterized subtree. The short form names uniforms by what they are: export const halftone = defineEffect(glShader, { name: "halftone", params: { dotSize: signal(6) }, shader: { fs: HALFTONE_FS }, // vs defaults to the fullscreen quad uniforms: ({ dotSize }, { progress }) => ({ dotSize: 1 + (dotSize - 1) * progress }), }); `tex`, `resolution`, `progress` and `time` are bound by the kind when the shader declares them; an effect's own value wins. A pass that draws itself (several passes, extra textures, depth) supplies `paint(state, ctx)` in place of `uniforms`.
glShader
, {
EffectSpec<"frost", { readonly amount: ActorFieldSignal<number>; }, ClippedRect, false>.name: "frost"
Unique among the backend's effects. With the backend's name, the effect's wire identity.
name
: "frost",
params: {
    readonly amount: ActorFieldSignal<number>;
} & NoPlaybackParams
Every param the kind's contribution reads, declared once as `signal(default)` or `signal.of(type, default)`.
params
: { amount: ActorFieldSignal<number>amount: signal<number>(initial: number): ActorFieldSignal<number> (+1 overload)
A timeline value on an actor, and an input to every spawn of it. Without an initial value the signal is required: `ctx.spawn` must supply it.
signal
(0.4) },
EffectSpec<"frost", { readonly amount: ActorFieldSignal<number>; }, ClippedRect, false>.target?: TypedEffectTargetContract<ClippedRect> | undefined
What an explicit target must carry, and whether the effect clips to it: `effectTargetContract<T>({ dataKinds, geometry, clips })`.
target
: effectTargetContract<ClippedRect>(contract: EffectTargetContractFor<ClippedRect>): TypedEffectTargetContract<ClippedRect>
A target contract that carries the target type its effect's render reads. `dataKinds` and `geometry` are checked against that type.
effectTargetContract
<
type ClippedRect = {
    readonly data: unknown;
    readonly geometry: "rect";
    readonly clips: true;
}
Any rect it clips to: a target, or the node a view binds.
ClippedRect
>({ dataKinds: readonly string[]dataKinds: [], geometry: readonly "rect"[]geometry: ["rect"], clips: trueclips: true }),
shader: GlShaderProgram<EffectParamValues<{
    readonly amount: ActorFieldSignal<number>;
}>>
shader
: { GlShaderProgram<TParams>.fs: stringfs: const FROST_FS: "#version 300 es\nprecision highp float;\nuniform sampler2D u_tex;\nuniform bool u_hasRegion;\nuniform vec4 u_regionRect;\nuniform float u_amount;\nin vec2 v_uv;\nout vec4 color;\nvoid main() {\n vec4 source = texture(u_tex, v_uv);\n vec2 local = (vec2(v_uv.x, 1.0 - v_uv.y) - u_regionRect.xy) / u_regionRect.zw;\n bool inside = all(greaterThanEqual(local, vec2(0.0))) && all(lessThanEqual(local, vec2(1.0)));\n color = u_hasRegion && !inside ? source : mix(source, vec4(1.0), u_amount);\n}"FROST_FS },
uniforms: GlShaderUniforms<EffectParamValues<{
    readonly amount: ActorFieldSignal<number>;
}>, ResolvedCanvasEffectTargetFor<unknown, "rect">>
uniforms
: ({ amount: numberamount }, { target: ResolvedCanvasEffectTargetFor<unknown, "rect"> | undefined
The explicit target, resolved to canvas geometry, when the effect was applied to one.
target
}) => ({ ...
function targetRegionUniforms(target: ResolvedCanvasEffectTarget | undefined): {
    readonly hasRegion: boolean;
    readonly regionRect: readonly [number, number, number, number];
}
The `u_hasRegion` / `u_regionRect` pair a region-scoped shader reads: the target's first rect or quad bounds in canvas UV, or the whole canvas for a pass with no target. A pass whose target has no area never paints (the pipeline skips it), so it never reads the whole canvas.
targetRegionUniforms
(target: ResolvedCanvasEffectTargetFor<unknown, "rect"> | undefined
The explicit target, resolved to canvas geometry, when the effect was applied to one.
target
), amount: numberamount }),
}); declare module "@motionactor/core" { interface ActorEffects { "dom:frost": typeof
const frost: EffectDefinition<"dom", "frost", {
    readonly amount: ActorFieldSignal<number>;
}, EffectKind<"dom", "shader", GlShaderTypes, {
    readonly kind: "offscreen";
    readonly scope: "actor";
}, "actor">, ClippedRect, GlShaderRuntime<EffectParamValues<{
    readonly amount: ActorFieldSignal<number>;
}>, ResolvedCanvasEffectTargetFor<unknown, "rect">>, false, "target">
frost
;
} } function registerEffects(definitions: readonly AnyEffectDefinition[]): void
Install effects by wire id. Call it in the effect's own module, after its `defineEffect(...)` (and beside its `ActorEffects` augmentation when it applies to an actor), so importing the effect installs it. Every effect registers. One that can apply to an actor is also on every actor's `fx`; one that cannot (a layer application, or one needing target data) stays off `fx` and applies with `ctx.apply` on a target. A later registration at a wire id replaces the earlier one. An actor effect named `for` throws: `fx.for` is taken.
registerEffects
([
const frost: EffectDefinition<"dom", "frost", {
    readonly amount: ActorFieldSignal<number>;
}, EffectKind<"dom", "shader", GlShaderTypes, {
    readonly kind: "offscreen";
    readonly scope: "actor";
}, "actor">, ClippedRect, GlShaderRuntime<EffectParamValues<{
    readonly amount: ActorFieldSignal<number>;
}>, ResolvedCanvasEffectTargetFor<unknown, "rect">>, false, "target">
frost
]);
class class CardCard extends class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor { Card.panel: ChildField<typeof LayoutActor, object>panel = child<typeof LayoutActor, object>(blueprint: typeof LayoutActor, overrides?: ChildOverrides<typeof LayoutActor, object> | undefined): ChildField<typeof LayoutActor, object>child(class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor); } export const
const compiled: CompiledScene<{
    card: Card;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
=
createScene<{
    card: Card;
}, Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>>(script: SceneScript<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, {
    card: Card;
}>, options?: SceneDefinitionOptions<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>> | undefined): SceneDefinition<...>
Declare a scene. Nothing compiles until a host builds it: `scene.build({ viewport, fps, inputs })` runs the script as `(ctx, inputs, viewport, layers)` and returns the compiled scene. `ctx.spawn` places a root actor in the default layer; `layers.<key>.spawn` places it in a declared one. `ctx.stage` stages another scene on this scene's clock, and a staged scene may stage again.
createScene
(function* (ctx: SceneContextctx) {
const const card: Cardcard = ctx: SceneContextctx.
CompileContext.spawn<Card>(definition: ActorClass<Card>, overrides?: {
    id?: undefined;
    localLayout?: undefined;
    worldLayout?: undefined;
    compositing?: {
        blend?: SignalInputValue<"source-over" | "multiply" | "screen" | "overlay" | "darken" | "lighten" | "color-dodge" | "color-burn" | "hard-light" | "soft-light" | "difference" | "exclusion" | "hue" | "saturation" | "color" | "luminosity" | "plus-lighter"> | undefined;
        isolate?: SignalInputValue<boolean> | undefined;
        clip?: SignalInputValue<number | null> | undefined;
    } | undefined;
    ... 19 more ...;
    panel?: {
        ...;
    } | undefined;
} | undefined, options?: {
    ...;
} | undefined): Card (+1 overload)
spawn
(class CardCard);
const card: Cardcard.Card.panel: ChildField<typeof LayoutActor, object>panel.Actor<TEvents extends ActorEventMap = {}>.fx: ActorFx
Installed effects by name: `yield* this.fx.burnDissolve({ noiseScale: 7 }, { duration: 0.6 })` plays one; `this.fx.glow({ spread: 24 })` keeps its handle. A name two installed backends define is selected with `this.fx.for(dom).glow(...)`. Applies only once spawned; the layer's backend is checked when bound.
fx
.
frost: () => FxHandle<EffectDefinition<"dom", "frost", {
    readonly amount: ActorFieldSignal<number>;
}, EffectKind<"dom", "shader", GlShaderTypes, {
    readonly kind: "offscreen";
    readonly scope: "actor";
}, "actor">, ClippedRect, GlShaderRuntime<EffectParamValues<{
    readonly amount: ActorFieldSignal<number>;
}>, ResolvedCanvasEffectTargetFor<unknown, "rect">>, false, "target">, {}> (+3 overloads)
Apply at the cursor with every param at its default.
frost
();
yield* ctx: SceneContextctx.CompileContext.wait(duration: Duration): Generator<Frame, void, unknown>wait(1); return { card: Cardcard }; }).
SceneDefinition<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, { ...; }>.build(args: SceneBuildInput<Readonly<Record<never, SceneInput>>>): CompiledScene<{
    card: Card;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
build
({ viewport: SceneViewportviewport: { SceneViewport.width: numberwidth: 1920, SceneViewport.height: numberheight: 1080 }, fps: numberfps: 30 });
export const const card: BackendRendererDefinition<readonly [typeof Card], "dom">card = const dom: StagedBackend<React.FC<ReactBackendHostProps>, "dom", React.ReactNode>
The React DOM backend, and the `dom` binding code names: `dom.render(Box, …)`, `createRenderRuntime({ backends: [dom] })`.
dom
.render: <typeof Card>(blueprint: typeof Card, render: ActorRendererForBlueprints<readonly [typeof Card], "dom">, options?: ActorRendererRegistrationOptions) => BackendRendererDefinition<readonly [typeof Card], "dom"> (+1 overload)render(class CardCard, ({
refs: TargetRefs<{}> & {
    readonly panel: BoundElementRef;
} & {
    readonly self: BoundElementRef;
}
refs
}) => (
<React.JSX.IntrinsicElements.article: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>article> <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div React.RefAttributes<HTMLDivElement>.ref?: React.Ref<HTMLDivElement> | undefined
Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
@see{@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
ref
={
refs: TargetRefs<{}> & {
    readonly panel: BoundElementRef;
} & {
    readonly self: BoundElementRef;
}
refs
.panel: BoundElementRefpanel}>Q3 revenue</React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div>
</React.JSX.IntrinsicElements.article: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>article> ));

card.panel.fx offers every installed effect on any child: whether the view binds it or renders it through its outlet is the view’s choice, so the check runs at bind. A child the view renders through its outlet keeps its own element, which runs any of its effects in a canvas of its own. A page binding has no actor element around it, so an offscreen effect on its actor throws at bind. While a bound node has no area (display: none, zero size), its effect paints nothing; it stays registered and paints again once the node shows.

Three bindings

A three renderer binds the same way, to objects of its own markup: refs.self binds an Object3D to the actor, and refs.<child> binds one to each child(...). Any actor binds. At the start of each advance of the canvas, before the composer and the render, the host writes each of position, rotation and scale the actor’s blueprint declares as an x/y/z group onto the object, so a frame that only moves an actor renders no component. An Object3DActor declares all three; a LayoutActor declares none, so its object keeps the placement its markup gives it.

import { function child<TBlueprint extends ActorClass<object>, TOwner extends object = object>(blueprint: TBlueprint, ...[overrides]: ChildOverridesArg<TBlueprint, TOwner>): ChildField<TBlueprint, TOwner>child, function createScene<TSceneExports, const I extends SceneInputs = Readonly<Record<never, SceneInput>>, const L extends SceneLayers = Readonly<Record<never, SceneLayer<BackendRef<string>>>>>(script: SceneScript<I, L, TSceneExports>, options?: SceneDefinitionOptions<I, L>): SceneDefinition<I, L, TSceneExports>
Declare a scene. Nothing compiles until a host builds it: `scene.build({ viewport, fps, inputs })` runs the script as `(ctx, inputs, viewport, layers)` and returns the compiled scene. `ctx.spawn` places a root actor in the default layer; `layers.<key>.spawn` places it in a declared one. `ctx.stage` stages another scene on this scene's clock, and a staged scene may stage again.
createScene
} from "@motionactor/core";
import { class Object3DActor<TEvents extends ActorEventMap = {}>Object3DActor, class Primitive3DPrimitive3D } from "@motionactor/three"; import { const three: Backend<ReactBackendHost, "three">three } from "@motionactor/three/react"; class class RigRig extends class Object3DActor<TEvents extends ActorEventMap = {}>Object3DActor { Rig.lid: ChildField<typeof Primitive3D, object>lid = child<typeof Primitive3D, object>(blueprint: typeof Primitive3D, overrides?: ChildOverrides<typeof Primitive3D, object> | undefined): ChildField<typeof Primitive3D, object>child(class Primitive3DPrimitive3D); } export const
const compiled: CompiledScene<{
    rig: Rig;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
=
createScene<{
    rig: Rig;
}, Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>>(script: SceneScript<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, {
    rig: Rig;
}>, options?: SceneDefinitionOptions<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>> | undefined): SceneDefinition<...>
Declare a scene. Nothing compiles until a host builds it: `scene.build({ viewport, fps, inputs })` runs the script as `(ctx, inputs, viewport, layers)` and returns the compiled scene. `ctx.spawn` places a root actor in the default layer; `layers.<key>.spawn` places it in a declared one. `ctx.stage` stages another scene on this scene's clock, and a staged scene may stage again.
createScene
(function* (ctx: SceneContextctx) {
const const rig: Rigrig = ctx: SceneContextctx.
CompileContext.spawn<Rig>(definition: ActorClass<Rig>, overrides?: {
    id?: undefined;
    cursor?: undefined;
    cursorSeconds?: undefined;
    sceneFps?: undefined;
    onInit?: undefined;
    onEnter?: undefined;
    onExit?: undefined;
    enter?: undefined;
    exit?: undefined;
    parent?: undefined;
    position?: {
        x?: SignalInputValue<number> | undefined;
        y?: SignalInputValue<number> | undefined;
        z?: SignalInputValue<number> | undefined;
    } | undefined;
    rotation?: {
        x?: SignalInputValue<number> | undefined;
        y?: SignalInputValue<number> | undefined;
        z?: SignalInputValue<...> | undefined;
    } | undefined;
    ... 4 more ...;
    lid?: {
        ...;
    } | undefined;
} | undefined, options?: {
    ...;
} | undefined): Rig (+1 overload)
spawn
(class RigRig);
yield* const rig: Rigrig.Rig.lid: ChildField<typeof Primitive3D, object>lid.Object3DActor<{}>.rotateTo(rotation: Vector3, transition?: TweenTransition): Generator<number, void, unknown>rotateTo({ x: numberx: 0, y: numbery: var Math: Math
An intrinsic object that provides basic mathematics functionality and constants.
Math
.Math.PI: number
Pi. This is the ratio of the circumference of a circle to its diameter.
PI
, z: numberz: 0 }, 1);
return { rig: Rigrig }; }).
SceneDefinition<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, { ...; }>.build(args: SceneBuildInput<Readonly<Record<never, SceneInput>>>): CompiledScene<{
    rig: Rig;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
build
({ viewport: SceneViewportviewport: { SceneViewport.width: numberwidth: 1920, SceneViewport.height: numberheight: 1080 }, fps: numberfps: 30 });
export const const rig: BackendRendererDefinition<readonly [typeof Rig], "three">rig = const three: Backend<ReactBackendHost, "three">three.render: <typeof Rig>(blueprint: typeof Rig, render: ActorRendererForBlueprints<readonly [typeof Rig], "three">, options?: ActorRendererRegistrationOptions) => BackendRendererDefinition<readonly [typeof Rig], "three"> (+1 overload)render(class RigRig, ({
refs: BindingRefs<Rig, {
    actor: ThreeBindable;
    ref: BoundObjectRef;
}>
refs
}) => (
<group: Mutable<Overwrite<Partial<Overwrite<Group<Object3DEventMap>, MathProps<Group<Object3DEventMap>> & ReactProps<Group<Object3DEventMap>> & Partial<EventHandlers>>>, Omit<InstanceProps<Group<Object3DEventMap>, typeof Group>, "object">>>group ref?: ((instance: Group<Object3DEventMap> | null) => void | (() => VoidOrUndefinedOnly) | DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | ... 4 more ... | undefinedref={
refs: BindingRefs<Rig, {
    actor: ThreeBindable;
    ref: BoundObjectRef;
}>
refs
.self: BoundObjectRefself}>
<mesh: Mutable<Overwrite<Partial<Overwrite<Mesh<BufferGeometry<NormalBufferAttributes, BufferGeometryEventMap>, Material<MaterialEventMap> | Material<MaterialEventMap>[], Object3DEventMap>, MathProps<Mesh<BufferGeometry<NormalBufferAttributes, BufferGeometryEventMap>, Material<MaterialEventMap> | Material<MaterialEventMap>[], Object3DEventMap>> & ReactProps<...> & Partial<...>>>, Omit<...>>>mesh ref?: ((instance: Mesh<BufferGeometry<NormalBufferAttributes, BufferGeometryEventMap>, Material<MaterialEventMap> | Material<MaterialEventMap>[], Object3DEventMap> | null) => void | (() => VoidOrUndefinedOnly) | DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | ... 4 more ... | undefinedref={
refs: BindingRefs<Rig, {
    actor: ThreeBindable;
    ref: BoundObjectRef;
}>
refs
.lid: BoundObjectReflid}>
<boxGeometry: Mutable<Overwrite<Partial<Overwrite<BoxGeometry, MathProps<BoxGeometry> & ReactProps<BoxGeometry>>>, Omit<InstanceProps<BoxGeometry, typeof BoxGeometry>, "object">>>boxGeometry /> <meshStandardMaterial: Mutable<Overwrite<Partial<Overwrite<MeshStandardMaterial, MathProps<MeshStandardMaterial> & ReactProps<MeshStandardMaterial>>>, Omit<InstanceProps<MeshStandardMaterial, typeof MeshStandardMaterial>, "object">>>meshStandardMaterial /> </mesh: Mutable<Overwrite<Partial<Overwrite<Mesh<BufferGeometry<NormalBufferAttributes, BufferGeometryEventMap>, Material<MaterialEventMap> | Material<MaterialEventMap>[], Object3DEventMap>, MathProps<Mesh<BufferGeometry<NormalBufferAttributes, BufferGeometryEventMap>, Material<MaterialEventMap> | Material<MaterialEventMap>[], Object3DEventMap>> & ReactProps<...> & Partial<...>>>, Omit<...>>>mesh> </group: Mutable<Overwrite<Partial<Overwrite<Group<Object3DEventMap>, MathProps<Group<Object3DEventMap>> & ReactProps<Group<Object3DEventMap>> & Partial<EventHandlers>>>, Omit<InstanceProps<Group<Object3DEventMap>, typeof Group>, "object">>>group> ));
While bound The object gets
The actor is present Each of position, rotation and scale its blueprint declares
The actor is absent visible = false
The object unbinds Its visibility, and each group it took, as it had them when it bound

A bound object is the actor’s effect target, whatever the actor: rig.lid.fx.<name>() selects the meshes under the object bound to lid. A LayoutActor drawn by a three view binds its root the same way, and takes effects without any placement:

import { class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor } from "@motionactor/core";
import { const three: Backend<ReactBackendHost, "three">three } from "@motionactor/three/react";

class class GalleryGallery extends class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor {}

export const const gallery: BackendRendererDefinition<readonly [typeof Gallery], "three">gallery = const three: Backend<ReactBackendHost, "three">three.render: <typeof Gallery>(blueprint: typeof Gallery, render: ActorRendererForBlueprints<readonly [typeof Gallery], "three">, options?: ActorRendererRegistrationOptions) => BackendRendererDefinition<readonly [typeof Gallery], "three"> (+1 overload)render(class GalleryGallery, ({ 
refs: BindingRefs<Gallery, {
    actor: ThreeBindable;
    ref: BoundObjectRef;
}>
refs
}) => (
<group: Mutable<Overwrite<Partial<Overwrite<Group<Object3DEventMap>, MathProps<Group<Object3DEventMap>> & ReactProps<Group<Object3DEventMap>> & Partial<EventHandlers>>>, Omit<InstanceProps<Group<Object3DEventMap>, typeof Group>, "object">>>group ref?: ((instance: Group<Object3DEventMap> | null) => void | (() => VoidOrUndefinedOnly) | DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | ... 4 more ... | undefinedref={
refs: BindingRefs<Gallery, {
    actor: ThreeBindable;
    ref: BoundObjectRef;
}>
refs
.self: BoundObjectRefself} position?: Vector3 | [x: number, y: number, z: number] | Readonly<number | Vector3 | [x: number, y: number, z: number] | undefined>
Object's local position.
@defaultValue`new THREE.Vector3()` - that is `(0, 0, 0)`.
position
={[0, 0, -4]}>
<mesh: Mutable<Overwrite<Partial<Overwrite<Mesh<BufferGeometry<NormalBufferAttributes, BufferGeometryEventMap>, Material<MaterialEventMap> | Material<MaterialEventMap>[], Object3DEventMap>, MathProps<Mesh<BufferGeometry<NormalBufferAttributes, BufferGeometryEventMap>, Material<MaterialEventMap> | Material<MaterialEventMap>[], Object3DEventMap>> & ReactProps<...> & Partial<...>>>, Omit<...>>>mesh> <planeGeometry: Mutable<Overwrite<Partial<Overwrite<PlaneGeometry, MathProps<PlaneGeometry> & ReactProps<PlaneGeometry>>>, Omit<InstanceProps<PlaneGeometry, typeof PlaneGeometry>, "object">>>planeGeometry /> <meshStandardMaterial: Mutable<Overwrite<Partial<Overwrite<MeshStandardMaterial, MathProps<MeshStandardMaterial> & ReactProps<MeshStandardMaterial>>>, Omit<InstanceProps<MeshStandardMaterial, typeof MeshStandardMaterial>, "object">>>meshStandardMaterial /> </mesh: Mutable<Overwrite<Partial<Overwrite<Mesh<BufferGeometry<NormalBufferAttributes, BufferGeometryEventMap>, Material<MaterialEventMap> | Material<MaterialEventMap>[], Object3DEventMap>, MathProps<Mesh<BufferGeometry<NormalBufferAttributes, BufferGeometryEventMap>, Material<MaterialEventMap> | Material<MaterialEventMap>[], Object3DEventMap>> & ReactProps<...> & Partial<...>>>, Omit<...>>>mesh> </group: Mutable<Overwrite<Partial<Overwrite<Group<Object3DEventMap>, MathProps<Group<Object3DEventMap>> & ReactProps<Group<Object3DEventMap>> & Partial<EventHandlers>>>, Omit<InstanceProps<Group<Object3DEventMap>, typeof Group>, "object">>>group> ));

Only Object3Ds bind; anything else throws a BoundObjectError. Primitive3D’s own renderer binds its mesh through refs.self.

Page bindings

Markup outside every actor’s view binds an actor too. actor.<tag> from @motionactor/dom/react renders that element bound to the actor a live handle names: a handle from the scene’s exports, compiled.scene. Render it among SceneRenderer’s children, which render in the scope of the scene’s DOM layer. Below, nothing draws the card: the heading is the page’s own, and each frame the DOM layer writes the title’s style onto it with no render of the page.

import { const createRenderRuntime: (input: CreateRenderRuntimeInput<ReactBackendHost, React.ReactNode>) => ReactRenderRuntime
The floor's `createRenderRuntime` for React: every backend's host is a React component and its stages wrap React nodes, so mixed backends (each with its own host props) compose without naming a type.
createRenderRuntime
} from "@motionactor/renderers/react";
import { const actor: ActorTags
Page markup bound to an actor: `<actor.h1 of={compiled.scene.card.title} className="text-6xl">Launch</actor.h1>` renders a heading the scene's DOM layer writes each frame the title moves, with no render of the page. Render it among `SceneRenderer`'s children, which render in the scope of the scene's DOM layer; the actor must paint in that layer. It renders the frame's style inline, on the server too; while the actor is absent, it keeps its place in flow, hidden. It owns nothing: the actor's element is its view's, and a view binds a node of its own markup with `refs`.
actor
, const dom: StagedBackend<React.FC<ReactBackendHostProps>, "dom", React.ReactNode>
The React DOM backend, and the `dom` binding code names: `dom.render(Box, …)`, `createRenderRuntime({ backends: [dom] })`.
dom
} from "@motionactor/dom/react";
import type {
const scene: SceneDefinition<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, {
    card: Card;
}>
scene
} from "./page-heading.scene";
export const const runtime: ReactRenderRuntimeruntime = function createRenderRuntime(input: CreateRenderRuntimeInput<ReactBackendHost, React.ReactNode>): ReactRenderRuntime
The floor's `createRenderRuntime` for React: every backend's host is a React component and its stages wrap React nodes, so mixed backends (each with its own host props) compose without naming a type.
createRenderRuntime
({
backends: readonly AnyBackend<ReactBackendHost, React.ReactNode>[]backends: [const dom: StagedBackend<React.FC<ReactBackendHostProps>, "dom", React.ReactNode>
The React DOM backend, and the `dom` binding code names: `dom.render(Box, …)`, `createRenderRuntime({ backends: [dom] })`.
dom
],
renderers?: readonly RendererRegistryEntry[] | undefined
Family and project renderers, for any backend. Each routes to the backend it names (`three.render(…)`); one naming a backend missing from `backends` throws.
renderers
: [],
}); // The page's markup for a build, rendered as SceneRenderer's children. // The scene's DOM layer writes the heading each frame. export const const page: (compiled: ReturnType<typeof scene.build>) => JSX.Elementpage = (
compiled: CompiledScene<{
    card: Card;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
: type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any
Obtain the return type of a function type
ReturnType
<typeof
const scene: SceneDefinition<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, {
    card: Card;
}>
scene
.
SceneDefinition<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, { ...; }>.build(args: SceneBuildInput<Readonly<Record<never, SceneInput>>>): CompiledScene<{
    card: Card;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
build
>) => (
<React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div React.HTMLAttributes<HTMLDivElement>.className?: string | undefinedclassName="grid h-[720px] place-items-center"> <const actor: ActorTags
Page markup bound to an actor: `<actor.h1 of={compiled.scene.card.title} className="text-6xl">Launch</actor.h1>` renders a heading the scene's DOM layer writes each frame the title moves, with no render of the page. Render it among `SceneRenderer`'s children, which render in the scope of the scene's DOM layer; the actor must paint in that layer. It renders the frame's style inline, on the server too; while the actor is absent, it keeps its place in flow, hidden. It owns nothing: the actor's element is its view's, and a view binds a node of its own markup with `refs`.
actor
.h1: React.FC<ActorTagProps<"h1">>h1
of: PageBindable
A live handle of the scene's exports: `compiled.scene.card.title`.
of
={
compiled: CompiledScene<{
    card: Card;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
.
CompiledScene<{ ...; }, CompiledLayersOf<...>>.scene: {
    card: Card;
}
What the scene's generator returned: its exported actors as the handles it authored with (`compiled.scene.card.title`). After the build they only name their actors: a write or lifecycle call through one throws, and a frame's values are read from `at(frame).scene`. Page markup binds one (`<actor.h1 of={compiled.scene.card.title}>`).
scene
.card: Cardcard.Card.title: ChildField<typeof Title, object>title}
className?: string | undefinedclassName="text-9xl font-medium text-[var(--stage-ink)]" > Launch </const actor: ActorTags
Page markup bound to an actor: `<actor.h1 of={compiled.scene.card.title} className="text-6xl">Launch</actor.h1>` renders a heading the scene's DOM layer writes each frame the title moves, with no render of the page. Render it among `SceneRenderer`'s children, which render in the scope of the scene's DOM layer; the actor must paint in that layer. It renders the frame's style inline, on the server too; while the actor is absent, it keeps its place in flow, hidden. It owns nothing: the actor's element is its view's, and a view binds a node of its own markup with `refs`.
actor
.h1: React.FC<ActorTagProps<"h1">>h1>
</React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>div> ); // @filename: stage.tsx import {
const SceneRenderer: <TSceneExports>({ compiled, frame, width, height, sceneMeta, style, children, runtime, }: {
    compiled: CompiledScene<TSceneExports>;
    frame: number;
    width: number;
    height: number;
    sceneMeta?: unknown;
    style?: React.CSSProperties;
    children?: React.ReactNode;
    runtime?: ReactRenderRuntime;
}) => JSX.Element
Frame-passive renderer for a CompiledScene: resolves the frame and paints its layers (`SceneLayers`) on a stage of `width` by `height`. Each layer is painted by the host its backend registers on the runtime; the default layer by the runtime's default backend. `children` are page markup: they render in the scope of the scene's DOM layer, where `<actor.h1 of={compiled.scene.card.title}>` binds a node of it to an actor (`SceneLayers`).
SceneRenderer
} from "@motionactor/renderers/react";
import type {
const scene: SceneDefinition<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, {
    card: Card;
}>
scene
} from "./page-heading.scene";
import { const page: (compiled: ReturnType<typeof scene.build>) => JSX.Elementpage, const runtime: ReactRenderRuntimeruntime } from "./page-heading.render"; type
type Build = CompiledScene<{
    card: Card;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
Build
= type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any
Obtain the return type of a function type
ReturnType
<typeof
const scene: SceneDefinition<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, {
    card: Card;
}>
scene
.
SceneDefinition<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, { ...; }>.build(args: SceneBuildInput<Readonly<Record<never, SceneInput>>>): CompiledScene<{
    card: Card;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
build
>;
export const
const Stage: ({ compiled, frame }: {
    compiled: Build;
    frame: number;
}) => JSX.Element
Stage
= ({
compiled: CompiledScene<{
    card: Card;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
, frame: numberframe }: {
compiled: CompiledScene<{
    card: Card;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
:
type Build = CompiledScene<{
    card: Card;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
Build
; frame: numberframe: number }) => (
<
const SceneRenderer: <TSceneExports>({ compiled, frame, width, height, sceneMeta, style, children, runtime, }: {
    compiled: CompiledScene<TSceneExports>;
    frame: number;
    width: number;
    height: number;
    sceneMeta?: unknown;
    style?: React.CSSProperties;
    children?: React.ReactNode;
    runtime?: ReactRenderRuntime;
}) => JSX.Element
Frame-passive renderer for a CompiledScene: resolves the frame and paints its layers (`SceneLayers`) on a stage of `width` by `height`. Each layer is painted by the host its backend registers on the runtime; the default layer by the runtime's default backend. `children` are page markup: they render in the scope of the scene's DOM layer, where `<actor.h1 of={compiled.scene.card.title}>` binds a node of it to an actor (`SceneLayers`).
SceneRenderer
compiled: CompiledScene<{
    card: Card;
}, Readonly<Record<string, CompiledLayer<BackendRef<string>>>>>
compiled
={
compiled: CompiledScene<{
    card: Card;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
} frame: numberframe={frame: numberframe} width: numberwidth={1280} height: numberheight={720} runtime?: ReactRenderRuntime | undefinedruntime={const runtime: ReactRenderRuntimeruntime}>
{function page(compiled: ReturnType<typeof scene.build>): JSX.Elementpage(
compiled: CompiledScene<{
    card: Card;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
)}
</
const SceneRenderer: <TSceneExports>({ compiled, frame, width, height, sceneMeta, style, children, runtime, }: {
    compiled: CompiledScene<TSceneExports>;
    frame: number;
    width: number;
    height: number;
    sceneMeta?: unknown;
    style?: React.CSSProperties;
    children?: React.ReactNode;
    runtime?: ReactRenderRuntime;
}) => JSX.Element
Frame-passive renderer for a CompiledScene: resolves the frame and paints its layers (`SceneLayers`) on a stage of `width` by `height`. Each layer is painted by the host its backend registers on the runtime; the default layer by the runtime's default backend. `children` are page markup: they render in the scope of the scene's DOM layer, where `<actor.h1 of={compiled.scene.card.title}>` binds a node of it to an actor (`SceneLayers`).
SceneRenderer
>
);

Vue renders <actor.h1 :of="compiled.scene.card.title" class="text-6xl"> in a <script setup> template, with actor from @motionactor/dom/vue, in SceneRenderer’s default slot. Svelte renders <actor.h1 of={compiled.scene.card.title} class="text-6xl">, with actor from @motionactor/dom/svelte, among its children.

The node is written exactly as a refs binding writes one (the table above), and keeps its place in the page’s flow. The server render and the first render carry the frame’s style inline, after the element’s own style, with the actor’s inline effects folded in as the node paints them: a domStyle effect that fades and blurs renders its opacity and blur(…) filter on the server too. An effect whose style reads the node’s box has no box before the node mounts and is measured, so the server render carries its box-less form and the node takes the measured one on its first frame. Before the actor spawns, the element’s own values, hidden. of takes a live handle of a LayoutActor: a frame’s resolved actor, or an actor with no layout, is a type error, and each tag takes its own element’s props.

The scene Its page markup renders in
The runtime’s default backend is DOM The default layer, mounted for the markup even when none of its actors paint
Another backend paints the default layer The first declared layer DOM paints
No layer is DOM Beneath every layer: an actor.<tag> there throws, naming the actor

The markup renders at its layer’s origin, beneath the layer’s actors and under its camera; layer order and clipping stay as declared. To render part of it in a later DOM layer, wrap that part in InLayer with the build’s handle on the layer, compiled.layers.<key>; markup with no address stays in the first DOM layer.

import { const createRenderRuntime: (input: CreateRenderRuntimeInput<ReactBackendHost, React.ReactNode>) => ReactRenderRuntime
The floor's `createRenderRuntime` for React: every backend's host is a React component and its stages wrap React nodes, so mixed backends (each with its own host props) compose without naming a type.
createRenderRuntime
,
const InLayer: ({ layer, children }: Readonly<{
    layer: LayerAddress;
    children?: React.ReactNode;
}>) => JSX.Element | null
Places its markup in the DOM layer `layer` addresses, a layer of the build the enclosing `SceneRenderer` renders: `<InLayer layer={compiled.layers.ui}>`, or a composition's `compiled.layersOf(scene).ui`. Anywhere in the page markup outside an actor's view, through any component, its markup renders in that layer's host (`PageContent`); markup with no address renders in the scene's first DOM layer. Nothing renders while the layer is not on stage. A changed address moves the markup; one of another build throws as it renders. Moved markup renders under the addressed layer's host, so a React context provided between `SceneRenderer` and the `InLayer` does not reach it.
InLayer
,
const SceneRenderer: <TSceneExports>({ compiled, frame, width, height, sceneMeta, style, children, runtime, }: {
    compiled: CompiledScene<TSceneExports>;
    frame: number;
    width: number;
    height: number;
    sceneMeta?: unknown;
    style?: React.CSSProperties;
    children?: React.ReactNode;
    runtime?: ReactRenderRuntime;
}) => JSX.Element
Frame-passive renderer for a CompiledScene: resolves the frame and paints its layers (`SceneLayers`) on a stage of `width` by `height`. Each layer is painted by the host its backend registers on the runtime; the default layer by the runtime's default backend. `children` are page markup: they render in the scope of the scene's DOM layer, where `<actor.h1 of={compiled.scene.card.title}>` binds a node of it to an actor (`SceneLayers`).
SceneRenderer
} from "@motionactor/renderers/react";
import { const actor: ActorTags
Page markup bound to an actor: `<actor.h1 of={compiled.scene.card.title} className="text-6xl">Launch</actor.h1>` renders a heading the scene's DOM layer writes each frame the title moves, with no render of the page. Render it among `SceneRenderer`'s children, which render in the scope of the scene's DOM layer; the actor must paint in that layer. It renders the frame's style inline, on the server too; while the actor is absent, it keeps its place in flow, hidden. It owns nothing: the actor's element is its view's, and a view binds a node of its own markup with `refs`.
actor
, const dom: StagedBackend<React.FC<ReactBackendHostProps>, "dom", React.ReactNode>
The React DOM backend, and the `dom` binding code names: `dom.render(Box, …)`, `createRenderRuntime({ backends: [dom] })`.
dom
} from "@motionactor/dom/react";
import {
const compiled: CompiledScene<{
    lead: Label;
    badge: Label;
}, CompiledLayersOf<{
    readonly page: SceneLayer<BackendRef<"dom">>;
    readonly overlay: SceneLayer<BackendRef<"dom">>;
}>>
compiled
} from "./badge.scene";
const const runtime: ReactRenderRuntimeruntime = function createRenderRuntime(input: CreateRenderRuntimeInput<ReactBackendHost, React.ReactNode>): ReactRenderRuntime
The floor's `createRenderRuntime` for React: every backend's host is a React component and its stages wrap React nodes, so mixed backends (each with its own host props) compose without naming a type.
createRenderRuntime
({ backends: readonly AnyBackend<ReactBackendHost, React.ReactNode>[]backends: [const dom: StagedBackend<React.FC<ReactBackendHostProps>, "dom", React.ReactNode>
The React DOM backend, and the `dom` binding code names: `dom.render(Box, …)`, `createRenderRuntime({ backends: [dom] })`.
dom
], renderers?: readonly RendererRegistryEntry[] | undefined
Family and project renderers, for any backend. Each routes to the backend it names (`three.render(…)`); one naming a backend missing from `backends` throws.
renderers
: [] });
export const
const Stage: ({ frame }: {
    frame: number;
}) => JSX.Element
Stage
= ({ frame: numberframe }: { frame: numberframe: number }) => (
<
const SceneRenderer: <TSceneExports>({ compiled, frame, width, height, sceneMeta, style, children, runtime, }: {
    compiled: CompiledScene<TSceneExports>;
    frame: number;
    width: number;
    height: number;
    sceneMeta?: unknown;
    style?: React.CSSProperties;
    children?: React.ReactNode;
    runtime?: ReactRenderRuntime;
}) => JSX.Element
Frame-passive renderer for a CompiledScene: resolves the frame and paints its layers (`SceneLayers`) on a stage of `width` by `height`. Each layer is painted by the host its backend registers on the runtime; the default layer by the runtime's default backend. `children` are page markup: they render in the scope of the scene's DOM layer, where `<actor.h1 of={compiled.scene.card.title}>` binds a node of it to an actor (`SceneLayers`).
SceneRenderer
compiled: CompiledScene<{
    lead: Label;
    badge: Label;
}, Readonly<Record<string, CompiledLayer<BackendRef<string>>>>>
compiled
={
const compiled: CompiledScene<{
    lead: Label;
    badge: Label;
}, CompiledLayersOf<{
    readonly page: SceneLayer<BackendRef<"dom">>;
    readonly overlay: SceneLayer<BackendRef<"dom">>;
}>>
compiled
} frame: numberframe={frame: numberframe} width: numberwidth={1280} height: numberheight={720} runtime?: ReactRenderRuntime | undefinedruntime={const runtime: ReactRenderRuntimeruntime}>
<const actor: ActorTags
Page markup bound to an actor: `<actor.h1 of={compiled.scene.card.title} className="text-6xl">Launch</actor.h1>` renders a heading the scene's DOM layer writes each frame the title moves, with no render of the page. Render it among `SceneRenderer`'s children, which render in the scope of the scene's DOM layer; the actor must paint in that layer. It renders the frame's style inline, on the server too; while the actor is absent, it keeps its place in flow, hidden. It owns nothing: the actor's element is its view's, and a view binds a node of its own markup with `refs`.
actor
.h2: React.FC<ActorTagProps<"h2">>h2 of: PageBindable
A live handle of the scene's exports: `compiled.scene.card.title`.
of
={
const compiled: CompiledScene<{
    lead: Label;
    badge: Label;
}, CompiledLayersOf<{
    readonly page: SceneLayer<BackendRef<"dom">>;
    readonly overlay: SceneLayer<BackendRef<"dom">>;
}>>
compiled
.
CompiledScene<{ lead: Label; badge: Label; }, CompiledLayersOf<{ readonly page: SceneLayer<BackendRef<"dom">>; readonly overlay: SceneLayer<BackendRef<"dom">>; }>>.scene: {
    lead: Label;
    badge: Label;
}
What the scene's generator returned: its exported actors as the handles it authored with (`compiled.scene.card.title`). After the build they only name their actors: a write or lifecycle call through one throws, and a frame's values are read from `at(frame).scene`. Page markup binds one (`<actor.h1 of={compiled.scene.card.title}>`).
scene
.lead: Labellead}>Launch</const actor: ActorTags
Page markup bound to an actor: `<actor.h1 of={compiled.scene.card.title} className="text-6xl">Launch</actor.h1>` renders a heading the scene's DOM layer writes each frame the title moves, with no render of the page. Render it among `SceneRenderer`'s children, which render in the scope of the scene's DOM layer; the actor must paint in that layer. It renders the frame's style inline, on the server too; while the actor is absent, it keeps its place in flow, hidden. It owns nothing: the actor's element is its view's, and a view binds a node of its own markup with `refs`.
actor
.h2: React.FC<ActorTagProps<"h2">>h2>
<
const InLayer: ({ layer, children }: Readonly<{
    layer: LayerAddress;
    children?: React.ReactNode;
}>) => JSX.Element | null
Places its markup in the DOM layer `layer` addresses, a layer of the build the enclosing `SceneRenderer` renders: `<InLayer layer={compiled.layers.ui}>`, or a composition's `compiled.layersOf(scene).ui`. Anywhere in the page markup outside an actor's view, through any component, its markup renders in that layer's host (`PageContent`); markup with no address renders in the scene's first DOM layer. Nothing renders while the layer is not on stage. A changed address moves the markup; one of another build throws as it renders. Moved markup renders under the addressed layer's host, so a React context provided between `SceneRenderer` and the `InLayer` does not reach it.
InLayer
layer: LayerAddresslayer={
const compiled: CompiledScene<{
    lead: Label;
    badge: Label;
}, CompiledLayersOf<{
    readonly page: SceneLayer<BackendRef<"dom">>;
    readonly overlay: SceneLayer<BackendRef<"dom">>;
}>>
compiled
.
CompiledScene<{ lead: Label; badge: Label; }, CompiledLayersOf<{ readonly page: SceneLayer<BackendRef<"dom">>; readonly overlay: SceneLayer<BackendRef<"dom">>; }>>.layers: CompiledLayersOf<{
    readonly page: SceneLayer<BackendRef<"dom">>;
    readonly overlay: SceneLayer<BackendRef<"dom">>;
}>
Its scene's declared layers by key: what page markup addresses (`<InLayer layer={compiled.layers.ui}>`). Empty for a scene that declares none. The layers of a scene it stages are `compiled.layersOf(scene)`.
layers
.overlay: CompiledLayer<BackendRef<"dom">>overlay}>
<const actor: ActorTags
Page markup bound to an actor: `<actor.h1 of={compiled.scene.card.title} className="text-6xl">Launch</actor.h1>` renders a heading the scene's DOM layer writes each frame the title moves, with no render of the page. Render it among `SceneRenderer`'s children, which render in the scope of the scene's DOM layer; the actor must paint in that layer. It renders the frame's style inline, on the server too; while the actor is absent, it keeps its place in flow, hidden. It owns nothing: the actor's element is its view's, and a view binds a node of its own markup with `refs`.
actor
.p: React.FC<ActorTagProps<"p">>p of: PageBindable
A live handle of the scene's exports: `compiled.scene.card.title`.
of
={
const compiled: CompiledScene<{
    lead: Label;
    badge: Label;
}, CompiledLayersOf<{
    readonly page: SceneLayer<BackendRef<"dom">>;
    readonly overlay: SceneLayer<BackendRef<"dom">>;
}>>
compiled
.
CompiledScene<{ lead: Label; badge: Label; }, CompiledLayersOf<{ readonly page: SceneLayer<BackendRef<"dom">>; readonly overlay: SceneLayer<BackendRef<"dom">>; }>>.scene: {
    lead: Label;
    badge: Label;
}
What the scene's generator returned: its exported actors as the handles it authored with (`compiled.scene.card.title`). After the build they only name their actors: a write or lifecycle call through one throws, and a frame's values are read from `at(frame).scene`. Page markup binds one (`<actor.h1 of={compiled.scene.card.title}>`).
scene
.badge: Labelbadge}>New</const actor: ActorTags
Page markup bound to an actor: `<actor.h1 of={compiled.scene.card.title} className="text-6xl">Launch</actor.h1>` renders a heading the scene's DOM layer writes each frame the title moves, with no render of the page. Render it among `SceneRenderer`'s children, which render in the scope of the scene's DOM layer; the actor must paint in that layer. It renders the frame's style inline, on the server too; while the actor is absent, it keeps its place in flow, hidden. It owns nothing: the actor's element is its view's, and a view binds a node of its own markup with `refs`.
actor
.p: React.FC<ActorTagProps<"p">>p>
</
const InLayer: ({ layer, children }: Readonly<{
    layer: LayerAddress;
    children?: React.ReactNode;
}>) => JSX.Element | null
Places its markup in the DOM layer `layer` addresses, a layer of the build the enclosing `SceneRenderer` renders: `<InLayer layer={compiled.layers.ui}>`, or a composition's `compiled.layersOf(scene).ui`. Anywhere in the page markup outside an actor's view, through any component, its markup renders in that layer's host (`PageContent`); markup with no address renders in the scene's first DOM layer. Nothing renders while the layer is not on stage. A changed address moves the markup; one of another build throws as it renders. Moved markup renders under the addressed layer's host, so a React context provided between `SceneRenderer` and the `InLayer` does not reach it.
InLayer
>
</
const SceneRenderer: <TSceneExports>({ compiled, frame, width, height, sceneMeta, style, children, runtime, }: {
    compiled: CompiledScene<TSceneExports>;
    frame: number;
    width: number;
    height: number;
    sceneMeta?: unknown;
    style?: React.CSSProperties;
    children?: React.ReactNode;
    runtime?: ReactRenderRuntime;
}) => JSX.Element
Frame-passive renderer for a CompiledScene: resolves the frame and paints its layers (`SceneLayers`) on a stage of `width` by `height`. Each layer is painted by the host its backend registers on the runtime; the default layer by the runtime's default backend. `children` are page markup: they render in the scope of the scene's DOM layer, where `<actor.h1 of={compiled.scene.card.title}>` binds a node of it to an actor (`SceneLayers`).
SceneRenderer
>
);

Vue writes <InLayer :layer="compiled.layers.overlay"> in the default slot, and Svelte <InLayer layer={compiled.layers.overlay}>, each from its @motionactor/renderers entry. compiled.layers holds one handle per declared layer, typed by its backend: a layer another backend paints, a key string, or a layer of another build does not pass. An InLayer may sit anywhere in the page markup outside an actor’s view, inside your own components too. Its markup renders in the layer it addresses, and the server renders it there too. Changing its layer moves the markup. In React, context provided between SceneRenderer and an InLayer does not reach the moved markup, so provide it above SceneRenderer. An InLayer inside another layer’s moved markup, or inside an actor’s view, throws.

compiled.layers holds the built scene’s own layers. A staged scene’s, at any depth, come from compiled.layersOf(scene), keyed by the definition staged. Two scenes that declare the same key stay apart, and each handle is typed by its own scene’s backend. The markup renders only while that scene is on stage.

import { const createRenderRuntime: (input: CreateRenderRuntimeInput<ReactBackendHost, React.ReactNode>) => ReactRenderRuntime
The floor's `createRenderRuntime` for React: every backend's host is a React component and its stages wrap React nodes, so mixed backends (each with its own host props) compose without naming a type.
createRenderRuntime
,
const InLayer: ({ layer, children }: Readonly<{
    layer: LayerAddress;
    children?: React.ReactNode;
}>) => JSX.Element | null
Places its markup in the DOM layer `layer` addresses, a layer of the build the enclosing `SceneRenderer` renders: `<InLayer layer={compiled.layers.ui}>`, or a composition's `compiled.layersOf(scene).ui`. Anywhere in the page markup outside an actor's view, through any component, its markup renders in that layer's host (`PageContent`); markup with no address renders in the scene's first DOM layer. Nothing renders while the layer is not on stage. A changed address moves the markup; one of another build throws as it renders. Moved markup renders under the addressed layer's host, so a React context provided between `SceneRenderer` and the `InLayer` does not reach it.
InLayer
,
const SceneRenderer: <TSceneExports>({ compiled, frame, width, height, sceneMeta, style, children, runtime, }: {
    compiled: CompiledScene<TSceneExports>;
    frame: number;
    width: number;
    height: number;
    sceneMeta?: unknown;
    style?: React.CSSProperties;
    children?: React.ReactNode;
    runtime?: ReactRenderRuntime;
}) => JSX.Element
Frame-passive renderer for a CompiledScene: resolves the frame and paints its layers (`SceneLayers`) on a stage of `width` by `height`. Each layer is painted by the host its backend registers on the runtime; the default layer by the runtime's default backend. `children` are page markup: they render in the scope of the scene's DOM layer, where `<actor.h1 of={compiled.scene.card.title}>` binds a node of it to an actor (`SceneLayers`).
SceneRenderer
} from "@motionactor/renderers/react";
import { const actor: ActorTags
Page markup bound to an actor: `<actor.h1 of={compiled.scene.card.title} className="text-6xl">Launch</actor.h1>` renders a heading the scene's DOM layer writes each frame the title moves, with no render of the page. Render it among `SceneRenderer`'s children, which render in the scope of the scene's DOM layer; the actor must paint in that layer. It renders the frame's style inline, on the server too; while the actor is absent, it keeps its place in flow, hidden. It owns nothing: the actor's element is its view's, and a view binds a node of its own markup with `refs`.
actor
, const dom: StagedBackend<FC<ReactBackendHostProps>, "dom", ReactNode>
The React DOM backend, and the `dom` binding code names: `dom.render(Box, …)`, `createRenderRuntime({ backends: [dom] })`.
dom
} from "@motionactor/dom/react";
import {
const compiled: CompiledScene<{
    badge: Label;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
,
const outro: SceneDefinition<Readonly<Record<never, SceneInput>>, {
    readonly overlay: SceneLayer<BackendRef<"dom">>;
}, {
    badge: Label;
}>
outro
} from "./staged.scene";
const const runtime: ReactRenderRuntimeruntime = function createRenderRuntime(input: CreateRenderRuntimeInput<ReactBackendHost, React.ReactNode>): ReactRenderRuntime
The floor's `createRenderRuntime` for React: every backend's host is a React component and its stages wrap React nodes, so mixed backends (each with its own host props) compose without naming a type.
createRenderRuntime
({ backends: readonly AnyBackend<ReactBackendHost, ReactNode>[]backends: [const dom: StagedBackend<FC<ReactBackendHostProps>, "dom", ReactNode>
The React DOM backend, and the `dom` binding code names: `dom.render(Box, …)`, `createRenderRuntime({ backends: [dom] })`.
dom
], renderers?: readonly RendererRegistryEntry[] | undefined
Family and project renderers, for any backend. Each routes to the backend it names (`three.render(…)`); one naming a backend missing from `backends` throws.
renderers
: [] });
const const Overlay: () => JSX.ElementOverlay = () => ( <
const InLayer: ({ layer, children }: Readonly<{
    layer: LayerAddress;
    children?: React.ReactNode;
}>) => JSX.Element | null
Places its markup in the DOM layer `layer` addresses, a layer of the build the enclosing `SceneRenderer` renders: `<InLayer layer={compiled.layers.ui}>`, or a composition's `compiled.layersOf(scene).ui`. Anywhere in the page markup outside an actor's view, through any component, its markup renders in that layer's host (`PageContent`); markup with no address renders in the scene's first DOM layer. Nothing renders while the layer is not on stage. A changed address moves the markup; one of another build throws as it renders. Moved markup renders under the addressed layer's host, so a React context provided between `SceneRenderer` and the `InLayer` does not reach it.
InLayer
layer: LayerAddresslayer={
const compiled: CompiledScene<{
    badge: Label;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
.
CompiledScene<{ badge: Label; }, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>.layersOf<{
    readonly overlay: SceneLayer<BackendRef<"dom">>;
}>(scene: {
    readonly __motionactorKind: "scene-definition";
    readonly layers: {
        readonly overlay: SceneLayer<BackendRef<"dom">>;
    };
}): CompiledLayersOf<{
    readonly overlay: SceneLayer<BackendRef<"dom">>;
}>
The build's handles on the layers `scene` declares, keyed like its declaration and typed by each backend: `<InLayer layer={compiled.layersOf(outro).overlay}>`. Handles belong to the definition: a scene staged twice keeps its handles, each in force at its own frames. `layersOf(built)` is `compiled.layers`. Throws for a scene the build did not stage.
layersOf
(
const outro: SceneDefinition<Readonly<Record<never, SceneInput>>, {
    readonly overlay: SceneLayer<BackendRef<"dom">>;
}, {
    badge: Label;
}>
outro
).overlay: CompiledLayer<BackendRef<"dom">>overlay}>
<const actor: ActorTags
Page markup bound to an actor: `<actor.h1 of={compiled.scene.card.title} className="text-6xl">Launch</actor.h1>` renders a heading the scene's DOM layer writes each frame the title moves, with no render of the page. Render it among `SceneRenderer`'s children, which render in the scope of the scene's DOM layer; the actor must paint in that layer. It renders the frame's style inline, on the server too; while the actor is absent, it keeps its place in flow, hidden. It owns nothing: the actor's element is its view's, and a view binds a node of its own markup with `refs`.
actor
.p: FC<ActorTagProps<"p">>p of: PageBindable
A live handle of the scene's exports: `compiled.scene.card.title`.
of
={
const compiled: CompiledScene<{
    badge: Label;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
.
CompiledScene<{ badge: Label; }, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>.scene: {
    badge: Label;
}
What the scene's generator returned: its exported actors as the handles it authored with (`compiled.scene.card.title`). After the build they only name their actors: a write or lifecycle call through one throws, and a frame's values are read from `at(frame).scene`. Page markup binds one (`<actor.h1 of={compiled.scene.card.title}>`).
scene
.badge: Labelbadge}>New</const actor: ActorTags
Page markup bound to an actor: `<actor.h1 of={compiled.scene.card.title} className="text-6xl">Launch</actor.h1>` renders a heading the scene's DOM layer writes each frame the title moves, with no render of the page. Render it among `SceneRenderer`'s children, which render in the scope of the scene's DOM layer; the actor must paint in that layer. It renders the frame's style inline, on the server too; while the actor is absent, it keeps its place in flow, hidden. It owns nothing: the actor's element is its view's, and a view binds a node of its own markup with `refs`.
actor
.p: FC<ActorTagProps<"p">>p>
</
const InLayer: ({ layer, children }: Readonly<{
    layer: LayerAddress;
    children?: React.ReactNode;
}>) => JSX.Element | null
Places its markup in the DOM layer `layer` addresses, a layer of the build the enclosing `SceneRenderer` renders: `<InLayer layer={compiled.layers.ui}>`, or a composition's `compiled.layersOf(scene).ui`. Anywhere in the page markup outside an actor's view, through any component, its markup renders in that layer's host (`PageContent`); markup with no address renders in the scene's first DOM layer. Nothing renders while the layer is not on stage. A changed address moves the markup; one of another build throws as it renders. Moved markup renders under the addressed layer's host, so a React context provided between `SceneRenderer` and the `InLayer` does not reach it.
InLayer
>
); export const
const Stage: ({ frame }: {
    frame: number;
}) => JSX.Element
Stage
= ({ frame: numberframe }: { frame: numberframe: number }) => (
<
const SceneRenderer: <TSceneExports>({ compiled, frame, width, height, sceneMeta, style, children, runtime, }: {
    compiled: CompiledScene<TSceneExports>;
    frame: number;
    width: number;
    height: number;
    sceneMeta?: unknown;
    style?: React.CSSProperties;
    children?: React.ReactNode;
    runtime?: ReactRenderRuntime;
}) => JSX.Element
Frame-passive renderer for a CompiledScene: resolves the frame and paints its layers (`SceneLayers`) on a stage of `width` by `height`. Each layer is painted by the host its backend registers on the runtime; the default layer by the runtime's default backend. `children` are page markup: they render in the scope of the scene's DOM layer, where `<actor.h1 of={compiled.scene.card.title}>` binds a node of it to an actor (`SceneLayers`).
SceneRenderer
compiled: CompiledScene<{
    badge: Label;
}, Readonly<Record<string, CompiledLayer<BackendRef<string>>>>>
compiled
={
const compiled: CompiledScene<{
    badge: Label;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
} frame: numberframe={frame: numberframe} width: numberwidth={1280} height: numberheight={720} runtime?: ReactRenderRuntime | undefinedruntime={const runtime: ReactRenderRuntimeruntime}>
<JSX.IntrinsicElements.section: DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>section> <const Overlay: () => JSX.ElementOverlay /> </JSX.IntrinsicElements.section: DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>section> </
const SceneRenderer: <TSceneExports>({ compiled, frame, width, height, sceneMeta, style, children, runtime, }: {
    compiled: CompiledScene<TSceneExports>;
    frame: number;
    width: number;
    height: number;
    sceneMeta?: unknown;
    style?: React.CSSProperties;
    children?: React.ReactNode;
    runtime?: ReactRenderRuntime;
}) => JSX.Element
Frame-passive renderer for a CompiledScene: resolves the frame and paints its layers (`SceneLayers`) on a stage of `width` by `height`. Each layer is painted by the host its backend registers on the runtime; the default layer by the runtime's default backend. `children` are page markup: they render in the scope of the scene's DOM layer, where `<actor.h1 of={compiled.scene.card.title}>` binds a node of it to an actor (`SceneLayers`).
SceneRenderer
>
);

An actor.<tag> is checked as it binds, before its actor spawns and on the server too. It throws, naming the actor, outside any SceneRenderer; for a handle of another build, even one whose id this build shares; and for an actor that paints in a layer other than the markup’s. For that last case, wrap the markup in its layer’s InLayer, spawn the actor through the markup’s layer, or bind it from a view. Whether the actor is present only shows or hides the node. It owns nothing: the actor’s element, if it has one, is still its view’s.

A render method on the class

A DOM actor can carry its own render method instead of a separate renderer. The DOM backend paints it with no registration, and a registered renderer for the class still takes precedence. Inside it, this.<signal>() reads the signal’s value at the frame being drawn.

import { class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor, 
function signal<T>(): RequiredSignal<T> (+1 overload)
module signal
A timeline value on an actor, and an input to every spawn of it. Without an initial value the signal is required: `ctx.spawn` must supply it.
signal
} from "@motionactor/core";
export class class NoteNote extends class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor { Note.text: ActorFieldSignal<string>text = signal<string>(initial: string): ActorFieldSignal<string> (+1 overload)
A timeline value on an actor, and an input to every spawn of it. Without an initial value the signal is required: `ctx.spawn` must supply it.
signal
("");
Note.render(this: {
    text(): string;
}): JSX.Element
render
(
this: {
    text(): string;
}
this
: { function text(): stringtext(): string }) {
return <React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>p React.HTMLAttributes<HTMLParagraphElement>.className?: string | undefinedclassName="note">{this.function text(): stringtext()}</React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>p>; } }

A class with a render method counts as a DOM renderer when a layer decides what it can paint, so spawn it into a DOM layer.

Was this page helpful?