Getting started
Motion
Motion tokens shared by every component, with a live preview for each one. Use them as CSS variables, Tailwind classes or in TypeScript.
Use the tokens
CSS: transition: scale var(--lunia-duration-xl) var(--lunia-ease-out);
Tailwind: duration-xl ease-throw. Reduced motion: motion-reduce:transition-none.
TypeScript: the build also writes motion.ts and a motion.json file in the design token format.
Previews play in a loop.
Duration
Short for small changes, longer for size and distance. Each bar fills in its own duration.
duration-2xs
--lunia-duration-2xs
120ms
Exit fades, tap feedback
duration-xs
--lunia-duration-xs
160ms
Quick exits
duration-sm
--lunia-duration-sm
200ms
Hover, color, small fades
duration-md
--lunia-duration-md
260ms
Fade in, blur in
duration-lg
--lunia-duration-lg
320ms
Color and rotation, chevrons
duration-xl
--lunia-duration-xl
380ms
Move, scale, icon swap
duration-2xl
--lunia-duration-2xl
420ms
Height and size, folds
duration-3xl
--lunia-duration-3xl
460ms
Text morph, large folds
duration-4xl
--lunia-duration-4xl
520ms
Thrown thumbs, arrivals
duration-5xl
--lunia-duration-5xl
640ms
Meters, growing bars, number roll
duration-6xl
--lunia-duration-6xl
900ms
Long number roll
duration-loop
--lunia-duration-loop
1600ms
One cycle of a loop: breathing, sheen
Easing
ease-out is the default and ease-throw overshoots a little. The dot moves with the curve you see.
ease-out
--lunia-ease-out
cubic-bezier(0.16, 1, 0.3, 1)
Default. Enter, move, morph
ease-settle
--lunia-ease-settle
cubic-bezier(0.23, 1, 0.32, 1)
Surfaces that change size, panels
ease-throw
--lunia-ease-throw
cubic-bezier(0.34, 1.36, 0.64, 1)
Small overshoot. Thumbs, pills, arrivals
ease-glide
--lunia-ease-glide
cubic-bezier(0.77, 0, 0.175, 1)
Travel across the screen
ease-loop
--lunia-ease-loop
cubic-bezier(0.45, 0, 0.55, 1)
Loops only
ease-exit
--lunia-ease-exit
ease-out
Short exits
ease-linear
--lunia-ease-linear
linear
Constant speed. Spinners, sheens, timers, caret blink
Stagger
The delay between letters, rows or steps. The cap keeps a long list from feeling slow.
stagger-text
--lunia-stagger-text
16ms
Delay between letters
stagger-list
--lunia-stagger-list
28ms
Delay between rows or bars
stagger-max
--lunia-stagger-max
160ms
Longest total stagger
stagger-step
--lunia-stagger-step
50ms
Delay between pasted items, steps and cards
Scale
How small a hidden icon gets, and how far a pressed button shrinks. Nothing scales from 0.
scale-swap
--lunia-scale-swap
0.6000000238418579
Scale of a hidden icon in a swap
scale-press
--lunia-scale-press
0.9700000286102295
Scale of a pressed button
Blur
A little blur hides the swap between two icons and the arrival of letters.
blur-swap
--lunia-blur-swap
3px
Blur (px) of a hidden icon
blur-text
--lunia-blur-text
4px
Blur (px) of entering letters and text
Distance
How far content rises, shifts or slides. Distances stay small.
distance-rise
--lunia-distance-rise
4px
Content rises in from
distance-nudge
--lunia-distance-nudge
6px
Panel content offset
distance-slide
--lunia-distance-slide
24px
Step and panel slides
Choreography rules
Seven rules decide how motion is put together. Each one has a small live example, and each follows the reduce motion switch above.
1Opacity resolves before movement
Content becomes solid first and stops moving after. The eye reads the content before it reads the path.
Opacity 260ms, move 420ms.
2Exits are about half the entrance
Leaving is quick and uses ease-exit. People have already decided to move on.
In 380ms, out 200ms.
3Content waits for its container
A panel grows first. Its content follows 60 to 120ms later, so text never sits on a moving edge.
Panel 420ms, text starts after 90ms.
4Grow from what was touched
A menu opens from its button, a pill grows from its place. Set the transform origin to that corner.
Transform origin top left, 320ms.
5Never scale from 0, keep distances small
Start at 0.6 or higher and move 4 to 24px. A shape that grows from nothing looks like it is popping in.
Scale 0.6 to 1, rise 4px.
6State changes use transitions
A transition can reverse in the middle. Use keyframes only to enter, to leave and for loops.
Try the switch: click it twice quickly.
7Every motion has a reduced result
When the user asks for less motion, the state still changes, but nothing moves.
Turn on Reduce motion: the color changes, the box stays.