mcpField
G
gsap-web

gsap-web

github.com/iart-aiデザイン・UI632.6k 回インストール18 週間前に更新
リポジトリ

gsap-web について

gsap-webは、GSAPを使うウェブ開発者向けのアニメーションスキルです。タイムライン、スクロール演出、テキスト表示、レイアウト遷移に加え、単体HTMLの検証手順も扱います。

主な機能

  1. 01GSAPタイムラインと精密なシーケンス
  2. 02ScrollTriggerによるスクロール演出
  3. 03SplitTextによるテキスト表示
  4. 04Flipによるレイアウト遷移
  5. 05アニメーションのクリーンアップと性能指針
  6. 06単体HTMLのスクリーンショット検証

活用シーン

  1. 01スクロール連動のウェブ演出を作る
  2. 02複数要素のヒーロー演出を組む
  3. 03テキスト表示やレイアウト変更を作る
  4. 04スムーススクロールとScrollTriggerの同期を調べる

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/iart-ai/web-animation-skills --skill gsap-web

インストール後、Claude Code で/gsap-webを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

README.md
examples/
hero-timeline.js
standalone-template.html
references/
scrolltrigger-cookbook.md
scrolltrigger-lenis.md

詳細

Web 向け GSAP

GSAP(GreenSock Animation Platform)は、シーケンス化されたタイムライン、スクロール連動のストーリーテリング、テキストの表示、レイアウト遷移など、コードで制御する Web アニメーションの主力ツールです。GSAP 3.12 以降では、すべてのプラグイン(ScrollTrigger、SplitText、Flip、MotionPath、MorphSVG、Draggable、Observer)が、商用利用を含めて完全に無料です。

使用する場面

  • スクロール連動のストーリーテリング:ピン留めされたセクション、パララックス、進行状況のスクラブ、横スクロール
  • 正確な重なり具合を制御する、シーケンス化されたヒーローアニメーションや複雑な複数要素のタイムライン
  • 文字・単語・行に分割したテキストの表示(SplitText)
  • 要素の位置・サイズ・親要素が変化するレイアウト遷移(Flip)
  • 細かなタイミング制御、イージングの精度、または命令型のオーケストレーションが必要なあらゆるモーション

インストールと登録

import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { SplitText } from "gsap/SplitText";
import { Flip } from "gsap/Flip";

gsap.registerPlugin(ScrollTrigger, SplitText, Flip);

プラグインは使用前に必ず登録してください。登録しない場合、何も起こらずに処理が無視されます。バンドラーを使う場合は、アプリのエントリーポイントで一度だけ登録してください。

コアテクニック

まずタイムラインを使う

独立した複数のトゥイーンよりも、1つのタイムラインを優先してください。単一の再生ヘッド、相対的な配置、簡単な逆再生が可能になります。

const tl = gsap.timeline({ defaults: { ease: "power3.out", duration: 0.6 } });
tl.from(".title", { yPercent: 100, opacity: 0 })
  .from(".sub",   { y: 20, opacity: 0 }, "-=0.3")  // start 0.3s before prev ends
  .from(".cta",   { scale: 0.9, opacity: 0 }, "<"); // align to prev tween START

位置パラメーターの早見表:

  • "+=0.5" / "-=0.3" — タイムラインの終端を基準とする(間隔/重なり)
  • "<" — 直前のトゥイーンの開始位置、">" — 直前のトゥイーンの終了位置
  • "<0.2" — 直前のトゥイーンの開始から0.2秒後
  • "myLabel" — tl.addLabel("myLabel") で追加した名前付きラベルの位置

開始時のアニメーションには .from() を使います(指定した値から現在の CSS 値へアニメーションします)。終了時には .to() を使います。両端を明示する必要がある場合は .fromTo() を使います(再実行時にも最も確実です)。

gsap.to と set と quickTo
gsap.set(el, { autoAlpha: 0 });           // instant, no tween (autoAlpha = opacity + visibility)
const xTo = gsap.quickTo(el, "x", { duration: 0.4, ease: "power3" });
window.addEventListener("pointermove", (e) => xTo(e.clientX)); // fast repeated updates

autoAlpha は、生の opacity よりも推奨されます。値が0のときに visibility:hidden も切り替え、要素をヒットテストの対象から外すためです。

ScrollTrigger の基本
gsap.to(".panel", {
  xPercent: -100,
  ease: "none",
  scrollTrigger: {
    trigger: ".wrap",
    start: "top top",      // when trigger top hits viewport top
    end: "+=2000",         // 2000px of scroll distance
    pin: true,             // freeze .wrap while the tween plays
    scrub: 1,              // tie progress to scrollbar (1 = 1s catch-up smoothing)
    markers: true,         // dev-only visual markers — remove for prod
  },
});

主な仕様:

  • start/end には "triggerPos viewportPos"(例:"top center")または "+=px" を指定します。
  • scrub: true はアニメーションの進行度をスクロールに正確に同期させます。scrub: <number> は遅延を加えて滑らかにします。
  • toggleActions: "play pause resume reverse" は、スクラブを使わないトリガーにおける onEnter/onLeave/onEnterBack/onLeaveBack の動作を制御します。
  • スクロールに連動するトゥイーンでは、モーションがスクロールに線形に追従するよう ease: "none" を使います。
スムーススクロール(Lenis)+ ScrollTrigger

Lenis(または Locomotive)のスムーススクロールを ScrollTrigger と組み合わせると、両方を1つのループで動かさない限り同期がずれます。Lenis は独自の rAF でスクロールを滑らかにし、ScrollTrigger は GSAP のティッカーでスクロール位置を読み取ります。それぞれが独立して動くと、ScrollTrigger は古い位置を読み取ります。解決策は、GSAP のティッカーから Lenis を動かし、Lenis のスクロールごとに ScrollTrigger を更新することです。

import Lenis from "lenis";

const lenis = new Lenis({ duration: 1.2, smoothWheel: true });

lenis.on("scroll", ScrollTrigger.update);          // 1. update ScrollTrigger on every Lenis scroll
gsap.ticker.add((t) => lenis.raf(t * 1000));       // 2. one loop: ticker drives Lenis (seconds → ms)
gsap.ticker.lagSmoothing(0);                        // 3. stop GSAP catch-up jitter on heavy frames

重要:gsap.ticker が渡す時間の単位は秒ですが、lenis.raf() が必要とする単位はミリ秒です。1000を掛けてください。Lenis 用に独立した requestAnimationFrame(raf) ループも実行しないでください。二重に動作してしまいます。

よくある不具合:

  • 揺れ・カクつき — 残った requestAnimationFrame(raf) ループがティッカーと競合しているか、lagSmoothing(0) が設定されていません。余計なループを削除し、ラグスムージングを0に設定してください。
  • マーカーがトリガーからずれる — ScrollTrigger.update が lenis.on("scroll", …) に登録されていません。
  • ピン留めが機能しない — Lenis 使用時は、scrollerProxy を設定しないでください(ドキュメントをスクロールします)。Locomotive 使用時は、scrollerProxy と pinType を必ず連携させ、すべてのトリガーに scroller: を設定してください。
  • スクロールが止まる/方向が反転する — * 1000 の単位変換がないか、2つのループの実行順序が逆になっています。

SPA のアンマウント時には、gsap.ticker.remove(update) と lenis.destroy() でクリーンアップしてください。そうしないと、ナビゲーションのたびにループが積み重なります。prefers-reduced-motion に応じて制御し、該当する場合は Lenis をスキップしてネイティブスクロールを使ってください。Lenis と Locomotive の完全な連携方法、アンカーリンクのルーティング、data-lenis-prevent、React(useGSAP/useEffect)、および症状→原因の一覧表については、references/scrolltrigger-lenis.md を参照してください。

SplitText(テキストの表示)
const split = SplitText.create(".headline", { type: "lines, words", linesClass: "line" });
gsap.from(split.lines, { yPercent: 100, opacity: 0, stagger: 0.08, duration: 0.7, ease: "power4.out" });

注意点:

  • 行マスクで表示する場合は、行のラッパーに overflow: hidden を設定して、yPercent: 100 で確実に隠れるようにします。フォントの読み込み時やリサイズ時に再分割するには、autoSplit: true(GSAP 3.13+)を追加します。
  • 再分割する前、またはアンマウント時には split.revert() を呼び出し、元の DOM を復元してノードの重複を防ぎます。
  • 改行位置の誤りを防ぐため、必ず Web フォントの読み込み後に分割します(document.fonts.ready.then(...))。
Flip(レイアウト遷移)

Flip は状態を記録し、DOM を即座に変更した後、見た目の差分をアニメーション化します(FLIP テクニック)。グリッドとリストの切り替え、カードの展開、親要素の変更に最適です。

const state = Flip.getState(".item");   // 1. capture BEFORE
container.classList.toggle("grid");      // 2. mutate DOM/CSS (instant)
Flip.from(state, {                        // 3. animate the delta
  duration: 0.6, ease: "power2.inOut", stagger: 0.05,
  absolute: true,                         // take items out of flow during move (prevents reflow jitter)
});
イージング早見ガイド
  • power2/3.out — 登場時(速く始まり、落ち着きます)
  • power2.inOut — 画面上の 2 つの状態間を移動します
  • back.out(1.7) — オーバーシュート/ポップ(数値はオーバーシュート量)
  • elastic.out(1, 0.3) — 弾む動きです。使いすぎないようにします
  • none — スクロールに連動するトゥイーン
  • steps(n) — スプライト/段階的な動き
  • カスタム cubic-bezier 相当:CustomEase.create("x", "M0,0 C0.2,0 0,1 1,1")(CustomEase は無料です)

パフォーマンスとクリーンアップ

  • transform(x/y/xPercent/scale/rotation)と opacity のみをアニメーション化します。これらは GPU で合成され、レイアウト/ペイントを省略できます。top/left/width/height のアニメーション化は避けます。
  • 負荷の高い要素や固定表示する要素には will-change: transform を設定し、処理後に削除します。
  • 多数の類似したスクロール表示は、要素ごとにトリガーを設定する代わりに ScrollTrigger.batch() でまとめます。
  • ビューポートやコンテンツの変更後は、ScrollTrigger.refresh() を呼び出します。

SPA/フレームワークではクリーンアップが必須です。孤立したトリガーはメモリーリークや意図しないピン留めの原因になります。gsap.context()(または @gsap/react の useGSAP)を使用します。

useEffect(() => {
  const ctx = gsap.context(() => {
    // all gsap + ScrollTrigger code here
  }, rootRef);
  return () => ctx.revert(); // kills tweens, triggers, and reverts inline styles
}, []);

提出と検証(スタンドアロン HTML)

同梱ヘルパー(scripts/):scripts/seek-shot.sh anim.html 0 1.5 3 は ?t=N ハーネスで再生を停止し、各時点のスクリーンショットを撮影します。scripts/contact-sheet.sh sheet.png frame-*.png は画像を並べて、一目で確認できる一覧を作成します。scripts/README.md を参照してください。

自己完結型のアニメーション(ヒーロー、表示アニメーション、ループ、マイクロシーン)では、納品物はブラウザーで直接開ける 1 つの HTML ファイルです。ビルド手順、フレームワーク、レンダリングパイプラインは必要ありません。作業の規模に合った納品物を選びます。Web モーションには単一ファイルが適切です。1 つのファイルで済むときに、バンドラーを使う必要はありません。

出力要件:

  • .html ファイルを 1 つ用意します。GSAP とプラグインを CDN から読み込み、マークアップとアニメーションを 1 つのインライン <script> に含めます。
  • すべてのモーションを1 つのマスタータイムライン(const tl = gsap.timeline())にまとめます。これにより、シーク可能な単一の再生ヘッドを使えます。
  • 下記のシークハーネスを含め、任意の時点で停止して確認できるようにします。

シークハーネス — スクリーンショット用に正確な時点で停止します。 動画プレーヤーでフレームを固定するのと同様に、?t=N を指定するとマスタータイムラインが N 秒の位置にシークして一時停止し、決定的な静止フレームをスクリーンショットに収められます。

<script>
  // ... build your master timeline as `tl` ...
  const t = new URLSearchParams(location.search).get("t");
  if (t !== null) { tl.pause(); tl.seek(parseFloat(t)); }  // frozen at t seconds
  // no ?t → plays normally
  window.__ready = true;            // ready signal for headless wait
  console.log("duration", tl.duration());
</script>

検証手順 — レンダリング → 停止 → スクリーンショット → 確認:

  1. タイムラインの開始、中間、終了の 3 つの時点でファイルを開きます。 …/anim.html?t=0、?t=<dur/2>、?t=<dur> を指定します。終了時刻はコンソールで tl.duration() を確認します。
  2. 停止した各フレームのスクリーンショットを撮影します。
  3. 忠実度(要件に合っているか)とアーティファクト(テキストの切れ、キャンバス外の要素、フォント読み込み前の FOUC、継ぎ目でのカクつき)の両方を確認します。意図が明確で、完成度の高い出力にします。

ヘッドレススクリーンショットツールなら何でも使用できます。エージェントのブラウザーツール、または Playwright が使えます。

npx playwright screenshot --wait-for-timeout=500 "file://$PWD/anim.html?t=1.2" frame-mid.png

完了前に確認すること:

  1. ブラウザーでスタンドアロン実行できます。コンソールエラーや CDN の読み込み漏れがありません。
  2. すべてのアニメーションが 1 つのマスタータイムラインにあり、?t=N で正しく停止します。
  3. 開始/中間/終了のスクリーンショットを撮影し、要件に合っていて、アーティファクトがありません。
  4. prefers-reduced-motion に対応しています(タイムラインを簡略化するか、スキップします)。
  5. イージングに意図があり、空間的な動きに誤って linear を使っていません。

ハーネスを組み込んだ、実行可能な完全版テンプレートは examples/standalone-template.html にあります。

クイックリファレンス

目的API
重なりを持たせたシーケンスtl.from(...).from(..., "-=0.3")
スクロール中に固定scrollTrigger:{ pin:true, end:"+=N" }
スクロールに合わせてスクラブscrollTrigger:{ scrub:1, ease:"none" }
テキストの行を表示SplitText.create(el,{type:"lines"})
レイアウト変更をアニメーション化Flip.getState → 変更 → Flip.from
ポインターをすばやく追従gsap.quickTo(el,"x",{...})
すべてを停止ScrollTrigger.getAll().forEach(t=>t.kill())

リファレンスファイル

  • references/scrolltrigger-cookbook.md — ピン留め、スクラブ、横スクロール、スナップ、ScrollTrigger.batch() による表示、視差効果、ネストされたトリガー、SPA のクリーンアップパターンを、コード全体とともに説明します。
  • references/scrolltrigger-lenis.md — ScrollTrigger と Lenis/Locomotive のスムーススクロール同期を詳しく説明します。標準的な設定、scrollerProxy、アンカーリンク、動きを減らす設定、React(useGSAP/useEffect)、デバッグ用チェックリスト、症状→原因の一覧を含みます。
  • examples/hero-timeline.js — SplitText、段階的な表示、動きを減らす設定への対応を含む、実行可能なヒーロー表示タイムラインの完全な例です。
  • examples/standalone-template.html — 成果物のテンプレートです。自己完結型(CDN GSAP)、マスタータイムラインを1つ使用し、スクリーンショット検証用の ?t=N シーク機能と、動きを減らす設定への対応を備えています。

コメント