MotionKitDesign motion. Export CSS.
59/59
Canvas
Surface
Border
Radius16pxSize60%
0.00s / 0.70s
Keyframes
0%
50%
100%
0%
100%
Slide Up
.mk-slide-up
Entrance
Durationms
Delayms
cubic-bezier(0.22, 1, 0.36, 1)
Keyframe position%
Translate Xpx
Translate Ypx
Translate Zpx
Scale×
Rotatedeg
Rotate X (3D)deg
Rotate Y (3D)deg
Skewdeg
Opacity
Blurpx
Brightness
Hue rotatedeg
Border radiuspx
Element color
Generated code
14 lines · 260 bytes · 0 of 5 options on
/* MotionKit — Slide Up */
.mk-slide-up {
  animation: mk-slide-up-kf 700ms cubic-bezier(.22,1,.36,1) 0ms 1 normal both;
}

@keyframes mk-slide-up-kf {
  0% {
    opacity: 0;
    transform: translate3d(0px, 48px, 0px);
  }
  100% {
    transform: none;
  }
}
Overview

A CSS animation generator that treats timing, easing and keyframes as one problem

Part of CSS LabKit, built by GrowQuest, leaders in web experiences.

Most tools in this space pick a single piece of the animation puzzle and stop there. You get a keyframes generator that outputs a fade or a slide with two flat states, or you get an easing curve tool that shows a pretty S-curve with nothing attached to it — no element moving, no timeline, no way to see what that curve actually does to a real multi-stop animation. Neither tells you what your animation looks like at the 340ms mark of a 600ms run, because neither has a timeline to ask.

MotionKit is built as one connected system: pick a preset with real multi-stop @keyframes, scale its motion up or down, shape the curve between each stop with a fully draggable cubic-bezier editor, then scrub the timeline to see any point in the animation on demand. Change the easing and the scrub position updates live, so cause and effect stay visible instead of requiring a mental model. The output is plain CSS — a @keyframes block and an animation shorthand that work with or without a framework.

Timing, easing and keyframes as one system

Drag the bezier curve and scrub the timeline in the same view, so cause and effect stay visible instead of requiring a mental model.

Real multi-stop presets

24 presets built from actual intermediate keyframes, not a single from/to pair scaled by a slider.

Framework-agnostic output

Plain @keyframes and an animation shorthand — nothing tied to a JS animation library or a specific build tool.

Features

What you can do with MotionKit

24 preset animations with real multi-stop keyframesentrances, exits, attention-seekers and loops, each built from actual intermediate stops rather than a single from/to pair.
Motion amount sliderscales every stop's translate, scale and rotate values up or down in one control, so a preset can be subtler or more dramatic without hand-editing percentages.
Scrubbable timelineclick or drag to seek to any point in the animation, with read-only markers at each preset's actual keyframe offsets.
Draggable cubic-bezier editorboth control-point handles move freely on the curve, not a dropdown of ease / ease-in-out presets, with the preview updating as you drag.
Full timing controlsduration, delay, iteration count (including infinite), direction, fill-mode and play state, all exposed directly.
Live card previewsee the animation on an actual element with adjustable canvas, surface, border, radius and size instead of imagining it from numbers.
Tabbed code outputCSS keyframes, HTML, and a JS-trigger snippet, with format, minify and comment toggles that default to off.
Undo/redo and keyboard shortcutsevery change to a preset or timing value sits on the history stack, so experimenting doesn't mean losing your last good state.
Framework-agnostic outputthe generated CSS is vanilla @keyframes and animation — nothing tied to a JS animation library or a specific build tool.
Runs entirely client-sideno round trip to a server for preview or export — the timeline scrubs and the curve drags in real time.
The science

What the browser is actually doing during a CSS animation

Every control maps to a real mechanism in the rendering engine. Understanding it explains the common failure modes — the animation that jumps back at the end, the one that stutters, the easing curve that looks wrong.

What @keyframes actually declares

A @keyframes rule is a named list of property states tied to percentages of a single animation cycle. The browser interpolates every animatable property between consecutive stops for you — you're describing checkpoints, not motion frame by frame. That's why a three-stop keyframe can produce an overshoot-and-settle motion a plain two-stop transition structurally cannot.

What the four cubic-bezier numbers mean

cubic-bezier(x1, y1, x2, y2) defines a curve from a fixed start (0,0) to a fixed end (1,1), with two control points bending it. The x-values are clamped to 0–1 because they represent time, but the y-values — progress — can go negative or past 1, which is exactly how you get anticipation or overshoot. Keyword values like ease-out are just named shorthand for specific control-point coordinates.

Why transform/opacity are cheap and top/left/width aren't

Animating transform and opacity can run entirely on the compositor thread — the browser hands the element off as its own layer and repositions or fades it each frame with no layout or paint. Animating top, left, width or margin forces layout recalculation on every frame, the layout-thrashing that makes an animation feel janky on lower-end hardware.

animation-fill-mode: what happens outside the active interval

By default an element snaps back to its pre-animation styles the instant the animation ends. forwards keeps it at its last keyframe's styles after completion; backwards applies the first keyframe's styles during any delay instead of the element's normal CSS. Skipping forwards is the usual cause of “it plays but then jumps back.”

animation vs. transition

A transition interpolates a property between two states in response to a trigger and needs that trigger to exist — a hover, a class toggle. An animation is self-contained: it runs from its own @keyframes, doesn't need an external state change to start, can have any number of stops, and can loop with animation-iteration-count: infinite.

prefers-reduced-motion, and how negative animation-delay seeks

prefers-reduced-motion: reduce reflects an OS-level accessibility setting — large or fast motion genuinely triggers vestibular discomfort for some users, so respecting it matters. Separately, animation-delay accepts negative values: -2000ms on a 5-second animation begins already two seconds in. Pausing the animation and setting a negative delay proportional to a scrub position is exactly how the timeline scrubber works.

CSS anatomy

Anatomy of the CSS behind a keyframe animation

A realistic multi-stop entrance animation, close to what a preset in the tool produces:

@keyframes fade-in-up {
  0% {
    opacity: 0;
    transform: translateY(24px) scale(0.96);
  }
  60% {
    opacity: 1;
    transform: translateY(-4px) scale(1.01);
  }
  100% {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.card {
  animation: fade-in-up 600ms cubic-bezier(0.22, 1, 0.36, 1) 100ms 1 normal forwards;
}
fade-in-upThe keyframe name, linking the @keyframes block to the animation shorthand — must match exactly.0%, 60%, 100%Checkpoints in the cycle; the browser interpolates every property between them. The 60% stop is what produces the overshoot before settling.600msTotal duration for one full cycle, start stop to end stop.
cubic-bezier(0.22, 1, 0.36, 1)Shapes the rate of change across the cycle — this one is a fast-out, gentle-settle curve.100msDelay before the animation starts; during this window the element shows its 0% styles only if fill-mode includes backwards.1 normal forwardsIteration count, playback direction, and fill-mode — forwards keeps the element at its 100% styles after the animation ends instead of reverting.
Best practices

Best practices & design principles

Match duration to the size of the change

Micro-interactions — a button press, a toggle — read best around 150–250ms. Page-level transitions or larger reveals can stretch to 300–500ms without feeling sluggish, since the eye has more visual distance to track.

Let easing communicate direction, not just smooth things out

Entrances generally read better with ease-out (fast start, gentle arrival), mimicking something arriving under its own momentum. Exits read better with ease-in (gentle start, fast departure). Using the same curve for both is a common reason motion feels flat.

Animate one or two properties at a time

Stacking simultaneous changes to opacity, transform, colour and shadow on the same element reads as noisy rather than rich. Pick the property or two that actually carry the meaning of the transition and let the rest stay static.

Default to transform and opacity

They're compositor-friendly and won't trigger layout — worth treating as the default and everything else as a special case, especially on lower-powered devices or when several elements animate at once.

Always account for prefers-reduced-motion

At minimum, drop large translates and scales toward zero or swap to a plain opacity fade when the OS setting is enabled. It's a small conditional and the right default, not an edge case to skip.

Keep a small, consistent set of easing curves across a UI

Reusing the same two or three timing functions for entrances, exits and hover states makes an interface's motion feel like one coherent system rather than a pile of individually-tuned effects.

Why we built it

Why MotionKit exists

CSS animation ends up split across too many single-purpose tools: one site for browsing keyframe presets, a different one for dragging a bezier curve, a third for a timing-function cheat sheet — and none of them show what an easing curve actually does to a multi-stop animation over time, because none of them have both attached to the same timeline.

MotionKit puts the pieces where they belong: pick real motion, shape its curve, scrub through it, and see the exact CSS that produces what's on screen. It's built to hold up whether you're picking your first easing value or tuning the twentieth micro-interaction of a design system, and the output stays something you'd actually want to commit — plain @keyframes and an animation shorthand, not a wrapper around a runtime dependency.

If you're new to this

Start from a preset, watch it play, then drag the timeline to see exactly what's happening at any point in the cycle — you'll understand cubic-bezier() faster by dragging the curve than by reading about it.

If you do this daily

Skip straight to motion-amount and timing controls on a preset that's close, tune the curve by eye against the scrubbed timeline, and copy CSS that's already close to commit-ready.

Honest output

Every toggle for comments, CSS variables and minification defaults to off. What you copy is the CSS you saw animate, nothing extra bolted on unless you ask for it.

Alternatives

A better alternative to Animista, cubic-bezier.com and Ceaser

Animista, cubic-bezier.com and Ceaser are all genuinely useful and well known for good reason — but each solves a narrower slice of the problem than a full animation build usually needs.

Animista gives you a large library of ready-made effects with timing and easing controls, but its easing input is a fixed set of named/preset curves rather than a freely draggable bezier editor, and there's no scrubbable timeline to inspect an in-progress frame.
cubic-bezier.com (Lea Verou's tool) is still the canonical way to visually reason about a bezier curve, but it's deliberately just the curve — no keyframe animation attached to see how it behaves across multiple stops, and no timeline.
Ceaser (Matthew Lein) pairs a bezier editor with a live preview, closer to a complete workflow — but the preview is a simple transition demo rather than a multi-stop keyframe animation, so it doesn't show how a curve interacts with an intermediate stop like an overshoot.
One curve editor, wired to a real multi-stop animation — drag the bezier handles and watch how the curve actually shapes motion between three or more keyframe stops, not a two-point demo.
A timeline, not just play/pause — scrub to any frame instead of only watching the animation run start to finish.
Multiple export formats from one source of truth — CSS keyframes, HTML and a JS-trigger snippet generated from the same animation state, so they stay in sync with each other.
FAQ

Frequently asked questions about CSS animation

What's the difference between a CSS animation and a CSS transition?

A transition interpolates a property between two states in response to a trigger — a hover, a class change — and stops existing once that interpolation finishes. An animation is defined independently via @keyframes, can have any number of intermediate stops, doesn't need a trigger to start, and can loop with animation-iteration-count: infinite.

Which CSS properties are safe to animate for performance?

transform and opacity are the two that can run on the compositor thread without triggering layout or paint, which is why they're the standard recommendation for smooth animation. Properties like top, left, width, height and margin force layout recalculation on every frame and are worth avoiding for anything performance-sensitive.

What do the four numbers in cubic-bezier() mean?

They're two control points, (x1, y1) and (x2, y2), bending a curve running from a fixed (0,0) to a fixed (1,1). The x-values (time) are clamped between 0 and 1; the y-values (progress) can go outside that range, which is how you get overshoot or anticipation effects.

Why does prefers-reduced-motion matter for CSS animations?

It reflects an OS-level accessibility setting for users who experience real discomfort — nausea, vestibular symptoms — from large or fast motion, so respecting it is an accessibility requirement, not a nice-to-have. A common pattern is dropping translate/scale magnitude toward zero or falling back to a plain fade when the setting is active.

How do I make my CSS animation start partway through, like a scrubber?

Set animation-delay to a negative value. A negative delay tells the browser to act as if the animation had already been running for that long, so -2000ms on a 5-second animation starts already two seconds in — pairing this with animation-play-state: paused and updating the delay on drag is how a scrubbable timeline is built.

What's the difference between animation-fill-mode: forwards and backwards?

forwards keeps the element at its final keyframe's computed styles after the animation ends, instead of reverting to its pre-animation CSS. backwards applies the first keyframe's styles during any animation-delay, instead of the element's normal styles showing during that wait.

Can I use generated CSS animations without a JavaScript library?

Yes — @keyframes and the animation property are plain CSS, supported natively without any runtime dependency. A JS trigger snippet is only needed if you want to start or restart the animation in response to a script-driven event rather than a CSS state like :hover or a class toggle.

How long should a UI animation last?

It depends on scale: small feedback like a button press or toggle typically reads best around 150–250ms, while a larger transition — a panel opening, a page-level change — can extend to 300–500ms. Longer than that tends to feel like it's slowing the user down.

References

Specs and further reading