Motion System: Linear
Category: Project Management / Productivity Fast, precise, and physically grounded — motion that feels like a native app, never a website.
Motion Philosophy
Linear's motion is built around the feeling of a high-performance native application. Every transition should communicate speed and control. The product is used by engineers and designers who are sensitive to latency — any animation that feels slow is felt as friction, not polish. Motion earns its place only when it aids orientation or confirms an action.
The physics model is spring-based, but never playful. Springs at Linear's tuning are tight and critically damped — they reach their target quickly and stop cleanly, with no oscillation. This gives interactive elements a satisfying mechanical feel: buttons that respond to pressure, drawers that snap into place, popovers that arrive with intention. The result is motion that feels native because it behaves like the physics of real interface objects, not the bounce of a toy.
Motion must never be expressive for its own sake. Linear does not celebrate, delight, or entertain through animation. If an element is entering, it fades and slides by a small amount — just enough to give the eye a vector without drawing attention to the transition itself. If something exits, it does so quickly. The interface should feel like it is always ready, always fast.
Duration Scale
| Token | Value | Use |
|---|---|---|
| instant | 0ms | State changes with no visual transition (toggling background sync, silent status updates) |
| fast | 100ms | Hover states, checkbox ticks, small icon transitions, tooltip appearance |
| default | 160ms | Most UI transitions: command menu opening, modal appearing, panel sliding |
| slow | 240ms | Page-level view transitions, sidebar expanding/collapsing |
| slower | 400ms | Onboarding coach marks, empty state illustrations entering |
Easing
| Token | Curve | Use |
|---|---|---|
| ease-out | cubic-bezier(0.16, 1, 0.3, 1) | Elements entering the screen — decelerates sharply to rest |
| ease-in | cubic-bezier(0.7, 0, 0.84, 0) | Elements exiting — accelerates quickly away |
| ease-in-out | cubic-bezier(0.45, 0, 0.55, 1) | Elements repositioning within the layout |
| spring | See spring configs | All interactive elements: buttons, toggles, drag handles |
The ease-out curve is notably aggressive — it front-loads the motion so the element appears to arrive almost instantly and merely settles into place. This is central to the native-app feel.
Spring Configs (Framer Motion / react-spring)
- Default: stiffness: 400, damping: 30, mass: 1
- Snappy: stiffness: 600, damping: 35, mass: 0.8
- Tight (for micro-interactions, icon morphs): stiffness: 700, damping: 40, mass: 0.6
- Gentle (for large panel transitions): stiffness: 250, damping: 28, mass: 1
No bouncy config exists in the Linear system. Damping ratios are always at or above critical damping.
Stagger Patterns
- List items: 20ms between each item
- Cards in grid: 30ms between each card
- Command menu results: 15ms between each result
- Children in container: 24ms delay from parent entrance
Stagger is used sparingly — primarily for list items rendering for the first time (e.g., initial load, filtered results). It is not applied to items that already exist in the DOM being rearranged.
Enter / Exit Patterns
Fade + Slide (default for panels, modals, command palette)
enter: opacity 0→1, translateY 6px→0, duration: default (160ms), ease: ease-out
exit: opacity 1→0, translateY 0→-4px, duration: fast (100ms), ease: ease-in
Scale Pop (popovers, context menus, tooltips)
enter: opacity 0→1, scale 0.97→1, duration: fast (100ms), ease: ease-out
exit: opacity 1→0, scale 1→0.97, duration: fast (100ms), ease: ease-in
Slide (command menu, right-hand detail panel)
enter: translateX 100%→0, duration: default (160ms), ease: ease-out
exit: translateX 0→100%, duration: fast (100ms), ease: ease-in
Sidebar / Left Nav Toggle
enter: translateX -100%→0, width animates with layout, duration: slow (240ms), ease: ease-out
exit: translateX 0→-100%, duration: default (160ms), ease: ease-in
Interaction States
- Hover: Subtle background fill transition at 80ms ease-out. No scale. Icon color shifts via CSS transition, not Framer. Feels instantaneous.
- Press/Active: scale(0.97) over 80ms with Default spring config. Releases to scale(1) on pointer-up, same spring. Communicates physical depression.
- Focus: Focus ring appears instantly (0ms) with no transition — using CSS
outline. Keyboard navigation should never be delayed by animation. - Drag: Dragged item scales to 1.02 and gains a shadow over 120ms ease-out. Drop targets pulse opacity 0.5→1 on 160ms ease-in-out loop while dragging over them.
- Loading: Skeleton shimmer using CSS animation: linear gradient moving left-to-right over 1400ms, infinite, no easing. Spinners are 16px, 800ms linear rotation.
Rules
- Respect
prefers-reduced-motion. When set, collapse all durations to 0ms and disable transforms. Spring configs should resolve to their target value immediately. - Never animate layout properties (width, height, padding, margin) directly. Use transforms and opacity — let layout shifts use
layoutprop in Framer Motion so the browser optimizes composite-layer transitions. - Exit animations must be shorter than enter animations. The interface should clear space faster than it fills it.
- Do not stack multiple simultaneous animations on a single element. If an item is entering, it should not also be scaling on hover until the entrance is complete.