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

group

Names a set of fields, so an actor reads card.typography.size and spawns with nested inputs.

group puts fields under one name. The fields inside stay what they were: signals, derived values, channels or other groups. A group adds a level to the path and nothing else, so it changes how a value is read and spawned and never how it animates.

import { function group<T extends Record<string, unknown>>(value: T): T & SignalGroupDefinitiongroup, 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 CardCard extends class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor {
Card.typography: {
    size: ActorFieldSignal<number>;
    color: ActorFieldSignal<string>;
    shadow: {
        blur: ActorFieldSignal<number>;
    } & SignalGroupDefinition;
} & SignalGroupDefinition
typography
=
group<{
    size: ActorFieldSignal<number>;
    color: ActorFieldSignal<string>;
    shadow: {
        blur: ActorFieldSignal<number>;
    } & SignalGroupDefinition;
}>(value: {
    size: ActorFieldSignal<number>;
    color: ActorFieldSignal<string>;
    shadow: {
        blur: ActorFieldSignal<number>;
    } & SignalGroupDefinition;
}): {
    size: ActorFieldSignal<number>;
    color: ActorFieldSignal<string>;
    shadow: {
        blur: ActorFieldSignal<number>;
    } & SignalGroupDefinition;
} & SignalGroupDefinition
group
({
size: ActorFieldSignal<number>size: 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
(48),
color: ActorFieldSignal<string>color: 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
("#ffffff"),
shadow: {
    blur: ActorFieldSignal<number>;
} & SignalGroupDefinition
shadow
:
group<{
    blur: ActorFieldSignal<number>;
}>(value: {
    blur: ActorFieldSignal<number>;
}): {
    blur: ActorFieldSignal<number>;
} & SignalGroupDefinition
group
({ blur: ActorFieldSignal<number>blur: 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) }),
}); }
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
} from "@motionactor/core";
import { class CardCard } from "./card"; 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?: {
    typography?: {
        size?: SignalInputValue<number> | undefined;
        color?: SignalInputValue<string> | undefined;
        shadow?: {
            blur?: SignalInputValue<number> | undefined;
        } | undefined;
    } | undefined;
    measuredBox?: undefined;
    layout?: {
        x?: SignalInputValue<LayoutValue> | undefined;
        y?: SignalInputValue<LayoutValue> | undefined;
        width?: Readonly<{
            kind: "layout.percent";
            value: number;
        }> | SignalInputValue<...> | undefined;
        height?: Readonly<...> | ... 1 more ... | undefined;
    } | undefined;
    ... 20 more ...;
    parent?: undefined;
} | undefined, options?: {
    ...;
} | undefined): Card (+1 overload)
spawn
(class CardCard, {
typography?: {
    size?: SignalInputValue<number> | undefined;
    color?: SignalInputValue<string> | undefined;
    shadow?: {
        blur?: SignalInputValue<number> | undefined;
    } | undefined;
} | undefined
typography
: { size?: SignalInputValue<number> | undefinedsize: 64,
shadow?: {
    blur?: SignalInputValue<number> | undefined;
} | undefined
shadow
: { blur?: SignalInputValue<number> | undefinedblur: 8 } },
}); yield* const card: Cardcard.
Card.typography: {
    size: ActorFieldSignal<number>;
    color: ActorFieldSignal<string>;
    shadow: {
        blur: ActorFieldSignal<number>;
    } & SignalGroupDefinition;
} & SignalGroupDefinition
typography
.
shadow: {
    blur: ActorFieldSignal<number>;
} & SignalGroupDefinition
shadow
.blur: ActorFieldSignal<number>blur.LiveSignal<number>.tween(target: number, options: number | SignalTweenOptions<number>): Generator<Frame, void, unknown>
Tween to target over authored seconds — must yield*
tween
(0, 0.5);
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 });
const 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?.
typography: {
    size: number;
    color: string;
    shadow: {
        blur: number;
    };
} | undefined
typography
;
// { size: 64, color: "#ffffff", shadow: { blur: 8 } }

Spawn inputs nest the same way. Fields left out keep their defaults, so color stays white. In reflection and editors each field has its dotted path, such as typography.shadow.blur.

A subclass inherits its parent’s groups. Redeclaring a group in a subclass replaces the whole group, so restate every field it keeps.

The groups every LayoutActor has

Group Fields
layout x, y, width, height
transform scale, rotation (degrees)
appearance opacity
compositing blend, isolate, clip
flexItem alignSelf
gridItem gridColumn, gridRow

LayoutActor covers what each one does.

layoutGroup

layoutGroup(overrides) builds the layout group with new defaults. Redeclare layout with it to change an actor’s default box without restating the axes you leave alone:

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 layoutGroup(overrides?: LayoutGroupOverrides): {
    x: ActorFieldSignal<LayoutValue>;
    y: ActorFieldSignal<LayoutValue>;
    width: TypedFieldSignal<number | `${number}%` | Readonly<{
        kind: "layout.percent";
        value: number;
    }>, number | `${number}%` | Readonly<{
        kind: "layout.percent";
        value: number;
    }>>;
    height: TypedFieldSignal<number | `${number}%` | Readonly<{
        kind: "layout.percent";
        value: number;
    }>, number | `${number}%` | Readonly<...>>;
} & SignalGroupDefinition
The canonical `layout` group: x/y/width/height signals with defaults filled in. Subclasses of `LayoutActor` redeclare `layout = layoutGroup({...})` to override defaults without restating the untouched axes.
layoutGroup
} from "@motionactor/core";
class class ThumbnailThumbnail extends class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor {
Thumbnail.layout: {
    x: ActorFieldSignal<LayoutValue>;
    y: ActorFieldSignal<LayoutValue>;
    width: TypedFieldSignal<number | `${number}%` | Readonly<{
        kind: "layout.percent";
        value: number;
    }>, number | `${number}%` | Readonly<{
        kind: "layout.percent";
        value: number;
    }>>;
    height: TypedFieldSignal<number | `${number}%` | Readonly<{
        kind: "layout.percent";
        value: number;
    }>, number | `${number}%` | Readonly<{
        kind: "layout.percent";
        value: number;
    }>>;
} & SignalGroupDefinition
layout
=
function layoutGroup(overrides?: LayoutGroupOverrides): {
    x: ActorFieldSignal<LayoutValue>;
    y: ActorFieldSignal<LayoutValue>;
    width: TypedFieldSignal<number | `${number}%` | Readonly<{
        kind: "layout.percent";
        value: number;
    }>, number | `${number}%` | Readonly<{
        kind: "layout.percent";
        value: number;
    }>>;
    height: TypedFieldSignal<number | `${number}%` | Readonly<{
        kind: "layout.percent";
        value: number;
    }>, number | `${number}%` | Readonly<...>>;
} & SignalGroupDefinition
The canonical `layout` group: x/y/width/height signals with defaults filled in. Subclasses of `LayoutActor` redeclare `layout = layoutGroup({...})` to override defaults without restating the untouched axes.
layoutGroup
({ LayoutGroupOverrides.width?: LayoutValue | undefinedwidth: 320, LayoutGroupOverrides.height?: LayoutValue | undefinedheight: 180 });
} const
const compiled: CompiledScene<{
    thumb: Thumbnail;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
=
createScene<{
    thumb: Thumbnail;
}, Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>>(script: SceneScript<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, {
    thumb: Thumbnail;
}>, 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 thumb: Thumbnailthumb = ctx: SceneContextctx.
CompileContext.spawn<Thumbnail>(definition: ActorClass<Thumbnail>, overrides?: {
    transform?: {
        scale?: SignalInputValue<number> | undefined;
        rotation?: SignalInputValue<number> | undefined;
    } | undefined;
    id?: undefined;
    measuredBox?: undefined;
    layout?: {
        x?: SignalInputValue<LayoutValue> | undefined;
        y?: SignalInputValue<LayoutValue> | undefined;
        width?: Readonly<{
            kind: "layout.percent";
            value: number;
        }> | SignalInputValue<number | `${number}%` | Readonly<...>> | undefined;
        height?: Readonly<...> | ... 1 more ... | undefined;
    } | undefined;
    ... 18 more ...;
    parent?: undefined;
} | undefined, options?: {
    ...;
} | undefined): Thumbnail (+1 overload)
spawn
(class ThumbnailThumbnail, {
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<{
        kind: "layout.percent";
        value: number;
    }>> | undefined;
} | undefined
layout
: { x?: SignalInputValue<LayoutValue> | undefinedx: "50%" } });
return { thumb: Thumbnailthumb }; }).
SceneDefinition<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, { ...; }>.build(args: SceneBuildInput<Readonly<Record<never, SceneInput>>>): CompiledScene<{
    thumb: Thumbnail;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
build
({ viewport: SceneViewportviewport: { SceneViewport.width: numberwidth: 1920, SceneViewport.height: numberheight: 1080 }, fps: numberfps: 30 });
const compiled: CompiledScene<{
    thumb: Thumbnail;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled
.
CompiledScene<{ ...; }, CompiledLayersOf<...>>.at(frame: Frame, options?: FrameResolutionOptions): FrameState<{
    thumb: Thumbnail;
}>
at
(0).
FrameState<{ ...; }>.scene: {
    thumb: ResolvedActorOfInstance<Thumbnail> | undefined;
}
scene
.thumb: ResolvedActorOfInstance<Thumbnail> | undefinedthumb?.
layout: {
    x: LayoutValue;
    y: LayoutValue;
    width: number | `${number}%` | Readonly<{
        kind: "layout.percent";
        value: number;
    }>;
    height: number | `${number}%` | Readonly<{
        kind: "layout.percent";
        value: number;
    }>;
} | undefined
layout
;
// { x: "50%", y: 0, width: 320, height: 180 }

A layout value is a number of pixels, a percentage string such as "50%", or pct(50). layout keeps the value as authored. The resolved box, localLayout and worldLayout, is always in pixels, with percentages taken of the host’s box or the scene’s viewport.

Was this page helpful?