Free, local and no login

CSS keyframe generator

Create and edit CSS @keyframes on a visual timeline. See every keyframe, change properties precisely, and export maintainable CSS rather than guessing percentages.

Create an animation

Try it right here

A working example with the exact code it produces. Copy it, or open it in the editor and change anything.

animation.css
.bounce-in {
  transform: translate3d(180px, 100px, 0);
  width: 120px;
  height: 120px;
  background: #6366f1;
  border-radius: 20px;
  animation: bounce-in-anim 900ms linear 0ms infinite both;
  will-change: transform, opacity;
}

@keyframes bounce-in-anim {
  0% {
    transform: translate3d(180px, -60px, 0);
    opacity: 0;
    animation-timing-function: ease-out;
  }
  2.78% {
    transform: translate3d(180px, -59.066px, 0);
    opacity: 0.149;
  }
  5.56% {
    transform: translate3d(180px, -56.265px, 0);
    opacity: 0.287;
  }
  8.33% {
    transform: translate3d(180px, -51.597px, 0);
    opacity: 0.416;
  }
  11.11% {
    transform: translate3d(180px, -45.062px, 0);
    opacity: 0.535;
  }
  13.89% {
    transform: translate3d(180px, -36.659px, 0);
    opacity: 0.644;
  }
  16.67% {
    transform: translate3d(180px, -26.389px, 0);
    opacity: 0.742;
  }
  19.44% {
    transform: translate3d(180px, -14.252px, 0);
    opacity: 0.828;
  }
  22.22% {
    transform: translate3d(180px, -0.247px, 0);
    opacity: 0.9;
  }
  25% {
    transform: translate3d(180px, 15.625px, 0);
    opacity: 0.956;
  }
  27.78% {
    transform: translate3d(180px, 33.364px, 0);
    opacity: 0.99;
  }
  30% {
    transform: translate3d(180px, 48.9px, 0);
    opacity: 1;
  }
  30.56% {
    transform: translate3d(180px, 52.971px, 0);
    opacity: 1;
  }
  33.33% {
    transform: translate3d(180px, 74.444px, 0);
    opacity: 1;
  }
  36.11% {
    transform: translate3d(180px, 97.785px, 0);
    opacity: 1;
  }
  38.89% {
    transform: translate3d(180px, 89.66px, 0);
    opacity: 1;
  }
  41.67% {
    transform: translate3d(180px, 80.069px, 0);
    opacity: 1;
  }
  44.44% {
    transform: translate3d(180px, 72.346px, 0);
    opacity: 1;
  }
  47.22% {
    transform: translate3d(180px, 66.489px, 0);
    opacity: 1;
  }
  50% {
    transform: translate3d(180px, 62.5px, 0);
    opacity: 1;
  }
  52.78% {
    transform: translate3d(180px, 60.378px, 0);
    opacity: 1;
  }
  55.56% {
    transform: translate3d(180px, 60.123px, 0);
    opacity: 1;
  }
  58.33% {
    transform: translate3d(180px, 61.736px, 0);
    opacity: 1;
  }
  61.11% {
    transform: translate3d(180px, 65.216px, 0);
    opacity: 1;
  }
  63.89% {
    transform: translate3d(180px, 70.563px, 0);
    opacity: 1;
  }
  66.67% {
    transform: translate3d(180px, 77.778px, 0);
    opacity: 1;
  }
  69.44% {
    transform: translate3d(180px, 86.86px, 0);
    opacity: 1;
  }
  72.22% {
    transform: translate3d(180px, 97.809px, 0);
    opacity: 1;
  }
  75% {
    transform: translate3d(180px, 95.625px, 0);
    opacity: 1;
  }
  77.78% {
    transform: translate3d(180px, 91.975px, 0);
    opacity: 1;
  }
  80.56% {
    transform: translate3d(180px, 90.193px, 0);
    opacity: 1;
  }
  83.33% {
    transform: translate3d(180px, 90.278px, 0);
    opacity: 1;
  }
  86.11% {
    transform: translate3d(180px, 92.23px, 0);
    opacity: 1;
  }
  88.89% {
    transform: translate3d(180px, 96.049px, 0);
    opacity: 1;
  }
  91.67% {
    transform: translate3d(180px, 99.236px, 0);
    opacity: 1;
  }
  94.44% {
    transform: translate3d(180px, 97.623px, 0);
    opacity: 1;
  }
  97.22% {
    transform: translate3d(180px, 97.878px, 0);
    opacity: 1;
  }
  100% {
    transform: translate3d(180px, 100px, 0);
    opacity: 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  .bounce-in {
    animation: none;
    transition: none;
  }
}

Why it is built this way

CSS timing functions cannot oscillate, so a real bounce cannot be written as a single cubic-bezier. The curve here is sampled and baked into extra keyframes, which is why the CSS has more stops than you would write by hand — and why it needs no JavaScript.

More ready-made animations

Browse all animations →

Heartbeat Animation

A double-beat pulse for likes, favourites and live counters.

Floating Animation

A slow vertical float for hero images and decorative elements.

Shake Animation

A horizontal shake for invalid form input and error states.

What you can do

Build multi-step @keyframes animations

Animate transform, opacity, rotation and scale

Use per-segment timing functions for natural motion

How it works

  1. 01

    Add a property track to the timeline.

  2. 02

    Place and adjust your keyframes.

  3. 03

    Export the generated @keyframes and animation declaration.

Frequently asked questions

What properties can I animate?

MotionCraft focuses on common motion properties such as transforms and opacity, which are generally efficient for browser animation.

Does it create the animation shorthand too?

Yes. Exports include the generated keyframes and the CSS needed to apply the animation.

Open MotionCraft