🛠️ 開発・MCP コミュニティ
gsap-react
GSAP integration with React including useGSAP hook, ref handling, cleanup patterns, and context management. Use when implementing GSAP animations in React components, handling component lifecycle, or building reusable animation hooks.
⚡ おすすめ: コマンド1行でインストール(60秒)
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o gsap-react.zip https://jpskill.com/download/23488.zip && unzip -o gsap-react.zip && rm gsap-react.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/23488.zip -OutFile "$d\gsap-react.zip"; Expand-Archive "$d\gsap-react.zip" -DestinationPath $d -Force; ri "$d\gsap-react.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
gsap-react.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
gsap-reactフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 1
📖 Claude が読む原文 SKILL.md(中身を展開)
この本文は AI(Claude)が読むための原文(英語または中国語)です。日本語訳は順次追加中。
GSAP React Integration
React-specific patterns for GSAP animations.
Quick Start
npm install gsap @gsap/react
import { useGSAP } from '@gsap/react';
import gsap from 'gsap';
function Component() {
const containerRef = useRef(null);
useGSAP(() => {
gsap.to('.box', { x: 200, duration: 1 });
}, { scope: containerRef });
return (
<div ref={containerRef}>
<div className="box">Animated</div>
</div>
);
}
useGSAP Hook
Basic Usage
import { useGSAP } from '@gsap/react';
import gsap from 'gsap';
function AnimatedComponent() {
const container = useRef(null);
useGSAP(() => {
// All GSAP animations here
gsap.from('.item', {
opacity: 0,
y: 50,
stagger: 0.1
});
}, { scope: container }); // Scope limits selector queries
return (
<div ref={container}>
<div className="item">Item 1</div>
<div className="item">Item 2</div>
<div className="item">Item 3</div>
</div>
);
}
With Dependencies
function AnimatedComponent({ isOpen }) {
const container = useRef(null);
useGSAP(() => {
gsap.to('.drawer', {
height: isOpen ? 'auto' : 0,
duration: 0.3
});
}, { scope: container, dependencies: [isOpen] });
return (
<div ref={container}>
<div className="drawer">Content</div>
</div>
);
}
Returning Context
function Component() {
const container = useRef(null);
const { context, contextSafe } = useGSAP(() => {
gsap.to('.box', { x: 200 });
}, { scope: container });
// Use contextSafe for event handlers
const handleClick = contextSafe(() => {
gsap.to('.box', { rotation: 360 });
});
return (
<div ref={container}>
<div className="box" onClick={handleClick}>Click me</div>
</div>
);
}
Ref Patterns
Single Element Ref
function SingleElement() {
const boxRef = useRef(null);
useGSAP(() => {
gsap.to(boxRef.current, {
x: 200,
rotation: 360,
duration: 1
});
});
return <div ref={boxRef}>Box</div>;
}
Multiple Element Refs
function MultipleElements() {
const itemsRef = useRef([]);
useGSAP(() => {
gsap.from(itemsRef.current, {
opacity: 0,
y: 30,
stagger: 0.1
});
});
return (
<div>
{[1, 2, 3].map((item, i) => (
<div
key={item}
ref={el => itemsRef.current[i] = el}
>
Item {item}
</div>
))}
</div>
);
}
Dynamic Refs
function DynamicList({ items }) {
const itemsRef = useRef(new Map());
useGSAP(() => {
gsap.from(Array.from(itemsRef.current.values()), {
opacity: 0,
y: 20,
stagger: 0.05
});
}, { dependencies: [items.length] });
return (
<div>
{items.map(item => (
<div
key={item.id}
ref={el => {
if (el) itemsRef.current.set(item.id, el);
else itemsRef.current.delete(item.id);
}}
>
{item.name}
</div>
))}
</div>
);
}
Context and Cleanup
Automatic Cleanup
// useGSAP automatically cleans up animations on unmount
function Component() {
useGSAP(() => {
// This timeline is automatically killed on unmount
gsap.timeline()
.to('.a', { x: 100 })
.to('.b', { x: 100 });
});
}
Manual Context (Without useGSAP)
import gsap from 'gsap';
function Component() {
useEffect(() => {
const ctx = gsap.context(() => {
gsap.to('.box', { x: 200 });
gsap.to('.circle', { rotation: 360 });
});
return () => ctx.revert(); // Cleanup
}, []);
}
Scoped Context
function Component() {
const containerRef = useRef(null);
useEffect(() => {
const ctx = gsap.context(() => {
// Selectors only query within containerRef
gsap.to('.item', { opacity: 1 });
}, containerRef);
return () => ctx.revert();
}, []);
}
Event Handlers
contextSafe for Events
function InteractiveComponent() {
const container = useRef(null);
const { contextSafe } = useGSAP(() => {
// Initial animation
gsap.set('.box', { scale: 1 });
}, { scope: container });
const handleMouseEnter = contextSafe(() => {
gsap.to('.box', { scale: 1.1, duration: 0.2 });
});
const handleMouseLeave = contextSafe(() => {
gsap.to('.box', { scale: 1, duration: 0.2 });
});
return (
<div ref={container}>
<div
className="box"
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
Hover me
</div>
</div>
);
}
useCallback Alternative
function Component() {
const boxRef = useRef(null);
const tweenRef = useRef(null);
const animateBox = useCallback(() => {
tweenRef.current?.kill();
tweenRef.current = gsap.to(boxRef.current, {
x: '+=50',
duration: 0.3
});
}, []);
useEffect(() => {
return () => tweenRef.current?.kill();
}, []);
return <div ref={boxRef} onClick={animateBox}>Click</div>;
}
Timeline Management
Timeline Ref Pattern
function TimelineComponent() {
const container = useRef(null);
const tl = useRef(null);
useGSAP(() => {
tl.current = gsap.timeline({ paused: true })
.to('.box', { x: 200 })
.to('.box', { y: 100 })
.to('.box', { rotation: 360 });
}, { scope: container });
const play = () => tl.current?.play();
const reverse = () => tl.current?.reverse();
const restart = () => tl.current?.restart();
return (
<div ref={container}>
<div className="box">Animated</div>
<button onClick={play}>Play</button>
<button onClick={reverse}>Reverse</button>
<button onClick={restart}>Restart</button>
</div>
);
}
Controlled Timeline
function ControlledAnimation({ progress }) {
const container = useRef(null);
const tl = useRef(null);
useGSAP(() => {
tl.current = gsap.timeline({ paused: true })
.to('.element', { x: 500 })
.to('.element', { y: 200 });
}, { scope: container });
// Update timeline progress when prop changes
useEffect(() => {
if (tl.current) {
tl.current.progress(progress);
}
}, [progress]);
return (
<div ref={container}>
<div className="element">Controlled</div>
</div>
);
}
ScrollTrigger in React
Basic ScrollTrigger
import { useGSAP } from '@gsap/react';
import gsap from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
gsap.registerPlugin(ScrollTrigger);
function ScrollComponent() {
const container = useRef(null);
useGSAP(() => {
gsap.from('.section', {
opacity: 0,
y: 100,
scrollTrigger: {
trigger: '.section',
start: 'top 80%',
toggleActions: 'play none none none'
}
});
}, { scope: container });
return (
<div ref={container}>
<div className="section">Scroll to reveal</div>
</div>
);
}
ScrollTrigger Cleanup
function ScrollComponent() {
const container = useRef(null);
useGSAP(() => {
const triggers = [];
gsap.utils.toArray('.item').forEach(item => {
const trigger = ScrollTrigger.create({
trigger: item,
start: 'top 80%',
onEnter: () => gsap.to(item, { opacity: 1 })
});
triggers.push(trigger);
});
// Return cleanup function
return () => triggers.forEach(t => t.kill());
}, { scope: container });
}
Custom Hooks
useAnimation Hook
function useAnimation(animation, deps = []) {
const elementRef = useRef(null);
const tweenRef = useRef(null);
useGSAP(() => {
if (elementRef.current) {
tweenRef.current = animation(elementRef.current);
}
return () => tweenRef.current?.kill();
}, { dependencies: deps });
return elementRef;
}
// Usage
function Component() {
const boxRef = useAnimation((el) =>
gsap.from(el, { opacity: 0, y: 50, duration: 0.5 })
);
return <div ref={boxRef}>Animated</div>;
}
useFadeIn Hook
function useFadeIn(options = {}) {
const { duration = 0.5, delay = 0, y = 30 } = options;
const ref = useRef(null);
useGSAP(() => {
gsap.from(ref.current, {
opacity: 0,
y,
duration,
delay,
ease: 'power2.out'
});
});
return ref;
}
// Usage
function Card() {
const cardRef = useFadeIn({ delay: 0.2 });
return <div ref={cardRef}>Card content</div>;
}
useHoverAnimation Hook
function useHoverAnimation(enterAnimation, leaveAnimation) {
const ref = useRef(null);
const { contextSafe } = useGSAP({ scope: ref });
const onEnter = contextSafe(() => enterAnimation(ref.current));
const onLeave = contextSafe(() => leaveAnimation(ref.current));
return { ref, onMouseEnter: onEnter, onMouseLeave: onLeave };
}
// Usage
function Button() {
const hoverProps = useHoverAnimation(
(el) => gsap.to(el, { scale: 1.05, duration: 0.2 }),
(el) => gsap.to(el, { scale: 1, duration: 0.2 })
);
return <button {...hoverProps}>Hover me</button>;
}
Temporal Collapse Patterns
Animated Countdown Digit
function CountdownDigit({ value, label }) {
const digitRef = useRef(null);
const prevValue = useRef(value);
useGSAP(() => {
if (prevValue.current !== value) {
gsap.timeline()
.to(digitRef.current, {
rotationX: -90,
opacity: 0,
duration: 0.25,
ease: 'power2.in'
})
.call(() => {
digitRef.current.textContent = value;
prevValue.current = value;
})
.fromTo(digitRef.current,
{ rotationX: 90, opacity: 0 },
{ rotationX: 0, opacity: 1, duration: 0.25, ease: 'power2.out' }
);
}
}, { dependencies: [value] });
return (
<div className="digit-container">
<span ref={digitRef} className="digit">{value}</span>
<span className="label">{label}</span>
</div>
);
}
Cosmic Pulse Effect
function CosmicPulse({ children, color = '#00F5FF' }) {
const containerRef = useRef(null);
useGSAP(() => {
gsap.to(containerRef.current, {
boxShadow: `0 0 30px ${color}, 0 0 60px ${color}`,
duration: 1,
repeat: -1,
yoyo: true,
ease: 'sine.inOut'
});
}, { scope: containerRef });
return <div ref={containerRef}>{children}</div>;
}
Performance Tips
// 1. Use will-change for heavy animations
gsap.set('.animated', { willChange: 'transform' });
// 2. Batch similar animations
useGSAP(() => {
gsap.to('.item', { opacity: 1, stagger: 0.1 }); // Single tween
// Not: items.forEach(item => gsap.to(item, ...)) // Multiple tweens
});
// 3. Use refs over selectors for frequently animated elements
const boxRef = useRef(null);
gsap.to(boxRef.current, { x: 100 }); // Faster
// 4. Kill animations on rapid state changes
const tweenRef = useRef(null);
useEffect(() => {
tweenRef.current?.kill();
tweenRef.current = gsap.to(...);
}, [dependency]);
Reference
- See
gsap-fundamentalsfor animation basics - See
gsap-sequencingfor timeline composition - See
gsap-scrolltriggerfor scroll-based animations