From d8b262d7813680463d1db6394b3fd4cf2af81bd3 Mon Sep 17 00:00:00 2001 From: Claude Code Date: Thu, 23 Jul 2026 03:57:39 -0700 Subject: [PATCH] Remove mouse particle tracer effect to resolve cursor lag and rendering glitches --- .../web/src/components/Visual/CursorFire.tsx | 152 +----------------- 1 file changed, 1 insertion(+), 151 deletions(-) diff --git a/server/web/src/components/Visual/CursorFire.tsx b/server/web/src/components/Visual/CursorFire.tsx index 153f8ec..d34a246 100644 --- a/server/web/src/components/Visual/CursorFire.tsx +++ b/server/web/src/components/Visual/CursorFire.tsx @@ -1,157 +1,7 @@ -import { useEffect, useRef } from 'react'; +import { useRef } from 'react'; 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() { const canvasRef = useRef(null); - const particles = useRef([]); - 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