CSS Keyframes Editor
Author a multi-stop animation on a timeline and copy it with its reduced-motion guard already written
Loading one replaces the timeline. Two of the presets over there are not on this list — they animate things a pixel timeline cannot express, and that page says which and why.
@keyframes rise-in {
0% {
transform: translate(0px, 16px) scale(0.96);
opacity: 0;
}
100% {
transform: none;
}
}
.rise-in {
animation: rise-in 600ms cubic-bezier(0.4, 0, 0.2, 1) both;
}
@media (prefers-reduced-motion: reduce) {
.rise-in {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
}
}<div class="rise-in">…</div>Now use it on something
Every effect, block, page and template in the catalog is styled against tokens shaped exactly like these — so they take your values rather than fighting them.
npx shadcn@latest add https://hoverlab.dev/r/hoverlab.json
Where on the timeline this frame sits, as a percentage of the duration. Two stops close together make a fast move with a pause either side — that is how you get a snap rather than a drift.
100% is fully opaque. Fading from 0 is the cheapest enter animation there is, and the one that survives reduced motion best.
Horizontal offset. Transforms are composited on the GPU and never trigger layout, which is why animating this instead of `left` is the difference between 60fps and jank.
Vertical offset. A rise of 8–24px is the standard enter; more than that and the element reads as flying in rather than settling.
100% is untouched. Small scales read as depth; below about 90% on an enter it starts to look like a zoom rather than an arrival.
Applied after the translate and before the scale, because CSS resolves a transform list right to left and reordering it silently changes the result.
The one property here that is not free — filter forces a repaint every frame. Effective in small doses on a single element, expensive across a list.
Used for both the @keyframes and the class. Emitted as rise-in — spaces and anything else invalid in a CSS identifier are folded to hyphens.
Under about 150ms an animation reads as a jump; over about 500ms it reads as a wait. Enter and exit want the short end; attention loops can afford the long one.
Held before the first frame. Staggering a list by 40–60ms per item is what makes a group arrive as a group rather than a stampede.
Applies between every pair of stops, not once across the whole animation. Want a different curve on one segment? Add a stop.
How many times it runs. Zero here means infinite — and an infinite animation gets the stricter reduced-motion guard, because a loop shortened to a millisecond is a loop running very fast forever.
alternate is how a pulse is written once instead of twice — you author half the movement and let the return trip come free.
The reason an enter animation snaps back at the end: none drops the animated values the instant it finishes. both is the safe default for anything that arrives and stays.
Shortcut for setting iterations to infinite. Useful while you are shaping the curve and wrong for almost anything you ship — an animation that never stops is an animation nobody can read past.
Keep this animation. This browser remembers what you last had open. A free account remembers the ones you name, on every machine you use.
- Motion PresetsEnter, exit and attention animations, each shipping with its prefers-reduced-motion guard already written — and each one opening in the keyframes editor when the preset is only nearly right. Preview what a reduced-motion visitor actually sees.
- Easing StudioVisual cubic-bezier editor. Drag the two control points on the curve, watch live translateX / scale / opacity previews, and pick from 14 named presets.
- Loader GeneratorSpinners, dots, bars, pulses and progress rings as pure CSS, tuned on sliders and seeded from the loaders already in the catalog. Every one ships with its reduced-motion guard and the accessible status role written in.