Motion System: Supabase
Category: Developer Platform / Backend-as-a-Service Calm, confident, and data-aware — motion that supports exploration without dramatizing infrastructure.
Motion Philosophy
Supabase is a developer platform where the primary content is data: tables, rows, queries, logs, and real-time events. The motion system's first obligation is to never distract from that content. Developers reading a query result or watching a real-time subscription cannot afford to have their attention pulled by animation. Motion is therefore used conservatively, reserved for structural navigation changes and genuine state transitions — not for celebration or flair.
The brand's dark-with-green aesthetic anchors the personality. The Supabase green is not used freely in animation; it appears in motion primarily as a signal — a brief connection-status pulse, a flash when a real-time row insert arrives, the shimmer in a loading skeleton. When that green moves, it means something. This scarcity gives the accent color semantic weight: users learn to read green motion as activity, not decoration.
A secondary consideration is the inherent latency of database operations. Supabase cannot animate query results appearing because results arrive asynchronously — the data IS the content, and it renders as it arrives. This shapes the system toward smooth structural transitions (sidebar navigation, panel opens, modal entrances) while leaving data presentation deliberately static. The interface frames data; it does not perform alongside it.
Duration Scale
| Token | Value | Use |
|---|---|---|
| instant | 0ms | Table row hover highlight, active row selection, syntax highlight in editor |
| micro | 80ms | Button press feedback, icon state changes, tab active indicator |
| fast | 150ms | Tooltip entrance, dropdown open, inline badge transitions |
| default | 200ms | Modal open/close, panel slide, toast notification entrance |
| slow | 280ms | Page-level navigation, sidebar expand/collapse, full-screen overlay |
| deliberate | 450ms | Onboarding flow transitions, first-run empty states |
Easing
| Token | Curve | Use |
|---|---|---|
| ease-out | cubic-bezier(0.16, 1, 0.3, 1) | Elements entering — aggressive deceleration to rest |
| ease-in | cubic-bezier(0.7, 0, 0.84, 0) | Elements exiting — clean acceleration away |
| ease-in-out | cubic-bezier(0.4, 0, 0.2, 1) | Repositioning elements, tab indicator movement |
| linear | linear | Progress bars, loading skeletons, real-time flash keyframes |
| spring | See spring configs | Interactive controls: toggles, drag handles, expandable rows |
The ease-out curve borrows from the broader developer-tool aesthetic — decisively front-loaded so that the element arrives within the first 40% of its duration and merely settles for the remainder. This keeps the interface feeling responsive even at 200ms.
Spring Configs (Framer Motion)
- Default: stiffness: 350, damping: 30, mass: 1
- Snappy (toggles, accordions, expandable table rows): stiffness: 500, damping: 35, mass: 0.85
- Tight (micro-interactions, icon morphs, badge count change): stiffness: 600, damping: 40, mass: 0.7
- Gentle (sidebar, large panel slide): stiffness: 220, damping: 28, mass: 1.1
All configs are critically damped. No bounce. Data-dense interfaces cannot afford oscillating chrome distracting from query output.
Stagger Patterns
- Dashboard cards on page load: 35ms between each card
- Table rows on initial render: no stagger — rows populate as data arrives, stagger would fight async pagination
- Navigation items in sidebar: 20ms between each item, only on first load
- Toast notifications stacking: 40ms between stacked toasts
Stagger is never applied to table data or query results. Those elements render as their data resolves. Stagger is limited to structural chrome elements that load once at session start.
Enter / Exit Patterns
Fade (default for modals, dialogs, overlays)
enter: opacity 0→1, scale 0.98→1, duration: default (200ms), ease: ease-out
exit: opacity 1→0, scale 1→0.98, duration: fast (150ms), ease: ease-in
Slide Panel (table detail, row inspector, right-side sheet)
enter: translateX 100%→0, duration: default (200ms), ease: ease-out
exit: translateX 0→100%, duration: fast (150ms), ease: ease-in
Dropdown / Popover
enter: opacity 0→1, translateY -4px→0, scale 0.97→1, duration: fast (150ms), ease: ease-out
exit: opacity 1→0, translateY 0→-4px, scale 1→0.97, duration: micro (80ms), ease: ease-in
Sidebar Navigation
enter: translateX -100%→0, duration: slow (280ms), ease: ease-out
exit: translateX 0→-100%, duration: default (200ms), ease: ease-in
Real-Time Row Flash (new INSERT from subscription)
keyframes: background transparent→rgba(62,207,142,0.18)→transparent
duration: 800ms, ease: linear, timing: 0ms hold → 200ms fade in → 600ms fade out
Connection Status Pulse (green dot, active subscription indicator)
keyframes: opacity 1→0.4→1, scale 1→0.9→1
duration: 1800ms, ease: ease-in-out, iteration: infinite
pauses when connection is confirmed stable (after 3 cycles)
Interaction States
- Hover (table rows): Background fill transitions at 0ms — instant. Table row hover must feel like cursor tracking, not animation. Using CSS
transition: noneon background in table contexts is correct behavior. - Hover (buttons, nav items): Background fill at 80ms ease-out. No scale changes on non-interactive-feeling elements.
- Press/Active: scale(0.97) over 60ms with Default spring, releases on pointer-up.
- Focus: Focus ring appears at 80ms ease-out with the brand green tint. Keyboard focus never delays.
- Loading skeleton: CSS animation — linear gradient moving left-to-right over 1600ms, infinite, using the dark surface palette with a slight green-tinted highlight at peak.
- Query running: A linear progress bar at the top of the results panel grows from 0% to 85% over an estimated duration (indeterminate behavior: starts fast, slows as it approaches 85%, snaps to 100% on resolve). Duration of snap-to-100%: 200ms ease-out.
- Error state: Element shakes horizontally — translateX keyframes: 0→-4px→4px→-3px→3px→0, total duration 320ms, linear between keyframes. Used on invalid SQL input, failed auth fields.
Rules
- Respect
prefers-reduced-motion. All durations collapse to 0ms; transforms are disabled. The connection status pulse and real-time flash are suppressed entirely — activity must be communicated through color or icon alone when motion is unavailable. - Never animate table cell content or query result text. Data renders as it arrives; applying transitions to async content causes layout thrash and communicates false timing.
- The brand green moves only as a signal. Do not use green color transitions for decorative hover states or non-semantic emphasis. Reserve green motion for connection status, real-time activity, and success confirmation.
- Keep structural motion invisible. A developer navigating the dashboard between Table Editor, Auth, and Storage should feel orientation from transitions, not spectacle. If a user notices the animation rather than the destination, the animation is too much.