Unofficial Svelte integration for GSAP (GreenSock Animation Platform) with automatic cleanup, full TypeScript support, and seamless ScrollTrigger integration.
✨ Svelte Actions - Idiomatic Svelte integration using actions
🧹 Automatic Cleanup - No memory leaks, animations cleaned up on component unmount
📘 TypeScript First - Full type definitions included
🎯 ScrollTrigger Ready - Built-in ScrollTrigger support
⚡ Performance - Leverages GSAP's industry-leading animation performance
🎨 Convenience Actions - Pre-built actions for common animations
🔄 SSR Safe - Works with SvelteKit out of the box
bun add -D @gsap/svelte gsap
npm install @gsap/svelte gsap
pnpm add @gsap/svelte gsap
yarn add @gsap/svelte gsap
<script>
import { gsapAnimate } from '@gsap/svelte';
</script>
<div use:gsapAnimate={{
type: 'from',
opacity: 0,
y: 50,
duration: 1,
ease: 'power2.out'
}}>
I fade and slide in!
</div>
<script>
import { GsapAnimate } from '@gsap/svelte';
</script>
<GsapAnimate type="from" opacity={0} y={50} duration={1} ease="power2.out">
<div>I fade and slide in!</div>
</GsapAnimate>
All actions have component wrappers for a more declarative API:
<script>
import { GsapAnimate, GsapFade, GsapSlide, GsapScale } from '@gsap/svelte';
</script>
<!-- Animate component -->
<GsapAnimate type="from" opacity={0} x={-100} duration={1}>
<div>Animated content</div>
</GsapAnimate>
<!-- Fade component -->
<GsapFade duration={1.5} delay={0.3}>
<span>Fades in</span>
</GsapFade>
<!-- Slide component -->
<GsapSlide direction="left" distance={100}>
<section>Slides from left</section>
</GsapSlide>
<!-- Scale component -->
<GsapScale from={0} duration={0.8}>
<article>Scales up</article>
</GsapScale>
All components support an element prop to change the wrapper element:
<GsapAnimate element="section" type="from" opacity={0}>
<h1>I'm wrapped in a section tag</h1>
</GsapAnimate>
gsapAnimateThe main animation action with full GSAP capabilities:
<script>
import { gsapAnimate } from '@gsap/svelte';
</script>
<!-- Animate TO values -->
<div use:gsapAnimate={{
type: 'to',
x: 100,
rotation: 360,
duration: 2
}}>
To Animation
</div>
<!-- Animate FROM values -->
<div use:gsapAnimate={{
type: 'from',
opacity: 0,
scale: 0.5,
duration: 1
}}>
From Animation
</div>
<!-- Animate FROM and TO -->
<div use:gsapAnimate={{
type: 'fromTo',
fromVars: { x: -100, opacity: 0 },
x: 0,
opacity: 1,
duration: 1.5
}}>
FromTo Animation
</div>
gsapFadeConvenience action for fade animations:
<script>
import { gsapFade } from '@gsap/svelte';
</script>
<div use:gsapFade={{ duration: 1, delay: 0.5 }}>
Fades in on mount
</div>
gsapSlideConvenience action for slide animations:
<script>
import { gsapSlide } from '@gsap/svelte';
</script>
<!-- Slide from different directions -->
<div use:gsapSlide={{ direction: 'left', distance: 100 }}>
Slides from left
</div>
<div use:gsapSlide={{ direction: 'up', distance: 50, duration: 1 }}>
Slides from top
</div>
Available directions: 'up', 'down', 'left', 'right'
gsapScaleConvenience action for scale animations:
<script>
import { gsapScale } from '@gsap/svelte';
</script>
<div use:gsapScale={{ from: 0, duration: 0.5 }}>
Scales up from 0
</div>
ScrollTrigger works seamlessly with all actions:
<script>
import { gsapAnimate } from '@gsap/svelte';
</script>
<div use:gsapAnimate={{
type: 'from',
opacity: 0,
y: 100,
duration: 1,
scrollTrigger: {
start: 'top 80%',
end: 'top 20%',
toggleActions: 'play none none reverse',
markers: true // Remove in production
}
}}>
Animates on scroll
</div>
createTimelineCreate complex animation sequences:
<script>
import { onMount } from 'svelte';
import { createTimeline } from '@gsap/svelte';
let box1, box2, box3;
onMount(() => {
const tl = createTimeline({
defaults: { duration: 1, ease: 'power2.out' }
});
tl.from(box1, { x: -100, opacity: 0 })
.from(box2, { x: 100, opacity: 0 }, '<0.2') // Overlap by 0.2s
.from(box3, { y: 50, opacity: 0 });
return () => tl.kill();
});
</script>
<div bind:this={box1}>Box 1</div>
<div bind:this={box2}>Box 2</div>
<div bind:this={box3}>Box 3</div>
batchAnimateAnimate multiple elements with stagger:
<script>
import { onMount } from 'svelte';
import { batchAnimate } from '@gsap/svelte';
let container;
onMount(() => {
const animation = batchAnimate('.item', {
opacity: 0,
y: 50,
duration: 1,
stagger: {
each: 0.1,
from: 'start'
},
scrollTrigger: {
trigger: container,
start: 'top center'
}
});
return () => animation.kill();
});
</script>
<div bind:this={container} class="grid">
{#each items as item}
<div class="item">{item}</div>
{/each}
</div>
createMatchMediaResponsive animations:
<script>
import { onMount } from 'svelte';
import { createMatchMedia, gsap } from '@gsap/svelte';
onMount(() => {
const mm = createMatchMedia();
mm.add('(min-width: 768px)', () => {
// Desktop animations
gsap.from('.hero', { x: -100, duration: 1 });
});
mm.add('(max-width: 767px)', () => {
// Mobile animations
gsap.from('.hero', { y: -100, duration: 1 });
});
return () => mm.revert();
});
</script>
Actions can be updated reactively:
<script>
import { gsapAnimate } from '@gsap/svelte';
let distance = 100;
let animationEnabled = true;
</script>
<input type="range" bind:value={distance} min="0" max="200" />
<label>
<input type="checkbox" bind:checked={animationEnabled} />
Enable Animation
</label>
<div use:gsapAnimate={{
type: 'from',
x: distance,
disabled: !animationEnabled
}}>
Interactive Animation
</div>
The package is safe to use in SvelteKit with SSR:
<script>
import { browser } from '$app/environment';
import { gsapAnimate } from '@gsap/svelte';
// Only animate in browser
$: animationConfig = browser ? {
type: 'from',
opacity: 0,
y: 50
} : { disabled: true };
</script>
<div use:gsapAnimate={animationConfig}>
SSR-safe animation
</div>
<script>
import { onMount } from 'svelte';
import { gsap, ScrollTrigger } from '@gsap/svelte';
let progressBar;
onMount(() => {
gsap.to(progressBar, {
scaleX: 1,
ease: 'none',
scrollTrigger: {
trigger: document.body,
start: 'top top',
end: 'bottom bottom',
scrub: true
}
});
});
</script>
<div bind:this={progressBar} class="progress-bar" style="transform: scaleX(0)"></div>
<script>
import { onMount } from 'svelte';
import { createContextSafeTimeline } from '@gsap/svelte';
let button;
const { timeline, contextSafe, kill } = createContextSafeTimeline();
const handleClick = contextSafe(() => {
timeline
.to(button, { scale: 1.2, duration: 0.2 })
.to(button, { scale: 1, duration: 0.2 });
});
onMount(() => {
return () => kill();
});
</script>
<button bind:this={button} on:click={handleClick}>
Click me!
</button>
Full TypeScript definitions are included:
import type { GSAPAnimateOptions } from '@gsap/svelte';
const config: GSAPAnimateOptions = {
type: 'from',
opacity: 0,
duration: 1,
scrollTrigger: {
trigger: '.element',
start: 'top center'
}
};
All GSAP plugins work seamlessly:
<script>
import { gsap } from '@gsap/svelte';
import { Draggable } from 'gsap/Draggable';
import { MotionPathPlugin } from 'gsap/MotionPathPlugin';
gsap.registerPlugin(Draggable, MotionPathPlugin);
// Use plugins as normal
</script>
gsapAnimate(node, options) - Main animation actiongsapFade(node, options) - Fade animationgsapSlide(node, options) - Slide animation gsapScale(node, options) - Scale animationcreateTimeline(options) - Create animation timelinecreateContextSafeTimeline(options) - Timeline with context safetybatchAnimate(targets, options) - Batch animate with staggercreateMatchMedia() - Responsive animationsscrollTrigger(targets, vars, config) - Scroll-triggered animationSee types.ts for all TypeScript definitions.
Check out the /examples directory for:
Contributions are welcome! Please read our contributing guidelines.
MIT © Roberto Chavez
GSAP is licensed by GreenSock. See GSAP licensing.
Built with ❤️ for the Svelte community.
Powered by GSAP by GreenSock.