feat: enhance 3D floating particles and geometric shapes; improve background animations and parallax effects

This commit is contained in:
defiQUG
2025-10-04 21:21:44 -07:00
parent b96b9d93d5
commit 184057a0f7

View File

@@ -143,32 +143,87 @@ function ParallaxContainer({ children, depth = 1, className = '' }: ParallaxCont
)
}
// Floating Particles Background
// Enhanced 3D Floating Particles Background
function FloatingParticles() {
const particles = Array.from({ length: 50 }, (_, i) => i)
const particles = Array.from({ length: 30 }, (_, i) => i)
return (
<div className="absolute inset-0 overflow-hidden pointer-events-none">
{particles.map((i) => (
{particles.map((i) => {
const size = Math.random() * 3 + 1
const depth = Math.random() * 4 + 1
return (
<motion.div
key={i}
className="absolute rounded-full bg-gradient-to-br from-primary-400/10 to-secondary-400/10 backdrop-blur-sm"
style={{
width: `${size}px`,
height: `${size}px`,
left: `${Math.random() * 100}%`,
top: `${Math.random() * 100}%`,
transformStyle: 'preserve-3d'
}}
animate={{
y: [-30, -120, -30],
x: [-15, 15, -15],
z: [0, depth * 20, 0],
opacity: [0.3, 0.8, 0.3],
scale: [0.8, 1.2, 0.8]
}}
transition={{
duration: Math.random() * 15 + 8,
repeat: Infinity,
delay: Math.random() * 3,
ease: "easeInOut"
}}
/>
)
})}
</div>
)
}
// 3D Geometric Shapes Component
function Floating3DShapes() {
const shapes = [
{ type: 'cube', color: 'from-primary-500/15 to-primary-600/15', size: 12 },
{ type: 'sphere', color: 'from-secondary-500/15 to-secondary-600/15', size: 16 },
{ type: 'pyramid', color: 'from-primary-400/15 to-secondary-500/15', size: 14 },
]
return (
<div className="absolute inset-0 overflow-hidden pointer-events-none">
{shapes.map((shape, i) => Array.from({ length: 3 }, (_, j) => (
<motion.div
key={i}
className="absolute w-1 h-1 bg-primary-400/20 rounded-full"
key={`${shape.type}-${i}-${j}`}
className={`absolute bg-gradient-to-br ${shape.color} backdrop-blur-sm ${
shape.type === 'cube' ? 'rounded-sm' :
shape.type === 'sphere' ? 'rounded-full' : 'rounded-sm'
}`}
style={{
left: `${Math.random() * 100}%`,
top: `${Math.random() * 100}%`,
width: `${shape.size}px`,
height: `${shape.size}px`,
left: `${(i * 30 + j * 15 + 10) % 90}%`,
top: `${(i * 25 + j * 20 + 15) % 80}%`,
transformStyle: 'preserve-3d',
filter: 'blur(0.5px)'
}}
animate={{
y: [-20, -100, -20],
x: [-10, 10, -10],
opacity: [0, 1, 0],
rotateX: [0, 360],
rotateY: [0, 360],
rotateZ: shape.type === 'pyramid' ? [0, 180, 360] : 0,
z: [0, 60, 0],
y: [-20, 20, -20]
}}
transition={{
duration: Math.random() * 10 + 5,
duration: 20 + i * 5,
repeat: Infinity,
delay: Math.random() * 2,
delay: j * 2,
ease: "linear"
}}
/>
))}
))
)}
</div>
)
}
@@ -466,12 +521,32 @@ function Hero() {
return (
<section ref={containerRef} className="relative isolate overflow-hidden min-h-screen flex items-center">
{/* 3D Background Layer */}
{/* Enhanced 3D Background Layers */}
<motion.div
className="absolute inset-0 bg-gradient-to-br from-primary-50/50 via-white to-secondary-50/50 dark:from-gray-900/50 dark:via-gray-800/50 dark:to-gray-900/50"
className="absolute inset-0 bg-gradient-to-br from-primary-50/30 via-white to-secondary-50/30 dark:from-gray-900/30 dark:via-gray-800/30 dark:to-gray-900/30"
style={{ y: backgroundY }}
>
<FloatingParticles />
{/* Animated depth gradient */}
<motion.div
className="absolute inset-0 opacity-20"
animate={{
background: [
"radial-gradient(800px 400px at 20% 30%, rgba(147, 51, 234, 0.1), transparent)",
"radial-gradient(600px 300px at 80% 60%, rgba(59, 130, 246, 0.1), transparent)",
"radial-gradient(700px 350px at 50% 20%, rgba(147, 51, 234, 0.1), transparent)"
]
}}
transition={{ duration: 15, repeat: Infinity, ease: "easeInOut" }}
/>
</motion.div>
<motion.div
className="absolute inset-0"
style={{ y: useTransform(scrollYProgress, [0, 1], ['0%', '30%']) }}
>
<Floating3DShapes />
</motion.div>
{/* Content Layer with Parallax */}
@@ -519,43 +594,135 @@ function Hero() {
</ParallaxContainer>
</motion.div>
{/* 3D Floating Elements */}
<div className="absolute inset-0 pointer-events-none">
{/* 3D Scroll Indicator */}
<motion.div
className="absolute bottom-8 left-1/2 -translate-x-1/2 hidden lg:block"
animate={{
y: [0, 10, 0],
rotateX: [0, 15, 0]
}}
transition={{ duration: 2, repeat: Infinity, ease: "easeInOut" }}
style={{ transformStyle: 'preserve-3d' }}
>
<div className="flex flex-col items-center gap-2 text-neutral-400 dark:text-neutral-500">
<span className="text-sm font-medium">Scroll to explore</span>
<motion.div
animate={{ y: [0, 5, 0] }}
transition={{ duration: 1.5, repeat: Infinity, ease: "easeInOut" }}
>
<ArrowRight className="h-5 w-5 rotate-90" />
</motion.div>
</div>
</motion.div>
{/* Enhanced 3D Icon Elements with More Visibility */}
<div className="absolute inset-0 pointer-events-none z-0">
{/* Top layer - more visible and engaging */}
<motion.div
className="absolute top-20 left-10 text-primary-300 dark:text-primary-600"
className="absolute top-1/4 left-[8%] text-primary-400/80 dark:text-primary-500/80 hidden lg:block"
animate={{
y: [-10, 10, -10],
y: [-15, 15, -15],
rotateY: [0, 360],
z: [0, 50, 0]
z: [0, 50, 0],
scale: [0.8, 1.2, 0.8]
}}
transition={{ duration: 6, repeat: Infinity, ease: "easeInOut" }}
style={{ transformStyle: 'preserve-3d' }}
style={{
transformStyle: 'preserve-3d',
filter: 'drop-shadow(0 4px 8px rgba(0,0,0,0.1))'
}}
>
<Heart className="h-8 w-8" />
</motion.div>
{/* Additional floating heart */}
<motion.div
className="absolute top-32 right-20 text-secondary-300 dark:text-secondary-600"
className="absolute top-1/3 right-1/4 text-rose-300/70 dark:text-rose-400/70 hidden xl:block"
animate={{
y: [10, -10, 10],
rotateX: [0, 180, 360],
z: [0, 30, 0]
rotateZ: [-15, 15, -15],
scale: [1, 1.3, 1]
}}
transition={{ duration: 4, repeat: Infinity, ease: "easeInOut", delay: 1 }}
style={{ transformStyle: 'preserve-3d' }}
>
<Sparkles className="h-6 w-6" />
<Heart className="h-5 w-5" />
</motion.div>
{/* Right side - more prominent sparkles */}
<motion.div
className="absolute bottom-32 left-20 text-primary-300 dark:text-primary-600"
className="absolute top-1/3 right-[12%] text-secondary-400/80 dark:text-secondary-500/80 hidden xl:block"
animate={{
y: [-8, 8, -8],
rotateZ: [0, 180, 360],
z: [0, 40, 0]
y: [20, -20, 20],
rotateX: [0, 180, 360],
z: [0, 40, 0],
scale: [0.9, 1.4, 0.9]
}}
transition={{ duration: 8, repeat: Infinity, ease: "easeInOut", delay: 2 }}
transition={{ duration: 5, repeat: Infinity, ease: "easeInOut", delay: 1.5 }}
style={{
transformStyle: 'preserve-3d',
filter: 'drop-shadow(0 2px 4px rgba(0,0,0,0.1))'
}}
>
<Sparkles className="h-7 w-7" />
</motion.div>
{/* Additional floating sparkle */}
<motion.div
className="absolute top-1/2 right-[20%] text-yellow-300/60 dark:text-yellow-400/60 hidden lg:block"
animate={{
rotate: [0, 360],
y: [-8, 8, -8],
scale: [0.7, 1.1, 0.7]
}}
transition={{ duration: 8, repeat: Infinity, ease: "easeInOut", delay: 3 }}
>
<Sparkles className="h-4 w-4" />
</motion.div>
{/* Bottom area - enhanced users icon */}
<motion.div
className="absolute bottom-1/4 left-[15%] text-primary-400/70 dark:text-primary-500/70 hidden lg:block"
animate={{
y: [-12, 12, -12],
rotateZ: [0, 180, 360],
z: [0, 45, 0],
scale: [0.8, 1.2, 0.8]
}}
transition={{ duration: 7, repeat: Infinity, ease: "easeInOut", delay: 3 }}
style={{
transformStyle: 'preserve-3d',
filter: 'drop-shadow(0 3px 6px rgba(0,0,0,0.1))'
}}
>
<Users className="h-6 w-6" />
</motion.div>
{/* Additional community icon */}
<motion.div
className="absolute bottom-1/3 right-[8%] text-blue-300/60 dark:text-blue-400/60 hidden xl:block"
animate={{
x: [-5, 5, -5],
y: [8, -8, 8],
rotateY: [0, 180, 360]
}}
transition={{ duration: 9, repeat: Infinity, ease: "easeInOut", delay: 4.5 }}
>
<Users className="h-4 w-4" />
</motion.div>
{/* Additional subtle elements */}
<motion.div
className="absolute top-1/2 right-[8%] text-primary-100/40 dark:text-primary-800/40 hidden xl:block"
animate={{
rotate: [0, 360],
scale: [0.8, 1.2, 0.8],
z: [0, 20, 0]
}}
transition={{ duration: 12, repeat: Infinity, ease: "easeInOut", delay: 4 }}
style={{ transformStyle: 'preserve-3d' }}
>
<Users className="h-7 w-7" />
<Star className="h-4 w-4" />
</motion.div>
</div>
</section>
@@ -647,12 +814,38 @@ function Programs() {
]
return (
<section id="programs" className="relative py-20">
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<SectionHeader eyebrow="What we do" title="Practical, student-first programs" subtitle="Flexible help that meets families where they are." />
<section id="programs" className="relative py-20 overflow-hidden">
{/* Background 3D Elements */}
<div className="absolute inset-0 pointer-events-none">
<motion.div
className="absolute top-10 right-10 w-32 h-32 bg-gradient-to-br from-primary-100/20 to-secondary-100/20 rounded-full blur-xl"
animate={{
y: [-20, 20, -20],
x: [-10, 10, -10],
scale: [0.8, 1.1, 0.8]
}}
transition={{ duration: 15, repeat: Infinity, ease: "easeInOut" }}
/>
<motion.div
className="absolute bottom-20 left-10 w-24 h-24 bg-gradient-to-br from-secondary-100/20 to-primary-100/20 rounded-full blur-xl"
animate={{
y: [15, -15, 15],
x: [8, -8, 8],
scale: [1, 0.9, 1]
}}
transition={{ duration: 12, repeat: Infinity, ease: "easeInOut", delay: 2 }}
/>
</div>
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 relative z-10">
<ParallaxContainer depth={0.2}>
<SectionHeader eyebrow="What we do" title="Practical, student-first programs" subtitle="Flexible help that meets families where they are." />
</ParallaxContainer>
<div className="mt-10 grid gap-6 md:grid-cols-3">
{items.map((i, idx) => (
<FeatureCard key={idx} icon={i.icon} title={i.title} body={i.body} />
<ParallaxContainer key={idx} depth={0.3 + idx * 0.1}>
<FeatureCard icon={i.icon} title={i.title} body={i.body} />
</ParallaxContainer>
))}
</div>
</div>
@@ -688,23 +881,48 @@ function Impact() {
return (
<section id="impact" className="relative py-24 overflow-hidden">
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<ParallaxContainer depth={0.3}>
{/* Enhanced Background Elements */}
<div className="absolute inset-0 pointer-events-none">
<motion.div
className="absolute top-1/4 left-0 w-40 h-40 bg-gradient-to-br from-primary-200/10 via-secondary-200/10 to-primary-300/10 rounded-full blur-2xl"
animate={{
x: [-50, 50, -50],
y: [-25, 25, -25],
scale: [0.8, 1.2, 0.8],
rotate: [0, 180, 360]
}}
transition={{ duration: 20, repeat: Infinity, ease: "easeInOut" }}
/>
<motion.div
className="absolute bottom-1/4 right-0 w-56 h-56 bg-gradient-to-bl from-secondary-200/10 via-primary-200/10 to-secondary-300/10 rounded-full blur-2xl"
animate={{
x: [30, -30, 30],
y: [20, -20, 20],
scale: [1, 0.9, 1],
rotate: [360, 180, 0]
}}
transition={{ duration: 25, repeat: Infinity, ease: "easeInOut", delay: 3 }}
/>
</div>
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 relative z-10">
<ParallaxContainer depth={0.2}>
<SectionHeader eyebrow="Impact" title="Every gift moves a student forward" subtitle="Transparent, measurable outcomes powered by local partnerships." />
</ParallaxContainer>
<div className="mt-12 grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
{stats.map((s, i) => (
<ParallaxContainer key={i} depth={0.4 + i * 0.1}>
<ParallaxContainer key={i} depth={0.3 + i * 0.05}>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
initial={{ opacity: 0, y: 30, rotateX: -15 }}
whileInView={{ opacity: 1, y: 0, rotateX: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6, delay: i * 0.1 }}
transition={{ duration: 0.8, delay: i * 0.15 }}
whileHover={{
scale: 1.05,
rotateY: 5,
z: 50
rotateY: 8,
z: 60,
boxShadow: "0 25px 50px -12px rgba(0, 0, 0, 0.25)"
}}
style={{ transformStyle: 'preserve-3d' }}
>
@@ -767,38 +985,143 @@ function HowItWorks() {
]
return (
<section id="how" className="relative py-24">
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<SectionHeader eyebrow="How it works" title="Simple process, real results" subtitle="Designed with counselors, optimized for speed and dignity." />
<section id="how" className="relative py-24 overflow-hidden">
{/* Animated Background Elements */}
<div className="absolute inset-0 pointer-events-none">
<motion.div
className="absolute top-16 right-1/4 w-3 h-3 bg-primary-300/40 dark:bg-primary-600/40 rounded-full"
animate={{
y: [-30, 30, -30],
x: [-15, 15, -15],
scale: [0.5, 1.5, 0.5],
opacity: [0.3, 0.8, 0.3]
}}
transition={{ duration: 8, repeat: Infinity, ease: "easeInOut" }}
/>
<motion.div
className="absolute bottom-20 left-1/3 w-2 h-2 bg-secondary-300/40 dark:bg-secondary-600/40 rounded-full"
animate={{
y: [20, -20, 20],
x: [10, -10, 10],
scale: [0.8, 1.2, 0.8],
opacity: [0.4, 0.9, 0.4]
}}
transition={{ duration: 6, repeat: Infinity, ease: "easeInOut", delay: 2 }}
/>
<motion.div
className="absolute top-1/3 left-1/5 w-4 h-4 bg-gradient-to-br from-primary-200/30 to-secondary-200/30 rounded-full blur-sm"
animate={{
rotate: [0, 360],
scale: [0.6, 1.1, 0.6],
y: [-10, 10, -10]
}}
transition={{ duration: 12, repeat: Infinity, ease: "easeInOut", delay: 4 }}
/>
</div>
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 relative z-10">
<ParallaxContainer depth={0.2}>
<SectionHeader eyebrow="How it works" title="Simple process, real results" subtitle="Designed with counselors, optimized for speed and dignity." />
</ParallaxContainer>
<div className="mt-10 grid gap-6 md:grid-cols-2">
<div className="card">
<ol className="relative space-y-6">
{steps.map((s, i) => (
<li key={i} className="relative pl-8">
<div className="absolute left-0 top-1 grid h-6 w-6 place-items-center rounded-full bg-gradient-to-br from-primary-500 to-secondary-600 text-white shadow text-xs">
{i + 1}
</div>
<div className="font-medium">{s.title}</div>
<p className="text-sm text-neutral-700 dark:text-neutral-300">{s.body}</p>
</li>
))}
</ol>
</div>
<ParallaxContainer depth={0.3}>
<motion.div
className="card"
initial={{ opacity: 0, rotateY: -15 }}
whileInView={{ opacity: 1, rotateY: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8 }}
style={{ transformStyle: 'preserve-3d' }}
>
<ol className="relative space-y-6">
{steps.map((s, i) => (
<motion.li
key={i}
className="relative pl-8"
initial={{ opacity: 0, x: -20 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6, delay: i * 0.15 }}
whileHover={{
x: 5,
transition: { duration: 0.2 }
}}
>
<motion.div
className="absolute left-0 top-1 grid h-6 w-6 place-items-center rounded-full bg-gradient-to-br from-primary-500 to-secondary-600 text-white shadow text-xs"
whileHover={{
scale: 1.1,
rotateY: 180,
boxShadow: "0 4px 8px rgba(0,0,0,0.2)"
}}
style={{ transformStyle: 'preserve-3d' }}
>
{i + 1}
</motion.div>
<div className="font-medium">{s.title}</div>
<p className="text-sm text-neutral-700 dark:text-neutral-300">{s.body}</p>
</motion.li>
))}
</ol>
</motion.div>
</ParallaxContainer>
<div className="grid gap-6">
<div className="rounded-2xl border border-emerald-500/20 bg-emerald-500/10 p-6">
<div className="flex items-center gap-3">
<div className="grid h-10 w-10 place-items-center rounded-xl bg-emerald-500 text-white"><Heart className="h-5 w-5"/></div>
<div className="font-semibold tracking-tight">Donor promise</div>
</div>
<p className="mt-2 text-sm text-emerald-900 dark:text-emerald-100">Your gift funds direct student needs first. We publish anonymized impact and receipts for transparency.</p>
</div>
<div className="rounded-2xl border border-secondary-500/20 bg-secondary-500/10 p-6">
<div className="flex items-center gap-3">
<div className="grid h-10 w-10 place-items-center rounded-xl bg-secondary-500 text-white"><Users className="h-5 w-5"/></div>
<div className="font-semibold tracking-tight">For counselors</div>
</div>
<p className="mt-2 text-sm text-secondary-950 dark:text-secondary-100">One-page referral. No uploads required. We do the running so students don't miss class.</p>
</div>
<ParallaxContainer depth={0.4}>
<motion.div
className="rounded-2xl border border-emerald-500/20 bg-emerald-500/10 p-6"
initial={{ opacity: 0, rotateX: 15, y: 20 }}
whileInView={{ opacity: 1, rotateX: 0, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.7, delay: 0.2 }}
whileHover={{
scale: 1.02,
rotateY: 3,
z: 20,
boxShadow: "0 8px 25px rgba(16, 185, 129, 0.15)"
}}
style={{ transformStyle: 'preserve-3d' }}
>
<div className="flex items-center gap-3">
<motion.div
className="grid h-10 w-10 place-items-center rounded-xl bg-emerald-500 text-white"
whileHover={{ rotateY: 180, scale: 1.1 }}
style={{ transformStyle: 'preserve-3d' }}
>
<Heart className="h-5 w-5"/>
</motion.div>
<div className="font-semibold tracking-tight">Donor promise</div>
</div>
<p className="mt-2 text-sm text-emerald-900 dark:text-emerald-100">Your gift funds direct student needs first. We publish anonymized impact and receipts for transparency.</p>
</motion.div>
</ParallaxContainer>
<ParallaxContainer depth={0.5}>
<motion.div
className="rounded-2xl border border-secondary-500/20 bg-secondary-500/10 p-6"
initial={{ opacity: 0, rotateX: -15, y: 20 }}
whileInView={{ opacity: 1, rotateX: 0, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.7, delay: 0.4 }}
whileHover={{
scale: 1.02,
rotateY: -3,
z: 20,
boxShadow: "0 8px 25px rgba(147, 51, 234, 0.15)"
}}
style={{ transformStyle: 'preserve-3d' }}
>
<div className="flex items-center gap-3">
<motion.div
className="grid h-10 w-10 place-items-center rounded-xl bg-secondary-500 text-white"
whileHover={{ rotateY: 180, scale: 1.1 }}
style={{ transformStyle: 'preserve-3d' }}
>
<Users className="h-5 w-5"/>
</motion.div>
<div className="font-semibold tracking-tight">For counselors</div>
</div>
<p className="mt-2 text-sm text-secondary-950 dark:text-secondary-100">One-page referral. No uploads required. We do the running so students don't miss class.</p>
</motion.div>
</ParallaxContainer>
</div>
</div>
</div>