export type FramePhase = "windup" | "active" | "recovery" | "cancel"; export interface FrameRange { phase: FramePhase; from: number; to: number; } export interface AnimationClip { id: string; frames: number; fps: number; ranges: readonly FrameRange[]; loop?: boolean; } export interface AnimationSnapshot { clipId: string; frame: number; elapsedMs: number; } export interface AnimationTickResult { clipId: string | null; frame: number; entered: readonly FramePhase[]; exited: readonly FramePhase[]; completed: boolean; } /** @internal */ export declare function clipDurationMs(clip: AnimationClip): number; /** @internal */ export declare function frameAtMs(clip: AnimationClip, elapsedMs: number): number; /** @internal */ export declare function phasesAtFrame(clip: AnimationClip, frame: number): FramePhase[]; /** @internal */ export declare function activeRangeAtFrame(clip: AnimationClip, frame: number): FrameRange | null; export interface AnimationState { play(clipId: string): void; stop(): void; tick(dtSeconds: number): AnimationTickResult; current(): AnimationSnapshot | null; phases(): readonly FramePhase[]; inPhase(phase: FramePhase): boolean; isActive(): boolean; canCancel(): boolean; activeWindowMs(): { from: number; to: number; } | null; } export interface AnimationStateConfig { clips: readonly AnimationClip[]; } /** @internal */ export declare function createAnimationState(config: AnimationStateConfig): AnimationState;