Retour au catalogue
Process Animated
Process steps en cards qui s'animent sequentiellement au scroll avec stagger et scale.
processmedium Both Responsive a11y
boldplayfuluniversalsaasagencygrid
Theme
"use client";
import { motion } from "framer-motion";
import { ArrowRight } from "lucide-react";
interface StepItem {
number: string;
title: string;
description: string;
}
interface ProcessAnimatedProps {
badge?: string;
title?: string;
subtitle?: string;
steps?: StepItem[];
}
const ease: [number, number, number, number] = [0.16, 1, 0.3, 1];
export default function ProcessAnimated({
badge = "Process",
title = "Comment ca marche",
subtitle = "Trois etapes simples pour demarrer.",
steps = [],
}: ProcessAnimatedProps) {
return (
<section
className="py-20 lg:py-28"
style={{ background: "var(--color-background)" }}
>
<div className="mx-auto max-w-5xl px-6">
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, ease }}
viewport={{ once: true }}
className="text-center mb-16"
>
{badge && (
<span
className="inline-block mb-4 text-xs font-medium tracking-widest uppercase"
style={{ color: "var(--color-accent)" }}
>
{badge}
</span>
)}
<h2
className="text-3xl md:text-4xl lg:text-5xl font-bold"
style={{ color: "var(--color-foreground)" }}
>
{title}
</h2>
{subtitle && (
<p className="mt-3 text-base" style={{ color: "var(--color-foreground-muted)" }}>
{subtitle}
</p>
)}
</motion.div>
<div className="grid md:grid-cols-3 gap-8">
{steps.map((step, i) => (
<motion.div
key={step.number}
initial={{ opacity: 0, y: 40, scale: 0.95 }}
whileInView={{ opacity: 1, y: 0, scale: 1 }}
transition={{
duration: 0.6,
ease,
delay: i * 0.15,
}}
viewport={{ once: true, margin: "-80px" }}
className="relative rounded-xl p-8 text-center"
style={{
background: "var(--color-background-alt)",
border: "1px solid var(--color-border)",
}}
>
{/* Step number */}
<motion.div
initial={{ scale: 0 }}
whileInView={{ scale: 1 }}
transition={{ duration: 0.4, ease, delay: i * 0.15 + 0.2 }}
viewport={{ once: true }}
className="w-12 h-12 rounded-full flex items-center justify-center mx-auto mb-5"
style={{ background: "var(--color-accent)" }}
>
<span
className="text-sm font-bold"
style={{ color: "var(--color-background)" }}
>
{step.number}
</span>
</motion.div>
<h3
className="text-lg font-bold mb-3"
style={{ color: "var(--color-foreground)" }}
>
{step.title}
</h3>
<p
className="text-sm leading-relaxed"
style={{ color: "var(--color-foreground-muted)" }}
>
{step.description}
</p>
{/* Arrow connector (not on last) */}
{i < steps.length - 1 && (
<div className="hidden md:flex absolute -right-4 top-1/2 -translate-y-1/2 z-10">
<ArrowRight size={16} style={{ color: "var(--color-accent)", opacity: 0.5 }} />
</div>
)}
</motion.div>
))}
</div>
</div>
</section>
);
}