/** * Decode an animated image (GIF / APNG / animated WebP / animated AVIF) into * a list of frames with cumulative timing using the browser's ImageDecoder * API. Used by the server-side export pipeline so that animated elements * can be rendered frame-accurately under our virtual clock — native * playback ignores virtual time, so without this every captured frame would * show the GIF stuck at frame 0. * * Live `/present` keeps using directly; only the export pipeline opts * into the canvas-from-decoded-frames path. */ export interface DecodedFrame { bitmap: ImageBitmap; /** Frame display duration in ms. */ durationMs: number; } export interface DecodedAnimatedImage { frames: DecodedFrame[]; totalMs: number; width: number; height: number; } /** True if the URL/data-URL looks like an animated container we can decode. * We don't try to detect "animated PNG" vs "static PNG" upfront — the decoder * call below will return one frame for static images and that's fine. */ export declare function isLikelyAnimated(src: string): boolean; /** Decode every frame of an animated image. Falls back to a single-frame * result for static images. Returns null when ImageDecoder is unavailable * (e.g. older browsers) so callers can degrade gracefully. */ export declare function decodeAnimatedImage(src: string): Promise; /** Pick the frame that should be visible at `elapsedMs` for a looping animation * of total `totalMs`. Returns the index. */ export declare function frameIndexAt(decoded: DecodedAnimatedImage, elapsedMs: number): number; /** Draw the frame visible at `elapsedMs` into the given canvas. */ export declare function drawFrameAt(canvas: HTMLCanvasElement, decoded: DecodedAnimatedImage, elapsedMs: number): void;