MOTION — Good motion is invisible

Applied app-wide on 2 Oct 2026 in ONE commit so it can be rolled back cleanly. Rollback point: branch backup-before-motion = commit 3c45a62 (site exactly as it was before motion).

The six rules

  1. Under 250ms. UI transitions use 150–250ms. Tokens in app/globals.css: --dur-fast 150ms, --dur-base 200ms, --dur-slow 250ms.
  2. Ease out. --ease-out: cubic-bezier(0.25, 1, 0.5, 1) for things appearing on screen.
  3. No overshoot on standard UI (menus, cards, modals, buttons). Springy bounce is only for delight: mascots and success moments.
  4. Transform origin = the trigger. The menu card grows from top-right (the 3-line button). Mascots are anchored to the floor (center bottom).
  5. Reduced motion. prefers-reduced-motion: reduce means fade, don't fly: loops stop, bots stand still, cards fade only.
  6. Transform and opacity only. Never animate width, height, top, left or margin. (The old nav animated height and the burger animated top; both were rewritten.)

Deliberate exceptions (delight)

  • Mascot idle loops, Oracle pulse, logo bob, and the tapped-bot springy bounce. They loop or overshoot on purpose. All stop under reduced motion.

Card motion — Ravneet, 6 Oct 2026 (applies to the timetable card AND every other card)

First used in components/timetable/timetable.css. Reuse these patterns for every new card:

  • Cards on page load: fade + slide up 8px, 250ms ease-out (.tt-card). List rows stagger 40ms (.tt-item).
  • Faculty / status dots on hover: bounce spring, transform only (.tt-dot, 320ms cubic-bezier(0.34,1.56,0.64,1)).
  • Buttons and tabs on click: scale spring to 0.94 (.tt-press) — instant feedback. Approved exception to rule 3.
  • Images: lazy-load and fade in once loaded (.tt-img + .is-loaded).
  • Reduced motion: cards and rows fade only; no bounce, no press scale.
  • TODO: lift these into a shared components/ui/motion.css when the next card type is built, so all cards share one file.

Why we did NOT use a blanket transform: none !important

It would break the 3-line to X icon and decorative glows under reduced motion. We switch off the specific moving things instead.

Checklist for any new UI

  • Uses var(--dur-*) and var(--ease-out), nothing over 250ms (springs: dots 320ms, press 180ms).
  • Animates only transform and opacity.
  • Has a reduced-motion version that fades.

Source: GitHub cetking-one/docs/MOTION.md. Edit the file there; this page updates on the next release.