summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-05-11 14:11:05 +0200
committerDanilo M. <danix@danix.xyz>2026-05-11 14:11:05 +0200
commit6fd9c1dd54e32b37fae9affd9b4980270fde5a12 (patch)
treeacf4fc759a379c85b5f8731768ecd14bfeab1e7e
parent82f263a78ea496190fa28e5d966d895dd5cd32ae (diff)
downloadcgit-theme-danix-6fd9c1dd54e32b37fae9affd9b4980270fde5a12.tar.gz
cgit-theme-danix-6fd9c1dd54e32b37fae9affd9b4980270fde5a12.zip
refactor(header): port matrix rain to frame-skip engine with CSS var colorsHEADmaster
Replaces float-y trail model with frame-skip column model matching repo-html-structure/.assets/matrix-rain.js. Key changes: pre-shuffled ASCII+katakana CHARS pool with sequential charIndex advance, distinct lead char in --text color, trail drawn in --accent/--accent2 read from CSS vars, hexToRgba bg clear using --bg2, DOMContentLoaded wrapper restored to fix null querySelector in <head> context. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
-rw-r--r--head.html163
1 files changed, 94 insertions, 69 deletions
diff --git a/head.html b/head.html
index 56af0ea..8f1b96b 100644
--- a/head.html
+++ b/head.html
@@ -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);
});
});
})();