diff --git a/apps/marketing/public/hero-bg.mp4 b/apps/marketing/public/hero-bg.mp4 new file mode 100644 index 0000000..ac43cd1 Binary files /dev/null and b/apps/marketing/public/hero-bg.mp4 differ diff --git a/apps/marketing/src/components/marketing/sections/hero.tsx b/apps/marketing/src/components/marketing/sections/hero.tsx index f9d4fde..0638965 100644 --- a/apps/marketing/src/components/marketing/sections/hero.tsx +++ b/apps/marketing/src/components/marketing/sections/hero.tsx @@ -4,71 +4,26 @@ import { useRef } from "react"; import { WEB_URLS } from "@/lib/app-urls"; import { gsap, useGSAP } from "@/lib/use-gsap"; +// Full-viewport hero: a muted looping video fills the section edge-to-edge, +// a dimming gradient keeps foreground copy readable, and the content stack +// is anchored to the lower-left. The site's fixed MarketingHeader is the top +// overlay (it sits above this on z). Background falls back to the ink canvas +// for reduced-motion users and while the video loads. export function Hero() { const root = useRef(null); useGSAP( () => { - const tl = gsap.timeline({ - defaults: { ease: "expo.out", duration: 1.2 }, - }); - - tl.from(".hero-eyebrow", { y: 30, autoAlpha: 0 }) - .from( - ".hero-title-line", - { y: "110%", duration: 1.3, stagger: 0.08 }, - "-=0.8", - ) - .from(".hero-sub", { y: 30, autoAlpha: 0 }, "-=0.6") - .from(".hero-cta", { y: 20, autoAlpha: 0, stagger: 0.08 }, "-=0.7") - .from(".hero-meta", { autoAlpha: 0 }, "-=0.5") - .from( - ".hero-art", - { autoAlpha: 0, scale: 0.92, duration: 1.4 }, - "-=1.4", - ); - - // Parallax on scroll - gsap.to(".hero-bg-art", { - yPercent: 30, - ease: "none", - scrollTrigger: { - trigger: root.current, - start: "top top", - end: "bottom top", - scrub: true, - }, - }); - - gsap.to(".hero-art", { - yPercent: -18, - ease: "none", - scrollTrigger: { - trigger: root.current, - start: "top top", - end: "bottom top", - scrub: true, - }, - }); - - gsap.to(".hero-art-ring", { - rotation: 360, - transformOrigin: "50% 50%", - ease: "none", - duration: 80, - repeat: -1, - }); - - gsap.to(".hero-title", { - yPercent: -10, - autoAlpha: 0.6, - ease: "none", - scrollTrigger: { - trigger: root.current, - start: "top top", - end: "bottom top", - scrub: true, - }, + // Only animate when the user hasn't asked for reduced motion — + // otherwise the content keeps its natural (visible) state. + const mm = gsap.matchMedia(); + mm.add("(prefers-reduced-motion: no-preference)", () => { + gsap + .timeline({ defaults: { ease: "expo.out", duration: 1.1 } }) + .from(".hero-eyebrow", { y: 24, autoAlpha: 0 }) + .from(".hero-title-line", { yPercent: 110, stagger: 0.1 }, "-=0.7") + .from(".hero-sub", { y: 24, autoAlpha: 0 }, "-=0.7") + .from(".hero-cta", { y: 18, autoAlpha: 0, stagger: 0.1 }, "-=0.7"); }); }, { scope: root }, @@ -77,62 +32,57 @@ export function Hero() { return (
- {/* Background art */} -