Save delight for rare moments

Bounce and confetti belong to first runs, milestones and empty states.

From find-animation-opportunities: delight only at the rare tier.

First invoice sent

Press Send, then push Bounce past 0.3.

FlatBad
INV-0001 Acme Co $1,200.00
display swap, 0ms
Delight budget spentGood
INV-0001 Acme Co $1,200.00
bounce 0.20 · 30ms stagger

const k = (2 * Math.PI / 0.5) ** 2;
const c = (1 - 0.2) * 4 * Math.PI / 0.5;

UILab.spring({ from: 0.6, to: 1, stiffness: k, damping: c,
  onUpdate: (s) => badge.style.setProperty("transform", `scale(${s})`) });

pieces.forEach((p, i) => p.animate(
  [{ transform: "translate(0, 0)", opacity: 1 },
   { transform: `translate(${dx}px, ${dy}px) rotate(${r}deg)`, opacity: 0 }],
  { duration: 900, delay: i * 30, easing: "cubic-bezier(0.23, 1, 0.32, 1)" }));

title.animate([{ opacity: 0, transform: "translateY(6px)" }, { opacity: 1, transform: "none" }],
  { duration: 400, delay: 180, easing: "cubic-bezier(0.23, 1, 0.32, 1)", fill: "backwards" });

Same flourish on every save

Type a note; each keystroke saves.

Celebrates every saveWrong tier
Row 1 No note Saved
0 × 0.95s = 0.0s
Frequent: no motionGood
Row 1 No note Saved
0 × 0s = 0.0s

.saved { opacity: 1; }
if (isFirstEver) celebrate(badge);

An empty state takes its time

Archive all, then compare the two entrances.

StaticBad
  • Linear$96.00
  • Figma$45.00
  • AWS$1,284.31
display swap, 0ms
Gentle entranceGood
  • Linear$96.00
  • Figma$45.00
  • AWS$1,284.31
600ms · text +210ms

const ease = "cubic-bezier(0.23, 1, 0.32, 1)";
illo.animate([{ opacity: 0, transform: "translateY(12px) scale(0.94)" }, { opacity: 1, transform: "none" }],
  { duration: beat, easing: ease });
[heading, body].forEach((el, i) => el.animate(
  [{ opacity: 0, transform: "translateY(6px)" }, { opacity: 1, transform: "none" }],
  { duration: 400, delay: beat * 0.35 + i * 120, easing: ease, fill: "backwards" }));

Why it matters, pros and cons

Why it matters

Celebration means “this mattered” only when rare. Fifty times in, it is latency.

Pros

  • Milestones feel noticed and remembered.
  • Empty states read as intentional.
  • Frequent paths stay instant, giving contrast.

Cons

  • Persist that it played, or it fires every login.
  • Never block the next action while it plays.
  • Skip it for background or destructive outcomes.