Communitygithub.com

nkurunziza-saddy/motion

為產品 UI 建立網頁動畫。它會判斷元素是否該動、為何而動,然後選擇工具(CSS transition、WAAPI、Motion、spring)、屬性、曲線、持續時間、中斷、離開與減少動畫路徑,並產出程式碼。也涵蓋錯開與編排、手勢(拖曳、輕彈、面板)、動畫權杖與效能。

motion 是什麼?

這個技能是專為產品 UI 的動畫設計而打造的決策引擎,支援 Claude Code、Cursor、Codex 等 AI 代理工具。它提供了一套嚴謹的動畫決策流程,從最關鍵的「是否該動」開始(根據使用者觀看頻率分級),接著明確命名動畫目的(空間、狀態、回饋、連續性、說明),然後選擇「最便宜且有效」的工具(從 CSS transition 到 Motion 函式庫),並嚴格規範可動畫的屬性(僅 transform 與 opacity)、曲線與持續時間的搭配(使用預定義的設計權杖)。技能也深入處理中斷機制(transition 與 spring 優於 keyframes)、離開動畫的方向性、減少動畫偏好設定,以及複雜的編排邏輯(主角、配角、裝飾、靜態元素的分工)。最後透過自動化差異檢查清單與效能驗證(4 倍速播放、CPU 節流)確保實作品質。它的核心哲學是「零行動畫也是一個有效結果」,避免過度動畫造成 UI 遲緩。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/nkurunziza-saddy/hmm-interfaces/tree/HEAD/motion

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

motion 是做什麼的?

此技能負責建立動畫。它擴充了 product-ui/references/values.md 中的動畫章節,該檔案存放已確定的數值(緩動曲線、按壓縮放、彈跳、錯開、持續時間表格、彈出通知與版面配置持續時間、移動距離、退出與進入比例)。此處不重複這些數值;此技能加入了決策順序、權杖、配方與失敗模式。

在任何決策之前,請先套用 product-ui §1(品味日誌與優先順序)與 §5(哪個技能負責什麼)。

決策順序

依序從上到下進行。每個步驟都可以結束任務。零行動畫是有效的結果,請直接說明。

1. 該動嗎?頻率閘門

詢問一位使用者每天看到這個動畫的次數。分級標準在 values.md 中。實務上:

  • 由鍵盤觸發,或每天看到 100 次以上:不加入動畫。原因:重複的動畫會變成延遲。
  • 每天看到幾次(懸停、分頁切換、行選取):不加入動畫,或僅做即時的色彩變化。
  • 使用者正在閱讀或操作的資料(表格中的數字、即時儀表板中的圖表)絕不會為了風格而動。原因:動畫會將視線從正在閱讀的內容上拉開。
  • 如果閘門判定為「否」,則不寫入動畫。說明它命中了哪個分級,並提供靜態替代方案(即時的狀態變更)。

2. 命名目的

選擇一個詞:空間(從哪裡來或到哪裡去)、狀態(此處已變更)、回饋(我聽到了)、連續性(防止跳躍)、說明(僅在罕見時刻)。如果無法命名一個詞,則停止。原因:頻繁元素上的「看起來不錯」是造成 UI 感覺遲緩的主要原因。

3. 選擇工具:最便宜且有效的那個

需求工具
由 class、屬性、懸浮或按壓切換的狀態CSS transition
從 display: none、彈出視窗或對話框進入@starting-style + transition-behavior: allow-discrete
一次性序列、錯開,或在頁面忙碌時必須執行的動畫CSS @keyframes
JS 決定何時開始;需要取消、反向、finished 或 FLIPWAAPI el.animate()
Spring、速度傳遞、卸載中 React 節點的離開、共享版面配置Motion (motion/react)

如果是整個元件(選單、彈出通知、抽屜),請使用內建焦點處理的函式庫,並呼叫 pick-library。切勿為了淡入效果而安裝 Motion。原因:CSS 在主執行緒外執行,且不增加套件大小。

4. 屬性

  • 對 transform 和 opacity 設定動畫;filter 僅用於 ≤ 2px 的交換模糊。命名每個屬性;絕不使用 transition: all。
  • 高度和版面配置變更:請參閱 references/recipes.md(網格行、FLIP)。切勿設定 width、top、left 或 margin 的動畫來移動元素。原因:每個都會在每一幀強制進行版面配置。
  • 切勿設定 box-shadow 的動畫。請改為淡入偽元素的 opacity。
  • translate 百分比是相對於元素自身大小,因此 translateY(100%) 適用於任何高度的抽屜和彈出通知。

5. 曲線與持續時間,依用途配對

切勿選擇最接近你猜測的數值。先說明用途(「選單關閉」、「圖示交換」),然後從 references/tokens.md 中選取對應的行。如果沒有與用途相符的行,請新增一個以該用途命名的權杖;不要硬套現有的權杖。原因:權杖是對動畫用途的陳述,因此用途不對的近似值就是錯誤的權杖。

  • 進入或離開:--ease-out。在螢幕上移動:--ease-in-out。抽屜:--ease-drawer。色彩:ease。旋轉圖示:linear。絕不使用 ease-in。
  • 任何可拖曳或在動作途中可中斷的元素應使用 spring,而非曲線。原因:曲線無法承接使用者手部產生的速度。
  • 感覺遲緩:先縮短持續時間,再減少移動距離,最後才調整曲線。

6. 中斷

  • 使用者可以在一秒內觸發兩次的任何項目,都應使用 transition 或 spring,絕不使用 @keyframes。原因:transition 會從當前值重新定位;keyframes 會重新啟動並跳躍。
  • WAAPI:在讀取當前值後取消舊動畫,並從該值開始新的動畫(references/recipes.md)。
  • 一個切換開關被快速點擊 10 次,必須在正確的狀態結束,且無跳躍。請測試它。

7. 離開

  • 預設離開是淡出,且比進入更短(權杖檔案中有各組配對)。
  • 任何有方向的元素(抽屜、面板、滑動關閉的彈出通知)應以原路離開。
  • 離開的元素會立即停止佔用空間,因此兄弟元素會在它淡出時填補空隙。
  • 離開動作是同時進行的,絕不錯開。原因:使用者已經決定要離開了。

8. 減少動畫,與動畫一同提供

保留不透明度和色彩。滑動、縮放、模糊和彈跳移除;滑動變為淡出,彈跳變為 0。切勿將動畫作為唯一的提示。模式請參閱 references/recipes.md。

編排

在計時之前,先為每個移動元素分配角色:

角色處理方式
主角(唯一需要關注的事物)最先移動,移動距離最遠
配角跟隨移動,移動距離較短
裝飾原地淡入,或不移動
靜態(容器、瀏覽器外殼)絕不移動
  • 每個容器只有一次進入。如果面板滑入,其內容應已存在。原因:兩層進入動畫會讓使用者等待兩次。
  • 順序以重要性為準,而非 DOM 順序。延遲保持在 values.md 的步驟(項目之間 40ms,標題、文字和動作之間 100ms)。透過角色而非延遲來變化移動距離和持續時間。
  • 列表錯開在第 6 項達到上限(最後一項延遲 240ms);之後的項目共用此延遲。在動畫播放期間,輸入功能仍需正常運作。
  • 絕不錯開選單、指令面板、分頁內容或任何重複開啟的項目。
  • 保持靜止:使用者即將點擊的任何項目、頁面再次載入時已在螢幕上的任何項目,以及距離上一次更新在 150ms 內的更新(直接跳到結束狀態)。
  • 方向應符合意義:下一項從右側進入,返回從左側進入;使用者觸發的事物從觸發點向外展開。

需要時才載入

  • references/tokens.md:當需要確切的持續時間、距離、縮放、模糊、緩動或 spring 值,以及為現有程式碼庫建立權杖時載入。
  • references/recipes.md:當建置選單、彈出視窗、對話框、抽屜、彈出通知、列表進入、圖示交換、高度變更、分頁指示器或數字變更時載入。
  • references/gestures.md:當需要拖曳、滑動、輕彈、面板,或任何跟隨指標的事物時載入。
  • references/performance.md:當動畫掉幀時,在動用 will-change 之前,以及當更新快速到來時載入。

配對範例

錯誤寫法修正寫法原因
.menu { transition: all 300ms ease-in }transition: opacity 200ms, transform 200ms var(--ease-out)命名屬性;ease-in 感覺遲緩;選單 ≤ 200ms
scale(0) 到 scale(1)scale(0.95) 和 opacity: 0 到 1沒有東西是從虛無中出現的
彈出視窗從中心縮放transform-origin: var(--transform-origin)它應該從它的觸發點向外生長
.open { animation: slide-in 300ms }transition: transform 在切換的狀態上Keyframes 在中斷時會快照跳躍
每一行 animation-delay: i * 120msmin(i, 6) * 40ms最後一行在 300ms 內到達
抽屜在滑入後淡出它會沿原路滑出方向本身就是一種解釋
拖曳放開時使用固定的 ease-out使用帶有釋放速度的 spring手的動量會持續
在 pointermove 中使用 setY(y)el.style.transform = ...避免每幀重新渲染

完成前

搜尋 diff,然後驗證。

搜尋內容修正方式
transition: all、* 上的 will-change、ease-in使用命名屬性、移除、改為 --ease-out
彈出視窗上的 scale(0)、transform-origin: center改為 0.95、觸發點的原點(對話框保持置中)
在一個會切換的 class 上的 @keyframes改為 transition
持續時間超過 tokens.md 中對應行,或某個數值不在 tokens.md 中使用該用途的權杖
keydown 處理器或指令面板上的動畫移除它
transition 中的 width、height、top、left、box-shadow改為 transform、opacity,或依照配方
沒有 prefers-reduced-motion 路徑新增它

在執行中的應用程式裡驗證:以 4 倍速播放(開發者工具動畫面板,或將持續時間乘以 4),快速點擊任何切換開關,在開啟減少動畫的情況下測試,並將 CPU 節流至 4 倍。說明哪些測試你無法執行。

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

nkurunziza-saddy/break

Stress-tests a piece of UI with worst-case data and every reachable state, then reports what broke with a numbered fix for each. Use it when the user types /break, or asks to "break this", "stress-test", "try the worst case", "what happens with long names", "check the empty and error states" or "find the edge cases" on a component or screen.

nkurunziza-saddy/layout

Structure and space in product UI on the web. It sets the spacing scale, grouping, alignment, density (compact or comfortable), hit areas, app shells (sidebar, toolbar, content, inspector), max widths, container-query responsiveness, dropdown and popover sizing, room for long and translated text, layout stability (no shift on load) and sticky elements that must not cover focus.

nkurunziza-saddy/pick-library

Picks the right library for a frontend task from a curated, status-checked list, instead of hand-rolling it or installing an abandoned package. Use it when the user asks "what should I use for…", "is there a library for…", or names a package, and when you are about to build a toast, command menu, drawer, date picker, table, virtual list, drag and drop, chart, OTP input, animated number, theme switch, form validation…

nkurunziza-saddy/surfaces

What product UI is made of on the web. It sets elevation levels with exact shadow recipes for light and dark mode, when to use a shadow and when a border, the transparent border for forced-colours mode, a small radius scale with concentric nesting, image outlines, every interactive state as a surface change (hover, pressed, selected, disabled, focus-visible), icons (one set, currentColor, outline and fill, stroke tha…

相關技能