import type { EasingInput } from '../physics/easing-registry'; import type { Easing } from '../physics/easings'; import type { AnimationHandle } from '../value/animatable'; /** * One expressive keyframe stop: a value plus an optional position and the easing * of the segment REACHING it. `at` is a 0..1 fraction of the total duration * (tween mode); `ease` overrides the animation easing for that one segment. A * bare value is shorthand for `{ value }`. `null` at index 0 means "from the * current value"; a `null` later HOLDS the previous value (a dwell). * * `at` positions a waypoint in time (WAAPI-consistent): an `at` on the LAST * waypoint means the final value is reached at that fraction and then held to the * end of the duration - a settle-and-dwell, not the full-duration default. */ export interface KeyframeStop { value: V | null; /** 0..1 position along the total duration where this stop is reached (tween mode). Non-decreasing. */ at?: number; /** Easing of the segment reaching this stop (tween mode); defaults to the animation easing. */ ease?: EasingInput; } /** A keyframe entry: a bare value, `null` (from-current / hold), or an expressive stop. */ export type KeyframeInput = V | null | KeyframeStop; /** * Keyframe semantics, shared by numeric channels and registry property groups. * Without a duration the waypoints are CHAINED SPRINGS: spring to waypoint k, * and only once it has rested (exact snap) spring to k+1 - the honest physics * of "spring through a list of targets" (positions/per-segment easing are * tween-only and ignored here). With a duration they become a piecewise tween; * the duration is split by the stops' positions (evenly when unset) and each * segment eases with its own easing (the animation easing when unset). A new * animate() interrupts the chain (velocity conserved into the replacement); * stop() freezes the running segment and drops the rest. Never rejects. */ export interface ChainOps { /** Teleport to a value (explicit keyframe-0 start), velocity 0. */ teleport(target: T): void; spring(target: T): AnimationHandle; tween(target: T, durationMs: number, easing: Easing): AnimationHandle; /** Reduced-motion: settle directly onto the final waypoint. */ settle(target: T): void; } export interface ChainConfig { duration?: number; easing: Easing; reduced: boolean; /** Per-waypoint segment duration in ms (tween mode); overrides the even split where present. */ segmentDurations?: number[]; /** Per-waypoint easing (tween mode); overrides `easing` for that segment where defined. */ segmentEasings?: ReadonlyArray; } export interface KeyframeChain { handle: AnimationHandle; /** A new animate() took over this channel: stop advancing and resolve (do not freeze - the replacement owns it now). */ interrupt(): void; } export interface NormalizedKeyframes { /** undefined = start from the current value+velocity; otherwise a teleport start. */ teleport: V | undefined; waypoints: V[]; /** Per-waypoint 0..1 arrival position; undefined = auto (even split). Aligned to `waypoints`. */ offsets: ReadonlyArray; /** Per-waypoint easing input reaching it; undefined = the animation easing. Aligned to `waypoints`. */ eases: ReadonlyArray; } /** * Normalize a keyframe array. `[]` -> null (ignored). `[a]` -> from current to a. * `[a, b, ...]` -> teleport to a (null a = from current), then chain b, ... . A * `null` past index 0 HOLDS the previous value (a dwell); a leading run of nulls * with no prior value is dropped. Bare values and `{ value, at, ease }` stops mix * freely; the per-waypoint `at`/`ease` are collected into parallel arrays. */ export declare function normalizeKeyframes(frames: ReadonlyArray>): NormalizedKeyframes | null; export declare function runKeyframeChain(normalized: { teleport: T | undefined; waypoints: T[]; }, ops: ChainOps, config: ChainConfig): KeyframeChain; /** * Fill per-waypoint arrival positions to a non-decreasing 0..1 array. Explicit * `at` values anchor; gaps interpolate linearly between the nearest anchors (a * virtual 0 before the first, 1 at the last when unset) - the times[] contract. */ export declare function fillOffsets(count: number, explicit: ReadonlyArray): number[]; //# sourceMappingURL=keyframes.d.ts.map