# Proportional Animation Values

**SHOULD** · **ID:** `animations-proportional-values` · **Category:** animations
**Source:** [Rauno](https://interfaces.rauno.me/)
**Interactive version:** https://ui-guides-agent-rules.netlify.app/principles/animations-proportional-values

> SHOULD: Keep animation values proportional to the element: dialogs scale from ~0.95–0.8 (never 0), buttons compress to ~0.96 on press (never 0.8).

Animation values should be proportional to the trigger size — don't scale from 0, use subtle values

Exaggerated animations feel cartoonish and disproportionate. A dialog appearing should scale from 0.95, not 0. A button press should compress to 0.97, not 0.5. Match the animation magnitude to the element's visual size and the interaction's importance.

## Bad — do not do this

`animations-proportional-animation-bad`

```tsx
import { useState } from 'react';

export function ProportionalAnimationBad() {
  const [showDialog, setShowDialog] = useState(false);

  return (
    <div className="w-full max-w-sm space-y-4">
      <div className="bg-card border border-border rounded-lg p-4 space-y-3">
        <button
          onClick={() => setShowDialog(true)}
          className="px-4 py-2 bg-primary text-primary-foreground rounded-lg text-sm active:scale-50 transition-transform"
        >
          Open Dialog
        </button>
        {showDialog && (
          <div
            className="bg-card border border-border rounded-lg p-4 shadow-lg animate-in zoom-in-0 duration-300"
          >
            <h4 className="text-sm font-medium text-foreground mb-2">Confirm Action</h4>
            <p className="text-sm text-muted-foreground mb-3">Are you sure you want to proceed?</p>
            <div className="flex gap-2 justify-end">
              <button onClick={() => setShowDialog(false)} className="px-3 py-1.5 text-sm border border-border rounded text-foreground">Cancel</button>
              <button onClick={() => setShowDialog(false)} className="px-3 py-1.5 text-sm bg-primary text-primary-foreground rounded">Confirm</button>
            </div>
          </div>
        )}
      </div>
      <p className="text-xs text-error">Dialog scales from 0 → 1, button shrinks to 0.5 — disproportionate</p>
    </div>
  );
}
```

## Good — do this

`animations-proportional-animation-good`

```tsx
import { useState } from 'react';

export function ProportionalAnimationGood() {
  const [showDialog, setShowDialog] = useState(false);

  return (
    <div className="w-full max-w-sm space-y-4">
      <div className="bg-card border border-border rounded-lg p-4 space-y-3">
        <button
          onClick={() => setShowDialog(true)}
          className="px-4 py-2 bg-primary text-primary-foreground rounded-lg text-sm active:scale-[0.97] transition-transform"
        >
          Open Dialog
        </button>
        {showDialog && (
          <div
            className="bg-card border border-border rounded-lg p-4 shadow-lg"
            style={{
              animation: 'proportional-fade-in 150ms ease-out forwards',
            }}
          >
            <style>{`
              @keyframes proportional-fade-in {
                from { opacity: 0; transform: scale(0.95); }
                to { opacity: 1; transform: scale(1); }
              }
            `}</style>
            <h4 className="text-sm font-medium text-foreground mb-2">Confirm Action</h4>
            <p className="text-sm text-muted-foreground mb-3">Are you sure you want to proceed?</p>
            <div className="flex gap-2 justify-end">
              <button onClick={() => setShowDialog(false)} className="px-3 py-1.5 text-sm border border-border rounded text-foreground">Cancel</button>
              <button onClick={() => setShowDialog(false)} className="px-3 py-1.5 text-sm bg-primary text-primary-foreground rounded">Confirm</button>
            </div>
          </div>
        )}
      </div>
      <p className="text-xs text-success">Dialog scales from 0.95, button to 0.97 — proportional to size</p>
    </div>
  );
}
```

## References

- [interfaces.rauno.me](https://interfaces.rauno.me/)
