@command
Labels a generator method for editors, with its parameters and a default duration, so a timeline can offer it without knowing the class.
Every generator method on an actor is a command a script can call. @command adds what an
editor needs to offer it to a person: a label, the parameters and their kinds, and a default
duration.
import { function command(options: CommandDecoratorOptions): SupportedMethodDecoratorcommand, class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor, type type Duration = numberDuration } from "@motionactor/core";
export class class CardCard extends class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor {
@function command(options: CommandDecoratorOptions): SupportedMethodDecoratorcommand({ CommandDecoratorOptions.label: stringlabel: "Reveal", CommandDecoratorOptions.duration?: CommandDurationMetadata | undefinedduration: { CommandDurationMetadata.default?: number | undefineddefault: 0.4 } })
*Card.reveal(duration?: Duration): Generator<number, void, unknown>reveal(duration: numberduration: type Duration = numberDuration = 0.4) {
yield* this.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, duration: numberduration);
}
@function command(options: CommandDecoratorOptions): SupportedMethodDecoratorcommand({
CommandDecoratorOptions.label: stringlabel: "Move to",
CommandDecoratorOptions.params?: Record<string, CommandParameterMetadata> | undefinedparams: {
x: {
kind: "number";
label: string;
}
x: { CommandParameterMetadata.kind: CommandParameterKindkind: "number", CommandParameterMetadata.label?: string | undefinedlabel: "X" },
y: {
kind: "number";
label: string;
}
y: { CommandParameterMetadata.kind: CommandParameterKindkind: "number", CommandParameterMetadata.label?: string | undefinedlabel: "Y" },
},
CommandDecoratorOptions.duration?: CommandDurationMetadata | undefinedduration: { CommandDurationMetadata.default?: number | undefineddefault: 0.6 },
})
*Card.moveTo({ x, y }: {
x: number;
y: number;
}, duration?: Duration): Generator<number, void, unknown>
moveTo({ x: numberx, y: numbery }: { x: numberx: number; y: numbery: number }, duration: numberduration: type Duration = numberDuration = 0.6) {
yield* this.Actor<{}>.runtime: ActorRuntimeOrchestration<this>runtime.ActorRuntimeOrchestration<this>.all(...generators: Generator<Frame, unknown, unknown>[]): Generator<Frame, void, unknown>all(
this.LayoutActor<{}>.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.x: ActorFieldSignal<LayoutValue>x.LiveSignal<LayoutValue>.tween(target: LayoutValue, options: number | SignalTweenOptions<LayoutValue>): Generator<Frame, void, unknown>Tween to target over authored seconds — must yield*tween(x: numberx, duration: numberduration),
this.LayoutActor<{}>.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.y: ActorFieldSignal<LayoutValue>y.LiveSignal<LayoutValue>.tween(target: LayoutValue, options: number | SignalTweenOptions<LayoutValue>): Generator<Frame, void, unknown>Tween to target over authored seconds — must yield*tween(y: numbery, duration: numberduration),
);
}
}
A decorated command takes one of two shapes. Without params, its only argument is the
duration. With params, it takes an object of those parameters first and the duration
second, and calling it with anything but an object first throws.
Options
| Option | |
|---|---|
label |
The name an editor shows. Required |
params |
Per parameter: kind, and optional label, description, options and fields |
duration |
default, and optional label and description |
A parameter’s kind is "string", "number", "boolean", "color", "enum" (with
options), "object" (with nested fields, for a point such as { x, y }) or "json".
duration.default is what an editor fills in. A script that calls the method gets the
method’s own default, so keep the two the same.
Reading it
Reflection lists an actor’s decorated commands, sorted by name:
import { function reflectBlueprint(definition: ActorClass<object>): ReflectedBlueprintReflect what a blueprint declares without spawning it: every input field
with its declared type, whether spawn requires it, and its default. The
pre-spawn read an editor needs before it can offer required values.reflectBlueprint } from "@motionactor/core";
import { class CardCard } from "./card";
function reflectBlueprint(definition: ActorClass<object>): ReflectedBlueprintReflect what a blueprint declares without spawning it: every input field
with its declared type, whether spawn requires it, and its default. The
pre-spawn read an editor needs before it can offer required values.reflectBlueprint(class CardCard).ReflectedBlueprint.commands: ReflectedCommand[]commands.Array<ReflectedCommand>.map<string>(callbackfn: (value: ReflectedCommand, index: number, array: ReflectedCommand[]) => string, thisArg?: any): string[]Calls a defined callback function on each element of an array, and returns an array that contains the results.map((c: ReflectedCommandc) => c: ReflectedCommandc.ReflectedCommand.label: stringlabel);
// ["Move to", "Reveal"]
compiled.reflect(frame) gives the same list for each spawned actor. Undecorated generator
methods still work from code. They are left out of the list because an editor would have
nothing to label them with.