mcpField
G
gsap-frameworks

gsap-frameworks

github.com/greensockデザイン・UI17.4k64.1k 回インストール27 週間前に更新
リポジトリ

gsap-frameworks について

gsap-frameworksは、Vue、Nuxt、Svelteなどライフサイクルを持つフレームワークでGSAPを書く、またはレビューする開発者向けのスキルです。セレクターのスコープ指定と破棄時のクリーンアップを扱い、VueとNuxtの実行可能な例も含みます。

主な機能

  1. 01DOMのマウント後にアニメーションを作成
  2. 02gsap.contextによるセレクター範囲の指定
  3. 03破棄時にアニメーションとScrollTriggerを元に戻す
  4. 04VueとNuxtのサンプルプロジェクト
  5. 05Nuxtプラグインの遅延読み込み

活用シーン

  1. 01VueコンポーネントにGSAPアニメーションを追加
  2. 02Svelteコンポーネントのアニメーションをクリーンアップ
  3. 03セレクターが他のコンポーネントに影響する問題の防止
  4. 04NuxtでGSAPプラグインを遅延読み込み

インストール

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

$npx skills add https://github.com/greensock/gsap-skills --skill gsap-frameworks

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

詳細

Vue、Svelte、その他のフレームワークでの GSAP

このスキルを使用する場合

ライフサイクル(マウント/アンマウント)を使用する Vue(または Nuxt)、Svelte(または SvelteKit)、その他のコンポーネントフレームワークで GSAP コードを記述またはレビューする場合に適用します。React の場合は、gsap-react(useGSAP フック、gsap.context())を使用してください。

関連スキル: トゥイーンとタイムラインには gsap-core と gsap-timeline を使用してください。スクロールベースのアニメーションには gsap-scrolltrigger を使用してください。React には gsap-react を使用してください。

原則(すべてのフレームワーク)

  • コンポーネントの DOM が利用可能になった後(例:onMounted、onMount)に、トゥイーンと ScrollTrigger を作成します。
  • 切り離されたノードで実行されたり、メモリリークが発生したりしないよう、アンマウント(または同等の処理)時のクリーンアップで、これらを停止または元に戻します。
  • セレクターの対象をコンポーネントのルートに限定し、.box などがページのほかの部分ではなく、そのコンポーネント内の要素だけに一致するようにします。

Vue 3(Composition API)

これらのパターンを実演する、実行可能な Vite + Vue 3 プロジェクトについては、examples/vue/ を参照してください。

onMounted を使用して、コンポーネントが DOM に追加された後に GSAP を実行します。クリーンアップには onUnmounted を使用します。

import { onMounted, onUnmounted, ref } from "vue";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger); // once per app, e.g. in main.js

export default {
  setup() {
    const container = ref(null);
    let ctx;

    onMounted(() => {
      if (!container.value) return;
      ctx = gsap.context(() => {
        gsap.to(".box", { x: 100, duration: 0.6 });
        gsap.from(".item", { autoAlpha: 0, y: 20, stagger: 0.1 });
      }, container.value);
    });

    onUnmounted(() => {
      ctx?.revert();
    });

    return { container };
  },
};
  • ✅ gsap.context(scope) — コンテナの ref(例:container.value)を第 2 引数として渡すと、.item などのセレクターがそのルート内に限定されます。コールバック内で作成されたすべてのアニメーションと ScrollTrigger が記録され、ctx.revert() の呼び出し時に元に戻されます。
  • ✅ onUnmounted — トゥイーンと ScrollTrigger を停止し、インラインスタイルを元に戻すため、必ず ctx.revert() を呼び出します。

Vue 3(script setup)

<script setup> と ref を使う場合も同じ考え方です。

<script setup>
import { onMounted, onUnmounted, ref } from "vue";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";

const container = ref(null);
let ctx;

onMounted(() => {
  if (!container.value) return;
  ctx = gsap.context(() => {
    gsap.to(".box", { x: 100 });
    gsap.from(".item", { autoAlpha: 0, stagger: 0.1 });
  }, container.value);
});

onUnmounted(() => {
  ctx?.revert();
});
</script>

<template>
  <div ref="container">
    <div class="box">Box</div>
    <div class="item">Item</div>
  </div>
</template>

Nuxt 4

プラグインの登録、遅延読み込み、SSR に安全なパターンを含む実行可能な Nuxt 4 プロジェクトについては、examples/nuxt/ を参照してください。

再利用可能な composable を使って GSAP プラグインを登録し、アプリケーション内であまり使われないプラグインも遅延読み込みします。

// composables/useGSAP.ts
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";

const PLUGINS = [
  "CSSRulePlugin",
  "CustomBounce",
  "CustomEase",
  "CustomWiggle",
  "Draggable",
  "DrawSVGPlugin",
  "EaselPlugin",
  "EasePack",
  "Flip",
  "GSDevTools",
  "InertiaPlugin",
  "MorphSVGPlugin",
  "MotionPathHelper",
  "MotionPathPlugin",
  "Observer",
  "Physics2DPlugin",
  "PhysicsPropsPlugin",
  "PixiPlugin",
  "ScrambleTextPlugin",
  "ScrollSmoother",
  "ScrollToPlugin",
  "ScrollTrigger",
  "SplitText",
  "TextPlugin",
] as const;

type Plugins = (typeof PLUGINS)[number];

// In order to dynamically load all the GSAP plugins
const pluginMap = {
  CustomEase: () => import("gsap/CustomEase"),
  Draggable: () => import("gsap/Draggable"),
  CSSRulePlugin: () => import("gsap/CSSRulePlugin"),
  EaselPlugin: () => import("gsap/EaselPlugin"),
  EasePack: () => import("gsap/EasePack"),
  Flip: () => import("gsap/Flip"),
  MotionPathPlugin: () => import("gsap/MotionPathPlugin"),
  Observer: () => import("gsap/Observer"),
  PixiPlugin: () => import("gsap/PixiPlugin"),
  ScrollToPlugin: () => import("gsap/ScrollToPlugin"),
  ScrollTrigger: () => import("gsap/ScrollTrigger"),
  TextPlugin: () => import("gsap/TextPlugin"),
  DrawSVGPlugin: () => import("gsap/DrawSVGPlugin"),
  Physics2DPlugin: () => import("gsap/Physics2DPlugin"),
  PhysicsPropsPlugin: () => import("gsap/PhysicsPropsPlugin"),
  ScrambleTextPlugin: () => import("gsap/ScrambleTextPlugin"),
  CustomBounce: () => import("gsap/CustomBounce"),
  CustomWiggle: () => import("gsap/CustomWiggle"),
  GSDevTools: () => import("gsap/GSDevTools"),
  InertiaPlugin: () => import("gsap/InertiaPlugin"),
  MorphSVGPlugin: () => import("gsap/MorphSVGPlugin"),
  MotionPathHelper: () => import("gsap/MotionPathHelper"),
  ScrollSmoother: () => import("gsap/ScrollSmoother"),
  SplitText: () => import("gsap/SplitText"),
} as const;

type PluginMap = typeof pluginMap;
type Plugins = keyof PluginMap;

// Resolves the module type for a given key, then picks the named export matching the key
// this allows to have the type definitions for autocomplete in your code editor
type PluginModule<K extends Plugins> = Awaited<ReturnType<PluginMap[K]>>;
type PluginExport<K extends Plugins> = PluginModule<K>[K & keyof PluginModule<K>];

export default function () {
  // Register all the GSAP Plugins you want at this point
  gsap.registerPlugin(ScrollTrigger);

  /*
    If you want to lazy load some of the plugins that are
    not widely used in your app (for example in just a couple
    of components or a single route), you can use this method
  */
  async function lazyLoadPlugin<K extends Plugins>(plugin: K): Promise<PluginExport<K>> {
    const loader = pluginMap[plugin];
    const m = await loader();
    const p = (m as any)[plugin];
    gsap.registerPlugin(p);
    return p;
  }

  return {
    gsap,
    ScrollTrigger,
    lazyLoadPlugin,
  };
}

コンポーネントでは useGSAP() を使ってアクセスします。

const { gsap, ScrollTrigger, lazyLoadPlugin } = useGSAP();
  • ✅ useGSAP() を使うと、gsap インスタンスと遅延読み込みメソッドに型付きでアクセスできます。
  • ✅ アプリで広く使われていないプラグイン(SplitText、MorphSVG など)は遅延読み込みし、初期バンドルサイズを削減します。
  • ✅ Vue 3 と同様に、コンポーネント内で gsap.context(scope) と onUnmounted → ctx.revert() を使用します。

Svelte

DOM の準備ができた後に GSAP を実行するには onMount を使用します。元に戻すには、onMount が返すクリーンアップ関数を使用するか、コンテキストを追跡してリアクティブブロック/コンポーネントの破棄時にクリーンアップします。Svelte 5 ではライフサイクルが異なりますが、基本原則は同じです。「マウント」時に作成し、「破棄」時に元に戻します。

<script>
  import { onMount } from "svelte";
  import { gsap } from "gsap";
  import { ScrollTrigger } from "gsap/ScrollTrigger";

  let container;

  onMount(() => {
    if (!container) return;
    const ctx = gsap.context(() => {
      gsap.to(".box", { x: 100 });
      gsap.from(".item", { autoAlpha: 0, stagger: 0.1 });
    }, container);
    return () => ctx.revert();
  });
</script>

<div bind:this={container}>
  <div class="box">Box</div>
  <div class="item">Item</div>
</div>
  • ✅ bind:this={container} — ルート要素への参照を取得し、gsap.context(scope) に渡せるようにします。
  • ✅ return () => ctx.revert() — Svelte の onMount はクリーンアップ関数を返せます。コンポーネントの破棄時にクリーンアップが実行されるよう、そこで ctx.revert() を呼び出します。

セレクターのスコープ設定

現在のコンポーネントの外側の要素に一致する可能性があるグローバルセレクターは使用しないでください。コールバック内で実行されるセレクターの対象をそのサブツリー内に限定するため、必ず gsap.context(callback, scope) の第 2 引数として scope(コンテナ要素または ref)を渡します。

  • ✅ gsap.context(() => { gsap.to(".box", ...) }, containerRef) — .box は containerRef 内だけで検索されます。
  • ❌ コンポーネント内でコンテキストのスコープなしに gsap.to(".box", ...) を実行すると、ほかのインスタンスやページの残りの部分に影響する可能性があります。

ScrollTrigger のクリーンアップ

トゥイーン/タイムラインの scrollTrigger 設定、または ScrollTrigger.create() を使用すると、ScrollTrigger インスタンスが作成されます。これらは gsap.context() に含まれ、ctx.revert() を呼び出すと元に戻されます。そのため、次のようにします。

  • トゥイーンに使用するものと同じ gsap.context() コールバック内で ScrollTrigger を作成します。
  • トリガー位置に影響するレイアウト変更(例:データ読み込み後)の後に ScrollTrigger.refresh() を呼び出します。Vue/Svelte では、多くの場合 DOM の更新後(例:Vue の nextTick、Svelte の tick、または非同期コンテンツの読み込み後)に実行します。

作成するタイミングと破棄するタイミング

ライフサイクル操作
マウント時gsap.context(scope) 内でトゥイーンと ScrollTrigger を作成します。
アンマウント/破棄時ctx.revert() を呼び出すと、そのコンテキスト内のすべてのアニメーションと ScrollTrigger が破棄され、インラインスタイルが元に戻ります。

ルート要素が存在する前に実行されるコンポーネントのセットアップや同期的なトップレベルスクリプトでは、GSAP アニメーションを作成しないでください。コンテナの ref が DOM に配置されるまで、onMounted / onMount(または同等の処理)を待ってください。

避けること

  • ❌ コンポーネントのマウント前にトゥイーンや ScrollTrigger を作成しないでください(例:onMounted を使わずに setup 内で作成する)。DOM ノードがまだ存在しない可能性があります。
  • ❌ scope を指定せずにセレクター文字列を使用しないでください(2 つ目の引数としてコンテナを gsap.context() に渡してください)。そうしないと、セレクターがコンポーネント外の要素にも一致する可能性があります。
  • ❌ クリーンアップを省略しないでください。コンポーネントの破棄時にアニメーションと ScrollTrigger が破棄されるよう、onUnmounted / onMount の return 内で必ず ctx.revert() を呼び出してください。
  • ❌ レンダリングのたびに実行されるコンポーネントの本体内でプラグインを登録しないでください(問題はありませんが、無駄が生じます)。アプリケーションレベルで一度だけ登録してください。
詳細を見る
  • React 固有のパターン(useGSAP、contextSafe)については、gsap-react スキルを参照してください。

コメント