ToolsWaves
Free GSAP Landing Page Template ยท ToolsWaves ยท E-commerce

Free Health Supplements E-commerce Hero Template

Free supplements and health e-commerce landing page template from ToolsWaves featuring a bottle-filling loader with falling powder particles, animated protein bottles with hover lift, swaying leaves, a green arch, a cart counter scramble, and a paint-stroke footer. Free for any use.

E-commerceHealthSupplementsParticlesHover Effects

About this ToolsWaves template

This free e-commerce landing page template from ToolsWaves is built specifically for wellness, supplement, and nutrition brands. The loader features a bottle being filled with falling powder particles โ€” a fitting metaphor for the product category that visitors will remember. Three protein bottles sit on the page with subtle hover lift animations, swaying leaves frame the scene with natural movement, a green arch grounds the composition, and the cart counter scrambles into its number rather than just appearing.

Use this template for nutrition stores, fitness supplement brands, vitamin shops, or any wellness-adjacent e-commerce site that needs to feel both clean and earthy. ToolsWaves provides this template free for commercial use with no sign-up โ€” copy the three files into your build, swap the demo bottle imagery for your actual product photography, and adjust the green palette via the CSS color variables to match your brand. The paint-stroke footer effect is achieved entirely with CSS and can be removed if it does not fit your aesthetic.

Copy the code

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Free Health Supplements E-commerce Hero Template</title>
  <meta name="description" content="Free GSAP supplements e-commerce landing page hero from ToolsWaves" />
  <meta name="generator" content="ToolsWaves - https://toolswaves.in/landing-pages" />

  <!-- Open Graph -->
  <meta property="og:title" content="Free Health Supplements E-commerce Hero Template" />
  <meta property="og:description" content="Free GSAP supplements e-commerce landing page hero from ToolsWaves" />
  <meta property="og:type" content="website" />
  <meta property="og:image" content="https://toolswaves.in/og?title=Free%20Health%20Supplements%20E-commerce%20Hero%20Template&category=Landing%20Page&icon=%F0%9F%93%84" />

  <!-- Twitter -->
  <meta name="twitter:card" content="summary_large_image" />
  <meta name="twitter:title" content="Free Health Supplements E-commerce Hero Template" />
  <meta name="twitter:description" content="Free GSAP supplements e-commerce landing page hero from ToolsWaves" />
  <meta name="twitter:image" content="https://toolswaves.in/og?title=Free%20Health%20Supplements%20E-commerce%20Hero%20Template&category=Landing%20Page&icon=%F0%9F%93%84" />

  <!-- Bootstrap (used by template โ€” replace with your own framework if you prefer) -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" />

  <style>
* { margin: 0; padding: 0; box-sizing: border-box; }

:root {
    --bg:    #ffffff;
    --ink:   #0f0f10;
    --muted: rgba(15, 15, 16, 0.6);
    --line:  rgba(15, 15, 16, 0.1);
    --green:      #3a9f2a;
    --green-deep: #2d8019;
    --green-soft: #4ab82f;
    --orange:     #f38f2a;
    --orange-deep:#e87817;
    --cream:      #faf7f0;
}

html, body {
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    background: var(--bg);
    color: var(--ink);
    overflow-x: hidden;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

.back-link {
    position: fixed;
    bottom: 0.75rem;
    left: 0.75rem;
    z-index: 1000;
    color: var(--ink);
    text-decoration: none;
    font-size: 0.65rem;
    font-weight: 600;
    letter-spacing: 0.12em;
    padding: 0.45rem 0.9rem;
    background: var(--bg);
    border: 1px solid var(--line);
    border-radius: 999px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
    opacity: 0.85;
    transition: opacity 0.3s, transform 0.3s;
}
.back-link:hover { opacity: 1; transform: translateY(-2px); }

/* =========================================================
   LOADER โ€” Bottle filling
   ========================================================= */
.loader {
    position: fixed;
    inset: 0;
    z-index: 999;
    background: var(--bg);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2rem;
}

.loader__scene {
    position: relative;
    width: 220px;
    height: 420px;
    display: flex;
    align-items: flex-end;
    justify-content: center;
}
.loader__bottle {
    width: 100%;
    height: 100%;
    max-height: 360px;
    filter: drop-shadow(0 20px 30px rgba(0, 0, 0, 0.1));
}

.loader__scoop {
    position: absolute;
    top: -10px;
    left: 50%;
    transform: translateX(-50%) rotate(0deg);
    width: 80px;
    z-index: 3;
    will-change: transform;
}
.loader__scoop svg { width: 100%; height: auto; }

.loader__particles {
    position: absolute;
    top: 35px;
    left: 50%;
    transform: translateX(-50%);
    width: 60px;
    height: 60px;
    pointer-events: none;
    z-index: 2;
}
.loader__particles span {
    position: absolute;
    top: 0;
    left: 50%;
    width: 5px;
    height: 5px;
    background: #b78551;
    border-radius: 50%;
    will-change: transform, opacity;
}

.loader__meta {
    display: flex;
    gap: 1.25rem;
    align-items: center;
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.75rem;
    letter-spacing: 0.25em;
    color: var(--muted);
}
.loader__counter {
    color: var(--green-deep);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    min-width: 3ch;
}

/* =========================================================
   STORE SECTION
   ========================================================= */
.store {
    position: relative;
    width: 100%;
    min-height: 100vh;
    overflow: hidden;
    background: var(--bg);
}

/* ---------- Top nav ---------- */
.topnav {
    position: relative;
    z-index: 30;
    display: flex;
    align-items: center;
    gap: 1.5rem;
    padding: 1.5rem 2.5rem;
}

.topnav__logo {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    text-decoration: none;
    color: var(--ink);
    font-weight: 700;
    font-size: 1.35rem;
    letter-spacing: -0.01em;
    will-change: transform;
}
.topnav__logo-mark { width: 36px; height: 36px; }
.topnav__logo-mark svg { width: 100%; height: 100%; display: block; }
.topnav__logo-text em {
    color: var(--green);
    font-style: normal;
}

.topnav__links {
    display: flex;
    gap: 2rem;
    margin: 0 auto;
}
.topnav__links a {
    position: relative;
    color: var(--ink);
    text-decoration: none;
    font-weight: 500;
    font-size: 0.95rem;
    padding: 0.3rem 0;
    will-change: transform;
}
.topnav__links a.is-active { color: var(--orange); }
.topnav__links a::after {
    content: '';
    position: absolute;
    left: 50%; bottom: -2px;
    width: 100%; height: 2px;
    background: var(--orange);
    transform: translateX(-50%) scaleX(0);
    transition: transform 0.35s cubic-bezier(0.65, 0, 0.35, 1);
}
.topnav__links a:hover::after { transform: translateX(-50%) scaleX(1); }

.topnav__actions {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}
.topnav__icon {
    position: relative;
    width: 42px; height: 42px;
    border-radius: 50%;
    background: none;
    border: none;
    color: var(--ink);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    text-decoration: none;
    will-change: transform;
    transition: background 0.3s;
}
.topnav__icon:hover { background: rgba(15, 15, 16, 0.06); }
.topnav__icon svg { width: 22px; height: 22px; }
.topnav__badge {
    position: absolute;
    top: 4px;
    right: 4px;
    background: var(--orange);
    color: #fff;
    font-size: 0.65rem;
    font-weight: 700;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 999px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
}
.topnav__menu {
    width: 42px; height: 42px;
    background: var(--green);
    color: #fff;
    border: none;
    border-radius: 50%;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    will-change: transform;
    transition: background 0.3s;
}
.topnav__menu svg { width: 18px; height: 18px; }
.topnav__menu:hover { background: var(--green-deep); }

/* ---------- Hero ---------- */
.hero {
    position: relative;
    z-index: 10;
    padding: 2rem 2rem 6rem;
    text-align: center;
    min-height: calc(100vh - 90px);
}

.hero__eyebrow {
    display: block;
    font-size: 0.7rem;
    font-weight: 700;
    color: var(--orange);
    letter-spacing: 0.35em;
    margin-bottom: 1.25rem;
}

.hero__title {
    font-family: 'Inter', sans-serif;
    font-weight: 900;
    font-size: clamp(2rem, 4.8vw, 3.6rem);
    line-height: 1.05;
    letter-spacing: -0.02em;
    color: var(--ink);
    margin: 0 auto 1.75rem;
    max-width: 840px;
}
.hero__line {
    display: block;
    overflow: hidden;
    padding-bottom: 0.04em;
}
.hero__char {
    display: inline-block;
    will-change: transform, color;
    transition: color 0.3s ease;
}
.hero__char.is-space { width: 0.25em; }

.hero__cta {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(135deg, var(--orange), var(--orange-deep));
    color: #fff;
    text-decoration: none;
    padding: 0.9rem 2.25rem;
    border-radius: 999px;
    font-weight: 600;
    font-size: 0.95rem;
    box-shadow: 0 12px 24px rgba(243, 143, 42, 0.35);
    overflow: hidden;
    will-change: transform;
    z-index: 4;
}
.hero__cta-label { position: relative; z-index: 2; }
.hero__cta-glow {
    position: absolute;
    inset: 0;
    background: radial-gradient(ellipse at center, rgba(255, 255, 255, 0.3) 0%, transparent 60%);
    opacity: 0;
    z-index: 1;
}

/* ---------- Bottles scene ---------- */
.bottles {
    position: relative;
    height: clamp(320px, 38vw, 440px);
    margin: 0 auto;
    max-width: 1100px;
}

.bottles__arch {
    position: absolute;
    left: 50%;
    bottom: 4%;
    transform: translateX(-50%);
    width: 70%;
    max-width: 700px;
    aspect-ratio: 2 / 1;
    background: radial-gradient(ellipse at center, var(--green-soft) 0%, var(--green) 60%, var(--green-deep) 100%);
    border-radius: 100% 100% 0 0 / 100% 100% 0 0;
    z-index: 1;
    will-change: transform;
    box-shadow: inset 0 -20px 60px rgba(0, 0, 0, 0.15);
}

.bottle {
    position: absolute;
    bottom: 0;
    z-index: 3;
    width: clamp(130px, 14vw, 170px);
    cursor: pointer;
    will-change: transform;
    filter: drop-shadow(0 30px 30px rgba(0, 0, 0, 0.3));
}
.bottle svg { width: 100%; height: auto; display: block; }
.bottle--left {
    left: calc(50% - 250px);
    z-index: 2;
}
.bottle--center {
    left: calc(50% - 90px);
    z-index: 4;
}
.bottle--right {
    left: calc(50% + 70px);
    z-index: 2;
}

/* Leaves */
.leaf {
    position: absolute;
    width: 60px;
    height: 100px;
    will-change: transform;
    z-index: 5;
}
.leaf--1 { top: -60px; left: -30px;  transform: rotate(-30deg); }
.leaf--2 { top: 20%;   left: -60px;  transform: rotate(40deg); width: 80px; height: 130px; }
.leaf--3 { top: -40px; right: -20px; transform: rotate(40deg); }
.leaf--4 { top: 30%;   right: -50px; transform: rotate(-20deg); width: 70px; height: 120px; }
.leaf--5 { bottom: 10%; right: -80px; transform: rotate(15deg); }

/* Scoop + bowl */
.scoop, .bowl {
    position: absolute;
    bottom: 0;
    width: 160px;
    height: 140px;
    z-index: 6;
    border-radius: 14px;
    overflow: hidden;
    will-change: transform;
}
.scoop { left: -30px; }
.bowl  { right: -30px; }
.scoop img, .bowl img {
    width: 100%; height: 100%;
    object-fit: cover;
    user-select: none;
}

/* ---------- Partners ---------- */
.partners {
    margin-top: 3.5rem;
    padding: 0 2rem;
}
.partners__divider {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    margin-bottom: 1.5rem;
}
.partners__dash {
    display: inline-block;
    width: 30px;
    height: 2px;
    background: var(--orange);
}
.partners__text {
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.25em;
    color: var(--muted);
}
.partners__logos {
    display: flex;
    justify-content: center;
    align-items: center;
    flex-wrap: wrap;
    gap: 2.5rem;
}
.partners__logo {
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--ink);
    opacity: 0.6;
    letter-spacing: -0.01em;
    display: inline-flex;
    align-items: center;
    gap: 0.2rem;
    cursor: pointer;
    filter: grayscale(1);
    will-change: transform;
    transition: filter 0.35s ease, opacity 0.35s ease;
}
.partners__logo em, .partners__logo b {
    font-style: normal;
    color: var(--green);
}
.partners__logo:hover {
    opacity: 1;
    filter: grayscale(0);
}

/* ---------- Paint stroke ---------- */
.paint-stroke {
    position: absolute;
    left: 0; right: 0;
    bottom: 0;
    width: 100%;
    height: 70px;
    z-index: 2;
}

/* ---------- Initial states ---------- */
[data-magnetic], [data-link], [data-fade], [data-title-line] .hero__char,
[data-bottle], [data-leaf], [data-scoop], [data-bowl], [data-cta], [data-arch], [data-partner] {
    opacity: 0;
}

/* ---------- Responsive ---------- */
@media (max-width: 1100px) {
    .topnav__links { display: none; }
}
@media (max-width: 760px) {
    .topnav { padding: 1rem 1.25rem; gap: 0.5rem; }
    .topnav__logo-text { font-size: 1.1rem; }
    .hero { padding: 1rem 1.25rem 5rem; }
    .hero__title { font-size: clamp(1.5rem, 7vw, 2.5rem); }
    .bottle--left  { left: calc(50% - 180px); width: 110px; }
    .bottle--right { left: calc(50% + 40px);  width: 110px; }
    .scoop, .bowl { width: 110px; height: 100px; }
    .scoop { left: -15px; }
    .bowl  { right: -15px; }
    .partners__logos { gap: 1.5rem; }
    .partners__logo { font-size: 0.9rem; }
    .leaf { width: 40px !important; height: 70px !important; }
}
@media (max-width: 480px) {
    .hero__eyebrow { font-size: 0.6rem; letter-spacing: 0.2em; }
    .bottles { height: 280px; }
    .bottle--left  { left: calc(50% - 140px); width: 85px; }
    .bottle--right { left: calc(50% + 30px);  width: 85px; }
    .bottle--center { width: 110px; }
    .scoop, .bowl { width: 80px; height: 70px; }
    .partners__logos { gap: 1rem; }
    .partners__logo { font-size: 0.75rem; }
    .topnav__menu { width: 36px; height: 36px; }
    .leaf--2, .leaf--4 { display: none; }
}

  </style>
</head>
<body>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Banner โ€” Supplements Store</title>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&family=JetBrains+Mono:wght@500;600&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="banner-supplements-store.css">
</head>
<body>
    

    <!-- ========== LOADER โ€” Protein bottle filling ========== -->
    <div class="loader" id="loader">
        <div class="loader__scene">
            <!-- Scoop pouring from top (small) -->
            <div class="loader__scoop" id="loader-scoop">
                <svg viewBox="0 0 80 50" aria-hidden="true">
                    <ellipse cx="40" cy="25" rx="28" ry="18" fill="#cfa172"/>
                    <ellipse cx="40" cy="22" rx="26" ry="14" fill="#b78551"/>
                    <rect x="50" y="10" width="4" height="20" fill="#8b5a2b" transform="rotate(25 52 20)"/>
                </svg>
            </div>
            <!-- Falling particles -->
            <div class="loader__particles" id="loader-particles"></div>
            <!-- Bottle SVG -->
            <svg class="loader__bottle" viewBox="0 0 200 340" aria-hidden="true">
                <!-- Cap -->
                <rect x="60" y="0" width="80" height="36" rx="4" fill="#0a0a0a"/>
                <rect x="64" y="4" width="72" height="4" fill="#2a2a2a"/>
                <!-- Neck -->
                <rect x="70" y="32" width="60" height="18" fill="#1a1a1a"/>
                <!-- Body outline -->
                <rect x="30" y="48" width="140" height="280" rx="8" fill="none" stroke="#0a0a0a" stroke-width="3"/>
                <!-- Fill mask -->
                <defs>
                    <clipPath id="bottleClip">
                        <rect x="32" y="50" width="136" height="276" rx="6"/>
                    </clipPath>
                </defs>
                <g clip-path="url(#bottleClip)">
                    <rect id="loader-fill" x="32" y="326" width="136" height="0" fill="url(#liquidGrad)"/>
                    <!-- Foam bubbles on top of liquid -->
                    <g id="loader-foam"></g>
                </g>
                <defs>
                    <linearGradient id="liquidGrad" x1="0" x2="0" y1="0" y2="1">
                        <stop offset="0%"  stop-color="#5ec13f"/>
                        <stop offset="100%" stop-color="#2d8019"/>
                    </linearGradient>
                </defs>
            </svg>
        </div>
        <div class="loader__meta">
            <span class="loader__label" id="loader-label">MIXING</span>
            <span class="loader__counter" id="loader-counter">0%</span>
        </div>
    </div>

    <section class="store" id="store">

        <!-- ========== TOP NAV ========== -->
        <header class="topnav">
            <a href="#" class="topnav__logo" data-magnetic>
                <span class="topnav__logo-mark">
                    <svg viewBox="0 0 40 40" aria-hidden="true">
                        <path d="M8 20 Q 12 6 20 8 Q 28 10 32 20 Q 28 30 20 32 Q 12 30 8 20 Z" fill="#4ab82f"/>
                        <path d="M20 8 Q 16 16 20 24 Q 24 16 20 8" fill="#2d8019"/>
                        <circle cx="20" cy="20" r="3" fill="#fff"/>
                    </svg>
                </span>
                <span class="topnav__logo-text">Brand<em>.</em></span>
            </a>

            <nav class="topnav__links">
                <a href="#" class="is-active" data-magnetic data-link>Home</a>
                <a href="#" data-magnetic data-link>Features</a>
                <a href="#" data-magnetic data-link>Ingredient</a>
                <a href="#" data-magnetic data-link>Gallery</a>
                <a href="#" data-magnetic data-link>Pricing</a>
                <a href="#" data-magnetic data-link>News</a>
                <a href="#" data-magnetic data-link>Shop</a>
                <a href="#" data-magnetic data-link>Contact</a>
            </nav>

            <div class="topnav__actions">
                <a href="#" class="topnav__icon topnav__cart" data-magnetic data-cart>
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
                        <path d="M6 6h15l-1.5 9h-12z"/>
                        <circle cx="10" cy="20" r="1.5"/>
                        <circle cx="18" cy="20" r="1.5"/>
                        <path d="M3 3h3l.5 3"/>
                    </svg>
                    <span class="topnav__badge" id="cart-count">3</span>
                </a>
                <button class="topnav__icon topnav__search" data-magnetic id="search-btn" aria-label="Search">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
                        <circle cx="11" cy="11" r="7"/>
                        <path d="M20 20l-4-4" stroke-linecap="round"/>
                    </svg>
                </button>
                <button class="topnav__menu" data-magnetic aria-label="Menu">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                        <circle cx="6"  cy="6"  r="1.5" fill="currentColor"/>
                        <circle cx="12" cy="6"  r="1.5" fill="currentColor"/>
                        <circle cx="18" cy="6"  r="1.5" fill="currentColor"/>
                        <circle cx="6"  cy="12" r="1.5" fill="currentColor"/>
                        <circle cx="12" cy="12" r="1.5" fill="currentColor"/>
                        <circle cx="18" cy="12" r="1.5" fill="currentColor"/>
                        <circle cx="6"  cy="18" r="1.5" fill="currentColor"/>
                        <circle cx="12" cy="18" r="1.5" fill="currentColor"/>
                        <circle cx="18" cy="18" r="1.5" fill="currentColor"/>
                    </svg>
                </button>
            </div>
        </header>

        <!-- ========== MAIN HERO ========== -->
        <div class="hero" id="hero">
            <span class="hero__eyebrow" data-fade>&hellip;INCREASED ENERGY WITH BRAND&hellip;</span>

            <h1 class="hero__title" aria-label="Mix Protein Provided Way To Growth">
                <span class="hero__line" data-title-line>MIX PROTEIN PROVIDED WAY</span>
                <span class="hero__line" data-title-line>TO GROWTH</span>
            </h1>

            <a href="#" class="hero__cta" data-magnetic data-cta>
                <span class="hero__cta-label">Shop Now</span>
                <span class="hero__cta-glow"></span>
            </a>

            <!-- Bottles scene -->
            <div class="bottles" id="bottles">
                <div class="bottles__arch" data-arch></div>

                <!-- Leaves scattered -->
                <svg class="leaf leaf--1" data-leaf viewBox="0 0 80 140" aria-hidden="true">
                    <path d="M40 5 Q 75 30 70 90 Q 50 135 10 125 Q 0 80 40 5 Z" fill="#3a9f2a"/>
                    <path d="M40 5 Q 30 60 20 125" stroke="#1f6519" stroke-width="1.5" fill="none"/>
                </svg>
                <svg class="leaf leaf--2" data-leaf viewBox="0 0 80 140" aria-hidden="true">
                    <path d="M40 5 Q 75 30 70 90 Q 50 135 10 125 Q 0 80 40 5 Z" fill="#4ab82f"/>
                    <path d="M40 5 Q 30 60 20 125" stroke="#1f6519" stroke-width="1.5" fill="none"/>
                </svg>
                <svg class="leaf leaf--3" data-leaf viewBox="0 0 80 140" aria-hidden="true">
                    <path d="M40 5 Q 75 30 70 90 Q 50 135 10 125 Q 0 80 40 5 Z" fill="#2d8019"/>
                    <path d="M40 5 Q 30 60 20 125" stroke="#1a4a12" stroke-width="1.5" fill="none"/>
                </svg>
                <svg class="leaf leaf--4" data-leaf viewBox="0 0 80 140" aria-hidden="true">
                    <path d="M40 5 Q 75 30 70 90 Q 50 135 10 125 Q 0 80 40 5 Z" fill="#3a9f2a"/>
                    <path d="M40 5 Q 30 60 20 125" stroke="#1f6519" stroke-width="1.5" fill="none"/>
                </svg>
                <svg class="leaf leaf--5" data-leaf viewBox="0 0 80 140" aria-hidden="true">
                    <path d="M40 5 Q 75 30 70 90 Q 50 135 10 125 Q 0 80 40 5 Z" fill="#4ab82f"/>
                    <path d="M40 5 Q 30 60 20 125" stroke="#1f6519" stroke-width="1.5" fill="none"/>
                </svg>

                <!-- 3 product bottles -->
                <div class="bottle bottle--left" data-bottle>
                    <svg viewBox="0 0 200 340" aria-hidden="true">
                        <rect x="60" y="0" width="80" height="36" rx="4" fill="#0a0a0a"/>
                        <rect x="64" y="4" width="72" height="4" fill="#2a2a2a"/>
                        <rect x="70" y="32" width="60" height="18" fill="#1a1a1a"/>
                        <rect x="30" y="48" width="140" height="280" rx="8" fill="#0a0a0a"/>
                        <rect x="40" y="85" width="120" height="205" rx="4" fill="#161616"/>
                        <polygon points="40,85 100,180 40,265" fill="#4ab82f"/>
                        <text x="100" y="165" text-anchor="middle" font-family="Inter, sans-serif" font-size="44" font-weight="900" fill="#fff" letter-spacing="-2">MB</text>
                        <rect x="50" y="200" width="100" height="1.5" fill="#fff" opacity="0.4"/>
                        <text x="100" y="225" text-anchor="middle" font-family="Inter, sans-serif" font-size="14" font-weight="700" fill="#fff" letter-spacing="2">WHEY</text>
                        <text x="100" y="248" text-anchor="middle" font-family="Inter, sans-serif" font-size="18" font-weight="900" fill="#4ab82f" letter-spacing="1">GOLD</text>
                    </svg>
                </div>
                <div class="bottle bottle--center" data-bottle>
                    <svg viewBox="0 0 200 340" aria-hidden="true">
                        <rect x="60" y="0" width="80" height="36" rx="4" fill="#0a0a0a"/>
                        <rect x="64" y="4" width="72" height="4" fill="#2a2a2a"/>
                        <rect x="70" y="32" width="60" height="18" fill="#1a1a1a"/>
                        <rect x="30" y="48" width="140" height="280" rx="8" fill="#0a0a0a"/>
                        <rect x="40" y="85" width="120" height="205" rx="4" fill="#161616"/>
                        <polygon points="40,85 100,180 40,265" fill="#4ab82f"/>
                        <text x="100" y="165" text-anchor="middle" font-family="Inter, sans-serif" font-size="44" font-weight="900" fill="#fff" letter-spacing="-2">MB</text>
                        <rect x="50" y="200" width="100" height="1.5" fill="#fff" opacity="0.4"/>
                        <text x="100" y="225" text-anchor="middle" font-family="Inter, sans-serif" font-size="14" font-weight="700" fill="#fff" letter-spacing="2">WHEY</text>
                        <text x="100" y="248" text-anchor="middle" font-family="Inter, sans-serif" font-size="18" font-weight="900" fill="#4ab82f" letter-spacing="1">GOLD</text>
                    </svg>
                </div>
                <div class="bottle bottle--right" data-bottle>
                    <svg viewBox="0 0 200 340" aria-hidden="true">
                        <rect x="60" y="0" width="80" height="36" rx="4" fill="#0a0a0a"/>
                        <rect x="64" y="4" width="72" height="4" fill="#2a2a2a"/>
                        <rect x="70" y="32" width="60" height="18" fill="#1a1a1a"/>
                        <rect x="30" y="48" width="140" height="280" rx="8" fill="#0a0a0a"/>
                        <rect x="40" y="85" width="120" height="205" rx="4" fill="#161616"/>
                        <polygon points="40,85 100,180 40,265" fill="#4ab82f"/>
                        <text x="100" y="165" text-anchor="middle" font-family="Inter, sans-serif" font-size="44" font-weight="900" fill="#fff" letter-spacing="-2">MB</text>
                        <rect x="50" y="200" width="100" height="1.5" fill="#fff" opacity="0.4"/>
                        <text x="100" y="225" text-anchor="middle" font-family="Inter, sans-serif" font-size="14" font-weight="700" fill="#fff" letter-spacing="2">WHEY</text>
                        <text x="100" y="248" text-anchor="middle" font-family="Inter, sans-serif" font-size="18" font-weight="900" fill="#4ab82f" letter-spacing="1">GOLD</text>
                    </svg>
                </div>

                <!-- Scoop + bowl accents (Unsplash) -->
                <div class="scoop" data-scoop>
                    <img src="https://images.unsplash.com/photo-1610725664285-7c57e6eeac3f?auto=format&fit=crop&w=260&q=75"
                         alt="" draggable="false" onerror="this.style.display='none'">
                </div>
                <div class="bowl" data-bowl>
                    <img src="https://images.unsplash.com/photo-1536594519042-88f9e4a3b00d?auto=format&fit=crop&w=260&q=75"
                         alt="" draggable="false" onerror="this.style.display='none'">
                </div>
            </div>

            <!-- Partners strip -->
            <div class="partners" data-fade>
                <div class="partners__divider">
                    <span class="partners__dash"></span>
                    <span class="partners__text">PERFECT BRAND IS FEATURED ON</span>
                    <span class="partners__dash"></span>
                </div>
                <div class="partners__logos">
                    <span class="partners__logo" data-partner>mollie</span>
                    <span class="partners__logo" data-partner>affirm</span>
                    <span class="partners__logo" data-partner>Paysafe<em>:</em></span>
                    <span class="partners__logo" data-partner>Qlik <b>Q</b></span>
                    <span class="partners__logo" data-partner>Walmart <em>&#10032;</em></span>
                    <span class="partners__logo" data-partner>&#9744; Square</span>
                </div>
            </div>
        </div>

        <!-- Green paint-stroke bottom -->
        <svg class="paint-stroke" viewBox="0 0 1440 90" preserveAspectRatio="none" aria-hidden="true">
            <path d="M0 70 Q 60 40 120 62 T 240 58 T 360 64 T 480 50 T 600 68 T 720 52 T 840 66 T 960 48 T 1080 64 T 1200 54 T 1320 66 T 1440 58 L 1440 90 L 0 90 Z"
                  fill="#2d8019"/>
            <path d="M0 76 Q 60 50 120 68 T 240 64 T 360 70 T 480 56 T 600 74 T 720 58 T 840 72 T 960 54 T 1080 70 T 1200 60 T 1320 72 T 1440 64 L 1440 90 L 0 90 Z"
                  fill="#3a9f2a" opacity="0.7"/>
        </svg>
    </section>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
    <script src="banner-supplements-store.js"></script>
</body>
</html>

</body>
</html>
JSbanner-supplements-store.jsโ€” GSAP animation timeline
(() => {
    const root = document.getElementById('store');
    if (!root) return;

    // -------------------------------------------------------------------
    //  SPLIT TITLE INTO CHARS
    // -------------------------------------------------------------------
    const titleLines = root.querySelectorAll('[data-title-line]');
    titleLines.forEach((line) => {
        const text = line.textContent;
        line.textContent = '';
        [...text].forEach((ch) => {
            const span = document.createElement('span');
            span.className = 'hero__char';
            if (ch === ' ') { span.classList.add('is-space'); span.innerHTML = '&nbsp;'; }
            else span.textContent = ch;
            line.appendChild(span);
        });
    });

    // -------------------------------------------------------------------
    //  BUILD FALLING PARTICLES (loader)
    // -------------------------------------------------------------------
    const particles = document.getElementById('loader-particles');
    const PARTICLE_COUNT = 18;
    for (let i = 0; i < PARTICLE_COUNT; i++) particles.appendChild(document.createElement('span'));
    const particleEls = particles.querySelectorAll('span');

    // -------------------------------------------------------------------
    //  REFERENCES
    // -------------------------------------------------------------------
    const loader = document.getElementById('loader');
    const loaderCounter = document.getElementById('loader-counter');
    const loaderLabel = document.getElementById('loader-label');
    const loaderScoop = document.getElementById('loader-scoop');
    const loaderFill = document.getElementById('loader-fill');
    const loaderFoam = document.getElementById('loader-foam');

    const magnetics = root.querySelectorAll('[data-magnetic]');
    const titleChars = root.querySelectorAll('.hero__char');
    const fades = root.querySelectorAll('[data-fade]');
    const bottles = root.querySelectorAll('[data-bottle]');
    const leaves = root.querySelectorAll('[data-leaf]');
    const scoop = root.querySelector('[data-scoop]');
    const bowl = root.querySelector('[data-bowl]');
    const cta = root.querySelector('[data-cta]');
    const ctaGlow = root.querySelector('.hero__cta-glow');
    const arch = root.querySelector('[data-arch]');
    const partners = root.querySelectorAll('[data-partner]');
    const cartEl = root.querySelector('[data-cart]');
    const cartCount = document.getElementById('cart-count');

    // Bottle base transforms (so parallax preserves the rotation/scale)
    const bottleBaseRot = [-8, 0, 8];
    const bottleBaseScale = [1, 1.15, 1];

    // -------------------------------------------------------------------
    //  INITIAL STATES
    // -------------------------------------------------------------------
    gsap.set(magnetics, { y: -20, opacity: 0 });
    gsap.set(fades, { y: 20, opacity: 0 });
    gsap.set(titleChars, { yPercent: 110, opacity: 0 });
    gsap.set(cta, { y: 30, opacity: 0, scale: 0.9 });
    gsap.set(arch, { scale: 0.2, opacity: 0, transformOrigin: 'center bottom' });

    gsap.set(bottles[0], { y: 120, opacity: 0, rotation: -8 });
    gsap.set(bottles[1], { y: 140, opacity: 0, rotation: 0, scale: 1.15 });
    gsap.set(bottles[2], { y: 120, opacity: 0, rotation: 8 });

    gsap.set(leaves, { scale: 0, opacity: 0, transformOrigin: 'center center' });
    gsap.set(scoop, { y: 60, x: -40, opacity: 0, rotation: -20 });
    gsap.set(bowl, { y: 60, x: 40, opacity: 0, rotation: 20 });
    gsap.set(partners, { y: 10, opacity: 0 });

    // -------------------------------------------------------------------
    //  LOADER TIMELINE โ€” Bottle fills with powder
    // -------------------------------------------------------------------
    const loaderTl = gsap.timeline({ onComplete: playScene });

    // Scoop tilts back and forth (pouring)
    gsap.to(loaderScoop, {
        rotation: 12,
        duration: 0.8,
        yoyo: true,
        repeat: -1,
        ease: 'sine.inOut',
        transformOrigin: '30% 50%',
    });

    // Particles fall continuously
    particleEls.forEach((el, i) => {
        const delay = (i % 6) * 0.15;
        gsap.fromTo(el,
            {
                y: 0,
                x: () => gsap.utils.random(-18, 18),
                opacity: 1,
                scale: gsap.utils.random(0.6, 1.2),
            },
            {
                y: 280,
                opacity: 0,
                duration: () => gsap.utils.random(1.2, 1.8),
                repeat: -1,
                delay,
                ease: 'power1.in',
            }
        );
    });

    // Counter + bottle fill
    const p = { v: 0 };
    loaderTl.to(p, {
        v: 100,
        duration: 2.4,
        ease: 'power1.inOut',
        onUpdate: () => {
            const v = p.v;
            loaderCounter.textContent = Math.floor(v) + '%';
            // Fill animates from bottom (y=326) growing upward
            const fillHeight = (v / 100) * 260;
            loaderFill.setAttribute('height', fillHeight);
            loaderFill.setAttribute('y', 326 - fillHeight);

            // Foam bubbles at liquid surface (only when filling)
            if (Math.random() > 0.85 && v < 98) {
                const bubble = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
                const x = 40 + Math.random() * 120;
                const y = 326 - fillHeight + 2;
                bubble.setAttribute('cx', x);
                bubble.setAttribute('cy', y);
                bubble.setAttribute('r', 1.5 + Math.random() * 2);
                bubble.setAttribute('fill', '#9ed67e');
                bubble.setAttribute('opacity', '0.8');
                loaderFoam.appendChild(bubble);
                gsap.to(bubble, {
                    cy: y - 10,
                    opacity: 0,
                    duration: 0.6,
                    onComplete: () => bubble.remove(),
                });
            }

            // Label changes at thresholds
            if (v > 30 && loaderLabel.textContent === 'MIXING') loaderLabel.textContent = 'SHAKING';
            if (v > 65 && loaderLabel.textContent === 'SHAKING') loaderLabel.textContent = 'ALMOST THERE';
            if (v > 95 && loaderLabel.textContent === 'ALMOST THERE') loaderLabel.textContent = 'READY TO SERVE';
        },
    });

    // Exit: bottle shakes like a shaker, then whole scene fades
    loaderTl.to(loaderScoop, { opacity: 0, duration: 0.3, y: -40 }, '+=0.1');
    loaderTl.to('.loader__bottle', {
        rotation: -3,
        duration: 0.08,
        yoyo: true,
        repeat: 5,
        ease: 'sine.inOut',
        transformOrigin: 'center bottom',
    }, '<');

    loaderTl.to([loaderCounter, loaderLabel], {
        y: -10, opacity: 0, duration: 0.3, stagger: 0.05,
    }, '-=0.3');
    loaderTl.to('.loader__scene', {
        scale: 1.1, opacity: 0, y: -30, duration: 0.6, ease: 'power3.in',
    }, '-=0.2');
    loaderTl.to(loader, {
        opacity: 0, duration: 0.4, ease: 'power2.inOut',
    }, '-=0.3');
    loaderTl.set(loader, { display: 'none' });

    // -------------------------------------------------------------------
    //  MAIN SCENE ENTRANCE
    // -------------------------------------------------------------------
    function playScene() {
        const tl = gsap.timeline({ defaults: { ease: 'power3.out' } });

        // Nav
        tl.to(magnetics, {
            y: 0, opacity: 1,
            duration: 0.6,
            stagger: 0.05,
        }, 0);

        // Eyebrow + fades (except partners)
        tl.to(fades[0], { y: 0, opacity: 1, duration: 0.6 }, 0.3);

        // Title chars
        tl.to(titleChars, {
            yPercent: 0, opacity: 1,
            duration: 1,
            stagger: 0.02,
            ease: 'expo.out',
        }, 0.5);

        // CTA
        tl.to(cta, {
            y: 0, opacity: 1, scale: 1,
            duration: 0.7,
            ease: 'back.out(1.6)',
        }, 0.9);

        // Green arch scales up
        tl.to(arch, {
            scale: 1, opacity: 1,
            duration: 1.2,
            ease: 'power4.out',
        }, 1);

        // Bottles drop in (side ones first, center last with bounce)
        tl.to(bottles[0], {
            y: 0, opacity: 1,
            duration: 1,
            ease: 'power4.out',
        }, 1.2);
        tl.to(bottles[2], {
            y: 0, opacity: 1,
            duration: 1,
            ease: 'power4.out',
        }, 1.3);
        tl.to(bottles[1], {
            y: 0, opacity: 1,
            duration: 1.2,
            ease: 'back.out(1.4)',
        }, 1.4);

        // Leaves bloom in
        tl.to(leaves, {
            scale: 1, opacity: 1,
            duration: 0.8,
            stagger: 0.07,
            ease: 'back.out(2)',
        }, 1.3);

        // Scoop + bowl
        tl.to([scoop, bowl], {
            y: 0, x: 0, opacity: 1, rotation: 0,
            duration: 0.9,
            stagger: 0.1,
            ease: 'power4.out',
        }, 1.5);

        // Partners (from the outer fade group 1 onwards)
        if (fades[1]) tl.to(fades[1], { y: 0, opacity: 1, duration: 0.6 }, 1.9);
        tl.to(partners, {
            y: 0, opacity: 0.6,
            duration: 0.5,
            stagger: 0.06,
        }, 2);

        tl.call(startContinuous, null, 2.2);
        tl.call(enableInteractions, null, 2.2);
    }

    // -------------------------------------------------------------------
    //  CONTINUOUS ANIMATIONS
    // -------------------------------------------------------------------
    function startContinuous() {
        // CTA glow pulse
        gsap.to(ctaGlow, {
            opacity: 0.7,
            duration: 1.2,
            yoyo: true,
            repeat: -1,
            ease: 'sine.inOut',
        });

        // Leaves sway individually
        leaves.forEach((leaf, i) => {
            gsap.to(leaf, {
                rotation: `+=${i % 2 === 0 ? 6 : -6}`,
                duration: 3 + i * 0.3,
                yoyo: true,
                repeat: -1,
                ease: 'sine.inOut',
                transformOrigin: 'bottom center',
            });
        });

        // Bottles subtle idle bob (individual per bottle, factored into parallax)
        bottles.forEach((b, i) => {
            b.dataset.idleT = String(i * 0.7);
        });
    }

    // -------------------------------------------------------------------
    //  INTERACTIONS
    // -------------------------------------------------------------------
    function enableInteractions() {

        // ---- Magnetic ----
        magnetics.forEach((el) => {
            const strength = el.classList.contains('hero__cta') ? 0.35
                : el.classList.contains('topnav__menu') ? 0.4
                : el.classList.contains('topnav__icon') ? 0.3
                : el.classList.contains('topnav__logo') ? 0.2
                : 0.22;
            el.addEventListener('mousemove', (e) => {
                const r = el.getBoundingClientRect();
                const cx = r.left + r.width / 2;
                const cy = r.top + r.height / 2;
                gsap.to(el, {
                    x: (e.clientX - cx) * strength,
                    y: (e.clientY - cy) * strength,
                    duration: 0.4, ease: 'power3.out',
                });
            });
            el.addEventListener('mouseleave', () => {
                gsap.to(el, { x: 0, y: 0, duration: 0.6, ease: 'elastic.out(1, 0.4)' });
            });
        });

        // ---- Title char proximity + hover ----
        const hero = document.getElementById('hero');
        let tmx = -9999, tmy = -9999;
        hero.addEventListener('mousemove', (e) => { tmx = e.clientX; tmy = e.clientY; });
        hero.addEventListener('mouseleave', () => {
            tmx = -9999; tmy = -9999;
            titleChars.forEach((c) => gsap.to(c, { y: 0, duration: 0.5, ease: 'power3.out' }));
        });
        gsap.ticker.add(() => {
            if (tmx < 0) return;
            titleChars.forEach((c) => {
                const r = c.getBoundingClientRect();
                if (r.width === 0) return;
                const cx = r.left + r.width / 2;
                const cy = r.top + r.height / 2;
                const dx = tmx - cx, dy = tmy - cy;
                const dist = Math.sqrt(dx * dx + dy * dy);
                if (dist < 140) gsap.set(c, { y: -(1 - dist / 140) * 12 });
                else gsap.set(c, { y: 0 });
            });
        });
        titleChars.forEach((c) => {
            c.addEventListener('mouseenter', () => gsap.to(c, { color: '#3a9f2a', duration: 0.2 }));
            c.addEventListener('mouseleave', () => gsap.to(c, { color: '#0f0f10', duration: 0.4 }));
        });

        // ---- Cart counter scramble on hover ----
        cartEl.addEventListener('mouseenter', () => {
            const start = parseInt(cartCount.textContent, 10) || 0;
            const target = start + 1 + Math.floor(Math.random() * 3);
            const obj = { v: start };
            gsap.to(obj, {
                v: target,
                duration: 0.4,
                snap: 'v',
                ease: 'power2.out',
                onUpdate: () => cartCount.textContent = Math.round(obj.v),
            });
            gsap.fromTo(cartEl.querySelector('.topnav__badge'),
                { scale: 1 },
                { scale: 1.4, duration: 0.2, yoyo: true, repeat: 1, ease: 'back.out(2)' }
            );
        });
        cartEl.addEventListener('mouseleave', () => {
            setTimeout(() => {
                const obj = { v: parseInt(cartCount.textContent, 10) || 0 };
                gsap.to(obj, {
                    v: 3,
                    duration: 0.4,
                    snap: 'v',
                    ease: 'power2.in',
                    onUpdate: () => cartCount.textContent = Math.round(obj.v),
                });
            }, 300);
        });

        // ---- Bottle hover: lift + tilt ----
        bottles.forEach((b, i) => {
            b.addEventListener('mouseenter', () => {
                const baseRot = bottleBaseRot[i];
                const baseScale = bottleBaseScale[i];
                gsap.to(b, {
                    y: -25,
                    rotation: baseRot * 0.3,
                    scale: baseScale * 1.08,
                    duration: 0.5,
                    ease: 'back.out(2)',
                });
            });
            b.addEventListener('mouseleave', () => {
                gsap.to(b, {
                    y: 0,
                    rotation: bottleBaseRot[i],
                    scale: bottleBaseScale[i],
                    duration: 0.7,
                    ease: 'elastic.out(1, 0.4)',
                });
            });

            // Click: shake
            b.addEventListener('click', (e) => {
                e.preventDefault();
                gsap.fromTo(b,
                    { rotation: bottleBaseRot[i] - 6 },
                    {
                        rotation: bottleBaseRot[i] + 6,
                        duration: 0.08,
                        yoyo: true,
                        repeat: 5,
                        ease: 'sine.inOut',
                        onComplete: () => gsap.to(b, { rotation: bottleBaseRot[i], duration: 0.3 }),
                    }
                );
            });
        });

        // ---- Leaves: follow cursor slightly ----
        leaves.forEach((leaf, i) => {
            leaf.addEventListener('mouseenter', () => {
                gsap.to(leaf, {
                    scale: 1.15,
                    duration: 0.4,
                    ease: 'back.out(2)',
                });
            });
            leaf.addEventListener('mouseleave', () => {
                gsap.to(leaf, {
                    scale: 1,
                    duration: 0.5,
                    ease: 'elastic.out(1, 0.5)',
                });
            });
        });

        // ---- Scoop + bowl hover ----
        scoop.addEventListener('mouseenter', () => {
            gsap.to(scoop, { rotation: -12, y: -6, duration: 0.4, ease: 'back.out(2)' });
        });
        scoop.addEventListener('mouseleave', () => {
            gsap.to(scoop, { rotation: 0, y: 0, duration: 0.5, ease: 'elastic.out(1, 0.4)' });
        });
        bowl.addEventListener('mouseenter', () => {
            gsap.to(bowl, { rotation: 360, duration: 0.8, ease: 'power2.inOut' });
        });
        bowl.addEventListener('mouseleave', () => {
            gsap.set(bowl, { rotation: 0 });
        });

        // ---- Partner logos: grayscale removed on hover (already in CSS). Add wiggle ----
        partners.forEach((pt) => {
            pt.addEventListener('mouseenter', () => {
                gsap.fromTo(pt,
                    { rotation: -2 },
                    { rotation: 0, duration: 0.5, ease: 'elastic.out(1, 0.4)' }
                );
            });
        });

        // ---- Scene parallax ----
        let mX = 0, mY = 0, cX = 0, cY = 0;
        const bottlesScene = document.getElementById('bottles');
        bottlesScene.addEventListener('mousemove', (e) => {
            const r = bottlesScene.getBoundingClientRect();
            mX = ((e.clientX - r.left) / r.width - 0.5) * 2;
            mY = ((e.clientY - r.top) / r.height - 0.5) * 2;
        });
        bottlesScene.addEventListener('mouseleave', () => { mX = 0; mY = 0; });

        let idleStart = performance.now();
        gsap.ticker.add(() => {
            cX += (mX - cX) * 0.05;
            cY += (mY - cY) * 0.05;
            const t = (performance.now() - idleStart) * 0.001;

            // Arch & bowl move least
            gsap.set(arch,  { x: cX * 8,  y: cY * 4 });
            gsap.set(scoop, { x: -cX * 10, y: -cY * 6 + Math.sin(t * 1.2) * 3, rotation: -cX * 1 });
            gsap.set(bowl,  { x: cX * 10,  y: -cY * 6 + Math.sin(t * 1.1 + 1) * 3 });

            // Bottles: parallax + idle bob, preserving base rotation/scale
            bottles.forEach((b, i) => {
                if (b.matches(':hover')) return;
                const baseRot = bottleBaseRot[i];
                const baseScale = bottleBaseScale[i];
                const bob = Math.sin(t * 1.2 + i * 0.9) * 6;
                gsap.set(b, {
                    x: cX * (14 + i * 2),
                    y: bob + cY * 6,
                    rotation: baseRot + cX * 1.4,
                    scale: baseScale,
                });
            });

            // Leaves drift with cursor
            leaves.forEach((leaf, i) => {
                if (leaf.matches(':hover')) return;
                const dir = i % 2 === 0 ? 1 : -1;
                gsap.set(leaf, {
                    x: cX * (18 + i * 4) * dir,
                    y: cY * (12 + i * 2),
                });
            });
        });
    }
})();

More GSAP landing pages