.cursor/skills/animation-best-practices/SKILL.md
CSS and UI animation patterns for responsive, polished interfaces. Use when implementing hover effects, tooltips, button feedback, transitions, or fixing animation issues like flicker and shakiness.
npx skillsauth add aidenybai/react-scan animation-best-practicesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Detailed reference guide for common animation scenarios. Use this as a checklist when implementing animations.
When something feels off but you can't identify why, record the animation and play it back frame by frame. This reveals details invisible at normal speed.
Elements may shift by 1px at the start/end of CSS transform animations due to GPU/CPU rendering handoff.
Fix:
.element {
will-change: transform;
}
This tells the browser to keep the element on the GPU throughout the animation.
Don't code and ship animations in one sitting. Step away, return with fresh eyes. The best animations are reviewed and refined over days, not hours.
Make interfaces feel responsive by adding subtle scale feedback:
button:active {
transform: scale(0.97);
}
This gives instant visual feedback that the interface is listening.
Starting from scale(0) makes elements appear from nowhere—it feels unnatural.
Bad:
.element {
transform: scale(0);
}
.element.visible {
transform: scale(1);
}
Good:
.element {
transform: scale(0.95);
opacity: 0;
}
.element.visible {
transform: scale(1);
opacity: 1;
}
Elements should always have some visible shape, like a deflated balloon.
First tooltip: delay + animation. Subsequent tooltips (while one is open): instant, no delay.
.tooltip {
transition:
transform 125ms ease-out,
opacity 125ms ease-out;
transform-origin: var(--transform-origin);
}
.tooltip[data-starting-style],
.tooltip[data-ending-style] {
opacity: 0;
transform: scale(0.97);
}
/* Skip animation for subsequent tooltips */
.tooltip[data-instant] {
transition-duration: 0ms;
}
Radix UI and Base UI support this pattern with data-instant attribute.
Popovers should scale from their trigger, not from center.
/* Default (wrong for most cases) */
.popover {
transform-origin: center;
}
/* Correct - scale from trigger */
.popover {
transform-origin: var(--transform-origin);
}
Radix UI:
.popover {
transform-origin: var(--radix-dropdown-menu-content-transform-origin);
}
Base UI:
.popover {
transform-origin: var(--transform-origin);
}
A faster-spinning spinner makes apps feel faster even with identical load times. A 180ms select animation feels more responsive than 400ms.
Rule: UI animations should stay under 300ms.
Arrow key navigation, keyboard shortcuts—these are repeated hundreds of times daily. Animation makes them feel slow and disconnected.
Never animate:
A hover effect is nice, but if triggered multiple times a day, it may benefit from no animation at all.
Guideline: Use your own product daily. You'll discover which animations become annoying through repeated use.
When hover animation changes element position, the cursor may leave the element, causing flicker.
Problem:
.box:hover {
transform: translateY(-20%);
}
Solution: Animate a child element instead:
<div class="box">
<div class="box-inner"></div>
</div>
.box:hover .box-inner {
transform: translateY(-20%);
}
.box-inner {
transition: transform 200ms ease;
}
The parent's hover area stays stable while the child moves.
Touch devices don't have true hover. Accidental finger movement triggers unwanted hover states.
@media (hover: hover) and (pointer: fine) {
.card:hover {
transform: scale(1.05);
}
}
Note: Tailwind v4's hover: class automatically applies only when the device supports hover.
Small buttons are hard to tap. Use a pseudo-element to create larger hit areas without changing layout.
Minimum target: 44px (Apple and WCAG recommendation)
@utility touch-hitbox {
position: relative;
}
@utility touch-hitbox::before {
content: "";
position: absolute;
display: block;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100%;
height: 100%;
min-height: 44px;
min-width: 44px;
z-index: 9999;
}
Usage:
<button className="touch-hitbox">
<BellIcon />
</button>
Elements entering or exiting should use ease-out. The fast start creates responsiveness.
.dropdown {
transition:
transform 200ms ease-out,
opacity 200ms ease-out;
}
ease-in starts slow—wrong for UI. Same duration feels slower because the movement is back-loaded.
Elements already visible that need to move should use ease-in-out. Mimics natural acceleration/deceleration like a car.
.slider-handle {
transition: transform 250ms ease-in-out;
}
Built-in CSS curves are usually too weak. Custom curves create more intentional motion.
Resources:
When easing and timing adjustments don't solve the problem, add subtle blur to mask imperfections.
.button-transition {
transition:
transform 150ms ease-out,
filter 150ms ease-out;
}
.button-transition:active {
transform: scale(0.97);
filter: blur(2px);
}
Blur bridges visual gaps between states, tricking the eye into seeing smoother transitions. The two states blend instead of appearing as distinct objects.
Performance note: Keep blur under 20px, especially on Safari.
"All those unseen details combine to produce something that's just stunning, like a thousand barely audible voices all singing in tune." — Paul Graham, Hackers and Painters
Details that go unnoticed are good—users complete tasks without friction. Great interfaces enable users to achieve goals with ease, not to admire animations.
tools
Use when work should span one or more detached tasks but still behave like one job with a single owner context. TaskFlow is the durable flow substrate under authoring layers like Lobster, ACPX, plugins, or plain code. Keep conditional logic in the caller; use TaskFlow for flow identity, child-task linkage, waiting state, revision-checked mutations, and user-facing emergence.
tools
# Lobster Lobster executes multi-step workflows with approval checkpoints. Use it when: - User wants a repeatable automation (triage, monitor, sync) - Actions need human approval before executing (send, post, delete) - Multiple tool calls should run as one deterministic operation ## When to use Lobster | User intent | Use Lobster? | | ------------------------------------------------------ | --------------------------
tools
# Lobster Lobster executes multi-step workflows with approval checkpoints. Use it when: - User wants a repeatable automation (triage, monitor, sync) - Actions need human approval before executing (send, post, delete) - Multiple tool calls should run as one deterministic operation ## When to use Lobster | User intent | Use Lobster? | | ------------------------------------------------------ | --------------------------
tools
A CLI tool for making authenticated requests to the X (Twitter) API. Use this skill when you need to post tweets, reply, quote, search, read posts, manage followers, send DMs, upload media, or interact with any X API v2 endpoint.