Blob 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-nocheck2'use client';3import { useTrail, animated } from '@react-spring/web';4import { useRef, useEffect, useCallback } from 'react';56import './BlobCursor.css';78const fast = { tension: 1200, friction: 40 };9const slow = { mass: 10, tension: 200, friction: 50 };10const trans = (x, y) => `translate3d(${x}px,${y}px,0) translate3d(-50%,-50%,0)`;1112const BlobCursor = ({ blobType = 'circle', fillColor = '#fegefe' }) => {13const [trail, api] = useTrail(3, (i) => ({14xy: [0, 0],15config: i === 0 ? fast : slow,16}));1718const ref = useRef<HTMLDivElement>(null);19const updatePosition = useCallback(() => {20if (ref.current) {21const rect = ref.current.getBoundingClientRect();22return { left: rect.left, top: rect.top };23}24return { left: 0, top: 0 };25}, []);2627const handleMove = (e) => {28const { left, top } = updatePosition();29const x = e.clientX || (e.touches && e.touches[0].clientX);30const y = e.clientY || (e.touches && e.touches[0].clientY);31api.start({ xy: [x - left, y - top] });32};3334useEffect(() => {35const handleResize = () => {36updatePosition();37};3839window.addEventListener('resize', handleResize);40return () => {41window.removeEventListener('resize', handleResize);42};43}, [updatePosition]);4445return (46<div className='container '>47<svg style={{ position: 'absolute', width: 0, height: 0 }}>48<filter id='blob'>49<feGaussianBlur in='SourceGraphic' result='blur' stdDeviation='30' />50<feColorMatrix51in='blur'52values='1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 35 -10'53/>54</filter>55</svg>56<div57ref={ref}58className='main'59onMouseMove={handleMove}60onTouchMove={handleMove}61>62{trail.map((props, index) => (63<animated.div64key={index}65style={{66transform: props.xy.to(trans),67borderRadius: blobType === 'circle' ? '50%' : '0%',68backgroundColor: fillColor,69}}70/>71))}72</div>73</div>74);75};7677export default BlobCursor;78
1npm install @react-spring/web2
1.container {2width: 100%;3height: 100%;4}56.main > div {7position: absolute;8will-change: transform;9border-radius: 50%;10background: lightcoral;11box-shadow: 10px 10px 5px 0px rgba(0, 0, 0, 0.75);12opacity: 0.6;13}1415.main > div:nth-child(1) {16width: 60px;17height: 60px;18}1920.main > div:nth-child(2) {21width: 125px;22height: 125px;23}2425.main > div:nth-child(3) {26width: 75px;27height: 75px;28}2930.main > div::after {31content: '';32position: absolute;33top: 20px;34left: 20px;35width: 20px;36height: 20px;37border-radius: 50%;38background: rgba(255, 0, 0, 0.8);39}4041.main > div:nth-child(2)::after {42top: 35px;43left: 35px;44width: 35px;45height: 35px;46}4748.main > div:nth-child(3)::after {49top: 25px;50left: 25px;51width: 25px;52height: 25px;53}5455.main {56position: absolute;57width: 100%;58height: 100%;59filter: url('#blob');60overflow: hidden;61background: transparent;62-webkit-touch-callout: none;63-webkit-user-select: none;64-khtml-user-select: none;65-moz-user-select: none;66-ms-user-select: none;67user-select: none;68cursor: default;69}