This project is not intended to be responsive.

Please view this website in a larger window on your computer.

About this site

This site a supplement to the Webflow X GSAP presentation by Dennis Karg, which was presented at the German-speaking Meetup on 07/20/2022. It is therefore primarily intended for all participants of the Meetup to internalize the presented content. But even if you as a Webflow user did not attend the Meetup, you are welcome to use this Cloneable to get an introduction to GSAP.

Ok, got it.
Video: Greensock Showreel 2020

Starting with GSAP

Always first: Add Scripts to project

Get the GSAP Core Script

Any GSAP specific code can only be executed if the core library and any necessary plugins have been added to your project or site. Important: The GSAP Core must always be in the first place. All plugins must be added afterwards.

Add the scripts to the Site Settings if you want to use GSAP on every page of your Webflow project:

Or add it to the Page Settings of a subpage if you want to use GSAP only on this specific page:

.to() Tween

View in Docs
gsap.to(".box", {
  rotation: 90, 
  x: 300, 
  duration: 2
});

How you format your code doesn't matter, so you could write it that way:

gsap.to(".box", {rotation: 90, x: 400, duration: 2});
Basic Tween 1 - gsap.to()
A

.from() Tween

View in Docs
gsap.from(".box", {
  rotation: 90, 
  x: 300, 
  duration: 2
});
Basic Tween 2 - gsap.from()
A

.fromTo() Tween

View in Docs
gsap.fromTo(".box", {
  rotation: 180,
  y: 100,
  x: 100,
  autoAlpha: 0,
}, {
  rotation: 0, 
  y: 0,
  x: 300,
  autoAlpha: 1, 
  duration: 2
});
Basic Tween 3 - gsap.fromTo()
A
gsap.set(".box", {
  backgroundColor: "red",
  rotation: 33, 
  y: 50,
  x: 200,
  autoAlpha: 0.8,
  scale: 0.7
});
Basic Tween 4 - gsap.set()
A

.set() Tween + .to() Tween

gsap.set(".box", {y: 100, autoAlpha: 0});

gsap.to(".box", {
  y: 0,
  autoAlpha: 1,
  ease: "Power4.easeOut", 
  duration: 1.6
});
Basic Tween 5 - gsap.set() & gsap.to()
A
B
C
gsap.set(".box", {y: 100, autoAlpha: 0});

gsap.to(".box", {
  y: 0,
  autoAlpha: 1,
  ease: "Power4.easeOut", 
  duration: 1.6,
  stagger: 0.12
});
Basic Tween 6 - stagger
A
B
C
gsap.fromTo(".box", {
  y: 50
}, {
  y: -50,
  ease: "Power3.easeInOut", 
  duration: 3.2,
  stagger: 0.12,
  yoyo: true,
  repeat: -1	
});
Basic Tween 7 - looping
A
B
C

.to() with function based values

View in Docs
gsap.to(".box", {
  duration: 2,
  x: (index) => {
    return (index + 1) * 50
  }
});
Basic Tweens 8 - function values
A
B
C

Callbacks

View in Docs
gsap.to(".box", {
  duration: 2,
  x: 300,
  onComplete: () => alert("Animation finished"), 
  // "onUpdate", "onStart", "onReverseComplete", 
  // "onInterrupt" or "onRepeat"
});
Basic Tweens 9 - eventCallback()
A

GSAP Timelines

Basic setup of a timeline

View in Docs
let timeline = gsap.timeline({defaults: {ease: "Power1.easeInOut"}});

timeline.to(".box", { rotation: 90, x: 300, duration: 2})
.to(".box", { rotation: 180, y: 100, duration: 1})
.to(".box", { rotation: 90, x: 0, duration: 2})
.to(".box", { rotation: 0, y: 0, duration: 1});

Or also in this variation:

let timeline = gsap.timeline({ defaults: {ease: "Power1.easeInOut"}});

timeline.to(".box", { rotation: 90, x: 300, duration: 2});
timeline.to(".box", { rotation: 180, y: 100, duration: 1});
timeline.to(".box", { rotation: 90, x: 0, duration: 2});
timeline.to(".box", { rotation: 0, y: 0, duration: 1});
Timeline 1 - Basic Setup
A

Timeline Nesting

View in Docs
function firstTimeline() {
  let tl = gsap.timeline({defaults: {duration: 3, ease: "Power1.easeInOut"}});
  tl.to(".box:nth-child(1)", { rotation: 180, x: 300});
  tl.to(".box:nth-child(1)", { rotation: 0, x: 0});
  return tl;
}

function secondTimeline() {
  let tl = gsap.timeline({defaults: {duration: 3, ease: "Power1.easeInOut"}});
  tl.to(".box:nth-child(2)", { rotation: -180, x: 300});
  tl.to(".box:nth-child(2)", { rotation: 0, x: 0});
  return tl;
}

function thirdTimeline() {
  let tl = gsap.timeline({defaults: {duration: 3, ease: "Power1.easeInOut"}});
  tl.to(".box:nth-child(3)", { rotation: 180, x: 300});
  tl.to(".box:nth-child(3)", { rotation: 0, x: 0});
  return tl;
}

const mainTimeline = gsap.timeline({paused: true});

mainTimeline.add(firstTimeline());
mainTimeline.add(secondTimeline());
mainTimeline.add(thirdTimeline());
Timeline 2 - Nesting
A
B
C

Timeline Position Parameter

View in Docs

Start exactly 3 seconds after the beginning of the timeline:

let timeline = gsap.timeline();

timeline.to(".box:nth-child(1)", { x: 300});
timeline.to(".box:nth-child(2)", { x: 0}, 3);

Start 2 seconds after the end of the previous tween:

let timeline = gsap.timeline();

timeline.to(".box:nth-child(1)", { x: 300});
timeline.to(".box:nth-child(2)", { x: 0}, "+=2");

Start 1.2 seconds before the end of the previous tween:

let timeline = gsap.timeline();

timeline.to(".box:nth-child(1)", { x: 300});
timeline.to(".box:nth-child(2)", { x: 0}, "-=1.2");

Start together with previous tween:

let timeline = gsap.timeline();

timeline.to(".box:nth-child(1)", { x: 300});
timeline.to(".box:nth-child(2)", { x: 0}, "<");

Feasible but unusual example:

gsap.set(".box:nth-child(2)", {rotation: 90, x: 300});

let timeline = gsap.timeline({
  paused: true, 
  defaults: {
    duration: 3, 
    ease: "Power1.easeInOut"
  }
});

timeline.to(".box:nth-child(1)", { rotation: 90, x: 300});
timeline.to(".box:nth-child(1)", { rotation: 0, x: 0});
timeline.to(".box:nth-child(2)", { rotation: 0, x: 0}, 0);
timeline.to(".box:nth-child(2)", { rotation: 90, x: 300}, "<+=3");
Timeline 3 - Position Parameter
A
B

Timeline Defaults

View in Docs
let timeline = gsap.timeline();

timeline.to(".box:nth-child(1)", {rotation: -270, duration: 1, ease: "elastic"});
timeline.to(".box:nth-child(1)", {rotation: -360, duration: 1, ease: "elastic"});
timeline.to(".box:nth-child(1)", {rotation: -180, duration: 1, ease: "elastic"});

Shortened with default parameters:

let timeline = gsap.timeline({ defaults: {duration: 1, ease: "elastic"} } );

timeline.to(".box:nth-child(1)", {rotation: -270});
timeline.to(".box:nth-child(2)", {rotation: -360});
timeline.to(".box:nth-child(3)", {rotation: -180});
Timeline 4 - Defaults
A
B
C

Timeline Parameter

View in Docs

Pause the timeline to start:

let timeline = gsap.timeline({ paused: true });

Delay the start time of the entire timeline (Delay):

let timeline = gsap.timeline({ delay: 0.5 });

Repeat the timeline X times:

let timeline = gsap.timeline({ repeat: 2 }); // -1 for infinite

Pause between repeats:

let timeline = gsap.timeline({ repeat: 2, repeatDelay: 1 });

Update start values after each repetition:

let timeline = gsap.timeline({ repeat: 2, repeatRefresh: true });

Yoyo effect for looping:

let timeline = gsap.timeline({ repeat: 2, yoyo: true });

onComplete, onStart, onUpdate, onRepeat, onReverseComplete:

let timeline = gsap.timeline({ onComplete: fireConfetti });

Example combination:

let timeline5 = gsap.timeline({
  paused: true,
  repeat: 3,
  repeatRefresh: true,
  repeatDelay: 0.2,
  defaults: {
    duration: 2, 
    ease: "Power1.easeInOut"
  }
});

timeline5.to(".playground._5 .box", {x: "+=100"});
Timeline 5 - Timeline Parameter
A

ScrollTrigger

Add Script to your project

Get the ScrollTrigger Script

Add plugins after the core:

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.4/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.4/ScrollTrigger.min.js"></script>

Register plugins:

gsap.registerPlugin(ScrollTrigger);

.to() with ScrollTrigger

View in Docs
gsap.to(".box", {
  scrollTrigger: {
    trigger: ".box",
    start: "top bottom",
  },
  x: 300,
  duration: 3,
  ease: "Power1.easeInOut"
});
ScrollTrigger 1 - gsap.to()
A

Show visual markers

gsap.to(".box", {
  scrollTrigger: {
    trigger: ".box",
    start: "top bottom",
    markers: true,
    id: "first" // id is optional
  },
  x: 300,
  duration: 3,
  ease: "Power1.easeInOut"
});

Start Parameter

View in Docs
gsap.to(".box", {
  scrollTrigger: {
    trigger: ".box",
    start: "top bottom", // [Trigger] [Viewport]
  },
  x: 300,
  duration: 3,
  ease: "Power1.easeInOut"
});

Other specification options:

[...]
start: "0% 100%", = start: "top bottom",
start: "50% 60%", = start: "center 60vh",
start: "bottom bottom", = start: "100% 100%",
start: "top-=200px 50%-=200px"
[...]
ScrollTrigger 2 - Start Parameter
A

Toogle Actions

View video in Docs

toggleActions Structure:

toggleActions: "
play
none
none
none
",

Default toggleActions, even if not defined:

gsap.to(".box", {
  scrollTrigger: {
    trigger: ".box",
    // toggleActions: "play none none none",
  },
  x: 300,
  duration: 3,
  ease: "Power1.easeInOut"
});

All toogleAction values:

"play", "pause", "resume", "reset", "restart", "complete", "reverse" & "none"

Usual combination::

gsap.to(".box", {
  scrollTrigger: {
    trigger: ".box",
    toggleActions: "play pause resume reset"
  },
  x: 300,
  duration: 3,
  ease: "Power1.easeInOut"
});
ScrollTrigger 3 - toggleActions
A

.timeline() with ScrollTrigger

View in Docs
let timeline = gsap.timeline({
  paused: true, 
    defaults: {
    ease: "Power1.easeInOut"
  },
  scrollTrigger: {
    trigger: ".box",
    toggleActions: "play pause resume reset",
    start: "top 60%"
  }
});

timeline.to(".box", { rotation: 90, x: 300, duration: 2});
timeline.to(".box", { rotation: 180, y: 100, duration: 1});
timeline.to(".box", { rotation: 90, x: 0, duration: 2});
timeline.to(".box", { rotation: 0, y: 0, duration: 1});
ScrollTrigger 4 - timeline()
A
let timeline = gsap.timeline({
  paused: true, 
    defaults: {
    ease: "Power1.easeInOut"
  },
  scrollTrigger: {
    trigger: ".box",
    start: "-=300 50%",
    end: "+=600px",
    scrub: true,
    // Instead of the value "true", numbers are also 
    // possible that give the animation a smooth 
    // effect - e.g. scrub: 0.9 or scrub: 2
  }
});

timeline.to(".box", { rotation: 90, x: 300, duration: 2});
timeline.to(".box", { rotation: 180, y: 100, duration: 1});
timeline.to(".box", { rotation: 90, x: 0, duration: 2});
timeline.to(".box", { rotation: 0, y: 0, duration: 1});
ScrollTrigger 5 - scrub
A

Scrub + Pinning

View in Docs
let timeline = gsap.timeline({
  defaults: {
    ease: "Power1.easeInOut"
  },
  scrollTrigger: {
    trigger: ".box",
    start: "center 50%",
    end: "+=600px",
    scrub: true,
    pin: true
  }
});

timeline.to(".box", { rotation: 90, x: 300, duration: 2});
timeline.to(".box", { rotation: 180, y: 100, duration: 1});
timeline.to(".box", { rotation: 90, x: 0, duration: 2});
timeline.to(".box", { rotation: 0, y: 0, duration: 1});
ScrollTrigger 6 - scrub & ping
A

Callbacks

View in Docs
ScrollTrigger.create({
  trigger: ".box",
  start: "center center",
  onEnter: ScrollTriggerReached,
});

All callbacks:

"onEnter", "onLeave", "onEnterBack", "onLeaveBack", "onUpdate", 
"onToggle", "onRefresh", "onRefreshInit" & "onScrubComplete"
ScrollTrigger 7 - Callbacks
A
ScrollTriggerReached() executed

People to follow

Blake Bowen
@OSUbowen
Cassie Evans
@cassiecodes
Frontend Horse
@FrontendHorse
Alex Trost
@trostcodes
Steve Gardner
Tom Miller / Creative Ocean
Craig Roblewsky
Cameron Knight
Petr Tichy
Ryan LaBar
Louis Hoebregts
Jhey Tompkins
Diaco M Lotfolahi
Karim Maaloul

GSAP Resources to absorb

Most Common GSAP Mistakes
greensock.com
Most Common ScrollTrigger Mistakes
greensock.com
Greensock Learning Youtube
youtube.com
Tips for Writing Animation Code Efficiently
css-tricks.com
Awwwards Category GSAP
awwwards.com
Motiontricks
motiontricks.com
Greensock 101 - ihatetomatoes
ihatetomatoes.net
Barba.js 101 - ihatetomatoes
ihatetomatoes.net
GSAP 3 Express by snorklTV
creativecodingclub.com
Timothy Ricks Youtube
youtube.com