gsap-scrolltrigger
GSAP(GreenSock Animation Platform)およびScrollTriggerプラグインに関する包括的なスキルです。Webアニメーション、スクロール連動エフェクト、タイムライン・トゥイーンの作成、ピン留め・スクラブ・パララックス効果、またはDOM要素・SVG・Canvas・WebGL・Three.jsのアニメーション実装が必要な場面で使用します。GSAP・ScrollTrigger・スムーズアニメーション・スクロールエフェクト・アニメーションのシーケンシングに関するタスクでトリガーされます。
description の原文を見る
Comprehensive skill for GSAP (GreenSock Animation Platform) and ScrollTrigger plugin. Use this skill when creating web animations, scroll-driven experiences, timelines, tweens, scroll-triggered animations, pinning, scrubbing, parallax effects, or animating DOM elements, SVG, Canvas, WebGL, or Three.js. Triggers on tasks involving GSAP, ScrollTrigger, smooth animations, scroll effects, or animation sequencing.
SKILL.md 本文
GSAP & ScrollTrigger 開発
概要
GSAP (GreenSock Animation Platform) は、高性能でプロダクションレベルのアニメーションを作成するための業界標準的な JavaScript アニメーションライブラリです。ScrollTrigger は GSAP のスクロール駆動アニメーション用の強力なプラグインです。これらを組み合わせることで、シンプルな UI トランジションから複雑なスクロールベースのストーリーテリング体験まで、あらゆるものを実現できます。
コア概念
基本: トゥイーン
トゥイーンは、ポイント A からポイント B への単一のアニメーションです。
// TO アニメーション(現在の状態から)
gsap.to(".box", {
x: 200,
rotation: 360,
duration: 1,
ease: "power2.inOut"
});
// FROM アニメーション(現在の状態へ)
gsap.from(".box", {
opacity: 0,
y: -50,
duration: 0.8
});
// FROM-TO アニメーション(開始と終了の両方を定義)
gsap.fromTo(".box",
{ opacity: 0, scale: 0.5 }, // FROM
{ opacity: 1, scale: 1, duration: 1 } // TO
);
タイムライン: アニメーションのシーケンス化
タイムラインは複数のトゥイーンを順序通りに、または重複させてオーケストレーションします。
const tl = gsap.timeline();
// デフォルトでは順序通り
tl.to(".box1", { x: 100, duration: 1 })
.to(".box2", { y: 100, duration: 1 })
.to(".box3", { rotation: 360, duration: 1 });
// ラベルを使用して整理
tl.addLabel("start")
.to(".hero", { opacity: 1, duration: 1 })
.addLabel("reveal")
.to(".content", { y: 0, duration: 0.8 }, "reveal") // "reveal" ラベルで開始
.to(".cta", { scale: 1, duration: 0.5 }, "reveal+=0.5"); // "reveal" から 0.5 秒後
ポジションパラメータ(タイムラインタイミング)
タイムライン内でアニメーションがいつ開始されるかを制御します:
const tl = gsap.timeline();
// デフォルト: 順に実行
tl.to(".box1", { x: 100 })
.to(".box2", { x: 100 }); // box1 の終了後に開始
// 同時に開始
tl.to(".box1", { x: 100 })
.to(".box2", { y: 100 }, 0); // 0 秒で開始
// 相対的なポジショニング
tl.to(".box1", { x: 100, duration: 2 })
.to(".box2", { y: 100 }, "-=1"); // box1 の終了 1 秒前に開始
.to(".box3", { rotation: 360 }, "+=0.5"); // box2 の終了から 0.5 秒後に開始
// 特定の時間に開始
tl.to(".box1", { x: 100 }, 2.5); // 2.5 秒で開始
ScrollTrigger の基礎
基本的なスクロールアニメーション
gsap.registerPlugin(ScrollTrigger);
gsap.to(".box", {
x: 500,
scrollTrigger: {
trigger: ".box",
start: "top center", // トリガーの上部がビューポート中央に到達したとき
end: "bottom center",
markers: true, // 開発時のみ - 開始/終了位置を表示
scrub: true, // アニメーションをスクロールバーにリンク
toggleActions: "play none none reverse" // onEnter onLeave onEnterBack onLeaveBack
}
});
開始と終了の位置
形式: "[トリガー位置] [ビューポート位置]"
// よく使われるパターン
start: "top top" // トリガーの上部がビューポートの上部に到達
start: "top center" // トリガーの上部がビューポート中央に到達(デフォルト)
start: "top bottom" // トリガーの上部がビューポート下部に到達
start: "center center" // トリガー中央がビューポート中央に到達
// オフセット付き
start: "top top+=100" // ビューポート上部から 100px 下
start: "top 80%" // ビューポートの 80% 下
end: "+=500" // 開始位置から 500px 後
end: "bottom top" // トリガー下部がビューポート上部に到達
スクラビング(スクロール同期アニメーション)
// ブール値: スクロールバーへの直接リンク(即座)
scrub: true
// 数値: 秒単位のスムージング遅延
scrub: 1 // スクロールバーに「追いつく」のに 1 秒かかる
scrub: 0.5 // より高速でキツい感覚
トグルアクション
スクロールの 4 つのポイントでアニメーションを制御します:
toggleActions: "play pause resume reset"
// onEnter | onLeave | onEnterBack | onLeaveBack
// アクション: play, pause, resume, restart, reset, complete, reverse, none
よく使われるパターン:
toggleActions: "play none none none" // 入場時に一度再生
toggleActions: "play none none reverse" // 前方再生、戻る時に逆方向
toggleActions: "play complete reverse reset" // 完全制御
toggleActions: "restart pause resume pause" // 入場時に毎回再開始
よく使われるパターン
1. スクロール時にフェードイン
gsap.from(".fade-in", {
opacity: 0,
y: 50,
duration: 1,
scrollTrigger: {
trigger: ".fade-in",
start: "top 80%",
end: "top 50%",
scrub: 1,
once: true // 一度だけアニメーション
}
});
2. スクロール中に要素をピン留め
ScrollTrigger.create({
trigger: ".panel",
start: "top top",
end: "+=500", // 500px のスクロール中にピン留め
pin: true,
pinSpacing: true // スペーシングを追加(デフォルト true)
});
3. 水平スクロールセクション
const sections = gsap.utils.toArray(".panel");
gsap.to(sections, {
xPercent: -100 * (sections.length - 1),
ease: "none",
scrollTrigger: {
trigger: ".container",
pin: true,
scrub: 1,
end: () => "+=" + document.querySelector(".container").offsetWidth
}
});
4. パララックス効果
// より遅い動き(背景レイヤー)
gsap.to(".bg", {
y: 200,
ease: "none",
scrollTrigger: {
trigger: ".section",
start: "top bottom",
end: "bottom top",
scrub: true
}
});
// より速い動き(前景レイヤー)
gsap.to(".fg", {
y: -100,
ease: "none",
scrollTrigger: {
trigger: ".section",
start: "top bottom",
end: "bottom top",
scrub: true
}
});
5. スクロール駆動タイムライン
const tl = gsap.timeline({
scrollTrigger: {
trigger: ".container",
start: "top top",
end: "+=500",
scrub: 1,
pin: true,
snap: {
snapTo: "labels", // タイムラインラベルにスナップ
duration: { min: 0.2, max: 3 },
delay: 0.2,
ease: "power1.inOut"
}
}
});
tl.addLabel("start")
.from(".title", { scale: 0.3, rotation: 45, autoAlpha: 0 })
.addLabel("color")
.from(".box", { backgroundColor: "#28a92b" })
.addLabel("spin")
.to(".box", { rotation: 360 })
.addLabel("end");
6. バッチアニメーション(複数要素)
// 複数要素をループ
gsap.utils.toArray(".box").forEach((box, i) => {
gsap.from(box, {
y: 100,
opacity: 0,
scrollTrigger: {
trigger: box,
start: "top 80%",
end: "top 50%",
scrub: 1
}
});
});
// または ScrollTrigger.batch を使用
ScrollTrigger.batch(".box", {
onEnter: batch => gsap.to(batch, { opacity: 1, y: 0, stagger: 0.15 }),
onLeave: batch => gsap.set(batch, { opacity: 0 }),
start: "top 80%",
once: true
});
7. スタイル付きアニメーション
gsap.from(".item", {
y: 50,
opacity: 0,
duration: 0.8,
stagger: 0.1, // 各要素間 0.1 秒
scrollTrigger: {
trigger: ".grid",
start: "top 80%"
}
});
// 高度なスタイル
gsap.from(".item", {
scale: 0,
duration: 1,
stagger: {
each: 0.1,
from: "center", // "start", "center", "end", "edges", またはインデックス番号
grid: "auto", // グリッドレイアウト用
ease: "power2.inOut"
}
});
インテグレーションパターン
Three.js / WebGL を使用
import * as THREE from 'three';
import gsap from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
gsap.registerPlugin(ScrollTrigger);
// カメラをアニメーション
gsap.to(camera.position, {
x: 5,
y: 3,
z: 10,
scrollTrigger: {
trigger: "#section2",
start: "top top",
end: "bottom top",
scrub: 1,
onUpdate: () => camera.lookAt(scene.position)
}
});
// メッシュの回転をアニメーション
gsap.to(mesh.rotation, {
y: Math.PI * 2,
scrollTrigger: {
trigger: "#section3",
start: "top bottom",
end: "bottom top",
scrub: true
}
});
// マテリアルプロパティをアニメーション
gsap.to(material, {
opacity: 0,
scrollTrigger: {
trigger: "#section4",
start: "top center",
end: "center center",
scrub: 1
}
});
React(useGSAP フック)を使用
import { useRef } from 'react';
import { useGSAP } from '@gsap/react';
import gsap from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
gsap.registerPlugin(ScrollTrigger);
function Component() {
const container = useRef();
const box = useRef();
useGSAP(() => {
gsap.to(box.current, {
x: 200,
scrollTrigger: {
trigger: box.current,
start: "top center",
end: "bottom center",
scrub: true,
markers: true
}
});
}, { scope: container }); // クリーンアップ用のスコープ
return (
<div ref={container}>
<div ref={box} className="box">Animated Box</div>
</div>
);
}
React でタイムラインを共有
function App() {
const [tl, setTl] = useState();
useGSAP(() => {
const timeline = gsap.timeline();
setTl(timeline);
}, []);
return (
<div>
<Box timeline={tl} index={0} />
<Circle timeline={tl} index={1} />
</div>
);
}
function Box({ timeline, index }) {
const ref = useRef();
useGSAP(() => {
timeline && timeline.to(ref.current, { x: 100 }, index * 0.1);
}, [timeline, index]);
return <div ref={ref} className="box" />;
}
Locomotive Scroll インテグレーション
import LocomotiveScroll from 'locomotive-scroll';
const scroller = new LocomotiveScroll({
el: document.querySelector('[data-scroll-container]'),
smooth: true
});
ScrollTrigger.scrollerProxy("[data-scroll-container]", {
scrollTop(value) {
return arguments.length ? scroller.scrollTo(value, 0, 0) : scroller.scroll.instance.scroll.y;
},
getBoundingClientRect() {
return {top: 0, left: 0, width: window.innerWidth, height: window.innerHeight};
},
pinType: document.querySelector("[data-scroll-container]").style.transform ? "transform" : "fixed"
});
ScrollTrigger.addEventListener("refresh", () => scroller.update());
ScrollTrigger.refresh();
高度なテクニック
画像シーケンススクラビング
const canvas = document.querySelector("canvas");
const context = canvas.getContext("2d");
const images = [];
const imageCount = 147;
const currentFrame = { value: 0 };
for (let i = 0; i < imageCount; i++) {
const img = new Image();
img.src = `./frames/frame_${i.toString().padStart(4, '0')}.jpg`;
images.push(img);
}
images[0].onload = () => {
canvas.width = images[0].width;
canvas.height = images[0].height;
render();
};
function render() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(images[Math.floor(currentFrame.value)], 0, 0);
}
gsap.to(currentFrame, {
value: imageCount - 1,
snap: "value",
ease: "none",
scrollTrigger: {
trigger: canvas,
start: "top top",
end: "+=500%",
scrub: true,
pin: true
},
onUpdate: render
});
要素へのスムーススクロール
gsap.registerPlugin(ScrollToPlugin);
// 要素にスクロール
gsap.to(window, {
duration: 1,
scrollTo: "#section2",
ease: "power2.inOut"
});
// オフセット付き
gsap.to(window, {
duration: 1.5,
scrollTo: { y: "#section2", offsetY: 50 },
ease: "expo.inOut"
});
// 水平スクロール
gsap.to(".container", {
duration: 2,
scrollTo: { x: 1000, autoKill: true }
});
条件付きアニメーション(メディアクエリ)
ScrollTrigger.matchMedia({
// デスクトップ
"(min-width: 800px)": function() {
gsap.to(".box", {
x: 500,
scrollTrigger: {
trigger: ".box",
start: "top center",
end: "bottom top",
scrub: true
}
});
},
// モバイル
"(max-width: 799px)": function() {
gsap.to(".box", {
y: 200,
scrollTrigger: {
trigger: ".box",
start: "top 80%",
scrub: 1
}
});
}
});
パフォーマンス最適化のベストプラクティス
1. will-change CSS を使用
.animated-element {
will-change: transform, opacity;
}
2. リペイントを制限
// 良い: transform/opacity をアニメーション(GPU 加速)
gsap.to(".box", { x: 100, opacity: 0.5 });
// 避ける: レイアウトプロパティをアニメーション
// gsap.to(".box", { width: 500, height: 300 }); // リフロータリガー
3. ScrollTrigger を削除
// 個別トリガーを削除
const trigger = ScrollTrigger.create({ /* ... */ });
trigger.kill();
// すべてのトリガーを削除
ScrollTrigger.getAll().forEach(t => t.kill());
// React でのクリーンアップ
useGSAP(() => {
const tween = gsap.to(".box", { /* ... */ });
return () => {
tween.kill();
};
}, []);
4. リサイズをデバウンス
ScrollTrigger はこれを自動的に処理しますが、カスタムリサイズロジックの場合:
let resizeTimer;
window.addEventListener("resize", () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
ScrollTrigger.refresh();
}, 250);
});
5. invalidateOnRefresh を使用
リサイズ時に変更される動的値の場合:
gsap.to(".box", {
x: () => window.innerWidth / 2, // 動的値
scrollTrigger: {
trigger: ".box",
start: "top center",
invalidateOnRefresh: true // リサイズ時に x を再計算
}
});
よくある落とし穴
1. 同じ要素上の複数トゥイーン
// 問題: 2 番目のトゥイーンが最初と競合
gsap.to('h1', { x: 100, scrollTrigger: { /* ... */ } });
gsap.to('h1', { x: 200, scrollTrigger: { /* ... */ } }); // ジャンプ!
// ソリューション 1: fromTo を使用
gsap.fromTo('h1', { x: 100 }, { x: 200, scrollTrigger: { /* ... */ } });
// ソリューション 2: immediateRender: false を使用
gsap.to('h1', { x: 200, immediateRender: false, scrollTrigger: { /* ... */ } });
// ソリューション 3: ScrollTrigger をタイムラインに適用
const tl = gsap.timeline({ scrollTrigger: { /* ... */ } });
tl.to('h1', { x: 100 })
.to('h1', { x: 200 });
2. 複数要素のループを使用していない
// 誤り: すべてを同時にアニメーション
gsap.to('.section', {
y: -100,
scrollTrigger: { trigger: '.section', scrub: true }
});
// 正解: 個別トリガー用のループ
gsap.utils.toArray('.section').forEach(section => {
gsap.to(section, {
y: -100,
scrollTrigger: { trigger: section, scrub: true }
});
});
3. プラグインの登録を忘れる
import gsap from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
import { ScrollToPlugin } from 'gsap/ScrollToPlugin';
gsap.registerPlugin(ScrollTrigger, ScrollToPlugin); // 登録必須!
4. タイムラインのネストされた ScrollTrigger
// 誤り: タイムライン内の個別トゥイーン上の ScrollTrigger
const tl = gsap.timeline();
tl.to('.box1', { x: 100, scrollTrigger: { /* ... */ } }) // これはしない!
.to('.box2', { y: 100, scrollTrigger: { /* ... */ } });
// 正解: 親タイムラインの ScrollTrigger
const tl = gsap.timeline({
scrollTrigger: { /* ... */ }
});
tl.to('.box1', { x: 100 })
.to('.box2', { y: 100 });
イージングリファレンス
// パワーイージング(最も一般的)
ease: "power1.out" // 微妙な減速
ease: "power2.inOut" // スムーズな加速/減速
ease: "power3.in" // 強い加速
ease: "power4.out" // 非常に強い減速
// 特別なイージング
ease: "elastic.out" // バウンシーなオーバーシュート
ease: "back.out" // わずかなオーバーシュート
ease: "bounce.out" // バウンス効果
ease: "circ.inOut" // 円形の動き感
ease: "expo.inOut" // 指数関数(ドラマティック)
// リニア(スクラブされたスクロールアニメーション用)
ease: "none"
ScrollTrigger メソッド
// すべての ScrollTrigger をリフレッシュ(DOM 変更後)
ScrollTrigger.refresh();
// すべての ScrollTrigger を取得
const triggers = ScrollTrigger.getAll();
// ID で特定のトリガーを取得
const st = ScrollTrigger.getById("myTrigger");
// トリガーを削除
st.kill();
// トリガーを更新
st.scroll(500); // プログラムでスクロール位置を設定
st.enable();
st.disable();
// グローバル ScrollTrigger 設定
ScrollTrigger.config({
limitCallbacks: true, // パフォーマンス改善
syncInterval: 15 // スクロール確認をスロットル( ms)
});
// デバッグモード
ScrollTrigger.defaults({
markers: true // すべてのトリガーにマーカーを表示
});
リソース
このスキルにはバンドルされたリソースが含まれています:
references/
api_reference.md: クイック API リファレンス(トゥイーンメソッド、タイムラインメソッド、ScrollTrigger プロパティ)easing_guide.md: 使用例付きビジュアルイージングリファレンスcommon_patterns.md: よく使われるシナリオ用のコピペパターン
scripts/
generate_animation.py: GSAP ボイラープレートコード生成timeline_builder.py: インタラクティブタイムラインシーケンスビルダー
assets/
starter_scroll/: 完全なスクロール駆動サイトテンプレートeasings/: イージングビジュアライゼーション HTML ツールexamples/: 実世界の ScrollTrigger 例
このスキルを使用するタイミング
以下の場合にこのスキルを使用します:
- スムーズな Web アニメーションを作成するとき
- スクロール駆動体験を構築するとき
- パララックス効果を実装するとき
- 複雑なアニメーションをシーケンス化するとき
- DOM、SVG、Canvas、WebGL をアニメーションするとき
- Three.js または React とアニメーションを統合するとき
- スクロールテリングウェブサイトを構築するとき
- インタラクティブな UI トランジションを作成するとき
Three.js 固有のアニメーションについては、threejs-webgl スキルも参照してください。 組み込みアニメーション付きの React コンポーネントについては、motion-framer スキルを参照してください。
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- freshtechbro
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/freshtechbro/claudedesignskills / ライセンス: MIT
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。