Docs
Animation
animate() is the timeline entry point. animateIn() is the intro. Use generator functions, yield*, all, and tween. Keep fontSize a positive constant.
Custom element animation is a generator function. yield pauses until the next frame. yield* runs another generator to completion, such as a tween.
public *animateIn(duration: number = 0.4): ThreadGenerator {
this.opacity(0);
yield* this.opacity(1, duration, easeOutCubic);
}Import ThreadGenerator, all, tween, waitFor, and easing from @vidova/core.
animate vs animateIn
animate() is the timeline entry point. The player calls it when the clip is active.
animateIn() is the intro. Thumbnails play animateIn() before capture. Frame 0 of a reveal-driven element is blank, which is why the thumbnail path needs a separate intro.
Keep them as two methods. animate() may call animateIn(), then hold or play the rest:
public *animateIn(duration: number = 0.4): ThreadGenerator {
this.opacity(0);
yield* this.opacity(1, duration, easeOutCubic);
}
public *animate(duration?: number): ThreadGenerator {
yield* this.animateIn(duration ?? 0.4);
}If animate() hides the element at the end, a thumbnail that played only animate() would capture an empty frame. That is the reason for the split.
Tweens and flow
A signal tween takes the next value, a duration in seconds, and an optional timing function:
yield* this.opacity(1, 0.4, easeOutCubic);Run tweens together with all:
yield* all(
this.opacity(1, 0.4, easeOutCubic),
this.scale(1, 0.4, easeOutCubic),
);Wait with waitFor:
yield* waitFor(0.2);tween is the low-level helper when you need a callback per frame:
yield* tween(0.4, (value) => {
this.opacity(value);
});Prefer signal tweens when the property is already a signal.
fontSize stays positive
fontSize must be a positive number on every frame. Do not drive it from a signal that starts at 0. Keep fontSize constant and animate scale.
public *animateIn(duration: number = 0.4): ThreadGenerator {
this.scale(0);
yield* this.scale(1, duration, easeOutCubic);
}A fontSize of 0 compiles and then fails at render. The clip shows nothing.
Refs
Hold a child when a method needs to tween it later:
import { createRef } from '@vidova/core';
import { Rect, Txt } from '@vidova/2d';
private readonly title = createRef<Txt>();
public constructor(props?: HelloTitleProps) {
super({ ...props });
this.add(
<Rect>
<Txt ref={this.title} text={() => this.label()} fontFamily="Inter Variable" />
</Rect>,
);
}
public *animateIn(duration: number = 0.4): ThreadGenerator {
this.title().opacity(0);
yield* this.title().opacity(1, duration, easeOutCubic);
}Class fields for refs are fine. Class fields for @signal props must not collide with Node members. See Layout.
