117 lines
4.1 KiB
TypeScript
117 lines
4.1 KiB
TypeScript
"use client";
|
|
|
|
/**
|
|
* Hero — type IS the hero. A display headline at 8-14vw reveals line by line
|
|
* (manual masked split via KineticText), the iridescent wave asset floats as a
|
|
* tasteful accent layer, and a trust line anchors the claim. Parallax on the
|
|
* accent + headline as the hero scrolls out.
|
|
*/
|
|
|
|
import { useEffect, useRef } from "react";
|
|
import { gsap } from "gsap";
|
|
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
|
import KineticText from "./KineticText";
|
|
import Magnetic from "./Magnetic";
|
|
|
|
gsap.registerPlugin(ScrollTrigger);
|
|
|
|
export default function Hero() {
|
|
const root = useRef<HTMLElement>(null);
|
|
|
|
useEffect(() => {
|
|
const el = root.current;
|
|
if (!el) return;
|
|
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
|
|
|
|
const ctx = gsap.context(() => {
|
|
const tl = gsap.timeline({ defaults: { ease: "power4.out" } });
|
|
tl.from(".hero__eyebrow", { y: 18, opacity: 0, duration: 0.9, delay: 0.15 })
|
|
.from(".hero__accent", { opacity: 0, scale: 1.06, duration: 1.4 }, 0)
|
|
.from(".hero__sub", { y: 22, opacity: 0, duration: 0.9 }, "-=0.2")
|
|
.from(".hero__actions > *", { y: 20, opacity: 0, stagger: 0.1, duration: 0.7 }, "-=0.5")
|
|
.from(".hero__trust", { opacity: 0, duration: 0.8 }, "-=0.4");
|
|
|
|
// parallax: accent drifts up, headline lifts + fades as hero scrolls out
|
|
gsap.to(".hero__accent", {
|
|
yPercent: -18,
|
|
ease: "none",
|
|
scrollTrigger: { trigger: el, start: "top top", end: "bottom top", scrub: true },
|
|
});
|
|
gsap.to(".hero__display", {
|
|
yPercent: 14,
|
|
opacity: 0.18,
|
|
ease: "none",
|
|
scrollTrigger: { trigger: el, start: "top top", end: "bottom top", scrub: true },
|
|
});
|
|
}, el);
|
|
|
|
return () => ctx.revert();
|
|
}, []);
|
|
|
|
return (
|
|
<section className="hero" ref={root}>
|
|
{/* iridescent wave accent — decorative texture layer */}
|
|
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
<img
|
|
src="/assets/hero-iridescent-1.png"
|
|
alt=""
|
|
aria-hidden="true"
|
|
className="hero__accent"
|
|
width={1344}
|
|
height={768}
|
|
fetchPriority="high"
|
|
decoding="async"
|
|
/>
|
|
|
|
<div className="hero__inner wrap">
|
|
<p className="hero__eyebrow">
|
|
<span className="dot" aria-hidden="true" />
|
|
Digital marketing agency
|
|
</p>
|
|
|
|
<h1 className="hero__display">
|
|
<KineticText as="span" className="hero__line" text="Marketing that" immediate delay={0.25} />
|
|
<KineticText as="span" className="hero__line" text="grows your" immediate delay={0.38} />
|
|
<KineticText
|
|
as="span"
|
|
className="hero__line hero__line--grad"
|
|
text="revenue."
|
|
immediate
|
|
delay={0.5}
|
|
highlight={[0, 0]}
|
|
/>
|
|
</h1>
|
|
|
|
<p className="hero__sub">
|
|
We're a results-driven digital marketing agency. We run paid, SEO,
|
|
and content programs built around <strong>your revenue targets</strong>,
|
|
then show you what they returned. Every month.
|
|
</p>
|
|
|
|
<div className="hero__actions">
|
|
<Magnetic strength={0.5}>
|
|
<a className="btn btn--primary hoverable" href="#contact" data-cursor="let's talk">
|
|
<span>Get your growth audit</span>
|
|
</a>
|
|
</Magnetic>
|
|
<a className="hero__secondary hoverable" href="#results">
|
|
See the results <span aria-hidden="true">→</span>
|
|
</a>
|
|
</div>
|
|
|
|
<p className="hero__trust">
|
|
<strong>$40M+</strong> in client revenue generated
|
|
<span className="hero__trust-sep" aria-hidden="true" />
|
|
<strong>50+</strong> brands grown
|
|
</p>
|
|
</div>
|
|
|
|
<a className="hero__scroll hoverable" href="#position" aria-label="Scroll to the next section">
|
|
<span>scroll</span>
|
|
<svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true">
|
|
<path d="M12 4v16m0 0l-6-6m6 6l6-6" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
|
|
</svg>
|
|
</a>
|
|
</section>
|
|
);
|
|
}
|