mcpField
G
gsap-scrolltrigger

gsap-scrolltrigger

github.com/bbeierle12デザイン・UI9606 回インストール1 日前に更新
リポジトリ

gsap-scrolltrigger について

gsap-scrolltrigger は、GSAP ScrollTrigger でスクロール連動アニメーションや操作を作る開発者向けのリファレンススキルです。トリガー設定やスクロール効果の実装例を扱います。

主な機能

  1. 01トリガー位置と動作の設定
  2. 02スクロールとアニメーション進行の連動
  3. 03セクション固定とスナップ位置の設定
  4. 04視差効果と横スクロールの作成
  5. 05スクロールアニメーションの一括処理
  6. 06コールバックによる状態追跡

活用シーン

  1. 01画面内に入る要素の表示演出
  2. 02固定セクションを使った横スクロールページ
  3. 03スクロール進捗バーや視差背景の追加

インストール

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

$npx skills add https://github.com/bbeierle12/skill-mcp-claude --skill gsap-scrolltrigger

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

同梱ファイル_meta.json

詳細

GSAP ScrollTrigger

スクロールに連動するアニメーションとインタラクションです。

クイックスタート

npm install gsap
import gsap from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';

gsap.registerPlugin(ScrollTrigger);

gsap.to('.box', {
  x: 500,
  scrollTrigger: {
    trigger: '.box',
    start: 'top center',
    end: 'bottom center',
    scrub: true
  }
});

基本概念

基本的な ScrollTrigger
gsap.to('.element', {
  x: 200,
  scrollTrigger: {
    trigger: '.element',  // Element that triggers the animation
    start: 'top center',  // When trigger hits viewport center
    end: 'bottom center', // When trigger leaves viewport center
    toggleActions: 'play pause resume reset'
  }
});
開始位置/終了位置
// Format: "trigger-position viewport-position"
start: 'top center'      // Trigger's top hits viewport center
start: 'top 80%'         // Trigger's top hits 80% down viewport
start: 'center center'   // Trigger's center hits viewport center
start: 'bottom top'      // Trigger's bottom hits viewport top
start: 'top top+=100'    // Trigger's top hits 100px below viewport top
位置の基準
値説明
top上端
center中央
bottom下端
80%上端から80%
+=100100ピクセル加算
-=5050ピクセル減算

スクラブアニメーション

基本的なスクラブ
// Animation progress tied to scroll position
gsap.to('.progress-bar', {
  scaleX: 1,
  scrollTrigger: {
    trigger: '.content',
    start: 'top top',
    end: 'bottom bottom',
    scrub: true  // Directly linked to scroll
  }
});
スムーズなスクラブ
gsap.to('.element', {
  x: 500,
  scrollTrigger: {
    trigger: '.section',
    scrub: 1,    // 1 second smoothing
    // scrub: 0.5  // 0.5 second smoothing
    // scrub: 2    // 2 second smoothing (laggy feel)
  }
});
タイムラインを使ったスクラブ
const tl = gsap.timeline({
  scrollTrigger: {
    trigger: '.container',
    start: 'top top',
    end: '+=3000',  // Scroll distance
    scrub: 1,
    pin: true
  }
});

tl.to('.step1', { opacity: 1 })
  .to('.step2', { opacity: 1 })
  .to('.step3', { opacity: 1 });

ピン留め

基本的なピン留め
ScrollTrigger.create({
  trigger: '.panel',
  start: 'top top',
  end: '+=500',      // Pin for 500px of scroll
  pin: true
});
アニメーションを使ったピン留め
gsap.to('.content', {
  x: '-200%',
  ease: 'none',
  scrollTrigger: {
    trigger: '.horizontal-section',
    start: 'top top',
    end: () => '+=' + document.querySelector('.horizontal-section').offsetWidth,
    pin: true,
    scrub: 1
  }
});
ピン留めの間隔
ScrollTrigger.create({
  trigger: '.section',
  pin: true,
  pinSpacing: true,   // Default: adds space for pinned duration
  // pinSpacing: false  // No extra space (content overlaps)
  // pinSpacing: '500px' // Custom spacing
});

切り替えアクション

アクションの構文
// Format: "onEnter onLeave onEnterBack onLeaveBack"
toggleActions: 'play pause resume reset'

// Common combinations:
toggleActions: 'play none none none'     // Play once
toggleActions: 'play reverse play reverse' // Toggle direction
toggleActions: 'restart none none none'  // Restart each time
toggleActions: 'play complete reverse reset'
アクションの値
アクション効果
play順方向に再生
pause一時停止
resume一時停止した位置から再開
reverse逆方向に再生
restart最初から再生
resetアニメーションなしで開始位置にリセット
complete終了位置にジャンプ
none何もしない

スナップ位置

基本的なスナップ
ScrollTrigger.create({
  trigger: '.sections',
  start: 'top top',
  end: 'bottom bottom',
  snap: 1 / 4  // Snap to quarters
});
ラベルへのスナップ
const tl = gsap.timeline({
  scrollTrigger: {
    trigger: '.container',
    scrub: 1,
    snap: {
      snapTo: 'labels',
      duration: 0.5,
      ease: 'power2.inOut'
    }
  }
});

tl.addLabel('intro')
  .to('.a', { opacity: 1 })
  .addLabel('middle')
  .to('.b', { opacity: 1 })
  .addLabel('end');
スナップの設定
snap: {
  snapTo: [0, 0.25, 0.5, 0.75, 1],  // Snap to specific points
  duration: { min: 0.2, max: 0.6 }, // Snap duration range
  delay: 0,                          // Delay before snap
  ease: 'power1.inOut',             // Snap easing
  directional: true                  // Snap in scroll direction
}

コールバック

ScrollTrigger のコールバック
ScrollTrigger.create({
  trigger: '.section',
  onEnter: () => console.log('Entered'),
  onLeave: () => console.log('Left'),
  onEnterBack: () => console.log('Entered from bottom'),
  onLeaveBack: () => console.log('Left going up'),
  onUpdate: (self) => console.log('Progress:', self.progress),
  onToggle: (self) => console.log('Active:', self.isActive),
  onRefresh: () => console.log('Refreshed')
});
進行度に基づく更新
ScrollTrigger.create({
  trigger: '.section',
  start: 'top bottom',
  end: 'bottom top',
  onUpdate: (self) => {
    // self.progress: 0 to 1
    // self.direction: 1 (down) or -1 (up)
    // self.velocity: scroll speed
    updateElement(self.progress);
  }
});

パララックス効果

基本的なパララックス
// Background moves slower than scroll
gsap.to('.background', {
  yPercent: -50,
  ease: 'none',
  scrollTrigger: {
    trigger: '.section',
    scrub: true
  }
});

// Foreground moves faster
gsap.to('.foreground', {
  yPercent: 50,
  ease: 'none',
  scrollTrigger: {
    trigger: '.section',
    scrub: true
  }
});
複数レイヤーのパララックス
const layers = [
  { selector: '.layer-1', speed: -20 },
  { selector: '.layer-2', speed: -40 },
  { selector: '.layer-3', speed: -60 },
  { selector: '.layer-4', speed: -80 }
];

layers.forEach(layer => {
  gsap.to(layer.selector, {
    yPercent: layer.speed,
    ease: 'none',
    scrollTrigger: {
      trigger: '.parallax-section',
      start: 'top bottom',
      end: 'bottom top',
      scrub: true
    }
  });
});

横スクロール

横スクロールセクション
const sections = gsap.utils.toArray('.panel');

gsap.to(sections, {
  xPercent: -100 * (sections.length - 1),
  ease: 'none',
  scrollTrigger: {
    trigger: '.horizontal-container',
    pin: true,
    scrub: 1,
    snap: 1 / (sections.length - 1),
    end: () => '+=' + document.querySelector('.horizontal-container').offsetWidth
  }
});

マーカー(開発時)

ScrollTrigger.create({
  trigger: '.section',
  start: 'top center',
  end: 'bottom center',
  markers: true,  // Show visual markers
  // markers: { startColor: 'green', endColor: 'red', fontSize: '12px' }
});

バッチアニメーション

スクロール時のスタッガー
ScrollTrigger.batch('.card', {
  onEnter: (elements) => {
    gsap.from(elements, {
      opacity: 0,
      y: 50,
      stagger: 0.1,
      duration: 0.5
    });
  },
  start: 'top 85%'
});
バッチの設定
ScrollTrigger.batch('.item', {
  interval: 0.1,  // Time between batches
  batchMax: 3,    // Max items per batch
  onEnter: batch => gsap.to(batch, { opacity: 1, y: 0, stagger: 0.1 }),
  onLeave: batch => gsap.to(batch, { opacity: 0, y: 20 }),
  onEnterBack: batch => gsap.to(batch, { opacity: 1, y: 0 }),
  onLeaveBack: batch => gsap.to(batch, { opacity: 0, y: -20 })
});

よく使われるパターン

スクロール時に表示
gsap.utils.toArray('.reveal').forEach(elem => {
  gsap.from(elem, {
    opacity: 0,
    y: 50,
    duration: 0.8,
    scrollTrigger: {
      trigger: elem,
      start: 'top 80%',
      toggleActions: 'play none none none'
    }
  });
});
進行状況インジケーター
gsap.to('.progress-bar', {
  scaleX: 1,
  transformOrigin: 'left center',
  ease: 'none',
  scrollTrigger: {
    trigger: 'body',
    start: 'top top',
    end: 'bottom bottom',
    scrub: 0.3
  }
});
スティッキーヘッダーの変形
ScrollTrigger.create({
  start: 'top -80',
  onUpdate: (self) => {
    if (self.direction === 1) {
      gsap.to('.header', { y: -80, duration: 0.3 });
    } else {
      gsap.to('.header', { y: 0, duration: 0.3 });
    }
  }
});

時間的な崩壊パターン

カウントダウンのスクロール表示
// Reveal countdown sections as user scrolls
const sections = ['days', 'hours', 'minutes', 'seconds'];

sections.forEach((section, i) => {
  gsap.from(`.countdown-${section}`, {
    opacity: 0,
    scale: 0.8,
    y: 50,
    duration: 0.8,
    ease: 'power3.out',
    scrollTrigger: {
      trigger: `.countdown-${section}`,
      start: 'top 80%',
      toggleActions: 'play none none none'
    }
  });
});
スクロールに基づく時間の遅延効果
gsap.timeline({
  scrollTrigger: {
    trigger: '.time-section',
    start: 'top center',
    end: 'bottom center',
    scrub: 1
  }
})
.to('.time-digit', {
  textShadow: '0 0 50px #00F5FF, 0 0 100px #00F5FF',
  scale: 1.1
})
.to('.particles', {
  opacity: 1,
  filter: 'blur(0px)'
}, '<');

パフォーマンスのヒント

// Disable on mobile if needed
ScrollTrigger.matchMedia({
  '(min-width: 768px)': function() {
    // Desktop animations
  },
  '(max-width: 767px)': function() {
    // Simpler mobile animations
  }
});

// Refresh on resize
ScrollTrigger.refresh();

// Kill all ScrollTriggers
ScrollTrigger.killAll();

// Kill specific trigger
const st = ScrollTrigger.create({ ... });
st.kill();

リファレンス

  • アニメーションの基本については gsap-fundamentals を参照してください
  • タイムラインの構成については gsap-sequencing を参照してください
  • ScrollTrigger の React 連携については gsap-react を参照してください

コメント