skills / design

emil-design-eng

what it does

This skill encodes Emil Kowalski's philosophy on UI polish, component design, animation decisions, and the invisible details that make software feel great.

Verified Before and after: 2 models 1 try per case View source Download .zip

Compare the answers

Answers from Claude Sonnet 5.5 and GPT-6.1 Sol · try 1 of 1

Same request, same model, once with the skill and once without. Read both and judge for yourself.

“Review the CSS for our account dropdown. It opens from a button in the top-right of the header.”

Source material given with the request

.account-menu { position: absolute; top: calc(100% + 8px); right: 0; transform: scale(0); transform-origin: center; transition: all 400ms ease-in; } .account-menu.is-open { transform: scale(1); }
with the skill
The dropdown should feel anchored to its trigger and respond immediately. Right now, scaling from zero, using a centered origin, and easing in over 400ms make it feel detached and slow. | Before | After | Why | | --- | --- | --- | | `transform: scale(0)` | `transform: scale(0.95); opacity: 0` | A subtle scale with a fade feels more natural than appearing from nothing. | | `transform-origin: center` | `transform-origin: top right` | The menu opens below a right-aligned trigger, so motion should originate from that corner. | | `transition: all 400ms ease-in` | Explicit `transform` and `opacity` transitions, 180ms with a strong ease-out | Immediate movement feels responsive; explicit properties avoid unintended animations. | | Closed state only changes scale | Add `visibility: hidden` and `pointer-events: none` | Prevent the closed menu from receiving focus or intercepting clicks. | | No reduced-motion handling | Remove scaling and retain a short fade | Respects motion preferences without losing state feedback. | ```css .account-menu { position: absolute; top: calc(100% + 8px); right: 0; opacity: 0; visibility: hidden; pointer-events: none; transform: scale(0.95);
Show the rest (43 more lines)
transform-origin: top right; /* Closing is slightly faster than opening. */ transition: transform 120ms cubic-bezier(0.23, 1, 0.32, 1), opacity 120ms cubic-bezier(0.23, 1, 0.32, 1), visibility 0s linear 120ms; } .account-menu.is-open { opacity: 1; visibility: visible; pointer-events: auto; transform: scale(1); transition-duration: 180ms, 180ms, 0s; transition-delay: 0s; } @media (prefers-reduced-motion: reduce) { .account-menu, .account-menu.is-open { transform: none; transition-duration: 100ms, 100ms, 0s; } .account-menu { transition-delay: 0s, 0s, 100ms; } .account-menu.is-open { transition-delay: 0s; } } /* Set by your interaction logic for keyboard-triggered changes. */ .account-menu[data-instant], .account-menu.is-open[data-instant] { transition: none; } ``` For keyboard opening or closing, apply `data-instant` before changing the state so the menu responds without animation. CSS alone also doesn’t handle focus management or the trigger’s `aria-expanded`; wire those up alongside the open state.
without
A few changes would make this dropdown feel more natural and behave more reliably: - **Anchor the animation to the trigger.** Use `transform-origin: top right` rather than `center`. - **Avoid scaling from zero.** It makes text visibly grow and can feel distracting. A slight offset and fade usually work better. - **Shorten the transition.** `400ms ease-in` can feel slow for a menu. Try `150ms ease-out`. - **Transition only specific properties**, not `all`. - **Hide the closed menu from interaction.** A transform alone doesn’t express its hidden state to assistive technology. - **Check its positioning container.** The trigger’s wrapper should have `position: relative` so the menu aligns with it. ```css .account-menu-wrapper { position: relative; } .account-menu { position: absolute; top: calc(100% + 8px); right: 0; z-index: 100;
Show the rest (29 more lines)
opacity: 0; visibility: hidden; pointer-events: none; transform: translateY(-4px) scale(0.98); transform-origin: top right; transition: opacity 150ms ease-out, transform 150ms ease-out, visibility 0s linear 150ms; } .account-menu.is-open { opacity: 1; visibility: visible; pointer-events: auto; transform: translateY(0) scale(1); transition-delay: 0s; } @media (prefers-reduced-motion: reduce) { .account-menu { transition: none; transform: none; } } ``` For keyboard accessibility, also have the button expose `aria-expanded` and `aria-controls`, support Escape to close, and return focus to the button when closing with Escape. If you use `role="menu"`, implement its expected keyboard navigation; otherwise, a simple dropdown of links can use ordinary link semantics.

Answers are shown exactly as the model wrote them, from the first try, and nothing is picked by hand.

The models

2 models

Claude Sonnet 5.5

made by Anthropic

claude-sonnet-5-5 · revision not reported by the provider

1 try per case · tested 3 Nov 2026

GPT-6.1 Sol

made by OpenAI

gpt-6.1-sol · revision not reported by the provider

1 try per case · tested 3 Nov 2026

The tasks

written by Carte Blanche
dropdown-css-review

“Review the CSS for our account dropdown. It opens from a button in the top-right of the header.”

janky-bottom-sheet

“Our mobile bottom sheet stutters when it opens and while you drag it, especially on cheap Android phones. Why?”

rapid-toast-css

“Write the CSS for a toast that slides up from the bottom of the screen when it appears and fades out when dismissed. Several toasts can be added within a second, and they stack.”

sluggish-command-palette

“Users say our Cmd+K command palette feels sluggish, even though it renders in under 10ms. Here's how it opens. What's going on?”

sticky-hover-dead-press

“On phones our buttons sometimes stay enlarged after you tap them. They also feel kind of dead when you press them. Can you fix the CSS?”

Install

Download the .zip and unzip it. Put its files, in a folder named emil-design-eng, here:

Claude Code~/.claude/skills/Every project. For one project only, use .claude/skills/ inside it.
Codex~/.agents/skills/Every project. For one repository only, use .agents/skills/ inside it.
Cursor~/.cursor/skills/Cursor also reads the Claude Code and Codex folders above.

Then start a new session and ask for what the skill does. Other agents that read SKILL.md have their own skills folder; check their docs.

Coming after launch: get skills from inside your agent, no download needed.