// Simple cursor.js - Fixed version with better line effects document.addEventListener("DOMContentLoaded", function () { // Check if touch device if (window.matchMedia("(pointer: coarse)").matches) return; const toggleBtn = document.getElementById('cursorToggle'); const body = document.body; // Start with system cursor let isCustomCursor = false; function updateCursorState() { if (isCustomCursor) { body.classList.remove('system-cursor'); if (toggleBtn) { toggleBtn.classList.add('active'); } } else { body.classList.add('system-cursor'); if (toggleBtn) { toggleBtn.classList.remove('active'); } } } // Initialize cursor state updateCursorState(); // Toggle button click handler if (toggleBtn) { toggleBtn.addEventListener('click', () => { isCustomCursor = !isCustomCursor; localStorage.setItem('customCursor', isCustomCursor); updateCursorState(); }); } // Create canvas for custom cursor const canvas = document.createElement("canvas"); canvas.id = "custom-cursor"; canvas.style.cssText = ` position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 999999; display: none; `; document.body.appendChild(canvas); const ctx = canvas.getContext("2d"); const tentacles = []; const mouse = { x: 0, y: 0 }; const oldMouse = { x: 0, y: 0 }; // Mouse move handler document.addEventListener("mousemove", (e) => { mouse.x = e.clientX; mouse.y = e.clientY; if (isCustomCursor) { canvas.style.display = 'block'; } else { canvas.style.display = 'none'; } }); // Window resize handler window.addEventListener("resize", () => { canvas.width = window.innerWidth; canvas.height = window.innerHeight; }); // Tentacle class with better line effects class Tentacle { constructor(x, y, targetX, targetY) { this.startX = x; this.startY = y; this.endX = targetX; this.endY = targetY; this.life = 1.0; this.decay = 0.015; this.growth = 0; this.maxLength = 0; } update() { // Grow the tentacle if (this.growth < 1.0) { this.growth += 0.1; } // Calculate actual end point based on growth const currentEndX = this.startX + (this.endX - this.startX) * this.growth; const currentEndY = this.startY + (this.endY - this.startY) * this.growth; this.currentEndX = currentEndX; this.currentEndY = currentEndY; // Decay over time this.life -= this.decay; } draw(ctx) { if (this.life <= 0) return; const opacity = this.life * this.growth; // Draw main line with gradient effect const gradient = ctx.createLinearGradient( this.startX, this.startY, this.currentEndX, this.currentEndY ); gradient.addColorStop(0, `rgba(20, 20, 20, ${opacity * 0.8})`); gradient.addColorStop(1, `rgba(20, 20, 20, ${opacity * 0.2})`); ctx.strokeStyle = gradient; ctx.lineWidth = 3 * opacity * this.growth; ctx.lineCap = 'round'; ctx.beginPath(); ctx.moveTo(this.startX, this.startY); ctx.lineTo(this.currentEndX, this.currentEndY); ctx.stroke(); // Draw glowing endpoint const glowSize = 6 * opacity; const glowGradient = ctx.createRadialGradient( this.currentEndX, this.currentEndY, 0, this.currentEndX, this.currentEndY, glowSize ); glowGradient.addColorStop(0, `rgba(20, 20, 20, ${opacity})`); glowGradient.addColorStop(1, `rgba(20, 20, 20, 0)`); ctx.fillStyle = glowGradient; ctx.beginPath(); ctx.arc(this.currentEndX, this.currentEndY, glowSize, 0, Math.PI * 2); ctx.fill(); // Draw connection dots along the line const dotCount = 3; for (let i = 1; i <= dotCount; i++) { const t = i / (dotCount + 1); const dotX = this.startX + (this.currentEndX - this.startX) * t; const dotY = this.startY + (this.currentEndY - this.startY) * t; const dotOpacity = opacity * (1 - t) * 0.5; ctx.fillStyle = `rgba(20, 20, 20, ${dotOpacity})`; ctx.beginPath(); ctx.arc(dotX, dotY, 2, 0, Math.PI * 2); ctx.fill(); } } } // Animation loop function animate() { if (!isCustomCursor) { requestAnimationFrame(animate); return; } ctx.clearRect(0, 0, canvas.width, canvas.height); // Create new tentacles on movement const dx = mouse.x - oldMouse.x; const dy = mouse.y - oldMouse.y; const distance = Math.sqrt(dx * dx + dy * dy); if (distance > 3) { // Create multiple tentacles in movement direction const angle = Math.atan2(dy, dx); const spread = 0.3; for (let i = 0; i < 4; i++) { const spreadAngle = angle + (Math.random() - 0.5) * spread; const length = 60 + Math.random() * 80; const targetX = mouse.x + Math.cos(spreadAngle) * length; const targetY = mouse.y + Math.sin(spreadAngle) * length; tentacles.push(new Tentacle(mouse.x, mouse.y, targetX, targetY)); } oldMouse.x = mouse.x; oldMouse.y = mouse.y; } // Update and draw tentacles for (let i = tentacles.length - 1; i >= 0; i--) { const tentacle = tentacles[i]; tentacle.update(); if (tentacle.life <= 0) { tentacles.splice(i, 1); } else { tentacle.draw(ctx); } } // Limit tentacle count if (tentacles.length > 15) { tentacles.splice(0, tentacles.length - 15); } // Draw cursor point with glow const cursorGradient = ctx.createRadialGradient( mouse.x, mouse.y, 0, mouse.x, mouse.y, 8 ); cursorGradient.addColorStop(0, 'rgba(20, 20, 20, 0.8)'); cursorGradient.addColorStop(1, 'rgba(20, 20, 20, 0)'); ctx.fillStyle = cursorGradient; ctx.beginPath(); ctx.arc(mouse.x, mouse.y, 6, 0, Math.PI * 2); ctx.fill(); // Add central bright point ctx.fillStyle = 'rgba(255, 255, 255, 0.9)'; ctx.beginPath(); ctx.arc(mouse.x, mouse.y, 2, 0, Math.PI * 2); ctx.fill(); requestAnimationFrame(animate); } animate(); });