diff options
| -rw-r--r-- | head.html | 163 |
1 files changed, 94 insertions, 69 deletions
@@ -34,67 +34,26 @@ document.addEventListener('DOMContentLoaded', function() { </script> <script> (function() { - if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; - - var CHARS = 'ヲイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~0123456789'; - var FONT_SIZE = 14; - var TRAIL_LEN = 12; - var TRAIL_FADE = 0.09; - var GREEN_MAX = 0.55; - var PURPLE_MAX = 0.75; - var PURPLE_PROB = 0.35; - var SPEED_MIN = 0.3; - var SPEED_MAX = 0.8; - var CANVAS_W_RATIO = 0.65; - var BG_CLEAR = 'rgba(12,21,32,0.18)'; - - function randChar() { - return CHARS[Math.floor(Math.random() * CHARS.length)]; - } + if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; - function makeColumn() { - return { - y: Math.random() * -20, - speed: SPEED_MIN + Math.random() * (SPEED_MAX - SPEED_MIN), - purple: Math.random() < PURPLE_PROB, - chars: Array.from({length: TRAIL_LEN}, randChar) - }; - } + 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 init(canvas, header) { - canvas.width = Math.floor(header.offsetWidth * CANVAS_W_RATIO); - canvas.height = header.offsetHeight; - var cols = Math.floor(canvas.width / FONT_SIZE); - return Array.from({length: cols}, makeColumn); + 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 draw(ctx, canvas, drops) { - ctx.fillStyle = BG_CLEAR; - ctx.fillRect(0, 0, canvas.width, canvas.height); - ctx.font = FONT_SIZE + 'px "JetBrains Mono", monospace'; - - var rows = Math.ceil(canvas.height / FONT_SIZE); - drops.forEach(function(drop, i) { - var x = i * FONT_SIZE; - for (var r = 0; r < TRAIL_LEN; r++) { - var row = Math.floor(drop.y) - r; - if (row < 0 || row >= rows) continue; - var fade = Math.max(0, 1 - r * TRAIL_FADE); - if (r === 0 && drop.purple) { - ctx.fillStyle = 'rgba(168,85,247,' + (PURPLE_MAX * fade).toFixed(2) + ')'; - } else { - ctx.fillStyle = 'rgba(0,255,136,' + (GREEN_MAX * fade).toFixed(2) + ')'; - } - if (Math.random() < 0.03) drop.chars[r % TRAIL_LEN] = randChar(); - ctx.fillText(drop.chars[r % TRAIL_LEN], x, row * FONT_SIZE); - } - drop.y += drop.speed; - if (drop.y * FONT_SIZE > canvas.height + 200) { - drop.y = Math.random() * -10; - drop.speed = SPEED_MIN + Math.random() * (SPEED_MAX - SPEED_MIN); - drop.purple = Math.random() < PURPLE_PROB; - } - }); + function hexToRgba(color, 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 + ')'; } document.addEventListener('DOMContentLoaded', function() { @@ -107,24 +66,90 @@ document.addEventListener('DOMContentLoaded', function() { header.appendChild(canvas); var fade = document.createElement('div'); - fade.id = 'matrix-rain-fade'; - fade.style.cssText = 'position:absolute;top:0;left:0;bottom:0;width:75%;background:linear-gradient(to right,rgba(12,21,32,0.88) 40%,transparent 100%);pointer-events:none;z-index:1;'; + fade.style.cssText = 'position:absolute;top:0;right:0;bottom:0;width:65%;background:linear-gradient(to right,var(--bg2) 0%,transparent 60%);pointer-events:none;z-index:1;'; header.appendChild(fade); - var ctx = canvas.getContext('2d'); - var drops = init(canvas, header); + var ctx = canvas.getContext('2d'); + var columns = []; + var frameCount = 0; + var colors = { accent: '#a855f7', accent2: '#00ff88', bg: '#0c1520', head: '#c4d6e8' }; + + function sampleColors() { + var style = getComputedStyle(document.documentElement); + colors.accent = style.getPropertyValue('--accent').trim() || '#a855f7'; + colors.accent2 = style.getPropertyValue('--accent2').trim() || '#00ff88'; + colors.bg = style.getPropertyValue('--bg2').trim() || '#0c1520'; + colors.head = style.getPropertyValue('--text').trim() || '#c4d6e8'; + } + + function resizeCanvas() { + canvas.width = Math.floor(header.offsetWidth * 0.65); + canvas.height = header.offsetHeight; + ctx.font = '14px "JetBrains 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.35 ? 'accent' : 'accent2', + charIndex: Math.floor(Math.random() * CHARS.length), + length: 8 + Math.floor(Math.random() * 13) + }); + } + } + + 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; - var raf; - function loop() { - draw(ctx, canvas, drops); - raf = requestAnimationFrame(loop); + 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.35 ? 'accent' : 'accent2'; + } + } + + requestAnimationFrame(drawFrame); } - loop(); + sampleColors(); + resizeCanvas(); + + var resizeTimer; window.addEventListener('resize', function() { - cancelAnimationFrame(raf); - drops = init(canvas, header); - loop(); + clearTimeout(resizeTimer); + resizeTimer = setTimeout(resizeCanvas, 150); + }); + + document.fonts.ready.then(function() { + requestAnimationFrame(drawFrame); }); }); })(); |
