ToolsWaves
Free GSAP Landing Page Template · ToolsWaves · Design Studio

Free Design Studio Hero Template with Orbiting Sparkles

Free design studio landing page template from ToolsWaves with a stroke-draw logo loader, orbiting sparkles, serif italic headline, stylized portrait with grid overlay and 3D tilt, floating terrain tags, and a lime CTA that bursts sparkles. Free for any use.

FuturisticSerifSparkle3D TiltPortrait

About this ToolsWaves template

This free design studio template on ToolsWaves pairs serif italic typography with high-tech accents — a stroke-drawn logo loader with orbiting sparkles, floating tags suggesting elevation, and a portrait with a grid overlay and subtle 3D tilt on mouse movement. The visual language is deliberately mixed-era: traditional editorial typography meeting clean futuristic interactions. The lime CTA that bursts sparkles on click gives the page an unexpected pop against the deep dark background.

Use this template for design studios, creative agencies, multi-disciplinary practices, or any brand whose work spans print and digital. ToolsWaves offers this template completely free — replace the demo branding and portrait with your studio's identity, swap the floating tags for your service areas, and you have a polished landing page hero. The three files (HTML, CSS, JavaScript) work in any framework or static site setup with no build pipeline required.

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 Design Studio Hero Template with Orbiting Sparkles</title>
  <meta name="description" content="Free GSAP design studio landing page hero from ToolsWaves" />
  <meta name="generator" content="ToolsWaves - https://toolswaves.in/landing-pages" />

  <!-- Open Graph -->
  <meta property="og:title" content="Free Design Studio Hero Template with Orbiting Sparkles" />
  <meta property="og:description" content="Free GSAP design studio landing page hero from ToolsWaves" />
  <meta property="og:type" content="website" />
  <meta property="og:image" content="https://toolswaves.in/og?title=Free%20Design%20Studio%20Hero%20Template%20with%20Orbiting%20Sparkles&category=Landing%20Page&icon=%F0%9F%93%84" />

  <!-- Twitter -->
  <meta name="twitter:card" content="summary_large_image" />
  <meta name="twitter:title" content="Free Design Studio Hero Template with Orbiting Sparkles" />
  <meta name="twitter:description" content="Free GSAP design studio landing page hero from ToolsWaves" />
  <meta name="twitter:image" content="https://toolswaves.in/og?title=Free%20Design%20Studio%20Hero%20Template%20with%20Orbiting%20Sparkles&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:     #080808;
    --bg-2:   #0a0a0a;
    --ink:    #e8dfd0;
    --muted:  rgba(232, 223, 208, 0.55);
    --lime:   #c4f52d;
    --lime-deep: #9fcf1f;
    --line:   rgba(255, 255, 255, 0.08);
    --cream:  #e8dfd0;
}

html, body {
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    background: var(--bg);
    color: var(--ink);
    overflow: hidden;
    cursor: none;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}
@media (hover: none), (pointer: coarse) { html, body { cursor: auto; } }

.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: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.15);
    border-radius: 999px;
    backdrop-filter: blur(8px);
    cursor: none;
    opacity: 0.85;
    transition: opacity 0.3s, transform 0.3s;
}
.back-link:hover { opacity: 1; transform: translateY(-2px); }

/* =========================================================
   CUSTOM CURSOR
   ========================================================= */
.cursor-dot, .cursor-ring {
    position: fixed;
    top: 0; left: 0;
    pointer-events: none;
    z-index: 10000;
    transform: translate(-50%, -50%);
    will-change: transform;
}
.cursor-dot {
    width: 5px; height: 5px;
    background: var(--lime);
    border-radius: 50%;
    box-shadow: 0 0 10px var(--lime);
}
.cursor-ring {
    width: 32px; height: 32px;
    border: 1px solid rgba(196, 245, 45, 0.5);
    border-radius: 50%;
    transition: width 0.3s, height 0.3s, border-color 0.3s, background 0.3s;
}
.cursor-ring.is-hover {
    width: 56px; height: 56px;
    border-color: var(--lime);
    background: rgba(196, 245, 45, 0.08);
}
@media (hover: none), (pointer: coarse) { .cursor-dot, .cursor-ring { display: none; } }

/* =========================================================
   LOADER — Sparkle + stroke-draw "N"
   ========================================================= */
.loader {
    position: fixed;
    inset: 0;
    z-index: 999;
    background: var(--bg);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2.5rem;
    overflow: hidden;
}

.loader__grid {
    position: absolute;
    inset: 0;
    background-image:
        repeating-linear-gradient(0deg, transparent 0, transparent 80px, rgba(196, 245, 45, 0.04) 80px, rgba(196, 245, 45, 0.04) 81px),
        repeating-linear-gradient(90deg, transparent 0, transparent 80px, rgba(196, 245, 45, 0.04) 80px, rgba(196, 245, 45, 0.04) 81px);
    opacity: 0;
}

.loader__stage {
    position: relative;
    width: 200px;
    height: 200px;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 2;
}
.loader__mark {
    width: 130px;
    height: 130px;
    position: relative;
    z-index: 2;
    filter: drop-shadow(0 0 12px rgba(196, 245, 45, 0.5));
}
#loader-N {
    stroke-dasharray: 250;
    stroke-dashoffset: 250;
}

.loader__sparkles {
    position: absolute;
    inset: -30px;
    pointer-events: none;
}
.loader__sparkles span {
    position: absolute;
    font-size: 24px;
    color: var(--lime);
    will-change: transform, opacity;
    text-shadow: 0 0 10px rgba(196, 245, 45, 0.6);
}

.loader__meta {
    display: flex;
    gap: 1.25rem;
    align-items: center;
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.7rem;
    letter-spacing: 0.3em;
    color: var(--muted);
    text-transform: uppercase;
    z-index: 2;
}
.loader__counter {
    color: var(--lime);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    min-width: 3ch;
}

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

.nexa__grid {
    position: absolute;
    inset: 0;
    background-image:
        repeating-linear-gradient(0deg, transparent 0, transparent 80px, rgba(196, 245, 45, 0.025) 80px, rgba(196, 245, 45, 0.025) 81px),
        repeating-linear-gradient(90deg, transparent 0, transparent 80px, rgba(196, 245, 45, 0.025) 80px, rgba(196, 245, 45, 0.025) 81px);
    z-index: 1;
    pointer-events: none;
}

/* ---------- Top nav ---------- */
.topnav {
    position: relative;
    z-index: 30;
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    gap: 2rem;
    align-items: center;
    padding: 1.5rem 3rem;
}

.topnav__logo {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    text-decoration: none;
    color: var(--ink);
    font-weight: 700;
    font-size: 1.5rem;
    letter-spacing: -0.01em;
    cursor: none;
    will-change: transform;
    justify-self: flex-start;
}
.topnav__logo-mark {
    width: 36px; height: 36px;
    background: rgba(196, 245, 45, 0.06);
    border: 1px solid rgba(196, 245, 45, 0.3);
    border-radius: 10px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    filter: drop-shadow(0 0 6px rgba(196, 245, 45, 0.3));
}
.topnav__logo-mark svg { width: 70%; height: 70%; }

.topnav__pill {
    display: inline-flex;
    align-items: center;
    gap: 0;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid var(--line);
    border-radius: 999px;
    padding: 0.35rem;
    backdrop-filter: blur(10px);
    justify-self: center;
}
.topnav__pill a {
    position: relative;
    color: var(--muted);
    text-decoration: none;
    font-weight: 500;
    font-size: 0.95rem;
    padding: 0.65rem 1.4rem;
    cursor: none;
    will-change: transform;
    border-radius: 999px;
    transition: color 0.3s, background 0.3s;
}
.topnav__pill a.is-active { color: var(--ink); background: rgba(255, 255, 255, 0.08); }
.topnav__pill a:hover { color: var(--ink); }

.topnav__actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    justify-self: flex-end;
}
.topnav__signup {
    color: var(--muted);
    text-decoration: none;
    padding: 0.6rem 1.2rem;
    font-weight: 500;
    font-size: 0.95rem;
    cursor: none;
    will-change: transform;
    transition: color 0.3s;
}
.topnav__signup:hover { color: var(--ink); }

.topnav__login {
    background: transparent;
    color: var(--ink);
    text-decoration: none;
    padding: 0.65rem 1.5rem;
    border-radius: 999px;
    font-weight: 500;
    font-size: 0.95rem;
    cursor: none;
    will-change: transform;
    border: 1px solid rgba(255, 255, 255, 0.2);
    transition: background 0.3s, border-color 0.3s;
}
.topnav__login:hover {
    background: var(--lime);
    color: var(--bg);
    border-color: var(--lime);
}

/* ---------- Hero ---------- */
.hero {
    position: relative;
    z-index: 10;
    display: grid;
    grid-template-columns: 1.4fr 1fr;
    gap: 3rem;
    padding: 2rem 3rem 2rem;
    align-items: center;
}

.hero__left {
    position: relative;
    padding-top: 1rem;
}

.hero__title {
    font-family: 'Fraunces', serif;
    font-weight: 500;
    font-size: clamp(2.4rem, 5.8vw, 5.25rem);
    line-height: 1.1;
    letter-spacing: -0.02em;
    color: var(--cream);
    margin-bottom: 2.25rem;
    font-style: italic;
}
.hero__line {
    display: block;
    overflow: hidden;
    padding-bottom: 0.04em;
    white-space: nowrap;
}
.hero__star {
    color: var(--lime);
    font-style: normal;
    margin: 0 0.1em;
    display: inline-block;
    will-change: transform;
    filter: drop-shadow(0 0 10px rgba(196, 245, 45, 0.6));
}
.hero__char {
    display: inline-block;
    will-change: transform, color;
    transition: color 0.3s ease;
}
.hero__char.is-space { width: 0.25em; }

.hero__card {
    position: relative;
    background: rgba(196, 245, 45, 0.025);
    border: 1px solid rgba(196, 245, 45, 0.1);
    border-radius: 24px;
    padding: 1.5rem 2rem;
    max-width: 560px;
    overflow: hidden;
    will-change: transform;
}
.hero__card-glow {
    position: absolute;
    top: -40%;
    left: -20%;
    width: 70%;
    height: 180%;
    background: radial-gradient(ellipse at center, rgba(196, 245, 45, 0.15) 0%, transparent 60%);
    filter: blur(20px);
    pointer-events: none;
}
.hero__desc {
    position: relative;
    z-index: 2;
    font-size: 0.95rem;
    line-height: 1.55;
    color: var(--muted);
}

.hero__sparkle {
    position: absolute;
    top: -5px;
    right: 15%;
    color: var(--lime);
    font-size: 36px;
    filter: drop-shadow(0 0 12px rgba(196, 245, 45, 0.7));
    will-change: transform;
    cursor: none;
}

/* Portrait frame */
.hero__portrait {
    position: relative;
    width: 100%;
    max-width: 340px;
    justify-self: center;
    will-change: transform;
}
.hero__portrait-frame {
    position: relative;
    border-radius: 30px;
    overflow: hidden;
    background: linear-gradient(135deg, rgba(196, 245, 45, 0.1) 0%, rgba(0, 0, 0, 0.9) 100%);
    border: 1px solid rgba(196, 245, 45, 0.2);
    aspect-ratio: 3 / 3.8;
    box-shadow: 0 30px 60px rgba(0, 0, 0, 0.6),
                inset 0 0 50px rgba(196, 245, 45, 0.1);
}
.hero__portrait-img {
    position: absolute;
    inset: 0;
}
.hero__portrait-img img {
    width: 100%; height: 100%;
    object-fit: cover;
    object-position: center 28%;
    user-select: none;
    filter: contrast(1.15) saturate(1.2) brightness(0.75) hue-rotate(-5deg) sepia(0.2);
    mix-blend-mode: multiply;
}
.hero__portrait-img::after {
    content: '';
    position: absolute;
    inset: 0;
    background:
        radial-gradient(ellipse at 30% 40%, rgba(255, 130, 60, 0.4) 0%, transparent 55%),
        radial-gradient(ellipse at 70% 50%, rgba(196, 245, 45, 0.2) 0%, transparent 60%),
        linear-gradient(180deg, transparent 40%, rgba(0, 0, 0, 0.6) 100%);
    mix-blend-mode: screen;
    pointer-events: none;
}
.hero__portrait-grid {
    position: absolute;
    inset: 0;
    width: 100%; height: 100%;
    pointer-events: none;
}
.corner {
    position: absolute;
    width: 14px; height: 14px;
    border: 2px solid var(--lime);
    pointer-events: none;
    filter: drop-shadow(0 0 6px rgba(196, 245, 45, 0.6));
}
.corner--tl { top: 12px; left: 12px; border-right: none; border-bottom: none; }
.corner--tr { top: 12px; right: 12px; border-left: none; border-bottom: none; }
.corner--bl { bottom: 12px; left: 12px; border-right: none; border-top: none; }
.corner--br { bottom: 12px; right: 12px; border-left: none; border-top: none; }

/* ---------- Terrain + Tags ---------- */
.terrain {
    position: absolute;
    left: 0; right: 0;
    bottom: 0;
    height: 260px;
    z-index: 8;
}
.terrain__mountains {
    position: absolute;
    inset: 0;
    width: 100%; height: 100%;
    pointer-events: none;
}

.tag {
    position: absolute;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0;
    will-change: transform;
    cursor: none;
    pointer-events: auto;
}
.tag__line {
    display: block;
    width: 1px;
    height: 40px;
    background: linear-gradient(180deg, rgba(196, 245, 45, 0.1), rgba(196, 245, 45, 0.8));
    order: 2;
    transform-origin: top;
}
.tag__pill {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    background: rgba(196, 245, 45, 0.06);
    border: 1px solid rgba(196, 245, 45, 0.25);
    color: var(--lime);
    padding: 0.35rem 0.75rem;
    border-radius: 6px;
    font-size: 0.65rem;
    font-weight: 700;
    letter-spacing: 0.15em;
    backdrop-filter: blur(8px);
    order: 1;
    margin-bottom: 4px;
    transition: background 0.3s, border-color 0.3s;
}
.tag__pill b { color: var(--lime); font-weight: 400; }
.tag:hover .tag__pill { background: rgba(196, 245, 45, 0.15); border-color: var(--lime); }

.tag--1 { bottom: 110px; left: 11%; }
.tag--2 { bottom: 70px;  left: 26%; }
.tag--3 { bottom: 45px;  left: 62%; }
.tag--4 { bottom: 65px;  left: 80%; }

.cta-big {
    position: absolute;
    bottom: 55px;
    left: 50%;
    transform: translateX(-50%);
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    background: var(--lime);
    color: var(--bg);
    text-decoration: none;
    padding: 1rem 2rem;
    border-radius: 999px;
    font-weight: 600;
    font-size: 1.05rem;
    cursor: none;
    will-change: transform;
    box-shadow: 0 0 40px rgba(196, 245, 45, 0.5),
                0 10px 24px rgba(0, 0, 0, 0.4);
    z-index: 3;
    overflow: hidden;
}
.cta-big::before {
    content: '';
    position: absolute;
    top: 0; left: -100%;
    width: 60%; height: 100%;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.5), transparent);
    transform: skewX(-20deg);
    transition: left 0.7s;
}
.cta-big:hover::before { left: 200%; }
.cta-big__arrow {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: transform 0.3s;
}
.cta-big__arrow svg { width: 18px; height: 18px; }
.cta-big:hover .cta-big__arrow { transform: translate(3px, -3px); }

/* ---------- Initial hidden states ---------- */
[data-magnetic], [data-link], [data-fade], [data-title-line] .hero__char,
[data-title-line] .hero__star, [data-card], [data-portrait], [data-tag],
[data-cta], [data-sparkle] {
    opacity: 0;
}

/* ---------- Responsive ---------- */
@media (max-width: 1100px) {
    .topnav { grid-template-columns: auto 1fr auto; padding: 1rem 1.5rem; }
    .topnav__pill { display: none; }
    .hero { grid-template-columns: 1fr; gap: 2rem; padding: 1.5rem; }
    .hero__portrait { max-width: 280px; }
    .tag__pill { font-size: 0.55rem; padding: 0.25rem 0.5rem; }
}
@media (max-width: 768px) {
    .topnav__signup { display: none; }
    .hero__title { font-size: clamp(1.8rem, 10vw, 3.2rem); white-space: normal; }
    .hero__line { white-space: normal; }
    .hero__card { padding: 1rem 1.25rem; }
    .hero__desc { font-size: 0.85rem; }
    .hero__portrait { max-width: 220px; }
    .terrain { height: 200px; }
    .tag--2, .tag--4 { display: none; }
    .tag--1 { bottom: 90px; left: 3%; }
    .tag--3 { bottom: 50px; left: 75%; }
    .cta-big { padding: 0.75rem 1.5rem; font-size: 0.9rem; }
}
@media (max-width: 480px) {
    .tag--1, .tag--3 { display: none; }
    .hero__sparkle { display: none; }
    .topnav__logo-text { 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 — Nexa</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=Fraunces:ital,wght@0,500;0,700;1,500;1,700&family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@500;600&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="banner-nexa.css">
</head>
<body>
    

    <!-- Custom cursor -->
    <div class="cursor-dot" id="cursor-dot"></div>
    <div class="cursor-ring" id="cursor-ring"></div>

    <!-- ========== LOADER — Star sparkle + stroke-draw N ========== -->
    <div class="loader" id="loader">
        <div class="loader__grid" id="loader-grid-bg"></div>
        <div class="loader__stage">
            <!-- Orbiting sparkles -->
            <div class="loader__sparkles" id="loader-sparkles"></div>
            <!-- Stroke-drawn "N" logo mark -->
            <svg class="loader__mark" viewBox="0 0 120 120" aria-hidden="true">
                <path id="loader-N" d="M 25 90 L 25 30 L 95 90 L 95 30"
                      fill="none" stroke="#c4f52d" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
            </svg>
        </div>
        <div class="loader__meta">
            <span class="loader__label" id="loader-label">INITIALIZING</span>
            <span class="loader__counter" id="loader-counter">0%</span>
        </div>
    </div>

    <section class="nexa" id="nexa">

        <!-- Background subtle grid -->
        <div class="nexa__grid" id="grid"></div>

        <!-- ========== TOP NAV ========== -->
        <header class="topnav">
            <a href="#" class="topnav__logo" data-magnetic>
                <span class="topnav__logo-mark" id="logo-mark">
                    <svg viewBox="0 0 36 36" aria-hidden="true">
                        <path d="M 8 28 L 8 8 L 28 28 L 28 8" stroke="#c4f52d" stroke-width="3" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
                    </svg>
                </span>
                <span class="topnav__logo-text">Nexa</span>
            </a>

            <nav class="topnav__pill">
                <a href="#" class="is-active" data-magnetic data-link>Home</a>
                <a href="#" data-magnetic data-link>About</a>
                <a href="#" data-magnetic data-link>Feature</a>
            </nav>

            <div class="topnav__actions">
                <a href="#" class="topnav__signup" data-magnetic>Signup</a>
                <a href="#" class="topnav__login" data-magnetic>Login</a>
            </div>
        </header>

        <!-- ========== HERO ========== -->
        <div class="hero" id="hero">

            <div class="hero__left">
                <h1 class="hero__title" aria-label="Unveil Tomorrow's Design Today">
                    <span class="hero__line" data-title-line>Unveil Tomorrow's</span>
                    <span class="hero__line" data-title-line>Design <span class="hero__star">&#10038;</span> Today!</span>
                </h1>

                <div class="hero__card" data-card>
                    <div class="hero__card-glow"></div>
                    <p class="hero__desc" data-fade>
                        Experience the future in our cutting-edge designs &mdash; where
                        innovation meets style, crafting a vision for the smart generation.
                    </p>
                </div>

                <span class="hero__sparkle hero__sparkle--1" data-sparkle>&#10038;</span>
            </div>

            <!-- Right: Portrait frame -->
            <div class="hero__portrait" id="portrait" data-portrait>
                <div class="hero__portrait-frame">
                    <div class="hero__portrait-img">
                        <img src="https://images.unsplash.com/photo-1599566150163-29194dcaad36?auto=format&fit=crop&w=700&q=80"
                             alt="Character"
                             draggable="false"
                             onerror="this.style.display='none'">
                    </div>
                    <!-- Grid overlay -->
                    <svg class="hero__portrait-grid" viewBox="0 0 300 380" preserveAspectRatio="none" aria-hidden="true">
                        <g stroke="rgba(196, 245, 45, 0.25)" stroke-width="0.6" fill="none">
                            <line x1="0" y1="95" x2="300" y2="95"/>
                            <line x1="0" y1="190" x2="300" y2="190"/>
                            <line x1="0" y1="285" x2="300" y2="285"/>
                            <line x1="75" y1="0" x2="75" y2="380"/>
                            <line x1="150" y1="0" x2="150" y2="380"/>
                            <line x1="225" y1="0" x2="225" y2="380"/>
                        </g>
                    </svg>
                    <!-- Corner accents -->
                    <span class="corner corner--tl"></span>
                    <span class="corner corner--tr"></span>
                    <span class="corner corner--bl"></span>
                    <span class="corner corner--br"></span>
                </div>
            </div>
        </div>

        <!-- ========== BOTTOM TERRAIN + TAGS ========== -->
        <div class="terrain" id="terrain">
            <svg class="terrain__mountains" viewBox="0 0 1400 260" preserveAspectRatio="none" aria-hidden="true">
                <path d="M0 260 L0 140 Q 100 80 200 110 T 400 90 T 600 120 T 800 85 T 1000 100 T 1200 75 T 1400 115 L 1400 260 Z"
                      fill="rgba(196, 245, 45, 0.05)"/>
                <path d="M0 260 L0 180 Q 120 130 250 160 T 500 140 T 750 175 T 1000 145 T 1250 165 T 1400 155 L 1400 260 Z"
                      fill="rgba(196, 245, 45, 0.08)"/>
                <path d="M0 260 L0 210 Q 150 180 300 200 T 600 190 T 900 210 T 1200 200 T 1400 205 L 1400 260 Z"
                      fill="rgba(196, 245, 45, 0.12)"/>
            </svg>

            <div class="tag tag--1" data-tag>
                <span class="tag__line"></span>
                <span class="tag__pill"><b>&#10038;</b> FUTURISTIC</span>
            </div>
            <div class="tag tag--2" data-tag>
                <span class="tag__line"></span>
                <span class="tag__pill"><b>&#10038;</b> SLEEK</span>
            </div>
            <div class="tag tag--3" data-tag>
                <span class="tag__line"></span>
                <span class="tag__pill"><b>&#10038;</b> TRENDSETTING</span>
            </div>
            <div class="tag tag--4" data-tag>
                <span class="tag__line"></span>
                <span class="tag__pill"><b>&#10038;</b> INTERACTIVE</span>
            </div>

            <a href="#" class="cta-big" data-magnetic data-cta>
                <span class="cta-big__label">Connect Now</span>
                <span class="cta-big__arrow">
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2">
                        <path d="M7 17L17 7M17 7H8M17 7v9" stroke-linecap="round" stroke-linejoin="round"/>
                    </svg>
                </span>
            </a>
        </div>
    </section>

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

</body>
</html>
JSbanner-nexa.js— GSAP animation timeline
(() => {
    const root = document.getElementById('nexa');
    if (!root) return;

    // -------------------------------------------------------------------
    //  SPLIT TITLE (preserve star element)
    // -------------------------------------------------------------------
    const titleLines = root.querySelectorAll('[data-title-line]');
    titleLines.forEach((line) => {
        const frag = document.createDocumentFragment();
        line.childNodes.forEach((node) => {
            if (node.nodeType === Node.TEXT_NODE) {
                [...node.textContent].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;
                    frag.appendChild(span);
                });
            } else {
                // Keep star span intact
                frag.appendChild(node.cloneNode(true));
            }
        });
        line.textContent = '';
        line.appendChild(frag);
    });

    // -------------------------------------------------------------------
    //  BUILD LOADER SPARKLES
    // -------------------------------------------------------------------
    const sparkleHost = document.getElementById('loader-sparkles');
    const STAR_COUNT = 8;
    for (let i = 0; i < STAR_COUNT; i++) {
        const s = document.createElement('span');
        s.textContent = i % 2 === 0 ? '\u2736' : '\u2737';
        const angle = (i / STAR_COUNT) * Math.PI * 2;
        const r = 100 + (i % 2) * 20;
        s.style.left = (100 + Math.cos(angle) * r) + 'px';
        s.style.top  = (100 + Math.sin(angle) * r) + 'px';
        s.style.transform = 'translate(-50%, -50%)';
        sparkleHost.appendChild(s);
    }
    const sparkles = sparkleHost.querySelectorAll('span');

    // -------------------------------------------------------------------
    //  REFERENCES
    // -------------------------------------------------------------------
    const loader = document.getElementById('loader');
    const loaderGridBg = document.getElementById('loader-grid-bg');
    const loaderN = document.getElementById('loader-N');
    const loaderCounter = document.getElementById('loader-counter');
    const loaderLabel = document.getElementById('loader-label');

    const cursorDot = document.getElementById('cursor-dot');
    const cursorRing = document.getElementById('cursor-ring');

    const magnetics = root.querySelectorAll('[data-magnetic]');
    const titleChars = root.querySelectorAll('.hero__char');
    const titleStar = root.querySelector('.hero__star');
    const card = root.querySelector('[data-card]');
    const desc = root.querySelector('[data-fade]');
    const portrait = document.getElementById('portrait');
    const tags = root.querySelectorAll('[data-tag]');
    const cta = root.querySelector('[data-cta]');
    const sparkle = root.querySelector('[data-sparkle]');
    const logoMark = document.getElementById('logo-mark');

    // -------------------------------------------------------------------
    //  INITIAL STATES
    // -------------------------------------------------------------------
    gsap.set(magnetics, { y: -15, opacity: 0 });
    gsap.set(titleChars, { yPercent: 110, opacity: 0 });
    gsap.set(titleStar, { scale: 0, opacity: 0, rotation: -90 });
    gsap.set(card, { y: 30, opacity: 0 });
    gsap.set(portrait, { x: 80, opacity: 0, scale: 0.9 });
    gsap.set(tags, { y: 20, opacity: 0 });
    gsap.set(cta, { scale: 0.8, opacity: 0 });
    gsap.set(sparkle, { scale: 0, opacity: 0, rotation: -90 });
    gsap.set(sparkles, { scale: 0, opacity: 0 });

    // -------------------------------------------------------------------
    //  LOADER TIMELINE
    // -------------------------------------------------------------------
    const loaderTl = gsap.timeline({ onComplete: playScene });

    // Grid fades in
    loaderTl.to(loaderGridBg, {
        opacity: 1,
        duration: 0.5,
        ease: 'power2.out',
    }, 0);

    // N stroke draws in
    loaderTl.to(loaderN, {
        strokeDashoffset: 0,
        duration: 1.4,
        ease: 'power2.inOut',
    }, 0.2);

    // Sparkles pop in around N with orbit
    loaderTl.to(sparkles, {
        scale: 1, opacity: 1,
        duration: 0.5,
        stagger: 0.05,
        ease: 'back.out(2)',
    }, 0.5);

    // Sparkles twinkle continuously
    sparkles.forEach((s) => {
        gsap.to(s, {
            scale: 1.4,
            rotation: 45,
            duration: 0.6 + Math.random() * 0.8,
            yoyo: true,
            repeat: -1,
            ease: 'sine.inOut',
            delay: Math.random() * 1,
            transformOrigin: 'center',
        });
    });

    // Counter + labels
    const p = { v: 0 };
    loaderTl.to(p, {
        v: 100,
        duration: 2.3,
        ease: 'power1.inOut',
        onUpdate: () => {
            loaderCounter.textContent = Math.floor(p.v) + '%';
            if (p.v > 25 && loaderLabel.textContent === 'INITIALIZING') loaderLabel.textContent = 'CRAFTING DESIGN';
            if (p.v > 60 && loaderLabel.textContent === 'CRAFTING DESIGN') loaderLabel.textContent = 'POLISHING PIXELS';
            if (p.v > 95 && loaderLabel.textContent === 'POLISHING PIXELS') loaderLabel.textContent = 'READY';
        },
    }, 0.3);

    // Exit: sparkles burst outward, N scales up and fades
    loaderTl.to(sparkles, {
        x: (i) => Math.cos(i / STAR_COUNT * Math.PI * 2) * 250,
        y: (i) => Math.sin(i / STAR_COUNT * Math.PI * 2) * 250,
        opacity: 0,
        scale: 0.2,
        rotation: 180,
        duration: 0.9,
        ease: 'power3.in',
        stagger: 0.02,
    }, '+=0.2');
    loaderTl.to('.loader__mark', {
        scale: 1.3, opacity: 0, duration: 0.6, ease: 'power3.in',
    }, '-=0.5');
    loaderTl.to([loaderCounter, loaderLabel], {
        y: -10, opacity: 0, duration: 0.3, stagger: 0.05,
    }, '-=0.4');
    loaderTl.to(loader, {
        opacity: 0, duration: 0.4, ease: 'power2.inOut',
    }, '-=0.2');
    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);

        // Title chars + star
        tl.to(titleChars, {
            yPercent: 0, opacity: 1,
            duration: 1,
            stagger: 0.018,
            ease: 'expo.out',
        }, 0.3);
        tl.to(titleStar, {
            scale: 1, opacity: 1, rotation: 0,
            duration: 0.7,
            ease: 'back.out(2)',
        }, 0.6);
        tl.to(sparkle, {
            scale: 1, opacity: 1, rotation: 0,
            duration: 0.7,
            ease: 'back.out(2)',
        }, 0.55);

        // Description card
        tl.to(card, {
            y: 0, opacity: 1,
            duration: 0.8,
            ease: 'power4.out',
        }, 0.9);

        // Portrait slides in
        tl.to(portrait, {
            x: 0, opacity: 1, scale: 1,
            duration: 1.2,
            ease: 'power4.out',
        }, 0.5);

        // Tags pop up from mountain
        tl.to(tags, {
            y: 0, opacity: 1,
            duration: 0.7,
            stagger: 0.1,
            ease: 'back.out(1.6)',
        }, 1.1);

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

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

    // -------------------------------------------------------------------
    //  CONTINUOUS
    // -------------------------------------------------------------------
    function startContinuous() {
        // Star rotates
        gsap.to(titleStar, {
            rotation: 360,
            duration: 10,
            repeat: -1,
            ease: 'none',
            transformOrigin: 'center center',
        });

        // Decorative sparkle pulses
        gsap.to(sparkle, {
            scale: 1.2, rotation: 30,
            duration: 1.5,
            yoyo: true,
            repeat: -1,
            ease: 'sine.inOut',
            transformOrigin: 'center',
        });

        // Portrait subtle breath
        gsap.to(portrait, {
            y: -10,
            duration: 3,
            yoyo: true,
            repeat: -1,
            ease: 'sine.inOut',
        });

        // Tags gentle float
        tags.forEach((tag, i) => {
            gsap.to(tag, {
                y: `-=${6 + i}`,
                duration: 2 + i * 0.3,
                yoyo: true,
                repeat: -1,
                ease: 'sine.inOut',
                delay: i * 0.15,
            });
        });

        // CTA subtle glow pulse
        gsap.to(cta, {
            boxShadow: '0 0 60px rgba(196, 245, 45, 0.7), 0 10px 24px rgba(0, 0, 0, 0.4)',
            duration: 1.4,
            yoyo: true,
            repeat: -1,
            ease: 'sine.inOut',
        });
    }

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

        // ---- Custom cursor ----
        let mx = window.innerWidth / 2, my = window.innerHeight / 2;
        let rx = mx, ry = my;
        window.addEventListener('mousemove', (e) => { mx = e.clientX; my = e.clientY; });
        gsap.ticker.add(() => {
            rx += (mx - rx) * 0.18;
            ry += (my - ry) * 0.18;
            gsap.set(cursorDot, { x: mx, y: my });
            gsap.set(cursorRing, { x: rx, y: ry });
        });

        const hovers = root.querySelectorAll('a, button, [data-magnetic], [data-tag], .hero__char, .hero__sparkle');
        hovers.forEach((el) => {
            el.addEventListener('mouseenter', () => cursorRing.classList.add('is-hover'));
            el.addEventListener('mouseleave', () => cursorRing.classList.remove('is-hover'));
        });

        // ---- Magnetic ----
        magnetics.forEach((el) => {
            const strength = el.classList.contains('cta-big') ? 0.3
                : el.classList.contains('topnav__login') ? 0.35
                : 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)' });
            });
        });

        // ---- Logo N redraws on hover ----
        const logo = root.querySelector('.topnav__logo');
        logo.addEventListener('mouseenter', () => {
            gsap.fromTo(logoMark.querySelector('path'),
                { strokeDasharray: 80, strokeDashoffset: 80 },
                { strokeDashoffset: 0, duration: 0.7, ease: 'power2.out' }
            );
        });

        // ---- Title char proximity + hover color ----
        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) * 14 });
                else gsap.set(c, { y: 0 });
            });
        });
        titleChars.forEach((c) => {
            c.addEventListener('mouseenter', () => gsap.to(c, { color: '#c4f52d', duration: 0.2 }));
            c.addEventListener('mouseleave', () => gsap.to(c, { color: '#e8dfd0', duration: 0.4 }));
        });

        // ---- Portrait 3D tilt ----
        const hPortraitImg = root.querySelector('.hero__portrait-img');
        let px = 0, py = 0, pcx = 0, pcy = 0;
        portrait.addEventListener('mousemove', (e) => {
            const r = portrait.getBoundingClientRect();
            px = ((e.clientX - r.left) / r.width - 0.5) * 2;
            py = ((e.clientY - r.top) / r.height - 0.5) * 2;
        });
        portrait.addEventListener('mouseleave', () => { px = 0; py = 0; });
        gsap.ticker.add(() => {
            pcx += (px - pcx) * 0.1;
            pcy += (py - pcy) * 0.1;
            gsap.set(portrait, {
                rotationY: pcx * 10,
                rotationX: -pcy * 8,
                transformPerspective: 1000,
                transformOrigin: 'center',
            });
            if (hPortraitImg) gsap.set(hPortraitImg, {
                x: -pcx * 10,
                y: -pcy * 6,
            });
        });

        // ---- Tags: hover lifts pill + line extends ----
        tags.forEach((tag) => {
            const line = tag.querySelector('.tag__line');
            const pill = tag.querySelector('.tag__pill');
            tag.addEventListener('mouseenter', () => {
                gsap.to(line, { scaleY: 1.5, duration: 0.4, ease: 'power3.out' });
                gsap.to(pill, { y: -8, scale: 1.05, duration: 0.4, ease: 'back.out(2)' });
            });
            tag.addEventListener('mouseleave', () => {
                gsap.to(line, { scaleY: 1, duration: 0.5 });
                gsap.to(pill, { y: 0, scale: 1, duration: 0.5, ease: 'elastic.out(1, 0.4)' });
            });
        });

        // ---- CTA click = shoot sparkle particles ----
        cta.addEventListener('click', (e) => {
            e.preventDefault();
            gsap.fromTo(cta,
                { scale: 1 },
                { scale: 0.95, duration: 0.1, yoyo: true, repeat: 1, ease: 'sine.inOut' }
            );
            const rect = cta.getBoundingClientRect();
            const cx = rect.left + rect.width / 2;
            const cy = rect.top + rect.height / 2;
            for (let i = 0; i < 10; i++) {
                const s = document.createElement('span');
                s.textContent = '\u2736';
                s.style.position = 'fixed';
                s.style.left = cx + 'px';
                s.style.top = cy + 'px';
                s.style.color = '#c4f52d';
                s.style.fontSize = '20px';
                s.style.textShadow = '0 0 8px rgba(196, 245, 45, 0.6)';
                s.style.pointerEvents = 'none';
                s.style.zIndex = '200';
                s.style.transform = 'translate(-50%, -50%)';
                document.body.appendChild(s);
                const a = (i / 10) * Math.PI * 2;
                const dist = 80 + Math.random() * 60;
                gsap.fromTo(s,
                    { x: 0, y: 0, opacity: 1, scale: 0.6 },
                    {
                        x: Math.cos(a) * dist,
                        y: Math.sin(a) * dist,
                        opacity: 0,
                        scale: 1.4,
                        rotation: 180,
                        duration: 0.9,
                        ease: 'power3.out',
                        onComplete: () => s.remove(),
                    }
                );
            }
        });

        // ---- Overall scene parallax ----
        let sx = 0, sy = 0, scx = 0, scy = 0;
        root.addEventListener('mousemove', (e) => {
            const r = root.getBoundingClientRect();
            sx = ((e.clientX - r.left) / r.width - 0.5) * 2;
            sy = ((e.clientY - r.top) / r.height - 0.5) * 2;
        });
        root.addEventListener('mouseleave', () => { sx = 0; sy = 0; });

        gsap.ticker.add(() => {
            scx += (sx - scx) * 0.04;
            scy += (sy - scy) * 0.04;
            tags.forEach((tag, i) => {
                if (tag.matches(':hover')) return;
                gsap.set(tag, { x: scx * (10 + i * 4) });
            });
        });
    }
})();

More GSAP landing pages