Instruction

Guide for Flops Webflow Template

GSAP Guide

Every GSAP code used on this template is here. How to edit them and find them is explain on this page. In every code block on this page, we added additional explanation to help you understand everything.

You can find the code in (Site settings) Footer Code.

Lenis Smooth Scroll

<script src="https://unpkg.com/lenis@1.3.1/dist/lenis.min.js"></script> 
<script>
  
// lenis smooth scroll
{
  let lenis;

  const initScroll = () => {
    lenis = new Lenis({
      smoothWheel: true,
      smoothTouch: false,
    });

    // Sync GSAP with Lenis
    lenis.on("scroll", ScrollTrigger.update);
    gsap.ticker.add((time) => lenis.raf(time * 1000));
    gsap.ticker.lagSmoothing(0);
  };

  function initGsapGlobal() {
    initScroll();

    const sendGsapEvent = () => {
      window.dispatchEvent(
        new CustomEvent("GSAPReady", {
          detail: { lenis },
        })
      );
    };

    if (document.fonts.status === "loaded") {
      sendGsapEvent();
    } else {
      document.fonts.ready.then(() => sendGsapEvent());
    }

    // --- Handle resize ---
    let resizeTimeout;
    const onResize = () => {
      clearTimeout(resizeTimeout);
      resizeTimeout = setTimeout(() => {
        ScrollTrigger.refresh();
        lenis.resize(); // ๐Ÿ‘ˆ also update Lenis' internal height
      }, 150);
    };
    window.addEventListener("resize", onResize);
    const resizeObserver = new ResizeObserver(() => onResize());
    resizeObserver.observe(document.body);

    // --- Handle lazy loading ---
    const refreshAll = () => {
      lenis.resize();            // ๐Ÿ‘ˆ force Lenis to recalc scroll height
      ScrollTrigger.refresh(true); // ๐Ÿ‘ˆ force GSAP to recalc positions
    };

    // When all page assets (including lazy) are done
    window.addEventListener("load", () => {
      setTimeout(refreshAll, 200); // wait a tick to be safe
    });

    // For each image that loads in later
    document.querySelectorAll("img").forEach((img) => {
      if (!img.complete) {
        img.addEventListener("load", refreshAll);
        img.addEventListener("error", refreshAll); // in case of failed loads
      }
    });

    // Reveal hidden elements after init
    queueMicrotask(() => {
      gsap.to("[data-start='hidden']", {
        autoAlpha: 1,
        duration: 0.1,
        delay: 0.2,
      });
    });
  }

  const documentReady =
    document.readyState === "complete" || document.readyState === "interactive";

  if (documentReady) {
    initGsapGlobal();
  } else {
    addEventListener("DOMContentLoaded", initGsapGlobal);
  }
}

</script>
Lenis Smooth Scroll is a lightweight JavaScript library that enables buttery-smooth, hardware-accelerated scrolling for websites. It works by intercepting the browserโ€™s native scroll behavior and applying eased, customizable motion, creating a more fluid and refined browsing experience. Lenis supports vertical and horizontal scroll, inertia effects, and syncs seamlessly with animations from libraries like GSAP or ScrollTrigger.

Hero Section GSAP Animation

GSAP animation of image inside the cube, it fade the image opacity whenever the cursor is moving and show it again in sequence when the cursor stop moving.
// HERO SECTION
  // Hero image cursor fade
  const images = document.querySelectorAll(".box-image");

  // Start fully visible
  gsap.set(images, { opacity: 1 });

  let movingActive = false;     // true while we're in a "moving" session
  let idleTimer = null;         // checks when movement stops
  let dimTimer = null;          // 0.3s delay before dim
  let brightenTimer = null;     // 0.3s delay before brighten

  let dimTween = null;          // reference to dim tween
  let brightenTween = null;     // reference to brighten tween

  const IDLE_GAP = 200;         // how long without movement = "stopped"
  const DELAY = 300;            // 0.3s before any animation starts

  function startDimAfterDelay() {
    // Only schedule once at the start of a moving session
    if (dimTimer) return;
    dimTimer = setTimeout(() => {
      dimTimer = null;
      // Kill any brighten in progress (movement wins)
      if (brightenTween) { brightenTween.kill(); brightenTween = null; }
      // Dim all to 3%
      dimTween?.kill();
      dimTween = gsap.to(images, { opacity: 0.03, duration: 0.2, onComplete: () => { dimTween = null; } });
    }, DELAY);
  }

  function startBrightenAfterDelay() {
    // Donโ€™t stack multiple brightens
    if (brightenTimer) return;
    brightenTimer = setTimeout(() => {
      brightenTimer = null;
      // Ensure dim tween isn't fighting
      dimTween?.kill(); dimTween = null;
      // Sequential brighten back to 1
      brightenTween?.kill();
      brightenTween = gsap.to(images, {
        opacity: 1,
        duration: 1,
        stagger: 0.3,
        onComplete: () => { brightenTween = null; }
      });
    }, DELAY);
  }

  document.body.addEventListener("mousemove", () => {
    // Movement detected: cancel "about-to-brighten"
    if (brightenTimer) { clearTimeout(brightenTimer); brightenTimer = null; }
    if (brightenTween) { brightenTween.kill(); brightenTween = null; }

    // If we weren't moving before, this is the start of a moving session
    if (!movingActive) {
      movingActive = true;
      startDimAfterDelay(); // schedule one dim after 0.3s
    }

    // Reset idle detection each move
    if (idleTimer) clearTimeout(idleTimer);
    idleTimer = setTimeout(() => {
      // Movement stopped
      movingActive = false;
      // Clear any pending dim that hasn't started yet
      if (dimTimer) { clearTimeout(dimTimer); dimTimer = null; }
      // Brighten sequence after 0.3s
      startBrightenAfterDelay();
    }, IDLE_GAP);
  });
  // END Hero image fade cursor
  

Service Section GSAP Animation

Featuring draggable slider using GSAP animation
// SERVICE SECTION
  
  // Service slider  
  gsap.registerPlugin(Draggable);

  const gallery = document.querySelector(".service-gallery-slide");

  Draggable.create(gallery, {
    type: "x",
    bounds: ".service-gallery", // container element
    inertia: true
  });
  // END Service slider