How Should Buttons Be Animated for Responsiveness: Lessons from emilkowalski/skills

Apply a subtle transform: scale(0.97) on the :active state with a 100–160ms transition using a strong custom ease-out curve (cubic-bezier(0.23, 1, 0.32, 1)) to deliver instant tactile feedback that feels snappy and natural.

Responsive button animation is central to Emil Kowalski's UI polish philosophy documented in the emilkowalski/skills repository. The goal is to provide users with immediate, physical feedback that confirms interactions without introducing perceptible lag or jarring motion. According to the source code analysis, following specific timing, easing, and transform standards ensures buttons feel fast and responsive across all devices.

Core Principles for Responsive Button Animations

Apply Subtle Scaling on Press

The foundation of responsive button feedback lies in a subtle scale transform. In skills/emil-design-eng/SKILL.md (lines 199–210), the recommended approach is to apply transform: scale(0.97) — or within the range of 0.95–0.98 — when the button receives the :active state. This creates a "press-in" effect that mimics physical buttons, giving users immediate confirmation that their touch or click registered.

Optimize Timing and Easing

Duration and easing curves determine whether an animation feels snappy or sluggish. The skills/review-animations/STANDARDS.md file (lines 41–44) specifies a duration between 100–160ms with a strong custom ease-out curve. This timing ensures the motion starts fast and ends gently, creating a responsive feel. The repository defines the specific curve as:

--ease-out: cubic-bezier(0.23, 1, 0.32, 1);

Built-in CSS easings are considered too weak for UI feedback, making this custom curve essential for achieving a punchy, tactile response.

Avoid Scaling From Zero

For entrance animations or state changes, never animate from scale(0). As noted in skills/review-animations/STANDARDS.md (lines 53–55), starting from a value below 0.9 appears unnatural. Instead, begin at scale(0.95) or higher, combining it with an opacity fade if necessary. This maintains the physical plausibility of the interface element.

Prefer CSS Transitions Over Keyframes

CSS transitions offer a critical advantage for responsive buttons: they are interruptible. According to skills/review-animations/STANDARDS.md (lines 69–78), if a user quickly clicks another button, the new animation can overwrite the previous one seamlessly. Keyframe animations, by contrast, can create jarring restarts or queue up awkwardly, degrading the responsive feel.

Implementation Example

The following CSS implements the responsive button pattern found in skills/animate/RECIPES.md and the standards documentation:

/* Core button style using the strong custom ease-out */
.button {
  transition: transform 160ms var(--ease-out);
}

/* Press feedback - scales down slightly on :active */
.button:active {
  transform: scale(0.97);
}

/* Optional overlay for richer feedback */
.button:active .overlay {
  transition: clip-path 200ms ease-out;
  clip-path: inset(0 0 0 0);
}

/* Entrance animation avoiding scale-from-zero */
.entering {
  transform: scale(0.95);
  opacity: 0;
  transition: transform 200ms var(--ease-out), opacity 200ms var(--ease-out);
}

Source Files and Standards

File Purpose
skills/review-animations/STANDARDS.md Defines duration tables, custom easing curves, and performance rules governing button press feedback.
skills/emil-design-eng/SKILL.md Provides the concrete CSS implementation (transform: scale(0.97) on :active) and philosophical rationale for tactile feedback.
skills/animate/RECIPES.md Contains ready-to-use component recipes, including the specific button animation pattern referenced above.

Summary

  • Apply transform: scale(0.97) (or 0.95–0.98) to the :active state to create a tactile "press-in" effect.
  • Use 100–160ms durations with a strong custom ease-out curve (cubic-bezier(0.23, 1, 0.32, 1)) for snappy feedback.
  • Avoid scale(0) entrance animations; start at 0.95 or higher with opacity fades.
  • Prefer CSS transitions over keyframes to ensure animations remain interruptible and responsive to rapid user input.
  • Keep animations under 300ms to stay within the recommended UI animation budget.

Frequently Asked Questions

According to skills/emil-design-eng/SKILL.md, you should apply transform: scale(0.97) when the button enters the :active state. The acceptable range falls between 0.95 and 0.98, creating a subtle "press-in" effect that confirms user interaction without distraction.

Why use a custom easing curve instead of standard CSS easings?

Standard CSS easings like ease-out are too weak for tactile UI feedback. The skills/review-animations/STANDARDS.md file recommends cubic-bezier(0.23, 1, 0.32, 1) because it creates a motion that starts fast and decelerates gently, giving the button press a punchy, responsive feel that built-in curves cannot achieve.

How long should a button press animation last?

The optimal duration falls between 100ms and 160ms as specified in skills/review-animations/STANDARDS.md. This range is short enough to feel instantaneous yet long enough to provide perceptible feedback, keeping the total interaction under the 300ms UI animation budget.

Why are CSS transitions preferred over keyframes for button animations?

CSS transitions are interruptible, meaning if a user rapidly clicks different buttons, the new animation can immediately replace the previous one without jarring restarts or animation queuing. As documented in skills/review-animations/STANDARDS.md (lines 69–78), this property makes transitions superior for maintaining responsiveness during rapid user interactions.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →