A person sitting on a chair in front of a building.

How to Edit GSAP Animations.

This guide helps non-tech users utilize GSAP for animations like text splitting and sliders, focusing on documentation without altering code logic.

GSAP Plugin Registration

What It does

This sets up GSAP basics.

HTML Requirements

Elements with data-gsap="split-text", containing plain text.

    // ============================================
    // GSAP PLUGIN REGISTRATION
    // ============================================
    gsap.registerPlugin(ScrollTrigger);
    gsap.config({ nullTargetWarn: false });
Code Block 1

Element Map

  • No direct elements; global setup for ScrollTrigger (scroll-based animations) and config to ignore missing targets.

Home Hero Slider

What It does

This animates a hero slider with slides, thumbnails, arrows, and autoplay.

    // ============================================
    // HOME HERO SLIDER WITH GSAP
    // ============================================
    function initHeroSliderAnimations() {
        document.querySelectorAll(".section_home_hero").forEach(section => {
            const heroSliderWrap = section.querySelector(".home_hero_slider");
            if (!heroSliderWrap) return;

            const heroSliderArrows = section.querySelectorAll(".slider_button");
            const heroSliderItems = heroSliderWrap.querySelectorAll(".home_hero_slider_item");
            const heroThumbnailContainer = section.querySelector(".custom_slider_thumbnail");
            const totalHeroSlides = heroSliderItems.length;
            let heroActiveIndex = 0;
            let heroCurrentTimeline = null;
            let heroAutoplayInterval;

            function startHeroAutoplay() {
                if (heroAutoplayInterval) heroAutoplayInterval.kill();
                heroAutoplayInterval = gsap.delayedCall(7, () => {
                    goNextHero(heroActiveIndex + 1);
                    startHeroAutoplay();
                });
            }

            function buildHeroThumbnails() {
                while (heroThumbnailContainer.firstChild) {
                    heroThumbnailContainer.removeChild(heroThumbnailContainer.firstChild); // Safe clear without innerHTML
                }

                heroSliderItems.forEach((item, index) => {
                    const heroImgElement = item.querySelector(".home_hero_slider_image img");
                    if (!heroImgElement) return;

                    const heroImgSrc = heroImgElement.getAttribute("src");

                    const heroThumbnail = document.createElement("div");
                    heroThumbnail.className = `thumbnail ${index === 0 ? "active" : ""}`;
                    heroThumbnail.dataset.index = index;

                    const img = document.createElement("img");
                    img.className = "object-cover-fit";
                    img.src = heroImgSrc;
                    img.alt = `Thumbnail ${index + 1}`;

                    heroThumbnail.appendChild(img);
                    heroThumbnailContainer.appendChild(heroThumbnail);
                });

                // Animate thumbnails with GSAP
                const heroThumbnails = heroThumbnailContainer.querySelectorAll('.thumbnail');
                gsap.from(heroThumbnails, {
                    scale: 0,
                    duration: 0.5,
                    stagger: 0.1,
                    ease: "back.out(1.7)"
                });
            }


            buildHeroThumbnails();
            const heroThumbnails = section.querySelectorAll(".thumbnail");

            function moveHeroSlide(nextIndex, forwards) {
                if (nextIndex === heroActiveIndex) return;
                if (heroCurrentTimeline) {
                    heroCurrentTimeline.kill();
                    heroCurrentTimeline = null;
                }

                // Animate thumbnails with GSAP
                gsap.to(heroThumbnails, {
                    scale: 1,
                    duration: 0.3,
                    ease: "power1.out"
                });
                heroThumbnails.forEach(thumb => thumb.classList.remove("active"));

                heroThumbnails[nextIndex].classList.add("active");
                gsap.to(heroThumbnails[nextIndex], {
                    scale: 1.1,
                    duration: 0.3,
                    ease: "power1.out"
                });

                const prevHeroItem = heroSliderItems[heroActiveIndex];
                const nextHeroItem = heroSliderItems[nextIndex];
                const oldHeroIndex = heroActiveIndex;
                heroActiveIndex = nextIndex;

                // Set z-index with GSAP
                heroSliderItems.forEach((item, i) => {
                    gsap.set(item, {
                        zIndex: i === nextIndex ? 2 : (i === oldHeroIndex ? 1 : 0)
                    });
                });

                const nextHeroSliderImage = nextHeroItem.querySelector(".home_hero_slider_image img");
                if (nextHeroSliderImage) {
                    gsap.set(nextHeroSliderImage, { scale: 1.15 });
                }

                prevHeroItem.classList.add("is-active");
                nextHeroItem.classList.add("is-active");

                const heroTitleFrom = forwards ? 100 : -100;
                const heroTitleDelay = forwards ? "<50%" : "<";

                heroCurrentTimeline = gsap.timeline({
                    defaults: { duration: 1, ease: "power1.out" },
                    onComplete: () => {
                        prevHeroItem.classList.remove("is-active");
                        heroSliderItems.forEach((item, i) => {
                            gsap.set(item, { zIndex: i === heroActiveIndex ? 2 : 0 });
                        });

                        const activeHeroSliderImage = nextHeroItem.querySelector(".home_hero_slider_image img");
                        if (activeHeroSliderImage) {
                            gsap.to(activeHeroSliderImage, {
                                scale: 1,
                                duration: 4,
                                ease: "power1.out"
                            });
                        }

                        heroCurrentTimeline = null;
                    }
                });

                // Slide transitions with GSAP
                if (forwards) {
                    heroCurrentTimeline.fromTo(
                        nextHeroItem,
                        { clipPath: "polygon(100% 0%, 100% 0%, 100% 100%, 100% 100%)" },
                        { clipPath: "polygon(0% 0%, 100% 0%, 100% 100%, -30% 100%)" }
                    );
                    heroCurrentTimeline.fromTo(
                        prevHeroItem,
                        { clipPath: "polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)" },
                        { clipPath: "polygon(0% 0%, 0% 0%, -30% 100%, 0% 100%)" },
                        "<"
                    );
                } else {
                    heroCurrentTimeline.fromTo(
                        nextHeroItem,
                        { clipPath: "polygon(0% 0%, 0% 0%, 0% 100%, 0% 100%)" },
                        { clipPath: "polygon(0% 0%, 100% 0%, 130% 100%, 0% 100%)" }
                    );
                    heroCurrentTimeline.fromTo(
                        prevHeroItem,
                        { clipPath: "polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)" },
                        { clipPath: "polygon(100% 0%, 100% 0%, 100% 100%, 130% 100%)" },
                        "<"
                    );
                }

                // Animate text with GSAP
                const heroTitleElements = nextHeroItem.querySelectorAll(".home_hero_slider_meta");
                heroCurrentTimeline.fromTo(
                    heroTitleElements,
                    { yPercent: heroTitleFrom, autoAlpha: 0 },
                    { yPercent: 0, autoAlpha: 1, duration: 0.5 },
                    heroTitleDelay
                );
            }

            function goNextHero(num) {
                const nextHeroIndex = num >= totalHeroSlides ? 0 : num;
                moveHeroSlide(nextHeroIndex, true);
                startHeroAutoplay();
            }

            function goPrevHero(num) {
                const nextHeroIndex = num < 0 ? totalHeroSlides - 1 : num;
                moveHeroSlide(nextHeroIndex, false);
                startHeroAutoplay();
            }

            // Initialize first slide animation with GSAP
            const firstHeroSliderImage = heroSliderItems[0]?.querySelector(".home_hero_slider_image img");
            if (firstHeroSliderImage) {
                gsap.fromTo(
                    firstHeroSliderImage,
                    { scale: 1.15 },
                    { scale: 1, duration: 4, ease: "power1.out" }
                );
            }

            gsap.set(heroThumbnails[0], { scale: 1.1 });

            startHeroAutoplay();

            // Setup arrow controls with GSAP hover effects
            section.querySelectorAll(".slider_button").forEach(arrow => {
                if (arrow.classList.contains("is-next")) {
                    arrow.addEventListener("click", () => {
                        goNextHero(heroActiveIndex + 1);
                        startHeroAutoplay();
                    });
                }
                if (arrow.classList.contains("is-prev")) {
                    arrow.addEventListener("click", () => {
                        goPrevHero(heroActiveIndex - 1);
                        startHeroAutoplay();
                    });
                }
            });

            // Setup thumbnail controls with GSAP hover effects
            heroThumbnails.forEach((thumb) => {
                thumb.addEventListener("click", () => {
                    const index = parseInt(thumb.dataset.index);
                    moveHeroSlide(index, index > heroActiveIndex);
                    startHeroAutoplay();
                });
            });
        });
    }
Code Block 2

Element Map

  • .section_home_hero: Hero section container.

  • .home_hero_slider_item: Individual slides; scale and fade.

  • .home_hero_slider_image img: Images zoom out slowly.

  • .home_hero_slider_meta: Text slides in on change.

  • .custom_slider_thumbnail: Thumbnails container; thumbnails scale in.

  • .slider_button.is-next, .slider_button.is-prev: Arrows for navigation.

HTML Requirement

A section with class section_home_hero containing a div home_hero_slider with multiple home_hero_slider_item divs (each with image and meta text), a custom_slider_thumbnail div, and arrow buttons.

Customizing Key Variables

  • Autoplay delay: Change gsap.delayedCall(7, ...) to gsap.delayedCall(10, ...) for 10-second wait.

    gsap.delayedCall(10, () => { ... });
  • Slide duration: In timeline, change defaults: { duration: 1, ... } to defaults: { duration: 1.5, ... } for slower transitions.

    heroCurrentTimeline = gsap.timeline({
        defaults: { duration: 1.5, ease: "power1.out" },
        ...
    });
  • Ease: Change "power1.out" to "bounce.out" for bouncy feel.

Removing Animations

  • Comment/Remove entire code shown in the Code Block 2

Testimony Slider

What It does

This animates a testimony slider with images, text, arrows, and autoplay.

    // ============================================
    // TESTIMONY SLIDER WITH GSAP
    // ============================================

    function initTestimonySliderAnimations() {
        const testimonyImageWrap = document.querySelector('.testimony_image-wrap');
        const testimonyImages = testimonyImageWrap?.querySelectorAll('.testimony_image') || [];
        const testimonyTextWrap = document.querySelector('.testimony_text-wrap');
        const testimonyTexts = testimonyTextWrap?.querySelectorAll('.testimony_text') || [];
        const testimonyNextArrow = document.querySelector('.testimony_arrow.is-next');
        const testimonyPrevArrow = document.querySelector('.testimony_arrow.is-prev');

        if (!testimonyImageWrap || !testimonyTextWrap || !testimonyNextArrow || !testimonyPrevArrow ||
            testimonyImages.length === 0 || testimonyTexts.length === 0) {
            return;
        }

        let testimonyActiveIndex = 0;
        let testimonyCurrentTimeline = null;
        let testimonyAutoplayInterval = null;

        function startTestimonyAutoplay() {
            if (testimonyAutoplayInterval) testimonyAutoplayInterval.kill();
            testimonyAutoplayInterval = gsap.delayedCall(7, () => {
                goNextTestimony();
                startTestimonyAutoplay();
            });
        }

        function moveTestimonySlide(nextIndex, direction) {
            if (nextIndex === testimonyActiveIndex) return;

            if (testimonyCurrentTimeline) {
                testimonyCurrentTimeline.kill();
                testimonyCurrentTimeline = null;
            }

            const prevTestimonyImage = testimonyImages[testimonyActiveIndex];
            const nextTestimonyImage = testimonyImages[nextIndex];
            const prevTestimonyText = testimonyTexts[testimonyActiveIndex];
            const nextTestimonyText = testimonyTexts[nextIndex];

            testimonyImages.forEach((img, i) => img.classList.toggle('is-active', i === nextIndex));
            testimonyTexts.forEach((text, i) => text.classList.toggle('is-active', i === nextIndex));

            gsap.set(prevTestimonyImage, { zIndex: 1, autoAlpha: 1 });
            gsap.set(nextTestimonyImage, { zIndex: 2, autoAlpha: 1 });
            gsap.set(prevTestimonyText, { zIndex: 1, autoAlpha: 1 });
            gsap.set(nextTestimonyText, { zIndex: 2, autoAlpha: 1 });

            const oldTestimonyIndex = testimonyActiveIndex;
            testimonyActiveIndex = nextIndex;

            testimonyCurrentTimeline = gsap.timeline({
                defaults: {
                    duration: 1,
                    ease: 'power2.inOut'
                },
                onComplete: () => {
                    if (testimonyActiveIndex !== oldTestimonyIndex) {
                        gsap.set(prevTestimonyImage, { autoAlpha: 0, zIndex: 0 });
                        gsap.set(prevTestimonyText, { autoAlpha: 0, zIndex: 0 });
                    }

                    testimonyImages.forEach((img, i) => {
                        if (i !== testimonyActiveIndex) {
                            gsap.set(img, { zIndex: 0, autoAlpha: 0 });
                        }
                    });
                    testimonyTexts.forEach((text, i) => {
                        if (i !== testimonyActiveIndex) {
                            gsap.set(text, { zIndex: 0, autoAlpha: 0 });
                        }
                    });

                    gsap.set(testimonyImages[testimonyActiveIndex], { zIndex: 2, autoAlpha: 1 });
                    gsap.set(testimonyTexts[testimonyActiveIndex], { zIndex: 2, autoAlpha: 1 });

                    testimonyCurrentTimeline = null;
                }
            });

            if (direction === 'next') {
                testimonyCurrentTimeline.fromTo(
                    nextTestimonyImage,
                    { clipPath: 'polygon(100% 0%, 100% 0%, 100% 100%, 100% 100%)' },
                    { clipPath: 'polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)' }
                );
                testimonyCurrentTimeline.fromTo(
                    prevTestimonyImage,
                    { clipPath: 'polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)' },
                    { clipPath: 'polygon(0% 0%, 0% 0%, 0% 100%, 0% 100%)' },
                    '<'
                );
            } else {
                testimonyCurrentTimeline.fromTo(
                    nextTestimonyImage,
                    { clipPath: 'polygon(0% 0%, 0% 0%, 0% 100%, 0% 100%)' },
                    { clipPath: 'polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)' }
                );
                testimonyCurrentTimeline.fromTo(
                    prevTestimonyImage,
                    { clipPath: 'polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)' },
                    { clipPath: 'polygon(100% 0%, 100% 0%, 100% 100%, 100% 100%)' },
                    '<'
                );
            }

            testimonyCurrentTimeline.fromTo(
                prevTestimonyText,
                { y: 0, autoAlpha: 1 },
                { y: -50, autoAlpha: 0, duration: 0.5 },
                '<'
            );
            testimonyCurrentTimeline.fromTo(
                nextTestimonyText,
                { y: 50, autoAlpha: 0 },
                { y: 0, autoAlpha: 1, duration: 0.5 },
                '<'
            );
        }

        function goNextTestimony() {
            const nextTestimonyIndex = (testimonyActiveIndex + 1) % testimonyImages.length;
            moveTestimonySlide(nextTestimonyIndex, 'next');
            startTestimonyAutoplay();
        }

        function goPrevTestimony() {
            const prevTestimonyIndex = (testimonyActiveIndex - 1 + testimonyImages.length) % testimonyImages.length;
            moveTestimonySlide(prevTestimonyIndex, 'prev');
            startTestimonyAutoplay();
        }

        // Initialize slider state with GSAP
        testimonyImages.forEach((img, index) => {
            img.classList.toggle('is-active', index === testimonyActiveIndex);
            gsap.set(img, {
                autoAlpha: index === testimonyActiveIndex ? 1 : 0,
                clipPath: 'polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)',
                zIndex: index === testimonyActiveIndex ? 2 : 0
            });
        });

        testimonyTexts.forEach((text, index) => {
            text.classList.toggle('is-active', index === testimonyActiveIndex);
            gsap.set(text, {
                autoAlpha: index === testimonyActiveIndex ? 1 : 0,
                y: index === testimonyActiveIndex ? 0 : 50,
                zIndex: index === testimonyActiveIndex ? 2 : 0
            });
        });

        // Setup click handlers
        testimonyNextArrow.addEventListener('click', goNextTestimony);
        testimonyPrevArrow.addEventListener('click', goPrevTestimony);

        // Start autoplay with GSAP
        startTestimonyAutoplay();
    }
Code Block 3

Element Map

  • .testimony_image-wrap: Images container; images clip in/out.

  • .testimony_image: Individual images; fade and slide.

  • .testimony_text-wrap: Texts container.

  • .testimony_text: Individual texts; slide up/down.

  • .testimony_arrow.is-next, .testimony_arrow.is-prev: Arrows.

HTML Requirements

Divs testimony_image-wrap with multiple testimony_image, testimony_text-wrap with matching testimony_text, and arrow elements.

Customizing Key Variables

  • Autoplay: 7 → 5.

    testimonyAutoplayInterval = gsap.delayedCall(5, () => { ... });
  • Duration: duration: 1 → 0.8.

    testimonyCurrentTimeline = gsap.timeline({
        defaults: { duration: 0.8, ease: 'power2.inOut' },
        ...
    });
  • Text: duration: 0.5 → 0.7.

    duration: 0.7
  • Ease: "power2.inOut" → "power3.inOut".

Removing Animations

  • Comment/Remove: // function initTestimonySlider() {..}

  • Or Comment/Remove: The code from page settings that are shown in Code Block 3

Expertise Section with GSAP

What It does

This animates expertise items on hover, switching images and texts.

    // ============================================
    // EXPERTISE SECTION WITH GSAP
    // ============================================

    function initExpertiseAnimations() {
        const expertiseFiguresContainer = document.querySelector('.home_expertise_figures');
        const expertiseInnerContainer = document.querySelector('.home_expertise_inner');
        const expertiseTextWrap = document.querySelector('.home_expertise_text_wrap');
        const expertiseTextItems = expertiseTextWrap?.querySelectorAll('.home_expertise_text') || [];

        if (!expertiseFiguresContainer || !expertiseInnerContainer || !expertiseTextItems.length) return;

        const expertiseImageElements = expertiseFiguresContainer.querySelectorAll('.home_expertise_image');
        const expertiseItemElements = expertiseInnerContainer.querySelectorAll('.home_expertise_item');

        // Initialize with GSAP
        gsap.set(expertiseImageElements, {
            position: 'absolute',
            top: 0,
            left: 0,
            autoAlpha: 0,
            zIndex: 0,
            scale: 1
        });

        gsap.set(expertiseImageElements[0], {
            autoAlpha: 1,
            zIndex: 2,
            scale: 1
        });

        expertiseItemElements[0].classList.add('is-active');
        expertiseTextItems[0].classList.add('is-active');
        gsap.set(expertiseTextItems[0], { y: 0, autoAlpha: 1 });

        gsap.set(Array.from(expertiseTextItems).slice(1), { y: 40, autoAlpha: 0 });

        // Setup hover animations with GSAP
        expertiseItemElements.forEach((item, itemIndex) => {
            item.addEventListener('mouseenter', () => {
                expertiseItemElements.forEach(el => el.classList.remove('is-active'));
                item.classList.add('is-active');

                const expertiseImageTransitionTL = gsap.timeline();

                expertiseImageTransitionTL.to(expertiseImageElements, {
                    autoAlpha: 0,
                    zIndex: 0,
                    scale: 1,
                    duration: 0.3,
                    ease: 'power2.inOut'
                });

                expertiseImageTransitionTL.fromTo(
                    expertiseImageElements[itemIndex],
                    { autoAlpha: 0, scale: 1.3, zIndex: 2 },
                    { autoAlpha: 1, scale: 1, zIndex: 2, duration: 0.5, ease: 'power2.out' },
                    '-=0.2'
                );

                expertiseTextItems.forEach((text, index) => {
                    if (index === itemIndex) {
                        text.classList.add('is-active');
                        gsap.to(text, { y: 0, autoAlpha: 1, duration: 0.5, ease: 'power2.out' });
                    } else {
                        text.classList.remove('is-active');
                        gsap.to(text, { y: 40, autoAlpha: 0, duration: 0.5, ease: 'power2.out' });
                    }
                });
            });
        });
    }
Code Block 4

Element Map

  • .home_expertise_figures: Images container; images scale/fade on hover.

  • .home_expertise_image: Individual images.

  • .home_expertise_inner: Items container.

  • .home_expertise_item: Hoverable items.

  • .home_expertise_text_wrap: Texts container.

  • .home_expertise_text: Texts slide in/out.

HTML Requirements

Div home_expertise_figures with multiple home_expertise_image, home_expertise_inner with home_expertise_item, home_expertise_text_wrap with matching home_expertise_text.

Customizing Key Variables

  • Fade duration: Change duration: 0.3 to duration: 0.6 for slower hide.

    expertiseImageTransitionTL.to(expertiseImageElements, {
        autoAlpha: 0,
        zIndex: 0,
        scale: 1,
        duration: 0.6,
        ease: 'power2.inOut'
    });
  • Scale duration: Change duration: 0.5 to duration: 0.7 for slower reveal.

    expertiseImageTransitionTL.fromTo(
        expertiseImageElements[itemIndex],
        { autoAlpha: 0, scale: 1.3, zIndex: 2 },
        { autoAlpha: 1, scale: 1, zIndex: 2, duration: 0.7, ease: 'power2.out' },
        '-=0.2'
    );
  • Ease: 'power2.out' → 'bounce.out'.

Removing Animations

  • Comment/Remove: The code from page settings that are shown in Code Block 4

Location Section with GSAP

What It does

This animates location items on hover, switching images.

    // ============================================
    // LOCATION SECTION WITH GSAP
    // ============================================

    function initLocationAnimations() {
        const locationTextElements = document.querySelectorAll('.location_text');
        const locationImageContainer = document.querySelector('.home_location_image_list');
        const locationImageItems = document.querySelectorAll('.home_location_image_item');

        if (!locationTextElements.length || !locationImageContainer || !locationImageItems.length) return;

        // Initialize with GSAP
        gsap.set(locationImageItems, {
            position: 'absolute',
            top: 0,
            left: 0,
            autoAlpha: 0,
            scale: 0.6
        });

        locationTextElements.forEach(textElement => {
            const locationTitleElement = textElement.querySelector('.location_title');
            if (locationTitleElement) locationTitleElement.classList.remove('is-active');
        });

        // Setup hover animations with GSAP
        locationTextElements.forEach((textElement, textIndex) => {
            textElement.addEventListener('mouseenter', () => {
                locationTextElements.forEach(el => {
                    const title = el.querySelector('.location_title');
                    if (title) title.classList.remove('is-active');
                });

                const hoveredLocationTitle = textElement.querySelector('.location_title');
                if (hoveredLocationTitle) hoveredLocationTitle.classList.add('is-active');

                const locationImageTL = gsap.timeline();

                locationImageTL.to(locationImageItems, {
                    autoAlpha: 0,
                    scale: 0.6,
                    duration: 0.3,
                    ease: 'power2.inOut'
                });

                locationImageTL.fromTo(
                    locationImageItems[textIndex],
                    { autoAlpha: 0, scale: 0.6 },
                    { autoAlpha: 1, scale: 1, duration: 0.5, ease: 'power2.out' },
                    '-=0.15'
                );
            });
        });
    }
Code Block 5

Element Map

  • .location_text: Hoverable text elements.

  • .location_title: Titles activate on hover.

  • .home_location_image_list: Images container.

  • .home_location_image_item: Images scale/fade on hover.

HTML Requirements

Multiple location_text divs each with location_title, home_location_image_list with matching home_location_image_item.

Customizing Key Variables

  • Hide duration: Change duration: 0.3 to duration: 0.5 for slower fade out.

    locationImageTL.to(locationImageItems, {
        autoAlpha: 0,
        scale: 0.6,
        duration: 0.5,
        ease: 'power2.inOut'
    });
  • Reveal duration: Change duration: 0.5 to duration: 0.8 for slower scale in.

    locationImageTL.fromTo(
        locationImageItems[textIndex],
        { autoAlpha: 0, scale: 0.6 },
        { autoAlpha: 1, scale: 1, duration: 0.8, ease: 'power2.out' },
        '-=0.15'
    );

Removing Animations

  • Comment/Remove: The code from page settings that are shown in Code Block 5

Initialize All Animations on Page Load

What It does

This runs all functions when page loads.

    // ============================================
    // INITIALIZE ALL ANIMATIONS ON PAGE LOAD
    // ============================================
    document.addEventListener('DOMContentLoaded', function () {
        initHeroSliderAnimations();
        initTestimonySliderAnimations();
        initExpertiseAnimations();
        initLocationAnimations();
    });
Code Block 6

Element Map

  • No new elements; calls other functions.

Removing Animations

  • Comment out function calls: // initHeroSliderAnimations(); etc.

Counter Animation with GSAP

What It does

This animates counters to count up from 0 on scroll.

HTML Requirements

Elements like <div class="counter">1234</div> with target number as text. Note: Don't includ the comma in original content in Webflow.

   // ============================================
    // COUNTER ANIMATION WITH GSAP
    // ============================================

    function initCounterAnimations() {
        const counterElements = document.querySelectorAll(".counter");

        counterElements?.forEach(counterItem => {
            gsap.from(counterItem, {
                textContent: 0,
                duration: 4,
                ease: "power1.in",
                snap: { textContent: 1 },
                scrollTrigger: {
                    trigger: counterItem,
                    start: "top 95%",
                    once: true
                },
                onUpdate: function () {
                    const counterValue = Math.ceil(parseInt(counterItem.textContent) || 0);
                    counterItem.textContent = counterValue.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
                }
            });
        });
    }

    // ============================================
    // INITIALIZE ANIMATIONS ON PAGE LOAD
    // ============================================
    document.addEventListener('DOMContentLoaded', function () {
        initCounterAnimations();
    });
Code Block 7

Element Map

  • .counter: Text animates from 0 to value, with commas.

Customizing Key Variables

  • Duration: 4 → 6 for slower.

    duration: 6
  • Reveal: 0.5 → 0.7.

    duration: 0.7
  • Ease: "power1.in" → "power2.inOut".

    ease: "power2.inOut"
  • Start: "top 95%" → "top 80%" for delayed trigger.

    start: "top 80%"

Removing Animations

  • Comment/Remove: The code from site settings that are shown in Code Block 7

A living room filled with furniture and plants.
Interested? 
Get in touch

Are you looking to buy or rent a property?