From 1a64b006ef36e41da1fdb43aa0ec643c5b83adfb Mon Sep 17 00:00:00 2001 From: Diksha Dabhole Date: Sun, 17 May 2026 19:28:15 +0530 Subject: [PATCH] feat(ui): replace pink background animation with brand particles --- app/layout.tsx | 4 +- components/BrandParticles.tsx | 82 +++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 components/BrandParticles.tsx diff --git a/app/layout.tsx b/app/layout.tsx index d94c9e9..22f52d0 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -2,7 +2,7 @@ import './globals.css'; import { Inter } from 'next/font/google'; import { Analytics } from '@vercel/analytics/next'; import Navbar from './components/navbar'; -import CherryBlossom from '@/components/CherryBlossom'; +import BrandParticles from '@/components/BrandParticles'; import type { Metadata } from 'next'; const inter = Inter({ subsets: ['latin'] }); @@ -66,7 +66,7 @@ export default function RootLayout({ children }: { children: React.ReactNode }) return ( - +
{children}
diff --git a/components/BrandParticles.tsx b/components/BrandParticles.tsx new file mode 100644 index 0000000..c96d139 --- /dev/null +++ b/components/BrandParticles.tsx @@ -0,0 +1,82 @@ +'use client'; + +import { motion } from 'framer-motion'; +import { useEffect, useState } from 'react'; + +// Generates an array of particles +const generateParticles = (count: number) => { + const colors = ['#10b981', '#8b5cf6', '#06b6d4', '#f59e0b', '#3b82f6']; + return Array.from({ length: count }).map((_, i) => ({ + id: i, + x: Math.random() * 100, // starting X position % + y: Math.random() * 100, // starting Y position % + size: Math.random() * 15 + 5, // size between 5 and 20 + color: colors[Math.floor(Math.random() * colors.length)], + duration: Math.random() * 30 + 30, // 30s to 60s duration + delay: Math.random() * -60, // Negative delay so they start already moving + rotateDirection: Math.random() > 0.5 ? 1 : -1, + opacity: 0.1 + Math.random() * 0.15, // subtle opacity (0.1 to 0.25) + borderRadius: Math.random() > 0.5 ? '2px' : '50%', // Mix of squares and circles + xAnimStart: Math.random() * 100 - 50, + xAnimEnd: Math.random() * -100 + 50, + })); +}; + +interface Particle { + id: number; + x: number; + y: number; + size: number; + color: string; + duration: number; + delay: number; + rotateDirection: number; + opacity: number; + borderRadius: string; + xAnimStart: number; + xAnimEnd: number; +} + +export default function BrandParticles() { + const [particles] = useState(() => generateParticles(40)); + const [mounted, setMounted] = useState(false); + + useEffect(() => { + // eslint-disable-next-line react-hooks/set-state-in-effect + setMounted(true); + }, []); + + if (!mounted) return null; + + return ( +
+ {particles.map((particle) => ( + + ))} +
+ ); +}