feat: optimize 3D floating particles and enhance parallax effects; improve visibility and interaction of UI elements

This commit is contained in:
defiQUG
2025-10-04 22:11:41 -07:00
parent 184057a0f7
commit ff7233bfed

View File

@@ -145,17 +145,17 @@ function ParallaxContainer({ children, depth = 1, className = '' }: ParallaxCont
// Enhanced 3D Floating Particles Background
function FloatingParticles() {
const particles = Array.from({ length: 30 }, (_, i) => i)
const particles = Array.from({ length: 20 }, (_, i) => i)
return (
<div className="absolute inset-0 overflow-hidden pointer-events-none">
{particles.map((i) => {
const size = Math.random() * 3 + 1
const depth = Math.random() * 4 + 1
const size = Math.random() * 2 + 0.5
const depth = Math.random() * 3 + 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"
className="absolute rounded-full bg-gradient-to-br from-primary-300/8 to-secondary-300/8 backdrop-blur-sm"
style={{
width: `${size}px`,
height: `${size}px`,
@@ -164,16 +164,16 @@ function FloatingParticles() {
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]
y: [-25, -100, -25],
x: [-10, 10, -10],
z: [0, depth * 15, 0],
opacity: [0.2, 0.6, 0.2],
scale: [0.9, 1.1, 0.9]
}}
transition={{
duration: Math.random() * 15 + 8,
duration: Math.random() * 18 + 10,
repeat: Infinity,
delay: Math.random() * 3,
delay: Math.random() * 4,
ease: "easeInOut"
}}
/>
@@ -551,21 +551,22 @@ function Hero() {
{/* Content Layer with Parallax */}
<motion.div
className="mx-auto grid max-w-7xl items-center gap-10 px-4 py-20 sm:px-6 lg:grid-cols-2 lg:gap-12 lg:py-28 lg:px-8 relative z-10"
className="mx-auto grid max-w-7xl items-center gap-16 px-4 py-20 sm:px-6 lg:grid-cols-12 lg:gap-8 lg:py-28 lg:px-8 relative z-10"
style={{ y: contentY }}
>
<ParallaxContainer depth={0.3}>
<motion.h1
initial={{ opacity: 0, y: 12 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6 }}
className="text-balance text-4xl font-bold tracking-tight sm:text-5xl md:text-6xl transform-gpu"
style={{ transformStyle: 'preserve-3d' }}
>
Equipping kids for success
<span className="relative whitespace-pre gradient-text"> school supplies, clothing, & more</span>
</motion.h1>
<div className="lg:col-span-7">
<ParallaxContainer depth={0.3}>
<motion.h1
initial={{ opacity: 0, y: 12 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6 }}
className="text-balance text-4xl font-bold tracking-tight sm:text-5xl md:text-6xl transform-gpu"
style={{ transformStyle: 'preserve-3d' }}
>
Equipping kids for success
<span className="relative whitespace-pre gradient-text"> school supplies, clothing, & more</span>
</motion.h1>
<p className="mt-5 max-w-xl text-lg leading-7 text-neutral-700 dark:text-neutral-300">
Miracles in Motion is a nonprofit providing students with the essentials they need to thrive: backpacks and notebooks, uniforms and shoes, and the everything-else fund for urgent needs.
</p>
@@ -587,52 +588,55 @@ function Hero() {
<li className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-emerald-500"/> Donations tax-deductible</li>
<li className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-emerald-500"/> Community-driven impact</li>
</ul>
</ParallaxContainer>
</ParallaxContainer>
</div>
<ParallaxContainer depth={0.5} className="relative">
<HeroShowcase />
</ParallaxContainer>
<div className="lg:col-span-5">
<ParallaxContainer depth={0.5} className="relative">
<HeroShowcase />
</ParallaxContainer>
</div>
</motion.div>
{/* 3D Scroll Indicator */}
<motion.div
className="absolute bottom-8 left-1/2 -translate-x-1/2 hidden lg:block"
className="absolute bottom-12 left-1/2 -translate-x-1/2 hidden lg:block z-20"
animate={{
y: [0, 10, 0],
rotateX: [0, 15, 0]
y: [0, 8, 0],
rotateX: [0, 10, 0]
}}
transition={{ duration: 2, repeat: Infinity, ease: "easeInOut" }}
transition={{ duration: 2.5, 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>
<div className="flex flex-col items-center gap-2 text-neutral-500 dark:text-neutral-400">
<span className="text-xs font-medium opacity-75">Scroll to explore</span>
<motion.div
animate={{ y: [0, 5, 0] }}
transition={{ duration: 1.5, repeat: Infinity, ease: "easeInOut" }}
animate={{ y: [0, 4, 0] }}
transition={{ duration: 1.8, repeat: Infinity, ease: "easeInOut" }}
>
<ArrowRight className="h-5 w-5 rotate-90" />
<ArrowRight className="h-4 w-4 rotate-90 opacity-60" />
</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 */}
{/* Top layer - subtle and non-interfering */}
<motion.div
className="absolute top-1/4 left-[8%] text-primary-400/80 dark:text-primary-500/80 hidden lg:block"
className="absolute top-1/4 left-[5%] text-primary-300/40 dark:text-primary-600/40 hidden xl:block"
animate={{
y: [-15, 15, -15],
y: [-12, 12, -12],
rotateY: [0, 360],
z: [0, 50, 0],
scale: [0.8, 1.2, 0.8]
z: [0, 30, 0],
scale: [0.9, 1.1, 0.9]
}}
transition={{ duration: 6, repeat: Infinity, ease: "easeInOut" }}
transition={{ duration: 8, repeat: Infinity, ease: "easeInOut" }}
style={{
transformStyle: 'preserve-3d',
filter: 'drop-shadow(0 4px 8px rgba(0,0,0,0.1))'
filter: 'drop-shadow(0 2px 4px rgba(0,0,0,0.05))'
}}
>
<Heart className="h-8 w-8" />
<Heart className="h-6 w-6" />
</motion.div>
{/* Additional floating heart */}
@@ -649,22 +653,22 @@ function Hero() {
<Heart className="h-5 w-5" />
</motion.div>
{/* Right side - more prominent sparkles */}
{/* Right side - subtle sparkles */}
<motion.div
className="absolute top-1/3 right-[12%] text-secondary-400/80 dark:text-secondary-500/80 hidden xl:block"
className="absolute top-1/3 right-[8%] text-secondary-300/40 dark:text-secondary-600/40 hidden xl:block"
animate={{
y: [20, -20, 20],
y: [15, -15, 15],
rotateX: [0, 180, 360],
z: [0, 40, 0],
scale: [0.9, 1.4, 0.9]
z: [0, 25, 0],
scale: [0.95, 1.2, 0.95]
}}
transition={{ duration: 5, repeat: Infinity, ease: "easeInOut", delay: 1.5 }}
transition={{ duration: 7, repeat: Infinity, ease: "easeInOut", delay: 1.5 }}
style={{
transformStyle: 'preserve-3d',
filter: 'drop-shadow(0 2px 4px rgba(0,0,0,0.1))'
filter: 'drop-shadow(0 1px 2px rgba(0,0,0,0.05))'
}}
>
<Sparkles className="h-7 w-7" />
<Sparkles className="h-5 w-5" />
</motion.div>
{/* Additional floating sparkle */}
@@ -731,9 +735,9 @@ function Hero() {
function HeroShowcase() {
return (
<div className="relative mx-auto max-w-md lg:max-w-none">
<div className="absolute -inset-8 -z-10 rounded-3xl bg-gradient-to-tr from-primary-500/20 via-secondary-500/20 to-secondary-600/20 blur-3xl" />
<div className="grid grid-cols-2 gap-4 sm:gap-6">
<div className="relative mx-auto max-w-sm lg:max-w-md xl:max-w-lg">
<div className="absolute -inset-6 -z-10 rounded-3xl bg-gradient-to-tr from-primary-500/15 via-secondary-500/15 to-secondary-600/15 blur-2xl" />
<div className="grid grid-cols-2 gap-3 sm:gap-4">
<TiltCard icon={Backpack} title="School Supplies" desc="Backpacks, notebooks, calculators" />
<TiltCard icon={Shirt} title="School Clothing" desc="Uniforms, shoes, coats" />
<TiltCard icon={Sparkles} title="Everything Else" desc="Glasses, fees, emergencies" />
@@ -746,10 +750,11 @@ function HeroShowcase() {
function TiltCard({ icon: Icon, title, desc }: TiltCardProps) {
const x = useMotionValue(0)
const y = useMotionValue(0)
const rx = useTransform(y, [-50, 50], [8, -8])
const ry = useTransform(x, [-50, 50], [-8, 8])
const springX = useSpring(rx, { stiffness: 200, damping: 20 })
const springY = useSpring(ry, { stiffness: 200, damping: 20 })
const rx = useTransform(y, [-50, 50], [12, -12])
const ry = useTransform(x, [-50, 50], [-12, 12])
const springX = useSpring(rx, { stiffness: 150, damping: 15 })
const springY = useSpring(ry, { stiffness: 150, damping: 15 })
const scale = useSpring(1, { stiffness: 300, damping: 25 })
return (
<motion.div
@@ -757,13 +762,28 @@ function TiltCard({ icon: Icon, title, desc }: TiltCardProps) {
const rect = e.currentTarget.getBoundingClientRect()
x.set(e.clientX - rect.left - rect.width / 2)
y.set(e.clientY - rect.top - rect.height / 2)
scale.set(1.05)
}}
onMouseLeave={() => {
x.set(0)
y.set(0)
scale.set(1)
}}
style={{ rotateX: springX, rotateY: springY, transformStyle: "preserve-3d" }}
className="group card card-hover will-change-transform"
style={{
rotateX: springX,
rotateY: springY,
scale: scale,
transformStyle: "preserve-3d",
boxShadow: useTransform(scale, [1, 1.05], [
"0 4px 6px -1px rgba(0, 0, 0, 0.1)",
"0 20px 25px -5px rgba(0, 0, 0, 0.15), 0 10px 10px -5px rgba(0, 0, 0, 0.04)"
])
}}
className="group card card-hover will-change-transform cursor-pointer"
whileHover={{
z: 20
}}
transition={{ duration: 0.2 }}
>
<div className="pointer-events-none absolute inset-0 -z-10 bg-[radial-gradient(150px_80px_at_var(--x)_var(--y),_rgba(255,255,255,0.35),_transparent)] opacity-0 transition-opacity duration-500 group-hover:opacity-100" />
<div className="flex items-start gap-4" style={{ transform: "translateZ(40px)" }}>
@@ -855,19 +875,53 @@ function Programs() {
function FeatureCard({ icon: Icon, title, body }: FeatureCardProps) {
return (
<div className="group card card-hover">
<div className="absolute left-1/2 top-0 -z-10 h-40 w-40 -translate-x-1/2 rounded-full bg-gradient-to-br from-primary-500/20 to-secondary-600/20 blur-2xl" />
<motion.div
className="group card card-hover cursor-pointer"
whileHover={{
scale: 1.02,
rotateY: 5,
z: 30,
boxShadow: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)"
}}
initial={{ rotateY: 0, z: 0 }}
style={{ transformStyle: 'preserve-3d' }}
transition={{ duration: 0.3, ease: "easeOut" }}
>
<motion.div
className="absolute left-1/2 top-0 -z-10 h-40 w-40 -translate-x-1/2 rounded-full bg-gradient-to-br from-primary-500/20 to-secondary-600/20 blur-2xl"
whileHover={{ scale: 1.2, opacity: 0.8 }}
transition={{ duration: 0.3 }}
/>
<div className="flex items-center gap-3">
<div className="grid h-10 w-10 place-items-center rounded-xl bg-gradient-to-br from-primary-500 to-secondary-600 text-white shadow">
<motion.div
className="grid h-10 w-10 place-items-center rounded-xl bg-gradient-to-br from-primary-500 to-secondary-600 text-white shadow"
whileHover={{
scale: 1.1,
rotateY: 180,
boxShadow: "0 8px 16px rgba(0,0,0,0.2)"
}}
style={{ transformStyle: 'preserve-3d' }}
transition={{ duration: 0.4 }}
>
<Icon className="h-5 w-5" />
</div>
</motion.div>
<div className="font-semibold tracking-tight">{title}</div>
</div>
<p className="mt-3 text-sm leading-6 text-neutral-700 dark:text-neutral-300">{body}</p>
<div className="mt-5 text-sm text-primary-700 transition group-hover:translate-x-1 dark:text-primary-300">
Explore <ArrowRight className="ml-1 inline h-4 w-4" />
</div>
</div>
<motion.div
className="mt-5 text-sm text-primary-700 transition dark:text-primary-300 flex items-center"
whileHover={{ x: 8 }}
transition={{ duration: 0.2 }}
>
Explore
<motion.div
whileHover={{ x: 4 }}
transition={{ duration: 0.2 }}
>
<ArrowRight className="ml-1 h-4 w-4" />
</motion.div>
</motion.div>
</motion.div>
)
}