summaryrefslogtreecommitdiffstats
path: root/.assets/js
diff options
context:
space:
mode:
Diffstat (limited to '.assets/js')
-rw-r--r--.assets/js/matrix-rain.js136
1 files changed, 136 insertions, 0 deletions
diff --git a/.assets/js/matrix-rain.js b/.assets/js/matrix-rain.js
new file mode 100644
index 0000000..e22ada2
--- /dev/null
+++ b/.assets/js/matrix-rain.js
@@ -0,0 +1,136 @@
+// Matrix rain background effect — header-scoped build for packages.danix.xyz
+// Derived from danix2-hugo-theme/assets/js/matrix-rain.js
+(function() {
+ if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
+
+ var header = document.querySelector('.site-header');
+ if (!header) return;
+
+ // Canvas
+ var canvas = document.createElement('canvas');
+ canvas.id = 'matrix-rain';
+ canvas.style.cssText = 'position:absolute;top:0;right:0;height:100%;pointer-events:none;z-index:0;';
+ header.appendChild(canvas);
+
+ // Gradient fade div — covers left portion of canvas area, left→transparent
+ var fade = document.createElement('div');
+ fade.style.cssText = 'position:absolute;top:0;right:0;bottom:0;width:65%;background:linear-gradient(to right,var(--bg-card) 0%,transparent 60%);pointer-events:none;z-index:1;';
+ header.appendChild(fade);
+
+ var ctx = canvas.getContext('2d');
+
+ var columns = [];
+ var frameCount = 0;
+ var colors = { accent: '#5c9cf5', accent2: '#4ec97b', bg: '#161b25', head: '#ffffff' };
+
+ var ASCII = Array.from({ length: 94 }, function(_, i) { return String.fromCharCode(33 + i); });
+ var KATA = Array.from({ length: 96 }, function(_, i) { return String.fromCodePoint(0x30a0 + i); });
+ var CHARS = shuffle([].concat(ASCII, KATA, KATA, KATA));
+
+ function shuffle(arr) {
+ for (var i = arr.length - 1; i > 0; i--) {
+ var j = Math.floor(Math.random() * (i + 1));
+ var tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp;
+ }
+ return arr;
+ }
+
+ function hexToRgba(color, alpha) {
+ var rgbMatch = color.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
+ if (rgbMatch) return 'rgba(' + rgbMatch[1] + ',' + rgbMatch[2] + ',' + rgbMatch[3] + ',' + alpha + ')';
+ var hex = color.replace('#', '');
+ var r = parseInt(hex.substring(0, 2), 16);
+ var g = parseInt(hex.substring(2, 4), 16);
+ var b = parseInt(hex.substring(4, 6), 16);
+ return 'rgba(' + r + ',' + g + ',' + b + ',' + alpha + ')';
+ }
+
+ function sampleColors() {
+ var style = getComputedStyle(document.documentElement);
+ var isDark = !document.documentElement.classList.contains('theme-light');
+ colors.accent = style.getPropertyValue('--accent').trim() || '#5c9cf5';
+ colors.accent2 = style.getPropertyValue('--accent2').trim() || '#4ec97b';
+ colors.bg = style.getPropertyValue('--bg-card').trim() || '#161b25';
+ colors.head = isDark ? '#ffffff' : '#1a0533';
+ }
+
+ function resizeCanvas() {
+ canvas.width = Math.floor(header.offsetWidth * 0.65);
+ canvas.height = header.offsetHeight;
+ ctx.font = '14px "IBM Plex Mono", monospace';
+ ctx.textBaseline = 'top';
+ initColumns();
+ }
+
+ function initColumns() {
+ columns = [];
+ var columnWidth = 14;
+ var columnCount = Math.floor(canvas.width / columnWidth);
+ for (var i = 0; i < columnCount; i++) {
+ columns.push({
+ x: i * columnWidth,
+ y: -Math.floor(Math.random() * 40),
+ speed: 2 + Math.floor(Math.random() * 3),
+ color: Math.random() < 0.6 ? 'accent2' : 'accent',
+ charIndex: Math.floor(Math.random() * CHARS.length),
+ length: 8 + Math.floor(Math.random() * 13)
+ });
+ }
+ }
+
+ function setupThemeObserver() {
+ var observer = new MutationObserver(function(mutations) {
+ for (var i = 0; i < mutations.length; i++) {
+ if (mutations[i].attributeName === 'class') { sampleColors(); break; }
+ }
+ });
+ observer.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] });
+ }
+
+ function drawFrame() {
+ frameCount++;
+ ctx.fillStyle = hexToRgba(colors.bg, 0.085);
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+
+ for (var ci = 0; ci < columns.length; ci++) {
+ var col = columns[ci];
+ if (frameCount % col.speed !== 0) continue;
+
+ ctx.fillStyle = colors[col.color];
+ for (var i = 1; i <= col.length; i++) {
+ var trailY = (col.y - i) * 14;
+ if (trailY < 0) continue;
+ var trailCharIndex = (col.charIndex - i + CHARS.length) % CHARS.length;
+ ctx.fillText(CHARS[trailCharIndex], col.x, trailY);
+ }
+
+ ctx.fillStyle = colors.head;
+ ctx.fillText(CHARS[col.charIndex % CHARS.length], col.x, col.y * 14);
+
+ col.y++;
+ col.charIndex = (col.charIndex + 1) % CHARS.length;
+
+ 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);
+ }
+
+ sampleColors();
+ resizeCanvas();
+ setupThemeObserver();
+
+ var resizeTimer;
+ window.addEventListener('resize', function() {
+ clearTimeout(resizeTimer);
+ resizeTimer = setTimeout(resizeCanvas, 150);
+ });
+
+ document.fonts.ready.then(function() {
+ requestAnimationFrame(drawFrame);
+ });
+})();