agentleFS
ZhouYinLong-labZhouYinLong-lab/Dog-Skills/emil-design-eng/SKILL.md

emil-design-eng

Skill7 starsChanged 5 months agoMITView on GitHub

Emil Kowalski's design engineering philosophy — animation decision framework, CSS transform mastery, clip-path animation techniques, gesture/drag interactions, and component building principles. From the creator of Sonner (13M+ weekly npm downloads) and Vaul. Trigger keywords: design engineering, UI polish, animation framework, 动效设计, Emil Kowalski, Sonner, 设计工程师, component design, 组件设计, animation decision, CSS animation, clip-path, gesture, drag interaction, 动画决策, 手势交互, UI打磨, design philosophy.

133 other projects use a version of this, 125 of them edited.

Adopted by

Most recently taken up by

Used with

Projects with it also use capture-learning-tools, design-frontend-dev and 10 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • The-Vibe-CompanySkill

    capture-learning-tools

    Turn technical conversations, bugs, CI failures, review comments,

    Also in 5 projects that use this

  • The-Vibe-CompanySkill

    design-frontend-dev

    Clean Impeccable frontend design skill. Use when the user wants to

    Also in 5 projects that use this

  • cal1888Skill

    pick-ui-library

    Pick the right library for a given frontend task from a curated, opinionated list — numbers, OTP inputs, charts, command menus, virtualization, drag and drop, toasts, state, styling, and more. Only runs when explicitly invoked; it does not trigger on its own.

    Also in 40 projects that use this

  • wxyhgkSkill

    find-animation-opportunities

    Search a codebase or UI for places that don't animate but should, and reject everything that shouldn't. Read-only; it proposes motion with exact values, it does not implement it. Use when the user asks "what could be animated here?" or wants to "make this feel more alive". For fixing existing animations, use improve-animations or review-animations instead.

    Also in 51 projects that use this

  • attentiondotnetSkill

    animation-vocabulary

    Reverse-lookup glossary that turns a vague description of a web animation or motion effect into its exact term ("the bouncy thing when a popover opens" → Pop in; "the iOS rubber-band scroll" → Rubber-banding). Use when the user asks "what's it called when…", or describes a motion effect without knowing its name and wants the right word to prompt an AI or designer with. For naming an effect, not designing or building one.

    Also in 61 projects that use this

  • wxyhgkSkill

    improve-animations

    Survey a codebase's animation and motion code as a senior motion advisor, then produce a prioritized audit and self-contained implementation plans for other agents (or cheaper models) to execute. Read-only on source code — it plans improvements, it does not apply them. Use when the user asks to "improve the animations", "audit the motion", "make this app feel better", or wants a roadmap of animation fixes rather than a review of a single diff.

    Also in 55 projects that use this

  • +3 more from The-Vibe-Company

The file

We split this skill into the rules it gives an agent

6 rules. 1 is common, 2 are distinctive, and 3 are very specific to this project.

  • 1

    Common

    Most of the 132 edited versions we read keep these.

  • 2

    Distinctive

    This author's own choices. Worth a look.

  • 3

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    When reviewing UI code, you MUST use a markdown table with | Before | After | Why | columns:

    line 33
  2. Common:

    Before writing any animation code, answer these four questions in order:

    line 45
  3. Distinctive:

    Keep bounce subtle (0.1-0.3).

    line 109
  4. Very specific:

    Start from scale(0.95) + opacity: 0.

    line 117
  5. Distinctive:

    Use cases: tabs with perfect color transitions, hold-to-delete, image reveals on scroll, comparison sliders.

    line 157
  6. Very specific:

    DX is key: No hooks, no context, no complex setup.

    line 188

“Common” is measured: kept by at least 6 in 10 of the 132 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Design Engineering — Emil Kowalski's Philosophy

"All those unseen details combine to produce something that's just stunning, like a thousand barely audible voices all singing in tune." — Paul Graham

You are a design engineer with the craft sensibility. You build interfaces where every detail compounds into something that feels right. Taste is the differentiator when everyone's software is good enough.

Core Philosophy

Taste is trained, not innate

Study why the best interfaces feel the way they do. Reverse engineer animations. Inspect interactions. Be curious.

Unseen details compound

Most details users never consciously notice — and that is the point. When a feature functions exactly as someone assumes, they proceed without a second thought.

Beauty is leverage

People select tools based on the overall experience. Good defaults and animations are real differentiators. Beauty is underutilized — use it as leverage.

Review Format (Required)

When reviewing UI code, you MUST use a markdown table with | Before | After | Why | columns:

BeforeAfterWhy
transition: all 300mstransition: transform 200ms ease-outSpecify exact properties; avoid all
transform: scale(0)transform: scale(0.95); opacity: 0Nothing in the real world appears from nothing
ease-in on dropdownease-out with custom curveease-in feels sluggish; ease-out gives instant feedback
No :active state on buttontransform: scale(0.97) on :activeButtons must feel responsive to press
transform-origin: center on popovertransform-origin: var(--transform-origin)Popovers scale from trigger (modals exempt)

The Animation Decision Framework

Before writing any animation code, answer these four questions in order:

1. Should this animate at all?

FrequencyDecision
100+ times/day (keyboard shortcuts, command palette)No animation. Ever.
Tens of times/day (hover, 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. Raycast has no open/close animation — that's optimal for something used hundreds of times a day.

2. What is the purpose?

Valid purposes: spatial consistency, state indication, explanation, feedback, preventing jarring changes. If it's just "looks cool" and users see it often, don't animate.

3. What easing should it use?

  • Entering/exiting? → ease-out (starts fast, feels responsive)
  • Moving/morphing on screen? → ease-in-out (natural acceleration/deceleration)
  • Hover/color change? → ease
  • Constant motion? → linear

Use custom easing curves — built-in CSS easings are too weak:

--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. It starts slow, making the interface feel sluggish.

References: easing.dev | easings.co

4. How fast should it be?

ElementDuration
Button press feedback100-160ms
Tooltips, small popovers125-200ms
Dropdowns, selects150-250ms
Modals, drawers200-500ms
Marketing/explanatoryCan be longer

Rule: UI animations should stay under 300ms. Perceived performance matters as much as actual speed.

Spring Animations

Springs feel more natural — they simulate real physics. Use for:

  • Drag interactions with momentum
  • Elements that should feel "alive" (like Apple's Dynamic Island)
  • Gestures that can be interrupted mid-animation
  • Decorative mouse-tracking interactions
// Apple's approach (recommended):
{ type: "spring", duration: 0.5, bounce: 0.2 }

// Traditional physics:
{ type: "spring", mass: 1, stiffness: 100, damping: 10 }

Keep bounce subtle (0.1-0.3). Springs maintain velocity when interrupted — ideal for gestures.

Component Building Principles

Buttons must feel responsive

transform: scale(0.97) on :active. Duration: 160ms ease-out.

Never animate from scale(0)

Start from scale(0.95) + opacity: 0. Even a barely-visible shape makes entrance feel natural.

Make popovers origin-aware

Popovers scale from their trigger — use transform-origin: var(--transform-origin). Exception: modals keep center.

Tooltips: skip delay on subsequent hovers

First tooltip: delayed to prevent accidental activation. Adjacent hover after one is open: instant, no animation.

Use CSS transitions over keyframes for interactive UI

Transitions can be interrupted and retargeted. Keyframes restart from zero.

Use blur to mask imperfect transitions

filter: blur(2px) during crossfade bridges visual gap between old and new states.

Animate enter states with @starting-style

.toast {
  opacity: 1;
  transform: translateY(0);
  transition: opacity 400ms ease, transform 400ms ease;
  @starting-style { opacity: 0; transform: translateY(100%); }
}

CSS Transform Mastery

  • translateY(%) is relative to the element's own size — use percentages, not pixels
  • scale() scales children too — font, icons, content scale proportionally
  • transform-style: preserve-3d enables real 3D effects
  • transform-origin — set to match where the trigger lives

clip-path for Animation

inset shape: clip-path: inset(top right bottom left)

/* Reveal from left to right */
.overlay { clip-path: inset(0 100% 0 0); transition: clip-path 200ms ease-out; }
.button:active .overlay { clip-path: inset(0 0 0 0); transition: clip-path 2s linear; }

Use cases: tabs with perfect color transitions, hold-to-delete, image reveals on scroll, comparison sliders.

Gesture and Drag Interactions

  • Momentum-based dismissal: calculate velocity = |dragDistance| / elapsedTime. Dismiss if > 0.11 regardless of distance.
  • Damping at boundaries: the more they drag past limits, the less it moves.
  • Pointer capture for drag: ensures dragging continues outside element bounds.
  • Multi-touch protection: ignore additional touch points after initial drag.
  • Friction instead of hard stops: allow over-drag with increasing resistance.

Performance Rules

  1. Only animate transform and opacity — they skip layout/paint, run on GPU.
  2. CSS variables are inheritable — updating --var on parent recalculates all children. Use transform directly.
  3. Framer Motion x/y are NOT hardware-accelerated — use transform: "translateX()" for GPU compositing.
  4. CSS animations beat JS under load — they run off the main thread.
  5. Use WAAPI for programmatic CSS animations — JS control with CSS performance.

Accessibility

@media (prefers-reduced-motion: reduce) {
  .element { animation: fade 0.2s ease; } /* No transform-based motion */
}
@media (hover: hover) and (pointer: fine) {
  .element:hover { transform: scale(1.05); }
}

The Sonner Principles (Building Loved Components)

  1. DX is key. No hooks, no context, no complex setup. Insert <Toaster /> once, call toast() from anywhere.
  2. Good defaults matter more than options. Ship beautiful out of the box.
  3. Naming creates identity. "Sonner" (French for "to ring") trumps "react-toast".
  4. Handle edge cases invisibly. Pause timers when tab hidden, fill gaps between toasts, capture pointer during drag.
  5. Use transitions, not keyframes, for dynamic UI.
  6. Build a great documentation site. Interactive examples lower adoption barriers.

Review your work the next day

Play animations in slow motion or frame-by-frame to spot timing issues invisible at full speed.

Asymmetric enter/exit timing

Slow where user decides (hold-to-delete: 2s linear), fast where system responds (release: 200ms ease-out).

Review Checklist

IssueFix
transition: allSpecify exact properties
scale(0) entry animationStart from scale(0.95) + opacity: 0
ease-in on UI elementSwitch to ease-out or custom curve
transform-origin: center on popoverSet to trigger location (modals exempt)
Animation on keyboard actionRemove entirely
Duration > 300ms on UI elementReduce to 150-250ms
Hover animation without media queryAdd @media (hover: hover) and (pointer: fine)
Keyframes on rapidly-triggered elementUse CSS transitions
Framer Motion x/y under loadUse transform: "translateX()"
Same enter/exit transition speedExit faster than enter
Elements all appear at onceAdd stagger delay (30-80ms)

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.