const yearElement = document.querySelector("#current-year"); const canvas = document.querySelector("#network-canvas"); if (yearElement) { yearElement.textContent = new Date().getFullYear().toString(); } if (canvas) { const context = canvas.getContext("2d"); const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)"); let animationFrame = null; const nodes = Array.from({ length: 42 }, (_, index) => ({ x: (index * 97) % 100, y: (index * 53) % 100, speed: 0.08 + (index % 5) * 0.015, phase: index * 0.7, })); function resizeCanvas() { const ratio = Math.min(window.devicePixelRatio || 1, 2); const { width, height } = canvas.getBoundingClientRect(); canvas.width = Math.max(1, Math.floor(width * ratio)); canvas.height = Math.max(1, Math.floor(height * ratio)); context.setTransform(ratio, 0, 0, ratio, 0, 0); } function drawNetwork(time = 0) { const { width, height } = canvas.getBoundingClientRect(); const points = nodes.map((node) => { const drift = prefersReducedMotion.matches ? 0 : time * 0.001 * node.speed; return { x: ((node.x + Math.sin(node.phase + drift) * 5 + 100) % 100) * width / 100, y: ((node.y + Math.cos(node.phase + drift) * 5 + 100) % 100) * height / 100, }; }); context.clearRect(0, 0, width, height); context.fillStyle = "#070a0f"; context.fillRect(0, 0, width, height); context.lineWidth = 1; for (let index = 0; index < points.length; index += 1) { for (let nextIndex = index + 1; nextIndex < points.length; nextIndex += 1) { const first = points[index]; const second = points[nextIndex]; const distance = Math.hypot(first.x - second.x, first.y - second.y); if (distance < 170) { const alpha = (1 - distance / 170) * 0.22; context.strokeStyle = `rgba(103, 232, 249, ${alpha})`; context.beginPath(); context.moveTo(first.x, first.y); context.lineTo(second.x, second.y); context.stroke(); } } } for (const point of points) { context.fillStyle = "rgba(124, 247, 182, 0.88)"; context.beginPath(); context.arc(point.x, point.y, 2.2, 0, Math.PI * 2); context.fill(); } if (!prefersReducedMotion.matches) { animationFrame = window.requestAnimationFrame(drawNetwork); } } resizeCanvas(); drawNetwork(); window.addEventListener("resize", () => { resizeCanvas(); if (prefersReducedMotion.matches) { drawNetwork(); } }); prefersReducedMotion.addEventListener("change", () => { if (animationFrame) { window.cancelAnimationFrame(animationFrame); animationFrame = null; } drawNetwork(); }); }