diff options
| author | Danilo M. <danix@danix.xyz> | 2026-04-05 08:40:09 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-04-05 08:40:09 +0200 |
| commit | dcf54cad8529526fd7f8d9d4b84b63ccb3fa9630 (patch) | |
| tree | ddd752bb91a333eb7f8f3f7bcf41a4f75c8cd460 /assets/js/matrix-rain.js | |
| parent | b1d3e5315bf92b925a1ca0603c2e476ae8c3d306 (diff) | |
| download | danixxyz-theme-dcf54cad8529526fd7f8d9d4b84b63ccb3fa9630.tar.gz danixxyz-theme-dcf54cad8529526fd7f8d9d4b84b63ccb3fa9630.zip | |
feat: add JavaScript modules (theme toggle, matrix rain, progress tracking, copy-to-clipboard)
Implement all 4 JavaScript modules:
- theme-toggle.js: Theme switching with localStorage persistence
- matrix-rain.js: Animated matrix-style rain effect on canvas
- progress-bar.js: Reading progress tracking during scroll
- copy-code.js: Copy-to-clipboard functionality for code blocks
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
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 }; +})(); |
