/* ASCII-Shimmer: rendert einen Text als flimmerndes ASCII-Art-Textbild. Idee: Buchstaben werden zu einer Pixelmaske, innerhalb der Maske werden Zeichen aus einem Zeichensatz zufaellig neu gewuerfelt. */ (function () { function initAsciiShimmer(container) { var text = container.dataset.text || 'KILABOR'; var cell = parseInt(container.dataset.cell || '10', 10); var primaryColor = container.dataset.color || '#ff4500'; var dimColor = container.dataset.dimColor || 'rgba(212,175,55,0.35)'; var intervalMs = parseInt(container.dataset.interval || '140', 10); var denseChars = ['$', '@', '%', '#', '&', '8', '0']; var edgeChars = ['+', 'x', '-', '=', ':', '.', 'o']; var canvas = document.createElement('canvas'); canvas.style.display = 'block'; container.appendChild(canvas); var ctx = canvas.getContext('2d'); var mask = []; var timer = null; var cssWidth = 0; var cssHeight = 0; function buildMask() { var width = container.clientWidth || 600; var fontSize = Math.min(width / (text.length * 0.62), 160); var height = Math.ceil(fontSize * 1.3); cssWidth = width; cssHeight = height; var dpr = Math.min(window.devicePixelRatio || 1, 2); canvas.width = Math.round(width * dpr); canvas.height = Math.round(height * dpr); canvas.style.width = width + 'px'; canvas.style.height = height + 'px'; ctx.setTransform(dpr, 0, 0, dpr, 0, 0); var mCanvas = document.createElement('canvas'); mCanvas.width = width; mCanvas.height = height; var mctx = mCanvas.getContext('2d'); // Canvas bleibt transparent (alpha 0) - nur der Text bekommt Alpha > 0, // darueber wird die Maske erkannt (kein separates Schwarz-Fuellen!). mctx.fillStyle = '#fff'; mctx.font = "900 " + fontSize + "px 'Courier New', monospace"; mctx.textBaseline = 'middle'; mctx.textAlign = 'center'; mctx.fillText(text, width / 2, height / 2); var imgData = mctx.getImageData(0, 0, width, height).data; var cols = Math.floor(width / cell); var rows = Math.floor(height / cell); mask = []; for (var ry = 0; ry < rows; ry++) { for (var rx = 0; rx < cols; rx++) { var px = Math.floor(rx * cell + cell / 2); var py = Math.floor(ry * cell + cell / 2); var idx = (py * width + px) * 4; var alpha = imgData[idx + 3] / 255; if (alpha > 0.15) { mask.push({ x: rx, y: ry, alpha: alpha }); } } } } function draw() { ctx.clearRect(0, 0, cssWidth, cssHeight); ctx.font = cell + "px 'Courier New', monospace"; ctx.textBaseline = 'middle'; ctx.textAlign = 'center'; for (var i = 0; i < mask.length; i++) { var c = mask[i]; var isDense = c.alpha > 0.7; var set = isDense ? denseChars : edgeChars; var char = set[(Math.random() * set.length) | 0]; ctx.fillStyle = isDense ? primaryColor : dimColor; ctx.fillText(char, c.x * cell + cell / 2, c.y * cell + cell / 2); } } function start() { buildMask(); draw(); timer = setInterval(draw, intervalMs); } function stop() { if (timer) { clearInterval(timer); timer = null; } } start(); var resizeTimeout; window.addEventListener('resize', function () { clearTimeout(resizeTimeout); resizeTimeout = setTimeout(function () { buildMask(); draw(); }, 200); }); document.addEventListener('visibilitychange', function () { if (document.hidden) { stop(); } else if (!timer) { start(); } }); } document.addEventListener('DOMContentLoaded', function () { var containers = document.querySelectorAll('[data-ascii-shimmer]'); for (var i = 0; i < containers.length; i++) { initAsciiShimmer(containers[i]); } }); })();