Aug 31, 2026 · Reflection · 5 min

The button AI can't finish

Any AI will hand you a correct button in seconds. Right radius, right padding, right contrast. What it can't do is finish it, and the difference doesn't show in a screenshot. It shows under your cursor.

Same pixels, different product

Below are two buttons. Same typeface, same radius, same colors, same size. Screenshot them and diff the pixels: identical. Now use them.

generated
finished
Left: correct. Right: finished. The difference never survives a screenshot.

The one on the right responds. It eases into its hover state instead of snapping there. It compresses under your click like something physical, and springs back when you let go. Nothing about the left one could be filed as a bug. It's just not finished.

css
transition: background-color 150ms ease-out,
            transform 150ms ease-out;
button:active { transform: scale(0.97); }
button:focus-visible { outline: 2px solid; outline-offset: 2px; }
The entire difference between the two buttons above. Four values.

What a micro-interaction actually is

A micro-interaction is the interface answering your body. You reach for a button: it acknowledges you. You press: it yields. You release: it comes back. You wait: it tells you it's working. None of this is decoration. It's feedback: the difference between pressing a button and clicking a picture of one.

The whole thing costs a few lines. An ease on hover, a scale to 0.97 on press, a spring on release. Said like that, the work sounds like typing those lines. The work is knowing the numbers.

It dies three times before production

If this layer is that cheap and that important, why does most of the web click like a picture? Because between intent and production, it gets three chances to die.

  • In Figma. A frame can't hold 200 milliseconds. Prototype links simulate navigation, not resistance. The tool that owns design decisions literally cannot represent this one.
  • In the handoff. I've written about the week I spent on a transition that arrived flat on the other side. Redlines carry positions and colors. They have no unit for what a press should feel like.
  • In the prompt. Feel can't be described, only recognized. Ask for “a satisfying press” and the model has to guess which of ten thousand satisfying presses you mean. It picks the median one. The median is exactly what your product shouldn't feel like.
Figma framenot representable
Redlinesnot specifiable
Promptnot describable
Three formats, three deaths. What ships is the picture of the button.

The loading dilemma

Here is where judgment stops being abstract. Press deploy below. The label becomes a spinner, and the button has to decide what happens to its width.

A · default
B · reserved width
C · animated width
Try all three. A jumps, B freezes, C stays one object.

A is the default, and what most generated output ships. B is the safe fix. C is the finished one: the width moves on the same curve as everything else, so the button stays one object instead of becoming two states. No spec chooses between B and C. Your finger does.

css
.label { width: var(--label-width); overflow: hidden;
         transition: width 300ms cubic-bezier(0.22, 1, 0.36, 1); }
.loading .label { width: 20px; }
C, verbatim. A transition, not a keyframe: press again mid-morph and the width retargets instead of snapping.

Why AI, specifically, can't finish it

This is the 70/30 rule at component scale. The model generates the entire button in seconds, so the 70 is free now. But finishing is a judgment about this product, this brand, this user mid-task, and that judgment isn't written anywhere the model can read. It optimizes toward the median of everything that has ever been praised. Your product's feel is, by definition, a deviation from that median.

So AI didn't make micro-interactions less valuable. It made them the differentiator. When every product ships correct, feel is what's left.

The designer who pushes

A micro-interaction can't be handed off. It has to be made in the medium: tuned at 60fps, felt, adjusted, felt again. Which means the person who owns the intent has to be in the code, or the intent dies in translation.

That's not a designer doing an engineer's job. It's the only place this particular design decision can be made. The 200 milliseconds were always design. AI just made everything around them cheap enough that finishing is now the job.