Copy Code<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Free Creative Portfolio Hero Template with Clapperboard Loader</title>
<meta name="description" content="Free GSAP video production landing page hero from ToolsWaves" />
<meta name="generator" content="ToolsWaves - https://toolswaves.in/landing-pages" />
<!-- Open Graph -->
<meta property="og:title" content="Free Creative Portfolio Hero Template with Clapperboard Loader" />
<meta property="og:description" content="Free GSAP video production landing page hero from ToolsWaves" />
<meta property="og:type" content="website" />
<meta property="og:image" content="https://toolswaves.in/og?title=Free%20Creative%20Portfolio%20Hero%20Template%20with%20Clapperboard%20Loader&category=Landing%20Page&icon=%F0%9F%93%84" />
<!-- Twitter -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Free Creative Portfolio Hero Template with Clapperboard Loader" />
<meta name="twitter:description" content="Free GSAP video production landing page hero from ToolsWaves" />
<meta name="twitter:image" content="https://toolswaves.in/og?title=Free%20Creative%20Portfolio%20Hero%20Template%20with%20Clapperboard%20Loader&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: #0a0a0a;
--ink: #ffffff;
--muted: rgba(255, 255, 255, 0.55);
--line: rgba(255, 255, 255, 0.12);
--lime: #c9ff2d;
--lime-deep: #a8dd15;
}
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: 4.5rem;
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.08);
border: 1px solid rgba(255, 255, 255, 0.18);
border-radius: 999px;
backdrop-filter: blur(8px);
opacity: 0.85;
cursor: none;
transition: opacity 0.3s, transform 0.3s, background 0.3s;
}
.back-link:hover { opacity: 1; transform: translateY(-2px); background: rgba(255, 255, 255, 0.14); }
/* =========================================================
CUSTOM CURSOR
========================================================= */
.cursor-dot, .cursor-ring {
position: fixed;
top: 0; left: 0;
pointer-events: none;
z-index: 10000;
transform: translate(-50%, -50%);
mix-blend-mode: difference;
will-change: transform;
}
.cursor-dot {
width: 6px; height: 6px;
background: var(--lime);
border-radius: 50%;
}
.cursor-ring {
width: 36px; height: 36px;
border: 1px solid rgba(201, 255, 45, 0.6);
border-radius: 50%;
transition: width 0.3s ease, height 0.3s ease, border-color 0.3s ease;
}
.cursor-ring.is-hover {
width: 60px; height: 60px;
border-color: var(--lime);
}
@media (hover: none), (pointer: coarse) {
.cursor-dot, .cursor-ring { display: none; }
}
/* =========================================================
LOADER — Clapperboard
========================================================= */
.loader {
position: fixed;
inset: 0;
z-index: 999;
background: var(--bg);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 2rem;
}
.clapper {
position: relative;
width: min(420px, 78vw);
height: min(260px, 55vw);
will-change: transform;
}
.clapper__arm {
position: absolute;
top: 0; left: 0;
width: 100%;
height: 30%;
background: var(--ink);
transform-origin: 6% 100%;
z-index: 2;
display: flex;
align-items: flex-end;
padding-top: 4px;
will-change: transform;
}
.clapper__stripes {
display: flex;
width: 100%;
height: 65%;
overflow: hidden;
}
.clapper__stripes span {
flex: 1;
transform: skewX(-30deg);
transform-origin: bottom;
}
.clapper__stripes span:nth-child(odd) { background: var(--ink); }
.clapper__stripes span:nth-child(even) { background: var(--bg); }
.clapper__body {
position: absolute;
top: 30%;
left: 0;
right: 0;
bottom: 0;
background: #1a1a1a;
border: 2px solid var(--ink);
padding: 1.25rem 1.5rem;
font-family: 'JetBrains Mono', monospace;
font-size: 0.85rem;
color: var(--ink);
display: flex;
flex-direction: column;
justify-content: space-around;
letter-spacing: 0.1em;
gap: 0.2rem;
}
.clapper__row {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px dashed rgba(255, 255, 255, 0.2);
padding-bottom: 0.35rem;
font-size: 0.72rem;
}
.clapper__row:last-child { border-bottom: none; }
.clapper__row span { color: rgba(255, 255, 255, 0.5); }
.clapper__row b { color: var(--lime); font-weight: 600; }
.loader__countdown {
font-family: 'Inter', sans-serif;
font-weight: 900;
font-size: clamp(4rem, 12vw, 9rem);
color: var(--lime);
line-height: 1;
font-variant-numeric: tabular-nums;
text-shadow: 0 0 40px rgba(201, 255, 45, 0.3);
}
.loader__label {
font-family: 'JetBrains Mono', monospace;
font-size: 0.7rem;
letter-spacing: 0.35em;
color: var(--muted);
}
/* =========================================================
REEL SECTION
========================================================= */
.reel {
position: relative;
width: 100%;
height: 100vh;
min-height: 720px;
overflow: hidden;
background: var(--bg);
}
.reel__video {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
z-index: 1;
filter: saturate(1.1) contrast(1.05) brightness(0.7);
}
.reel__overlay {
position: absolute;
inset: 0;
z-index: 2;
background:
radial-gradient(ellipse at 30% 50%, rgba(0, 0, 0, 0.2) 0%, rgba(0, 0, 0, 0.75) 80%),
linear-gradient(180deg, rgba(10, 10, 10, 0.6) 0%, rgba(10, 10, 10, 0.3) 30%, rgba(10, 10, 10, 0.85) 100%);
pointer-events: none;
}
/* ---------- Top nav ---------- */
.topnav {
position: relative;
z-index: 20;
display: flex;
align-items: center;
gap: 2rem;
padding: 1rem 1.5rem;
border-bottom: 1px solid var(--line);
background: rgba(10, 10, 10, 0.35);
backdrop-filter: blur(10px);
}
.topnav__logo {
display: inline-flex;
align-items: center;
gap: 0.6rem;
color: var(--ink);
text-decoration: none;
font-weight: 700;
font-size: 1.35rem;
letter-spacing: -0.01em;
will-change: transform;
cursor: none;
}
.topnav__logo-mark { width: 36px; height: 36px; }
.topnav__logo-mark svg {
width: 100%; height: 100%;
transition: transform 0.7s cubic-bezier(0.65, 0, 0.35, 1);
}
.topnav__logo:hover .topnav__logo-mark svg { transform: rotate(360deg); }
.topnav__links {
margin: 0 auto;
display: flex;
gap: 2.5rem;
}
.topnav__links a {
position: relative;
color: var(--ink);
text-decoration: none;
font-weight: 600;
font-size: 0.85rem;
letter-spacing: 0.1em;
padding: 0.3rem 0;
cursor: none;
will-change: transform;
}
.topnav__links a.is-active { color: var(--lime); }
.topnav__links a::after {
content: '';
position: absolute;
left: 0; bottom: -2px;
width: 100%; height: 1px;
background: var(--lime);
transform: scaleX(0);
transform-origin: right;
transition: transform 0.4s cubic-bezier(0.65, 0, 0.35, 1);
}
.topnav__links a.is-active::after,
.topnav__links a:hover::after { transform: scaleX(1); transform-origin: left; }
.topnav__actions {
display: flex;
align-items: center;
gap: 0.75rem;
}
.topnav__mute {
width: 40px; height: 40px;
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.18);
color: var(--ink);
border-radius: 50%;
display: inline-flex;
align-items: center;
justify-content: center;
cursor: none;
will-change: transform;
transition: background 0.3s ease;
}
.topnav__mute:hover { background: rgba(255, 255, 255, 0.18); }
.topnav__mute svg { width: 16px; height: 16px; }
.topnav__cta {
display: inline-flex;
align-items: center;
gap: 0.5rem;
background: var(--lime);
color: var(--bg);
text-decoration: none;
padding: 0.75rem 1.2rem;
border-radius: 999px;
font-weight: 600;
font-size: 0.9rem;
cursor: none;
will-change: transform;
transition: background 0.3s;
}
.topnav__cta svg { width: 16px; height: 16px; transition: transform 0.3s ease; }
.topnav__cta:hover { background: var(--lime-deep); }
.topnav__cta:hover svg { transform: translateX(3px); }
/* ---------- Rails ---------- */
.rail {
position: absolute;
z-index: 15;
display: flex;
flex-direction: column;
align-items: center;
pointer-events: none;
}
.rail > * { pointer-events: auto; }
.rail--left {
top: 6rem; left: 0.75rem; bottom: 5rem;
gap: 2rem;
}
.rail--right {
top: 6rem; right: 0.75rem; bottom: 5rem;
gap: 1.5rem;
}
.rail__dots {
display: grid;
grid-template-columns: repeat(3, 6px);
gap: 4px;
}
.rail__dots span {
width: 6px; height: 6px;
border-radius: 50%;
background: var(--ink);
cursor: none;
will-change: transform;
transition: background 0.3s ease;
}
.rail__dots span:hover { background: var(--lime); }
.rail__phone {
writing-mode: vertical-rl;
transform: rotate(180deg);
color: var(--ink);
text-decoration: none;
font-size: 0.72rem;
letter-spacing: 0.25em;
font-family: 'JetBrains Mono', monospace;
cursor: none;
transition: color 0.3s ease;
}
.rail__phone:hover { color: var(--lime); }
.rail__scroll, .rail__follow {
margin-top: auto;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.75rem;
font-size: 0.65rem;
letter-spacing: 0.35em;
color: var(--muted);
}
.rail__follow { margin-top: 0; }
.rail__scroll-label, .rail__follow-label {
writing-mode: vertical-rl;
transform: rotate(180deg);
}
.rail__scroll-line, .rail__follow-line {
width: 1px;
height: 70px;
background: linear-gradient(180deg, rgba(255,255,255,0.4), transparent);
display: block;
transform-origin: top;
}
.rail__scroll-arrow { font-size: 0.8rem; opacity: 0.6; }
.rail__social {
display: flex;
flex-direction: column;
gap: 0.65rem;
margin-top: auto;
align-items: center;
}
.rail__social-icon {
width: 34px; height: 34px;
border-radius: 50%;
background: rgba(255,255,255,0.06);
border: 1px solid rgba(255,255,255,0.12);
color: var(--ink);
display: inline-flex;
align-items: center;
justify-content: center;
text-decoration: none;
font-size: 0.75rem;
font-weight: 700;
cursor: none;
will-change: transform;
transition: background 0.3s ease, color 0.3s ease;
}
.rail__social-icon svg { width: 15px; height: 15px; }
.rail__social-icon:hover { background: var(--lime); color: var(--bg); }
/* ---------- Hero content ---------- */
.hero {
position: absolute;
left: 5rem;
top: 6rem;
right: 5rem;
bottom: 5rem;
z-index: 10;
display: flex;
flex-direction: column;
justify-content: flex-start;
gap: 1.5rem;
pointer-events: none;
}
.hero > * { pointer-events: auto; }
.hero__eyebrow {
position: relative;
display: inline-flex;
align-items: flex-start;
gap: 0.4rem;
color: var(--ink);
text-decoration: none;
font-size: 0.95rem;
font-weight: 500;
line-height: 1.4;
padding-bottom: 0.4rem;
max-width: max-content;
cursor: none;
will-change: transform;
}
.hero__eyebrow-text {
border-bottom: 1px solid rgba(255, 255, 255, 0.4);
padding-bottom: 0.2rem;
}
.hero__eyebrow-arrow {
display: inline-block;
font-size: 0.85em;
transition: transform 0.4s cubic-bezier(0.65, 0, 0.35, 1);
}
.hero__eyebrow:hover .hero__eyebrow-arrow {
transform: translate(4px, -4px) rotate(3deg);
}
.hero__title {
font-weight: 800;
font-size: clamp(3rem, 9vw, 8rem);
line-height: 0.95;
letter-spacing: -0.04em;
color: var(--ink);
margin: auto 0;
max-width: 780px;
text-shadow: 0 8px 40px rgba(0, 0, 0, 0.5);
}
.hero__line {
display: block;
overflow: hidden;
padding-bottom: 0.05em;
}
.hero__char {
display: inline-block;
will-change: transform, color;
transition: color 0.3s ease;
}
.hero__char.is-space { width: 0.25em; }
.hero__play {
display: inline-flex;
align-items: center;
gap: 1rem;
text-decoration: none;
color: var(--ink);
max-width: max-content;
cursor: none;
will-change: transform;
}
.hero__play-scribble { width: 70px; height: 52px; }
.hero__play-scribble path {
stroke-dasharray: 120;
stroke-dashoffset: 120;
}
.hero__play-btn {
position: relative;
width: 62px;
height: 62px;
display: inline-flex;
align-items: center;
justify-content: center;
}
.hero__play-btn > svg:first-child {
width: 100%; height: 100%;
transition: transform 0.3s ease;
}
.hero__play-ring {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
will-change: transform;
}
.hero__play:hover .hero__play-btn > svg:first-child { transform: scale(1.08); }
.hero__play-label {
display: flex;
flex-direction: column;
font-weight: 500;
font-size: 1rem;
line-height: 1.1;
}
/* Floating stat chips */
.chips {
display: flex;
flex-wrap: wrap;
gap: 0.6rem;
margin-top: 0.5rem;
}
.chip {
padding: 0.45rem 0.9rem;
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.15);
border-radius: 999px;
font-size: 0.75rem;
letter-spacing: 0.08em;
color: var(--ink);
backdrop-filter: blur(10px);
cursor: none;
will-change: transform;
transition: background 0.3s, border-color 0.3s;
}
.chip b { color: var(--lime); margin-right: 0.3rem; font-weight: 700; }
.chip:hover { background: rgba(201, 255, 45, 0.1); border-color: rgba(201, 255, 45, 0.4); }
/* ---------- Marquee ---------- */
.marquee {
position: absolute;
left: 0; right: 0; bottom: 0;
z-index: 10;
background: var(--lime);
color: var(--bg);
padding: 1.1rem 0;
overflow: hidden;
white-space: nowrap;
}
.marquee__track { display: flex; width: max-content; will-change: transform; }
.marquee__group { display: flex; gap: 3rem; padding: 0 1.5rem; align-items: center; }
.marquee__item {
font-size: clamp(1rem, 1.7vw, 1.5rem);
font-weight: 700;
letter-spacing: -0.01em;
cursor: none;
}
/* ---------- Initial hidden states ---------- */
[data-magnetic], [data-rail], [data-social], [data-eyebrow],
[data-title-line] .hero__char, [data-play], [data-chips] {
opacity: 0;
}
/* ---------- Responsive ---------- */
@media (max-width: 1100px) {
.topnav__links { display: none; }
.hero { left: 4rem; right: 3.5rem; top: 5rem; }
}
@media (max-width: 768px) {
.rail--right .rail__follow { display: none; }
.rail--left .rail__phone { display: none; }
.rail__social { gap: 0.4rem; }
.rail__social-icon { width: 28px; height: 28px; }
.hero { left: 3rem; right: 3rem; top: 5rem; bottom: 4.5rem; }
.hero__title { font-size: clamp(2.3rem, 11vw, 6rem); }
.topnav { padding: 0.75rem 1rem; gap: 0.75rem; }
.topnav__logo-text { display: none; }
.chips { gap: 0.4rem; }
.chip { font-size: 0.65rem; padding: 0.3rem 0.7rem; }
.clapper__body { font-size: 0.65rem; padding: 1rem; }
.clapper__row { font-size: 0.6rem; }
}
@media (max-width: 480px) {
.rail { gap: 1rem; }
.rail--left { top: 5rem; }
.rail--right { top: 5rem; }
.rail__scroll, .rail__follow, .rail__dots { display: none; }
.hero { left: 1.25rem; right: 1.25rem; }
.topnav__mute { width: 32px; height: 32px; }
.topnav__cta { padding: 0.5rem 0.9rem; font-size: 0.8rem; }
}
</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 — Creative Reel</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@400;500;600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="banner-creative-reel.css">
</head>
<body>
<!-- Custom cursor -->
<div class="cursor-dot" id="cursor-dot"></div>
<div class="cursor-ring" id="cursor-ring"></div>
<!-- ========== LOADER — CLAPPERBOARD + COUNTDOWN ========== -->
<div class="loader" id="loader">
<div class="clapper" id="clapper">
<div class="clapper__arm" id="clapper-arm">
<div class="clapper__stripes">
<span></span><span></span><span></span><span></span>
<span></span><span></span><span></span><span></span>
<span></span><span></span><span></span><span></span>
</div>
</div>
<div class="clapper__body">
<div class="clapper__row"><span>SCENE</span><b>01</b></div>
<div class="clapper__row"><span>TAKE</span><b>01</b></div>
<div class="clapper__row"><span>DATE</span><b>04 · 20 · 26</b></div>
<div class="clapper__row"><span>DIRECTOR</span><b>BRAND</b></div>
<div class="clapper__row"><span>PROD.</span><b>CREATIVE REEL</b></div>
</div>
</div>
<div class="loader__countdown" id="countdown">3</div>
<div class="loader__label">ROLLING</div>
</div>
<section class="reel" id="reel">
<!-- Background video -->
<video class="reel__video" id="reel-video" autoplay loop muted playsinline
poster="https://images.unsplash.com/photo-1485846234645-a62644f84728?auto=format&fit=crop&w=1600&q=75">
<source src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4" type="video/mp4">
</video>
<!-- Dark overlay + vignette for readability -->
<div class="reel__overlay"></div>
<!-- ========== TOP NAV ========== -->
<header class="topnav">
<a href="#" class="topnav__logo" data-magnetic>
<span class="topnav__logo-mark">
<svg viewBox="0 0 40 40">
<circle cx="20" cy="20" r="20" fill="#c9ff2d"/>
<path d="M16 12v16M12 20h16M14 14l12 12M26 14L14 26" stroke="#0a0a0a" stroke-width="1.5"/>
</svg>
</span>
<span class="topnav__logo-text">Brand</span>
</a>
<nav class="topnav__links">
<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>WORKS</a>
<a href="#" data-magnetic data-link>SERVICES</a>
<a href="#" data-magnetic data-link>CONTACT</a>
</nav>
<div class="topnav__actions">
<button class="topnav__mute" id="mute-btn" data-magnetic aria-label="Mute">
<svg class="mute-on" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
<path d="M11 5L6 9H2v6h4l5 4z"/>
<line x1="23" y1="9" x2="17" y2="15"/>
<line x1="17" y1="9" x2="23" y2="15"/>
</svg>
<svg class="mute-off" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" style="display:none;">
<path d="M11 5L6 9H2v6h4l5 4z"/>
<path d="M15.5 8.5a5 5 0 010 7M19 5a10 10 0 010 14"/>
</svg>
</button>
<a href="#" class="topnav__cta" data-magnetic>
<span>Let's Talk</span>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
<path d="M5 12h14M13 6l6 6-6 6" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</a>
</div>
</header>
<!-- ========== LEFT RAIL ========== -->
<aside class="rail rail--left">
<div class="rail__dots" data-rail>
<span></span><span></span><span></span>
<span></span><span></span><span></span>
<span></span><span></span><span></span>
</div>
<a href="#" class="rail__phone" data-rail>+(02)·574·328·301</a>
<div class="rail__scroll" data-rail>
<span class="rail__scroll-label">SCROLL DOWN</span>
<span class="rail__scroll-line"></span>
<span class="rail__scroll-arrow">↓</span>
</div>
</aside>
<!-- ========== RIGHT RAIL ========== -->
<aside class="rail rail--right">
<div class="rail__follow" data-rail>
<span class="rail__follow-label">FOLLOW ME</span>
<span class="rail__follow-line"></span>
</div>
<div class="rail__social" data-rail>
<a href="#" class="rail__social-icon" data-social aria-label="Behance"><span>Be</span></a>
<a href="#" class="rail__social-icon" data-social aria-label="Dribbble">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
<circle cx="12" cy="12" r="9"/>
<path d="M3 12c6 0 13 1 18 7M5 6c4 2 11 8 14 15M20 6c-4 4-12 6-17 4"/>
</svg>
</a>
<a href="#" class="rail__social-icon" data-social aria-label="Twitter">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M18.9 7.3c0 .2 0 .4 0 .5 0 5.4-4.1 11.6-11.6 11.6-2.3 0-4.5-.7-6.3-1.9.3 0 .6.1 1 .1 1.9 0 3.7-.7 5.1-1.8-1.8 0-3.3-1.2-3.9-2.9.3 0 .5.1.8.1.4 0 .7 0 1.1-.1-1.9-.4-3.4-2.1-3.4-4.2v-.1c.6.3 1.2.5 1.9.5-1.1-.8-1.9-2.2-1.9-3.7 0-.8.2-1.5.6-2.1 2.1 2.5 5.1 4.1 8.6 4.3-.1-.3-.1-.6-.1-.9 0-2.3 1.8-4.1 4.1-4.1 1.2 0 2.3.5 3 1.3.9-.2 1.8-.5 2.6-1-.3 1-1 1.8-1.8 2.3.8-.1 1.6-.3 2.4-.6-.6.8-1.3 1.5-2.1 2.1z"/></svg>
</a>
<a href="#" class="rail__social-icon" data-social aria-label="LinkedIn">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M19.5 3h-15C3.7 3 3 3.7 3 4.5v15c0 .8.7 1.5 1.5 1.5h15c.8 0 1.5-.7 1.5-1.5v-15c0-.8-.7-1.5-1.5-1.5zM8.3 18H5.7V9.8h2.6V18zM7 8.6c-.8 0-1.5-.7-1.5-1.5S6.2 5.6 7 5.6s1.5.7 1.5 1.5S7.8 8.6 7 8.6zM18.3 18h-2.6v-4.2c0-1 0-2.3-1.4-2.3s-1.6 1.1-1.6 2.2V18H10.1V9.8h2.5v1.1h.1c.3-.7 1.2-1.4 2.5-1.4 2.7 0 3.2 1.8 3.2 4V18z"/></svg>
</a>
</div>
</aside>
<!-- ========== HERO CONTENT ========== -->
<div class="hero" id="hero">
<a href="#" class="hero__eyebrow" data-magnetic data-eyebrow>
<span class="hero__eyebrow-text">Currently available for freelance<br>worldwide</span>
<span class="hero__eyebrow-arrow">↗</span>
</a>
<h1 class="hero__title" aria-label="Creative Visual Designer">
<span class="hero__line" data-title-line>Creative Visual</span>
<span class="hero__line" data-title-line>Designer</span>
</h1>
<a href="#" class="hero__play" data-play data-hover>
<svg class="hero__play-scribble" viewBox="0 0 80 60" aria-hidden="true">
<path d="M10 30 Q 20 10, 40 20 T 70 35" stroke="#c9ff2d" stroke-width="1.8" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M65 30 L 70 35 L 65 40" stroke="#c9ff2d" stroke-width="1.8" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<span class="hero__play-btn">
<svg viewBox="0 0 32 32" fill="none">
<circle cx="16" cy="16" r="15" stroke="#ffffff" stroke-width="1" fill="none"/>
<path d="M13 11l9 5-9 5z" fill="#ffffff"/>
</svg>
<svg class="hero__play-ring" viewBox="0 0 32 32" fill="none" aria-hidden="true">
<circle cx="16" cy="16" r="15.5" stroke="#c9ff2d" stroke-width="0.8" stroke-dasharray="4 3"/>
</svg>
</span>
<span class="hero__play-label">
<span>Work</span>
<span>Process</span>
</span>
</a>
<!-- Floating stat chips -->
<div class="chips" data-chips>
<span class="chip"><b>12+</b> Years Experience</span>
<span class="chip"><b>240+</b> Projects Delivered</span>
<span class="chip"><b>18</b> Awards</span>
</div>
</div>
<!-- ========== MARQUEE ========== -->
<div class="marquee" id="marquee">
<div class="marquee__track" id="marquee-track">
<div class="marquee__group">
<span class="marquee__item">✴ Website Design & Logo</span>
<span class="marquee__item">✴ Business Branding</span>
<span class="marquee__item">✴ Mobile Application Design</span>
<span class="marquee__item">✴ UI/UX Mobile Design</span>
<span class="marquee__item">✴ Motion & Interaction</span>
</div>
<div class="marquee__group" aria-hidden="true">
<span class="marquee__item">✴ Website Design & Logo</span>
<span class="marquee__item">✴ Business Branding</span>
<span class="marquee__item">✴ Mobile Application Design</span>
<span class="marquee__item">✴ UI/UX Mobile Design</span>
<span class="marquee__item">✴ Motion & Interaction</span>
</div>
</div>
</div>
</section>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
<script src="banner-creative-reel.js"></script>
</body>
</html>
</body>
</html>JS banner-creative-reel.js — GSAP animation timeline
(() => {
const root = document.getElementById('reel');
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 = ' ';
} else {
span.textContent = ch;
}
line.appendChild(span);
});
});
// -------------------------------------------------------------------
// REFERENCES
// -------------------------------------------------------------------
const loader = document.getElementById('loader');
const clapper = document.getElementById('clapper');
const clapperArm = document.getElementById('clapper-arm');
const countdown = document.getElementById('countdown');
const loaderLabel = loader.querySelector('.loader__label');
const video = document.getElementById('reel-video');
const muteBtn = document.getElementById('mute-btn');
const muteOn = muteBtn.querySelector('.mute-on');
const muteOff = muteBtn.querySelector('.mute-off');
const cursorDot = document.getElementById('cursor-dot');
const cursorRing = document.getElementById('cursor-ring');
const magnetics = root.querySelectorAll('[data-magnetic]');
const rails = root.querySelectorAll('[data-rail]');
const socials = root.querySelectorAll('[data-social]');
const eyebrow = root.querySelector('[data-eyebrow]');
const titleChars = root.querySelectorAll('.hero__char');
const playBtn = root.querySelector('[data-play]');
const playRing = root.querySelector('.hero__play-ring');
const playScribble = root.querySelector('.hero__play-scribble path');
const chips = root.querySelector('[data-chips]');
const chipEls = root.querySelectorAll('.chip');
const marqueeTrack = document.getElementById('marquee-track');
// -------------------------------------------------------------------
// INITIAL STATES
// -------------------------------------------------------------------
gsap.set(magnetics, { y: -20, opacity: 0 });
gsap.set(rails, { x: (i, el) => el.closest('.rail--left') ? -30 : 30, opacity: 0 });
gsap.set(socials, { x: 30, opacity: 0 });
gsap.set(eyebrow, { y: 20, opacity: 0 });
gsap.set(titleChars, { yPercent: 110, opacity: 0 });
gsap.set(playBtn, { y: 30, opacity: 0 });
gsap.set(chips, { y: 30, opacity: 0 });
gsap.set(chipEls, { scale: 0.8, opacity: 0 });
gsap.set(video, { scale: 1.15, opacity: 0 });
// -------------------------------------------------------------------
// LOADER TIMELINE — Clapperboard countdown
// -------------------------------------------------------------------
const loaderTl = gsap.timeline({ onComplete: playScene });
// Clapper entrance
loaderTl.from(clapper, {
y: -30,
opacity: 0,
scale: 0.92,
duration: 0.6,
ease: 'power3.out',
}, 0);
// Countdown: 3 → 2 → 1 → ACTION
const counts = ['3', '2', '1', 'ACTION'];
counts.forEach((val, i) => {
loaderTl.call(() => {
countdown.textContent = val;
gsap.fromTo(countdown,
{ scale: 1.4, opacity: 0 },
{ scale: 1, opacity: 1, duration: 0.35, ease: 'back.out(2)' }
);
}, null, 0.7 + i * 0.75);
});
// Update label when ACTION
loaderTl.call(() => {
loaderLabel.textContent = 'TAKE 01';
}, null, 0.7 + 3 * 0.75);
// Clap arm snaps shut with a bounce
loaderTl.to(clapperArm, {
rotation: -28,
duration: 0.5,
ease: 'power2.in',
}, '+=0.25');
loaderTl.to(clapperArm, {
rotation: 0,
duration: 0.25,
ease: 'power4.in',
onComplete: () => {
// Sound wave pulse effect
gsap.fromTo(clapper,
{ scale: 1 },
{ scale: 1.04, duration: 0.1, yoyo: true, repeat: 1, ease: 'sine.inOut' }
);
},
});
// Exit: clapper rotates + shoots up, countdown shrinks, loader fades
loaderTl.to(countdown, {
scale: 3,
opacity: 0,
duration: 0.5,
ease: 'power3.in',
}, '+=0.15');
loaderTl.to(clapper, {
y: -80,
rotation: -8,
scale: 0.85,
opacity: 0,
duration: 0.7,
ease: 'power3.in',
}, '<');
loaderTl.to(loaderLabel, {
opacity: 0,
y: -10,
duration: 0.3,
}, '<');
loaderTl.to(loader, {
yPercent: -100,
duration: 0.8,
ease: 'power4.inOut',
}, '-=0.2');
loaderTl.set(loader, { display: 'none' });
// -------------------------------------------------------------------
// MAIN SCENE ENTRANCE
// -------------------------------------------------------------------
function playScene() {
const tl = gsap.timeline({ defaults: { ease: 'power3.out' } });
// Video fades in + scale settle
tl.to(video, {
scale: 1,
opacity: 1,
duration: 1.6,
ease: 'power3.out',
}, 0);
// Nav
tl.to(magnetics, {
y: 0, opacity: 1,
duration: 0.6,
stagger: 0.05,
}, 0.2);
// Rails
tl.to(rails, {
x: 0, opacity: 1,
duration: 0.7,
stagger: 0.08,
}, 0.4);
tl.to(socials, {
x: 0, opacity: 1,
duration: 0.5,
stagger: 0.06,
}, 0.55);
// Eyebrow
tl.to(eyebrow, {
y: 0, opacity: 1,
duration: 0.7,
}, 0.8);
// Title chars
tl.to(titleChars, {
yPercent: 0, opacity: 1,
duration: 1.1,
stagger: 0.02,
ease: 'expo.out',
}, 0.95);
// Play button
tl.to(playBtn, {
y: 0, opacity: 1,
duration: 0.8,
ease: 'back.out(1.6)',
}, 1.5);
// Scribble draw
tl.to(playScribble, {
strokeDashoffset: 0,
duration: 0.9,
ease: 'power2.out',
}, 1.7);
// Chips container + stagger
tl.to(chips, { y: 0, opacity: 1, duration: 0.5 }, 1.7);
tl.to(chipEls, {
scale: 1, opacity: 1,
duration: 0.5,
stagger: 0.1,
ease: 'back.out(1.7)',
}, 1.8);
tl.call(startContinuous, null, 2.1);
tl.call(enableInteractions, null, 2.1);
}
// -------------------------------------------------------------------
// CONTINUOUS ANIMATIONS
// -------------------------------------------------------------------
let playRingRot = null;
let marqueeAnim = null;
let scrollPulse = null;
function startContinuous() {
playRingRot = gsap.to(playRing, {
rotation: 360,
duration: 8,
repeat: -1,
ease: 'none',
transformOrigin: 'center center',
});
const group = marqueeTrack.querySelector('.marquee__group');
const groupWidth = group.offsetWidth;
marqueeAnim = gsap.to(marqueeTrack, {
x: -groupWidth,
duration: 28,
ease: 'none',
repeat: -1,
modifiers: { x: gsap.utils.unitize(x => parseFloat(x) % groupWidth) },
});
const scrollLine = root.querySelector('.rail__scroll-line');
if (scrollLine) {
scrollPulse = gsap.fromTo(scrollLine, { scaleY: 0.3 }, {
scaleY: 1,
duration: 1.6,
yoyo: true,
repeat: -1,
ease: 'sine.inOut',
transformOrigin: 'top',
});
}
}
// -------------------------------------------------------------------
// 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 });
});
// Expand ring on interactive elements
const hovers = root.querySelectorAll('a, button, [data-magnetic], [data-hover], .chip, .rail__social-icon, .rail__dots span');
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('topnav__cta') ? 0.35
: el.classList.contains('topnav__mute') ? 0.45
: el.classList.contains('topnav__logo') ? 0.2
: el.classList.contains('hero__eyebrow') ? 0.18
: 0.25;
el.addEventListener('mousemove', (e) => {
const r = el.getBoundingClientRect();
const cx = r.left + r.width / 2;
const cy = r.top + r.height / 2;
const dx = (e.clientX - cx) * strength;
const dy = (e.clientY - cy) * strength;
gsap.to(el, { x: dx, y: dy, 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 < 160) gsap.set(c, { y: -(1 - dist / 160) * 22 });
else gsap.set(c, { y: 0 });
});
});
titleChars.forEach((c) => {
c.addEventListener('mouseenter', () => gsap.to(c, { color: '#c9ff2d', duration: 0.2 }));
c.addEventListener('mouseleave', () => gsap.to(c, { color: '#ffffff', duration: 0.4 }));
});
// ---- Socials spring ----
socials.forEach((s) => {
s.addEventListener('mouseenter', () => {
gsap.to(s, { scale: 1.18, rotation: -8, duration: 0.4, ease: 'back.out(2)' });
});
s.addEventListener('mouseleave', () => {
gsap.to(s, { scale: 1, rotation: 0, duration: 0.5, ease: 'elastic.out(1, 0.4)' });
});
});
// ---- Dots ripple ----
const dots = root.querySelectorAll('.rail__dots span');
dots.forEach((dot, i) => {
dot.addEventListener('mouseenter', () => {
dots.forEach((d, j) => {
gsap.to(d, {
scale: 1.8,
delay: Math.abs(j - i) * 0.04,
duration: 0.25,
yoyo: true,
repeat: 1,
ease: 'power2.inOut',
});
});
});
});
// ---- Play button ----
playBtn.addEventListener('mouseenter', () => {
if (playRingRot) playRingRot.timeScale(4);
gsap.fromTo(playScribble,
{ strokeDashoffset: 120 },
{ strokeDashoffset: 0, duration: 0.6, ease: 'power2.out' }
);
});
playBtn.addEventListener('mouseleave', () => {
if (playRingRot) playRingRot.timeScale(1);
});
// ---- Chips hover tilt ----
chipEls.forEach((chip) => {
chip.addEventListener('mouseenter', () => {
gsap.to(chip, { y: -4, rotation: gsap.utils.random(-3, 3), duration: 0.35, ease: 'back.out(2)' });
});
chip.addEventListener('mouseleave', () => {
gsap.to(chip, { y: 0, rotation: 0, duration: 0.5, ease: 'elastic.out(1, 0.4)' });
});
});
// ---- Marquee pause on hover ----
const marqueeEl = document.getElementById('marquee');
marqueeEl.addEventListener('mouseenter', () => {
if (marqueeAnim) gsap.to(marqueeAnim, { timeScale: 0.2, duration: 0.4 });
});
marqueeEl.addEventListener('mouseleave', () => {
if (marqueeAnim) gsap.to(marqueeAnim, { timeScale: 1, duration: 0.4 });
});
// ---- Mute toggle ----
muteBtn.addEventListener('click', (e) => {
e.preventDefault();
video.muted = !video.muted;
muteOn.style.display = video.muted ? '' : 'none';
muteOff.style.display = video.muted ? 'none' : '';
if (!video.muted) video.play().catch(() => {});
});
// Ensure video plays (some browsers need user-interaction)
video.play().catch(() => {
// Fallback: show poster; attempt play on any click
const tryPlay = () => {
video.play().catch(() => {});
window.removeEventListener('click', tryPlay);
};
window.addEventListener('click', tryPlay);
});
// ---- Video subtle parallax ----
let vX = 0, vY = 0, vcX = 0, vcY = 0;
root.addEventListener('mousemove', (e) => {
const r = root.getBoundingClientRect();
vX = ((e.clientX - r.left) / r.width - 0.5) * 2;
vY = ((e.clientY - r.top) / r.height - 0.5) * 2;
});
root.addEventListener('mouseleave', () => { vX = 0; vY = 0; });
gsap.ticker.add(() => {
vcX += (vX - vcX) * 0.04;
vcY += (vY - vcY) * 0.04;
gsap.set(video, { x: -vcX * 15, y: -vcY * 10, scale: 1.05 });
});
}
})();