memoscan
← all memos

Memo 0xbac51f02…fe8e44 on Ethereum

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>Smear Art</title> <style>*{margin:0;padding:0;box-sizing:border-box}body,html{width:100%;height:100%;overflow:hidden;background:#000}#container{position:relative;width:600px;height:600px;margin:0 auto;background:#000}.partition{position:absolute;overflow:hidden}.partition canvas{width:100%;height:100%;display:block;image-rendering:pixelated;image-rendering:crisp-edges;position:relative;z-index:10}</style> </head> <body> <div id="container"></div> <script> const container = document.getElementById('container'); const partitions = [{"x":-2,"y":0,"w":308,"h":600,"pattern":"random-blocks","color1":"#ceff00","color2":"#000000","cellSize":10,"speed":5,"smearAmount":2,"direction":{"dx":-1,"dy":0,"name":"left"},"enableDirectionChange":true,"directionChangeInterval":3861.3076612313293,"sourceInterval":1000,"smearMode":"replace","trailIntensity":0.85,"opacity":1},{"x":303,"y":3,"w":311,"h":605,"pattern":"cellular-automata","color1":"#f865b0","color2":"#000000","cellSize":10,"speed":5,"smearAmount":2,"direction":{"dx":1,"dy":0,"name":"right"},"enableDirectionChange":false,"directionChangeInterval":3000,"sourceInterval":1000,"smearMode":"trail","trailIntensity":0.98,"opacity":1},{"x":163,"y":-2,"w":222,"h":611,"pattern":"perlin","color1":"#f4faff","color2":"#000000","cellSize":10,"speed":5,"smearAmount":2,"direction":{"dx":-1,"dy":1,"name":"down-left"},"enableDirectionChange":true,"directionChangeInterval":2805.7492425761707,"sourceInterval":1000,"smearMode":"replace","trailIntensity":0.85,"opacity":0.81}]; class SmearPartition { constructor(config) { this.config = config; this.div = document.createElement('div'); this.div.className = 'partition'; this.div.style.left = config.x + 'px'; this.div.style.top = config.y + 'px'; this.div.style.width = config.w + 'px'; this.div.style.height = config.h + 'px'; this.canvas = document.createElement('canvas'); this.canvas.width = Math.floor(config.w); this.canvas.height = Math.floor(config.h); this.ctx = this.canvas.getContext('2d'); this.ctx.imageSmoothingEnabled = false; this.div.appendChild(this.canvas); container.appendChild(this.div); this.direction = config.direction; this.enableDirectionChange = config.enableDirectionChange || false; this.directionChangeInterval = config.directionChangeInterval || 3000; this.lastDirectionChange = 0; this.lastSourceTime = 0; this.imageData = null; this.opacity = config.opacity !== undefined ? config.opacity : 1.0; this.fgRGB = this.hexToRGB(config.color1); this.bgRGB = this.hexToRGB(config.color2 || '#000000'); this.sourceParams = this.generateSourceParams(); this.gradientCache = null; this.caState = null; this.initPattern(); this.start(); } generateSourceParams() { return { steps: 3 + Math.floor(Math.random() * 6), stripeWidth: 2 + Math.floor(Math.random() * 8), checkSize: 1 + Math.floor(Math.random() * 4), phase: 0, dashLength: 3 + Math.floor(Math.random() * 10), gapLength: 2 + Math.floor(Math.random() * 6), density: 0.05 + Math.random() * 0.25, frequency: 1 + Math.random() * 4, sinePhase: Math.random() * Math.PI * 2, seed1: Math.random() * 100, seed2: Math.random() * 100, seed3: Math.random() * 100, counter: Math.floor(Math.random() * 65536), caRule: Math.random() > 0.5 ? 30 : 110 }; } hexToRGB(hex) { const r = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return r ? { r: parseInt(r[1], 16), g: parseInt(r[2], 16), b: parseInt(r[3], 16) } : { r: 255, g: 255, b: 255 }; } lerpColor(t) { return { r: Math.round(this.bgRGB.r + (this.fgRGB.r - this.bgRGB.r) * t), g: Math.round(this.bgRGB.g + (this.fgRGB.g - this.bgRGB.g) * t), b: Math.round(this.bgRGB.b + (this.fgRGB.b - this.bgRGB.b) * t) }; } getSourceValue(pos, length) { const t = pos / length; const cfg = this.config; switch(cfg.pattern) { case 'noise': return Math.random() > 0.5 ? this.fgRGB : this.bgRGB; case 'linear-gradient': return this.lerpColor(t); case 'stepped-gradient': const steps = this.sourceParams.steps || 5; return this.lerpColor(Math.floor(t * steps) / (steps - 1)); case 'random-gradient': if (!this.gradientCache || this.gradientCache.length !== length) { this.generateRandomGradient(length); } return this.lerpColor(this.gradientCache[pos]); case 'stripes': return (Math.floor(pos / (cfg.cellSize || 10)) % 2 === 0) ? this.fgRGB : this.bgRGB; case 'checkerboard': return ((Math.floor(pos / (cfg.cellSize || 10)) + (this.sourceParams.phase || 0)) % 2 === 0) ? this.fgRGB : this.bgRGB; case 'random-blocks': const blockIndex = Math.floor(pos / (cfg.cellSize || 10)); const blockRandom = Math.sin(blockIndex * 12.9898 + this.sourceParams.seed1) * 43758.5453; return (blockRandom - Math.floor(blockRandom)) > 0.5 ? this.fgRGB : this.bgRGB; case 'dashes': const cycle = (this.sourceParams.dashLength || 6) + (this.sourceParams.gapLength || 3); return (pos % cycle < (this.sourceParams.dashLength || 6)) ? this.fgRGB : this.bgRGB; case 'dots': return Math.random() < (this.sourceParams.density || 0.15) ? this.fgRGB : this.bgRGB; case 'sine': const sv = (Math.sin((t * (this.sourceParams.frequency || 2) * Math.PI * 2) + (this.sourceParams.sinePhase || 0)) + 1) / 2; return this.lerpColor(sv); case 'perlin': const p1 = Math.sin(t * 3.7 + this.sourceParams.seed1) * 0.5; const p2 = Math.sin(t * 7.3 + this.sourceParams.seed2) * 0.25; const p3 = Math.sin(t * 13.1 + this.sourceParams.seed3) * 0.125; return this.lerpColor(Math.max(0, Math.min(1, (p1 + p2 + p3 + 0.875) / 1.75))); case 'binary-counter': return ((this.sourceParams.counter >> (pos % 16)) & 1) ? this.fgRGB : this.bgRGB; case 'cellular-automata': if (!this.caState || this.caState.length !== length) { this.initCellularAutomata(length); } return this.caState[pos] ? this.fgRGB : this.bgRGB; default: return Math.random() > 0.5 ? this.fgRGB : this.bgRGB; } } generateRandomGradient(length) { const np = 3 + Math.floor(Math.random() * 4); const cp = [0]; for (let i = 1; i < np - 1; i++) cp.push(Math.random()); cp.push(1); cp.sort((a, b) => a - b); const cv = cp.map(() => Math.random()); this.gradientCache = []; for (let i = 0; i < length; i++) { const t = i / length; let si = 0; for (let j = 0; j < cp.length - 1; j++) { if (t >= cp[j] && t <= cp[j + 1]) { si = j; break; } } const st = (t - cp[si]) / (cp[si + 1] - cp[si]); this.gradientCache.push(cv[si] + (cv[si + 1] - cv[si]) * st); } } initCellularAutomata(length) { this.caState = []; for (let i = 0; i < length; i++) { this.caState.push(Math.random() > 0.5); } } evolveCellularAutomata() { if (!this.caState) return; const rule = this.sourceParams.caRule || 30; const os = [...this.caState]; const len = this.caState.length; for (let i = 0; i < len; i++) { const p = (os[(i - 1 + len) % len] ? 4 : 0) + (os[i] ? 2 : 0) + (os[(i + 1) % len] ? 1 : 0); this.caState[i] = ((rule >> p) & 1) === 1; } } updateSourceParams() { const cfg = this.config; switch(cfg.pattern) { case 'checkerboard': this.sourceParams.phase = (this.sourceParams.phase + 1) % 2; break; case 'sine': this.sourceParams.sinePhase += 0.5; break; case 'binary-counter': this.sourceParams.counter++; break; case 'cellular-automata': this.evolveCellularAutomata(); break; case 'random-gradient': this.gradientCache = null; break; case 'perlin': this.sourceParams.seed1 += 0.3; this.sourceParams.seed2 += 0.2; this.sourceParams.seed3 += 0.1; break; } } generateSourceEdge() { this.updateSourceParams(); const data = this.imageData.data; const w = this.canvas.width; const h = this.canvas.height; const length = w; const cfg = this.config; for (let i = 0; i < length; i++) { const x = i; const y = 0; // top edge let color; // 2D patterns need both x and y coordinates if (cfg.pattern === 'checkerboard') { const cellX = Math.floor(x / (cfg.cellSize || 10)); const cellY = Math.floor(y / (cfg.cellSize || 10)); color = ((cellX + cellY) % 2 === 0) ? this.fgRGB : this.bgRGB; } else if (cfg.pattern === 'random-blocks') { const cellX = Math.floor(x / (cfg.cellSize || 10)); const cellY = Math.floor(y / (cfg.cellSize || 10)); const seed = cellX * 73856093 ^ cellY * 19349663; const blockRandom = Math.sin(seed + this.sourceParams.seed1) * 43758.5453; color = (blockRandom - Math.floor(blockRandom)) > 0.5 ? this.fgRGB : this.bgRGB; } else { // 1D patterns color = this.getSourceValue(i, length); } const idx = i * 4; data[idx] = color.r; data[idx + 1] = color.g; data[idx + 2] = color.b; data[idx + 3] = Math.round(this.opacity * 255); } } changeDirection() { const dirs = [ { dx: 0, dy: 1, name: 'down' }, { dx: 1, dy: 1, name: 'down-right' }, { dx: 1, dy: 0, name: 'right' }, { dx: 1, dy: -1, name: 'up-right' }, { dx: 0, dy: -1, name: 'up' }, { dx: -1, dy: -1, name: 'up-left' }, { dx: -1, dy: 0, name: 'left' }, { dx: -1, dy: 1, name: 'down-left' } ]; const currentIndex = dirs.findIndex(d => d.dx === this.direction.dx && d.dy === this.direction.dy); if (currentIndex === -1) return; const newIndex = Math.random() > 0.5 ? (currentIndex + 1) % 8 : (currentIndex + 7) % 8; this.direction = dirs[newIndex]; } initPattern() { const w = this.canvas.width; const h = this.canvas.height; const length = w; const cfg = this.config; this.imageData = this.ctx.createImageData(w, h); for (let y = 0; y < h; y++) { for (let x = 0; x < w; x++) { let color; // 2D patterns need both x and y if (cfg.pattern === 'checkerboard') { const cellX = Math.floor(x / (cfg.cellSize || 10)); const cellY = Math.floor(y / (cfg.cellSize || 10)); color = ((cellX + cellY) % 2 === 0) ? this.fgRGB : this.bgRGB; } else if (cfg.pattern === 'random-blocks') { const cellX = Math.floor(x / (cfg.cellSize || 10)); const cellY = Math.floor(y / (cfg.cellSize || 10)); const seed = cellX * 73856093 ^ cellY * 19349663; const blockRandom = Math.sin(seed + this.sourceParams.seed1) * 43758.5453; color = (blockRandom - Math.floor(blockRandom)) > 0.5 ? this.fgRGB : this.bgRGB; } else { // 1D patterns color = this.getSourceValue(x, length); } const idx = (y * w + x) * 4; this.imageData.data[idx] = color.r; this.imageData.data[idx + 1] = color.g; this.imageData.data[idx + 2] = color.b; this.imageData.data[idx + 3] = Math.round(this.opacity * 255); } } this.ctx.putImageData(this.imageData, 0, 0); } smear() { if (!this.imageData) return; const cfg = this.config; const data = this.imageData.data; const w = this.canvas.width; const h = this.canvas.height; const newData = this.ctx.createImageData(w, h); const newPixels = newData.data; const mode = cfg.smearMode || 'replace'; const intensity = cfg.trailIntensity || 0.85; for (let y = 0; y < h; y++) { for (let x = 0; x < w; x++) { let srcX = x - this.direction.dx * cfg.smearAmount; let srcY = y - this.direction.dy * cfg.smearAmount; srcX = (srcX + w) % w; srcY = (srcY + h) % h; const srcIdx = (srcY * w + srcX) * 4; const dstIdx = (y * w + x) * 4; if (mode === 'trail') { newPixels[dstIdx] = data[srcIdx] * intensity + data[dstIdx] * (1 - intensity); newPixels[dstIdx + 1] = data[srcIdx + 1] * intensity + data[dstIdx + 1] * (1 - intensity); newPixels[dstIdx + 2] = data[srcIdx + 2] * intensity + data[dstIdx + 2] * (1 - intensity); newPixels[dstIdx + 3] = Math.round(this.opacity * 255); } else { newPixels[dstIdx] = data[srcIdx]; newPixels[dstIdx + 1] = data[srcIdx + 1]; newPixels[dstIdx + 2] = data[srcIdx + 2]; newPixels[dstIdx + 3] = Math.round(this.opacity * 255); } } } this.imageData = newData; this.ctx.putImageData(this.imageData, 0, 0); } start() { const animate = (timestamp) => { if (!this.lastDirectionChange) this.lastDirectionChange = timestamp; if (!this.lastSourceTime) this.lastSourceTime = timestamp; if (this.enableDirectionChange && timestamp - this.lastDirectionChange >= this.directionChangeInterval) { this.changeDirection(); this.lastDirectionChange = timestamp; this.directionChangeInterval = 1000 + Math.random() * 4000; } if (timestamp - this.lastSourceTime >= (this.config.sourceInterval || 1000)) { this.generateSourceEdge(); this.lastSourceTime = timestamp; } this.smear(); setTimeout(() => requestAnimationFrame(animate), 1000 / this.config.speed); }; requestAnimationFrame(animate); } } partitions.forEach(config => new SmearPartition(config)); </script> </body> </html>