summaryrefslogtreecommitdiffstats
path: root/themes/danix-xyz-hacker/assets/js/matrix-rain.js
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-04-22 12:43:22 +0200
committerDanilo M. <danix@danix.xyz>2026-04-22 12:43:22 +0200
commit5b476f8905f411768e23cb01d577a60e5a5fd725 (patch)
tree0a08cc83d809dbea714f52826e822501ee7c0165 /themes/danix-xyz-hacker/assets/js/matrix-rain.js
parent082e9246ffe453031894d32d3cee9d5d1bf2b67a (diff)
downloaddanixxyz-5b476f8905f411768e23cb01d577a60e5a5fd725.tar.gz
danixxyz-5b476f8905f411768e23cb01d577a60e5a5fd725.zip
chore: extract theme into git submodule (danix2-hugo-theme)
Diffstat (limited to 'themes/danix-xyz-hacker/assets/js/matrix-rain.js')
-rw-r--r--themes/danix-xyz-hacker/assets/js/matrix-rain.js157
1 files changed, 0 insertions, 157 deletions
diff --git a/themes/danix-xyz-hacker/assets/js/matrix-rain.js b/themes/danix-xyz-hacker/assets/js/matrix-rain.js
deleted file mode 100644
index 53c55d8..0000000
--- a/themes/danix-xyz-hacker/assets/js/matrix-rain.js
+++ /dev/null
@@ -1,157 +0,0 @@
-// Matrix rain background effect
-(function() {
- // Bail out if user prefers reduced motion
- if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
- return;
- }
-
- // Canvas and context
- let canvas = document.getElementById('matrix-rain');
- if (!canvas) return;
- const ctx = canvas.getContext('2d');
-
- // State
- let columns = [];
- let frameCount = 0;
- let colors = { accent: '#a855f7', accent2: '#00ff88', bg: '#060b10', head: '#ffffff' };
-
- // Character set: 30% ASCII, 70% katakana
- const ASCII = Array.from({ length: 94 }, (_, i) => String.fromCharCode(33 + i));
- const KATA = Array.from({ length: 96 }, (_, i) => String.fromCodePoint(0x30a0 + i));
- const CHARS = shuffle([...ASCII, ...KATA, ...KATA, ...KATA]);
-
- // Utility: shuffle array
- function shuffle(arr) {
- for (let i = arr.length - 1; i > 0; i--) {
- const j = Math.floor(Math.random() * (i + 1));
- [arr[i], arr[j]] = [arr[j], arr[i]];
- }
- return arr;
- }
-
- // Utility: convert hex or rgb color to rgba string
- function hexToRgba(color, alpha) {
- const rgbMatch = color.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
- if (rgbMatch) {
- return `rgba(${rgbMatch[1]}, ${rgbMatch[2]}, ${rgbMatch[3]}, ${alpha})`;
- }
- const hex = color.replace('#', '');
- const r = parseInt(hex.substring(0, 2), 16);
- const g = parseInt(hex.substring(2, 4), 16);
- const b = parseInt(hex.substring(4, 6), 16);
- return `rgba(${r}, ${g}, ${b}, ${alpha})`;
- }
-
- // Sample CSS variables based on current theme
- function sampleColors() {
- const style = getComputedStyle(document.documentElement);
- const isDark = document.documentElement.classList.contains('theme-dark');
- colors.accent = style.getPropertyValue('--accent').trim();
- colors.accent2 = style.getPropertyValue('--accent2').trim();
- colors.bg = style.getPropertyValue('--bg').trim();
- // Head char: bright white in dark mode, deep purple-black in light mode
- colors.head = isDark ? '#ffffff' : '#1a0533';
- }
-
- // Resize canvas to window dimensions
- function resizeCanvas() {
- canvas.width = window.innerWidth;
- canvas.height = window.innerHeight;
- ctx.font = '14px "JetBrains Mono", monospace';
- ctx.textBaseline = 'top';
- initColumns();
- }
-
- // Initialize columns for the current canvas width
- function initColumns() {
- columns = [];
- const columnWidth = 14;
- const columnCount = Math.floor(canvas.width / columnWidth);
-
- for (let i = 0; i < columnCount; i++) {
- columns.push({
- x: i * columnWidth,
- y: -Math.floor(Math.random() * 40), // stagger start above viewport
- speed: 2 + Math.floor(Math.random() * 3), // 2-4 frames between drops
- color: Math.random() < 0.6 ? 'accent2' : 'accent', // 60% green, 40% purple
- charIndex: Math.floor(Math.random() * CHARS.length),
- length: 8 + Math.floor(Math.random() * 13), // trail length 8-20
- });
- }
- }
-
- // Set up MutationObserver for theme switching
- function setupThemeObserver() {
- const observer = new MutationObserver(function(mutations) {
- for (const m of mutations) {
- if (m.attributeName === 'class') {
- sampleColors();
- break;
- }
- }
- });
- observer.observe(document.documentElement, {
- attributes: true,
- attributeFilter: ['class'],
- });
- }
-
- // Main animation loop
- function drawFrame() {
- frameCount++;
-
- // Fade layer: semi-transparent background fill
- ctx.fillStyle = hexToRgba(colors.bg, 0.085);
- ctx.fillRect(0, 0, canvas.width, canvas.height);
-
- // Draw each column
- for (const col of columns) {
- // Skip if not time to drop yet (per-column throttle)
- if (frameCount % col.speed !== 0) continue;
-
- // Draw explicit trail in column color
- ctx.fillStyle = colors[col.color];
- for (let i = 1; i <= col.length; i++) {
- const trailY = (col.y - i) * 14;
- if (trailY < 0) continue;
- const trailCharIndex = (col.charIndex - i + CHARS.length) % CHARS.length;
- ctx.fillText(CHARS[trailCharIndex], col.x, trailY);
- }
-
- // Draw head character (bright)
- ctx.fillStyle = colors.head;
- const headCharIndex = col.charIndex % CHARS.length;
- ctx.fillText(CHARS[headCharIndex], col.x, col.y * 14);
-
- // Advance column
- col.y++;
- col.charIndex = (col.charIndex + 1) % CHARS.length;
-
- // Reset when scrolled off screen
- if (col.y * 14 > canvas.height + col.length * 14) {
- col.y = -Math.floor(Math.random() * 20);
- col.charIndex = Math.floor(Math.random() * CHARS.length);
- col.color = Math.random() < 0.6 ? 'accent2' : 'accent';
- }
- }
-
- requestAnimationFrame(drawFrame);
- }
-
- // Initialize
- sampleColors();
- resizeCanvas();
- setupThemeObserver();
-
- // Debounced resize handler
- let resizeTimer;
- window.addEventListener('resize', function() {
- clearTimeout(resizeTimer);
- resizeTimer = setTimeout(resizeCanvas, 150);
- });
-
- // Start animation when fonts are ready
- document.fonts.ready.then(function() {
- requestAnimationFrame(drawFrame);
- });
-})();