mcpField
M
motion-principles

motion-principles

github.com/athevon设计与 UI6981.1k 次安装3 周前更新
代码仓库

关于 motion-principles

motion-principles 是面向 Claude Code、claude.ai 和 Cowork 的创意编码技能,涵盖 Web、Android 和 Apple 平台的动效与交互设计。它提供时长、缓动、无障碍和性能指导,并链接到平台专属技能以深入实践。

主要功能

  1. 01跨平台动效指南
  2. 02时长与缓动建议
  3. 03减少动态效果的无障碍指导
  4. 04动画性能检查清单
  5. 05链接平台专属技能

适用场景

  1. 01规划 UI 转场行为
  2. 02检查动画是否支持减少动态效果
  3. 03改善动画流畅度和性能

安装

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

$npx skills add https://github.com/athevon/genjutsu --skill motion-principles

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

详细介绍

版本敏感。 以下所有 API 名称、SDK 门槛和浏览器支持声明均已于 2026-09-08 对照一手来源核实。核实了什么以及何时核实,见 _jutsu/VERSIONS.md。如果该日期已过,请在依据版本号采取行动前重新核实。

动效原则

基础内容。每次调用创意技能时都会加载。 此处列出简明规则。深入内容见 references/。


时长规则

场景时长原因
微交互(切换、悬停、焦点)100-150ms即时反馈,不会让人感觉有延迟
UI 过渡(模态框、抽屉、标签切换)200-300ms流畅但绝不迟滞
页面/路由过渡300-500ms构建空间叙事
滚动驱动 / 3D自由(基于进度)与用户输入绑定,不设固定时长

频率规则: 动画播放得越频繁,就必须越短、越含蓄。 按钮悬停(每天 1000 次)= 100ms 透明度变化。引导流程揭示(仅一次)= 600ms 以上的完整编排。


缓动速查表

操作缓动原因
元素进入ease-out / 弹簧减速并停在静止位置(自然到达)
元素退出ease-in加速离开(不挡路)
元素在状态间移动ease-in-out平滑启动和停止
与滚动同步linear / none与输入保持 1:1 匹配,不会感觉滞后
弹跳/活泼弹簧(欠阻尼)超调带来生命力
干脆利落的 UIcubic-bezier(0.2, 0, 0, 1)快速启动,平滑落定

退出总是比进入更含蓄。 进入:300ms ease-out,完整编排。退出:200ms ease-in,仅改变透明度。

原生缓动对应关系(跨平台)
Web(CSS / JS)SwiftUICompose
cubic-bezier(0.2, 0, 0, 1).spring(response: 0.4, dampingFraction: 0.85) 或 .snappyspring(stiffness = Spring.StiffnessMedium, dampingRatio = 0.85f)
ease-out.easeOut(duration: 0.3)tween(durationMillis = 300, easing = LinearOutSlowInEasing)
ease-in.easeIn(duration: 0.2)tween(durationMillis = 200, easing = FastOutLinearInEasing)
弹簧(弹跳).bouncy(iOS 17+)spring(stiffness = Spring.StiffnessLow, dampingRatio = Spring.DampingRatioMediumBouncy)
弹簧(平滑).smooth(iOS 17+)spring(stiffness = Spring.StiffnessMedium, dampingRatio = Spring.DampingRatioNoBouncy)

无障碍(不可妥协)

减少动态效果 - 必须遵守

每个动画组件都必须尊重用户对减少动态效果的偏好。无论平台如何,都不得例外。

平台API
Web CSS@media (prefers-reduced-motion: reduce)
Web JSwindow.matchMedia('(prefers-reduced-motion: reduce)')
SwiftUI@Environment(\.accessibilityReduceMotion) var reduceMotion
UIKitUIAccessibility.isReduceMotionEnabled(+ reduceMotionStatusDidChangeNotification)
Compose使用 Settings.Global.ANIMATOR_DURATION_SCALE 的自定义辅助函数(深入内容见 mobile-principles/references/accessibility-mobile.md)

CSS:

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

SwiftUI:

struct AnimatedView: View {
    @Environment(\.accessibilityReduceMotion) var reduceMotion
    @State var visible = false

    var body: some View {
        Text("Hello")
            .opacity(visible ? 1 : 0)
            .animation(reduceMotion ? .none : .spring(response: 0.4, dampingFraction: 0.85), value: visible)
    }
}

Compose:

@Composable
fun rememberReduceMotion(): Boolean {
    val context = LocalContext.current
    return remember {
        Settings.Global.getFloat(context.contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE, 1f) == 0f
    }
}

@Composable
fun AnimatedComponent(visible: Boolean) {
    val reduce = rememberReduceMotion()
    val alpha by animateFloatAsState(
        targetValue = if (visible) 1f else 0f,
        animationSpec = if (reduce) snap() else spring(stiffness = Spring.StiffnessMedium)
    )
}
其他无障碍要求
  • 焦点指示器绝不能被动画隐藏
  • 动画内容在每一帧都必须满足 WCAG 对比度比例(不能在过渡中途淡化到文字不可见)
  • 循环动画:提供暂停机制

通用“禁止”规则

1. 绝不对 width/height/top/left 添加动画

每一帧都会触发布局重新计算 = 卡顿。

/* BAD */
.drawer { transition: height 0.3s ease; }
.drawer.open { height: 400px; }

/* GOOD */
.drawer { transition: transform 0.3s ease-out; transform: translateY(100%); }
.drawer.open { transform: translateY(0); }

SwiftUI 对应写法(错误 vs 正确):

// BAD - animates frame (causes layout pass)
.frame(height: open ? 400 : 0)
.animation(.easeInOut, value: open)

// GOOD - animates transform via offset
.offset(y: open ? 0 : 400)
.animation(.spring(), value: open)

Compose 对应写法(错误 vs 正确):

// BAD - animates size (full layout pass)
val height by animateDpAsState(if (open) 400.dp else 0.dp)

// GOOD - animates Y offset via graphicsLayer
val translation by animateFloatAsState(if (open) 0f else 400f)
Box(modifier = Modifier.graphicsLayer { translationY = translation })
2. 绝不缩放到 0

scale(0) 会让元素像掉进黑洞一样消失。始终保留最小值。

/* BAD */
.modal-exit { transform: scale(0); }

/* GOOD */
.modal-exit { transform: scale(0.95); opacity: 0; }

SwiftUI 对应写法:

// BAD
.scaleEffect(visible ? 1.0 : 0.0)

// GOOD
.scaleEffect(visible ? 1.0 : 0.95)
.opacity(visible ? 1.0 : 0.0)

Compose 对应写法:

// BAD
Modifier.graphicsLayer { scaleX = if (visible) 1f else 0f; scaleY = if (visible) 1f else 0f }

// GOOD
Modifier.graphicsLayer {
    scaleX = if (visible) 1f else 0.95f
    scaleY = if (visible) 1f else 0.95f
    alpha = if (visible) 1f else 0f
}
3. 进入时绝不使用 ease-in

Ease-in = 缓慢启动。进入的元素若迟疑不前,会让人感觉出了问题。

/* BAD */
.card-enter { animation: fadeIn 0.3s ease-in; }

/* GOOD */
.card-enter { animation: fadeIn 0.3s ease-out; }
/* OR spring via JS for natural feel */
4. UI 交互耗时绝不超过 500ms

模态框、下拉菜单、工具提示、标签页——用户都在等待。请珍惜他们的时间。

// BAD
gsap.to(modal, { opacity: 1, y: 0, duration: 0.8 });

// GOOD
gsap.to(modal, { opacity: 1, y: 0, duration: 0.25, ease: "power2.out" });

SwiftUI:

// BAD
.animation(.easeInOut(duration: 0.8), value: state)

// GOOD
.animation(.spring(response: 0.25, dampingFraction: 0.85), value: state)

Compose:

// BAD
animateContentSize(animationSpec = tween(800))

// GOOD
animateContentSize(animationSpec = spring(stiffness = Spring.StiffnessMediumLow))
5. 绝不忽略 prefers-reduced-motion

这是无障碍要求,不是可有可无的选项。

// BAD
gsap.from('.hero-title', { opacity: 0, y: 40, duration: 0.6 });

// GOOD
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (!prefersReduced) {
  gsap.from('.hero-title', { opacity: 0, y: 40, duration: 0.6 });
}

SwiftUI / Compose 的对应实现,请参阅上方跨平台「减少动态效果」部分。


性能检查清单

  • 仅对 transform 和 opacity(仅合成属性)进行动画处理
  • 谨慎使用 will-change,并在动画完成后将其移除
  • 对于 JS 动画,优先使用 requestAnimationFrame,而不是 setTimeout/setInterval
  • 对于滚动驱动的动画:CSS animation-timeline > JS IntersectionObserver > 滚动监听器
  • 在低端设备上测试(在 DevTools 中将 CPU 限制为 4 倍)

快速参考:加载子技能

需求加载
深入了解缓动、弹簧配置references/easing-guide.md
可直接复制粘贴的进入/退出模式references/enter-exit-recipes.md
设计师加权的风格选择references/designers.md
移动端 UX 背景../mobile-principles/SKILL.md
桌面端 UX 背景../desktop-principles/SKILL.md
GSAP 详细信息../gsap/SKILL.md
Framer Motion 详细信息../framer-motion/SKILL.md
纯 CSS 动画../css-native/SKILL.md
Three.js / R3F../threejs-r3f/SKILL.md
Canvas / 生成式内容../canvas-generative/SKILL.md
Compose Android 动画../compose-motion/SKILL.md
Compose Multiplatform../compose-multiplatform/SKILL.md
SwiftUI iOS/macOS 动画../swiftui-motion/SKILL.md
Compose 高级图形../compose-graphics/SKILL.md
SwiftUI 高级图形../swiftui-graphics/SKILL.md
视觉 / 动效 / 无障碍审计../design-audit/SKILL.md
UI/UX 智能参考(84 种风格、192 种调色板)../ui-ux-pro-max/SKILL.md

评论

支持 Markdown