Actor
The root runtime unit — state, commands, events, lifecycle hooks, and orchestration helpers.
class Counter extends Actor {
count = signal(0);
*incrementTo(target: number, duration = 0.4) {
yield* this.count.tween(target, duration);
}
}Generator methods are the authoring surface. A method that yield*s a tween consumes
authored time; a method that only calls set does not.
Built-in fields
this.id; // stable string id assigned at spawn
this.cursor; // current authored frame, read during compile time
this.emit; // typed event emitter, when events are declared
this.runtime; // orchestration helpersLifecycle hooks
class Panel extends Actor {
onInit() {
// synchronous, called when the actor is created
}
onSpawn() {
// structure decided here: hostInSlot for conditional children
}
*onEnter() {
// a generator — consumed at spawn time
yield* this.appearance.opacity.tween(1, 0.3);
}
*onExit() {
yield* this.appearance.opacity.tween(0, 0.2);
}
}Orchestration
The same primitives as ctx, available inside any actor method:
// Concurrent
yield* this.runtime.all(a.enter(), b.enter());
// Sequential with stagger
yield* this.runtime.sequence(0.05, ...items.map((i) => i.enter()));
// Wait
yield* this.runtime.wait(1);
// Fire-and-forget — takes no authored time
this.runtime.fork(function* (this: Panel) {
yield* this.doSomething();
});
// Repeats until despawned
this.runtime.loop(function* (this: Panel) {
yield* this.pulse();
yield* this.runtime.wait(2);
});See scene orchestration for the full surface.
Command style
Methods taking more than one primitive argument use object parameters. Multiple number
positionals are the specific thing to avoid — at the call site they are unreadable and
silently order-sensitive.
// Good
*focusTo({ x, y, duration }: { x: number; y: number; duration?: Duration }) {}
// Avoid
*focusTo(x: number, y: number, duration: number) {}Use a different base when
The actor needs layout, transform or appearance, or hosts slotted children — use
LayoutActor.