ToollyX
no sign-up · instant · free

CSS Animation Builder

Build keyframe animations on a real visual timeline — click to add stops anywhere from 0% to 100%, tune movement, scale, rotation and opacity per keyframe, and preview with play, pause and restart. Runs entirely in your browser.

KEYFRAMESUnlimited
PRESETS9 built-in
EASINGCustom bezier
PROCESSEDBrowser-local
UPLOADNone needed
728 × 90 — Leaderboard Ad
CSS Output
Name
Presets
Timeline
Keyframe 1
%
Move X0px
Move Y24px
Scale1.00
Rotate0°
Opacity0.00
Keyframe 2
%
Move X0px
Move Y0px
Scale1.00
Rotate0°
Opacity1.00
Timing
Duration0.6s
Delay0.0s
Easing
Repeat1
Direction
Fill Mode
Infinite loop
Repeat the animation forever instead of a fixed count
Autoplay preview
Start the preview animating automatically
Pause on hover
Pause the preview animation while the mouse is over it
A Real Timeline, Not Just Two Endpoints
Most CSS animation generators only offer a start and end state. This one supports unlimited keyframes placed anywhere from 0% to 100% — click the timeline to drop a new stop, drag values with sliders, and preview with play/pause/restart and hover-pause, all before copying a single block of CSS.
728 × 90 — Leaderboard Ad

Getting Motion That Feels Deliberate, Not Decorative

  • Animate transform and opacity, not width or position. Those two properties can run on the compositor thread without recalculating layout every frame — everything else, including top, margin and width, is measurably more likely to stutter on a slower device.
  • Set fill-mode to forwards or both for any entrance animation. Without it, an element that animates in will snap back to its pre-animation state — often invisible — the instant the animation finishes.
  • Keep entrance animations under 600ms. Motion that lingers longer starts to feel like the interface is waiting on itself rather than responding to the user, especially on anything that runs on every page load.
  • Reach for a custom cubic-bezier only when a named easing genuinely can't produce the feel needed — a slight overshoot past the resting position, for instance. For most UI motion, ease-out alone already reads as natural.

Features

Visual timeline
Click anywhere on the 0-100% timeline to drop a new keyframe instantly.
Unlimited keyframes
Not just a start and end state — build multi-stage motion like bounce or shake.
Custom easing
Five named curves plus a full custom cubic-bezier(x1, y1, x2, y2) editor.
Real preview controls
Play, pause, restart, and an optional pause-on-hover toggle.
Nine ready-made presets
Fade, slide, bounce, pulse, shake, spin and zoom, ready to adjust.
100% browser-based
Every value is computed client-side — nothing about your animation ever leaves the page.

Two Endpoints Is a Transition Wearing an Animation's Name

A huge share of tools called "CSS animation generators" only ever produce a 0% and a 100% keyframe — which is technically a real animation, but it's doing exactly what a plain CSS transition already does, just with more setup. The actual reason @keyframes exists as its own syntax, separate from transition, is to describe motion that passes through intermediate states on its own timeline: a bounce that overshoots and settles, a shake that reverses direction five times, a pulse that grows and shrinks in a loop. None of those are expressible with two endpoints, which is why this generator's timeline supports dropping a keyframe at any percentage rather than only ever editing a start and an end.

Why the Browser Cares Which Properties Are Animating

Not all CSS properties cost the same to animate. Transform and opacity can be handled almost entirely by the GPU compositor, without the browser recalculating where every other element on the page sits — which is why every keyframe here is built from translate, scale, rotate and opacity rather than raw left/top or width/height. Animating position or size properties instead forces a full layout recalculation on every single frame of the animation, and on a lower-end phone that's often the exact difference between motion that feels instant and motion that visibly stutters. The visual result of translate(20px, 0) and left: 20px can look identical at a glance; the performance profile behind them is not.

This is also why scale is preferred over animating width and height directly for anything that needs to grow or shrink — a button that pulses on click, a modal that scales in from its center. transform: scale(1.08) resizes the element visually without asking the browser to reconsider how every sibling and parent element should reflow around a genuinely new box size, while animating width or height does exactly that reflow calculation, repeatedly, for the entire duration of the animation.

What fill-mode Is Actually Deciding

animation-fill-mode answers a question most people don't think to ask until the bug shows up: what should the element look like before the animation starts, and after it ends? Left at its default of none, the element reverts to its ordinary CSS the instant the animation finishes — which is exactly why a fade-in-up animation can appear to work perfectly and then instantly snap back to invisible once it's done. forwards keeps the final keyframe's values applied after completion; backwards applies the first keyframe's values immediately, even during animation-delay, which is what prevents a one-frame flash of the wrong state before a delayed animation begins. both does both at once, which is the right default for the vast majority of entrance animations.

Direction and Iteration Count Solve a Narrower Problem Than They Look Like

animation-direction is easy to assume controls speed or intensity, but it only ever decides which way through the keyframe list each pass runs. normal always plays 0% to 100%; reverse always plays 100% to 0%; alternate and alternate-reverse flip direction every other iteration, which is the specific setting a back-and-forth motion — a breathing glow, a swaying element — needs to avoid a visible snap back to the start at the end of every loop. Pairing alternate with an even iteration-count returns the element to its starting keyframe when the animation eventually stops; pairing it with an odd count leaves it at the opposite end, which is worth checking deliberately rather than discovering by accident once infinite is turned off.

728 × 90 — Leaderboard Ad

Presets as Recognizable Motion Vocabulary

Bounce, pulse, shake and spin aren't arbitrary — they're specific, named patterns that show up constantly across real interfaces because each one communicates something different at a glance. A shake reads instantly as "this input is wrong" without a single word of copy. A pulse on a notification badge says "something changed here" without demanding attention the way a full-screen alert would. Loading this generator's multi-stage keyframe timeline with each preset's real values, rather than approximating them with a two-keyframe shortcut, is what makes the shake actually shake and the bounce actually bounce instead of producing a flatter, less convincing version of either.

None of the nine presets are meant to be the final word, though — they're a faster route to the right starting keyframes than building an eleven-stop shake animation by hand. Loading Shake and then softening the horizontal distance from ±8px down to ±4px for a smaller input field, or stretching Bounce's duration from one second to 1.4 for a heavier-feeling element, is the normal way these get used — the preset supplies the timeline shape, the sliders supply the fine-tuning a specific component actually needs.

From a Tuned Preview to Motion That Ships

A typical path: load a preset close to the intended effect, then adjust individual keyframes — nudging a bounce's peak height, tightening a shake's distance, or extending a pulse's duration — against the live preview rather than guessing values blind. Once the timing feels right, deciding fill-mode and iteration-count usually comes down to what kind of motion it is: a one-time entrance wants forwards and a fixed count, a loading indicator or notification pulse wants infinite. From there, the CSS output drops straight into a stylesheet alongside whatever's already positioning the element — the flexbox or grid layout it sits inside doesn't need to change at all, since animation only ever affects the element's own transform and opacity, not how its container arranges it. That separation is worth keeping in mind when something looks wrong after adding motion to an existing component — if the animated element is shifting its siblings around as it moves, the bug almost always traces back to a property outside transform and opacity being touched somewhere, not to the animation timing itself.

Verified by ToollyX Team · Last updated July 2026

Frequently Asked Questions

728 × 90 — Leaderboard Ad

Related Tools