Gradient Cursor Effect
An interactive React component that adds a dynamic bubble effect, visually tracking cursor movement in real time.
An interactive React component that adds a dynamic bubble effect, visually tracking cursor movement in real time.
1// @ts-nocheck23'use client';45import { useState, useEffect } from 'react';6import { motion, AnimatePresence } from 'framer-motion';7import { useMouse } from '@/hooks/use-mouse';89const GradientCursor = () => {10const [mouseState, ref] = useMouse();11const [hue, setHue] = useState(0);1213const [particles, setParticles] = useState<14{ id: number; x: number; y: number; size: number; intensity: number }[]15>([]);1617useEffect(() => {18if (mouseState.x && mouseState.y) {19const newHue = (mouseState.x || 0) % 360;20setHue(newHue);2122// Add multiple new particles23const newParticles = Array.from({ length: 3 }, () => ({24id: Date.now() + Math.random(),25x: mouseState.x + (Math.random() - 0.5) * 20,26y: mouseState.y + (Math.random() - 0.5) * 20,27size: Math.random() * 3 + 2, // Random size between 2 and 528intensity: Math.random() * 0.5 + 0.5, // Random intensity between 0.5 and 129}));3031setParticles((prev) => [...prev, ...newParticles].slice(-30)); // Keep last 30 particles32}33}, [mouseState.x, mouseState.y]);3435return (36<div className='relative w-full h-full ' ref={ref}>37{mouseState.x !== null && mouseState.y !== null && (38<>39{/* Main cursor with gradient */}40<motion.div41className='fixed pointer-events-none z-50'42style={{43left: mouseState.x,44top: mouseState.y,45x: '-50%',46y: '-50%',47width: '40px',48height: '40px',49}}50transition={{ duration: 0.2 }}51>52<div53className='w-full h-full rounded-full mix-blend-screen'54style={{55background: `radial-gradient(56circle at center,57hsl(${hue}, 100%, 70%),58hsl(${(hue + 60) % 360}, 100%, 60%)59)`,60boxShadow: `0 0 20px hsl(${hue}, 100%, 50%, 0.5)`,61}}62/>63</motion.div>6465{/* Particle trail */}66<AnimatePresence>67{particles.map((particle, index) => (68<motion.div69key={particle.id}70className='fixed pointer-events-none mix-blend-screen'71style={{72left: particle.x,73top: particle.y,74x: '-50%',75y: '-50%',76}}77initial={{ opacity: particle.intensity, scale: 0 }}78animate={{ opacity: 0, scale: particle.size }}79exit={{ opacity: 0 }}80transition={{ duration: 1, ease: 'easeOut' }}81>82<div83className='rounded-full'84style={{85width: `${particle.size * 4}px`,86height: `${particle.size * 4}px`,87background: `radial-gradient(88circle at center,89hsl(${(hue + index * 10) % 360}, 100%, ${70 + particle.intensity * 30}%),90transparent91)`,92filter: 'blur(2px)',93boxShadow: `0 0 ${particle.size * 2}px hsl(${(hue + index * 10) % 360}, 100%, 50%, ${particle.intensity})`,94}}95/>96</motion.div>97))}98</AnimatePresence>99</>100)}101</div>102);103};104105export default GradientCursor;106
1npm install framer-motion
1'use client';2import { type RefObject, useLayoutEffect, useRef, useState } from 'react';34interface MouseState {5x: number | null;6y: number | null;7elementX: number | null;8elementY: number | null;9elementPositionX: number | null;10elementPositionY: number | null;11}1213export function useMouse(): [MouseState, RefObject<HTMLDivElement>] {14const [state, setState] = useState<MouseState>({15x: null,16y: null,17elementX: null,18elementY: null,19elementPositionX: null,20elementPositionY: null,21});2223const ref = useRef<HTMLDivElement | null>(null);2425useLayoutEffect(() => {26const handleMouseMove = (event: MouseEvent) => {27const newState: Partial<MouseState> = {28x: event.pageX,29y: event.pageY,30};3132if (ref.current instanceof Element) {33const { left, top } = ref.current.getBoundingClientRect();34const elementPositionX = left + window.scrollX;35const elementPositionY = top + window.scrollY;36const elementX = event.pageX - elementPositionX;37const elementY = event.pageY - elementPositionY;3839newState.elementX = elementX;40newState.elementY = elementY;41newState.elementPositionX = elementPositionX;42newState.elementPositionY = elementPositionY;43}4445setState((s) => ({46...s,47...newState,48}));49};5051document.addEventListener('mousemove', handleMouseMove);5253return () => {54document.removeEventListener('mousemove', handleMouseMove);55};56}, []);5758return [state, ref];59}