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

Compiled scenes

Turning a frame number into state, finding actors in it, caching it and reflecting it for editors.

A compiled scene is the record a scene script wrote: what its actors did and when. scene holds what the script returned: the actor objects it authored with, which after the build only identify their actors. A write or a lifecycle call on one throws, and its build owns it, so a renderer binds it only against that build (actor.<tag> of={…}). at(frame) replays the record to the frame you ask for and returns a FrameState, whose state.scene holds snapshots of the same actors at that frame: their values, but no handle.

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
} from "@motionactor/core";
export class class TitleTitle extends class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor { static Title.type: stringtype = "title"; Title.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
("");
} export const
const compiled: CompiledScene<{
    title: Title;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
=
createScene<{
    title: Title;
}, Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>>(script: SceneScript<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, {
    title: Title;
}>, 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 title: Titletitle = ctx: SceneContextctx.
CompileContext.spawn<Title>(definition: ActorClass<Title>, overrides?: {
    measuredBox?: undefined;
    text?: SignalInputValue<string> | undefined;
    appearance?: {
        opacity?: SignalInputValue<number> | undefined;
    } | undefined;
    id?: undefined;
    layout?: {
        x?: SignalInputValue<LayoutValue> | undefined;
        y?: SignalInputValue<LayoutValue> | undefined;
        width?: Readonly<{
            kind: "layout.percent";
            value: number;
        }> | SignalInputValue<number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>> | undefined;
        height?: Readonly<...> | ... 1 more ... | undefined;
    } | undefined;
    ... 18 more ...;
    parent?: undefined;
} | undefined, options?: {
    ...;
} | undefined): Title (+1 overload)
spawn
(
class TitleTitle, { text?: SignalInputValue<string> | undefinedtext: "Launch day",
appearance?: {
    opacity?: SignalInputValue<number> | undefined;
} | undefined
appearance
: { opacity?: SignalInputValue<number> | undefinedopacity: 0 } },
{ id?: string | undefinedid: "title" }, ); yield* const title: Titletitle.
LayoutActor<{}>.appearance: {
    opacity: TypedFieldSignal<number, number>;
} & SignalGroupDefinition
appearance
.opacity: TypedFieldSignal<number, number>opacity.function tween(target: number, options: number | SignalTweenOptions<number>): Generator<Frame, void, unknown>
Tween to target over authored seconds — must yield*
tween
(1, 0.5);
yield* ctx: SceneContextctx.CompileContext.wait(duration: Duration): Generator<Frame, void, unknown>wait(1); return { title: Titletitle }; }).
SceneDefinition<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, { ...; }>.build(args: SceneBuildInput<Readonly<Record<never, SceneInput>>>): CompiledScene<{
    title: Title;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
build
({ viewport: SceneViewportviewport: { SceneViewport.width: numberwidth: 1920, SceneViewport.height: numberheight: 1080 }, fps: numberfps: 30 });
const compiled: CompiledScene<{
    title: Title;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
.CompiledScene<{ ...; }, CompiledLayersOf<...>>.fps: numberfps; // 30
const compiled: CompiledScene<{
    title: Title;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
.CompiledScene<{ ...; }, CompiledLayersOf<...>>.totalDuration: numbertotalDuration; // 45
const
const state: FrameState<{
    title: Title;
}>
state
=
const compiled: CompiledScene<{
    title: Title;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
.
CompiledScene<{ ...; }, CompiledLayersOf<...>>.at(frame: Frame, options?: FrameResolutionOptions): FrameState<{
    title: Title;
}>
at
(30);
const state: FrameState<{
    title: Title;
}>
state
.
FrameState<{ ...; }>.scene: {
    title: ResolvedActorOfInstance<Title> | undefined;
}
scene
.title: ResolvedActorOfInstance<Title> | undefinedtitle?.text: string | undefinedtext; // "Launch day"
const state: FrameState<{
    title: Title;
}>
state
.FrameState<{ ...; }>.camera: Camera2DState
2D scene camera. Identity when no spawned actor's class declares `SCENE_CAMERA`.
camera
.Camera2DState.zoom: numberzoom; // 1
CompiledScene
fps Frames per second the scene compiled at
totalDuration Length in frames
at(frame, options?) The FrameState at that frame
scene What the script returned, as the build’s actor handles: page markup binds one (page bindings)
layers One handle per declared layer, typed by its backend: page markup addresses one with InLayer
layersOf(scene) The handles on a staged scene’s layers, by the definition staged, at any depth
placements Every staged scene at any depth, stager first: path, parentPath, depth, startFrame, endFrame
reflect(frame?, options?) The frame’s actors described for an editor
events, operations The raw record, for tools
cells The build’s publications, for a host: subscribe(fn) and version() move when one changes, resetRun() starts a new run
[Symbol.dispose]() Releases the build; see below

A frame past the end resolves to the final state, so a host that overshoots shows the last frame. A frame before 0 resolves with no actors.

Frame state

FrameState
frame The frame it resolves
scene The scene’s exports, each actor resolved
actors Every live actor, as a Map from id
layers The frame’s layers in paint order
camera centerX, centerY, zoom, rotation, originX, originY

An actor that has not spawned yet, or has despawned, is absent from actors and resolves to undefined in scene.

camera comes from the scene’s camera actor, such as Camera2D, and is identity when there is none.

Looking up actors

The scene’s exports are the typed way in. For an actor the scene did not return, look it up by class. The class carries the type, so the result needs no cast, and a subclass instance matches too:

import { 
const compiled: CompiledScene<{
    title: Title;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
, class TitleTitle } from "./title.scene";
const
const state: FrameState<{
    title: Title;
}>
state
=
const compiled: CompiledScene<{
    title: Title;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
.
CompiledScene<{ title: Title; }, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>.at(frame: Frame, options?: FrameResolutionOptions): FrameState<{
    title: Title;
}>
at
(30);
const state: FrameState<{
    title: Title;
}>
state
.
FrameState<{ title: Title; }>.findActor<typeof Title>(blueprint: typeof Title): (Omit<ResolvedActor, "signals" | "channels"> & {
    text: string;
    appearance: {
        opacity: number;
    };
    measuredBox: Rect | undefined;
    layout: {
        x: LayoutValue;
        y: LayoutValue;
        width: number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>;
        height: number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>;
    };
    transform: {
        scale: number;
        rotation: number;
    };
    shape: {
        radius: number;
    };
    compositing: {
        blend: "source-over" | "multiply" | ... 14 more ... | "plus-lighter";
        isolate: boolean;
        clip: number | null;
    };
    flexItem: {
        ...;
    };
    gridItem: {
        ...;
    };
    transitionState: {
        ...;
    };
} & {
    ...;
}) | undefined
findActor
(class TitleTitle)?.text: string | undefinedtext; // first match
const state: FrameState<{
    title: Title;
}>
state
.
FrameState<{ title: Title; }>.findActors<typeof Title>(blueprint: typeof Title): (Omit<ResolvedActor, "signals" | "channels"> & {
    text: string;
    appearance: {
        opacity: number;
    };
    measuredBox: Rect | undefined;
    layout: {
        x: LayoutValue;
        y: LayoutValue;
        width: number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>;
        height: number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>;
    };
    transform: {
        scale: number;
        rotation: number;
    };
    shape: {
        radius: number;
    };
    compositing: {
        blend: "source-over" | "multiply" | ... 14 more ... | "plus-lighter";
        isolate: boolean;
        clip: number | null;
    };
    flexItem: {
        ...;
    };
    gridItem: {
        ...;
    };
    transitionState: {
        ...;
    };
} & {
    ...;
})[]
findActors
(class TitleTitle); // every match
const state: FrameState<{
    title: Title;
}>
state
.
FrameState<{ title: Title; }>.getActor<typeof Title>(id: string, blueprint: typeof Title): (Omit<ResolvedActor, "signals" | "channels"> & {
    text: string;
    appearance: {
        opacity: number;
    };
    measuredBox: Rect | undefined;
    layout: {
        x: LayoutValue;
        y: LayoutValue;
        width: number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>;
        height: number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>;
    };
    transform: {
        scale: number;
        rotation: number;
    };
    shape: {
        radius: number;
    };
    compositing: {
        blend: "source-over" | ... 15 more ... | "plus-lighter";
        isolate: boolean;
        clip: number | null;
    };
    flexItem: {
        ...;
    };
    gridItem: {
        ...;
    };
    transitionState: {
        ...;
    };
} & {
    ...;
}) | undefined
getActor
("title", class TitleTitle); // by id, if it is a Title
const state: FrameState<{
    title: Title;
}>
state
.FrameState<{ title: Title; }>.actor(id: string): ResolvedActor | undefinedactor("title"); // by id, untyped
const state: FrameState<{
    title: Title;
}>
state
.FrameState<{ title: Title; }>.findActorByType(type: string): ResolvedActor | undefined
First actor whose class lineage includes `type` (its `static type` chain, computed from `classCtor`). Matches subclasses, as `findActor` does, for a caller that has the type name and not the class.
findActorByType
("title"); // by static type, untyped

findActorByType matches the static type of the class and its parents. It is for code that has a type name but not the class, such as an inspector.

Resolved actors

Every lookup and export resolves to an actor’s state at the frame. Its fields appear under their own names, typed by the class, beside these:

Key Holds
id, type The actor’s id and its class’s static type
parentId, slotName Its host and the slot it is in; null for a root actor
slotChildren The ids in each of its slots, in hosted order
localLayout, worldLayout Its box relative to its parent and to the stage
compositing Opacity, blend mode, isolation and clip, ready for a backend
effects The effects active on it
layer The id of the layer it paints in: its key, or key#2 when the build declares the key twice; null for the default
spawnFrame, despawnFrame When it entered and left
signals Every field’s value by name, channels included
channels A handle per channel: its value when called, write, unpublish and demand

Values from the host

Percentages resolve against the viewport the scene was built for; a new size is a new build. A value the host measures goes into a channel, written through the resolved actor’s handle:

import {
  
function channel<TValue>(options: {
    readonly default: TValue;
    readonly record?: boolean;
    readonly equals?: (previous: TValue, next: TValue) => boolean;
}): ChannelDefinition<TValue> & {
    readonly hasDefault: true;
    readonly default: TValue;
} (+1 overload)
A channel is a writable, scope-aware cell carrying an actor-channel brand. Declared as an actor field it lives in the spawning build's store (keyed `${actorId}:${name}` by the spawn walk, like a signal); declared free (in `buildScene`, a script, or module top) it keys by its scope, in its build's store or the module's, and is shared by reference. Either way resolution reads it live. The static return type stays `ChannelDefinition<TValue>` so the `isChannelDefinition` predicate is unchanged; at runtime the handle is a live cell.
channel
,
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 derived<TThis, T>(fn: (this: TThis) => T): DerivedDefinition<T, TThis>derived, 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"; class class LabelLabel extends class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor { Label.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
("");
Label.available: ChannelDefinition<number> & {
    readonly hasDefault: true;
    readonly default: number;
}
available
=
channel<number>(options: {
    readonly default: number;
    readonly record?: boolean;
    readonly equals?: ((previous: number, next: number) => boolean) | undefined;
}): ChannelDefinition<number> & {
    readonly hasDefault: true;
    readonly default: number;
} (+1 overload)
A channel is a writable, scope-aware cell carrying an actor-channel brand. Declared as an actor field it lives in the spawning build's store (keyed `${actorId}:${name}` by the spawn walk, like a signal); declared free (in `buildScene`, a script, or module top) it keys by its scope, in its build's store or the module's, and is shared by reference. Either way resolution reads it live. The static return type stays `ChannelDefinition<TValue>` so the `isChannelDefinition` predicate is unchanged; at runtime the handle is a live cell.
channel
({ default: numberdefault: 0 });
Label.fits: DerivedDefinition<boolean, unknown>fits = derived<unknown, boolean>(fn: (this: unknown) => boolean): DerivedDefinition<boolean, unknown>derived(() => this.Label.text: () => stringtext().String.length: number
Returns the length of a String object.
length
* 30 <= this.Label.available: () => numberavailable());
} const
const compiled: CompiledScene<{
    label: Label;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
=
createScene<{
    label: Label;
}, Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>>(script: SceneScript<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, {
    label: Label;
}>, 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 label: Labellabel = ctx: SceneContextctx.
CompileContext.spawn<Label>(definition: ActorClass<Label>, overrides?: {
    measuredBox?: undefined;
    text?: SignalInputValue<string> | undefined;
    id?: undefined;
    available?: undefined;
    fits?: undefined;
    layout?: {
        x?: SignalInputValue<LayoutValue> | undefined;
        y?: SignalInputValue<LayoutValue> | undefined;
        width?: Readonly<{
            kind: "layout.percent";
            value: number;
        }> | SignalInputValue<number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>> | undefined;
        height?: Readonly<...> | ... 1 more ... | undefined;
    } | undefined;
    ... 19 more ...;
    parent?: undefined;
} | undefined, options?: {
    ...;
} | undefined): Label (+1 overload)
spawn
(class LabelLabel, { text?: SignalInputValue<string> | undefinedtext: "Launch day" }, { id?: string | undefinedid: "label" });
yield* ctx: SceneContextctx.CompileContext.wait(duration: Duration): Generator<Frame, void, unknown>wait(1); return { label: Labellabel }; }).
SceneDefinition<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, { ...; }>.build(args: SceneBuildInput<Readonly<Record<never, SceneInput>>>): CompiledScene<{
    label: Label;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
build
({ viewport: SceneViewportviewport: { SceneViewport.width: numberwidth: 1920, SceneViewport.height: numberheight: 1080 }, fps: numberfps: 30 });
const compiled: CompiledScene<{
    label: Label;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
.
CompiledScene<{ ...; }, CompiledLayersOf<...>>.at(frame: Frame, options?: FrameResolutionOptions): FrameState<{
    label: Label;
}>
at
(0).
FrameState<{ ...; }>.scene: {
    label: ResolvedActorOfInstance<Label> | undefined;
}
scene
.label: ResolvedActorOfInstance<Label> | undefinedlabel?.fits: boolean | undefinedfits; // false
const compiled: CompiledScene<{
    label: Label;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
.
CompiledScene<{ ...; }, CompiledLayersOf<...>>.at(frame: Frame, options?: FrameResolutionOptions): FrameState<{
    label: Label;
}>
at
(0).
FrameState<{ ...; }>.scene: {
    label: ResolvedActorOfInstance<Label> | undefined;
}
scene
.label: ResolvedActorOfInstance<Label> | undefinedlabel?.channels: ActorClassChannels<Omit<Label, keyof Actor<any>>>channels.available: ResolvedChannelHandle<number>available.ResolvedChannelHandle<number>.write(value: number, frame?: number): void
Publish `value`. `frame` is the frame the producer's scene host committed; a `record: true` channel files the value under it, so a later seek reads the value observed at that frame. Without one the write is live only.
write
(600);
const compiled: CompiledScene<{
    label: Label;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
.
CompiledScene<{ ...; }, CompiledLayersOf<...>>.at(frame: Frame, options?: FrameResolutionOptions): FrameState<{
    label: Label;
}>
at
(0).
FrameState<{ ...; }>.scene: {
    label: ResolvedActorOfInstance<Label> | undefined;
}
scene
.label: ResolvedActorOfInstance<Label> | undefinedlabel?.fits: boolean | undefinedfits; // true

The publication applies to every later call until it is replaced or removed.

Caching

at keeps each actor’s resolved values and revisits only the actors whose values can have changed: a timeline they read moves, a channel they read is published, or an effect on them is active. An actor that holds is the same object in the next frame, and a repeat of the last frame with nothing due is the same FrameState. frame.resolution counts the actors visited. at(frame, { cache: false }) resolves afresh and keeps nothing.

import { 
const compiled: CompiledScene<{
    title: Title;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
} from "./title.scene";
const compiled: CompiledScene<{
    title: Title;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
.
CompiledScene<{ title: Title; }, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>.at(frame: Frame, options?: FrameResolutionOptions): FrameState<{
    title: Title;
}>
at
(10) ===
const compiled: CompiledScene<{
    title: Title;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
.
CompiledScene<{ title: Title; }, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>.at(frame: Frame, options?: FrameResolutionOptions): FrameState<{
    title: Title;
}>
at
(10); // true
const compiled: CompiledScene<{
    title: Title;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
.
CompiledScene<{ title: Title; }, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>.at(frame: Frame, options?: FrameResolutionOptions): FrameState<{
    title: Title;
}>
at
(11).FrameState<{ title: Title; }>.resolution: FrameResolution
How this frame was resolved: the actors visited, of the live ones.
resolution
; // { visited: 1, actors: 1 }
const compiled: CompiledScene<{
    title: Title;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
.
CompiledScene<{ title: Title; }, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>.at(frame: Frame, options?: FrameResolutionOptions): FrameState<{
    title: Title;
}>
at
(10, { FrameResolutionOptions.cache?: false | undefined
`false` resolves the frame afresh: nothing is reused from earlier calls and nothing is kept for later ones. The frame equals a cached call's.
cache
: false }) ===
const compiled: CompiledScene<{
    title: Title;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
.
CompiledScene<{ title: Title; }, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>.at(frame: Frame, options?: FrameResolutionOptions): FrameState<{
    title: Title;
}>
at
(10); // false

Reflection

reflect(frame) describes the frame’s actors for an editor that holds no classes: each one’s fields with their current values, its groups and its commands.

import { 
const compiled: CompiledScene<{
    title: Title;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
} from "./title.scene";
const const title: ReflectedActor | nulltitle =
const compiled: CompiledScene<{
    title: Title;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
.CompiledScene<{ title: Title; }, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>.reflect(frame?: Frame, options?: FrameResolutionOptions): SceneReflectionreflect(15).SceneReflection.getActor(id: string): ReflectedActor | nullgetActor("title");
const title: ReflectedActor | nulltitle?.ReflectedActor.groups: ReflectedGroup[]groups.Array<ReflectedGroup>.map<U>(callbackfn: (value: ReflectedGroup, index: number, array: ReflectedGroup[]) => U, thisArg?: any): U[]
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
((group: ReflectedGroupgroup) => group: ReflectedGroupgroup.ReflectedGroup.key: stringkey);
// ["appearance", "compositing", "flexItem", "gridItem", // "layout", "transform", "transitionState"] const title: ReflectedActor | nulltitle?.ReflectedActor.fields: ReflectedField[]fields.Array<ReflectedField>.find<S>(predicate: (value: ReflectedField, index: number, obj: ReflectedField[]) => value is S, thisArg?: any): S | undefined (+1 overload)
Returns the value of the first element in the array where predicate is true, and undefined otherwise.
@parampredicate find calls predicate once for each element of the array, in ascending order, until it finds one where predicate returns true. If such an element is found, find immediately returns that element value. Otherwise, find returns undefined.@paramthisArg If provided, it will be used as the this value for each invocation of predicate. If it is not provided, undefined is used instead.
find
((field: ReflectedFieldfield) => field: ReflectedFieldfield.ReflectedField.path: stringpath === "text")?.ReflectedField.currentValue: unknowncurrentValue;
// "Launch day"

reflectActor(Class, overrides) reflects one actor without a scene, and reflectBlueprint(Class) reflects a class before anything spawns it. Commands and their parameters come from @command.

Releasing a build

A compiled scene owns its cells: their values, publications and recorded frames. Disposing it releases them:

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 } from "@motionactor/core";
class class CardCard extends class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor {} { using
using 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?: {
    measuredBox?: undefined;
    layout?: {
        x?: SignalInputValue<LayoutValue> | undefined;
        y?: SignalInputValue<LayoutValue> | undefined;
        width?: Readonly<{
            kind: "layout.percent";
            value: number;
        }> | SignalInputValue<number | `${number}%` | Readonly<{
            kind: "layout.percent";
            value: number;
        }>> | undefined;
        height?: Readonly<{
            kind: "layout.percent";
            value: number;
        }> | SignalInputValue<number | `${number}%` | Readonly<...>> | undefined;
    } | undefined;
    ... 20 more ...;
    parent?: undefined;
} | undefined, options?: {
    ...;
} | undefined): Card (+1 overload)
spawn
(class CardCard);
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 });
using compiled: CompiledScene<{
    card: Card;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
.
CompiledScene<{ ...; }, CompiledLayersOf<...>>.at(frame: Frame, options?: FrameResolutionOptions): FrameState<{
    card: Card;
}>
at
(0).
FrameState<{ ...; }>.scene: {
    card: ResolvedActorOfInstance<Card> | undefined;
}
scene
.card: ResolvedActorOfInstance<Card> | undefinedcard?.
layout: {
    x: LayoutValue;
    y: LayoutValue;
    width: number | `${number}%` | Readonly<{
        kind: "layout.percent";
        value: number;
    }>;
    height: number | `${number}%` | Readonly<{
        kind: "layout.percent";
        value: number;
    }>;
}
layout
.x: LayoutValue | undefinedx; // 0
} // released here

After that, at throws This compiled scene was disposed: build it again to resolve its frames., and a write through any of its handles throws. Outside a block, call compiled[Symbol.dispose](). A composition build is disposed the same way.

Was this page helpful?