Motion System: Cursor
Category: AI Code Editor / Developer Tool Instant where it must be, spring-grounded where it should be — motion at the speed of thought.
Motion Philosophy
Cursor inherits VS Code's institutional expectation of near-zero latency and then raises the bar. Developers running Cursor have calibrated their nervous systems to VS Code's responsiveness; any regression from that baseline is immediately felt as sluggishness, not softness. Motion is therefore budgeted tightly: most transitions live in the 80–120ms range, and anything touching the text cursor, caret movement, or syntax highlighting carries a strict 0ms mandate. The editor surface is never animated. Only the chrome moves.
The physics model borrows from native macOS panel behavior: panels, the file tree, and sidebars use springs rather than duration-based easing. This makes resize and open/close feel like moving a physical object — the panel has weight that decelerates naturally rather than cutting off at an arbitrary millisecond. But the spring tuning is tight, critically damped, and never bouncy. Cursor would read as broken if a panel oscillated. The spring exists to provide a natural deceleration curve, not to communicate elasticity.
AI-specific surfaces — the inline diff view, the composer panel, the chat sidebar — enter with a subtle scale-fade that communicates arrival without performing excitement. Streaming AI output has no animation applied to it; the token-by-token appearance is itself the motion, and adding transitions on top of it would create visual noise. When an AI suggestion appears as a ghost text overlay, it fades in at 60ms. When dismissed, it vanishes at 0ms — rejection should feel as instant as pressing Escape.
Duration Scale
| Token | Value | Use |
|---|---|---|
| instant | 0ms | Text cursor movement, caret blinks, syntax highlighting, hover backgrounds in the editor gutter, AI ghost text dismissal |
| micro | 60ms | AI ghost text appearance, tooltip fade-in, status bar badge updates |
| fast | 80ms | Hover states on sidebar icons, tab active indicator, breadcrumb transitions |
| default | 100ms | Command palette entrance, quick open file picker, context menu appearance |
| medium | 140ms | Panel open/close (non-spring), notification toasts entering |
| slow | 200ms | AI composer panel sliding in, primary sidebar expanding |
| layout | spring | File tree expand/collapse, panel resize, editor group splits |
Easing
| Token | Curve | Use |
|---|---|---|
| ease-out | cubic-bezier(0.16, 1, 0.3, 1) | Elements entering — aggressive deceleration for native feel |
| ease-in | cubic-bezier(0.7, 0, 0.84, 0) | Elements exiting — fast acceleration away |
| ease-in-out | cubic-bezier(0.4, 0, 0.2, 1) | Elements repositioning within a layout (tab reordering) |
| linear | cubic-bezier(0, 0, 1, 1) | Continuous animations: loading bars, spinner rotation |
| spring | See spring configs | All resize handles, panel open/close, file tree nodes |
The ease-out curve front-loads motion so elements appear to arrive almost before the interaction registers. This is non-negotiable for a tool where users perceive 16ms differences.
Spring Configs (Framer Motion)
- Panel: stiffness: 500, damping: 38, mass: 0.9 — sidebar and bottom panel open/close
- Snappy: stiffness: 700, damping: 42, mass: 0.7 — file tree node expand, tab group transitions
- Resize: stiffness: 600, damping: 50, mass: 1 — drag-to-resize panel edges (high damping prevents oscillation during active drag)
- Micro: stiffness: 900, damping: 45, mass: 0.5 — icon scale on hover, active tab indicator position
No spring config produces visible overshoot. Damping is always at or above critical damping.
Stagger Patterns
- File tree children: 12ms between each node when a folder first expands
- Command palette results: 10ms between each result on initial population
- Notification group: 20ms between stacked toasts
- Settings panel sections: 18ms between sections on page load
Stagger only applies on initial render of a list. Re-filtering command palette results does not re-stagger — items reorder without entrance animation to preserve the feeling of speed during active search.
Enter / Exit Patterns
Scale Fade (command palette, quick open, AI chat)
enter: opacity 0→1, scale 0.98→1, duration: default (100ms), ease: ease-out
exit: opacity 1→0, scale 1→0.98, duration: fast (80ms), ease: ease-in
Slide Up (notification toasts, inline AI suggestions bar)
enter: opacity 0→1, translateY 8px→0, duration: medium (140ms), ease: ease-out
exit: opacity 1→0, translateY 0→-4px, duration: fast (80ms), ease: ease-in
Slide In (AI composer panel, secondary sidebar)
enter: translateX 100%→0, duration: slow (200ms), spring: Panel config
exit: translateX 0→100%, duration: medium (140ms), ease: ease-in
Fade Only (ghost text, inline diff overlay, status indicators)
enter: opacity 0→1, duration: micro (60ms), ease: ease-out
exit: opacity 1→0, duration: instant (0ms)
Bottom Panel Reveal (terminal, output, problems)
enter: translateY 100%→0, spring: Panel config
exit: translateY 0→100%, duration: medium (140ms), ease: ease-in
Interaction States
- Hover: Background fill at 60ms ease-out. No scale on editor elements. Sidebar icons shift opacity 0.6→1 at 60ms. Feels near-instant.
- Press/Active: scale(0.96) on buttons over 60ms with Micro spring. Releases on pointer-up. Tab items do not scale — only dedicated button elements.
- Focus: Focus ring at 0ms via CSS outline. Keyboard navigation is never delayed by animation.
- Resize handle drag: Cursor changes immediately. Panel follows pointer with no lag. Spring config on pointer-up only, snapping the handle to a clean pixel boundary.
- AI streaming: No transition applied. Token appearance is the animation. Cursor blink is suppressed during active streaming.
- Loading / indexing: Linear progress bar in status bar, 1200ms cycle, CSS animation. No spinner in the editor chrome — spinners signal waiting, and Cursor avoids communicating that.
Rules
- Respect
prefers-reduced-motion. All durations collapse to 0ms; transforms are skipped. Springs resolve to their final value immediately. - Never animate anything on the editor surface itself — text area, gutter, scrollbar, minimap. These are zero-latency zones.
- Exit durations must be shorter than enter durations. The interface clears faster than it fills.
- No bouncy spring configs. If a panel wiggles past its target, the config is wrong.