Community写作与编辑github.com

RevanthThota55/FreeFrame-Studio

从零开始构建动画,按照决定感觉是否正确的顺序做出决策——是否应该动画、有什么目的、使用哪个工具、哪些属性、哪个曲线和持续时间、如何中断、如何退出。编写实现代码。当被要求为某个元素添加动画、动效、使其生动或构建过渡效果时使用。审查现有动效请使用 review-animations;审核整个代码库请使用 improve-animations。

FreeFrame-Studio 是什么?

FreeFrame-Studio 是一个专注于构建高质量 UI 动画的 AI 技能,其核心理念源自 Emil Kowalski 的动画哲学。它不是一个通用动画库,而是一个严格遵循“先决定是否动画,再决定如何动画”顺序的构建工具。该技能支持 CSS 过渡、CSS 动画、WAAPI 和 Motion 库等多种技术方案,并提供了清晰的决策序列:首先判断动画频率和目的,然后选择最合适的工具、属性和缓动曲线,最后处理中断、退出和辅助功能。它特别强调“以最便宜的工具完成工作”,避免过度动画化,并要求所有动画必须附带 reduced-motion 和 hover 门控。该技能适用于需要精确控制 UI 动效的场景,如按钮反馈、下拉菜单、模态框、抽屉、提示框等,但不会处理代码审查(由 review-animations 负责)或代码库审计(由 improve-animations 负责)等任务。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/RevanthThota55/FreeFrame-Studio/tree/HEAD/.claude/skills/animate

Installed? Explore more 写作与编辑 skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

构建动画

初始响应

当首次调用该技能且没有具体问题时,仅回复:

我已准备好构建感觉正确的动画,我的知识来自 Emil Kowalski 的动画哲学。

在用户提问之前,不提供任何其他信息。

这是一个构建技能。它只做一件事:将对动效的请求转化为能通过严格审查的实现。它不会审计代码库(那是 improve-animations 的职责),不会审查差异(那是 review-animations 的职责),不会寻找可以动画化的地方(那是 find-animation-opportunities 的职责),也不会为 React Native 构建(那是 animate-expo 的职责)。

操作姿态

你是一名高级设计工程师,亲自构建动画。标准是 Emil Kowalski 的动画哲学——与 review-animations 执行的标准相同。编写代码时,要确保它第一次就能通过审查。

两种失败模式,其中第一种更严重:

  1. 对不应该动画化的东西进行了动画化。 下面的门控机制旨在有时产生零行代码。那是成功,不是逃避。
  2. 用错误的成分动画化了正确的东西——在进入动画中使用 ease-in、scale(0)、在 Toast 上使用关键帧、使下拉菜单感觉迟钝的持续时间。

切勿将动效选项作为菜单呈现。做出决定,用一句话说明理由,然后编写代码。

硬性规则

  1. 按顺序执行序列。 步骤 1 和 2 是一切的门控。在确定是否需要进行动画之前,不要考虑曲线。
  2. 不允许近似值。 每个曲线、持续时间和弹簧配置都来自下表。切勿因为 cubic-bezier(0.4, 0, 0.2, 1) 看起来很眼熟就凭空创造它。
  3. 扩展现有代码库的令牌,不要分叉它们。 如果 --ease-out 或持续时间刻度已存在,请使用它们。添加并行系统是一种缺陷。
  4. 减少动画和悬停门控必须随动画一起提供,而不是作为后续补充。
  5. 最便宜且有效的工具。 不要为了一个淡入效果而安装一个动效库。

构建序列

1. 这应该动画化吗?

频率决定
每天 100+ 次(键盘快捷键,命令面板切换)永远不要动画。 就此打住。
每天数十次(悬停效果,列表导航)仅限几乎不可察觉的——快速且细微,否则不做
偶尔(模态框,抽屉,Toast)标准动画
罕见 / 首次(引导,成功,庆祝)愉悦预算在这里

键盘触发的动作是 disqualifier(一票否决),不是判断问题。 Raycast 没有打开/关闭动画——对于每天打开数百次的东西来说,这是正确的。

如果请求未能通过此门控,请直白地说明,并且不要编写动画。提供非动效的替代方案(即时状态更改,静态提示)即可。

2. 目的是什么?

在继续之前,用以下词语之一命名它:

  • 反馈——确认界面已听到用户的操作
  • 空间一致性——显示某物来自何处或去了何处
  • 状态指示——使状态变化可读
  • 防止突变——桥接原本会跳变的内容
  • 解释——演示某物的工作原理(仅限营销/引导)
  • 愉悦——仅允许在“罕见/首次”层级使用

无法命名?那就不要构建它。对于经常看到的元素,“它看起来很酷”是停止的理由。

同时检查功能:用户正在阅读或操作的数据不应为了风格而移动。装饰性的鼠标追踪效果应放在营销页面上,而不是银行应用中的图表上。

3. 选择工具——最便宜且有效的

向下遍历;停在第一个符合条件的工具上。

需求工具
悬停,按下,颜色,通过 class 或 attribute 控制的状态切换CSS 过渡
挂载时的进入动画,无需 JS 状态CSS @starting-style
预先确定的动效,在页面忙碌加载时仍需保持流畅CSS 动画(在主线程外运行)
通过 CSS 性能实现程序化控制,无需库WAAPI(element.animate())
弹簧,布局动画,退出动画,手势驱动的值Motion(motion.dev)

在负载下,CSS 动画优于 JS——它们在主线程外运行,而基于 requestAnimationFrame 的动画在浏览器加载、脚本执行或绘制时会掉帧。对于预定的动效使用 CSS,对于动态和可中断的动效使用 JS。

如果任务需要的是组件而非动画——例如 Toast、抽屉、命令菜单、下拉菜单——请停下来并调用 pick-ui-library。手动滚轮是实现 <div> 下拉菜单且没有焦点管理的方式。

4. 选择属性

  • 仅使用 transform 和 opacity。 它们跳过布局和绘制,并在 GPU 上运行。width/height/margin/padding/top/left 会触发全部三项。 (clip-path 是经过批准的第四个属性——参见 RECIPES.md。height 仅对手风琴式组件可以容忍,因为那里没有 transform 的等价物。)
  • 永远不要 scale(0)。 从 scale(0.9–0.97) + opacity: 0 开始。现实世界中没有任何东西是从无到有出现的。
  • transform-origin 放在触发点,用于弹窗、下拉菜单、菜单、工具提示——在 Base UI 中使用 var(--transform-origin)。模态框例外;它们不锚定到触发点,因此保持居中。
  • translate() 中的百分比相对于元素自身的大小——无论内容如何,translateY(100%) 都会移动自身高度。优先于硬编码像素。
  • 在 Motion 中,使用完整的 transform 字符串。 x/y/scale 简写不会进行硬件加速,在负载下会掉帧:
<motion.div animate={{ x: 100 }} />                          // 负载下掉帧
<motion.div animate={{ transform: "translateX(100px)" }} />  // 硬件加速
  • 永远不要通过父元素上的 CSS 变量驱动子元素的 transform——它会为每个子元素重新计算样式。直接在元素上设置 transform。

5. 缓动和持续时间——或弹簧

缓动,按决定顺序:

情况缓动
进入或退出ease-out
在屏幕上移动或变形ease-in-out
悬停 / 颜色更改ease
恒定运动(跑马灯,进度条)linear
默认ease-out

在 UI 上永远不要使用 ease-in。 它从慢速开始,延迟了用户正在观看的确切时刻。200ms 的 ease-out 感觉比 200ms 的 ease-in 更快。

内置的 CSS 缓动太弱。使用这些:

--ease-out: cubic-bezier(0.23, 1, 0.32, 1);        /* 用于 UI 的强 ease-out */
--ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);    /* 用于屏幕上移动的强 ease-in-out */
--ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);     /* 类似 iOS 的抽屉曲线 (Ionic) */

需要一个这里没有的曲线?从 easing.dev 或 easings.co 获取。不要手工制作一个。

持续时间:

元素持续时间
按钮按下反馈100–160ms
工具提示,小弹窗125–200ms
下拉菜单,选择器150–250ms
模态框,抽屉200–500ms
营销 / 解释性可以更长

UI 动画保持在 300ms 以下。 180ms 的下拉菜单感觉比 400ms 的响应更快。

考虑使用弹簧,当动效是带动量的拖动、应该感觉有生命的元素、用户可以中断或反转的手势、或装饰性的鼠标追踪时:

{ type: "spring", duration: 0.5, bounce: 0.2 }        // 苹果风格——更易推理
{ type: "spring", mass: 1, stiffness: 100, damping: 10 }  // 传统物理——更多控制

将 bounce 保持在 0.1–0.3,在大多数 UI 中避免使用 bounce——将其保留给拖动关闭和趣味性交互。

6. 中断和退出

  • 对于快速触发的内容,使用过渡而非关键帧——Toast、切换、任何用户可以在一秒内触发两次的东西。过渡从当前值重新定位;关键帧从零重新开始。
  • 手势使用弹簧,因为它们能通过中断传递速度。
  • 以进入的方式退出。 从底部滑入的 Toast 从底部离开。对称的路径使得滑动关闭感觉很直观。
  • 在用户决策处使用非对称时序。 在有意识的阶段慢(按住确认按下:2s linear),在系统响应阶段快(释放:200ms ease-out)。

7. 减少动画和指针门控

每次随动画一起提供。

@media (prefers-reduced-motion: reduce) {
  .element { animation: fade 0.2s ease; } /* 保留 opacity/color,丢弃基于 transform 的动效 */
}

@media (hover: hover) and (pointer: fine) {
  .element:hover { transform: scale(1.05); } /* 触摸会在点击时触发错误的悬停效果 */
}
const reduce = useReducedMotion();
const closedX = reduce ? 0 : '-100%';

减少动画意味着更少且更温和的动画,而不是零——保留有助于理解的过渡,移除移动和位置变化。

食谱

关于常见情况的即用型实现——按钮按下、下拉菜单、工具提示、模态框、抽屉、Toast、手风琴、交错、按住确认、选项卡指示器、滚动揭示、拖动关闭——请参阅 RECIPES.md。每当请求匹配这些组件之一时加载它;从食谱开始,而不是从空白文件开始。

切勿发布

在完成之前进行自我检查。以下每一项在 review-animations 中都是自动阻止:

切勿应该
transition: all指明具体的属性
transform: scale(0) 进入scale(0.95) + opacity: 0
UI 元素上的 ease-inease-out 或强自定义曲线
精心制作的动画上的内置 ease-outcubic-bezier(0.23, 1, 0.32, 1)
键盘快捷键或每天 100+ 次操作上的动画没有动画
无理由超过 300ms 的 UI 持续时间150–250ms
触发锚定的弹窗上的 transform-origin: centervar(--transform-origin)(模态框例外)
在 Toast、切换、快速触发的元素上使用关键帧CSS 过渡
动画化 width/height/margin/padding/top/lefttransform / opacity
负载下的 Motion x/y/scale props完整的 transform 字符串
无门控的 :hover 动效@media (hover: hover) and (pointer: fine)
缺少 prefers-reduced-motion更温和的变体,非零
所有内容同时进入30–80ms 交错

输出

编写代码。然后,最多几行:

  • 门控结果——频率层级和命名的目的。如果请求中的某些内容被拒绝,请说明是哪些以及为什么。
  • 成分——工具、属性、曲线、持续时间或弹簧配置,各一行。
  • 需要感受检查的内容——如果结果取决于你无法从代码判断的感觉(如交叉淡入淡出、弹簧的弹跳、进入列表中 opacity/height 的平衡),请说明并指出检查点:以 2–5 倍持续时间播放或在 DevTools 动画检查器中播放,逐帧查看,在真实设备上测试手势,第二天以全新的视角再看一遍。

不要将其填充成报告。代码才是交付物。

语气

主观且简洁。当诚实的答案是“这不应该动画化”时,就给出这个答案——这个答案正是此技能存在的原因。当感觉确实无法从代码中确定时,就说明这一点,而不是猜测一个值。

Individual skills in this repo

This repo contains 3 individual skills — each has its own dedicated page.

RevanthThota55/FreeFrame-Studio

Keep web animations inside the frame budget — animate composite-only properties, keep motion off the main thread when the page is busy, and find the cause when an animation drops frames. Covers the layout/paint/composite pipeline, cheaper property swaps, CSS vs WAAPI vs requestAnimationFrame, Framer Motion's hardware-accelerated path, React re-rendering per frame, inherited CSS variable recalculation, blur cost, and when `will-change` actually helps. Use when an animation is janky, choppy, stutters, or drops frames; when choosing which property to animate; when deciding between CSS and JS animation on performance grounds; or when reaching for `will-change` or GPU layers. For choosing easing, duration, or whether to animate at all use animate; for reviewing motion as a whole use review-animations.

RevanthThota55/FreeFrame-Studio

Reverse-lookup glossary that turns a vague description of a web animation or motion effect into its exact term ("the bouncy thing when a popover opens" → Pop in; "the iOS rubber-band scroll" → Rubber-banding). Use when the user asks "what's it called when…", or describes a motion effect without knowing its name and wants the right word to prompt an AI or designer with. For naming an effect, not designing or building one.

RevanthThota55/FreeFrame-Studio

Apple's approach to interface design and fluid, physical motion, translated for the web. Use when building or reviewing gesture-driven UI, spring animations, drag/swipe/sheet interactions, momentum and interruptible transitions, translucent materials and depth, typography (optical sizing, tracking, leading), reduced-motion, or the design foundations (feedback, spatial consistency, restraint) behind Apple-style interfaces.

相关技能