mcpField
U
ui-animation

ui-animation

github.com/mblode设计与 UI16910.5k 次安装1 天前更新
代码仓库

关于 ui-animation

ui-animation 是用于界面动效设计与实现的技能,涵盖动效决策、编码、审查、调试,以及从录屏反推动效。适合处理 UI 行为的开发与设计人员,参考资料涉及模式、性能、无障碍和代码输出。

主要功能

  1. 01动效设计决策指南
  2. 02过渡与手势模式参考
  3. 03动效代码审查与调试
  4. 04动效测量与曲线拟合
  5. 05面向多种 UI 框架生成代码
  6. 06无障碍与性能指导

适用场景

  1. 01判断界面哪些部分适合加入动效
  2. 02实现对话框或菜单过渡
  3. 03排查迟缓或不连贯的动画
  4. 04根据录屏还原动效

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mblode/agent-skills --skill ui-animation

安装后在 Claude Code 中输入/ui-animation确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

evals/
discovery-mode.json
evals.json
evals/fixtures/
settings-panel.tsx
references/
choreography.md
clip-path-techniques.md
code-output.md
component-patterns.md
contextual-animations.md
curve-fitting.md
debugging-symptoms.md
decision-framework.md
gesture-drag.md
interface-sfx.md
measurement-guide.md
performance-deep-dive.md
review-format.md
scroll-animations.md
spring-animations.md
svg-animation.md
transition-recipes.md
vocabulary.md
scripts/
extract_frames.py
fit_curves.py
track_motion.py

详细介绍

UI 动画

  • 是: 设计、实现、评审和调试 UI 动效(弹簧、手势、拖拽、缓动、CSS 过渡、关键帧、Motion);全面检查界面,找出真正适合加入动效的时刻;测量录制视频中的动效(提取帧、跟踪、拟合曲线),生成代码和交接规范;为描述的动效命名(反向查询词汇);以及控制界面音效的适量使用。
  • 不是: 选择整体视觉方向、配色或字体(使用 ui-design 的 Direction 模式);审查整个页面的 UI 质量(使用 ui-design 的 Audit 模式);或处理命名的文字效果规范(如已安装,请使用外部 animate-text 技能)。

参考文件

文件何时阅读
references/decision-framework.md默认阅读:判断是否需要动画以及原因、选择缓动风格;也用于探索性检查(“哪些地方应该添加动画”)
references/spring-animations.md弹簧物理、Motion useSpring、配置弹簧参数、Apple 阻尼/响应值、不对称的打开/关闭风格、中断机制
references/component-patterns.md按钮、Toast、交叉淡化、列表交错和移除、悬停、分步表单、Motion 布局变形和自动高度、3D
references/clip-path-techniques.md使用 clip-path 实现揭示、选项卡、按住删除、对比滑块
references/gesture-drag.md拖动、滑动关闭、惯性、指针捕获、速度交接、惯性投影、旋钮拖动、定位点、轮播图 touch-action
references/scroll-animations.md滚动触发的揭示、擦洗式/滚动驱动的动画(animation-timeline、useScroll)、视差、粘性滚动叙事,以及何时不应使用滚动动画
references/performance-deep-dive.md卡顿、CSS 与 JS、WAAPI、CSS 变量陷阱、Framer Motion 注意事项
references/debugging-symptoms.md动画感觉不对劲,但说不出原因:按症状索引的表格,涵盖迟缓、机械、廉价、跳动和触发异常的动效
references/svg-animation.md矢量图动画:线条绘制(stroke-dashoffset)、SVG transform-origin 陷阱、路径变形、抖动、环境动效
references/review-format.md审查动画代码:十项标准(每项都包含一眼识别问题的触发条件)、Before/After/Why 表格、Block/Approve 判定
references/contextual-animations.md上下文相关的图标切换、逐词交错入场、弱化外围元素、固定偏移量的退出
references/transition-recipes.md添加 CSS 过渡:容器变形、卡片尺寸调整、徽标、下拉菜单和工具提示(带库来源变量)、模态框(使用 @starting-style 入场)、面板和抽屉、页面滑动、图标切换、数字弹入、里程表滚动、文本切换、成功、头像悬停、错误抖动
references/measurement-guide.md逆向工程:需要测量什么、目测与脚本、读取 metrics.json、选择 ROI
references/curve-fitting.md逆向工程:读取 fit_curves.py 输出、弹簧与贝塞尔曲线、评估拟合误差、不对称的打开/关闭
references/code-output.md逆向工程:生成 CSS、Motion/Framer Motion、SwiftUI、React Native、UIKit 代码
references/choreography.md逆向工程:多元素/多阶段动效:交错、先模糊后移动、各边分别稳定
references/vocabulary.md为用户描述模糊的动效命名(“……那种效果叫什么?”)
references/interface-sfx.md点击音效、界面音频、UI 音效、触觉反馈与声音的结合,或“为什么 Web 对声音如此抗拒”

核心规则

  • 为提供反馈、明确方向、保持连续性或带来刻意设计的惊喜而添加动画。如果只是“看起来很酷”,而且用户会经常看到,就不要添加。
  • 键盘焦点和重复导航应即时响应。状态转换可以有动画,但焦点和任务完成不能因此延迟。
  • 对可中断的 UI,优先使用 CSS transitions:被中断时,关键帧动画会从头开始,而 transitions 会调整目标。仅在序列预先确定时使用关键帧。
  • 实现优先级:CSS transitions > WAAPI > CSS keyframes > JS(requestAnimationFrame);负载较高时,CSS 仍能保持流畅,而 JS 会掉帧。
  • 采用非对称时长:偶尔发生的交互可以稍慢地进入、快速退出。对于高频、短暂的 UI(悬停高亮、弹出层、面板切换),则反过来:立即进入(0ms),短暂淡出后退出(100-150ms),让操作显得即时。
  • 可点击控件在 :active 时立即按下(0ms),并设置 touch-action: manipulation。
  • 使用 @starting-style 实现 DOM 元素进入;不支持时改用 data-mounted 属性。
  • 添加少量 filter: blur(2px),可以掩盖内容切换时生硬的交叉淡化。

动效设计原则

  • 保持连续,避免瞬移。 在两种状态下都可见的元素应原地过渡;元素应从其所在位置展开,而不是淡入一个新实例。切勿复制持久元素,也不要在包含相同组件的视图之间硬切;硬切会丢失空间背景。
  • 动效方向与位置一致。 标签页和轮播图的过渡方向应与空间布局相符(向前时从左向右,向后时从右向左)。
  • 从触发元素处展开。 覆盖层、托盘和面板应从打开它们的元素处向外展开;从屏幕中央进入会破坏空间方向感。如果形状允许,更好的做法是让触发元素变成表面(参见容器变形方案)。
  • 就地确认,而非放在角落。 操作结果应显示在触发操作的控件上:按钮变为“已复制”,停留片刻后再恢复。放在远处角落的 Toast 会让用户移开视线,离开刚刚操作的对象,去确认操作是否成功。仅当结果没有屏幕上的来源(例如后台任务完成、收到消息)时,才使用角落 Toast。
  • 成对状态同时添加动效。 如果打开时有动画,关闭时也应有动画。如果悬停时有动效,焦点和按下状态也应提供同等反馈。不要只打磨重复交互中的一半。
  • 交互越少见,越可以增添个性。 高频操作的动效必须让人几乎察觉不到。
  • 动效能提升感知速度。 即使加载时长完全相同,平滑过渡也会比硬切感觉更快。

动画内容

  • 移动:仅使用 transform 和 opacity;它们不会触发布局和绘制。
  • 状态反馈:可以使用 color、background-color 和 opacity。
  • 切勿为布局属性(width、height、top、left)添加动画;它们会在每一帧触发布局重新计算。(例外情况:刻意对容器添加补间动画,参见卡片尺寸调整和容器形变的方案。)
  • 切勿使用 transition: all;它会为非预期属性添加动画,还会悄然将未来新增的属性纳入动画。请明确列出属性。
  • 避免为核心交互添加 filter 动画;若无法避免,请将模糊度保持在 ≤ 20px(重度模糊开销很大,尤其是在 Safari 中)。
  • SVG:在 <g> 包装元素上应用变换,并设置 transform-box: fill-box; transform-origin: center;否则元素会围绕画布原点旋转或缩放。线条绘制、路径变形和 Motion SVG 原点覆盖详见 references/svg-animation.md。
  • transform: scale() 也会缩放子元素(图标、文本和边框都会按比例缩放),这与 width/height 不同:它适合用于按压反馈,但若内部元素必须保持固定尺寸,请考虑这一点。
  • 切换主题时禁用过渡([data-theme-switching] * { transition: none !important }),否则所有主题属性都会同时播放动画。在切换完成后强制回流(void document.body.offsetHeight),并在下一帧移除覆盖规则;或者使用 next-themes 的 disableTransitionOnChange。

缓动默认值

元素时长缓动
按钮按压反馈100-160mscubic-bezier(0.22, 1, 0.36, 1)
工具提示、小型弹出框125-200msease-out 或进入曲线
下拉菜单、选择器150-250mscubic-bezier(0.22, 1, 0.36, 1)
模态框、抽屉200-350mscubic-bezier(0.22, 1, 0.36, 1)
屏幕内移动/滑动200-300mscubic-bezier(0.25, 1, 0.5, 1)
页面过渡250-400ms进入或移动曲线
悬停(颜色/透明度),单个控件200msease
悬停(变换/缩放)100-150ms进入曲线
插画/营销内容最长 1000ms弹簧曲线或自定义曲线

常规 UI 动画应控制在 300ms 以内;时长应根据移动距离调整(全屏滑动可以超过 300ms,6px 的工具提示位移应控制在 150ms 以内)。

命名曲线

  • 进入: cubic-bezier(0.22, 1, 0.36, 1),用于入场动画和基于变换的悬停效果
  • 移动: cubic-bezier(0.25, 1, 0.5, 1),用于滑动、抽屉和面板
  • 抽屉(类似 iOS): cubic-bezier(0.32, 0.72, 0, 1)(起始斜率极陡;因此 500ms 不会显得很慢)
  • 指数减速: cubic-bezier(0.19, 1, 0.22, 1),用于戏剧性的显现效果、卡片悬停和文本显现
  • 按压: cubic-bezier(0.25, 0.46, 0.45, 0.94),用于按钮按压反馈
  • 屏幕内移动: cubic-bezier(0.645, 0.045, 0.355, 1),用于在屏幕内往返的移动

避免在 UI 中使用 ease-in:它的起步很慢,元素会滞后于用户操作,让人感觉迟钝。相比内置的 ease/ease-out,更推荐使用 easing.dev 的自定义曲线;内置曲线的加速度较柔和,显得轻柔而不够果断。

过渡决策规则

先匹配 UI 元素,再从 references/transition-recipes.md 中选择方案:

UI 模式方案
触发器 + 浮动圆点/计数通知徽标
触发器扩展为其打开的界面容器变形
触发器 + 锚定界面菜单下拉
页面上方居中的界面模态对话框
滑入现有容器的面板面板显现
列表 ↔ 详情或向导步骤页面并排滑动
元素尺寸变化卡片缩放
文本原位更新文本状态切换
同一位置的两个图标图标切换
数字自行出现数字弹出
用户正在控制的数字里程表数字滚动
确认 / 成功时刻成功庆祝
水平堆叠中悬停的项目头像组悬停
表单验证错误错误状态抖动

除非设计需要 JS 编排,否则优先选择开销更低的过渡(仅 CSS)。

空间与时序

  • 弹出层的 transform-origin 设在触发器处(模态框保持 center);对话框/菜单的入场缩放使用 scale(0.9-0.96),而非 scale(0)(小型弹出层取较低值,完整对话框取较高值:较大的界面本身就会在绝对像素上移动很远);错开 30-50ms(总时长低于 300ms,最重要的元素先动)。完整规则和代码见 references/transition-recipes.md 和 references/contextual-animations.md。
  • 配对元素规则: 一起动效的元素(模态框 + 遮罩层、工具提示 + 箭头、FAB + 标签)必须使用相同的缓动和时长。时序不匹配通常会让人觉得“哪里不对劲”。

无障碍

  • 将悬停(动效和绘制)限制在 @media (hover: hover) and (pointer: fine) 条件下,或让触屏设备在点按时重现悬停效果。添加条件前先检查生成的 CSS;Tailwind v4 已经会将 hover: 包在 @media (hover: hover) 中。
  • 直接操控期间,让元素紧跟指针,不使用缓动;释放后再添加缓动。
  • 可选的界面音效:少量使用、由手势解锁,且仅用于增强确认反馈。参见 references/interface-sfx.md。

性能

  • 使用 IntersectionObserver 暂停屏幕外的循环动画;即使不可见,它们也会消耗 GPU。
  • 仅在重度动效期间对 transform/opacity 切换 will-change;结束后移除。每次提升图层都会消耗合成器内存;在许多元素上永久提升图层比完全不提升更糟。
  • 不要通过容器上的 CSS 变量实现拖动动画;每次更新都会为所有子元素重新计算样式。直接在移动元素上设置 transform。
  • 轴向移动和拖动默认使用 Motion 的 x/y 值(可绕过 React 重新渲染)。当一个所有者必须组合多个变换函数、与非 Motion 代码互操作,或在主线程繁忙时保持流畅,可使用完整的 transform 字符串:这些简写会在 requestAnimationFrame 上运行,当动效与导航、数据加载或 hydration 同时发生时会丢帧;此时 CSS/WAAPI 仍能保持流畅。
  • 只在某些时候卡顿的动效(打开时、导航期间、数据到达时)通常是同一帧中有长任务,而非动画开销过大。不要在同一帧中启动动画并执行耗时工作:先启动动效,等一帧呈现后再执行工作,或将其延迟到 transitionend。
  • 有关 WAAPI、合成图层、动画期间的长任务,以及 CSS 与 JS 对比表,请参见 references/performance-deep-dive.md。

反模式

上述内容未涵盖的高信号失败案例:

  • 挂载时未经用户触发就播放动画:意料之外的动效会让人不知所措,因为用户并未做任何操作来触发它。
  • 拖动到边界时突然停止,会让人感觉功能坏了;应施加摩擦力/阻尼,让越过边界后的移动逐渐减弱(参见 gesture-drag 参考)。
  • 同时为容器和其中的子元素添加错开动画:每个容器只选择一种入场方式。如果面板滑入,其中的内容在面板到达时就应已经可见。
  • 第一个提示框打开后仍播放动画:同组后续提示框应立即打开,否则工具栏会显得迟缓。
  • 通过滚动显示产品 UI、首屏内容或页面的每个部分:滚动显示效果只适用于营销页面中少数精心选择的时刻,只播放一次,并且向上滚动时绝不重新播放(参见 references/scroll-animations.md)。
  • 为 Scrub(由滚动驱动)的动效设置缓动或时长:滚动位置就是时钟,因此任何曲线或时长都会让动效滞后于滚动条。此处应使用 linear 且不设置时长,也只有此处如此。
  • 仅通过 CSS 处理减少动效偏好:Motion 的 JS 驱动动画不会遵循 @media (prefers-reduced-motion) 代码块,因此 CSS 限制虽然通过审查,空间位移仍会播放。请将应用封装在 <MotionConfig reducedMotion="user"> 中,或根据 useReducedMotion() 进行分支处理。另一个矫枉过正的做法是在减少动效时全局应用 * { transition: none !important },这也会去掉减少动效模式下仍应保留的不透明度和颜色反馈。
  • 为新项目安装 framer-motion:该软件包现在名为 motion,React 导入路径为 motion/react。旧软件包仍能解析,因此混合代码库虽然可以编译,却会同时打包两份库。

工作流

复制并跟踪:

Animation progress:
- [ ] Step 1: Decide whether the interaction should animate
- [ ] Step 2: Choose purpose, easing, and duration
- [ ] Step 3: Pick the implementation style
- [ ] Step 4: Load the relevant component or technique reference
- [ ] Step 5: Validate timing, interruption, and device behavior
  1. 按照 references/decision-framework.md 回答四个问题:是否添加动画?目的是什么?使用什么缓动?速度如何?
  2. 根据上方的缓动默认值表选择时长。如果该值存在争议,请在 DevTools 的贝塞尔曲线编辑器中(Chrome 或 Firefox;Safari 没有此功能)对照真实组件实时调整,然后将具体值粘贴到源码中其他计时常量旁边:DevTools 中的修改会在页面跳转时消失。
  3. 选择实现方式:CSS transition > WAAPI > spring > keyframe > JS。
  4. 查阅与你的组件或技术相关的参考资料。
  5. 审查时,遵循 references/review-format.md 中的严格要求:对照十项标准进行衡量,输出 Before/After/Why 表格,随后给出分级结论,并以 Block/Approve 决策收尾。

验证

为每项检查提供证据(DevTools 中的观察结果,而不是“看起来没问题”):

  • 在 diff 中搜索布局属性过渡(width、height、top、left)和 transition: all。
  • 快速重复切换组件;确认过渡会重新定位,而非从零开始重播。
  • 在 DevTools 的 Animations 面板中将速度降至 10%,以发现全速播放时不易察觉的时序和 transform-origin 问题。
  • 确认 will-change 只在动画期间启用,而不是永久设置;循环动画应在视口外暂停。
  • 在真实设备上测试触控交互;模拟器会低估手势和轻触触发悬停状态的问题。
  • 遵循 prefers-reduced-motion:将空间位移替换为即时状态变化或克制的淡入淡出。使用 animation-play-state: paused 暂停循环装饰(不要用 display: none 将其移除)。保留明确由用户触发的反馈。以该模式执行同一项任务。

发现工作流

对于“哪里应该添加动画”这一问题,请运行 references/decision-framework.md 中的 Discovery 检查。报告有目的和使用频率作为依据的机会,同时列出被否决的选项。只有在实现属于工作范围时,才落实建议。

逆向工程工作流

使用此分支从屏幕录制中测量现有动画,然后生成可复现该动画的代码和交接规范。scripts/ 下的脚本是规范且确定的执行路径;请运行脚本,而不是自行重构其逻辑。

以下所有 scripts/ 命令都应相对于已安装的技能目录解析,而不是相对于应用的工作目录。

**依赖项:**提取帧需要 ffmpeg(brew install ffmpeg);跟踪和曲线拟合需要 Python,并通过 pip install opencv-python numpy scipy 安装相关包。支持降级运行:仅有 ffmpeg 时,可以提取帧并进行视觉分析;跟踪和拟合则需要 Python 包。

Reverse-engineer progress:
- [ ] Step 1: Extract frames + contact sheet (per direction if open differs from close)
- [ ] Step 2: Vision pass: identify element, effects, phases
- [ ] Step 3: Decide precision (eye-only vs scripted)
- [ ] Step 4: Track motion and fit curves (if escalating)
- [ ] Step 5: Annotate choreography (delays, asymmetry)
- [ ] Step 6: Emit code for the target(s)
- [ ] Step 7: Validate against the recording
  1. **提取。**运行 python3 scripts/extract_frames.py <video> <outdir>。使用 --start/--duration 将片段裁剪到仅包含转场;如果交互同时包含打开和关闭,请裁剪出两个时间窗口,并分别对每个方向运行一次完整流程(它们几乎从不是镜像效果)。让 --fps 与源视频一致(使用 ffprobe 检查),切勿以高于源帧率的频率采样。先打开 contact_sheet.png。
  2. **视觉分析。**列出运动的元素、所有效果(平移、缩放(通常各向异性)、不透明度、模糊、圆角半径、阴影、颜色)以及各个阶段,并注明哪些属性先发生、哪些后发生。使用 references/measurement-guide.md 中的检查清单。
  3. **确定精度。**简单淡入淡出或线性滑动:从联系表读取时间,跳过步骤 4。弹性、弹簧式或涉及多个属性的运动:进入步骤 4(凭目测估算弹簧效果并不可靠)。
  4. **跟踪并拟合。**运行 python3 scripts/track_motion.py <outdir> 生成 metrics.json(传入 --bbox X,Y,W,H 可隔离单个元素),然后运行 python3 scripts/fit_curves.py <outdir>/metrics.json 获取弹簧参数、三次贝塞尔曲线以及各属性的拟合误差。传入提取时使用的相同 --fps。阅读 references/curve-fitting.md 以选择模型;如果两种模型的误差都很高,说明是多阶段运动(分段并分别拟合)。
  5. **标注。**加载 references/choreography.md。构建时间偏移表(记录每个属性开始和稳定的时间);先后间隔和过度拉伸带来的观感,比任何单条曲线都重要。
  6. **生成。**将拟合参数代入 references/code-output.md 中适用于目标平台的模板。让运动效果仅由 transform/opacity 实现。如果打开和关闭的效果不同,则生成两个转场;另外生成完整的交接规范,以便无需视频即可实现动画。
  7. **验证。**重新推导:播放生成的动画,录制屏幕,将录制内容再次交给 extract_frames.py 处理,并排比较联系表。将速度降至 0.1x,以确认阶段顺序和过度拉伸效果仍然保留。确认代码只对 transform、opacity 和 filter 进行动画处理。

逆向工程注意事项:

  • fit_curves.py 默认使用 --fps 30:若以 60 帧提取,却使用默认值拟合,则每个 duration_ms 都会翻倍,拟合出的刚度会降至四分之一。务必在拟合时传入提取所用的帧率。
  • 高于源帧率采样会产生重复帧:以 60 帧提取 24 fps 的 GIF,会因 metrics.json 中出现平台状的连续帧而增大拟合误差。请检查并匹配源帧率。
  • 屏幕录制可能会丢帧,iOS/QuickTime 录制则使用可变帧率;连续相同的行代表重复帧,而非暂停。如果平台状片段占比过高,请以更稳定的帧率重新录制。
  • 将打开和关闭分别测量为独立片段,并报告两条曲线;切勿拟合一条曲线后反向复用(参见 references/choreography.md)。若拟合 error 高于 0.08,则应视为可疑。

相关技能

  • product-design:确定存在哪些状态、操作会影响什么,以及操作是否可撤销。如果某个手势取代了控件,请先转到此处,因为滑动删除和长按确认会改变用户能做什么,然后才改变操作方式。
  • ui-design Direction 模式:视觉方向、调色板、排版;先确定视觉系统,再调整动效。
  • ui-design Audit 模式:页面/功能级 UI 质量审计。动效设计与修复归属此处。
  • 可选:已安装时使用外部 animate-text 技能:提供精选的命名文本效果(打字机、逐行显示、交错构建),并附带精确的 JSON 规范。

仅用于维护:evals/ 存放回归场景(evals.json,以及用于 Discovery 路由和门控的 discovery-mode.json)及其测试数据;用户任务期间不会加载其中任何内容。

评论

支持 Markdown