ClockActor
A stopwatch whose elapsed time is computed from the frame, from @motionactor/primitives.
ClockActor counts frames while it runs. It stores only when it started and what it had
counted before, and works out the elapsed time from the frame being resolved, so frame 105
reads the same whether playback got there by playing or by seeking.
import { function child<TBlueprint extends ActorClass<object>, TOwner extends object = object>(blueprint: TBlueprint, ...[overrides]: ChildOverridesArg<TBlueprint, TOwner>): ChildField<TBlueprint, TOwner>child, 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, function derived<TThis, T>(fn: (this: TThis) => T): DerivedDefinition<T, TThis>derived, class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor } from "@motionactor/core";
import { class ClockActorClockActor } from "@motionactor/primitives";
class class StopwatchStopwatch extends class LayoutActor<TEvents extends ActorEventMap = {}>LayoutActor {
Stopwatch.clock: ChildField<typeof ClockActor, object>clock = child<typeof ClockActor, object>(blueprint: typeof ClockActor, overrides?: ChildOverrides<typeof ClockActor, object> | undefined): ChildField<typeof ClockActor, object>child(class ClockActorClockActor);
Stopwatch.label: DerivedDefinition<string, unknown>label = derived<unknown, string>(fn: (this: unknown) => string): DerivedDefinition<string, unknown>derived(() => this.Stopwatch.clock: ChildField<typeof ClockActor, object>clock.ClockActor.elapsedSeconds: DerivedDefinition
() => number
elapsedSeconds().Number.toFixed(fractionDigits?: number): stringReturns a string representing a number in fixed-point notation.toFixed(1));
}
const const compiled: CompiledScene<{
watch: Stopwatch;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled = createScene<{
watch: Stopwatch;
}, Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>>(script: SceneScript<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, {
watch: Stopwatch;
}>, 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 watch: Stopwatchwatch = ctx: SceneContextctx.CompileContext.spawn<Stopwatch>(definition: ActorClass<Stopwatch>, overrides?: {
clock?: {
accumulatedFrames?: SignalInputValue<number> | undefined;
startedAtFrame?: SignalInputValue<number> | undefined;
running?: SignalInputValue<boolean> | undefined;
elapsedFrames?: undefined;
elapsedSeconds?: undefined;
elapsedMilliseconds?: undefined;
} | undefined;
id?: undefined;
cursor?: undefined;
cursorSeconds?: undefined;
sceneFps?: undefined;
onInit?: undefined;
onEnter?: undefined;
onExit?: undefined;
... 16 more ...;
bounds?: undefined;
} | undefined, options?: {
...;
} | undefined): Stopwatch (+1 overload)
spawn(class StopwatchStopwatch);
yield* const watch: Stopwatchwatch.Stopwatch.clock: ChildField<typeof ClockActor, object>clock.ClockActor.start(duration?: Duration): Generator<number, void, unknown>Start counting from the cursor. A running clock keeps its count.start(2);
yield* const watch: Stopwatchwatch.Stopwatch.clock: ChildField<typeof ClockActor, object>clock.ClockActor.pause(duration?: Duration): Generator<number, void, unknown>Stop counting and keep the count.pause(1);
yield* const watch: Stopwatchwatch.Stopwatch.clock: ChildField<typeof ClockActor, object>clock.ClockActor.resume(duration?: Duration): Generator<number, void, unknown>Count on from where the clock paused.resume(1);
return { watch: Stopwatchwatch };
}).SceneDefinition<Readonly<Record<never, SceneInput>>, Readonly<Record<never, SceneLayer<BackendRef<string>>>>, { ...; }>.build(args: SceneBuildInput<Readonly<Record<never, SceneInput>>>): CompiledScene<{
watch: Stopwatch;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
build({ viewport: SceneViewportviewport: { SceneViewport.width: numberwidth: 1920, SceneViewport.height: numberheight: 1080 }, fps: numberfps: 30 });
const compiled: CompiledScene<{
watch: Stopwatch;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled.CompiledScene<{ ...; }, CompiledLayersOf<...>>.at(frame: Frame, options?: FrameResolutionOptions): FrameState<{
watch: Stopwatch;
}>
at(60).FrameState<{ ...; }>.scene: {
watch: ResolvedActorOfInstance<Stopwatch> | undefined;
}
scene.watch: ResolvedActorOfInstance<Stopwatch> | undefinedwatch?.label: string | undefinedlabel; // "2.0"
const compiled: CompiledScene<{
watch: Stopwatch;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled.CompiledScene<{ ...; }, CompiledLayersOf<...>>.at(frame: Frame, options?: FrameResolutionOptions): FrameState<{
watch: Stopwatch;
}>
at(75).FrameState<{ ...; }>.scene: {
watch: ResolvedActorOfInstance<Stopwatch> | undefined;
}
scene.watch: ResolvedActorOfInstance<Stopwatch> | undefinedwatch?.label: string | undefinedlabel; // "2.0", paused
const compiled: CompiledScene<{
watch: Stopwatch;
}, CompiledLayersOf<Readonly<Record<never, SceneLayer<BackendRef<string>>>>>>
compiled.CompiledScene<{ ...; }, CompiledLayersOf<...>>.at(frame: Frame, options?: FrameResolutionOptions): FrameState<{
watch: Stopwatch;
}>
at(105).FrameState<{ ...; }>.scene: {
watch: ResolvedActorOfInstance<Stopwatch> | undefined;
}
scene.watch: ResolvedActorOfInstance<Stopwatch> | undefinedwatch?.label: string | undefinedlabel; // "2.5"
Commands
Each command changes the clock at the cursor and then waits its duration in seconds, 0 by
default. start(2) reads as “start, and let it run for two seconds”.
| Command | Does |
|---|---|
start(duration?) |
Starts counting. On a running clock it does nothing |
pause(duration?) |
Stops counting and keeps the count |
resume(duration?) |
Counts on from the kept count. The same as start |
reset(duration?) |
Stops the clock and zeroes it |
Values
| Field | |
|---|---|
elapsedFrames |
Frames counted |
elapsedSeconds |
elapsedFrames over the build’s frame rate |
elapsedMilliseconds |
The same, in milliseconds |
running |
Whether it is counting |
The elapsed values are derived, so another actor’s derived value or a
renderer can read them like any signal. A countdown is total - clock.elapsedSeconds().
Past the scene’s last frame a running clock reads as it did on that frame, because every later frame resolves as the last one. It never reads wall-clock time.
ClockActor measures time and runs nothing. To repeat work, use
runtime.loop. To wait, use ctx.wait.