GSAP Guide
You can find the code in (Site settings) Footer Code.
1. Fade Animations
Scroll-triggered entrance animations applied via data-animate attributes on any element (GSAP interactions).
Variants
- data-animate="fade-up"
- data-animate="fade-in"
- data-animate="stagger-up"
All three fire once when the element's top edge crosses 90% of the viewport. They do not replay on scroll back.
To add to any element in Webflow: add a custom attribute — Name: data-animate, Value: fade-up, fade-in, or stagger-up.
Buttons
Buttons and links arrows animated in custom code with initArrowAnimation(); initBtnPrimaryAnimation(); initBtnSecondaryAnimation();
2. Slider Split
Auto-advancing content slider with a progress bar and prev/next navigation. Starts only when the section scrolls into view.
Selectors used
- .section_slider-split — section wrapper, one per slider
- .slider_split-item-content-item-wrap — wraps each slide's text
- .slider_split-item-content-item — text content, fades in/out
- .slider_split-item-img — slide image, fades in/out
- .slider_split-controls-progress — progress bar, CSS sets width:0, GSAP animates it to 100%
- .slider_split-controls-counter-current — current slide number
- .slider_split-controls-counter-total — total slide count
- .slider_split-controls-nav-item-prev — previous button
- .slider_split-controls-nav-item-next — next button
Customising timing
To change how long each slide is shown (default 5 seconds):
var duration = 5;
To change how fast slides transition between each other:
gsap.to(contentItems[currentIndex], { opacity: 0, duration: 0.4 });
Removing slider autoplay
- Comment out the startProgress() call inside goToSlide().
- Comment out the entire function startProgress() { ... } block.
- Prev/next buttons will still work. Slider becomes manual-only.
- Style fix required: GSAP sets display:none on all .slider_split-item-content-item-wrap elements except the active one, and sets opacity:0 + visibility:hidden on all .slider_split-item-img elements except the active one. After removing the script, go into Webflow and manually set all wraps to display:block and all images to opacity:1 and visibility:visible — otherwise only the first slide will be visible.
3. Loop Carousel
Continuously scrolling carousel with seamless looping. Supports mouse and touch drag. Pauses on hover. Resumes autoscroll 1 second after drag release.
Selectors used
- .section_loop-carousel — section wrapper
- .loop_carousel-row — scrolling track, drag events attach here
- .loop_carousel-list — item list, cloned once automatically for seamless loop
- .loop_carousel-list-item — individual card, hover pauses autoscroll
- .loop_carousel-list-item-btn — button wrapper shown on hover
- .btn-secondary — button inside each card, fades in on hover
Note: do not manually add a second .loop_carousel-list in Webflow. The script clones it automatically — a duplicate will break the loop.
Customising
To change scroll speed in pixels per second (default 50):
var sliderSpeed = 50;
To change how long autoscroll waits after drag before resuming (default 1 second):
resumeTimer = gsap.delayedCall(1, function() { ... });
Removing drag only
- Remove the addEventListener lines for mousedown, touchstart, mousemove, touchmove, mouseup, touchend.
- Remove the onDragStart, onDragMove, onDragEnd functions.
- Remove row.style.cursor = "grab". Autoscroll continues normally.
Removing carousel entirely
- Delete the initLoopCarousel() call.
- Delete the var defined_loopCarouselInstances declaration and the entire function initLoopCarousel() { ... } block.
- No style fixes needed — the clone and all transforms are created by JavaScript at runtime. Without the script, .loop_carousel-list has display:flex from CSS and items will render in a normal horizontal row.
4. Hero Circle
On scroll into view, cards fan out from the top of the circle to their final positions with a fade-in. The circle then rotates slowly and continuously.
Selectors used
- .hero_section-circle-section — section wrapper, scroll trigger attaches here
- .hero_section-circle — the circle that rotates, GSAP adds rotation transform at runtime
- .hero_section-circle-item — individual cards, CSS sets position:absolute top:0 left:0 — GSAP repositions and fades them in
- .hero_section-circle-title — center title, CSS already centers it with position:absolute and translate(-50%, -50%), GSAP only controls opacity
Customising
To change how long the intro fan-out takes:
var duration;
To change rotation speed — higher number means slower (default: 60 seconds per full rotation):
gsap.to(circle, { rotation: "+=360", duration: 60, ease: "none", repeat: -1 });
To change the easing of the fan-out:
ease: "power3.out"
To change how early each card starts fading in as it approaches its position — higher number means fade starts earlier:
var fadeWindow = (fullCircle / totalItems) * 5.5;
To change when the intro fires:
ScrollTrigger.create({ trigger: section, start: "top 80%" });
Removing Hero Circle
- Delete the initHeroCircle() call.
- Delete the var defined_heroCircleInstances declaration and the entire function initHeroCircle() { ... } block.
- Style fix required — critical: in CSS, all .hero_section-circle-item elements have position:absolute, top:0, left:0. Without GSAP repositioning them, every card will be stacked in the top-left corner of the circle. You must redesign this section in Webflow — either change the items to position:static and use a flexbox or grid layout, or manually set individual top/left values for each card.
- Style fix required: .hero_section-circle-title starts with opacity:0 set by GSAP — without the script it will be invisible. In Webflow, set its opacity to 1. Its position is already handled by CSS so no layout change needed there.
Key Variables at a Glance
- duration (fade-up/in) — found in initFadeAnimations — fade entrance duration in seconds
- stagger — found in initFadeAnimations — delay between words in stagger-up
- duration (slider) — found in initSliderSplit — seconds per slide before auto-advance
- sliderSpeed — found in initLoopCarousel — carousel speed in pixels per second
- resumeTimer delay — found in initLoopCarousel — seconds after drag before autoscroll resumes
- duration (hero intro) — found in initHeroCircle — card fan-out intro duration
- rotation duration — found in initHeroCircle — seconds per full circle rotation
- fadeWindow multiplier — found in initHeroCircle — how early cards start fading in during intro
5. Header Scroll
Adds an is-scrolled class to the header when the page is scrolled more than 50px down. Used to trigger a background colour change.
Selectors used
- .header — the fixed header element
- .header.is-scrolled — CSS class applied on scroll, sets background-color to white
Customising
To change how far the user must scroll before the class is added (default 50px):
ScrollTrigger.create({ trigger: body, start: "top -50" });
Removing
- Delete the initHeaderScroll() call and the entire function initHeaderScroll() { ... } block.
- No style fixes needed — is-scrolled is only added by JS. Without the script the header stays transparent. If you want it always white, set background-color directly on .header in Webflow.
6. Slider Flick
A draggable card carousel where the active card is centered and neighbouring cards peek from the sides. Supports click and drag to change slides. Runs on desktop and tablet.
Selectors used
- .section-flick-cards — section wrapper
- .slider_flick-component — outer component with overflow:hidden
- .slider_flick-list — card container, drag attaches here
- .slider_flick-card — individual card, positioned absolutely by GSAP
- .slider_flick-card.is-current — active card class
- .slider_flick-card-content — card text, fades in when active
- .slider_flick-card-gradient — overlay gradient, fades in when active
- .slider_flick-card-button — card button, fades in when active
- .slider_flick-prev / .slider_flick-next — prev/next nav buttons
Customising
To change how much neighbouring cards peek in from the sides, adjust firstPeek multiplier (default 0.12 on desktop, 0.06 on tablet):
var firstPeek = cardWidth * firstScale * 0.12;
To change the slide change threshold — how far the user must drag to trigger a slide change (default 25% of card width):
var threshold = cardWidth * 0.25;
Removing
- Delete the initSliderFlick() call and the entire function initSliderFlick() { ... } block.
- Style fix required: .slider_flick-card has position:absolute set in CSS. Without GSAP positioning them, all cards will be stacked in the same spot. You will need to redesign this section or change the cards to position:static with a different layout.
- Style fix required: .slider_flick-card-content, .slider_flick-card-gradient, and .slider_flick-card-button all have opacity:0 in CSS. Without GSAP they will be invisible. Set opacity:1 on each in Webflow.
7. Courses Tabs
A manual tab switcher for the courses section. Clicking a nav item fades out the current content and fades in the selected one.
Selectors used
- .section-courses-tabs — section wrapper
- .courses_tabs-text-item-wrap — wraps each tab's text content
- .courses_tabs-text-item — text content, fades in/out
- .courses_tabs-img — tab image, fades in/out
- .courses_tabs-nav-item — clickable nav items, gets is-active class when selected
Customising
To change the fade transition speed (default 0.4 seconds):
gsap.to(textItems[currentIndex], { opacity: 0, duration: 0.4 });
Removing
- Delete the initCoursesTabs() call and the entire function initCoursesTabs() { ... } block.
- Style fix required: GSAP sets display:none on all .courses_tabs-text-item-wrap elements except the first, and opacity:0 + visibility:hidden on all .courses_tabs-img except the first. After removing the script, set all wraps to display:block and all images to opacity:1 and visibility:visible in Webflow. You will also need to handle tab switching with Webflow's native interactions or remove the tab structure entirely.
8. Logo Sliders
Continuously scrolling logo marquee. Supports multiple rows, with an optional reverse direction row.
Selectors used
- .section-logo-sliders — section wrapper
- .section_logo_sliders-row — one row of logos, scrolls left to right by default
- .section_logo_sliders-row.section_logo_sliders-row-reverse — scrolls right to left
- .section_logo_sliders-list — logo list, cloned once automatically for seamless loop
Note: do not manually add a second .section_logo_sliders-list — the script clones it automatically.
Customising
To change scroll speed in pixels per second (default 50):
var sliderSpeed = 50;
Removing
- Delete the initLogoSliders() call and the entire function initLogoSliders() { ... } block.
- No style fixes needed — the clone and transforms are created by JS only. Without the script the logos render in a static row.
9. Steps Slider
A manual step-by-step slider with clickable step indicators and prev/next navigation. Clicking a step or nav button fades the content and image to the selected slide.
Selectors used
- .section_steps-slider — section wrapper
- .steps_slider-content-item-wrap — wraps each step's text content
- .steps_slider-content-item — text content, fades in/out
- .steps_slider-img — step image, fades in/out
- .steps_slider-step-item — clickable step indicators
- .steps_slider-step-item-step-dot — dot indicator, gets is-active class
- .steps_slider-step-item-text — step label, gets is-active class
- .steps_slider-steps-wrap — scrollable steps container, auto-scrolls to keep active step visible
- .steps_slider-nav-prev / .steps_slider-nav-next — prev/next buttons
Customising
To change the fade transition speed (default 0.4 seconds):
gsap.to(contentItems[currentIndex], { opacity: 0, duration: 0.4 });
Removing
- Delete the initStepsSlider() call and the entire function initStepsSlider() { ... } block.
- Style fix required: GSAP sets display:none on all .steps_slider-content-item-wrap elements except the first, and opacity:0 + visibility:hidden on all .steps_slider-img except the first. After removing the script, set all wraps to display:block and all images to opacity:1 and visibility:visible in Webflow.
- Style fix required: is-active class on step dots and labels is managed by JS only. Without the script no step will appear active. Either remove the active styles from CSS or manually add is-active to the first step in Webflow.