createStates
Creates a state machine to manage and transition between different animations.
The createStates function is a high-level utility for managing complex animation logic. It allows you to define a set of named animation trees and provides a simple API for seamless transitions between them.
Example
import { a } from "@freestylejs/ani-core";
// 1. Define different animation structures for each named state.
const animations = {
inactive: a.ani({ to: { scale: 1, opacity: 0.5 }, duration: 0.5 }),
active: a.ani({ to: { scale: 1.2, opacity: 1 }, duration: 0.3 }),
};
// 2. Create a state machine controller with an initial state and initial values.
const myStates = a.createStates({
initial: 'inactive',
initialFrom: { scale: 1, opacity: 0.5 }, // The starting point for the first animation
states: animations,
});
// 3. Listen for updates from the currently active timeline.
myStates.timeline().onUpdate(({ state }) => {
console.log(state.scale);
});
// 4. Transition to a new state. This will smoothly switch to the 'active' animation.
myStates.transitionTo('active');Usage & Concepts
Overview
createStates is ideal for UI components with multiple visual states (e.g., hover, active, disabled, selected) or complex character animations. When you call transitionTo, it intelligently retrieves the current animation's values and uses them as the from point for the new state's animation, ensuring graceful and seamless transitions rather than abrupt cuts.
The Controller
The createStates function returns a controller object with the following methods:
timeline(): Returns the currently activetimelineinstance. Use this to subscribe to updates or control playback manually (e.g.,myStates.timeline().pause()).transitionTo(newState, [timelineConfig], [canBeIntercepted]): Switches to a different animation state. You can optionally provide atimelineConfigobject (similar totimeline.play()) to customize the transition's duration, keyframes, or repeat count.canBeIntercepteddetermines if the transition will occur even if the timeline is already playing.onTimelineChange(callback): Registers a callback that fires whenever the active timeline changes (i.e., after atransitionTocall). This is useful for reacting to global state changes managed bycreateStates.
Best Practices
- Do use
createStatesto manage distinct visual states of a component, especially when smooth transitions between states are required. - Do provide a sensible
initialFromvalue that matches the component's initial appearance. - Don't manually manage multiple
timelineinstances and their transitions;createStatesis designed to abstract this complexity. - Don't create a new
createStatesinstance frequently; it should be initialized once for a given set of states.
API Reference
Parameters
The createStates function accepts a single config object with the following properties:
| Name | Type | Description |
|---|---|---|
initial | keyof states | The key of the initial animation state to play. |
initialFrom | AniGroup<...> | The initial from value for the very first animation. |
states | AnimationStateShape | A record where keys are state names and values are animation nodes. |
clock | AnimationClock | (Optional) A custom animation clock. |
Type Definitions
import { AnimationClockInterface, AnimationNode, Groupable, Timeline, TimelineStartingConfig, ExtractAnimationNode, AniGroup } from '@freestylejs/ani-core';
type AnimationStateShape = Record<string, AnimationNode<Groupable>>;
type GetTimeline<State extends AnimationStateShape> = Timeline<ExtractAnimationNode<State[keyof State]>, any>;
interface StateController<AnimationStates extends AnimationStateShape> {
timeline: () => GetTimeline<AnimationStates>;
transitionTo(
newState: keyof AnimationStates,
timelineConfig?: TimelineStartingConfig<ExtractAnimationNode<AnimationStates[keyof AnimationStates]>, any>,
canBeIntercepted?: boolean
): void;
onTimelineChange(callback: (newTimeline: GetTimeline<AnimationStates>) => void): () => void;
}
interface StateProps<AnimationStates extends AnimationStateShape> {
initial: keyof AnimationStates;
initialFrom: AniGroup<ExtractAnimationNode<AnimationStates[keyof AnimationStates]>>;
states: AnimationStates;
clock?: AnimationClockInterface;
}
declare function createStates<AnimationStates extends AnimationStateShape>(
config: StateProps<AnimationStates>
): StateController<AnimationStates>;