首頁 / Skills / 網頁與介面設計 / 設計工程 Design Engineering(Emil Kowalski)
網頁與介面設計

設計工程 Design Engineering(Emil Kowalski)

Emil KowalskiMITSkill 語言: 英文
授權已核對不含腳本低風險
演示真實執行紀錄 · claude-sonnet-5-5 · 2026年10月
Please review this UI code for polish and animation problems. ```css .btn { transition: all 300ms; } .menu { transform: scale(0); transform-origin: center; transition: transform 500ms ease-in; } .menu.open { transform: scale(1); } .card:hover { transform: scale(1.05); } .row { opacity: 0; animation: slideIn 600ms ease-in-out forwards; } ``` ```jsx <motion.div animate={{ x: open ? 0 : -300 }} /> // Cmd+K opens the command palette with a 400ms fade and slide ``` The .menu is a dropdown anchored to a profile button; the row animation plays on a list of 40 items all at once.
Skill: emil-design-eng

Here's the review.

Before After Why
.btn { transition: all 300ms; } transition: transform 160ms ease-out; plus .btn:active { transform: scale(0.97); } all animates properties you didn't intend to animate and can trigger layout and paint. 300ms is too slow for button feedback (aim for 100-160ms). The button also has no press state.
.menu { transform: scale(0) } transform: scale(0.95); opacity: 0; and .menu.open { transform: scale(1); opacity: 1; } Nothing in the real world appears from nothing. scale(0) makes the menu pop out of a point.
transform-origin: center on the profile dropdown transform-origin: top right (or the trigger's side), or var(--transform-origin) if you use Base UI or Radix A popover should grow from its trigger. Only modals stay centered.
transition: transform 500ms ease-in transition: transform 180ms cubic-bezier(0.23, 1, 0.32, 1), opacity 180ms ease-out; ease-in starts slow, which is exactly when the user is watching. 500ms is far too long for a dropdown (150-250ms). Make the close faster than the open, around 120ms.
.card:hover { transform: scale(1.05); } Wrap it in @media (hover: hover) and (pointer: fine), drop to about scale(1.02), and add transition: transform 200ms ease-out on .card Touch devices fire hover on tap, so the card sticks scaled. There is also no transition, so the hover snaps. 1.05 is heavy for a card, and it resizes the content and can cause neighbors to look cramped.
.row { animation: slideIn 600ms ease-in-out forwards; } on 40 items at once animation: slideIn 250ms cubic-bezier(0.23, 1, 0.32, 1) both; with animation-delay: calc(var(--i) * 30ms), and cap the stagger (for example min(var(--i), 8)) Entering elements need ease-out, not ease-in-out. 600ms is too long. All 40 rows moving in unison reads as one block, so stagger them by 30-80ms. Don't let the stagger run for seconds (40 × 30ms is 1.2s), so cap it. Never block interaction while it plays.
.row { opacity: 0; ... } as the base style Put the hidden state in the keyframe's from and use animation-fill-mode: both If the animation fails or is disabled, rows stay invisible forever. Also consider @starting-style or transitions if rows get added dynamically, since keyframes restart from zero when interrupted.
<motion.div animate={{ x: open ? 0 : -300 }} /> animate={{ transform: open ? "translateX(0)" : "translateX(-100%)" }} with an explicit transition, such as a spring (duration: 0.3, bounce: 0) The x shorthand runs on the main thread and drops frames under load. A hardcoded -300 breaks if the panel width changes, so percentages are safer. Springs also keep velocity if the user toggles mid-motion.
Cmd+K palette with a 400ms fade and slide No animation. Render it instantly. A keyboard shortcut used hundreds of times a day should feel instant. Raycast does this. If you want some softness, use at most a 100ms opacity-only fade, and none on close.
No reduced-motion handling anywhere @media (prefers-reduced-motion: reduce) keeps opacity fades and removes the slide, scale and translate motion. In Motion, use useReducedMotion(). Reduced motion means gentler, not zero. Keep the fades that aid comprehension and remove the movement.

Priorities

  1. Remove the Cmd+K animation. It has the biggest impact on how the app feels.
  2. Fix the dropdown (scale(0), ease-in, 500ms, center origin), since it hits every issue at once.
  3. Stagger and shorten the list animation.
  4. Clean up transition: all, the hover gating, and the Motion x prop.

Suggested CSS for the dropdown and rows

:root { --ease-out: cubic-bezier(0.23, 1, 0.32, 1); }

.menu {
  opacity: 0;
  transform: scale(0.95);
  transform-origin: top right; /* match the profile button's position */
  transition: transform 120ms var(--ease-out), opacity 120ms ease-out;
}
.menu.open {
  opacity: 1;
  transform: scale(1);
  transition-duration: 180ms;
}

.row {
  animation: slideIn 250ms var(--ease-out) both;
  animation-delay: calc(min(var(--i), 8) * 40ms);
}
@keyframes slideIn {
  from { opacity: 0; transform: translateY(8px); }
}

The menu's closed state needs pointer-events: none or visibility: hidden so it isn't clickable while invisible.

Test run: a pasted CSS and JSX snippet with common animation mistakes. The model used the required Before, After, Why table, flagged the Cmd+K palette animation and gave a priority list. Nothing was run or rendered; the suggested values come from the Skill's own tables.

它做什麼

把一位設計工程師對介面打磨的做法寫成規則。它依序提出動畫問題:這個到底要不要動畫(每天用上百次的鍵盤操作永遠不要)、目的是什麼、用哪種緩動、多快。它主張用自訂的強緩動曲線,而不是 CSS 內建的幾種,讓介面動畫保持在約 300 毫秒以內,並說明何時該用彈簧。它也涵蓋元件細節(按下回饋、不從 0 縮放、從觸發點出現的彈出層、提示框的延遲規則、用轉場而不是關鍵影格)、clip-path 技巧、拖曳與手勢、效能規則(只對 transform 與 opacity 做動畫)、減少動態效果與觸控裝置上的懸停處理。評審必須以「修改前 / 修改後 / 原因」的表格輸出,並附一份檢查清單。

輸出

評審表格、優先順序清單,以及附有每個數值理由的 CSS 或 JSX 建議。

適合什麼場景

想讓介面「手感對」的前端開發者與設計師,以及想為動態與元件打磨建立統一評審標準的團隊。

說明與風險

低風險:純指令檔,沒有腳本,不連網,不寫檔。它給出的是主張鮮明的前端建議,數值來自作者自己的表格,請當作有力的預設值,而不是鐵律。已用一段貼上的程式碼試用一次:回傳了規定的表格,指出命令面板的動畫問題並給出優先順序。沒有執行或渲染任何東西。沒有帶問題呼叫時,它只會回覆一句簡短的問候。作者 Emil Kowalski,MIT 授權。

SKILL.md 原文套件內共 2 個檔案