关于 seenry-motion
用于判断界面动画是否必要,并指导其实现的设计技能。它为 UI 设计师和开发者提供基于使用频率的决策流程、实现方式、时长建议,以及中断和无障碍检查。
主要功能
- 01按使用频率判断动画
- 02选择动画目的与实现方式
- 03时长与缓动建议
- 04处理中断与退出状态
- 05减少动态效果与输入规则
- 06常见界面动效方案
适用场景
- 01检查界面状态是否应添加动画
- 02为菜单或对话框选择实现方式
- 03处理过渡期间的重复输入
- 04添加减少动态效果支持
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ ayangabryl/ seenry-skills --skill seenry-motion安装后在 Claude Code 中输入/seenry-motion确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
agents/openai.yamlassets/anchored-surface.mjscount-pop-demo.htmlcount-pop.csscount-pop.mjsfit-interaction.mjsfit-interaction.test.mjsassets/action-menu/action-menu.cssaction-menu.mjsdemo.htmlREADME.mdassets/boundary-trace/boundary-trace.cssboundary-trace.mjsdemo.htmlREADME.mdassets/confirmation-burst/confirmation-burst.mjsdemo.htmlREADME.mdworkbench.htmlassets/directional-stage/demo.htmldirectional-stage.cssdirectional-stage.mjsREADME.mdassets/expanding-card/demo.htmlexpanding-card.cssexpanding-card.mjsREADME.mdassets/fluid/fluid-search.cssFluidSearch.jsxFluidSurface.jsx详细介绍
Seenry Motion
动效的作用是解释变化:某个元素从哪里来、输入产生了什么效果、界面当前处于什么状态。按照以下顺序构建每个动画;第 1 步和第 2 步决定是否需要编写任何代码。
做出决定,并用一句话说明;不要提供多个动效选项。扩展项目现有的动效令牌和组件,而不是另建一套。
构建顺序
1. 是否需要动画? 根据出现频率决定。
| 用户看到它的频率 | 决定 |
|---|---|
| 每天 100 次以上(命令菜单、键盘快捷键、用方向键浏览列表) | 不使用动画。立即响应。 |
| 每天几十次(悬停、标签页、切换开关) | 使用现有状态时钟提供简短的不透明度/颜色反馈,或不添加反馈;绝不延迟已接受的状态 |
| 偶尔(菜单、对话框、抽屉、Toast) | 使用下表中的标准动效 |
| 很少(新手引导、首次成功、从空到满的时刻) | 可以展现个性 |
键盘触发的操作绝不等待动画。如果判断结果是不使用动画,就明确说明,并立即切换状态。
2. 用一个词说出目的:反馈、方向(元素从哪里来或移向哪里)、状态、连续性(避免突兀跳变)、说明(仅用于营销和新手引导)或惊喜(仅用于罕见时刻)。没有目的,就不添加动画。用户正在阅读的数据绝不为了样式而移动。
3. 选择能满足需求的最简单工具。
| 需求 | 工具 |
|---|---|
| 悬停、按下、颜色、类或属性切换 | CSS transition |
挂载时进入、在 display: none 前退出、原生 <dialog> 和 popover | CSS transition + @starting-style + allow-discrete |
高度设为 auto | interpolate-size: allow-keywords,或使用网格 0fr → 1fr 轨道 |
| 路由切换、列表 → 详情、指示器变形 | View Transitions API |
| 与滚动关联的效果 | animation-timeline: view() / scroll() |
| 可编程、可取消、不依赖库 | Web Animations(element.animate) |
| 在 React 中实现弹簧、速度、布局动画、手势、元素存在动画 | Motion(motion.dev) |
| 完整组件(Toast、抽屉、命令菜单、选择框) | 维护中的库,参见 libraries |
4. 选择属性。 仅使用 translate、scale、rotate、opacity、clip-path、filter。绝不从 scale(0) 开始:从 0.95–0.97 且不透明度为 0 开始。弹出层从其触发器的位置缩放(在触发器一侧设置 transform-origin);对话框从中心缩放。百分比平移(translate: 0 100%)按元素自身的尺寸移动。
5. 选择曲线和时长,或选择弹簧。
| 动效 | 时长 | 缓动 |
|---|---|---|
| 按下反馈 | 100–160ms | --ease-out |
| 工具提示、小型弹出层 | 120–200ms | --ease-out |
| 菜单、下拉菜单、选择框 | 150–250ms | --ease-out |
| 对话框 | 200–250ms | --ease-out |
| 底部面板、抽屉 | 350–500ms | --ease-drawer |
| 元素在屏幕上移动、变形 | 250–400ms | --ease-in-out |
| 悬停时的颜色、背景、边框 | 使用现有状态令牌;Transitions kit 使用 180ms | 使用现有状态曲线;该 kit 使用 cubic-bezier(.25,0,.06,1) |
| 进度、跑马灯、按住确认时的填充 | 与操作耗时相同 | linear |
--ease-out: cubic-bezier(0.23, 1, 0.32, 1)、--ease-in-out: cubic-bezier(0.77, 0, 0.175, 1)、--ease-drawer: cubic-bezier(0.32, 0.72, 0, 1)。界面动效绝不使用 ease-in:它会延迟用户正在关注的那个时刻。产品 UI 动效最好短于 300ms;较长的面板移动必须有其理由。除非为了保持直接操作或空间关系而需要相同的时长,否则退出动画通常比进入动画快约 20–30%。对于用户可以拖动、轻扫或中途反向操作的元素,使用弹簧:Motion {type: "spring", duration: 0.5, bounce: 0.2}(产品 UI 的 bounce 设为 0;趣味性动效设为 ≤0.3),或者使用 recipes 中的 CSS linear() 弹簧。
6. 规划中断和退出。 对可逆的属性变化,优先使用 CSS transitions,因为它们会从当前值重新调整目标。几何变化或编排需要用到 WAAPI 时,先捕获当前渲染状态,再取消或重新调整由当前逻辑控制的动画,并防范过期的完成回调。第二次输入应反转或替换旧请求,而不是排在它后面等待。立即发布新的逻辑状态;可以用单独的呈现状态继续绘制退出中的内容。
优化被中断的变化。 在适合该组件的情况下,使用以下检查。这些是设计启发式,并不能保证评审得分。尝试在进入和退出期间重复输入,包括间隔 50–150ms 的输入;提出时间相关的说法时,记录实际耗时。
- 保持连续性和语义。 相关的标签页、筛选器或状态可以共用一个网格单元(
display:grid、grid-area:1/1),并过渡透明度或小幅位移。让非活动内容退出焦点顺序和无障碍树;已挂载不等于可交互。较短的退出阶段(约 65–90ms)和 120–160ms 的进入阶段可以作为起点,而非必需方案。仅在当前过渡允许时卸载或隐藏内容;过期的完成回调绝不能隐藏较新的状态。可显式取消的 WAAPI 动画和带有防护的原生对话框退出也是有效替代方案。 - 确保结果易于理解。 避免意外的空白间隔或难以辨认的重叠文本。根据内容选择重叠、短暂交叉淡化或即时替换;让整个标签淡出再显示可能比让文本穿过图像移动更稳妥。在动画不可用或减少时,保留恰当的静态提示。检查实际可读性,不要用透明度阈值作为证明。
- 移动物体只保留一份。 标题、头像或封面移动到新位置时,避免出现可见的重复绘制。让目标位置保持隐藏,直到移动对象到达,再移除临时副本。检查文字在图像和移动外壳上的呈现;终点未被裁切并不能证明整个移动路径都可读。
- 标签要与结果一致。 类似“标记为已付款”变为“已付款”的标签,应与其结果采用相同的已确认应用状态。必要时为其预留占位,并避免出现过期文本或可聚焦的重复标签。不要为了完成装饰效果而延迟真实的成功状态。
- 序列可以取消。 打字演示、分阶段揭示和重播应由同一逻辑方管理待执行步骤。暂停、反转和新输入都应取消过时的工作,并从当前状态重新调整可见动画。过期的计时器不得恢复已暂停的序列,也不得覆盖较新的内容。
- 释放已完成的动画。 通过 CSS 或已提交的样式确立稳定状态,然后在适当时释放有限时长且由当前逻辑方管理的 WAAPI 动画。
fill:forwards不得继续覆盖后续状态变化。交互稳定后,检查是否存在意外动画;有意持续运行的加载指示器可以继续显示,直到相关工作结束。 - 每次移动都应体现一种关系。 菜单从其触发器处展开,面板从边缘展开,相关内容则随导航一致地移动。将上述时长范围作为起点;确保用户感知到的响应是即时的,并说明较长移动的理由。应测试中断和减少动态效果的情况,而不是把固定时长当作品质证明。 **达到 9 分。**在动效评审中,7 分代表正确但平庸,8 分明显出色,9 分则具有 Apple 或 Linear 级别的鲜明特色。评审分数停留在 7–8 分,原因总是那几个。花费一次运行前,请先处理所有问题:
- **一次处理一个组件。**使用
--labels "<Row>"单独评审每个组件,直到它得 9 分,并保留各组件的最佳版本。目录的总体评分取决于最弱的几行,因此一次修补多行永远无法提升总分;即使评审建议了某项改动,只要它会降低某一行的分数,就应撤销。 - **应用所有修复,不要只改最显眼的问题。**反复出现的小问题(悬停、按下和关闭控件的反馈)会让
states连续多轮停留在 7 分。--prev <last motion.json>会列出分数未提升的标准,以及再次要求修复的交互;check.mjs会自动传入它。 - **修复后又出现的问题,根源在结构上。**调整时序无法修复交叉的运动路径。共享元素在不同状态下应保持相对位置:标题在封面下方,就应在详情视图中仍位于封面下方,这样二者就不会相互穿过。
- **不能出现空白帧。**在每个录制时刻(30–320ms),发生变化的区域都应显示真实内容。外壳扩展时要带着内容一起扩展;流式答案从第一个词开始逐步展开。绝不要显示空白答案框,也不要显示等待一段时间后才消失的骨架屏。
- **每个组件都要有一个精心设计的创意。**需要保留的元素应随之移动,新元素应由其出现的原因引出。淡入、平移 4px 和标签切换,只能得 7 分。
- **让关闭方式符合流程。**对于直接展开的卡片或切换面板,当控件变为返回操作时,应保留源操作点。评审核对话框时,应关注有意义的操作、安全的 Cancel 路径、恰当的 Escape 行为以及焦点是否返回;不要为了满足空间规则而要求多余的 Close 或 X 按钮,也不要把 Cancel 移到启动器上。适当时,导航流程应使用 Back。评估实际的退出方式及其状态,而不是是否存在某个特定图标。菜单和弹出层无需关闭按钮:它们会在选择、点击外部区域或按下 Escape 时关闭;从按钮变形而来的菜单会折叠回按钮中。如果某个面板替换了整个区域(例如展开的卡片或专辑),则应将 Close 放在页眉右上角;绝不要把控件固定在过时的源位置,以免它悬在多余空间中或超出面板边缘。
- **单次运行不等于最终分数。**一次评审运行(本身是三次评审的中位数)在代码未变的情况下也可能相差 1 分。只有连续两次独立运行都达到 9 分,才接受这个分数;比较版本时,各版本的运行次数必须相同。
**7. 同时交付减少动态效果和输入门控。**在 prefers-reduced-motion: reduce 下,移除位移、视差、模糊和循环动画;保留有助于理解的短暂透明度变化。普通控件的悬停效果应保持静止:改变色调或边框环,而不是位置、缩放或布局。使用 @media (hover: hover) and (pointer: fine) 控制悬停反馈;有意设计的指针跟踪材质演示属于单独的交互,不应作为默认悬停效果。每次动画状态变化都应同时提供静态提示(标签、图标、颜色),以便在动画不运行时仍能理解状态。
示例方案
从 示例方案 开始,了解按下反馈、菜单和弹出层、工具提示、对话框、抽屉、消息提示、手风琴、错开入场、标签指示器、页面和共享元素过渡、滚动显示、图标切换、数字变化、按住确认、拖动关闭(包含速度投影和橡皮筋效果)、交叉淡化遮罩、主题切换和首次渲染抑制。包测试会在 Chromium 中运行原生 CSS 示例方案。
可运行资源
| 请求的更改 | 针对性路线 |
|---|---|
| 操作菜单或简短状态标签 | 原始操作菜单、状态切换和产品过渡效果。如果要求菜单以动画方式展开和收起,请在收起阶段保留其表面;关闭时有条件地卸载会跳过该阶段。对于状态过渡,请在预留位置移动文本;仅替换文本或更改圆点颜色是不完整的。实际操作由应用程序负责。 |
| 流内展开区域或几何形状变化 | 原始展开卡片、几何辅助工具和表面模式。保留焦点,并从当前几何状态重新定位。 |
| 专注的模态任务 | 原始模态表面和表面模式。使用原生对话框处理顶层显示和焦点行为;关闭前应允许退出动画完成,反向操作则应取消待执行的关闭。 |
| 变化的数字或图标 | 数字过渡和辅助工具。对于较小的整数计数,优先使用原始的计数弹出辅助工具,而不是重新构建数字语义。保留一个真实的无障碍值;不要隐藏所有数字,再将 aria-label 放到普通的 <strong> 上。数字过渡需要按位运动;单位应保持锚定。 |
| 实时语音输入或输出 | 原始语音状态接受由应用程序管理的状态和归一化音频级别。请将控件和播报保留在 DOM 中;生成的演示信号并不代表麦克风活动。 |
| 加载或进程状态 | 原始信号场、边界轨迹和加载模式。动画时长不等于进度。 |
| 已解码图像或表现力材质 | 原始图像显现、反射实体与边缘表面、指针倾斜、表面效果和表现力效果。替换内容加载期间,应保留有用内容;只有在材质确有需要时才使用反射和倾斜效果。 |
| 设计任何新的交互组件(简介、状态图、运动方案、输入契约、检查清单) | 交互设计 |
| Toast 或横幅堆叠 | 反馈模式和原始通知 reducer。退出动画开始前,应先从活动状态中移除溢出项;请测试三项堆叠中的第四个事件。 |
| 偶尔完成的里程碑 | 原始确认爆发效果。先在应用程序状态中记录成功,再播放有限时长的装饰效果;效果结束后,稳定结果仍须保持可见。 |
| 选中标签页或按顺序切换页面 | 原始选中表面用于共享高亮,方向性舞台用于相关视图;选中项、面板、路由和历史记录由应用程序负责。其他结构请使用导航模式。 |
| 滚动或协同系统 | 滚动编排、示例方案、系统编排和运动索引。 |
仅选择此更改所需的指南和辅助工具。捆绑的原始资源是可复用的起点,并非对具名源组件的自动替代品,也不能证明其忠实还原了该组件。复制任何第三方运行时内容时,请保留其许可证;原始 Seenry 资源使用仓库的 Apache-2.0 许可证。
切勿发布
| 切勿 | 改为 |
|---|---|
| 对每天触发 100+ 次或由键盘驱动的操作添加动画 | 即时变化 |
transition: all | 明确列出属性 |
从 scale(0) 开始出现 | scale: 0.96 + opacity: 0 |
在 UI 上使用 ease-in | --ease-out |
刻意设计的入场动画使用默认 ease/ease-out | 使用上文的自定义曲线 |
| 产品 UI 动画超过 300ms,且没有合理原因 | 150–250ms |
| 弹出框从中心缩放 | 将 transform-origin 设为触发元素 |
| 交互再次触发时使用无法控制的关键帧动画 | 可重新定向的过渡,或可明确取消的 WAAPI |
为 width、height、top、left、margin 添加动画 | 使用变换;高度使用网格轨道或 interpolate-size |
| 悬停时移动或缩放普通控件 | 仅改变色调或环线,并仅在精细悬停指针条件下启用;缩放反馈仅用于按下操作 |
| 没有减少动态效果的变体 | 仅改变不透明度,或即时变化 |
| 长列表中的项目逐个入场 | 错开 30–50ms,且总时长不超过约 300ms;或不使用动画 |
| 仅用动态效果表示状态变化 | 同时提供静态提示 |
在 transition-duration 中放入 duration easing 的令牌(整个声明会被丢弃,每次状态变化都会变成即时变化) | 在时长列表中使用纯时长;在计算样式中确认 transitionDuration 不为 0s |
过滤列表项时,display 规则优先级高于 [hidden] 属性 | 在布局规则中使用 :not([hidden]);检查隐藏项既不会绘制,也无法通过 Tab 键聚焦 |
| 颜色变化时,在变形的表面上交叉淡入第二个形状 | 使用单个表面,让其自身填充色在展开时变化 |
输出
编写代码,然后用几行报告:检查结果(频率和用途,或不播放动画的原因)、组成要素(工具、属性、时长、曲线或弹簧),以及检查内容(正常速度、DevTools Animations 中的 10% 速度、快速重复、反向操作、键盘、减少动态效果、手机)。
研究观察到的行为
匹配提供的参考时,要检查正常速度播放及有用的中间帧,而不仅是起止状态。动态效果研究介绍录制内容、Seenry MCP、创作者研究和来源限制;仅在需要研究时加载。静态图片无法确定时长、打断行为或键盘行为。没有播放内容时,应实现建议的效果并在本地测试。
**录制阶段检查:**将源素材的检查点与浏览器中正在运行的动画进行匹配。直接跳转状态只能验证起止状态,无法验证时长。请参阅动态效果重建。
验证
先运行静态扫描,无需浏览器,耗时远低于一秒:node ../seenry/scripts/motion_scan.mjs <project>。它会标记不符合令牌的时长、延迟和曲线、浏览器默认和线性缓动、transition: all、布局属性过渡、超过 20ms 的交错步长,以及缺少减少动态效果分支的情况,并为每项标出最接近的令牌。修复违规项和无法说明合理性的警告,然后使用交互验证清单验证你更改的行为。小幅修复只需检查受影响的状态并进行回归测试,无需重新进行全站基准测试。检查正常速度播放和有用的慢动作帧;除文档溢出外,也要检查内部文本和控件是否适配。在反向播放期间,确认最终逻辑状态和无障碍状态,并检查实际移动的图层,而不只是固定容器。
当可使用同级目录中的 seenry 技能运行时和授权的模型访问权限时,从此技能的安装目录解析 ../seenry/scripts/motion_judge.mjs,并使用 Node 对页面运行该脚本。不要假设调用方的工作目录就是技能目录。如果运行时不可用,请报告该检查无法执行。对于 Web 证据,验收底线是:每项声明的动态效果标准和每一行已审查的交互评分均达到 9 分,且没有违规项;每个已捕获的交互标签都必须有对应行。缺少标准或标签覆盖时,结果均视为未验证;总体高分不能抵消较弱的单项评分。报告会注明捕获范围,不会为未测试的组件背书。原生视频的旧版评审仍遵循单独的约定。根据评审结果检查相关交互。将该评审与功能检查和渲染检查分开;评审器不可用或缺少录制时,结果属于未验证,绝不能算通过。尝试测试相关的键盘、窄屏宽度和减少动态效果状态。对于手势,请使用触摸模拟;如有条件,也要用真机测试,并报告实际测试过的方式。
如需深入了解机制,请阅读动态效果设计、交互剖析、产品过渡、滚动编排、表面效果和数字过渡。整体界面方向和材质请使用 seenry。