(function () { var prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; if (prefersReducedMotion) return; if (window.innerWidth < 768) return; var grid = document.getElementById('matrix-grid'); if (!grid) return; var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789<>/?;:"[]{}\\|!@#$%^&*()_+-='; var TILE_SIZE = 60; var gridReady = false; function createTile() { var tile = document.createElement('div'); tile.className = 'matrix-tile'; tile.textContent = chars[Math.floor(Math.random() * chars.length)]; tile.addEventListener('click', function () { tile.textContent = chars[Math.floor(Math.random() * chars.length)]; tile.classList.add('matrix-glitch'); setTimeout(function () { tile.classList.remove('matrix-glitch'); }, 200); }); return tile; } function createGrid() { grid.innerHTML = ''; var columns = Math.floor(window.innerWidth / TILE_SIZE) || 1; var rows = Math.floor(window.innerHeight / TILE_SIZE) || 1; grid.style.gridTemplateColumns = 'repeat(' + columns + ', 1fr)'; grid.style.gridTemplateRows = 'repeat(' + rows + ', 1fr)'; var total = columns * rows; for (var i = 0; i < total; i++) { grid.appendChild(createTile()); } gridReady = true; } function handleMouseMove(e) { if (!gridReady) return; var mouseX = e.clientX; var mouseY = e.clientY; var radius = window.innerWidth / 3.5; var tiles = grid.children; for (var i = 0; i < tiles.length; i++) { var tr = tiles[i].getBoundingClientRect(); var tileX = tr.left + tr.width / 2; var tileY = tr.top + tr.height / 2; var dx = mouseX - tileX; var dy = mouseY - tileY; var distance = Math.sqrt(dx * dx + dy * dy); var intensity = Math.max(0, 1 - distance / radius); tiles[i].style.setProperty('--intensity', intensity); } } // Scroll-based fade: hidden during hero/tree, fades in after tree explosion function updateOpacity() { var hero = document.querySelector('.hero'); var workSection = document.getElementById('work'); if (!hero || !workSection) return; var heroBottom = hero.offsetTop + hero.offsetHeight; // Tree animation ends around here — match the tree fadeOutEnd logic var fadeInStart = workSection.offsetTop - window.innerHeight * 0.3; var fadeInEnd = workSection.offsetTop; var scrollY = window.scrollY; var opacity; if (scrollY <= fadeInStart) { opacity = 0; } else if (scrollY >= fadeInEnd) { opacity = 1; } else { opacity = (scrollY - fadeInStart) / (fadeInEnd - fadeInStart); } grid.style.opacity = opacity; } window.addEventListener('scroll', function () { requestAnimationFrame(updateOpacity); }, { passive: true }); var resizeTimer; function debouncedResize() { clearTimeout(resizeTimer); resizeTimer = setTimeout(createGrid, 150); } createGrid(); updateOpacity(); window.addEventListener('resize', debouncedResize); window.addEventListener('mousemove', handleMouseMove); })();