懶人包
- emil-design-eng 是 Emil Kowalski 在 MIT 授權的
emilkowalski/skills裡放的主力 skill,674 行,是整個 repo 最長的一支。內容是他的設計工程判斷:該不該動、用哪條 easing、要多快、細節清單與審查格式。- 它的 frontmatter 只有 name 和一句 description,沒有
disable-model-invocation,也沒寫「什麼時候用」。我同一句需求不點名跑 3 次,只有 1 次自動載入。- 我叫 Claude Code(Sonnet)寫同一個下拉選單:點名
/emil-design-eng的版本換成cubic-bezier(0.23, 1, 0.32, 1),關閉 110ms 比開啟 170ms 快,減少動態時保留淡入淡出。Playwright 量到 opacity 到 0.9 只要 102ms,沒用 skill 的三份是 152–183ms。- 靜態截圖兩邊幾乎一樣,差異全在動態。代價是每次載入約多 9.9k input tokens,單次執行成本從 0.076 美元變 0.140 美元。
- 跟 apple-design 的分工:apple-design 管手勢、彈簧與材質;emil-design-eng 管一般 UI 元件的時間、曲線與「不要動」的判斷。
- emil-design-eng 是什麼?
- 674 行裡有哪些章節?
- 最有料的四條判斷:該不該動、easing、時長、細節清單
- 實測:同一個下拉選單,有沒有用上它差在哪
- 它會自動觸發嗎?要吃多少 context?
- 跟 apple-design 差在哪、哪裡重疊?
- 怎麼安裝與點名?
- 什麼情況不適合用
- 延伸資源
🎛️ emil-design-eng 是什麼?
emil-design-eng 是一份給 AI coding agent 讀的 SKILL.md。作者 Emil Kowalski 寫過 toast 元件 sonner 和 drawer 元件 vaul,repo README 對這支的介紹是「主要講動畫,也有一些設計建議的主 skill」。
它的 frontmatter 只有兩行:
name: emil-design-eng
description: This skill encodes Emil Kowalski's philosophy on UI polish, component design, animation decisions, and the invisible details that make software feel great.
正文開頭先給 agent 一個身分:有工藝感的 design engineer,相信「大家的軟體都夠好用時,品味就是差異」。接下來 600 多行把這個品味拆成規則、數字和 code 範例。
它跟同 repo 的 animate、review-animations 這些「單一任務」skill 不同:那幾支只做一件事(從零做動畫、審查動畫),emil-design-eng 是它們共同的母體。我比對過,cubic-bezier(0.23, 1, 0.32, 1) 這條曲線在 animate、animate-expo、find-animation-opportunities 裡也都出現。
repo 的 git 紀錄顯示這支在 2026-03-16 跟 repo 一起建立,之後改過三次:03-25 調整開場訊息與格式、07-21 把 Radix UI 的範例換成 Base UI、09-15 拿掉課程連結。我讀的是 commit 2d22863 的版本。
📚 674 行裡有哪些章節?
全文 15 個 H2。我依「什麼時候會用到」分成四組:
| 分組 | 章節 | 內容 |
|---|---|---|
| 行為設定 | Initial Response、Core Philosophy、Review Format | 沒問題時只回一句固定招呼;三條信念(品味是練出來的、看不見的細節會累積、美是槓桿);審查時必須用 Before/After/Why 三欄表格 |
| 動畫決策 | Animation Decision Framework、Spring Animations | 依序回答四題:要不要動、目的是什麼、用哪條曲線、多快;何時改用 spring 與設定方式 |
| 元件與技法 | Component Building Principles、CSS Transform、clip-path、Gesture and Drag、Performance | 按鈕按壓、不要從 scale(0) 開始、popover 從觸發點展開、tooltip 延遲、@starting-style;百分比 translate、clip-path 揭露;拖曳關閉的速度門檻;只動 transform 與 opacity |
| 品質與收尾 | Accessibility、Sonner Principles、Stagger、Debugging、Review Checklist | 減少動態、觸控裝置 hover;做 sonner 學到的六條原則;錯開進場;慢動作與逐幀檢查;11 列問題對照表 |
🎯 最有料的四條判斷:該不該動、easing、時長、細節清單
先問:這個東西要不要動?
skill 用「使用者一天看到幾次」來決定:
| 一天看到的次數 | 例子 | 判斷 |
|---|---|---|
| 上百次 | 鍵盤快捷鍵、command palette 開關 | 完全不動 |
| 幾十次 | hover、清單上下移動 | 拿掉或大幅縮短 |
| 偶爾 | modal、drawer、toast | 一般動畫 |
| 很少或第一次 | onboarding、慶祝畫面 | 可以加料 |
用哪條 easing?
決策樹很短:進場或離場用 ease-out;畫面內移動或變形用 ease-in-out;hover 和顏色變化用 ease;跑馬燈、進度條這種等速運動用 linear;拿不準就 ease-out。
它認為 CSS 內建的曲線太弱,給了三條自訂曲線:
--ease-out: cubic-bezier(0.23, 1, 0.32, 1); /* UI 互動 */
--ease-in-out: cubic-bezier(0.77, 0, 0.175, 1); /* 畫面內移動 */
--ease-drawer: cubic-bezier(0.32, 0.72, 0, 1); /* iOS 風格抽屜,出自 Ionic */
還有一句很絕對的話:UI 動畫不要用 ease-in。理由是 ease-in 一開始動得慢,而開頭正是使用者盯得最緊的時候,同樣 300ms,ease-in 感覺比 ease-out 慢。
要多快?
| 元件 | 時長 |
|---|---|
| 按鈕按壓回饋 | 100–160ms |
| tooltip、小 popover | 125–200ms |
| dropdown、select | 150–250ms |
| modal、drawer | 200–500ms |
細節清單
最後的 Review Checklist 有 11 列,我挑幾條最容易在 AI 產出裡看到的:
transition: all要改成指定屬性。- 進場不要從
scale(0)開始,改成scale(0.95)加opacity: 0。 - popover 的
transform-origin要對準觸發點;modal 例外,維持置中。 - hover 動畫要包在
@media (hover: hover) and (pointer: fine)裡,避免觸控裝置點一下就觸發。 - 進場和離場同速要改成離場比較快。
- 一起出現的多個元素加 30–80ms 的錯開。
🧪 實測:同一個下拉選單,有沒有用上它差在哪
我開了幾個乾淨的資料夾,Claude Code 版本 2.1.306、模型 Sonnet,用 claude -p 跑同一句需求,排除我自己的全域 CLAUDE.md 與 rules,避免它們干擾:
在目前資料夾建立單一檔案 dropdown.html:一個「更多操作」下拉選單(按鈕點開,
裡面 5 個選項),要有開啟與關閉的動畫,點外面或按 Esc 會關閉,選項可以用
鍵盤上下鍵移動。只用原生 HTML/CSS/JS,不要裝套件、不要用 CDN。
寫完檔案就結束,不用解釋。
對照組沒裝 skill,跑了 3 次;實驗組在需求前面加 /emil-design-eng。另外有 3 次是裝了 skill、但不點名(下一節談觸發)。
程式碼差在哪
| 項目 | 沒用 skill(3 次) | 點名 /emil-design-eng |
|---|---|---|
| 曲線 | 內建 ease | --ease-out: cubic-bezier(0.23, 1, 0.32, 1) |
| 開/關時長 | 160ms/160ms,對稱 | 170ms/110ms,關閉較快 |
| 起始狀態 | scale(.96) + translateY(-6px) | scale(0.95) + translateY(-4px) |
| 按鈕按下 | 3 次中有 2 次加了 scale(.97) | scale(0.97) |
| 減少動態 | transition: none、0.01s 或 0s,全部歸零 | 只拿掉 transform,保留透明度淡入淡出 |
| 檔案長度 | 163/163/147 行 | 232 行 |
.menu {
transform-origin: top left;
opacity: 0;
transform: scale(0.95) translateY(-4px);
/* exit: faster than enter */
transition: opacity 110ms var(--ease-out), transform 110ms var(--ease-out),
visibility 0s linear 110ms;
}
.menu[data-open="true"] {
opacity: 1;
transform: none;
transition: opacity 170ms var(--ease-out), transform 170ms var(--ease-out),
visibility 0s;
}
這幾項都能對回 skill 原文:自訂 ease-out、dropdown 150–250ms、不從 scale(0) 開始、按鈕 scale(0.97)、離場比進場快、減少動態保留透明度。
用 Playwright 量動態
開啟後的靜態畫面,兩邊幾乎分不出來。差異只有 icon 換成 SVG、刪除前面加了分隔線:
所以我改量動態。用 Playwright 開 headless Chromium,在每個 requestAnimationFrame 讀選單的 computed opacity 與 transform,開啟量一次、按 Esc 關閉量一次:
| 版本 | opacity 首次 ≥ 0.9 | 關閉時 opacity ≤ 0.1 | 完全關閉 |
|---|---|---|---|
| 沒用 skill #1 | 183ms | 106ms | 160ms |
| 沒用 skill #2 | 154ms | 114ms | 169ms |
| 沒用 skill #3 | 152ms | 100ms | 155ms |
點名 /emil-design-eng | 102ms | 50ms | 98ms |
點名版的總時長只比對照組多 10ms,但強 ease-out 讓大部分變化擠在前段,看起來「一按就出來」。關閉方向的差距更大,是因為時長本身就縮短了。headless 的 rAF 取樣有幾毫秒抖動,這些數字適合拿來比相對快慢,不適合當絕對規格。
我也開了 reducedMotion: 'reduce' 再量一次:點名版的 scale 全程停在 1,透明度照樣漸變;對照組因為整段 transition 被關掉,畫面是直接跳出來。
🔍 它會自動觸發嗎?要吃多少 context?
觸發:3 次只有 1 次
Claude Code 在 session 開始時會把每支 skill 的 description 列給模型,由模型自己決定要不要載入。emil-design-eng 沒有 disable-model-invocation,所以理論上可以自動觸發。同 repo 只有 pick-ui-library、prototype、review-animations 三支設了這個欄位,必須手動點名。
但它的 description 只說「這份 skill 編碼了 Emil 的哲學」,沒有像 apple-design 那樣列出「Use when building or reviewing…」的情境清單。我裝好 skill、不點名,同一句需求跑了 3 次:
| 次數 | 有沒有呼叫 Skill 工具 | 產出的曲線與時長 |
|---|---|---|
| 第 1 次 | 沒有 | transform 用了 cubic-bezier(0.23, 1, 0.32, 1),opacity 仍是 ease,開關都約 150–180ms |
| 第 2 次 | 沒有 | 開啟用帶回彈的 cubic-bezier(.2,.9,.3,1.1),180ms 開、150ms 關 |
| 第 3 次 | 有 | 自訂 ease-out、180ms 開/120ms 關,另外把 hover 包進 (hover: hover) and (pointer: fine) |
Context 成本:約 9.9k tokens
SKILL.md 是 27,797 bytes。我從 stream-json 讀每次執行第一個請求的 input tokens:
| 情境 | 第一個請求 input tokens | 單次執行成本 |
|---|---|---|
| 沒裝 skill | 25,360 | 0.076 美元 |
| 裝了沒點名、沒觸發 | 25,419 | 0.075 美元 |
點名 /emil-design-eng | 35,313 | 0.140 美元 |
claude -p 回報的 total_cost_usd。自動觸發的第 3 次也類似,成本 0.124 美元、對話輪數從 2 輪變 4 輪。如果你在一個 session 裡只是要改一個按鈕顏色,載入這份 skill 不划算。
⚖️ 跟 apple-design 差在哪、哪裡重疊?
同 repo 的 apple-design 是 290 行,我之前實測過。兩支並排讀完:
| 比較 | emil-design-eng | apple-design |
|---|---|---|
| 行數 | 674 | 290 |
| 出發點 | Emil 自己做 sonner、vaul 與產品 UI 的判斷 | Apple WWDC 設計演講,主軸 Designing Fluid Interfaces |
| 主力題材 | 一般 UI 元件:按鈕、dropdown、popover、tooltip、toast | 手勢互動:拖曳、sheet、動量、橡皮筋、半透明材質 |
| 時間觀 | 以 duration 與 easing 為主,spring 是其中一節 | 以 spring 為主,主張用行為取代固定時長 |
| 獨有內容 | 頻率表、Before/After/Why 審查格式、clip-path 技法、Sonner 原則 | 動量投射公式、橡皮筋公式、材質層級、字體光學尺寸 |
| description | 一句話,沒寫使用情境 | 列出 drag、spring、sheet 等使用情境 |
我的選法:要寫的是拖曳、可甩動的面板,用 apple-design;是一般網頁元件的開關動畫、要審查既有 CSS 的時長與曲線,用 emil-design-eng。兩支都裝不會撞名,但同一次需求兩支都載入會再多吃一份 context。
⚙️ 怎麼安裝與點名?
只裝這一支,指令是:
npx skills@latest add emilkowalski/skills --skill emil-design-eng
不加參數時 CLI 會問要裝給哪個 agent。我實際跑的是帶 agent 與跳過確認的版本,當時 skills CLI 是 1.7.4:
npx -y skills@latest add emilkowalski/skills --skill emil-design-eng -a claude-code -y
跑完專案裡會出現 .claude/skills/emil-design-eng/SKILL.md(674 行)和 skills-lock.json。CLI 會顯示第三方安全評估,我那次是 Gen Safe、Socket 0 alerts、Snyk Low Risk。
點名方式有兩種:
- 在需求最前面打
/emil-design-eng,後面接具體需求。這樣 skill 內容會直接展開進對話。 - 在需求裡寫「依照 emil-design-eng skill」,讓模型自己去載入。
/emil-design-eng 不帶問題時,skill 規定只回一句「I'm ready to help you build interfaces that feel right…」,不會主動給建議。這是設計,不是壞掉;要它做事就把需求接在同一行。
要它審查既有程式碼時,輸出會是 Before/After/Why 三欄表格,這是 skill 標為 Required 的格式。
🚧 什麼情況不適合用
- 只改小東西:一次載入約 9.9k tokens。改一個顏色或文案不需要它。
- 手勢為主的互動:它有 Gesture and Drag 一節,但深度不如 apple-design 的動量與橡皮筋公式。
- 鍵盤密集的工具型產品:它本身就會建議你少做動畫。如果你期待它「幫我加很多動畫」,結果可能相反。
- React Native、Swift:範例以 CSS、Motion 為主。同 repo 有 animate-expo 和 write-swift。
- 想用靜態截圖驗收:這次實測靜態畫面幾乎一樣,要看差異得量時間曲線,或至少在 DevTools 的 Animations 面板放慢播放。
🔗 延伸資源
- GitHub repo:emilkowalski/skills(2026-10-21 查詢為 48,159 stars、2,785 forks,這是 repo 內 15 支 skill 共用的數字)
- skill 原文:skills/emil-design-eng/SKILL.md
- 手勢與彈簧那一半:apple-design skill 實測
- 只想審查動畫、不想載入整份:review-animations
- 作者網站:emilkowal.ski
/emil-design-eng 請 Claude Code 依 Review Checklist 審一次,拿到 Before/After/Why 表格後,先只改 easing 和離場時長兩項,再用 DevTools 放慢 4 倍看前後差異。