ui-animation

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

UI Animation

UI 动画

Open Design execution context

Open Design 执行上下文

Use this as a functional helper on the user's current interface or accepted brief. Keep the host's task route, current stage, tool availability, and output contract. Planning describes the motion; implementation happens only in the host's authoring stage. Do not add an extra review, recording, rendering, or approval phase when the host disallows it. Reuse the project's existing stack and motion tokens. Companion skills are optional: use them only if installed; otherwise apply the relevant guidance here without inventing a tool invocation. Report measurements only when actually observed; mark visual estimates and checks that could not be performed explicitly.
  • IS: designing, implementing, reviewing, debugging UI motion (springs, gestures, drag, easing, CSS transitions, keyframes, Motion), sweeping an interface for the moments that would genuinely benefit from motion, measuring motion from a recording (extract frames, track, fit curves) to emit code plus a handoff spec, naming a described motion effect (reverse-lookup vocabulary), and gating sparse interface sound.
  • IS NOT: choosing overall visual direction, palettes, or typography (use
    ui-design
    Direction mode), auditing a whole page's UI quality (use
    ui-design
    Audit mode), or named text-effect specs (use the external
    animate-text
    skill where installed).
将其作为用户当前界面或已确认 brief 的功能性辅助工具。保留宿主任务的路由、当前阶段、工具可用性和输出约定。规划用于描述动效;实现仅在宿主的创作阶段进行。当宿主不允许时,不要额外增加审查、录制、渲染或批准阶段。复用项目现有的技术栈和动效 token。配套 skill 为可选项:仅在已安装时使用;否则应用此处相关指导,不要虚构工具调用。仅在实际观测后报告测量结果;明确标注视觉估算和无法执行的检查。
  • IS: 设计、实现、审查和调试 UI 动效(弹簧、手势、拖拽、缓动、CSS transitions、keyframes、Motion),扫描界面以找出真正适合加入动效的时机,从录屏中测量动效(提取帧、跟踪、拟合曲线)以输出代码和交接规范,为用户描述的动效效果确定名称(反向查找词汇),以及控制少量界面音效的触发。
  • IS NOT: 选择整体视觉方向、配色或字体(使用
    ui-design
    Direction 模式)、审计整页 UI 质量(使用
    ui-design
    Audit 模式),或处理具名的文本效果规范(在已安装时使用外部
    animate-text
    skill)。

Reference files

参考文件

FileRead when
references/decision-framework.mdDefault: deciding whether/why to animate, picking easing character; also the Discovery sweep ("where should this animate")
references/spring-animations.mdSpring physics, Motion
useSpring
, configuring spring params, Apple damping/response values, asymmetric open/close character, interruption mechanics
references/component-patterns.mdButtons, toasts, crossfades, list stagger and removal, hover, step forms, Motion layout morphs and auto height, 3D
references/clip-path-techniques.mdclip-path for reveals, tabs, hold-to-delete, comparison sliders
references/gesture-drag.mdDrag, swipe-to-dismiss, momentum, pointer capture, velocity handoff, momentum projection, rotary/knob drag, detents, carousel
touch-action
references/scroll-animations.mdScroll-triggered reveals, scrubbed/scroll-driven animation (
animation-timeline
,
useScroll
), parallax, sticky scrollytelling, and when a scroll animation shouldn't exist
references/performance-deep-dive.mdJank, CSS vs JS, WAAPI, CSS variables trap, Framer Motion caveats
references/debugging-symptoms.mdAn animation feels off and the cause isn't named: symptom-indexed tables for sluggish, robotic, cheap, jumpy, and misfiring motion
references/svg-animation.mdAnimating vector art: line drawing (
stroke-dashoffset
), SVG transform-origin traps, path morphing, shakes, ambient life
references/review-format.mdReviewing animation code: ten standards (each with flag-on-sight triggers), Before/After/Why table, Block/Approve verdict
references/contextual-animations.mdContextual icon swaps, word-level stagger entrances, peripheral de-emphasis, fixed-offset exits
references/transition-recipes.mdInstalling a CSS transition: container morph, card resize, badge, dropdown and tooltip (with library origin variables), modal (with
@starting-style
entry), panel and drawer, page slide, icon swap, number pop-in, odometer roll, text swap, success, avatar hover, error shake
references/measurement-guide.mdReverse-engineer: what to measure, eye vs script, reading
metrics.json
, choosing an ROI
references/curve-fitting.mdReverse-engineer: reading
fit_curves.py
output, spring vs bezier, judging fit error, asymmetric open/close
references/code-output.mdReverse-engineer: emitting code for CSS, Motion/Framer Motion, SwiftUI, React Native, UIKit
references/choreography.mdReverse-engineer: multi-element/multi-phase motion: staggers, blur-before-move, per-edge settling
references/vocabulary.mdNaming a motion effect the user describes vaguely ("what's it called when...")
references/interface-sfx.mdClick sounds, interface audio, UI SFX, haptic-plus-sound, or "why is the web afraid of sound"
文件何时阅读
references/decision-framework.md默认:决定是否/为何添加动画、选择缓动特征;以及 Discovery sweep(“哪里应该添加动画”)
references/spring-animations.md弹簧物理、Motion
useSpring
、配置 spring 参数、Apple damping/response 值、非对称打开/关闭特征、中断机制
references/component-patterns.md按钮、toast、交叉淡化、列表交错与移除、hover、步骤表单、Motion 布局变形和自动高度、3D
references/clip-path-techniques.md使用 clip-path 实现显现、标签页、长按删除、对比滑块
references/gesture-drag.md拖拽、滑动 dismiss、惯性、pointer capture、速度交接、动量投射、旋钮拖拽、限位档位、carousel
touch-action
references/scroll-animations.md滚动触发的显现、scrubbed/scroll-driven 动画(
animation-timeline
、
useScroll
)、视差、sticky scrollytelling,以及何时不应使用滚动动画
references/performance-deep-dive.md卡顿、CSS vs 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 transition:容器变形、卡片调整尺寸、徽章、下拉菜单和 tooltip(带库来源变量)、modal(带
@starting-style
入场)、panel 和 drawer、页面滑动、图标切换、数字弹出、里程表滚动、文本交换、成功、头像 hover、错误抖动
references/measurement-guide.md逆向工程:测量什么、肉眼 vs 脚本、读取
metrics.json
、选择 ROI
references/curve-fitting.md逆向工程:读取
fit_curves.py
输出、spring vs bezier、判断拟合误差、非对称打开/关闭
references/code-output.md逆向工程:输出 CSS、Motion/Framer Motion、SwiftUI、React Native、UIKit 代码
references/choreography.md逆向工程:多元素/多阶段动效:交错、模糊后移动、逐边稳定
references/vocabulary.md为用户模糊描述的动效效果确定名称(“这个效果叫什么来着……”)
references/interface-sfx.md点击声、界面音频、UI SFX、触觉加声音,或“为什么网页害怕声音”

Core rules

核心规则

  • Animate for feedback, orientation, continuity, or deliberate delight. If it's just "it looks cool" and the user sees it often, don't.
  • Keep keyboard focus and repeated navigation immediate. A state transition may animate if focus and task completion do not wait for it.
  • Prefer CSS transitions for interruptible UI: keyframes restart from zero on interruption, transitions retarget. Use keyframes only for predetermined sequences.
  • Implementation priority: CSS transitions > WAAPI > CSS keyframes > JS (
    requestAnimationFrame
    ); under load CSS stays smooth while JS drops frames.
  • Asymmetric timing: occasional interactions can enter slightly slower, exit fast. High-frequency ephemeral UI (hover highlights, popovers, panel toggles) inverts this: enter instantly (0ms), exit with a brief fade (100-150ms) so the action feels immediate.
  • Tappable controls press on
    :active
    at 0ms and set
    touch-action: manipulation
    .
  • Use
    @starting-style
    for DOM entry; fall back to a
    data-mounted
    attribute where unsupported.
  • A small
    filter: blur(2px)
    hides rough crossfades between swapped content.
  • 仅为反馈、方向感、连续性或刻意的愉悦感添加动画。如果只是“看起来很酷”且用户经常看到,就不要添加。
  • 保持键盘焦点和重复导航即时响应。状态切换可以添加动画,前提是焦点和任务完成不依赖该动画。
  • 对于可中断 UI,优先使用 CSS transitions:keyframes 在中断时从零重新开始,而 transitions 会重新设定目标。仅将 keyframes 用于预先确定的序列。
  • 实现优先级:CSS transitions > WAAPI > CSS keyframes > JS(
    requestAnimationFrame
    );在负载下 CSS 仍能保持流畅,而 JS 会掉帧。
  • 非对称时序:偶尔发生的交互可以入场稍慢、退出较快。高频、短暂 UI(hover 高亮、popover、panel 切换)则相反:立即入场(0ms),退出时短暂淡出(100-150ms),让操作感觉即时。
  • 可点击控件在
    :active
    时以 0ms 响应按下,并设置
    touch-action: manipulation
    。
  • DOM 入场使用
    @starting-style
    ;不支持时回退到
    data-mounted
    attribute。
  • 较小的
    filter: blur(2px)
    可掩盖内容切换时粗糙的交叉淡化。

Motion design principles

动效设计原则

  • Continuity over teleportation. Elements visible in both states transition in place; expand from where elements sit rather than fading in a new instance. Never duplicate a persistent element or hard-cut between views that share components; hard cuts lose spatial context.
  • Directional motion matches position. Tab and carousel transitions animate in the direction matching spatial layout (left-to-right forward, right-to-left back).
  • Emerge from the trigger. Overlays, trays, and panels animate outward from the element that opened them; generic centre-screen entrances break spatial orientation. Better still where the shapes allow: let the trigger become the surface (see the container-morph recipe).
  • Confirm in place, not in a corner. An action's result belongs on the control that caused it: the button becomes "Copied", holds, and reverts. A toast in the far corner makes the user's eye leave the thing they just touched to find out whether it worked. Reserve corner toasts for results with no on-screen origin (a background job finishing, an incoming message).
  • Animate paired states together. If open animates, close animates. If hover has motion, focus and pressed states get equivalent feedback. Do not polish only one half of a repeated interaction.
  • Delight scales inversely with frequency. Rarer interactions get more personality; high-frequency actions must be invisible.
  • Motion enhances perceived speed. Smooth transitions feel faster than hard cuts, even at identical load times.
  • 连续性优先于瞬移。 两个状态中都可见的元素应原地过渡;从元素所在位置扩展,而不是淡入一个新实例。绝不重复创建常驻元素,也不要在共享组件的视图之间硬切;硬切会丢失空间上下文。
  • 方向性运动与位置匹配。 标签页和 carousel 过渡应沿空间布局对应的方向运动(向前时从左到右,返回时从右到左)。
  • 从触发源涌现。 Overlay、tray 和 panel 应从打开它们的元素向外展开;通用的屏幕中央入场会破坏空间方向感。形状允许时效果更佳:让触发元素成为该表面(参见容器变形配方)。
  • 在原地确认,而不是在角落确认。 操作结果应呈现在触发它的控件上:按钮变为“Copied”,保持片刻后再恢复。角落中的 toast 会让用户视线离开刚操作的控件去寻找操作结果。仅将角落 toast 用于屏幕上没有来源的结果(后台任务完成、收到消息)。
  • 成对状态一起动效化。 如果打开有动画,关闭也应有动画。如果 hover 有动效,focus 和 pressed 状态应提供等价反馈。不要只打磨重复交互的一半。
  • 愉悦感与频率成反比。 越少见的交互越可以展现个性;高频操作必须无感。
  • 动效提升感知速度。 即使实际加载时间相同,平滑过渡也会比硬切感觉更快。

What to animate

应该为哪些内容添加动画

  • Movement:
    transform
    and
    opacity
    only; they skip layout and paint.
  • State feedback:
    color
    ,
    background-color
    , and
    opacity
    are acceptable.
  • Never animate layout properties (
    width
    ,
    height
    ,
    top
    ,
    left
    ); they trigger layout recalc every frame. (Exception: a deliberate container tween, see the card-resize and container-morph recipes.)
  • Never use
    transition: all
    ; it animates unintended properties and silently adopts future ones. List them explicitly.
  • Avoid
    filter
    animation for core interactions; if unavoidable keep blur ≤ 20px (heavy blur is expensive, especially in Safari).
  • SVG: apply transforms on a
    <g>
    wrapper with
    transform-box: fill-box; transform-origin: center
    ; without it they rotate/scale around the canvas origin. Line drawing, path morphing, and the Motion SVG origin override live in references/svg-animation.md.
  • transform: scale()
    also scales children (icons, text, borders scale proportionally), unlike
    width
    /
    height
    : a feature for press feedback, but account for it when an inner element must stay fixed-size.
  • Disable transitions during theme switches (
    [data-theme-switching] * { transition: none !important }
    ), or every themed property animates at once. Force a reflow (
    void document.body.offsetHeight
    ) after the flip and remove the override on the next frame, or use
    next-themes
    disableTransitionOnChange
    .
  • 移动:仅使用
    transform
    和
    opacity
    ;这样可以跳过布局和绘制。
  • 状态反馈:可以使用
    color
    、
    background-color
    和
    opacity
    。
  • 切勿动画化布局属性(
    width
    、
    height
    、
    top
    、
    left
    );它们每帧都会触发布局重新计算。(例外:刻意进行的容器补间,参见卡片调整尺寸和容器变形配方。)
  • 切勿使用
    transition: all
    ;它会动画化非预期属性,并自动接纳未来新增的属性。应明确列出属性。
  • 核心交互应避免动画化
    filter
    ;如果无法避免,将模糊控制在 ≤ 20px(重度模糊成本较高,在 Safari 中尤其如此)。
  • SVG:在
    <g>
    包装器上应用 transform,并设置
    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
    。

Easing defaults

缓动默认值

ElementDurationEasing
Button press feedback100-160ms
cubic-bezier(0.22, 1, 0.36, 1)
Tooltips, small popovers125-200ms
ease-out
or enter curve
Dropdowns, selects150-250ms
cubic-bezier(0.22, 1, 0.36, 1)
Modals, drawers200-350ms
cubic-bezier(0.22, 1, 0.36, 1)
Move/slide on screen200-300ms
cubic-bezier(0.25, 1, 0.5, 1)
Page transitions250-400msenter or move curve
Hover (colour/opacity), one control200ms
ease
Hover (transform/scale)100-150msenter curve
Illustrative/marketingUp to 1000msSpring or custom
Keep routine UI under 300ms; scale duration with distance (a full-screen slide can exceed 300ms, a 6px tooltip shift stays under 150ms).
Named curves
  • Enter:
    cubic-bezier(0.22, 1, 0.36, 1)
    for entrances and transform-based hover
  • Move:
    cubic-bezier(0.25, 1, 0.5, 1)
    for slides, drawers, panels
  • Drawer (iOS-like):
    cubic-bezier(0.32, 0.72, 0, 1)
    (extremely steep start; the reason its 500ms doesn't read as slow)
  • Expo out:
    cubic-bezier(0.19, 1, 0.22, 1)
    for dramatic reveals, card hovers, text reveals
  • Press:
    cubic-bezier(0.25, 0.46, 0.45, 0.94)
    for button press feedback
  • On-screen move:
    cubic-bezier(0.645, 0.045, 0.355, 1)
    for back-and-forth movement that stays on screen
Avoid
ease-in
for UI: it starts slow, so the element lags the user's action and feels sluggish. Prefer custom curves from easing.dev over built-in
ease
/
ease-out
, whose gentle acceleration reads soft, not decisive.
元素时长缓动
按钮按下反馈100-160ms
cubic-bezier(0.22, 1, 0.36, 1)
Tooltip、小型 popover125-200ms
ease-out
或入场曲线
Dropdown、select150-250ms
cubic-bezier(0.22, 1, 0.36, 1)
Modal、drawer200-350ms
cubic-bezier(0.22, 1, 0.36, 1)
屏幕内移动/滑动200-300ms
cubic-bezier(0.25, 1, 0.5, 1)
页面过渡250-400ms入场或移动曲线
单一控件的 hover(颜色/透明度)200ms
ease
Hover(transform/scale)100-150ms入场曲线
展示性/营销动效最长 1000msSpring 或自定义曲线
常规 UI 应控制在 300ms 以内;根据移动距离调整时长(全屏滑动可以超过 300ms,而 6px 的 tooltip 位移应控制在 150ms 以内)。
命名曲线
  • Enter:
    cubic-bezier(0.22, 1, 0.36, 1)
    ,用于入场和基于 transform 的 hover
  • Move:
    cubic-bezier(0.25, 1, 0.5, 1)
    ,用于滑动、drawer 和 panel
  • Drawer (iOS-like):
    cubic-bezier(0.32, 0.72, 0, 1)
    (起始阶段极其陡峭;这就是其 500ms 时长不会显得缓慢的原因)
  • Expo out:
    cubic-bezier(0.19, 1, 0.22, 1)
    ,用于戏剧性显现、卡片 hover 和文本显现
  • Press:
    cubic-bezier(0.25, 0.46, 0.45, 0.94)
    ,用于按钮按下反馈
  • On-screen move:
    cubic-bezier(0.645, 0.045, 0.355, 1)
    ,用于始终停留在屏幕内的往复运动
UI 中应避免使用
ease-in
:它起步较慢,会让元素落后于用户操作并显得迟缓。相比内置的
ease
/
ease-out
,优先使用 easing.dev 中的自定义曲线;内置曲线的平缓加速会显得柔和,而不是果断。

Transition decision rules

过渡决策规则

Match the UI element first, then pick the recipe from references/transition-recipes.md:
UI patternRecipe
Trigger + floating dot/countNotification badge
Trigger grows into the surface it opensContainer morph
Trigger + anchored surfaceMenu dropdown
Centred surface on top of pageModal dialog
Panel sliding into existing containerPanel reveal
List ↔ detail or wizard stepsPage side-by-side slides
Element dimension changesCard resize
Text updating in placeText state swap
Two icons in same slotIcon swap
Number arriving on its ownNumber pop-in
Number the user is drivingOdometer digit roll
Confirmation / success momentSuccess celebration
Hovering item in horizontal stackAvatar group hover
Form validation errorError state shake
Prefer lower-overhead transitions (CSS-only) unless the design requires JS orchestration.
先匹配 UI 元素,再从 references/transition-recipes.md 中选择配方:
UI 模式配方
触发源 + 浮动圆点/计数通知徽章
触发源扩展为打开的表面容器变形
触发源 + 锚定表面菜单下拉
页面顶部的居中表面模态对话框
在现有容器中滑入的 panel面板显现
列表 ↔ 详情或向导步骤页面并排滑动
元素尺寸变化卡片尺寸调整
原地更新的文本文本状态切换
同一位置中的两个图标图标切换
独立出现的数字数字弹出
用户正在控制的数字里程表数字滚动
确认/成功时刻成功庆祝
水平堆叠中悬停的项目头像组 hover
表单验证错误错误状态抖动
除非设计要求 JS 编排,否则优先使用开销较低的过渡(仅使用 CSS)。

Spatial and sequencing

空间关系与时序编排

  • Popover
    transform-origin
    at the trigger (modals stay
    center
    ), dialog/menu entrances from
    scale(0.9-0.96)
    not
    scale(0)
    (small popovers at the low end, full dialogs at the high end: a large surface already travels far in absolute pixels), and 30-50ms staggers (total under 300ms, most important element leading). Full rules and code in references/transition-recipes.md and references/contextual-animations.md.
  • Paired elements rule: elements that animate together (modal + overlay, tooltip + arrow, FAB + label) must share easing and duration. Mismatched timing is the usual cause of "something feels off".
  • Popover 的
    transform-origin
    应位于触发源(modal 则保持在
    center
    ),dialog/menu 从
    scale(0.9-0.96)
    入场,而不是
    scale(0)
    (小型 popover 取较低值,完整 dialog 取较高值:大型表面本身已经移动了较远的绝对像素距离),并采用 30-50ms 的交错间隔(总时长不超过 300ms,且最重要的元素先出现)。完整规则和代码见 references/transition-recipes.md 与 references/contextual-animations.md。
  • 成对元素规则: 一起运动的元素(modal + overlay、tooltip + arrow、FAB + label)必须共享缓动和时长。计时不匹配通常就是“感觉不对”的原因。

Accessibility

无障碍

  • Gate hover (motion and paint) behind
    @media (hover: hover) and (pointer: fine)
    , or touch devices replay hover on tap. Inspect the generated CSS before adding a gate; Tailwind v4 already wraps
    hover:
    in
    @media (hover: hover)
    .
  • During direct manipulation, keep the element locked to the pointer with no easing; add easing only after release.
  • Optional interface SFX: sparse, gesture-unlocked, additive confirmation only. See references/interface-sfx.md.
  • 将 hover(动效和绘制)限制在
    @media (hover: hover) and (pointer: fine)
    之后,否则触摸设备会在点击时重放 hover。添加限制前应检查生成的 CSS;Tailwind v4 已经将
    hover:
    包裹在
    @media (hover: hover)
    中。
  • 直接操控期间,让元素无缓动地锁定在指针位置;仅在释放后添加缓动。
  • 可选的界面 SFX:应保持稀疏、由手势触发,且仅用于附加确认。参见 references/interface-sfx.md。

Performance

性能

  • Pause looping animations off-screen with
    IntersectionObserver
    ; they burn GPU even when invisible.
  • Toggle
    will-change
    only during heavy motion and only for
    transform
    /
    opacity
    ; remove it after. Each promotion costs compositor memory; permanent promotion across many elements is worse than none.
  • Do not animate drag via CSS variables on a container; every update recalculates styles for all children. Set
    transform
    directly on the moving element.
  • Motion
    x
    /
    y
    values are the default for axis movement and drag (they bypass React re-renders). Use a full
    transform
    string when one owner must combine multiple transform functions, interop with non-Motion code, or survive a busy main thread: the shorthands run on
    requestAnimationFrame
    and drop frames when motion coincides with navigation, data loading, or hydration; CSS/WAAPI stay smooth there.
  • Motion that janks only sometimes (on open, during navigation, while data lands) is usually a long task sharing the tick, not a costly animation. Don't start an animation and expensive work in the same tick: start the motion, let a frame land, then do the work, or defer it to
    transitionend
    .
  • See references/performance-deep-dive.md for WAAPI, compositing layers, long tasks during animation, and the CSS vs JS comparison table.
  • 使用
    IntersectionObserver
    暂停屏幕外的循环动画;即使不可见,它们也会消耗 GPU。
  • 仅在重度运动期间为
    transform
    /
    opacity
    切换
    will-change
    ,完成后将其移除。每次图层提升都会消耗合成器内存;在大量元素上永久提升比不提升更糟。
  • 不要通过容器上的 CSS 变量实现拖拽动画;每次更新都会为所有子元素重新计算样式。应直接在移动元素上设置
    transform
    。
  • Motion 的
    x
    /
    y
    值是轴向移动和拖拽的默认方式(可绕过 React 重新渲染)。当必须组合多个 transform 函数、与非 Motion 代码互操作,或需要在繁忙主线程中保持流畅时,使用完整的
    transform
    字符串;简写形式通过
    requestAnimationFrame
    运行,在动画与导航、数据加载或 hydration 同时发生时可能掉帧,而 CSS/WAAPI 在这些情况下仍能保持流畅。
  • 仅在某些情况下卡顿的动效(打开时、导航期间、数据到达时),通常是长任务与动画 tick 共享所致,而非动画本身成本过高。不要在同一 tick 中启动动画和执行昂贵工作:先启动动效,让一帧落地,然后再执行工作,或将工作推迟到
    transitionend
    。
  • 有关 WAAPI、合成层、动画期间的长任务,以及 CSS 与 JS 对比表,请参阅 references/performance-deep-dive.md。

Anti-patterns

反模式

High-signal failures not covered above:
  • Animating on mount without a user trigger: unexpected motion disorients; the user did nothing to cause it.
  • Hard stops on drag boundaries feel broken; apply friction/damping so movement diminishes past it (see gesture-drag reference).
  • Animating both a container and staggering its children: pick one entrance per container. If the panel slides in, its content should already be visible on arrival.
  • Tooltip animation after the first is open: subsequent tooltips in the group open instantly, or the toolbar feels laggy.
  • Scroll-revealing product UI, above-the-fold content, or every section of a page: scroll reveals belong to a few chosen moments on marketing surfaces, run once, and never re-animate on scroll-up (see references/scroll-animations.md).
  • Easing or duration on scrubbed (scroll-driven) motion: scroll position is the clock, so any curve or duration makes it lag the scrollbar.
    linear
    and no duration is correct there, and only there.
  • Reduced motion handled only in CSS: Motion's JS-driven animations ignore a
    @media (prefers-reduced-motion)
    block, so the CSS gate passes review while spatial travel still plays. Wrap the app in
    <MotionConfig reducedMotion="user">
    or branch on
    useReducedMotion()
    . The opposite overcorrection, a global
    * { transition: none !important }
    under reduce, also strips the opacity and colour feedback that reduced motion keeps.
  • Installing
    framer-motion
    for new work: the package is now
    motion
    and React imports come from
    motion/react
    . The old package still resolves, so a mixed codebase compiles while shipping two copies of the library.
以下问题未在上文覆盖,但值得警惕:
  • 未由用户触发便在挂载时添加动画:意外运动会让人迷失方向,因为用户没有做任何事来引发它。
  • 拖拽边界处突然停止会显得异常;应施加摩擦/阻尼,使元素越过边界后逐渐减速(参见手势拖拽参考)。
  • 同时动画化容器并交错其子元素:为每个容器选择一种入场方式。如果 panel 滑入,其内容在到达时就应已经可见。
  • 某个 tooltip 首次打开后,后续 tooltip 才开始动画:同一组中的后续 tooltip 应立即打开,否则工具栏会显得迟缓。
  • 使用滚动显现产品 UI、首屏内容或页面中的每个区块:滚动显现仅适用于营销界面中少数经过选择的时刻,只运行一次,并且在向上滚动时绝不重新播放(参见 references/scroll-animations.md)。
  • 为 scrubbed(滚动驱动)动效设置缓动或时长:滚动位置本身就是时钟,因此任何曲线或时长都会使其落后于滚动条。只有在这种情况下才应使用
    linear
    且不设置时长。
  • 仅在 CSS 中处理 reduced motion:Motion 的 JS 驱动动画会忽略
    @media (prefers-reduced-motion)
    ,因此 CSS 限制虽然通过审查,空间移动效果仍会播放。请将应用包裹在
    <MotionConfig reducedMotion="user">
    中,或通过
    useReducedMotion()
    分支处理。反向的过度修正同样有问题:在 reduced motion 下使用全局
    * { transition: none !important }
    ,会移除 reduced motion 仍保留的透明度和颜色反馈。
  • 为新工作安装
    framer-motion
    :该包现已更名为
    motion
    ,React 导入路径为
    motion/react
    。旧包仍可解析,因此混合代码库虽然可以编译,却会同时打包两份库。

Workflow

工作流

Copy and track:
text
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. Answer the four questions in references/decision-framework.md: animate? purpose? easing? speed?
  2. Pick duration from the easing defaults table above. If the value is contested, dial it live in the DevTools bezier editor (Chrome or Firefox; Safari has none) against the real component, then paste the literal into source beside the other timing constants: a DevTools edit dies on navigation.
  3. Choose implementation: CSS transition > WAAPI > spring > keyframe > JS.
  4. Load the reference for your component or technique.
  5. When reviewing, apply the strict posture in references/review-format.md: measure against the ten standards, output the Before/After/Why table, then a tiered verdict ending in a Block/Approve decision.
复制并跟踪:
text
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 bezier editor(Chrome 或 Firefox;Safari 没有)中针对真实组件实时调节,然后将字面数值粘贴到源代码中其他计时常量旁边:DevTools 中的编辑会在页面导航后丢失。
  3. 选择实现方式:CSS transition > WAAPI > spring > keyframe > JS。
  4. 加载与组件或技术相关的参考文件。
  5. 审查时,采用 references/review-format.md 中的严格标准:根据十项标准进行评估,输出 Before/After/Why 表格,然后给出分级结论,并以 Block/Approve 决策结束。

Validation

验证

Produce evidence for each check (DevTools observations, not "looks fine"):
  • Grep the diff for layout property transitions (
    width
    ,
    height
    ,
    top
    ,
    left
    ) and
    transition: all
    .
  • Retoggle components rapidly; confirm transitions retarget instead of restarting from zero.
  • Slow to 10% in the DevTools Animations panel to catch timing and
    transform-origin
    issues invisible at full speed.
  • Confirm
    will-change
    is toggled around animations, not permanently set, and looping animations pause off-screen.
  • Test touch interactions on real devices; simulators under-report gesture and hover-on-tap issues.
  • Honor
    prefers-reduced-motion
    : replace spatial travel with immediate state changes or restrained fades. Pause looping decorations with
    animation-play-state: paused
    (do not yank them with
    display: none
    ). Keep explicit user-triggered feedback. Exercise the same task in that mode.
为每项检查提供证据(记录 DevTools 中的观察结果,而不是“看起来不错”):
  • 在 diff 中搜索布局属性过渡(
    width
    、
    height
    、
    top
    、
    left
    )和
    transition: all
    。
  • 快速反复切换组件;确认过渡会重新设定目标,而不是从零重新开始。
  • 在 DevTools Animations 面板中减速至 10%,以发现全速下不可见的时序和
    transform-origin
    问题。
  • 确认
    will-change
    在动画前后切换,而不是永久设置;确认循环动画会在离开屏幕时暂停。
  • 在真实设备上测试触摸交互;模拟器通常会低估手势和点击触发 hover 的问题。
  • 遵循
    prefers-reduced-motion
    :将空间移动替换为即时状态变化或克制的淡化。使用
    animation-play-state: paused
    暂停循环装饰动画(不要使用
    display: none
    将其突然移除)。保留明确的用户触发反馈,并在该模式下执行相同任务。

Discovery workflow

Discovery 工作流

For "where should this animate", run the Discovery sweep in
references/decision-framework.md
. Report opportunities supported by purpose and usage frequency, plus the rejected ones. Implement a suggestion only when implementation is in scope.
对于“哪里应该添加动画”,运行 references/decision-framework.md 中的 Discovery sweep。报告由目的和使用频率支持的机会,同时列出已否决的候选项。仅当实现属于当前范围时才实施建议。

Reverse-engineer workflow

逆向工程工作流

Use this branch to measure an existing animation from a screen recording, then emit code and a handoff spec that reproduce it. The scripts under
scripts/
are the canonical, deterministic path; run them rather than reconstructing their logic.
Resolve every
scripts/
command below relative to the installed skill directory, not the application working directory.
Dependencies: Check for
ffmpeg
/
ffprobe
and a Python environment with
opencv-python
,
numpy
, and
scipy
before running the measurement scripts. Do not assume these are installed by Open Design. Reuse an available isolated Python environment; any dependency setup must respect the host's authorization. If only ffmpeg is available, extract frames and label the analysis as a visual estimate. If media inspection is unavailable, state the missing capability; never claim measured timing, fitted curves, or a recording comparison. Use a fresh task-local output directory for each extraction so old frames cannot contaminate the contact sheet. The scripts below are optional measurement tools, not a requirement for ordinary interface-animation implementation.
text
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. Extract. Run
    python3 scripts/extract_frames.py <video> <outdir>
    . Trim to just the transition with
    --start
    /
    --duration
    ; if the interaction has both an open and a close, trim two windows and run the pipeline once per direction (they are almost never mirror images). Match
    --fps
    to the source (probe with
    ffprobe
    ), never sampling above the source rate. Open
    contact_sheet.png
    first.
  2. Vision pass. Name the element(s) that move, every effect (translate, scale often anisotropic, opacity, blur, corner radius, shadow, color), and the phases, noting which property leads and lags. Use the checklist in
    references/measurement-guide.md
    .
  3. Decide precision. Simple fade or linear slide: read timing off the contact sheet, skip to step 5. Elastic, springy, or multi-property motion: escalate to step 4 (eyeballing a spring is unreliable).
  4. Track and fit. Run
    python3 scripts/track_motion.py <outdir>
    for
    metrics.json
    (pass
    --bbox X,Y,W,H
    to isolate one element), then
    python3 scripts/fit_curves.py <outdir>/metrics.json
    for spring params, cubic-bezier, and per-property fit error. Pass the same
    --fps
    you extracted with. Read
    references/curve-fitting.md
    to pick the model; high error on both means multi-phase motion (split and fit each segment).
  5. Annotate. Load
    references/choreography.md
    . Build the timing-offset table (when each property starts and settles); lead/lag gaps and over-stretch carry more feel than any single curve.
  6. Emit. Substitute fitted parameters into the templates in
    references/code-output.md
    for the target. Keep movement on
    transform
    /
    opacity
    . Emit two transitions when open and close differ, plus the consolidated handoff spec so it can be implemented without the video.
  7. Validate. Re-derive: play the emitted animation, screen-record it, run it back through
    extract_frames.py
    , and compare contact sheets side by side. Slow to 0.1x to confirm phase order and over-stretch survive. Confirm the code only animates
    transform
    ,
    opacity
    , and
    filter
    .
Reverse-engineer gotchas:
  • fit_curves.py
    defaults to
    --fps 30
    : extract at 60 but fit at the default and every
    duration_ms
    doubles while fitted stiffness drops to a quarter. Always pass the extraction fps to the fit.
  • Sampling above the source rate duplicates frames: a 24 fps GIF extracted at 60 inflates fit error with plateaued runs in
    metrics.json
    . Probe and match the source rate.
  • Screen recordings drop frames and iOS/QuickTime captures are variable-frame-rate; consecutive identical rows are duplicated frames, not a pause. Re-record at a steadier rate if plateaus dominate.
  • Measure open and close as separate clips and report two curves; never fit one and reuse it reversed (see
    references/choreography.md
    ). Treat a fit
    error
    above 0.08 as suspect.
使用此分支从屏幕录制中测量现有动画,然后输出可复现该动画的代码和交接规范。
scripts/
下的脚本是规范且确定性的执行路径;应直接运行这些脚本,而不是重新实现其逻辑。
以下所有
scripts/
命令都应相对于已安装的 skill 目录解析,而不是相对于应用工作目录。
依赖项: 运行测量脚本前,检查
ffmpeg
/
ffprobe
以及包含
opencv-python
、
numpy
和
scipy
的 Python 环境。 不要假定 Open Design 已安装这些依赖。复用可用的隔离 Python 环境;任何依赖项安装都必须遵循宿主的授权。 如果只有 ffmpeg 可用,则提取帧并将分析标记为视觉估算。如果无法检查媒体,应说明缺少的能力; 绝不能声称获得了实测时序、拟合曲线或录屏对比结果。 每次提取都使用新的任务本地输出目录,避免旧帧污染 contact sheet。以下脚本是可选的测量工具, 并非普通界面动画实现的必需条件。
text
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. 视觉分析。 确定移动的元素、每一种效果(translate、scale 通常是非等比的、opacity、blur、corner radius、shadow、color)和各个阶段,并注明哪个属性领先、哪个属性滞后。使用 references/measurement-guide.md 中的检查清单。
  3. 确定精度。 对于简单淡出或线性滑动:从 contact sheet 读取时序,然后跳至第 5 步。对于弹性、弹簧感或多属性运动:提升至第 4 步(仅凭肉眼判断 spring 不可靠)。
  4. 跟踪与拟合。 运行
    python3 scripts/track_motion.py <outdir>
    生成
    metrics.json
    (传入
    --bbox X,Y,W,H
    可隔离单个元素),然后运行
    python3 scripts/fit_curves.py <outdir>/metrics.json
    获取 spring 参数、cubic-bezier 和各属性的拟合误差。传入与提取时相同的
    --fps
    。阅读 references/curve-fitting.md 以选择模型;如果两者的误差都很高,则说明这是多阶段运动,应拆分并分别拟合每个阶段。
  5. 标注。 加载 references/choreography.md。建立时序偏移表(每个属性何时开始以及何时稳定);领先/滞后差距和过度拉伸对动效质感的影响通常大于任何单条曲线。
  6. 输出。 将拟合参数代入 references/code-output.md 中针对目标平台的模板。移动应保持在
    transform
    /
    opacity
    上。如果打开和关闭不同,则输出两组过渡,同时提供合并后的交接规范,使其无需参考视频也能实现。
  7. 验证。 重新推导:播放输出的动画、进行屏幕录制,再通过
    extract_frames.py
    运行录制内容,并并排比较 contact sheet。减速至 0.1x,确认阶段顺序和过度拉伸均得以保留。确认代码仅动画化
    transform
    、
    opacity
    和
    filter
    。
逆向工程常见陷阱:
  • fit_curves.py
    默认使用
    --fps 30
    :如果以 60fps 提取却使用默认值拟合,每个
    duration_ms
    会翻倍,而拟合出的刚度会降至四分之一。始终将提取时的 fps 传给拟合步骤。
  • 以高于源帧率的速率采样会复制帧:以 60fps 提取 24fps GIF 会扩大
    metrics.json
    的拟合误差,并出现平台期。检测并匹配源帧率。
  • 屏幕录制可能丢帧,iOS/QuickTime 捕获则可能采用可变帧率;连续相同的行是重复帧,而不是停顿。如果平台期占主导,应以更稳定的速率重新录制。
  • 分别测量打开和关闭片段并报告两条曲线;绝不能拟合一条曲线后反向复用(参见 references/choreography.md)。拟合
    error
    高于 0.08 时应视为可疑。

Related skills

相关 skill

  • product-design
    : which states exist, what an action affects, and whether it is reversible. Route here first when a gesture replaces a control, since swipe-to-delete and hold-to-confirm change what the user can do before they change how it moves.
  • ui-design
    Direction mode: visual direction, palettes, typography; settle the visual system before tuning motion.
  • ui-design
    Audit mode: page/feature-level UI quality audit. Motion craft and fixes belong here.
  • Optional external
    animate-text
    skill where installed: curated named text effects (typewriter, line reveal, stagger builds) with exact JSON specs.
Upstream evaluation fixtures are not part of this runtime bundle. Source and adaptation details are recorded in SOURCES.md.
  • product-design
    :确定存在哪些状态、操作会影响什么,以及操作是否可逆。当手势替代控件时,应优先路由到此处,因为滑动删除和长按确认不仅会改变元素的移动方式,还会先改变用户可执行的操作。
  • ui-design
    Direction 模式:视觉方向、配色、字体;在调整动效之前先确定视觉系统。
  • ui-design
    Audit 模式:页面或功能级 UI 质量审计。动效工艺和相关修复应放在此处。
  • 可选的外部
    animate-text
    skill(已安装时):提供精选的具名文本效果(typewriter、line reveal、stagger builds)及精确 JSON 规范。
上游评估 fixtures 不属于此运行时 bundle。来源和改编详情记录在 SOURCES.md 中。