A page's own CSS @keyframes, on the kernel clock. The look stays in the stylesheet; Fizlet owns the time. Each animation under root is paused and reads its time from one custom property that a timeline moves through the ledger: .led { animation: blink 1s steps(2) infinite paused; animation-delay: var(--fz-t, 0s); } .bug { animation: walk 6s linear infinite paused; animation-delay: calc(var(--fz-t, 0s) - 3s); } - One shared requestAnimationFrame with every other engine on the page; off screen or in a hidden tab it asks for no frames at all. - Settles: after loops plays of span seconds it rests where it started (every animation whose duration divides span is back on its first frame) and the engine sleeps. A pointer over the root, focus inside it or coming back into view plays it again. - Reduced motion: play() lands on the rest frame at once (the still poster). - Recall: destroy() (or aborting signal) gives the root's style back as it was.
import { cssClock } from "https://fizlet.com/dist/css-clock.js";
NPM · @fzlt/core
npm install @fzlt/core
import { cssClock } from "@fzlt/core/css-clock";
IN SHORT
/* CSS: the look stays in the stylesheet, paused; its time is --fz-t */
.led { animation: blink 1s steps(2) infinite paused; animation-delay: var(--fz-t, 0s); }
const c = cssClock(diagram, { span: 6, loops: 3 }); // rests on frame one, settles
pauseButton.onclick = () => c.hold(!held); // c.destroy() gives the page back
API
Every export with its signature, parameters, return type, doc comment and status flag, generated at build time from the published type declarations of v0.21.3 by the TypeScript compiler. For AI agents: the whole API as plain text.
CssClockOptions interface BETA
Options for cssClock(): the loop length, how many plays before it rests, the custom property, the frame cap, reduced motion and an abort signal.
export interface CssClockOptions {
/** Seconds in one play: the loop length (the longest animation, or a common multiple). Default 6. */
span?: number;
/** Plays before it rests and the engine settles (default 3). */
loops?: number;
/** The custom property the animations read (default "--fz-t"). */
prop?: string;
/** Frame-rate cap, e.g. 30 for steps() blinks (default: none, 60 Hz). */
fps?: number;
/** Animate (default: yes, unless the visitor prefers reduced motion). */
motion?: boolean;
/** Aborting it destroys the clock (Recall included). */
signal?: AbortSignal;
}
cssClock function BETA
Run the CSS
@keyframes under root on the kernel clock: each paused animation reads its time from one custom property a timeline moves. It settles after loops plays and wakes on pointer, focus or coming back into view; destroy() gives the root's style back.