1 line
5.1 KiB
JavaScript
1 line
5.1 KiB
JavaScript
// cursor.js document.addEventListener("DOMContentLoaded", function (){if (window.matchMedia("(pointer: coarse)").matches) return;// --- SETTINGS --- const CONFIG ={tentacleCount: 8, triggerDist: 10, maxLength: 300, connectionDist: 150, thickness: 1, color: "rgba(20, 20, 20, 1)", prediction: 3.5};const toggleBtn = document.getElementById('cursorToggle');const body = document.body;// Default to system cursor (disabled custom cursor) let isCursorDisabled = localStorage.getItem('venomCursorDisabled') !== 'false';function updateCursorState(){if (isCursorDisabled){// System cursor (default) - show spidy icon body.classList.add('system-cursor');if (toggleBtn){toggleBtn.classList.remove('active');const icon = toggleBtn.querySelector('.cursor-icon');if (icon){// Check if we're on a page in the sites/ folder const currentPath = window.location.pathname;const isInSitesFolder = currentPath.includes('/sites/');const imagePath = isInSitesFolder ? '../images/additional/spidy.png' : 'images/additional/spidy.png';icon.src = imagePath;}}}else{// Custom cursor (secondary) - show cursor icon body.classList.remove('system-cursor');if (toggleBtn){toggleBtn.classList.add('active');const icon = toggleBtn.querySelector('.cursor-icon');if (icon){// Check if we're on a page in the sites/ folder const currentPath = window.location.pathname;const isInSitesFolder = currentPath.includes('/sites/');const imagePath = isInSitesFolder ? '../images/additional/cursor.png' : 'images/additional/cursor.png';icon.src = imagePath;}}}}updateCursorState();if (toggleBtn){toggleBtn.addEventListener('click', () =>{isCursorDisabled = !isCursorDisabled;localStorage.setItem('venomCursorDisabled', isCursorDisabled);updateCursorState();});}const canvas = document.createElement("canvas");canvas.id = "venom-cursor";document.body.appendChild(canvas);const ctx = canvas.getContext("2d");const width = window.innerWidth;const height = window.innerHeight;canvas.width = width;canvas.height = height;const tentacles = [];const mouse ={x: 0, y: 0};const oldMouse ={x: 0, y: 0};document.addEventListener("mousemove", (e) =>{mouse.x = e.clientX;mouse.y = e.clientY;});window.addEventListener("resize", () =>{canvas.width = window.innerWidth;canvas.height = window.innerHeight;});class Tentacle{constructor(mx, my, targetX, targetY){this.dead = false;this.anchor ={x: targetX, y: targetY};this.currentDist = 0;// For calculating connection opacity}update(currentMouse){const dx = currentMouse.x - this.anchor.x;const dy = currentMouse.y - this.anchor.y;this.currentDist = Math.sqrt(dx*dx + dy*dy);if (this.currentDist > CONFIG.maxLength){this.dead = true;}}draw(ctx, currentMouse){if (this.dead) return;// Tension (0..1) const tension = Math.min(this.currentDist / CONFIG.maxLength, 1);const dynamicThickness = CONFIG.thickness * (1 - tension * 0.9);// Draw main line (Cursor -> Anchor) ctx.beginPath();ctx.moveTo(currentMouse.x, currentMouse.y);ctx.lineTo(this.anchor.x, this.anchor.y);ctx.lineWidth = Math.max(0.2, dynamicThickness);ctx.strokeStyle = CONFIG.color;ctx.lineCap = "butt";ctx.stroke();// Draw anchor point ctx.beginPath();ctx.arc(this.anchor.x, this.anchor.y, 1.5 * (1 - tension), 0, Math.PI * 2);ctx.fillStyle = CONFIG.color;ctx.fill();}}function render(){ctx.clearRect(0, 0, width, height);// 1. Create new tentacles on movement const distMoved = Math.hypot(mouse.x - oldMouse.x, mouse.y - oldMouse.y);if (distMoved > CONFIG.triggerDist){const vx = mouse.x - oldMouse.x;const vy = mouse.y - oldMouse.y;// "Spread" of shots increased slightly for better geometry const targetX = mouse.x + vx * CONFIG.prediction + (Math.random() - 0.5) * 60;const targetY = mouse.y + vy * CONFIG.prediction + (Math.random() - 0.5) * 60;tentacles.push(new Tentacle(mouse.x, mouse.y, targetX, targetY));oldMouse.x = mouse.x;oldMouse.y = mouse.y;}// Remove old ones (FIFO) if (tentacles.length > CONFIG.tentacleCount){tentacles.shift();}// 2. Draw main tentacles for (let i = tentacles.length - 1;i >= 0;i--){const t = tentacles[i];t.update(mouse);if (t.dead){tentacles.splice(i, 1);}else{t.draw(ctx, mouse);}}// 3. DRAW CONNECTIONS BETWEEN ANCHORS (New logic) // Iterate through all pairs of active tentacles ctx.beginPath();// Begin common path for optimization ctx.lineWidth = 0.5;// Connections are always thin for (let i = 0;i < tentacles.length;i++){for (let j = i + 1;j < tentacles.length;j++){const t1 = tentacles[i];const t2 = tentacles[j];// Calculate distance between ends of two tentacles const dx = t1.anchor.x - t2.anchor.x;const dy = t1.anchor.y - t2.anchor.y;const dist = Math.sqrt(dx*dx + dy*dy);// If they are close to each other — connect if (dist < CONFIG.connectionDist){// Opacity depends on how far apart they are // And how much the tentacles themselves are stretched const alpha = (1 - dist / CONFIG.connectionDist) * 0.6;ctx.beginPath();// New path for each to control opacity ctx.strokeStyle = `rgba(20, 20, 20, ${alpha})`;ctx.moveTo(t1.anchor.x, t1.anchor.y);ctx.lineTo(t2.anchor.x, t2.anchor.y);ctx.stroke();}}}// 4. Cursor (Rhombus) ctx.beginPath();ctx.fillStyle = CONFIG.color;ctx.moveTo(mouse.x, mouse.y - 5);ctx.lineTo(mouse.x + 5, mouse.y);ctx.lineTo(mouse.x, mouse.y + 5);ctx.lineTo(mouse.x - 5, mouse.y);ctx.fill();requestAnimationFrame(render);}render();});
|