Design and Animation
Source: Emil Kowalski's design engineering philosophy. Skill at
skills/engineering/design-engineering-polish/. Course: animations.dev. Cursor rule:.cursor/rules/design-animation-rules.mdc.
Source baseline: Emil Kowalski (emilkowalski/skill, animations.dev). Source: Emil Kowalski (emilkowalski/skill, animations.dev)
Core Philosophy
Taste is trained, not innate. Study why the best interfaces feel the way they do. Reverse engineer animations. Inspect interactions. Be curious. Emil Kowalski's reshare of Rasmus Andersson's taste-building thread is the rule in social form: intuitive design comes from collecting references, noticing details, and learning to name what works. Source: X/@emilkowalski, 2024-03-04; Source: X/@rsms, 2023-03-11
Hard CSS/UI rules (scrollbars, hit-area pseudo-elements, @property gradients, fluid clamp, agent lean-ctx bootstrap) live in CSS UI Enforcement - enforced across Kevin repos.
Unseen details compound. Most details users never consciously notice. That is the point. A thousand barely audible voices all singing in tune.
Beauty is a product multiplier. People select tools based on the overall experience, not just functionality. Good defaults and good animations are real differentiators.
Animation Decision Framework
1. Should this animate at all?
| Frequency | Decision |
|---|---|
| 100+ times/day (keyboard shortcuts, command palette) | No animation. Ever. |
| Tens of times/day (hover effects, list navigation) | Remove or drastically reduce |
| Occasional (modals, drawers, toasts) | Standard animation |
| Rare/first-time (onboarding, celebrations) | Can add delight |
Never animate keyboard-initiated actions. If the purpose is just "it looks cool" and the user will see it often, don't animate.
2. Easing Decision Flowchart
Entering or exiting viewport? -> ease-out
Moving/morphing on screen? -> ease-in-out
Hover/color change? -> ease
Constant motion (marquee, progress)? -> linear
Default -> ease-out
The reviewed quick-decision card is the pocket version of this framework: ease-out for entry/exit, ease-in-out for movement already on screen, ease for hover/color, no animation for actions users see 100+ times daily, springs for drag or interruptible gestures, longer duration for larger surfaces like drawers, and faster exits than entrances. Source: X/@emilkowalski, 2026-04-17; Source: local image artifact review, 2026-07-03
Use custom curves. Built-in CSS easings lack punch:
--ease-out: cubic-bezier(0.23, 1, 0.32, 1);
--ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
--ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);
Never use ease-in for UI animations. It starts slow, making the interface feel
sluggish. Resources: easing.dev, easings.co.
3. Duration Guidelines
| Element Type | Duration |
|---|---|
| Button press feedback | 100-160ms |
| Tooltips, small popovers | 125-200ms |
| Dropdowns, selects | 150-250ms |
| Modals, drawers | 200-500ms |
| Marketing/explanatory | Can be longer |
Rules:
- UI animations stay under 300ms
- Larger elements animate slower than smaller ones
- Exit animations can be ~20% faster than entrance
- Match duration to distance -- longer travel = longer duration
Component Rules
-
Scale buttons on press:
transform: scale(0.97)on:activewithtransition: transform 160ms ease-out. Scale 0.95-0.98. -
Never animate from scale(0): Start from
scale(0.95)withopacity: 0. Nothing in the real world appears from nothing. -
Origin-aware popovers: Set
transform-originto trigger location. Usevar(--radix-popover-content-transform-origin). Exception: modals stay centered. -
Skip tooltip delay on subsequent hovers: Once one is open, adjacent tooltips open instantly with
[data-instant] { transition-duration: 0ms; }. -
CSS transitions over keyframes: Transitions are interruptible. Keyframes restart from zero. Use transitions for toasts, toggles, rapidly-triggered UI.
-
Blur to mask crossfades:
filter: blur(2px)during transition. Under 20px. -
Asymmetric enter/exit timing: Press slow when deliberate (hold-to-delete: 2s linear), release always snappy (200ms ease-out).
-
Stagger animations: 30-80ms between items. Never block interaction during stagger.
-
Use
@starting-stylefor entry animations: Modern CSS replaces theuseEffect+setMounted(true)pattern.
Page Transitions
Page transitions are navigation, not decoration. Use them only when they preserve orientation across routes: the outgoing surface should blur, fade, scale, or slide in a way that tells the user where the new surface came from. A reviewed Framer demo by Hamza Ehsan / AliGrids shows the useful version: a creamy marketing site moves from a hero state into a mission/story state through blur, fade, and scale choreography without losing the spatial thread. Source: X/@AliGrids, 2026-03-15; Source: local video artifact review, 2026-07-01
Do not cargo-cult the production stack from the reference. If the final app is a React product, route through Frontend and Design Skills, Frontend and Design Skills, or CSS view transitions. If the artifact is a Framer marketing site, preserve the reference as taste vocabulary and only port the behavior that improves comprehension.
Slow-Motion Animation Review
Fast UI motion should be reviewed slowly before it is judged. AliGrids' 0.1x CSS-animation artifact shows a dark sidebar where the Home selection pill hands off to Chat: at normal speed the hover feels polished, but the slowed pass exposes the pointer target, icon weight, moving pill, label reveal, tooltip timing, and whether the surrounding layout shifts. Source: X/@AliGrids, 2026-06-14; Source: local video contact sheet, 2026-07-02
Use 0.1x review for hover navigation, selection-pill handoffs, icon-label morphs, tooltip timing, and sidebar/dock state changes. Capture the slow pass before changing durations: if the geometry jumps, easing cannot fix it. The review target is not slower animation; it is smoother spatial continuity at production speed.
Launch Explainer Motion
Product-launch videos are not only marketing assets; they are compressed interaction specs. Mark Vassilevskiy's 2D animation reel shows why: the artifact uses soft brand fields, product screenshots, abstract data islands, phone frames, and animated type to explain Replit Slides, Bud's AI Human Emulator positioning, and other SaaS concepts without requiring a full product tour. Source: X/@MarkKnd, 2026-05-02
Use this pattern when a product is conceptually hard but visually simple: show the abstract workflow as motion, keep the UI frames crisp, and let the video carry the explanation. Do not copy the soft pastel style by default; the durable rule is sequencing and compression, not the palette.
Scroll Parallax References
The Framer "3 clicks" parallax bookmark is useful as a taste reference, not as evidence that every production site should be built in Framer. The sampled video shows a dark AI-agent landing page where the hero product panel and landscape foreground move at different scroll rates, then resolve into supporting copy and partner marks before returning to the hero. The durable motion rule is restrained depth: parallax should create spatial separation between content layers, not hide the copy or turn the page into a product tour. Source: X/@stfnco, 2026-03-05; Source: local video contact sheet, 2026-07-03
Parametric Motion Tuning
When decorative motion has more than a handful of spatial parameters, expose those parameters in a temporary tuning console instead of guessing values in code. Soren Blank's Linear parallax-bar recreation demonstrates the pattern: a floating DialKit-like panel adjusts bar count, x/y step, diagonal offsets, peak nodes, peak height, falloff, and floor while the bar geometry updates live. Source: X/@sorenblank and local video contact sheet, 2026-07-03
Use this for parallax, waves, soft extrusion, layered bars, and complex decorative geometry. Ship the resulting constants or design tokens; do not ship the dev tuning panel unless it is explicitly a user-facing creative tool.
Spring Animations
Springs feel more natural because they simulate real physics. No fixed duration -- they settle based on physical parameters.
Novikoff's spring-curve artifact gives a useful visual taxonomy: bouncy overshoots and returns, smooth reaches the target quickly without overshoot, and flattened eases in with a long slow approach. In Motion-style terms, use bounce: 0 for most polished UI springs; it starts fast, has a long tail, and avoids the toy feel of visible rebound. Negative-bounce or flattened curves can work for quiet decorative motion, but they often feel sluggish on controls. Source: X/@novikoff and local image review, 2026-07-03
When to use: drag interactions with momentum, elements that feel "alive", gestures that can be interrupted, decorative mouse-tracking.
const springRotation = useSpring(mouseX * 0.1, { stiffness: 100, damping: 10 });
Apple's approach (recommended): { type: "spring", duration: 0.5, bounce: 0.2 }.
Keep bounce subtle (0.1-0.3). Avoid bounce in most UI contexts.
Springs maintain velocity when interrupted -- CSS animations restart from zero.
clip-path Techniques
clip-path: inset(top right bottom left) is one of the most capable animation
tools. Techniques: hold-to-delete overlays, tab color transitions (duplicate + clip),
image reveals on scroll, comparison sliders.
Gesture Rules
- Momentum-based dismissal: calculate velocity (
distance / time). If > 0.11, dismiss. - Damping at boundaries: the more they drag past the edge, the less it moves.
- Pointer capture once dragging starts (
setPointerCapture). - Multi-touch protection: ignore additional touch points after initial drag.
- Friction instead of hard stops.
Performance
- Only animate
transformandopacity(GPU-composited). - Framer Motion
x/y/scaleare NOT hardware-accelerated. Usetransform: "translateX(100px)"for GPU. - CSS animations run off main thread. Use CSS for predetermined, JS for dynamic.
- Don't animate CSS variables on parents -- recalculates all children.
- WAAPI (
element.animate()) gives JS control with CSS performance.
Accessibility
prefers-reduced-motion: keep opacity/color, remove movement.- Gate hover behind
@media (hover: hover) and (pointer: fine). - 44px minimum hit area on touch targets.
Practical Tips
| Scenario | Solution |
|---|---|
| Make buttons feel responsive | transform: scale(0.97) on :active |
| Element appears from nowhere | Start from scale(0.95), not scale(0) |
| Shaky/jittery animations | Add will-change: transform |
| Hover causes flicker | Animate child element, not parent |
| Popover scales from wrong point | Set transform-origin to trigger location |
| Sequential tooltips feel slow | Skip delay/animation after first tooltip |
| Small buttons hard to tap | Use 44px minimum hit area (pseudo-element) |
| Something still feels off | Add subtle blur (under 20px) to mask it |
| Hover triggers on mobile | Use @media (hover: hover) and (pointer: fine) |
Review Checklist
| Issue | Fix |
|---|---|
transition: all |
Specify exact properties |
scale(0) entry |
scale(0.95) with opacity: 0 |
ease-in on UI element |
ease-out or custom curve |
transform-origin: center on popover |
Trigger location (modals exempt) |
| Animation on keyboard action | Remove entirely |
| Duration > 300ms on UI element | 150-250ms |
| Hover without media query | @media (hover: hover) and (pointer: fine) |
| Keyframes on rapid triggers | CSS transitions |
Framer Motion x/y under load |
transform: "translateX()" |
| Same enter/exit speed | Exit ~20% faster |
| Everything appears at once | Stagger 30-80ms |
The Sonner Principles
From building Sonner (13M+ weekly npm downloads):
- No hooks, no context, no setup. Insert once, call from anywhere.
- Good defaults matter more than options. Ship beautiful out of the box.
- Handle edge cases invisibly. Pause timers on hidden tabs. Fill gaps between stacked toasts. Capture pointer during drag.
- Match motion to mood. Playful = bouncier. Dashboard = crisp and fast.
- Review animations the next day with fresh eyes.
Timeline
- 2026-07-03 | Added Emil Kowalski's quick animation decision card as the compact rule table for easing, frequency, springs, scale-aware duration, and faster exits. Source: X/@emilkowalski, 2026-04-17; Source: local image artifact review, 2026-07-03
- 2026-07-03 | Added Novikoff's spring-curve taxonomy: use smooth
bounce: 0springs for most UI, reserve visible bounce for playful or gesture-heavy contexts, and treat flattened curves as slower decorative motion. Source: X/@novikoff, 2026-06-14; Source: local image artifact review, 2026-07-03 - 2026-07-03 | Added Soren Blank's Linear parallax-bar recreation as a parametric motion-tuning rule: expose geometry and wave parameters through a temporary console, then ship the tuned constants. Source: X/@sorenblank, 2026-05-01; Source: local video contact sheet, 2026-07-03
- 2026-07-03 | Added the Framer parallax landing-page artifact as a restrained-depth reference: separate hero panel, foreground landscape, and supporting copy layers without obscuring the page's reading path. Source: X/@stfnco, 2026-03-05; Source: local video contact sheet, 2026-07-03
- 2026-07-02 | Deep-reviewed the local image artifact behind Emil's Rasmus/Ira Glass taste-building bookmark. The durable rule stays unchanged: taste is trained by volume, reference collection, reverse engineering, and vocabulary-building; the image is preserved as provenance rather than a new philosophy page. Source: X/@emilkowalski, 2024-03-04; Source: local image artifact, 2026-07-02
- 2026-07-02 | Added Mark Vassilevskiy's 2D launch-animation artifact as a reference for compact product explainers: use motion to sequence abstract workflow, UI screenshots, and benefit framing without adding a product tour. Source: X/@MarkKnd, 2026-05-02; local video artifact reviewed 2026-07-02
- 2026-07-01 | Added Emil Kowalski's practical skill-file tips artifact as provenance for the button press, entry scale,
will-change, child-hover, origin-aware popover, tooltip, tap-target, blur, and touch-hover rules. Source: X/@emilkowalski, 2026-03-11 - 2026-06-25 | Added Emil Kowalski's bookmarked Rasmus Andersson taste-building reference as evidence for the "taste is trained" rule. Source: X/@emilkowalski, 2024-03-04; Source: X/@rsms, 2023-03-11
- 2026-07-01 | Added Framer page-transition artifact review as a reusable navigation-orientation rule: preserve spatial continuity, then implement through the production stack instead of copying the prototype tool. Source: X/@AliGrids, 2026-03-15