95 lines
3.6 KiB
TypeScript
95 lines
3.6 KiB
TypeScript
"use client";
|
|
|
|
import React from "react";
|
|
import { motion } from "motion/react";
|
|
import { Parallax } from "@/components/parallax/Parallax";
|
|
import { FlipWords } from "@/components/ui/flip-words";
|
|
import { AvatarMotion } from "@/app/components/avatar-motion";
|
|
import { TRANSITIONS } from "@/lib/animation";
|
|
|
|
export function HeroSection() {
|
|
return (
|
|
<section
|
|
id="hero"
|
|
aria-label="Hero"
|
|
className="relative min-h-[130vh] w-full overflow-clip flex items-center"
|
|
>
|
|
{/* Background depth layers */}
|
|
<Parallax speed={0.05} className="pointer-events-none absolute inset-0 -z-20">
|
|
<div className="absolute inset-0 bg-[radial-gradient(1200px_600px_at_50%_-20%,rgba(255,255,255,0.10),transparent_70%)]" />
|
|
</Parallax>
|
|
|
|
<Parallax speed={0.08} className="pointer-events-none absolute inset-0 -z-10">
|
|
<div className="absolute -inset-x-10 -inset-y-20 bg-gradient-to-b from-transparent via-white/5 to-transparent blur-2xl" />
|
|
</Parallax>
|
|
|
|
{/* Content */}
|
|
<div className="relative z-10 mx-auto flex w-full max-w-5xl flex-col items-center gap-8 px-6">
|
|
<Parallax speed={-0.12} className="mt-24">
|
|
<AvatarMotion
|
|
src="/images/profile.jpg"
|
|
srcSet={{
|
|
avif: {
|
|
'120': '/images/profile-120.avif',
|
|
'160': '/images/profile-160.avif',
|
|
'original': '/images/profile.avif'
|
|
},
|
|
fallback: '/images/profile.jpg'
|
|
}}
|
|
alt="Hand drawn portrait of Nicholai"
|
|
size={200}
|
|
className="ring-1 ring-white/10"
|
|
/>
|
|
</Parallax>
|
|
|
|
<div className="text-center">
|
|
<motion.h1
|
|
className="mx-auto max-w-3xl bg-clip-text text-5xl font-extrabold tracking-tight text-transparent sm:text-6xl md:text-7xl
|
|
bg-gradient-to-b from-neutral-100 to-neutral-300"
|
|
initial={{ opacity: 0, y: 24, filter: "blur(8px)" }}
|
|
animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
|
|
transition={TRANSITIONS.base}
|
|
>
|
|
Nicholai
|
|
</motion.h1>
|
|
|
|
<motion.p
|
|
className="mx-auto mt-3 max-w-xl text-balance text-sm text-neutral-300 sm:text-base"
|
|
initial={{ opacity: 0, y: 12 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ ...TRANSITIONS.base, delay: 0.1 }}
|
|
>
|
|
Building cinematic web moments with code and craft.
|
|
</motion.p>
|
|
|
|
<motion.div
|
|
className="mx-auto mt-4 text-base sm:text-lg text-neutral-200"
|
|
initial={{ opacity: 0, y: 8 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ ...TRANSITIONS.base, delay: 0.2 }}
|
|
>
|
|
<FlipWords
|
|
words={["VFX Artist", "Developer", "Experience Designer"]}
|
|
className="font-medium"
|
|
/>
|
|
</motion.div>
|
|
</div>
|
|
|
|
{/* Scroll cue */}
|
|
<motion.div
|
|
aria-hidden
|
|
className="absolute bottom-8 left-1/2 -translate-x-1/2 text-neutral-400"
|
|
initial={{ opacity: 0, y: 0 }}
|
|
animate={{ opacity: 1, y: [0, 6, 0] }}
|
|
transition={{ duration: 1.8, repeat: Infinity, ease: [0.2, 0.8, 0.2, 1] }}
|
|
>
|
|
<svg width="20" height="28" viewBox="0 0 20 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<rect x="1.5" y="1.5" width="17" height="25" rx="8.5" stroke="currentColor" opacity="0.45"/>
|
|
<circle cx="10" cy="7" r="2" fill="currentColor"/>
|
|
</svg>
|
|
</motion.div>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|