Getting Started

Follow the setup instructions below to customize every section of the template quickly and launch your website with confidence.

Down Arrow
Frame ImageFrame Image

Lenis Smooth Scrolling

This provides smooth scrolling across the entire template. To turn off just comment out this code.

<!-- 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>
(function () {


  function initCounterAnimation() {
    if (
      typeof gsap === "undefined" ||
      typeof ScrollTrigger === "undefined"
    ) {
      return;
    }

    gsap.registerPlugin(ScrollTrigger);

    document.querySelectorAll('[class*="wf-counter"]').forEach(function (counter) {
      var textEl = counter.querySelector("*") || counter;
      var original = textEl.textContent.trim();

      var match = original.match(/^([^0-9]*)([0-9.,]+)(.*)$/);
      if (!match) return;

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

      var hasDecimal = numberPart.indexOf(".") !== -1;
      var target = parseFloat(numberPart);

      if (isNaN(target)) return;

      var obj = { value: 0 };

      gsap.to(obj, {
        value: target,
        duration: 1.2,
        ease: "power1.out",
        scrollTrigger: {
          trigger: counter,
          start: "top 90%",
          once: true
        },
        onUpdate: function () {
          var currentValue = hasDecimal
            ? obj.value.toFixed(1)
            : Math.floor(obj.value).toLocaleString();

          textEl.textContent = prefix + currentValue + suffix;
        }
      });
    });
  }



  function initSmoothScroll() {
    if (
      typeof Lenis === "undefined" ||
      !window.matchMedia("(min-width: 768px)").matches
    ) {
      return;
    }

    var lenis = new Lenis({
      duration: 0.8,
      smoothWheel: true,
      smoothTouch: false,
      allowNestedScroll: true,
      easing: function (t) {
        return 1 - Math.pow(1 - t, 3);
      }
    });

    function raf(time) {
      lenis.raf(time);
      requestAnimationFrame(raf);
    }

    requestAnimationFrame(raf);
  }

  function init() {
    initCounterAnimation();
    initSmoothScroll();
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", init);
  } else {
    init();
  }

})();
</script>

GSAP Auto Hero Slider

An auto-playing GSAP hero slider with image zoom, animated progress, and slide counter.

<!-- Hero Slider -->
<script>
const slides = gsap.utils.toArray(".hero-slide");
const progress = document.querySelector(".hero-slider-progress-fill");
const current = document.querySelector(".hero-slider-current");

let index = 0;
const duration = 4;

gsap.set(slides, { autoAlpha: 0 });
gsap.set(slides[0], { autoAlpha: 1 });
gsap.set(progress, { width: "0%" });

function nextSlide() {

  // Hide all slides
  gsap.set(slides, { autoAlpha: 0 });

  // Show active slide
  gsap.set(slides[index], { autoAlpha: 1 });

  // Update counter
  current.textContent = String(index + 1).padStart(2, "0");

  // Reset image scale
  gsap.set(slides[index].querySelector("img"), {
    scale: 1.1
  });

  // Reset progress instantly when loop starts again
  if (index === 0) {
    gsap.set(progress, { width: "0%" });
  }

  const tl = gsap.timeline({
    onComplete: () => {

      index++;

      if (index >= slides.length) {
        index = 0;
      }

      nextSlide();

    }
  });

  // Image zoom
  tl.to(slides[index].querySelector("img"), {
    scale: 1,
    duration: duration,
    ease: "power1.out"
  }, 0);

  // Progress
  tl.to(progress, {
    width: `${((index + 1) / slides.length) * 100}%`,
    duration: duration,
    ease: "none"
  }, 0);

}

nextSlide();

</script>