AI 工具 24 min read

animate skill 實測:4 次都拒絕替 Ctrl+K 加動畫

animate 是 Emil Kowalski 在 2026 年 8 月放進 emilkowalski/skills(MIT)的 Claude Code skill,用一份 SKILL.md 加 14 份元件食譜,把「加個動畫」拆成先問該不該動、再挑工具與曲線的 7 步流程。同一句需求實測,沒裝 skill 的 3 次都替 Ctrl+K 面板加了動畫、1 次還弄壞,有 skill 的 4 次全部拒絕,下拉選單也統一用 0.95 縮放與同一條曲線——它最有價值的是會說「這不該動」。

animate skill 實測:4 次都拒絕替 Ctrl+K 加動畫
本文目錄 · 9
懶人包
  • animate 是 Emil Kowalski 開源在 emilkowalski/skills(MIT)裡的 Claude Code skill,2026-08-05 加入。它把「做一個動畫」拆成 7 步固定順序:先問該不該動、為了什麼,才輪到工具、屬性、曲線、中斷與退場。
  • repo 在 2026-10-21 是 48.2k stars、2.8k forks,這是 15 支 skill 共用的數字,不是 animate 一支的。
  • 我用同一句需求「替帳號下拉選單和 Ctrl+K 命令面板加開關動畫」各跑多次:沒裝 skill 的 3 次全都替面板加了動畫,其中 1 次還把 Ctrl+K 弄成按了打不開;有 skill 的 4 次全部拒絕替 Ctrl+K 加動畫,理由是鍵盤快捷鍵一天會按上百次。
  • 有 skill 的下拉選單統一用 scale(0.95)、cubic-bezier(0.23, 1, 0.32, 1),開 180ms、關 120ms(4 次裡 3 次如此);開了「減少動態效果」時保留淡入淡出,沒裝 skill 的版本則直接把動畫全關。
  • 沒點名的情況跑 3 次,3 次都自動載入;只打 /animate 不帶需求,它只回一句固定開場白。在 Git Bash 用 claude -p "/animate ..." 時,/animate 會被改寫成 Windows 路徑。
  1. animate skill 是什麼?
  2. 裡面有哪兩份檔案、各做什麼?
  3. 7 步決策在講什麼?
  4. 實測:同一句需求,有沒有 skill 差在哪
  5. 什麼時候會觸發?要不要點名?
  6. 怎麼安裝到 Claude Code?
  7. 限制與坑
  8. 適合誰、不適合誰?
  9. 延伸資源

🎬 animate skill 是什麼?

animate 是一份給 AI coding agent 讀的 SKILL.md,作者是 Emil Kowalski(toast 函式庫 Sonner 的作者),收在 emilkowalski/skills 這個 MIT 授權的 repo 裡。README 對它的介紹只有一句:從零做一個動畫,同時選對曲線、時長、屬性等細節。

它自稱是「construction skill」,只做一件事:把「幫我加個動畫」變成一段能通過嚴格審查的實作。審查既有動畫、掃整個專案、找哪裡可以加動畫、寫 React Native,都明確交給同 repo 的其他 skill(review-animations、improve-animations、find-animation-opportunities、animate-expo)。

它開宗明義列了兩種失敗,並說第一種比較糟:

  1. 替不該動的東西加了動畫。 所以第一步的關卡有時候會產出「零行程式碼」,skill 原文說這是成功,不是推託。
  2. 該動的東西用錯材料:進場用 ease-in、從 scale(0) 長出來、toast 用 keyframes、下拉選單的時長拖到讓人覺得卡。
還有一條語氣上的規定:不要把動畫方案列成選單讓使用者挑,直接決定、用一行說理由、寫程式碼。

📦 裡面有哪兩份檔案、各做什麼?

資料夾裡只有兩個檔案(以 commit 2d22863 為準):

檔案行數內容
SKILL.md207frontmatter、開場白規則、5 條硬規則、7 步決策流程、Never Ship 自檢表、輸出格式
RECIPES.md32414 個常見元件的現成寫法
SKILL.md 是主體。除了下一節要拆的 7 步,還有兩塊值得先看:
  • 5 條硬規則:照順序走、不准用「看起來眼熟」的近似值(曲線、時長、spring 參數都要從表裡拿)、專案已經有 --ease-out 之類的 token 就沿用不要另起一套、減少動態效果與 hover 防護要跟動畫一起交付、能用最便宜的工具就不要裝動畫函式庫。
  • Never Ship 表:13 列「不准出貨」的寫法和替代做法,例如 transition: all、scale(0) 進場、UI 用 ease-in、沒理由超過 300ms、錨定在按鈕上的 popover 卻用 transform-origin: center、動 width/height/top/left、沒防護的 :hover 動畫、整群元素同時進場(要錯開 30–80ms)。原文說這 13 項每一項在 review-animations 裡都是直接擋下。
最後的輸出格式也有規定:寫完程式碼後最多用幾行交代「關卡結果」「用了哪些材料」「哪裡要靠眼睛確認」,不要寫成報告。

RECIPES.md 是 14 份食譜:按鈕按壓、下拉選單/popover、tooltip、modal、drawer、toast、手風琴、群組錯開進場、長按確認、分頁指示器、捲動揭示、拖曳關閉、用模糊遮掉不乾淨的交叉淡化、不靠函式庫的 WAAPI。每份都是一小段 CSS 或 JS 加一兩句「為什麼」,例如:

  • tooltip 打開一個之後,鄰近的 tooltip 要瞬間出現(transition-duration: 0ms),整排工具列才會感覺快。
  • toast 刻意用 ease 和 400ms,比一般 UI 慢,因為 Sonner 的手感是依元件個性調的。
  • 長按確認的填色用 linear 2 秒,放手時 200ms 收回,進度條本來就不該有緩動。
  • 拖曳關閉除了距離門檻,還看速度(原文用 velocity > 0.11),並要求 pointer capture、多指防護、超出邊界的阻尼。
SKILL.md 說請求符合這些元件時要先讀 RECIPES.md。不過我在下面的 4 次實測裡,模型都只讀了 index.html,沒有一次打開 RECIPES.md。

🧭 7 步決策在講什麼?

這是整份 skill 的核心。原文要求按順序走,第 1、2 步沒過就不准往下。

第 1 步:這東西該動嗎?

用「一天會觸發幾次」分四級:

頻率決定
一天 100 次以上(鍵盤快捷鍵、命令面板開關)不加動畫,到此為止
一天數十次(hover、列表上下移動)只能快到幾乎察覺不到,或乾脆不加
偶爾(modal、drawer、toast)標準動畫
很少或第一次(新手引導、成功、慶祝)才有「好玩」的額度
原文特別寫了一句:由鍵盤觸發的動作直接出局,不是判斷題,並舉 Raycast 沒有開關動畫為例。被擋下時要直說,改給不靠動畫的替代方案,例如瞬間切換或一個靜態提示。

第 2 步:目的是什麼?

必須能用六個詞之一說出目的:回饋、空間一致性、狀態提示、避免突兀跳動、說明(限行銷頁與新手引導)、驚喜(只限第 1 步最少用的那一級)。說不出來就不做。另外,使用者正在讀或操作的資料,不能為了風格而移動。

第 3 步:挑最便宜的工具

由上往下,符合就停:CSS transition → CSS @starting-style(掛載時進場)→ CSS animation(頁面忙的時候仍要順,跑在主執行緒外)→ WAAPI(要程式控制但不想加函式庫)→ Motion(spring、版面動畫、退場、手勢)。

如果需求其實是「元件」而不是動畫,例如 toast、drawer、命令選單、下拉選單,要停下來改用 pick-ui-library 選元件庫,避免手刻出一個沒有焦點管理的 <div> 下拉選單。

第 4 步:動哪些屬性

  • 只動 transform 和 opacity;clip-path 是第四個許可項,height 只限手風琴。
  • 不准 scale(0),從 scale(0.9–0.97) 加 opacity: 0 開始。
  • popover、下拉選單、tooltip 的 transform-origin 放在觸發它的按鈕上;modal 例外,維持置中。
  • translate() 優先用百分比;Motion 裡用完整的 transform 字串而不是 x/y 簡寫。
  • 不要用父層的 CSS 變數去驅動子元素的 transform,每個子元素都會重算樣式。

第 5 步:曲線、時長或 spring

曲線依情境挑:進場、退場用 ease-out;畫面上移動用 ease-in-out;hover 和顏色用 ease;等速運動用 linear。UI 一律不用 ease-in,因為它在使用者盯著看的那一刻最慢。

它認為 CSS 內建的曲線太弱,給了三個 token:

--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);

時長表:按鈕回饋 100–160ms、tooltip 125–200ms、下拉選單 150–250ms、modal 與 drawer 200–500ms,UI 動畫原則上 300ms 以內。拖曳、可中途反轉的手勢改用 spring,原文建議 { type: "spring", duration: 0.5, bounce: 0.2 },bounce 控制在 0.1–0.3。

第 6 步:被打斷與退場

會被連續觸發的東西用 transition 不用 keyframes,因為 transition 會從當下的值接著走,keyframes 會從頭重播。手勢用 spring 才能把速度帶過中斷點。怎麼進來就怎麼出去。使用者在做決定的地方用不對稱時間,例如長按確認按住時 2 秒、放開 200ms。

第 7 步:減少動態效果與 hover 防護

這兩項「每次都跟著動畫一起出貨」。prefers-reduced-motion 的意思是更少、更溫和,不是歸零:保留有助理解的淡入淡出,拿掉位移。hover 動畫要包在 @media (hover: hover) and (pointer: fine) 裡,避免觸控裝置點一下就觸發假 hover。

🧪 實測:同一句需求,有沒有 skill 差在哪

實驗設計

我在暫存目錄建了一個 75 行的 index.html:一個「帳號」下拉選單和一個 Ctrl+K 命令面板,兩者原本都用 display: none 瞬間切換。需求故意把兩個東西寫在一起,因為依照 skill 第 1 步,下拉選單屬於「偶爾」,命令面板屬於「一天 100 次以上」:

幫這個頁面(index.html)的「帳號」下拉選單和 Ctrl+K 命令面板加上開啟/關閉的動畫,讓介面感覺更精緻。直接修改 index.html,不要裝套件、不要用 CDN。改完就結束,最後用三五行說明你做了什麼。

每次都是全新目錄,用 headless 模式執行:

CLAUDE_CODE_DISABLE_CLAUDE_MDS=1 claude -p "$PROMPT" \
  --setting-sources project --strict-mcp-config --model sonnet \
  --dangerously-skip-permissions --output-format stream-json --verbose

--setting-sources project 加上關掉 CLAUDE.md,是為了不讓我自己的全域設定和 skill 混進來。環境是 Claude Code 2.1.306,模型是 Sonnet。分三組:

組別設定次數
沒有 skill專案裡沒有任何 skill3
有 skill、沒點名.claude/skills/animate/ 已裝,需求原樣送出3
有 skill、點名用 skills CLI 安裝,需求前面加 /animate 1

結果

項目沒有 skill(3 次)有 skill(4 次)
Ctrl+K 命令面板3 次都加了 180ms 淡入加位移縮放4 次都拒絕加動畫,維持瞬間開關
下拉選單起始狀態translateY(-4~-6px) scale(.96~.97)scale(0.95),不位移
下拉選單時長開關同為 150 或 160ms3 次開 180ms、關 120ms;1 次開關同為 150ms
曲線透明度用 ease;位移縮放 3 次各不同(cubic-bezier(.2,.8,.2,1)、cubic-bezier(.23,1,.32,1)、ease)4 次全用 cubic-bezier(0.23, 1, 0.32, 1),點名那次還定義成 --ease-out token
減少動態效果3 次都把動畫時間設成 0 或整個關掉4 次都保留淡入淡出,只拿掉縮放
能不能用1 次 Ctrl+K 按了打不開4 次都能用
兩組有一個共通點:都把下拉選單的 transform-origin 設在左上角、也就是按鈕的位置,都用 visibility 延遲讓關閉時也有動畫。差異集中在「該不該動」和「數值從哪來」。

有 skill 的 4 次在最後說明裡都給了拒絕的理由。沒點名的第 2 次是這樣寫的:

Ctrl+K 是鍵盤快捷鍵,一天可能按上百次,每次都等動畫會覺得拖慢。Raycast 這類工具也是刻意做成瞬間開關。如果你堅持要,我可以加一個約 100ms 只做淡入、不做位移的版本。

點名那次則多建議了一個替代方案:不做開關動畫,改加靜態的快捷鍵提示。這兩個說法都對得上 skill 第 1 步「直說並給非動畫替代方案」的要求。

逐格看下拉選單

我用 Playwright 開啟產出的頁面,觸發開啟後把 document.getAnimations() 全部暫停,再把時間軸設到指定毫秒截圖。上排是沒有 skill 的第 3 次,下排是有 skill、沒點名的第 2 次:

下拉選單開啟動畫逐格比較:沒有 skill 的版本在 30ms 透明度 0.27、60ms 0.65;有 animate skill 的版本在 30ms 已到 0.60、60ms 0.88

兩者總時長只差 20ms,差在前段。cubic-bezier(0.23, 1, 0.32, 1) 前段衝得很快,第 30ms 透明度已經 0.60,內建 ease 這時才 0.27。這就是 skill 說「內建曲線太弱」的意思:同樣不到 200ms,前 60ms 看到的東西不一樣多。

Ctrl+K 第 60ms

按下 Ctrl+K 後第 60ms 的命令面板:沒有 skill 的版本遮罩透明度 0.58、面板還半透明;有 animate skill 的版本已完全顯示

沒有 skill 的第 1 次還有一個實際的 bug:它把 .open 狀態從 display: flex 改成只調透明度和 visibility,卻留著基底樣式的 display: none。我用 Playwright 按 Ctrl+K 後量了 0 到 1000ms,class 確實變成 open,display 一直是 none,畫面上什麼都沒出現。那次的最後說明自己也寫了「沒有在瀏覽器裡實際開啟測試」。有 skill 的版本沒碰命令面板,自然沒有這個風險。

這組實驗不能證明什麼

  • 每組只有 3 次(點名只有 1 次),而且只用 Sonnet 一個模型、一個頁面。
  • 「拒絕替 Ctrl+K 加動畫」對不對,取決於你是否同意 skill 的立場。如果需求方明確要求面板有動畫,skill 的做法會變成多一輪溝通。
  • 沒有 skill 的第 2 次湊巧也用了 cubic-bezier(.23,1,.32,1),可見模型本來就認得這條曲線,skill 的作用是讓它每次都用、而且用在每個屬性上。
  • 時長和手感我只量了數值,沒有做使用者測試。

🚦 什麼時候會觸發?要不要點名?

frontmatter 的 description 列了觸發情境:被要求替某個東西加動畫、加 motion、讓元件「活起來」、做 transition。它也寫明「批評既有動畫用 review-animations,稽核整個專案用 improve-animations」,等於告訴模型這三種需求各走哪條路。

animate 沒有設 disable-model-invocation,模型可以自己決定載入。同 repo 只有 pick-ui-library、prototype、review-animations 三支設了這個欄位,那三支一定要手動點名。

實測結果:

  • 沒點名:3 次都在第一步呼叫了 Skill 工具載入 animate。這和 apple-design 那篇 的結果不同,那支 skill 在類似條件下 3 次只觸發 1 次。我的推測是「加動畫」這個字面需求和 animate 的 description 幾乎逐字對上,但只有 3 次樣本,不能當成保證。
  • 點名:在需求前面加 /animate ,skill 內容直接注入,不會出現 Skill 工具呼叫,產出同樣遵守 7 步。
  • 只打 /animate 不帶需求:只回一句固定開場白 "I'm ready to build animations that feel right, my knowledge comes from Emil Kowalski's animation philosophy.",然後等你下指令。這是 2026-09-15 加進 SKILL.md 的 Initial Response 規則,當天另一個 commit 拿掉了句尾的課程連結。
想要穩定效果,我的建議仍然是點名,成本只有多打 9 個字元。

⚙️ 怎麼安裝到 Claude Code?

先確認 CLI 存在,npx skills@latest --help 會列出 add、list、remove、update 等指令(我執行時抓到的是 1.7.4)。只裝 animate 一支:

npx skills@latest add emilkowalski/skills --skill animate

不想回答互動問題,就指定 agent 並加上 -y。我在空目錄實跑的是這行:

npx -y skills@latest add emilkowalski/skills --skill animate --agent claude-code --copy -y

結果:

  • 產生 .claude/skills/animate/SKILL.md 與 RECIPES.md,和 repo 原檔 diff -r 比對完全相同。
  • 根目錄多一個 skills-lock.json,記錄來源 emilkowalski/skills 與檔案雜湊。
  • 安裝過程顯示安全評估:Gen「Safe」、Socket「0 alerts」、Snyk「Low Risk」。
--copy 是複製檔案而不是建 symlink,在 Windows 上比較單純。要裝到使用者層級(所有專案共用)就加 -g。

🕳️ 限制與坑

  • Git Bash 會吃掉 /animate:我第一次在 Git Bash 跑 claude -p "/animate",模型收到的是 C:/Program Files/Git/animate,因為 MSYS 把開頭的 / 當成路徑轉換了。模型自己認出問題並反問要做什麼動畫。加上 MSYS_NO_PATHCONV=1 重跑,就正確回出開場白。在互動式 Claude Code 裡打 /animate 不受影響,這只發生在從 Git Bash 傳參數給 claude -p 的時候。
  • 它會說「不」:第 1 步是硬規則。如果你的產品就是要命令面板有開場動畫,要在需求裡講清楚,或是改請它做「約 100ms 只淡入」的折衷版,它自己也提過這個選項。
  • RECIPES.md 不一定會被讀:4 次實測都沒打開。下拉選單的食譜是 200ms,實測產出是 150 或 180ms,都在 SKILL.md 時長表的 150–250ms 內,但不是食譜原值。想要它照食譜做,就在需求裡直接說「照 RECIPES.md 的 dropdown」。
  • 手感它判斷不了:skill 自己規定要在說明裡指出哪裡要靠眼睛確認,4 次實測都建議用 DevTools 的動畫面板放慢播放。它給的數值是起點,不是驗收。
  • 元件需求會轉給別支 skill:toast、drawer、命令選單這類從零開始的元件,skill 要求先用 pick-ui-library 選元件庫。只裝 animate 一支時,這個轉介會落空。

🙋 適合誰、不適合誰?

適合:

  • 寫網頁前端、常請 AI 加 hover、下拉、modal 動畫,想讓數值有一致來源的人。
  • 專案已有 design token,希望 AI 沿用 --ease-out 這類變數而不是每次自創一條曲線。
  • 想要減少動態效果與觸控 hover 防護「預設就有」,不用每次提醒。
不適合:
  • 審查或重構既有動畫:animate 只負責從零做。審一段既有動畫看 review-animations,掃整個專案用 improve-animations。
  • React Native/Expo:skill 明說交給 animate-expo。
  • 原生 iOS、Android:範例全是 CSS、WAAPI 與 Motion。
  • 行銷頁、需要大量表演性動畫:它的時長表和「100 次」關卡是為產品 UI 設計的,行銷頁可以更長,但它的預設會讓你收斂。

🔗 延伸資源

下一步建議:在你的專案裡挑一個用 display: none 切換的下拉選單和一個鍵盤快捷鍵觸發的面板,用 /animate 請 Claude Code 一起處理,看它對兩者的判斷是否和你預期一致,再用 DevTools 動畫面板放慢 4 倍看前 60ms。
author
陳
陳彥彤

AI 工程師 · AI 顧問。Java 後端 8 年、AI 工程師 2 年。AI 內訓 · AI 導入顧問 · 前後端與雲端培訓。

support

覺得文章有用可以到 GitHub 給個 star,或是透過信箱聊聊 AI 內訓、AI 導入顧問或前後端 / 雲端培訓。