DEV Community

Cover image for I've been building an animation library for years — here's SmoothUI
Edu Calvo
Edu Calvo Subscriber

Posted on

I've been building an animation library for years — here's SmoothUI

TL;DRSmoothUI is a free, open-source collection of 75+ animated React components. shadcn/ui compatible — install any component with npx shadcn@latest add. Every component respects prefers-reduced-motion. MIT licensed. GitHub → educlopez/smoothui.

How it started

A few years ago I wanted to get better at animations. So I started building small things — a card that tilts, a button that reacts to your mouse, a file upload that actually feels alive. No roadmap, no library plans. Just a sandbox to learn.

It grew. At some point it stopped being a sandbox and started being a library.

Then shadcn happened. Then a dozen shadcn-style libraries happened. And it clicked that the thing I'd been quietly building — components with real attention to motion — fit right into that copy-paste, own-your-code model.

So I pivoted. SmoothUI today is two things at once:

  1. A shadcn-compatible library you can install component-by-component
  2. A set of tutorials that teach you how each component works — so if you don't like mine, you can build your own

That second part matters to me. Animation is one of those skills where reading the code isn't enough — you need to understand why a spring has bounce 0.1 instead of 0.3, or why ease-out feels right for entrances but wrong for hovers. The library exists, but the knowledge does too.

5 components I'm proud of

1. Magnetic Button

Magnetic Button demo — button springs toward cursor

The button follows your cursor. Not literally — it springs toward it within a configurable radius, then relaxes back when you leave. It feels like the button is faintly gravitational.

The trick is useSpring motion values mapped to cursor position, clamped to a radius. Dampening on the spring makes it yield instead of lagging.

<MagneticButton strength={0.3} radius={150}>
  Click me
</MagneticButton>
Enter fullscreen mode Exit fullscreen mode

Install: npx shadcn@latest add @smoothui/magnetic-button

2. Scrollable Card Stack

Scrollable Card Stack demo — cards layer with scale + blur on scroll

A stack of cards with real depth. As you scroll, each card scales (~0.08 per layer), blurs, and fades into the one behind it — then snaps with a spring (stiffness 250, damping 20).

The blur is the detail most libraries skip. Without it you get flat layering. With it, your eye buys the illusion.

<ScrollableCardStack items={items} cardHeight={300} />
Enter fullscreen mode Exit fullscreen mode

3. Siri Orb

Siri Orb demo — animated conic gradients

Looks like Apple Intelligence on a good day. Three pastel conic gradients rotating at different multipliers (×1, ×2, ×-3), stacked with a backdrop-blur dot pattern in mix-blend-mode: overlay. No Motion library — pure CSS animating a @property --angle.

The part I want you to notice: blur, contrast, mask radius, and dot size all scale with the component's size prop. It looks intentional at 30px AND at 192px, which is the hard part most "fancy" components skip.

<SiriOrb size="192px" animationDuration={20} />
Enter fullscreen mode Exit fullscreen mode

4. Expandable Cards

Expandable Cards demo — cards grow horizontally on click

Cards that grow horizontally on click — 200px → 500px — using Motion's layoutId to handle the reflow and cubic-bezier (0.23, 1, 0.32, 1) for the ease-out.

The ease-out-quint is the part to study. Regular ease-out feels mechanical. This one snaps forward hard, then settles — which is what "premium" motion usually is underneath.

5. Gooey Popover

Gooey Popover demo — SVG goo filter morphs trigger into content

The popover doesn't appear, it merges out of the trigger. An SVG feGaussianBlur goo filter softens the edges while the shape morphs from circle to rectangle. The math is boring. The effect is not.

<GooeyPopover trigger={<Button>Menu</Button>}>
  <p>Content</p>
</GooeyPopover>
Enter fullscreen mode Exit fullscreen mode

A note on accessibility

All five of these (and every other animated component) call useReducedMotion from motion/react. If your OS has "reduce motion" on, the animations collapse to instant state changes. This is non-negotiable for me — motion libraries without this are broken.

Tech stack

  • React 19 (uses ref-as-prop, no forwardRef dance)
  • Motion (née Framer Motion) 12
  • Tailwind CSS v4
  • shadcn/ui compatible — install one component, keep the code
  • MIT licensed, no dependencies you don't see

Getting started

# Install any component
npx shadcn@latest add @smoothui/magnetic-button

# Or browse everything
https://smoothui.dev
Enter fullscreen mode Exit fullscreen mode

The component lands in your project. It's yours. Tweak the spring, swap the easing, rewrite the filter — the library is a starting point, not a black box.

What's next

I'm working on:

  • An npm-published @smoothui/cli for batch installs
  • An MCP server for AI-assisted component discovery inside Claude / Cursor
  • More tutorials on the "why" behind specific animation choices

If any of this sounds useful, the project lives at smoothui.dev and on GitHub. A ⭐ helps a lot; feedback helps more.

Happy to answer questions about any component, animation decision, or the pivot from sandbox-to-library in the comments.

Top comments (0)