this repo has no description
at main 117 lines 3.4 kB view raw
1<!DOCTYPE html> 2<html> 3 <head> 4 <meta charset="utf-8"> 5 <style> 6 * { 7 margin: 0; 8 padding: 0; 9 } 10 html, body { 11 overflow: hidden; 12 } 13 canvas { 14 display: block; 15 image-rendering: pixelated; 16 } 17 </style> 18 </head> 19 <body> 20 <canvas id="c" width="88" height="31"></canvas> 21 <script> 22 const canvas = document.getElementById("c"), ctx = canvas.getContext("2d"); 23 24 const BUTTON_W = 88, BUTTON_H = 31; 25 const pixelBuffer = new Uint8ClampedArray(BUTTON_W * BUTTON_H * 4); 26 27 let time = 0; 28 29 const bayer = [0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5].map((v) => v / 16); 30 function dither(brightness, x, y) { 31 const threshold = bayer[(y & 3) * 4 + (x & 3)]; 32 return brightness > threshold ? 255 : 0; 33 } 34 35 function wave(x, y, time) { 36 const normX = x / BUTTON_W; 37 const normY = y / BUTTON_H; 38 39 const depth = normY; 40 const depth2 = depth * depth; 41 42 const frequency = 7 + 18 * depth2; 43 const scrollSpeed = time * (0.5 + depth2 * 1.4); 44 45 const w1 = Math.sin(normX * frequency + scrollSpeed + Math.sin(normX * 3.1 - time * 0.4) * 1.5); 46 const w2 = Math.sin( 47 normX * frequency * 0.6 - scrollSpeed * 1.2 + Math.cos(normX * 5.7 + time * 0.5) * 1.0, 48 ); 49 const w3 = Math.sin(normX * frequency * 1.4 + scrollSpeed * 0.8 + normY * 5 - time); 50 const w4 = Math.cos( 51 normX * frequency * 0.35 - scrollSpeed * 0.6 + Math.sin(normY * 8 + time * 0.7) * 0.8, 52 ); 53 54 const weightedBrightness = w1 * 0.35 + w2 * 0.3 + w3 * 0.2 + w4 * 0.15; 55 const foamCrest = Math.max(0, weightedBrightness - 0.45) * 4 * depth; 56 const contrastScaled = weightedBrightness * (0.25 + depth2 * 0.75) + 0.4; 57 58 return Math.max(0, Math.min(1, contrastScaled + foamCrest)); 59 } 60 61 const glyphs = { 62 k: ["1000", "1001", "1010", "1100", "1010", "1001"], 63 y: ["0000", "1001", "1001", "0111", "0001", "0110"], 64 u: ["0000", "1001", "1001", "1001", "1001", "0111"], 65 ".": ["0", "0", "0", "0", "0", "1"], 66 r: ["0000", "1011", "1100", "1000", "1000", "1000"], 67 e: ["0000", "0110", "1001", "1111", "1000", "0110"], 68 }; 69 70 const charWidths = { k: 4, y: 4, u: 4, ".": 1, r: 4, e: 4 }; 71 const labelChars = ["k", "y", "u", ".", "r", "e"]; 72 73 const TAG_W = 30, TAG_H = 11; 74 const TAG_X = BUTTON_W - TAG_W; 75 const TAG_Y = BUTTON_H - TAG_H; 76 const TEXT_X = TAG_X + 2; 77 const TEXT_Y = TAG_Y + 2; 78 79 function drawTag() { 80 ctx.fillStyle = "#000"; 81 ctx.fillRect(TAG_X, TAG_Y, TAG_W, TAG_H); 82 83 ctx.fillStyle = "#fff"; 84 let cursorX = TEXT_X; 85 labelChars.forEach((char) => { 86 glyphs[char].forEach((row, rowIndex) => { 87 [...row].forEach((bit, bitIndex) => { 88 if (bit === "1") ctx.fillRect(cursorX + bitIndex, TEXT_Y + rowIndex, 1, 1); 89 }); 90 }); 91 cursorX += charWidths[char] + 1; 92 }); 93 } 94 95 function drawFrame() { 96 time += 0.038; 97 for (let y = 0; y < BUTTON_H; y++) { 98 for (let x = 0; x < BUTTON_W; x++) { 99 const brightness = dither(wave(x, y, time), x, y); 100 const bufferIndex = (y * BUTTON_W + x) * 4; 101 pixelBuffer[bufferIndex] = brightness; 102 pixelBuffer[bufferIndex + 1] = brightness; 103 pixelBuffer[bufferIndex + 2] = brightness; 104 pixelBuffer[bufferIndex + 3] = 255; 105 } 106 } 107 108 ctx.putImageData(new ImageData(pixelBuffer, BUTTON_W, BUTTON_H), 0, 0); 109 drawTag(); 110 111 requestAnimationFrame(drawFrame); 112 } 113 114 drawFrame(); 115 </script> 116 </body> 117</html>