
最近 GitHub 上冒出来一个叫 oil-motion 的仓库,定位很直白:给 AI Agent 用的交互动画 Skill。它不帮你写业务组件,而是管「动作怎么设计、连续帧怎么出、最后怎么接到滚动 / 鼠标 / 拖动 / 触摸 / 设备方向」。
我试着想了一下自己上周踩过的坑——产品要一个「滚动时产品图跟着转、松手回弹」的 hero。以前我会打开 Motion(前身 framer-motion)、手写 useScroll + useTransform,调阻尼到半夜。现在的路径变成:把约束丢给 Agent,让它先吐出可编辑的动画资产,再由人把边界条件和可访问性钉死。
oil-motion 这类项目,真正有意思的不是「AI 会做动画了」,而是动画流水线终于能被 skill 化。
前端动画为什么总在返工
交互动画难,不是库难用,是约束散落各处:
- 设计稿给的是「感觉」,没有帧率、没有 reduced-motion 策略
- 工程师用 CSS transition 凑合,产品说不够「有弹性」
- 换成 JS 时间轴后,滚动容器一嵌套,进度全错
- 移动端触摸和桌面 hover 各写一套,最后只剩一套能跑
CSS 滚动驱动动画(animation-timeline: scroll())能解决一部分「进度绑定滚动」的问题,我之前也写过。但它管不了「生成一套连续、可交互的 motion 语言」。oil-motion 站的位置更上游:从意图到资产,再到绑定事件源。
一条更像生产线的链路
我理想中的工作流大概是这样:
- 约束先写清楚:时长上限、是否可打断、
prefers-reduced-motion时降级成淡入、主要驱动源(scroll / pointer / drag) - Agent 出 motion spec:关键帧、缓动曲线、循环与否、命中区域
- 生成连续帧或矢量关键路径:不是一张海报,是可播的序列
- 接到真实 DOM:用 CSS scroll-driven、WAAPI,或 Motion 的 scroll/drag API
- 人做门禁:掉帧、布局抖动、键盘用户是否被动画挡路
// 伪代码:把「滚动进度 0→1」映射到已生成的序列帧
const frames = await loadMotionPack('/motion/hero-spin')
const scroller = document.querySelector('#hero')
scroller.animate(
frames.map((src, i) => ({
backgroundImage: `url(${src})`,
offset: i / (frames.length - 1),
})),
{
timeline: new ScrollTimeline({ source: scroller, axis: 'block' }),
fill: 'both',
}
)
真正落地时你会发现:Agent 给的缓动往往「好看但不省电」。手机上 60 帧位图序列能把发热打满。这时要么改成 2–3 个关键状态 + CSS transform,要么用 Lottie/Rive 一类矢量时间轴,别死磕全帧 PNG。
和现有栈怎么相处
| 手段 | 适合 | 别硬上 |
|---|---|---|
CSS transition / @keyframes |
微交互、状态切换 | 复杂手势、多轴联动 |
| CSS scroll-driven | 进度条、视差、章节指示 | 需要程序分支的剧情动画 |
| Motion / GSAP | 手势、编排、共享布局 | 只为淡入淡出一个依赖 |
| oil-motion 类 Skill | 从需求快速出可迭代资产 | 无门禁地直接合进生产 |
我的经验是:Agent 负责发散和草稿,仓库里的 design tokens 和 motion 规范负责收敛。比如统一 duration-fast = 150ms、ease-emphasized,Agent 输出必须映射到这些 token,否则 review 直接打回。
图:滚动与指针驱动的动画,本质是把输入信号变成可打断的时间轴

接入时我会卡的三道门
性能。 打开 Performance 面板看 Main thread。动画如果触发 layout(改 width/top),滚动时必卡。能 transform / opacity 解决的,别动布局属性。序列帧优先放在 content-visibility 友好的容器里,离屏就停。
可访问性。 prefers-reduced-motion: reduce 时给静态首帧或短淡入。焦点态不要被装饰动画盖住。拖动类交互要有键盘等价操作,或者明确宣告「仅指针可用」并提供替代信息架构。
可维护性。 把 motion pack 当依赖版本化:hero-spin@1.2,changelog 写清改了哪条曲线。否则三个月后没人敢动 hero,因为「只有当初那个 Agent 会话知道参数」。
我现在的默认策略
落地页 hero、活动页、品牌叙事:可以让 Skill 先出两版,人挑选再收束。
后台表格、表单、设置页:少用叙事动画。状态反馈用 150ms 内的 opacity/transform 就够,省下来的时间去写错误文案。
如果团队已经有 Motion 组件库,不要为了追热榜再引入第二条时间轴引擎。让 Agent 的输出编译到你现有的 API,比再学一套运行时划算。
和 CSS 滚动驱动、View Transition 怎么分工
三者别抢活:
- CSS scroll-driven:章节进度、阅读百分比、轻微视差。声明式,主线程压力小,适合「跟滚动走」的装饰。
- View Transition:路由级共享元素、列表到详情。浏览器管快照,你管
view-transition-name别冲突。 - Agent motion pack:品牌向的多关键帧、需要设计反复改的叙事段。出资产后仍建议落到 CSS/WAAPI/Motion,而不是在生产环境跑一套私有播放器。
我在落地页上的习惯是:首屏叙事用 pack 或 Motion;往下滚动的章节指示全改 scroll-driven;详情页英雄图切列表用 View Transition。三套同时上可以,但要在文档里画一张「谁负责哪一段」,否则半年后全员不敢删。
还有个很土的检查:开低端 Android 真机,开电池百分比录 30 秒滚动。掉 2% 以上,先砍序列帧,再谈「高级感」。
小结
oil-motion 这类项目提醒我:2026 年的前端动效,瓶颈不在「会不会写 animate」,而在意图 → 资产 → 绑定 → 门禁有没有闭环。CSS 滚动驱动和 View Transition 解决「浏览器原生进度」;Agent Skill 解决「从一句话到可点可滚的草稿」。人的工作变成定约束、做取舍、挡掉会发热和伤无的版本。
下次产品说「要有一点高级感」时,先问三个问题:驱动源是什么、能不能被用户打断、减动效模式怎么办。答不清之前,别急着生成 120 帧。


