Claude
Skills
Sign in
Back

motion-polish

Included with Lifetime
$97 forever

Use this skill when the user wants to add animations, make transitions smooth, add micro-interactions, or apply final polish. Also use when the user says 'my app feels static,' 'add some life to this,' 'make it feel smoother,' 'the transitions are janky,' or 'make this feel like Linear/Stripe.' Covers transition patterns, micro-interactions, page transitions, loading animations, scroll interactions, and the restraint principle.

Sales & CRM

What this skill does


# Motion & Polish

Animation is the final 10% that makes a functional app feel premium. Apply motion to reinforce spatial relationships, confirm user actions, and smooth state changes. This skill covers what to animate, how to animate it, and — most importantly — what to leave alone.

**This skill is for adding motion and animation polish.** For visual design (colors, typography, spacing), use **beautify**. For page layouts and component selection, use **ui-patterns**. For user flow and navigation design, use **ux-design**. For a full design audit, use **design-review**.

## Quick Start

**Tell AI:**
```
Add polish animations to my app. Apply these in order of impact:
1. Button press feedback (subtle scale on click)
2. Hover states on cards and interactive elements
3. Smooth transitions on modals, dropdowns, and side panels
4. Loading skeletons replacing spinners for content areas
5. Toast notification entrance/exit animations

Use CSS transitions where possible (not JS). Respect prefers-reduced-motion.
Keep all durations under 300ms. Use ease-out for entrances, ease-in for exits.
```

## Workflow

```
Add motion polish (in priority order):
- [ ] Button press feedback (active:scale-[0.98])
- [ ] Hover states on cards and list items
- [ ] Modal/dropdown entrance transitions (fade + scale from 95%)
- [ ] Loading skeletons instead of spinners
- [ ] Toast notification entrance/exit
- [ ] Staggered list entrance on page load
- [ ] Reduced motion support (prefers-reduced-motion)
```

**Do these in order.** Each one is independently valuable. Stop whenever it feels like enough.

**Lovable / Replit** — paste the Quick Start prompt above. These tools apply Tailwind transitions directly.

**Claude Code** — use the Quick Start prompt, or point to specific components: "Add hover state animation to the card component in `src/components/Card.tsx`."

---

## The Restraint Principle

What you don't animate matters more than what you do. If a user notices an animation, it's probably too much. Motion should feel like physics — objects have weight, momentum, and settle into place. It should never feel like a performance.

**Hard rules:**

- Never animate something just because you can. Every animation must serve a purpose: confirm an action, maintain spatial context, or guide attention.
- Never animate more than two things simultaneously. The eye can't track it.
- Never add animation during MVP. Ship the product, then polish.
- If removing an animation makes the UI worse, keep it. If removing it changes nothing, delete it.
- When in doubt, use opacity. Fading is the least distracting transition and works in nearly every context.

---

## Timing and Easing

### Duration Guidelines

| Interaction Type | Duration | Why |
|-----------------|----------|-----|
| Micro-interactions (hover, focus) | 100–150ms | Must feel instant. User expects immediate feedback. |
| Element transitions (expand, collapse) | 150–250ms | Enough to see the change, not enough to wait. |
| Page transitions | 200–300ms | Smooth the jarring content swap. |
| Complex sequences (staggered lists) | 200–400ms total | Individual items faster, total sequence under 400ms. |

**Hard ceiling: 500ms.** No UI animation should ever exceed this. Anything longer feels broken, not polished.

### Easing Functions

- **`ease-out`** — For entrances. Element arrives and decelerates into place. Most common easing in UI.
- **`ease-in`** — For exits. Element accelerates away. Use when something is leaving the screen.
- **`ease-in-out`** — For state changes where the element stays on screen (toggle slide, position shift).
- **Never use `linear`** for UI animations. Linear motion has no acceleration — it feels robotic and mechanical. Reserve it for infinite loops like spinners.

### Tailwind Defaults

```
transition-all duration-150 ease-out    /* micro-interactions */
transition-all duration-200 ease-out    /* element transitions */
transition-all duration-300 ease-in-out /* page/state transitions */
```

For custom easing, define `cubic-bezier` values in your Tailwind config. A good general-purpose curve: `cubic-bezier(0.4, 0, 0.2, 1)` (Material Design standard).

---

## Transition Patterns

### Fade

Use for content replacing content — tab changes, page loads, image swaps.

```css
/* CSS */
.fade-enter { opacity: 0; }
.fade-enter-active { opacity: 1; transition: opacity 200ms ease-out; }
.fade-exit-active { opacity: 0; transition: opacity 150ms ease-in; }
```

Tailwind: `transition-opacity duration-200 ease-out`

Fade is the safest default. When unsure which transition to use, fade.

### Slide

Use for panels, drawers, mobile menus, and side sheets. The direction must match the trigger — a left sidebar slides in from the left, a bottom sheet slides up from the bottom.

```css
/* Slide from right (for side panels) */
.panel { transform: translateX(100%); transition: transform 250ms ease-out; }
.panel.open { transform: translateX(0); }
```

Tailwind for a right panel: `translate-x-full` → `translate-x-0` with `transition-transform duration-250 ease-out`

### Scale

Use for modals, tooltips, popovers, and dropdown menus. Scale from 95% to 100% — not 0% to 100%. The subtle 5% scale change adds life without being dramatic.

```css
.modal { opacity: 0; transform: scale(0.95); transition: all 200ms ease-out; }
.modal.open { opacity: 1; transform: scale(1); }
```

Tailwind: `scale-95 opacity-0` → `scale-100 opacity-100` with `transition-all duration-200 ease-out`

Always combine scale with fade. Scale alone looks jarring.

### Expand / Collapse

Use for accordions, detail disclosures, and expandable sections. Animate `max-height` or `grid-template-rows` — not `height`, which requires knowing the exact pixel value.

```css
/* Modern approach using grid */
.collapsible { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 250ms ease-in-out; }
.collapsible.open { grid-template-rows: 1fr; }
.collapsible > div { overflow: hidden; }
```

Tailwind: Use `grid` with `grid-rows-[0fr]` → `grid-rows-[1fr]` and `transition-all duration-250 ease-in-out`. The inner content needs `overflow-hidden`.

---

## Micro-Interactions

These are the small details that make an app feel alive. Each one takes minutes to implement and compounds into a premium feel.

### Button Feedback

Add a subtle scale on press. Not on hover — on active press.

```
active:scale-[0.98] transition-transform duration-100 ease-out
```

Never go below `scale-[0.95]` — it looks broken, not responsive.

### Hover States

Go beyond color change. Combine two properties for a richer feel:

```
hover:shadow-md hover:-translate-y-0.5 transition-all duration-150 ease-out  /* cards */
hover:bg-gray-100 transition-colors duration-100 ease-out                    /* list items */
```

For primary action buttons, darken the background. For cards, elevate with shadow. For list items, add a background.

### Toggle / Switch

The thumb should slide smoothly, and the track color should transition:

```
/* Track */
transition-colors duration-200 ease-in-out

/* Thumb */
transition-transform duration-200 ease-in-out
```

### Checkbox and Radio

Add a scale bounce on check. The checkmark appears at `scale-100` from `scale-0`:

```
transition-all duration-150 ease-out
```

Do not add rotation or complex keyframes to checkboxes. A simple scale entrance is enough.

### Input Focus

Expand the focus ring outward. Combine `ring` with a color transition on the border:

```
focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-all duration-150 ease-out
```

For floating labels, translate the label up and scale it down simultaneously:

```
/* Label moves from inside input to above it */
peer-focus:-translate-y-6 peer-focus:scale-75 transition-all duration-200 ease-out
```

### Link Hover

Animate the underline rather than toggling it. Use a pseudo-element that scales from 0 to 100% width:

```css
a { text-decoration: none; position: relative; }
a::after { content: '';

Related in Sales & CRM