Children
A child is a part every instance of an actor has, spawned with it and able to read it.
child(Class, overrides) declares an actor that spawns with its owner and lives as long as
it does. The field name is its place in the owner. Use a child for a part of the class, such
as a phone’s status bar or a card’s caption, and a slot for contents the
user of the class decides.
import { function child<TBlueprint extends ActorClass<object>, TOwner extends object = object>(blueprint: TBlueprint, ...[overrides]: ChildOverridesArg<TBlueprint, TOwner>): ChildField<TBlueprint, TOwner>child, 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 StatusBarStatusBar extends class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor {
StatusBar.carrier: ActorFieldSignal<string>carrier = 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("");
StatusBar.battery: ActorFieldSignal<number>battery = 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(100);
}
export class class PhonePhone extends class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor {
Phone.name: ActorFieldSignal<string>name = 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("Pixel");
Phone.status: ChildField<typeof StatusBar, Phone>status = child<typeof StatusBar, Phone>(blueprint: typeof StatusBar, overrides?: ChildOverrides<typeof StatusBar, Phone> | undefined): ChildField<typeof StatusBar, Phone>child(class StatusBarStatusBar, (owner: Phoneowner: class PhonePhone) => ({
carrier?: SignalInputValue<string> | undefinedcarrier: derived<any, string>(fn: (this: any) => string): DerivedDefinition<string, any>derived(() => `${owner: Phoneowner.Phone.name: () => stringname()} Mobile`),
battery?: SignalInputValue<number> | undefinedbattery: 82,
}));
}
In a scene script and in the owner’s methods, the field is the child itself:
phone.status.carrier() reads the child’s signal and yield* phone.status.enter() runs its
onEnter.
Overrides
The second argument sets the child’s initial values. It is required when the child’s class has a field with no default, and optional otherwise.
Pass a function instead and it receives the owner, so the child’s values can come from the
owner’s. A derived override keeps reading the owner at every frame. When the scene renames
the phone, the status bar follows:
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 PhonePhone } from "./phone";
const const compiled: CompiledScene<{
phone: Phone;
status: ChildField<typeof StatusBar, Phone>;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled = createScene<{
phone: Phone;
status: ChildField<typeof StatusBar, Phone>;
}, Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>>(script: SceneScript<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, {
phone: Phone;
status: ChildField<typeof StatusBar, Phone>;
}>, options?: SceneDefinitionOptions<...> | 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 phone: Phonephone = ctx: SceneContextctx.CompileContext.spawn<Phone>(definition: ActorClass<Phone>, overrides?: {
measuredBox?: undefined;
name?: SignalInputValue<string> | undefined;
status?: {
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<...> | ... 1 more ... | undefined;
} | undefined;
... 8 more ...;
battery?: SignalInputValue<...> | undefined;
} | undefined;
... 21 more ...;
parent?: undefined;
} | undefined, options?: {
...;
} | undefined): Phone (+1 overload)
spawn(class PhonePhone);
yield* ctx: SceneContextctx.CompileContext.wait(duration: Duration): Generator<Frame, void, unknown>wait(1);
const phone: Phonephone.Phone.name: ActorFieldSignal<string>name.LiveSignal<string>.set(value: string): voidSet value instantly at current cursor (no yield needed)set("Galaxy");
yield* ctx: SceneContextctx.CompileContext.wait(duration: Duration): Generator<Frame, void, unknown>wait(1);
return { phone: Phonephone, status: ChildField<typeof StatusBar, Phone>status: const phone: Phonephone.Phone.status: ChildField<typeof StatusBar, Phone>status };
}).SceneDefinition<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, { ...; }>.build(args: SceneBuildInput<Readonly<Record<never, SceneInput>>>): CompiledScene<{
phone: Phone;
status: ChildField<typeof StatusBar, Phone>;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
build({ viewport: SceneViewportviewport: { SceneViewport.width: numberwidth: 1920, SceneViewport.height: numberheight: 1080 }, fps: numberfps: 30 });
const compiled: CompiledScene<{
phone: Phone;
status: ChildField<typeof StatusBar, Phone>;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled.CompiledScene<{ ...; }, CompiledLayersOf<...>>.at(frame: Frame, options?: FrameResolutionOptions): FrameState<{
phone: Phone;
status: ChildField<typeof StatusBar, Phone>;
}>
at(0).FrameState<{ ...; }>.scene: {
phone: ResolvedActorOfInstance<Phone> | undefined;
status: ResolvedActorOfInstance<StatusBar> | undefined;
}
scene.status: ResolvedActorOfInstance<StatusBar> | undefinedstatus?.carrier: string | undefinedcarrier; // "Pixel Mobile"
const compiled: CompiledScene<{
phone: Phone;
status: ChildField<typeof StatusBar, Phone>;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled.CompiledScene<{ ...; }, CompiledLayersOf<...>>.at(frame: Frame, options?: FrameResolutionOptions): FrameState<{
phone: Phone;
status: ChildField<typeof StatusBar, Phone>;
}>
at(30).FrameState<{ ...; }>.scene: {
phone: ResolvedActorOfInstance<Phone> | undefined;
status: ResolvedActorOfInstance<StatusBar> | undefined;
}
scene.status: ResolvedActorOfInstance<StatusBar> | undefinedstatus?.carrier: string | undefinedcarrier; // "Galaxy Mobile"
Annotate the owner parameter with the owner’s class, as (owner: Phone) does, so the
function can read its fields.
Reading a child
A resolved actor does not carry its children’s state. Return a child from the scene, as
status is above, to read it typed. Its id is in the owner’s slotChildren under the
field’s name, and the child’s parentId and slotName point back.
Reading the owner
Any hosted actor, a child or a slot’s occupant, can reach its host with this.parent().
Pass a class to get it typed: this.parent(Phone) returns the host when it is a Phone, and
undefined otherwise.
import { function child<TBlueprint extends ActorClass<object>, TOwner extends object = object>(blueprint: TBlueprint, ...[overrides]: ChildOverridesArg<TBlueprint, TOwner>): ChildField<TBlueprint, TOwner>child, 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 BadgeBadge extends class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor {
Badge.label(): numberlabel() {
return this.Actor<{}>.parent<typeof Inbox>(_blueprint: typeof Inbox): Inbox | undefined (+1 overload)parent(class InboxInbox)?.Inbox.unread: () => numberunread() ?? 0;
}
}
class class InboxInbox extends class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor {
Inbox.unread: ActorFieldSignal<number>unread = 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(3);
Inbox.badge: ChildField<typeof Badge, object>badge = child<typeof Badge, object>(blueprint: typeof Badge, overrides?: ChildOverrides<typeof Badge, object> | undefined): ChildField<typeof Badge, object>child(class BadgeBadge);
}
Prefer an owner function when the child only needs values: the dependency is then written where the child is declared, and the child’s class stays free of its owner.