diff options
Diffstat (limited to 'assets/js/matrix-rain.js')
| -rw-r--r-- | assets/js/matrix-rain.js | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/assets/js/matrix-rain.js b/assets/js/matrix-rain.js new file mode 100644 index 0000000..479231f --- /dev/null +++ b/assets/js/matrix-rain.js @@ -0,0 +1,65 @@ +// matrix-rain.js +(function () { + const canvas = document.getElementById('matrix-canvas'); + if (!canvas) return; + if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; + + const ctx = canvas.getContext('2d'); + const CHARS = 'アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン0123456789ABCDEF<>/\\|{}[]$#@!'; + const FS = 14; // font size / column width in px + let cols, drops, raf; + + function init() { + canvas.width = canvas.offsetWidth; + canvas.height = canvas.offsetHeight; + cols = Math.floor(canvas.width / FS) + 1; + drops = Array.from({ length: cols }, () => Math.random() * -(canvas.height / FS)); + } + + function tick() { + const light = document.documentElement.classList.contains('theme-light'); + // Fade trail: near-transparent fill each frame + ctx.fillStyle = light ? 'rgba(240,244,248,0.07)' : 'rgba(6,11,16,0.055)'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.font = `${FS}px "JetBrains Mono", monospace`; + + for (let i = 0; i < cols; i++) { + const char = CHARS[Math.floor(Math.random() * CHARS.length)]; + // 4% chance of bright "head" char, otherwise use accent color + ctx.fillStyle = Math.random() > 0.96 + ? (light ? '#008f5a' : '#00ff88') // bright green head + : (light ? '#7c3aed' : '#a855f7'); // purple trail + ctx.fillText(char, i * FS, drops[i] * FS); + + if (drops[i] * FS > canvas.height && Math.random() > 0.975) { + drops[i] = Math.random() * -20; // reset column randomly + } + drops[i] += 0.5; // slow fall speed + } + raf = requestAnimationFrame(tick); + } + + // Listen for theme changes and reinit + window.addEventListener('theme-changed', function() { + // Matrix rain auto-colors based on theme-light class + }, { passive: true }); + + init(); + window.addEventListener('resize', () => { + cancelAnimationFrame(raf); + init(); + tick(); + }, { passive: true }); + + document.addEventListener('visibilitychange', () => { + if (document.hidden) { + cancelAnimationFrame(raf); + } else { + tick(); + } + }); + + tick(); + + window.MatrixRain = { init, tick }; +})(); |
