Brand Logo
Home
About
Services
Pricing
Blog
Contact

Instruction

Easily customize the GSAP animations used throughout the template. To edit the GSAP custom code, navigate to the relevant Page Settings and update the code placed in the “Before </body> tag” section.

<!-- Lenis CSS -->
<link rel="stylesheet" href="https://unpkg.com/lenis@1.1.20/dist/lenis.css">

<!-- Lenis JS -->
<script src="https://unpkg.com/lenis@1.3.1/dist/lenis.min.js"></script>

<script>
window.addEventListener("DOMContentLoaded", () => {

  /*
  --------------------------------
  COUNTER ANIMATION
  --------------------------------
  */

  gsap.utils.toArray(".counter-number").forEach((counter) => {

    const textEl = counter.querySelector("*") || counter;
    const original = textEl.textContent.trim();

    const match = original.match(/^([^0-9]*)([0-9.,]+)(.*)$/);

    if (!match) return;

    const prefix = match[1];
    const numberPart = match[2].replace(/,/g, "");
    const suffix = match[3];

    const hasDecimal = numberPart.includes(".");
    const target = parseFloat(numberPart);

    if (Number.isNaN(target)) return;

    const value = {
      current: 0
    };

    gsap.to(value, {
      current: target,
      duration: 1.2,
      ease: "power1.out",

      scrollTrigger: {
        trigger: counter,
        start: "top 90%",
        once: true
      },

      onUpdate: () => {

        const currentValue = hasDecimal
          ? value.current.toFixed(1)
          : Math.floor(value.current).toLocaleString();

        textEl.textContent =
          prefix +
          currentValue +
          suffix;

      }

    });

  });


  /*
  --------------------------------
  LENIS SMOOTH SCROLL
  --------------------------------
  */

  if (window.matchMedia("(min-width: 768px)").matches) {

    const lenis = new Lenis({
      duration: 1,
      smoothWheel: true,
      smoothTouch: false,
      allowNestedScroll: true,

      easing: (t) => {
        return 1 - Math.pow(1 - t, 3);
      }

    });

    const raf = (time) => {
      lenis.raf(time);
      requestAnimationFrame(raf);
    };

    requestAnimationFrame(raf);

  }


  /*
  --------------------------------
  IMAGE TRAIL
  --------------------------------
  */

  function initImageTrail(wrapper, trailImages, options) {

    const wrapperPosition =
      getComputedStyle(wrapper).position;

    if (wrapperPosition === "static") {
      wrapper.style.position = "relative";
    }


    trailImages.forEach((item) => {

      item.style.position = "absolute";
      item.style.pointerEvents = "none";

      gsap.set(item, {
        autoAlpha: 0
      });

    });


    let globalIndex = 0;

    let last = {
      x: 0,
      y: 0
    };

    let isActive = false;


    function handleMove(e) {

      const rect =
        wrapper.getBoundingClientRect();

      const x =
        e.clientX - rect.left;

      const y =
        e.clientY - rect.top;


      const distance =
        Math.hypot(
          x - last.x,
          y - last.y
        );


      if (
        distance >
        window.innerWidth / options.moveDistance
      ) {

        const item =
          trailImages[
            globalIndex % trailImages.length
          ];

        globalIndex++;


        const img =
          item.querySelector("img");


        gsap.killTweensOf(item);

        if (img) {
          gsap.killTweensOf(img);
        }


        const itemRect =
          item.getBoundingClientRect();


        const startX =
          last.x - itemRect.width / 2;

        const startY =
          last.y - itemRect.height / 2;


        const endX =
          x - itemRect.width / 2;

        const endY =
          y - itemRect.height / 2;


        gsap.set(item, {
          left: startX,
          top: startY,
          zIndex: globalIndex
        });


        if (img) {
          gsap.set(img, {
            opacity: 1,
            scale: 1
          });
        }


        const tl =
          gsap.timeline();


        tl.fromTo(
          item,

          {
            autoAlpha: 0
          },

          {
            autoAlpha: 1,
            duration: 0.2
          }
        );


        tl.fromTo(

          item,

          {
            left: startX,
            top: startY
          },

          {
            left: endX,
            top: endY,
            duration: 0.5
          },

          "<"

        );


        if (img) {

          tl.to(
            img,

            {
              opacity: 0,
              scale: 0.6,
              duration: 0.2
            }

          );

        } else {

          tl.to(

            item,

            {
              autoAlpha: 0,
              scale: 0.6,
              duration: 0.2
            }

          );

        }


        last = {
          x,
          y
        };

      }

    }


    function start() {

      if (isActive) return;

      if (
        window.innerWidth <
        options.minWidth
      ) {
        return;
      }

      isActive = true;

      wrapper.addEventListener(
        "mousemove",
        handleMove
      );

    }


    function stop() {

      if (!isActive) return;

      isActive = false;

      wrapper.removeEventListener(
        "mousemove",
        handleMove
      );

    }


    function handleResize() {

      if (
        window.innerWidth <
        options.minWidth
      ) {

        stop();

      } else {

        start();

      }

    }


    window.addEventListener(
      "resize",
      handleResize
    );


    start();

  }


  /*
  --------------------------------
  IMAGE TRAIL INITIALIZATION
  --------------------------------
  */

  const wrapper =
    document.querySelector(
      '[data-trail="wrapper"]'
    );


  const trailImages =
    gsap.utils.toArray(
      '[data-trail="item"]'
    );


  if (
    wrapper &&
    trailImages.length
  ) {

    initImageTrail(
      wrapper,
      trailImages,

      {
        minWidth: 992,
        moveDistance: 15
      }

    );

  }

});
</script>
demo@consultive.com
Footer Image

Helping businesses unlock their full potential through strategic consulting, innovative solutions, and data-driven decision-making tailored for long-term growth.

Main pages
HomeAboutServicesPricingBlogContact
Inner pages
Case Study DetailsBlog  DetailsInstruction
Utility page
Not FoundPassword  LicensesPrivacy Policy Terms & ConditionsStyleguide
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
©2025 Consultive
Designed By
Zain's Studio
Consultive