Motion demo
Buttons with a brain
One button component, two instances. Click for a real 20% random failure rate, or use the force triggers to see success and error on demand. Tab to a button and press Enter/Space to try it with a keyboard.
Send message
Real 20% random failure rate — click it a few times to see both outcomes naturally, or force one below.
Add to cart
Same component, different copy/icon/tone — proving the motion language is a system, not a one-off.
Duration & easing choices
- 150ms ease-out for hover/press (background-color, active:scale) — fast enough to feel like a direct response to the cursor, not a delayed effect.
- 200ms ease-out for the idle/loading/error cross-fades — matches the
tool-fade-intiming already used for the assistant's tool cards, so the whole app shares one motion vocabulary. - 200ms with a small overshoot (cubic-bezier(0.34, 1.56, 0.64, 1)) for the success checkmark — success is the one moment worth a tiny bit of delight instead of a flat linear fade.
- 400ms shakeon error, transform-only (translateX) — skipped entirely under prefers-reduced-motion (see the global rule in globals.css); the red color and "Retry" label still carry the message without any motion.
- All layers live in the same grid cell and animate only
opacity/transform— the button's box size never changes, so there's no layout thrash to reflow around it.