在一个人人都能用 AI 写出能用的软件的时代,品味才是真正的差异化。你有没有过这种经历?让 AI 写一个动画,功能是对的,但总觉得哪里不对——缓动用错了、时长太长了、元素从
—— Emil Kowalski
scale(0) 凭空出现、弹窗从中间放大而不是从按钮长出来……
你知道它感觉不对,但你说不出来为什么不对。
Emil Kowalski——前 Vercel、Linear 设计工程师,Sonner、Vaul 等开源组件的作者——把他多年积累的动画与界面设计经验,打包成了一套 AI Skills。这不是又一个"10 个动画技巧"的清单,这是一套让 AI 拥有设计品味的操作系统。
已有 11,632 名设计师和工程师通过他的课程提升了动画技能。而 Skills,就是这套方法论的 AI 时代版本。
---
为什么你需要这套 Skills?
1.1 AI 没有品味
这是最核心的问题。AI 可以写出功能完美的代码,但它不知道:
- 入场动画应该用
ease-out还是ease-in? - 一个下拉菜单的动画时长应该是 200ms 还是 500ms?
- 为什么
scale(0)的入场感觉就像从虚空中冒出来? - 为什么 popover 必须从触发点长出来,而不是从中心?
所有这些"小细节"叠加在一起,就决定了你的界面是令人惊艳,还是平平无奇。
"所有那些看不见的细节组合在一起,就产生了某种令人惊叹的东西,就像一千个几乎听不见的声音齐声歌唱。"
—— Paul Graham
1.2 这是你的捷径
在 AI 时代,每个人都能快速产出界面。但产出有品味的界面的人,依然稀缺。
这套 Skills 就是你的捷径——把一位顶级设计工程师多年的经验,直接装进你的 AI 代理里。你不需要花几年时间慢慢积累品味,你可以站在巨人的肩膀上。
"AI 不会取代专业知识,它会放大你能从中获得的东西,让你比其他人优秀得多。所以去学编码、学设计、或者在任何其他领域发展专业知识。这极其有价值。"---
—— Emil Kowalski
三大核心 Skill
Emil 的 Skills 包含三个独立但互补的技能,覆盖从创作到审查的全流程:
| Skill | 定位 | 一句话总结 |
|---|---|---|
| emil-design-eng | 主力技能 | 动画 + 设计建议的百科全书,帮你做对每一个决定 |
| review-animations | 严格审查员 | 用 Emil 的标准无情审查你的动画,批准是挣来的,不是默认的 |
| animation-vocabulary | 术语词典 | 把模糊的描述("那个弹一下的东西")变成精确术语 |
2.1 emil-design-eng — 主力技能
这是核心技能。它包含了 Emil 的完整设计工程哲学:从动画决策框架到组件构建原则,从 CSS transform 技巧到 clip-path 魔法。
它能帮你:
- 决定一个元素该不该有动画
- 选择正确的缓动曲线
- 设定合适的动画时长
- 写出有物理感的交互
- 避免常见的性能陷阱
2.2 review-animations — 严格审查员
这是一个专门的审查技能。它只做一件事:用极高的标准审查你的动画代码。
它的默认立场是标记问题——批准是挣来的,不是假设的。一个"能跑"但感觉迟钝、从错误的原点出现、或者频繁触发的过渡,在它眼里是退化,不是通过。
十大不可妥协标准:
| # | 标准 | 违反即标记 |
|---|---|---|
| 1 | 有目的的运动 | 每个动画必须回答"为什么要有这个动画?" |
| 2 | 频率适配 | 每天 100+ 次的操作 → 无动画;偶尔 → 标准动画;罕见 → 可以加惊喜 |
| 3 | 响应式缓动 | 入场/出场用 ease-out;UI 上用 ease-in 直接打回 |
| 4 | 300ms 以内 | UI 动画必须控制在 300ms 以内 |
| 5 | 原点与物理正确性 | Popover 从触发点缩放,不从中心;不从 scale(0) 开始 |
| 6 | 可中断 | 快速触发的动作用 transitions 或 springs,不用 keyframes |
| 7 | GPU -only 属性 | 只动画 transform 和 opacity |
| 8 | 可访问性 | 尊重 prefers-reduced-motion;hover 动画加指针媒体查询 |
| 9 | 不对称的入/出 | 主动作慢,系统响应快 |
| 10 | 一致性 | 动效要匹配组件性格和产品整体风格 |
2.3 animation-vocabulary — 术语词典
你有没有过想描述一个动效但说不出名字?"就是那个……弹一下然后出现的东西?"
这个 Skill 就是解决这个问题的。它把模糊的描述映射到精确的术语,这样你跟 AI(或设计师)沟通时,才能说清楚你到底想要什么。
示例:
用户:"那个弹窗好像是从你点的按钮里长出来的,而不是从中间变大的,叫什么来着?"---
Origin-aware animation —— 元素从它的触发点动画出来,就像 popover 从打开它的按钮长出来,而不是从 CSS 默认的自身中心。
快速开始
3.1 安装
只需一行命令:
bash
npx skills add emilkowalski/skill
或者安装完整的 skills 仓库:
bash
npx skills@latest add emilkowalski/skills
3.2 使用方式
安装后,你可以在支持 Skills 的 AI 代理中直接使用。推荐的工作流是:
第一步:用 emil-design-eng 构建动画
第二步:用 review-animations 审查结果
第三步:用 animation-vocabulary 精化你的描述
典型对话示例:
你:帮我优化这个对话框的入场动画,用 emil-design-eng 的标准。
AI:(基于 Emil 的原则分析并给出优化建议,用 Before/After 表格呈现)
Before After Why transition: all 300mstransition: transform 200ms ease-out指定精确属性;避免 all transform: scale(0)transform: scale(0.95); opacity: 0现实中没有东西会从无到有出现 ease-in 下拉ease-out + 自定义曲线ease-in 感觉迟钝;ease-out 即时反馈按钮没有 :active 状态 :active 时 transform: scale(0.97)按钮必须有按压反馈
---
动画决策框架(核心)
这是 emil-design-eng 的灵魂。在写任何动画代码之前,先按顺序回答这四个问题。
4.1 问题一:这个到底该不该动画?
问自己: 用户多久会看到这个动画一次?
| 频率 | 决策 |
|---|---|
| 每天 100+ 次(快捷键、命令面板切换) | 不要动画。永远不要。 |
| 每天几十次(hover 效果、列表导航) | 移除或大幅精简 |
| 偶尔(弹窗、抽屉、Toast) | 标准动画 |
| 罕见/第一次(引导、反馈表单、庆祝) | 可以加惊喜效果 |
关键原则:永远不要给键盘触发的操作加动画。 这些操作每天重复数百次。动画会让它们感觉慢、延迟、与用户的行动脱节。Raycast 没有开/关动画——这就是每天用几百次的东西的最优体验。
4.2 问题二:动画的目的是什么?
每个动画都必须能清晰回答"为什么要有这个动画?"
合理的目的:
- 空间一致性:Toast 从同一个方向进出,让滑动关闭感觉直觉
- 状态指示:变形的反馈按钮显示状态变化
- 解释:展示功能如何工作的营销动画
- 反馈:按钮按下时缩小,确认界面听到了用户
- 防止突兀变化:元素没有过渡地出现/消失会感觉像坏了
如果目的只是"看起来酷"而且用户会经常看到,那就不要动画。
4.3 问题三:用什么缓动?
缓动是动画最重要的成分。选错了缓动,再好的代码也救不回来。
决策流程图:
元素是在入场还是出场?
├── 是 → ease-out(开始快,感觉响应迅速)
└── 否
├── 它在屏幕上移动/变形吗?
│ └── 是 → ease-in-out(自然的加速/减速)
└── 它是 hover/颜色变化吗?
├── 是 → ease
└── 它是恒速运动吗?
├── 是 → linear
└── 默认 → ease-out
⚠️ 关键警告:永远不要在 UI 动画上用 ease-in。
它开始慢,会让界面感觉迟钝和不响应。一个 300ms 的 ease-in 下拉菜单和一个 300ms 的 ease-out 下拉菜单,感觉上前者慢得多——因为 ease-in 延迟了初始运动,而那正是用户最关注的瞬间。
推荐的自定义缓动曲线:
css
/ UI 交互专用的强 ease-out /
--ease-out: cubic-bezier(0.23, 1, 0.32, 1);
/ 屏幕内运动的强 ease-in-out /
--ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
/ iOS 风格的抽屉曲线(来自 Ionic Framework) /
--ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);
内置的 CSS 缓动太弱了。它们缺乏让动画感觉有意图的冲击力。不要从零开始创建曲线——用 easing.dev 或 easings.co 找更强的自定义版本。
4.4 问题四:多快?
| 元素类型 | 时长 |
|---|---|
| 按钮按压反馈 | 100-160ms |
| Tooltip、小 popover | 125-200ms |
| 下拉菜单、选择器 | 150-250ms |
| 弹窗、抽屉 | 200-500ms |
| 营销/解释性动画 | 可以更长 |
铁律:UI 动画必须控制在 300ms 以内。
一个 180ms 的下拉菜单比 400ms 的感觉响应快得多。一个转得更快的 spinner 会让 app 感觉加载更快——即使加载时间完全一样。
#### 感知性能
动画中的速度不仅仅是"感觉爽"——它直接影响用户对你的 app 性能的感知:
- 一个转得快的 spinner 让加载感觉更快(相同的加载时间,不同的感知)
- 一个 180ms 的选择动画比 400ms 的感觉更响应
- 第一个 tooltip 打开后,后续的 tooltip 即时打开(跳过延迟 + 跳过动画),让整个工具栏感觉更快
速度的感知和实际速度一样重要。而缓动会放大这个效应:200ms 的 ease-out 感觉上比 200ms 的 ease-in 更快,因为用户看到的是即时运动。
---
组件构建原则
5.1 按钮必须有按压感
给 :active 状态加上 transform: scale(0.97)。这给了即时反馈,让 UI 感觉真的在听用户的话。
css
.button {
transition: transform 160ms ease-out;
}
.button:active {
transform: scale(0.97);
}
这个原则适用于任何可按压的元素。缩放比例要微妙(0.95-0.98)。
5.2 永远不要从 scale(0) 开始
现实世界中,没有东西会完全消失再完全出现。从 scale(0) 动画的元素看起来就像从虚空中冒出来。
从 scale(0.9) 或更高的值开始,配合透明度变化。即使是一个几乎看不见的初始缩放,也会让入场感觉更自然——就像气球即使瘪了也有可见的形状,它永远不会完全消失。
css
/ ❌ 错误 /
.entering {
transform: scale(0);
}
/ ✅ 正确 /
.entering {
transform: scale(0.95);
opacity: 0;
}
5.3 Popover 要有原点感知
Popover 应该从它的触发点缩放进场,而不是从中心。默认的 transform-origin: center 对几乎所有 popover 来说都是错的。
例外:Modal(模态框)。 Modal 应该保持 transform-origin: center,因为它们不锚定到特定触发点——它们出现在视口中央。
css
/ Radix UI /
.popover {
transform-origin: var(--radix-popover-content-transform-origin);
}
/ Base UI /
.popover {
transform-origin: var(--transform-origin);
}
用户是否单独注意到这个差异并不重要。在整体中,看不见的细节会变得可见。它们会叠加。
5.4 Tooltip:后续 hover 跳过延迟
Tooltip 应该有延迟才出现,以防止意外触发。但一旦一个 tooltip 打开了,悬停到相邻的 tooltip 上应该即时打开,没有动画。这样感觉更快,同时不破坏初始延迟的目的。
css
.tooltip {
transition: transform 125ms ease-out, opacity 125ms ease-out;
transform-origin: var(--transform-origin);
}
.tooltip[data-starting-style],
.tooltip[data-ending-style] {
opacity: 0;
transform: scale(0.97);
}
/ 后续 tooltip 跳过动画 /
.tooltip[data-instant] {
transition-duration: 0ms;
}
5.5 用 Blur 掩盖不完美的过渡
当两个状态之间的 crossfade 无论怎么调缓动和时长都感觉不对时,在过渡期间加上微妙的 filter: blur(2px)。
为什么 blur 有效: 没有 blur 时,交叉淡入淡出中你看到的是两个不同的物体——旧状态和新状态重叠。这看起来不自然。Blur 通过混合两个状态来弥补视觉差距,欺骗眼睛感知到一个平滑的转变,而不是两个物体在交换。
css
.button-content {
transition: filter 200ms ease, opacity 200ms ease;
}
.button-content.transitioning {
filter: blur(2px);
opacity: 0.7;
}
Blur 保持在 20px 以下。重度模糊很耗性能,尤其是在 Safari 中。
5.6 用 @starting-style 做入场动画
现代 CSS 方式——不需要 JavaScript 就能动画元素的入场:
css
.toast {
opacity: 1;
transform: translateY(0);
transition: opacity 400ms ease, transform 400ms ease;
@starting-style {
opacity: 0;
transform: translateY(100%);
}
}
这取代了 React 中常见的 useEffect + mounted: true 模式。浏览器支持时优先用 @starting-style;否则回退到 data-mounted 属性模式。
---
弹簧动画(Spring Animations)
弹簧比基于时长的动画感觉更自然,因为它们模拟真实物理。它们没有固定的时长——它们基于物理参数来稳定下来。
6.1 什么时候用弹簧
- 带动量的拖拽交互
- 应该感觉"有生命"的元素(比如 Apple 的 Dynamic Island)
- 可以在动画中途被打断的手势
- 装饰性的鼠标追踪交互
6.2 弹簧配置
Apple 的方式(推荐——更容易理解):
js
{ type: "spring", duration: 0.5, bounce: 0.2 }
传统物理方式(更多控制):
js
{ type: "spring", mass: 1, stiffness: 100, damping: 10 }
使用时 bounce 保持微妙(0.1-0.3)。大多数 UI 上下文中避免 bounce。把它用在拖拽关闭和好玩的交互上。
6.3 可中断性优势
弹簧在被打断时保持速度——CSS 动画和关键帧会从零重新开始。这让弹簧非常适合用户可能在动作中途改变主意的手势。当你点击一个展开的项目然后快速按 Escape 时,基于弹簧的动画会从当前位置平滑地反转回去。
---
动画术语速查(Vocabulary)
跟 AI 沟通时,用对词 = 得到对的结果。以下是最常用的术语分类:
7.1 入场与出场
| 术语 | 含义 |
|---|---|
| Fade in / Fade out | 元素通过改变不透明度出现或消失 |
| Slide in | 元素从屏幕外滑入(左、右、上、下) |
| Scale in | 元素从小到大出现,通常配合淡入 |
| Pop in | 元素出现时有轻微的过冲,像弹到位 |
| Reveal | 内容被逐渐揭开,通常通过动画 clip-path 或 mask |
7.2 排序与时间
| 术语 | 含义 |
|---|---|
| Stagger | 一个接一个地动画多个项目,每个之间有小延迟,形成级联效果 |
| Orchestration | 有意地协调多个动画的时间,让它们感觉像一个协调的运动 |
| Delay | 动画开始前的等待时间 |
| Duration | 动画持续多长时间 |
7.3 反馈与交互
| 术语 | 含义 |
|---|---|
| Press / Tap feedback | 点击时微妙的缩小,让元素感觉有物理感 |
| Hold to confirm | 用户按住按钮时填充的进度效果 |
| Rubber-banding | 拖过边界时的阻力和回弹(iOS 过滚感觉) |
| Shake / Wiggle | 快速的左右抖动,表示错误或被拒绝的输入 |
| Ripple | 从点击点展开的圆圈,确认按压 |
7.4 必须知道的原则
| 原则 | 含义 |
|---|---|
| Purposeful animation | 运动应该服务于功能——定位、给反馈、显示关系——而不只是装饰 |
| Perceived performance | 正确的动画让界面感觉更快,即使实际上并没有 |
| Frequency of use | 用户越经常看到一个动画,它就应该越短越微妙 |
| Spatial consistency | 动画时让元素保持其身份和位置,这样用户永远不会丢失东西的踪迹 |
| Reduced motion | 尊重用户的 prefers-reduced-motion 设置,减弱或移除运动 |
💡 完整的术语表 包含 12 个分类、近 100 个术语。当你不知道一个效果叫什么时,animation-vocabulary skill 可以帮你反向查找。
---
来自社区的声音
不要只听我们说。看看用过的人怎么说:
"我每次都这么说,但这就是你想要的课程。真正的课程内容,是那种你马上就能用的东西。"
—— shadcn,Vercel 设计工程师
"我肯定不是第一个、也不会是最后一个赞美这门课程有多好的人。细节的水平、清晰度和智慧简直是疯狂的。 这才是设计教育的标杆。"
—— Scotty Matthewman,SpruceID 高级设计师
"少数我买了之后还会不断回头参考的课程之一。即使你不打算用代码构建这些,理论和资源本身也真的能帮你理解如何把你的工作从'好'提升到'棒'。"
—— Leo Fernandez,Wealthsimple 产品设计师
"强烈推荐这门课程。近年来我设计执行质量的最大倍增器。"
—— Hannu Oksa,Reaktor 工程师
"我刚买了 Emil 的网页动画课程,简直不能更开心。导论章节就改变了我对动画的心智模型。 每一分钱都值。"
—— Geoorge,软件工程师
"作为一个经验法则,每个前端开发者都应该购买 Emil 的动画课程。"---
—— Anthony Rubio,Hexium 创始人
进阶:把你自己的品味也打包进去
Emil 的这套方法最强大的地方在于:它是可复制的。你不只可以用他的 skills,你还可以创建你自己的。
步骤:
- 后退一步,问问自己为什么你做了某个决定
- 清晰地表达 为什么某件事必须这样做
- 设定规则,而且要严格
- 把规则写进 skill 文件,喂给你的 AI 代理
你可以把任何"品味"决定打包进一个 skill——无论是布局、图标、还是色彩理论。
"当然,工作中更有创意的部分仍然取决于你,但你能打包进 skill 的越多,你从代理中获得的杠杆就越大。"为了让这个过程更容易,Emil 推荐使用 Anthropic 的
—— Emil Kowalski
skill-creator skill。
---
立即开始
你已经看到了这套系统的威力。现在,是时候让你的 AI 也拥有顶级设计品味了。
安装
bash
npx skills add emilkowalski/skill
下一步
- 安装后先试一个简单任务——让 AI 优化一个按钮的动画
- 用 review-animations 审查结果——感受一下标准有多严格
- 深入学习——如果你想真正掌握背后的理论,去 animations.dev 加入等待列表,下一次注册开放在 8 月 25 日,为期 10 天
- 创建你自己的 skills——把你的品味也系统化
记住:在 AI 时代,功能是廉价的,品味才是稀缺品。
---
官方资源:
- Emil's AI Skills — 技能主页
- animations.dev — 完整动画课程
- emilkowalski/skills (GitHub) — 开源技能仓库
- Agents with Taste — 如何把品味传递给编码代理
- 动画词汇表 — 完整术语参考