signal
A value the scene writes. set, tween, play, animate, transition and derive record each write at the cursor.
A signal is a field whose value the scene records over time. Call it to read it. Its methods write, and every write is recorded at the cursor, so the value at any frame is whatever the record says at that 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";
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("Ready");
Badge.tone: ActorFieldSignal<"neutral" | "success">tone = signal<"neutral" | "success">(initial: "neutral" | "success"): ActorFieldSignal<"neutral" | "success"> (+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<"neutral" | "success">("neutral");
Badge.count: ActorFieldSignal<number>count = 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 BadgeBadge } from "./status-badge";
const const compiled: CompiledScene<{
badge: Badge;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled = createScene<{
badge: Badge;
}, Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>>(script: SceneScript<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, {
badge: Badge;
}>, 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 badge: Badgebadge = ctx: SceneContextctx.CompileContext.spawn<Badge>(definition: ActorClass<Badge>, overrides?: {
label?: SignalInputValue<string> | undefined;
measuredBox?: undefined;
tone?: SignalInputValue<"neutral" | "success"> | undefined;
count?: SignalInputValue<number> | 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): Badge (+1 overload)
spawn(class BadgeBadge, { label?: SignalInputValue<string> | undefinedlabel: "Go" });
yield* const badge: Badgebadge.Badge.count: ActorFieldSignal<number>count.LiveSignal<number>.tween(target: number, options: number | SignalTweenOptions<number>): Generator<Frame, void, unknown>Tween to target over authored seconds — must yield*tween(100, 1);
const badge: Badgebadge.Badge.label: ActorFieldSignal<string>label.LiveSignal<string>.set(value: string): voidSet value instantly at current cursor (no yield needed)set("Done");
const badge: Badgebadge.Badge.tone: ActorFieldSignal<"neutral" | "success">tone.LiveSignal<"neutral" | "success">.set(value: "neutral" | "success"): voidSet value instantly at current cursor (no yield needed)set("success");
yield* ctx: SceneContextctx.CompileContext.wait(duration: Duration): Generator<Frame, void, unknown>wait(0.5);
return { badge: Badgebadge };
}).SceneDefinition<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, { ...; }>.build(args: SceneBuildInput<Readonly<Record<never, SceneInput>>>): CompiledScene<{
badge: Badge;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
build({ viewport: SceneViewportviewport: { SceneViewport.width: numberwidth: 1920, SceneViewport.height: numberheight: 1080 }, fps: numberfps: 30 });
const compiled: CompiledScene<{
badge: Badge;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled.CompiledScene<{ ...; }, CompiledLayersOf<...>>.at(frame: Frame, options?: FrameResolutionOptions): FrameState<{
badge: Badge;
}>
at(15).FrameState<{ ...; }>.scene: {
badge: ResolvedActorOfInstance<Badge> | undefined;
}
scene.badge: ResolvedActorOfInstance<Badge> | undefinedbadge?.count: number | undefinedcount; // 50
const compiled: CompiledScene<{
badge: Badge;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled.CompiledScene<{ ...; }, CompiledLayersOf<...>>.at(frame: Frame, options?: FrameResolutionOptions): FrameState<{
badge: Badge;
}>
at(15).FrameState<{ ...; }>.scene: {
badge: ResolvedActorOfInstance<Badge> | undefined;
}
scene.badge: ResolvedActorOfInstance<Badge> | undefinedbadge?.label: string | undefinedlabel; // "Go"
const compiled: CompiledScene<{
badge: Badge;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled.CompiledScene<{ ...; }, CompiledLayersOf<...>>.at(frame: Frame, options?: FrameResolutionOptions): FrameState<{
badge: Badge;
}>
at(30).FrameState<{ ...; }>.scene: {
badge: ResolvedActorOfInstance<Badge> | undefined;
}
scene.badge: ResolvedActorOfInstance<Badge> | undefinedbadge?.label: string | undefinedlabel; // "Done"
badge.count() inside the scene reads the value at the cursor. Inside a
derived it reads the value at the frame being resolved. peek()
is the same read.
Declaring
signal(initial) takes its type from the initial value. Pass the type when the initial value
is narrower than the values the field will hold: signal<"neutral" | "success">("neutral"),
or signal<string[]>([]), which would otherwise be never[].
Every signal is also a spawn input, so ctx.spawn(Badge, { label: "Go" }) starts the badge
with that label. A signal declared without an initial value is required:
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";
class class TitleTitle extends class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor {
Title.text: RequiredSignal<string>text = signal<string>(): RequiredSignal<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<string>();
}
createScene<void, Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>>(script: SceneScript<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, void>, 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) {
ctx: SceneContextctx.CompileContext.spawn<Title>(definition: ActorClass<Title>, overrides: {
text: SignalInputValue<string>;
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<...> | undefined;
} | undefined;
... 20 more ...;
parent?: undefined;
}, options?: {
...;
} | undefined): Title (+1 overload)
spawn(class TitleTitle, { text: SignalInputValue<string>text: "Chapter one" });
}).SceneDefinition<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, void>.build(args: SceneBuildInput<Readonly<Record<never, SceneInput>>>): CompiledScene<void, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>build({ viewport: SceneViewportviewport: { SceneViewport.width: numberwidth: 1920, SceneViewport.height: numberheight: 1080 }, fps: numberfps: 30 });
Spawning Title without text is a type error, and at run time it throws
Title: text is required.
signal.of(type, initial) declares a field whose value has a named type, such as
unitInterval, colorType or an asset type like image. Reflection reports the type, so an
editor can offer the right control, and spawn checks inputs against the type’s schema. A
color field also accepts a CSS string and stores the parsed color.
Media, assets and fonts covers the asset types.
Writing
| Method | Takes time | Writes |
|---|---|---|
set(value) |
no | The value, from the cursor on |
tween(target, timing) |
yes | A move from the current value to target |
play({ to, ... }) |
yes | A tween with repeats, direction, delay and fill |
animate(options) |
no | A play that runs beside the script |
transition(fn, timing) |
yes | Whatever fn returns for each frame’s progress |
derive(fn) |
no | A binding to a computation, from the cursor on |
A method that takes time is a generator, and the scene waits for it with yield*. The others
return at once and the cursor stays where it was.
The top dot tweens once. The middle one plays the same range four times, alternating
direction. The bottom one starts a scale animate and then a tween: animate takes no time,
so both begin on the same frame.
Timing
timing is required: a number of seconds, or an object with a duration.
| Option | |
|---|---|
duration |
Seconds. Required |
easing |
A function from progress to eased progress, such as Easing.outCubic |
spring |
{ stiffness, damping, mass }, a spring curve across duration, such as SpringPresets.bouncy |
from |
The start value, in place of the current one |
space |
"srgb" or "oklch", for tweens between color strings |
Seconds become whole frames at the build’s fps. A spring runs inside the duration and lands
on the target at its last frame. Between the endpoints, a spring or an easing such as wiggle
can carry a number past its target and back; a color stays between its two endpoints.
SpringPresets.gentle peaks 3% past the target, stiff 11%, bouncy 21% and wobbly 30%;
heavy does not overshoot.
play
yield* const dot: Dotdot.Dot.x: ActorFieldSignal<number>x.LiveSignal<number>.play(options: SignalPlaybackOptions<number>): Generator<Frame, void, unknown>Structured yieldable signal playback segment.play({
SignalPlaybackOptions<number>.to: numberto: 100,
SignalTweenOptions<number>.duration: numberduration: 0.5,
SignalPlaybackOptions<number>.iterations?: number | undefinediterations: 2,
SignalPlaybackOptions<number>.direction?: SignalAnimationDirection | undefineddirection: "alternate",
SignalPlaybackOptions<number>.delay?: number | undefineddelay: 0.2,
SignalPlaybackOptions<number>.fill?: SignalAnimationFill | undefinedfill: "forwards",
});
}).SceneDefinition<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, void>.build(args: SceneBuildInput<Readonly<Record<never, SceneInput>>>): CompiledScene<void, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>build({ viewport: SceneViewportviewport: { SceneViewport.width: numberwidth: 1920, SceneViewport.height: numberheight: 1080 }, fps: numberfps: 30 });
direction is "normal", "reverse", "alternate" or "alternate-reverse", as in CSS.
fill decides what holds outside the active span: "backwards" shows the first value during
delay, "forwards" keeps the last value after the end, "both" does both and "none"
returns to the underlying value. The default is "forwards".
animate
animate takes the options play takes and records the same motion on a branch of its own.
The script carries on from the same frame. A finite animate that outlasts the script keeps
the scene going until it ends. One with iterations: Infinity runs until the scene ends and
does not make it longer.
Starting another anonymous animate on the same signal replaces the running one. Named
animations, animate("pulse", options), replace an animation with the same name; starting
one while an animation with another name is running on the signal throws. A tween or
play on the signal stops the animation, and so does the actor’s exit.
transition
transition calls fn with the eased progress and the value the signal had when the
transition started. Use it for values a tween cannot interpolate:
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";
class class CaptionCaption extends class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor {
Caption.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("Backspace");
}
const const compiled: CompiledScene<{
caption: Caption;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled = createScene<{
caption: Caption;
}, Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>>(script: SceneScript<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, {
caption: Caption;
}>, 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 caption: Captioncaption = ctx: SceneContextctx.CompileContext.spawn<Caption>(definition: ActorClass<Caption>, overrides?: {
measuredBox?: undefined;
text?: SignalInputValue<string> | 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;
... 20 more ...;
parent?: undefined;
} | undefined, options?: {
...;
} | undefined): Caption (+1 overload)
spawn(class CaptionCaption);
yield* const caption: Captioncaption.Caption.text: ActorFieldSignal<string>text.LiveSignal<string>.transition(fn: (progress: number, from: string) => string, options: number | SignalTransitionOptions<string>): Generator<Frame, void, unknown>Custom transition — must yield*transition(
(progress: numberprogress, from: stringfrom) =>
from: stringfrom.String.slice(start?: number, end?: number): stringReturns a section of a string.slice(0, var Math: MathAn intrinsic object that provides basic mathematics functionality and constants.Math.Math.round(x: number): numberReturns a supplied numeric expression rounded to the nearest integer.round(from: stringfrom.String.length: numberReturns the length of a String object.length * (1 - progress: numberprogress))),
1,
);
return { caption: Captioncaption };
}).SceneDefinition<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, { ...; }>.build(args: SceneBuildInput<Readonly<Record<never, SceneInput>>>): CompiledScene<{
caption: Caption;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
build({ viewport: SceneViewportviewport: { SceneViewport.width: numberwidth: 1920, SceneViewport.height: numberheight: 1080 }, fps: numberfps: 30 });
const compiled: CompiledScene<{
caption: Caption;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled.CompiledScene<{ ...; }, CompiledLayersOf<...>>.at(frame: Frame, options?: FrameResolutionOptions): FrameState<{
caption: Caption;
}>
at(15).FrameState<{ ...; }>.scene: {
caption: ResolvedActorOfInstance<Caption> | undefined;
}
scene.caption: ResolvedActorOfInstance<Caption> | undefinedcaption?.text: string | undefinedtext; // "Backs"
A list that changes as a whole, such as a set of windows opening at once, can be one
signal<Window[]> written by a transition that returns the new array each frame. When
separate leaves of a nested value move on their own schedules, use a
reactiveSignal.
derive
derive binds the signal to a computation from the cursor on. It is how one actor follows
another without either owning the other’s state:
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";
class class DotDot extends class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor {
Dot.x: ActorFieldSignal<number>x = 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);
}
const const compiled: CompiledScene<{
follower: Dot;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled = createScene<{
follower: Dot;
}, Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>>(script: SceneScript<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, {
follower: Dot;
}>, 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 leader: Dotleader = ctx: SceneContextctx.CompileContext.spawn<Dot>(definition: ActorClass<Dot>, overrides?: {
measuredBox?: undefined;
x?: SignalInputValue<number> | 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<...> | undefined;
} | undefined;
... 20 more ...;
parent?: undefined;
} | undefined, options?: {
...;
} | undefined): Dot (+1 overload)
spawn(class DotDot);
const const follower: Dotfollower = ctx: SceneContextctx.CompileContext.spawn<Dot>(definition: ActorClass<Dot>, overrides?: {
measuredBox?: undefined;
x?: SignalInputValue<number> | 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<...> | undefined;
} | undefined;
... 20 more ...;
parent?: undefined;
} | undefined, options?: {
...;
} | undefined): Dot (+1 overload)
spawn(class DotDot);
const follower: Dotfollower.Dot.x: ActorFieldSignal<number>x.LiveSignal<number>.derive<unknown>(fn: (this: unknown) => number): voidBind this signal to a derived computation at the current cursor.derive(() => const leader: Dotleader.Dot.x: () => numberx() + 10);
yield* const leader: Dotleader.Dot.x: ActorFieldSignal<number>x.LiveSignal<number>.tween(target: number, options: number | SignalTweenOptions<number>): Generator<Frame, void, unknown>Tween to target over authored seconds — must yield*tween(100, 1);
return { follower: Dotfollower };
}).SceneDefinition<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, { ...; }>.build(args: SceneBuildInput<Readonly<Record<never, SceneInput>>>): CompiledScene<{
follower: Dot;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
build({ viewport: SceneViewportviewport: { SceneViewport.width: numberwidth: 1920, SceneViewport.height: numberheight: 1080 }, fps: numberfps: 30 });
const compiled: CompiledScene<{
follower: Dot;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled.CompiledScene<{ ...; }, CompiledLayersOf<...>>.at(frame: Frame, options?: FrameResolutionOptions): FrameState<{
follower: Dot;
}>
at(30).FrameState<{ ...; }>.scene: {
follower: ResolvedActorOfInstance<Dot> | undefined;
}
scene.follower: ResolvedActorOfInstance<Dot> | undefinedfollower?.x: number | undefinedx; // 110
A later set or tween on the follower replaces the binding.
Several at once
The verbs that take time are generators, so the scene’s helpers compose them: ctx.all(...)
runs several together and ctx.sequence(delay, ...) starts each one delay seconds after
the one before. Inside a command the same helpers are on this.runtime.
Scene orchestration covers them.
Writing to a signal while a frame resolves, in a derived body for example, throws
Cannot set signal "x" during signal resolution.