mcpField
U
ui-animation

ui-animation

github.com/nexu-io设计与 UI105.2k158 次安装2 天前更新
代码仓库

关于 ui-animation

这项技能用于设计、实现、审查和调试界面动效,也可从录屏测量动效。内容侧重有明确目的且兼顾无障碍的 UI 动效,并提供模式、时序、性能和实现参考。

主要功能

  1. 01设计和调试 UI 动效
  2. 02发现动效机会并审查
  3. 03测量动效并拟合曲线
  4. 04CSS、WAAPI 和 JS 指导
  5. 05交互与无障碍原则

适用场景

  1. 01调整按钮、菜单或模态框过渡
  2. 02排查迟缓或跳动的界面动效
  3. 03根据录屏复现动效
  4. 04审查动效代码的可用性

安装

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

$npx skills add https://github.com/nexu-io/open-design --skill ui-animation

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

包含的文件

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

LICENSE
SOURCES.md
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 Animation

Open Design 执行上下文

将其用作当前界面或用户认可的简报中的功能辅助工具。保留宿主的任务路由、当前阶段、工具可用性和输出约定。规划描述动效;仅在宿主的创作阶段进行实现。如果宿主不允许,不要增加额外的审核、录制、渲染或审批阶段。复用项目现有的技术栈和动效令牌。配套技能为可选项:仅在已安装时使用;否则,应用此处的相关指导,不要臆造工具调用。仅在实际观察到测量结果时报告;明确标注视觉估算和无法执行的检查。

  • 是: 设计、实现、审核、调试 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)。
  • 为经滚动驱动的动效设置缓动或时长:此时滚动位置就是时钟,因此任何曲线或时长都会让动效落后于滚动条。此处应使用 linear 且不设时长,只有此处如此。
  • 仅通过 CSS 处理减少动态效果:Motion 的 JS 驱动动画会忽略 @media (prefers-reduced-motion) 代码块,因此 CSS 条件虽能通过审核,空间位移仍会播放。请用 <MotionConfig reducedMotion="user"> 包裹应用,或根据 useReducedMotion() 进行分支处理。反向过度修正也不妥:在 reduce 条件下全局应用 * { 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 中的观察结果,而不是“看起来没问题”):

  • 在差异中搜索布局属性的过渡(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 / ffprobe,以及安装了 opencv-python、numpy 和 scipy 的 Python 环境。 不要假设 Open Design 已安装这些依赖项。请复用可用的隔离式 Python 环境;任何依赖项配置都必须遵守主机的授权要求。 如果只有 ffmpeg 可用,请提取帧,并将分析标注为视觉估算。如果无法检查媒体,请说明 缺少的能力;绝不要声称测得了时间、拟合了曲线或比较了录制结果。 每次提取都使用全新的任务专用输出目录,避免旧帧污染联系表。以下脚本是可选的测量工具, 并非实现常规界面动画的必要条件。

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 步,直接进行第 5 步。弹性、弹簧式或多属性运动:进入第 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 规格。

上游评估样例不属于此运行时包。源文件和适配详情记录在 SOURCES.md 中。

评论

支持 Markdown