Glitch Cursor Effect

An interactive React component that adds a dynamic bubble effect, visually tracking cursor movement in real time.

1
// @ts-nocheck
2
'use client';
3
4
import { useState, useEffect } from 'react';
5
import { useMouse } from '@/hooks/use-mouse';
6
7
const GlitchCursor = () => {
8
const [mouseState, ref] = useMouse();
9
const [glitchActive, setGlitchActive] = useState(false);
10
const [glitchOffsets, setGlitchOffsets] = useState([]);
11
const [intensity, setIntensity] = useState(1);
12
13
useEffect(() => {
14
let interval;
15
if (glitchActive) {
16
interval = setInterval(() => {
17
const newOffsets = Array(5)
18
.fill(0)
19
.map(() => ({
20
x: (Math.random() - 0.5) * 20 * intensity,
21
y: (Math.random() - 0.5) * 20 * intensity,
22
scale: 0.8 + Math.random() * 0.4,
23
rotation: (Math.random() - 0.5) * 45 * intensity,
24
opacity: 0.5 + Math.random() * 0.5,
25
hue: Math.random() * 360,
26
}));
27
setGlitchOffsets(newOffsets);
28
}, 50);
29
} else {
30
setGlitchOffsets([]);
31
}
32
return () => clearInterval(interval);
33
}, [glitchActive, intensity]);
34
35
const handleMouseSpeed = (e) => {
36
const speed = Math.sqrt(
37
Math.pow(e.movementX, 2) + Math.pow(e.movementY, 2)
38
);
39
setIntensity(Math.min(Math.max(speed / 10, 1), 3));
40
};
41
42
return (
43
<div
44
className='relative w-full h-full '
45
ref={ref}
46
onMouseMove={handleMouseSpeed}
47
>
48
{mouseState.x !== null && mouseState.y !== null && (
49
<>
50
{/* Glitch layers */}
51
{glitchOffsets.map((offset, index) => (
52
<div
53
key={index}
54
className='fixed pointer-events-none mix-blend-screen'
55
style={{
56
left: mouseState.x + offset.x,
57
top: mouseState.y + offset.y,
58
transform: `translate(-50%, -50%)
59
scale(${offset.scale})
60
rotate(${offset.rotation}deg)`,
61
opacity: offset.opacity,
62
}}
63
>
64
<div
65
className='w-8 h-8 rounded-full'
66
style={{
67
background: `hsl(${offset.hue}, 100%, 50%)`,
68
filter: 'blur(2px)',
69
}}
70
/>
71
</div>
72
))}
73
74
{/* Main cursor */}
75
<div
76
className='fixed pointer-events-none z-50'
77
style={{
78
left: mouseState.x,
79
top: mouseState.y,
80
transform: 'translate(-50%, -50%)',
81
}}
82
>
83
<div className='w-8 h-8 bg-white rounded-full mix-blend-screen' />
84
</div>
85
86
{/* Static effect overlay */}
87
{glitchActive && (
88
<div
89
className='fixed pointer-events-none mix-blend-screen'
90
style={{
91
left: mouseState.x,
92
top: mouseState.y,
93
transform: 'translate(-50%, -50%)',
94
width: '100px',
95
height: '100px',
96
background: `url("data:image/svg+xml,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100' height='100' filter='url(%23noise)' opacity='0.5'/%3E%3C/svg%3E")`,
97
opacity: 0.3,
98
}}
99
/>
100
)}
101
</>
102
)}
103
104
<div className='flex flex-col items-center justify-center h-full gap-8'>
105
<button
106
className={`px-8 py-4 bg-red-600/30 text-white rounded-lg transition-all duration-300 relative overflow-hidden
107
${glitchActive ? 'animate-pulse' : ''}`}
108
onMouseEnter={() => setGlitchActive(true)}
109
onMouseLeave={() => setGlitchActive(false)}
110
>
111
Trigger Glitch
112
{glitchActive && (
113
<div className='absolute inset-0 bg-red-500/20 animate-glitch-overlay' />
114
)}
115
</button>
116
</div>
117
118
<style>{`
119
@keyframes glitch-overlay {
120
0% { transform: translateX(0); }
121
25% { transform: translateX(-5px); }
122
50% { transform: translateX(5px); }
123
75% { transform: translateX(-2px); }
124
100% { transform: translateX(0); }
125
}
126
`}</style>
127
</div>
128
);
129
};
130
131
export default GlitchCursor;
132

useMouse

1
'use client';
2
import { type RefObject, useLayoutEffect, useRef, useState } from 'react';
3
4
interface MouseState {
5
x: number | null;
6
y: number | null;
7
elementX: number | null;
8
elementY: number | null;
9
elementPositionX: number | null;
10
elementPositionY: number | null;
11
}
12
13
export function useMouse(): [MouseState, RefObject<HTMLDivElement>] {
14
const [state, setState] = useState<MouseState>({
15
x: null,
16
y: null,
17
elementX: null,
18
elementY: null,
19
elementPositionX: null,
20
elementPositionY: null,
21
});
22
23
const ref = useRef<HTMLDivElement | null>(null);
24
25
useLayoutEffect(() => {
26
const handleMouseMove = (event: MouseEvent) => {
27
const newState: Partial<MouseState> = {
28
x: event.pageX,
29
y: event.pageY,
30
};
31
32
if (ref.current instanceof Element) {
33
const { left, top } = ref.current.getBoundingClientRect();
34
const elementPositionX = left + window.scrollX;
35
const elementPositionY = top + window.scrollY;
36
const elementX = event.pageX - elementPositionX;
37
const elementY = event.pageY - elementPositionY;
38
39
newState.elementX = elementX;
40
newState.elementY = elementY;
41
newState.elementPositionX = elementPositionX;
42
newState.elementPositionY = elementPositionY;
43
}
44
45
setState((s) => ({
46
...s,
47
...newState,
48
}));
49
};
50
51
document.addEventListener('mousemove', handleMouseMove);
52
53
return () => {
54
document.removeEventListener('mousemove', handleMouseMove);
55
};
56
}, []);
57
58
return [state, ref];
59
}