Remove mouse particle tracer effect to resolve cursor lag and rendering glitches
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
This commit is contained in:
@@ -1,157 +1,7 @@
|
|||||||
import { useEffect, useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
import './CursorFire.css';
|
import './CursorFire.css';
|
||||||
|
|
||||||
const BIT_CHARS = '01';
|
|
||||||
const HEX_CHARS = '0123456789ABCDEF';
|
|
||||||
const MAX_PARTICLES = 480;
|
|
||||||
const EMIT_PER_FRAME = 12;
|
|
||||||
const EMIT_WINDOW_MS = 140;
|
|
||||||
const FONT_STACK = '"JetBrains Mono", "Fira Code", "Cascadia Code", monospace';
|
|
||||||
|
|
||||||
interface Particle {
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
vx: number;
|
|
||||||
vy: number;
|
|
||||||
life: number;
|
|
||||||
decay: number;
|
|
||||||
char: string;
|
|
||||||
fontSize: number;
|
|
||||||
tint: 'cyan' | 'green';
|
|
||||||
}
|
|
||||||
|
|
||||||
function pickChar(): string {
|
|
||||||
if (Math.random() < 0.88) return BIT_CHARS[Math.floor(Math.random() * 2)];
|
|
||||||
return HEX_CHARS[Math.floor(Math.random() * HEX_CHARS.length)];
|
|
||||||
}
|
|
||||||
|
|
||||||
function colorForLife(life: number, tint: Particle['tint']): string {
|
|
||||||
const a = Math.min(1, life * 1.05);
|
|
||||||
if (tint === 'cyan') {
|
|
||||||
if (life > 0.5) return `rgba(0, 255, 255, ${a})`;
|
|
||||||
return `rgba(0, 240, 200, ${a * 0.92})`;
|
|
||||||
}
|
|
||||||
if (life > 0.5) return `rgba(80, 255, 160, ${a})`;
|
|
||||||
return `rgba(0, 255, 120, ${a * 0.9})`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function glowForTint(tint: Particle['tint']): string {
|
|
||||||
return tint === 'cyan' ? '#00e8f5' : '#00ff88';
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function CursorFire() {
|
export default function CursorFire() {
|
||||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||||
const particles = useRef<Particle[]>([]);
|
|
||||||
const mouse = useRef({ x: -9999, y: -9999 });
|
|
||||||
const lastMoveRef = useRef(0);
|
|
||||||
const rafRef = useRef(0);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const motionQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
|
|
||||||
if (motionQuery.matches) return;
|
|
||||||
|
|
||||||
const canvas = canvasRef.current;
|
|
||||||
if (!canvas) return;
|
|
||||||
const ctx = canvas.getContext('2d');
|
|
||||||
if (!ctx) return;
|
|
||||||
|
|
||||||
let running = true;
|
|
||||||
|
|
||||||
const resize = () => {
|
|
||||||
const dpr = Math.min(window.devicePixelRatio || 1, 2);
|
|
||||||
const w = window.innerWidth;
|
|
||||||
const h = window.innerHeight;
|
|
||||||
canvas.width = Math.floor(w * dpr);
|
|
||||||
canvas.height = Math.floor(h * dpr);
|
|
||||||
canvas.style.width = `${w}px`;
|
|
||||||
canvas.style.height = `${h}px`;
|
|
||||||
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
||||||
};
|
|
||||||
resize();
|
|
||||||
window.addEventListener('resize', resize);
|
|
||||||
|
|
||||||
const onMove = (e: MouseEvent) => {
|
|
||||||
mouse.current = { x: e.clientX, y: e.clientY };
|
|
||||||
lastMoveRef.current = performance.now();
|
|
||||||
};
|
|
||||||
window.addEventListener('mousemove', onMove, { passive: true });
|
|
||||||
|
|
||||||
const stopOnReducedMotion = () => {
|
|
||||||
if (!motionQuery.matches) return;
|
|
||||||
running = false;
|
|
||||||
cancelAnimationFrame(rafRef.current);
|
|
||||||
particles.current = [];
|
|
||||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
||||||
};
|
|
||||||
motionQuery.addEventListener('change', stopOnReducedMotion);
|
|
||||||
|
|
||||||
const emit = () => {
|
|
||||||
if (performance.now() - lastMoveRef.current > EMIT_WINDOW_MS) return;
|
|
||||||
const { x, y } = mouse.current;
|
|
||||||
|
|
||||||
for (let i = 0; i < EMIT_PER_FRAME; i++) {
|
|
||||||
const spread = 14;
|
|
||||||
particles.current.push({
|
|
||||||
x: x + (Math.random() - 0.5) * spread,
|
|
||||||
y: y + (Math.random() - 0.5) * (spread * 0.45),
|
|
||||||
vx: (Math.random() - 0.5) * 1.8,
|
|
||||||
vy: -(Math.random() * 3.2 + 2.1),
|
|
||||||
life: 1,
|
|
||||||
decay: Math.random() * 0.016 + 0.012,
|
|
||||||
char: pickChar(),
|
|
||||||
fontSize: Math.random() * 16 + 16,
|
|
||||||
tint: Math.random() < 0.5 ? 'cyan' : 'green',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (particles.current.length > MAX_PARTICLES) {
|
|
||||||
particles.current = particles.current.slice(-MAX_PARTICLES);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const draw = () => {
|
|
||||||
if (!running) return;
|
|
||||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
||||||
emit();
|
|
||||||
|
|
||||||
const alive: Particle[] = [];
|
|
||||||
for (const p of particles.current) {
|
|
||||||
p.vx += (Math.random() - 0.5) * 0.28;
|
|
||||||
p.vx *= 0.96;
|
|
||||||
p.vy -= 0.035;
|
|
||||||
p.x += p.vx;
|
|
||||||
p.y += p.vy;
|
|
||||||
p.life -= p.decay;
|
|
||||||
p.fontSize *= 0.985;
|
|
||||||
|
|
||||||
if (p.life <= 0 || p.fontSize < 8) continue;
|
|
||||||
alive.push(p);
|
|
||||||
|
|
||||||
const glow = 10 + p.life * 18;
|
|
||||||
ctx.shadowBlur = glow;
|
|
||||||
ctx.shadowColor = glowForTint(p.tint);
|
|
||||||
ctx.font = `600 ${p.fontSize}px ${FONT_STACK}`;
|
|
||||||
ctx.textAlign = 'center';
|
|
||||||
ctx.textBaseline = 'middle';
|
|
||||||
ctx.fillStyle = colorForLife(p.life, p.tint);
|
|
||||||
ctx.fillText(p.char, p.x, p.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.shadowBlur = 0;
|
|
||||||
particles.current = alive;
|
|
||||||
rafRef.current = requestAnimationFrame(draw);
|
|
||||||
};
|
|
||||||
|
|
||||||
rafRef.current = requestAnimationFrame(draw);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
running = false;
|
|
||||||
cancelAnimationFrame(rafRef.current);
|
|
||||||
window.removeEventListener('resize', resize);
|
|
||||||
window.removeEventListener('mousemove', onMove);
|
|
||||||
motionQuery.removeEventListener('change', stopOnReducedMotion);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return <canvas ref={canvasRef} className="cursor-hacker-fx" aria-hidden="true" />;
|
return <canvas ref={canvasRef} className="cursor-hacker-fx" aria-hidden="true" />;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user