nicholais-website/app/sections/ProcessSection.tsx

116 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import React, { useRef } from "react";
import { motion, useTransform } from "motion/react";
import { useSectionProgress } from "@/lib/scroll";
import { Parallax } from "@/components/parallax/Parallax";
import { Reveal } from "@/components/motion/Reveal";
import { Stagger } from "@/components/motion/Stagger";
import { TRANSITIONS } from "@/lib/animation";
export function ProcessSection() {
const sectionRef = useRef<HTMLElement>(null!);
const progress = useSectionProgress(sectionRef);
const pathLength = useTransform(progress, [0, 1], [0, 1]);
const steps = [
{
title: "Discover",
desc:
"Align on goals, audience, and tone. Define constraints and success metrics.",
},
{
title: "Design",
desc:
"Establish visual language, motion rhythm, and section-level compositions.",
},
{
title: "Build",
desc:
"Implement Lenis scroll orchestration and Framer Motion systems with a11y in mind.",
},
{
title: "Polish",
desc:
"Optimize performance, refine microinteractions, and tune parallax depth.",
},
];
return (
<section
id="process"
ref={sectionRef}
aria-label="Process"
className="relative w-full overflow-clip py-28 md:py-36"
>
{/* Ambient vignette */}
<Parallax speed={0.04} className="pointer-events-none absolute inset-0 -z-10">
<div className="absolute inset-0 bg-[radial-gradient(900px_480px_at_10%_20%,rgba(255,255,255,0.08),transparent_70%)]" />
</Parallax>
<div className="mx-auto w-full max-w-6xl px-6">
<div className="text-center mb-12">
<motion.h2
className="text-2xl sm:text-3xl md:text-4xl font-bold tracking-tight text-neutral-100"
initial={{ opacity: 0, y: 10 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={TRANSITIONS.base}
>
Process
</motion.h2>
<motion.p
className="mt-2 text-sm text-neutral-400"
initial={{ opacity: 0, y: 6 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ ...TRANSITIONS.base, delay: 0.05 }}
>
A simple path from idea to cinematic, performant delivery.
</motion.p>
</div>
{/* Timeline drawing */}
<div className="relative">
<motion.svg
width="100%"
height="220"
viewBox="0 0 1200 220"
className="hidden md:block"
>
<motion.path
d="M 40 180 C 320 60, 880 300, 1160 80"
fill="none"
stroke="currentColor"
className="text-neutral-700"
strokeWidth="2"
strokeLinecap="round"
style={{ pathLength }}
/>
</motion.svg>
<div className="mt-0 grid grid-cols-1 gap-6 md:-mt-16 md:grid-cols-4">
<Stagger delayChildren={0.05}>
{steps.map((s, i) => (
<Reveal key={s.title} delay={i * 0.05} distance={16}>
<article className="relative rounded-2xl glass p-5">
<div className="mb-2 text-xs font-semibold uppercase tracking-wider text-neutral-400">
{String(i + 1).padStart(2, "0")}
</div>
<h3 className="text-lg font-semibold text-neutral-100">
{s.title}
</h3>
<p className="mt-2 text-sm text-neutral-300">
{s.desc}
</p>
</article>
</Reveal>
))}
</Stagger>
</div>
</div>
</div>
</section>
);
}