Click the empty timeline to add a stop. Drag a stop to move it, or focus one and use the arrow keys, Shift and an arrow for ten percent, Home and End for the ends, and Delete to remove it.
The preview runs in a fully sandboxed frame: it loads no script and makes no request. The frame is used so a generated @keyframes name cannot collide with this site's own.
@keyframes fade-in {
0% {
transform: translate(0px, 8px) rotate(0deg) scale(1);
opacity: 0;
}
100% {
transform: translate(0px, 0px) rotate(0deg) scale(1);
opacity: 1;
}
}
/* Only animate when the visitor has not asked for less motion. Written as
no-preference rather than as a reduce override, so a browser that does
not understand the query never starts the animation at all. */
@media (prefers-reduced-motion: no-preference) {
.fade-in {
animation: fade-in 320ms ease-out 0ms 1 normal both;
}
}Related tools
- Cubic Bezier Easing EditorDrag the control points of a CSS easing curve, watch it animate, and copy the cubic-bezier or linear() value.
- CSS Gradient GeneratorBuild linear, radial, and conic CSS gradients visually, pick the interpolation color space, and copy the CSS.
- CSS Anchor Positioning BuilderBuild CSS anchor-positioned tooltips, menus, and popovers with flip fallbacks and a plain-CSS fallback.
- Box Shadow GeneratorStack multiple CSS box-shadow layers visually, preview them on light and dark, and copy the CSS or the Tailwind value.
- Fluid Clamp CalculatorTurn a min and max size into a responsive CSS clamp() expression, with a preview at six viewport widths.
- Clip Path GeneratorDrag shape handles over your own image and copy the matching CSS clip-path or SVG path.
What it does
Builds a CSS @keyframes animation on a timeline. Each stop sits at a percentage and carries a translate, a rotation, a scale, an opacity, and an optional background color, all edited with sliders while a preview element runs the result. It writes the @keyframes block, the animation shorthand with every longhand spelled out, and, if you want it, the prefers-reduced-motion guard that keeps the animation from running for visitors who asked for less of it.
How to use it
Pick a preset, then add stops on the timeline and adjust each one. Set the duration, the timing function, the iteration count, the direction, and the fill mode in the settings, and give the animation a name if you do not want the preset's. Press Replay to watch it again, then copy the CSS. The whole timeline lives in the URL, so a link reproduces exactly the animation you built.
Why this one
Most keyframe generators give you a fixed list of canned animations and no way to move a stop. This one is a real timeline: add a stop anywhere, drag it, and see the transform recomposed as the same function list at every stop, which is what a browser needs in order to interpolate at all. It also refuses an animation name that is a CSS-wide keyword, which is a silent failure that costs people an afternoon, and it offers the reduced motion guard by default. It runs entirely in the page, so your files and inputs never leave your device.
FAQ
- Why does my transform animation jump instead of interpolating?
- A browser can only interpolate two transforms whose function lists match in kind and in order. If one stop says translateY(20px) and the next says scale(1.1), there is nothing to interpolate between, so the value snaps at the stop boundary. This tool writes translate, rotate, and scale on every stop as soon as any stop needs a transform, which is exactly what keeps the animation smooth.
- What does animation-fill-mode actually change?
- It decides what the element looks like outside the animation's own running time. With the default of none, the element snaps back to its normal styles the moment the animation ends, which is why a fade in often flashes back to invisible. forwards holds the last keyframe, backwards applies the first keyframe during the delay, and both does the two together. For an entrance animation, both is almost always what you meant.
- How should I handle prefers-reduced-motion?
- Put the animation inside a prefers-reduced-motion: no-preference query rather than turning it off inside a reduce query. Written that way, a browser that does not understand the query never starts the animation at all, so the safe path is the default rather than the exception. Motion that conveys meaning, such as a progress spinner, can stay, but large movement, parallax, and anything that loops should not run for someone who asked for less of it.
Keyboard shortcuts: press ? anywhere on this page to see them.