mcpField
T
taste-gsap

taste-gsap

github.com/madebymustafa设计与 UI20050 次安装11 周前更新
代码仓库

关于 taste-gsap

taste-gsap 是面向编码 Agent 的 GSAP 动画开发技能,涵盖无障碍动效、滚动效果、性能与清理规范。

主要功能

  1. 01用 gsap.context 限定动画范围
  2. 02通过 matchMedia 控制动效
  3. 03限制并组织固定滚动区段
  4. 04优先使用变换和透明度动画
  5. 05提供静态与减少动效回退

适用场景

  1. 01规划 GSAP 滚动触发区段
  2. 02让动画遵循减少动效偏好
  3. 03检查固定与滚动联动效果
  4. 04保持动画布局性能稳定

安装

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

$npx skills add https://github.com/madebymustafa/design-taste --skill taste-gsap

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

详细介绍

taste-gsap

GSAP 是手术刀,不是亮片枪。一个干净的固定区段胜过九层视差效果,也更经得起代码审查。

1. 架构(不可妥协的基础)

  • 将每个页面的所有动画都封装在单个 gsap.context(() => { ... }, rootElement) 中——它会限定选择器的作用范围,并支持即时清理。
  • 所有内容都要通过 gsap.matchMedia() 控制:
    • (prefers-reduced-motion: no-preference)——所有动画都放在这里。减少动态效果的用户会看到完整的静态页面。
    • (min-width: 768px)——复杂效果(固定、滚动控制、逐字符拆分)仅限桌面端;小屏幕使用淡入效果或不添加动画。
  • matchMedia 回调会返回清理函数;在 SPA 中,卸载时调用 ctx.revert()。
  • 每个区段使用一个时间轴,并以区段命名;不要创建包含 40 个补间动画的巨型全局时间轴。
  • Lenis(免费版,不是 ScrollSmoother):new Lenis({ duration: ~1.1, anchors: true }),通过 lenis.on("scroll", ScrollTrigger.update) + gsap.ticker.add(t => lenis.raf(t * 1000)) + gsap.ticker.lagSmoothing(0) 将其接入 ScrollTrigger。预加载期间调用 lenis.stop(),完成后调用 lenis.start()。减少动态效果时绝不使用平滑滚动。

2. 固定与滚动控制规范(最容易出大问题的地方)

  • 每个页面最多固定两个区段。 每次固定都会占用滚动线程。两个是上限;通常一个就够。
  • 固定设置:pin: true, pinSpacing: true(默认值,保留它)、start: "top top"、end: "+=200%" 到 "+=300%"。结束距离越长,滚动控制越慢,在移动设备上也越容易卡顿。
  • 横向画廊(Awwwards 的标志性做法):固定区段,平移轨道(仅使用 x,绝不使用 left);设置 end: () => "+=" + (track.scrollWidth - innerWidth),以便在调整窗口大小时重新计算距离;使用 scrub: 1,仅限桌面端。必须保留原生 overflow-x + scroll-snap,作为无 JS 或减少动态效果时的回退方案。
  • 拖动轮播(Magma-school):Draggable.create(track, { type: "x", inertia: true, bounds: () => ({ minX: -(track.scrollWidth - wrap.offsetWidth), maxX: 0 }) })——将边界设置为函数,以便在调整窗口大小时重新计算。edgeResistance 约为 0.9;保留原生 overflow-x + snap 作为无 JS 回退方案,并添加光标或 UI 提示,说明条带可以拖动。
  • 复杂区段使用 scrub: 0.6–1;scrub: true 仅用于简单补间动画。没有平滑处理的滚动控制补间动画会与滚动产生冲突。
  • 绝不在另一个固定区段内固定;第一个区段的占位空间结束前,绝不开始第二个固定区段。字体或图片加载后调用 ScrollTrigger.refresh()(window.load + document.fonts.ready),否则所有内容都会错位。
  • 发布前,在 768px 宽度下测试固定效果——让移动端用户被困在固定区段中是 bug,不是功能(因此固定效果仅在 (min-width: 768px) 条件下启用)。
  • 对依赖刷新结果的触发器设置 invalidateOnRefresh: true,避免重新布局后位置逐渐偏移。

3. 动画内容(仅使用变换和不透明度)

  • 仅对 x、y、scale、rotation、opacity 添加动画——绝不对 top/left/width/height/margin/filter 添加动画(布局抖动会导致卡顿)。
  • 文本揭示:默认按行拆分(使用 overflow: hidden 包裹,并将 yPercent: 110 移至 0)。仅对主视觉标题按字符拆分,且只能在桌面端条件下使用。
  • 不要滥用 will-change——动画期间将其设置在动画元素的包装元素上,动画结束后移除(或交由 GSAP 管理)。每个 will-change 都是在承诺占用内存。
  • 保持真实的 60fps:不要在一帧内对 200 个元素应用交错动画,不要滚动控制 40 个 DOM 属性。使用 gsap.utils.toArray 批量处理并设置交错效果——一个补间动画,多个目标,开销低。

4. 揭示动画模式(专业人士的默认做法)

  • 起始状态应写在代码中,而不是 CSS 中: 元素在 CSS 中默认可见;在 matchMedia 条件门控内使用 gsap.from(...) 和 immediateRender: true,仅当 JS 和动态效果均启用时才隐藏元素。如果 GSAP 未能加载,页面仍然完整——这是安全保障。
  • 标准揭示动画:opacity: 0, y: 40, duration: 0.9, ease: "power3.out",触发位置为 top 82%,内容区块使用 once: true。
  • 主视觉开场:加载时播放 gsap.timeline()——元素之间错开 80–120ms,使用 ease: "expo.out" 或 power4.out,总时长少于 1.4s。页面是一个有开篇的故事,而不是幻灯片。
  • 数字递增动画:对代理对象执行补间(gsap.to(obj, { v: target })),在 onUpdate 中写入 el.textContent,snap 为可选项。触发器上使用 once: true。

5. 一整套禁忌(每项都不可接受)

  • 在没有平滑滚动层(Lenis)的情况下劫持滚轮滚动,之后又不进行测试——原生滚动是一项特性。
  • 内容尚未存在就触发动画(缺少 ScrollTrigger.refresh())。
  • 无限滚动字幕在减少动态效果偏好下仍未暂停——也要通过 CSS 中的 @media (prefers-reduced-motion: reduce) 停用,而不只是用 JS。
  • 任何自动播放内容:主视觉视频、手风琴,以及无需输入就会移动的轮播。Awwwards 式的自信,体现在片刻之间的静止。
  • 页面若要靠动画才能“惊艳”:如果静态截图很乏味,动画只是粉饰,而不是设计。

6. 检查清单(出现以下情况时,动画不予通过……)

  • 没有使用 gsap.context + matchMedia 进行条件门控(偏好减少动态效果的用户仍会看到动画)。
  • 固定区块超过两个,或在 768px 以下使用固定区块。
  • 使用了任何动画布局属性(top/left/width/height)。
  • 字体或图像加载后没有调用 ScrollTrigger.refresh()。
  • 在桌面端条件门控之外拆分逐字符动画。
  • 滚动字幕或自动播放没有减少动态效果的停用开关。
  • 静止画面(无 JS)不是完整、精美的页面。
  • 动画只是为了动画而存在——每个动作都必须服务于故事,否则就删掉。

评论

支持 Markdown