steps()
steps() is a GSAP ease that quantizes a tween's progress into a fixed number of discrete jumps instead of interpolating smoothly, so the animated value snaps between set positions. It's how you get a mechanical, tick-by-tick feel: typewriter reveals, odometer digits, a clock's second hand, sprite-sheet frames.
Updated July 1, 2026
How steps() works
Every other ease returns a continuous value as the tween plays. steps(n) rounds that value to the nearest of n evenly spaced plateaus, so the property holds, then jumps, n times across the duration. There are no in-between frames. With steps(6) the tween moves through 6 hard jumps and the element never shows a value that sits between two of them.
It's the core SteppedEase, so nothing extra to register. Pass the count in the string form and GSAP does the rest:
The graph is a staircase, not a curve. That's the whole point: motion that reads as increments, not as sliding. A higher n gives more, smaller ticks (approaching smooth as n climbs); a lower n gives fewer, chunkier jumps.
Use it for
- Typewriter reveals where one character should appear per beat, no fade or slide between them
- Number counters that should tick through visible integers like an odometer instead of blurring up to the total
- Sprite-sheet or frame-by-frame animation, where you're stepping a background-position through fixed cells
- A clock's second hand, a loading tick, a segmented progress bar filling one block at a time
- Any UI where the intended feel is mechanical and discrete rather than fluid
Use something else when
- You want smooth, responsive UI motion, that's
expo.outorpower3.out, not a staircase - You need a custom curve with hold-and-release character but not hard snaps, use
CustomEase - You only need to land values on a grid (nearest 10px, nearest integer) while the motion itself stays smooth, use GSAP's
snaputility on the property, not a stepped ease - The effect is pure CSS with no timeline logic, native CSS
steps()inanimation-timing-functiondoes the same job with zero JS
GSAP steps() vs CSS steps()
steps(n, start) jumps at the beginning of each interval and steps(n, end) (the default) jumps at the end. GSAP's steps(n) is a single stepped curve you drop into a tween or timeline, so you get sequencing, pausing, and reversal for free. Most stepped motion in the wild is still CSS: 91.7% of mobile pages ship a CSS transition while only 18.4% load a JS animation library at all (HTTP Archive Web Almanac, 2024).Used in these Annnimate components
Two Annnimate components live on this discrete, tick-by-tick cadence, even where they reach it through a timeline rather than the ease directly:
- Typewriter reveals one character at a time so the caret advances in fixed jumps instead of sliding. It builds that with a per-character timeline, and
steps()is the single-tween way to get the same mechanical reveal when you don't need per-character timing control. - Counter rolls a number up to its target and reformats the value every frame. It rides
power3.inOutfor a smooth ramp, but swap that forsteps()and the digits tick in visible increments, the odometer feel instead of the blur.
Watch the count
See it running in production
Common questions
- Does GSAP's steps() need EasePack?
- No. steps() is the core SteppedEase, included in gsap itself, so you can write
ease: "steps(6)"without importing or registering anything. EasePack adds RoughEase, SlowMo, and ExpoScaleEase, none of which you need for stepped motion. And since GSAP 3.13 every plugin is free anyway, so there's no paywall to worry about either way. - How is GSAP steps() different from CSS steps()?
- Same staircase output, different control. CSS
steps()lives inanimation-timing-functionand takes a direction (startorend) that decides whether the jump happens at the front or back of each interval. GSAP'ssteps(n)is an ease you pass to a tween or timeline, so it inherits GSAP's play/pause/reverse/scrub and sequencing. Reach for CSS steps() on a self-contained keyframe animation, GSAP steps() when the stepped move is part of a larger timeline. - How many jumps does steps(6) actually produce?
- Six discrete increments across the tween. The value holds on a plateau, jumps, and repeats until it reaches the end. If your animation looks like it has one too many or too few stops, that's almost always a mismatch between the step count and the number of real positions you're moving through (frames in a sprite sheet, digits in an odometer). Set the count to the number of positions, not a round guess.
- Can I use steps() for a typewriter effect?
- Yes, if you're revealing a fixed-width block character by character (for example animating a
widthor a clip that exposes one glyph per step). steps(numberOfCharacters) makes each character appear on its own beat with no fade. For variable-width type or human-typing jitter, a per-character timeline gives you more control, which is how the Annnimate Typewriter is built. steps() is the quick single-tween version. - steps() vs snap for ticking numbers?
- Different jobs.
steps()quantizes the tween's PROGRESS, so the whole motion moves in jumps at fixed time intervals. GSAP'ssnapquantizes the VALUE, so the motion can still ease smoothly but only ever lands on allowed values (nearest integer, nearest 10). For an odometer that ticks on a rhythm, steps(). For a value that eases in but must settle on whole numbers, snap the property and keep a smooth ease.
onMounted once the DOM exists, scope them to the component with a template ref, and kill them in onUnmounted.