memoscan
← all memos

Memo 0xc1a31a42…29e7f2 on Ethereum

<!doctype html><html><head><meta charset="utf-8"><title>smear</title><style> * { margin: 0; padding: 0; box-sizing: border-box; } body, html { width: 100%; height: 100%; overflow: hidden; background: #000; } smear-partition { display: block; width: 100%; height: 100%; position: relative; } smear-canvas { display: block; position: absolute; } smear-canvas canvas { display: block; width: 100%; height: 100%; image-rendering: pixelated; image-rendering: -moz-crisp-edges; image-rendering: crisp-edges; -ms-interpolation-mode: nearest-neighbor; } .smear-container { position: absolute; overflow: hidden; } .smear-container canvas { display: block; width: 100%; height: 100%; image-rendering: pixelated; image-rendering: crisp-edges; } </style></head><body style="margin:0;background-color:black;width:100vw;height:100vh;overflow:hidden;"><div id="puzzle-container"><div class="smear-container" data-x="0.2633542944785276" data-y="0.15239432515337423" data-width="0.12508573619631902" data-height="0.3071027607361963" data-start-edge="left" data-speed="66" data-source-interval="699" data-pixel-size="6" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="binary-counter" style="left: 171.707px; top: 99.3611px; width: 81.5559px; height: 200.231px;"><canvas></canvas></div><div class="smear-container" data-x="0.38844018404907976" data-y="0.15239432515337423" data-width="0.2792116564417178" data-height="0.1314920245398773" data-start-edge="right" data-speed="85" data-source-interval="772" data-pixel-size="4" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="binary-counter" style="left: 253.263px; top: 99.3611px; width: 182.046px; height: 85.7328px;"><canvas></canvas></div><div class="smear-container" data-x="0.7443144171779141" data-y="0.34110429447852764" data-width="0.25568558282208587" data-height="0.13884861963190184" data-start-edge="bottom" data-speed="99" data-source-interval="736" data-pixel-size="1" data-color-fg="#FF00CC" data-color-bg="#000000" data-source-type="binary-counter" style="left: 485.293px; top: 222.4px; width: 166.707px; height: 90.5293px;"><canvas></canvas></div><div class="smear-container" data-x="0" data-y="0.7027009202453988" data-width="0.5411533742331288" data-height="0.06321395705521472" data-start-edge="top" data-speed="39" data-source-interval="1880" data-pixel-size="3" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="binary-counter" style="left: 0px; top: 458.161px; width: 352.832px; height: 41.2155px;"><canvas></canvas></div><div class="smear-container" data-x="0.7443144171779141" data-y="0.15239432515337423" data-width="0.20815184049079755" data-height="0.1637638036809816" data-start-edge="right" data-speed="92" data-source-interval="1891" data-pixel-size="4" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="binary-counter" style="left: 485.293px; top: 99.3611px; width: 135.715px; height: 106.774px;"><canvas></canvas></div><div class="smear-container" data-x="0.4079769938650306" data-y="0.0725159509202454" data-width="0.4255122699386503" data-height="0.0798782208588957" data-start-edge="right" data-speed="93" data-source-interval="1188" data-pixel-size="5" data-color-fg="#FFFFFF" data-color-bg="#CCCCCC" data-source-type="binary-counter" style="left: 266.001px; top: 47.2804px; width: 277.434px; height: 52.0806px;"><canvas></canvas></div><div class="smear-container" data-x="0" data-y="0.15239432515337423" data-width="0.10145950920245399" data-height="0.330361963190184" data-start-edge="right" data-speed="64" data-source-interval="617" data-pixel-size="6" data-color-fg="#FFFFFF" data-color-bg="#CCCCCC" data-source-type="binary-counter" style="left: 0px; top: 99.3611px; width: 66.1516px; height: 215.396px;"><canvas></canvas></div><div class="smear-container" data-x="0.6256978527607362" data-y="0.9106088957055215" data-width="0.3743021472392638" data-height="0.08939125766871166" data-start-edge="left" data-speed="33" data-source-interval="999" data-pixel-size="6" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="binary-counter" style="left: 407.955px; top: 593.717px; width: 244.045px; height: 58.2831px;"><canvas></canvas></div><div class="smear-container" data-x="0" data-y="0.0725159509202454" data-width="0.4079769938650306" data-height="0.0798782208588957" data-start-edge="left" data-speed="75" data-source-interval="1083" data-pixel-size="1" data-color-fg="#FF00CC" data-color-bg="#000000" data-source-type="binary-counter" style="left: 0px; top: 47.2804px; width: 266.001px; height: 52.0806px;"><canvas></canvas></div><div class="smear-container" data-x="0.6005966257668711" data-y="0.4594969325153374" data-width="0.14371779141104293" data-height="0.22607975460122698" data-start-edge="bottom" data-speed="73" data-source-interval="1478" data-pixel-size="6" data-color-fg="#FFFFFF" data-color-bg="#CCCCCC" data-source-type="binary-counter" style="left: 391.589px; top: 299.592px; width: 93.704px; height: 147.404px;"><canvas></canvas></div><div class="smear-container" data-x="0.38844018404907976" data-y="0.32644171779141107" data-width="0.35587423312883437" data-height="0.08893895705521472" data-start-edge="left" data-speed="94" data-source-interval="1506" data-pixel-size="1" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="binary-counter" style="left: 253.263px; top: 212.84px; width: 232.03px; height: 57.9882px;"><canvas></canvas></div><div class="smear-container" data-x="0" data-y="0.8408604294478528" data-width="0.19852914110429448" data-height="0.15913957055214725" data-start-edge="right" data-speed="90" data-source-interval="1173" data-pixel-size="5" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="binary-counter" style="left: 0px; top: 548.241px; width: 129.441px; height: 103.759px;"><canvas></canvas></div><div class="smear-container" data-x="0.6256978527607362" data-y="0.7956932515337424" data-width="0.3743021472392638" data-height="0.08404171779141105" data-start-edge="bottom" data-speed="51" data-source-interval="1395" data-pixel-size="2" data-color-fg="#FFFFFF" data-color-bg="#CCCCCC" data-source-type="binary-counter" style="left: 407.955px; top: 518.792px; width: 244.045px; height: 54.7952px;"><canvas></canvas></div><div class="smear-container" data-x="0.4653865030674847" data-y="0.4594969325153374" data-width="0.13520981595092024" data-height="0.22607975460122698" data-start-edge="bottom" data-speed="54" data-source-interval="1446" data-pixel-size="4" data-color-fg="#FFFFFF" data-color-bg="#CCCCCC" data-source-type="binary-counter" style="left: 303.432px; top: 299.592px; width: 88.1568px; height: 147.404px;"><canvas></canvas></div><div class="smear-container" data-x="0.4803819018404908" data-y="0.7956932515337424" data-width="0.14531733128834357" data-height="0.20430674846625765" data-start-edge="top" data-speed="62" data-source-interval="727" data-pixel-size="3" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="binary-counter" style="left: 313.209px; top: 518.792px; width: 94.7469px; height: 133.208px;"><canvas></canvas></div><div class="smear-container" data-x="0.8568496932515338" data-y="0.47995245398773" data-width="0.14315076687116565" data-height="0.20562423312883438" data-start-edge="bottom" data-speed="66" data-source-interval="1945" data-pixel-size="1" data-color-fg="#FFFFFF" data-color-bg="#CCCCCC" data-source-type="binary-counter" style="left: 558.666px; top: 312.929px; width: 93.3343px; height: 134.067px;"><canvas></canvas></div><div class="smear-container" data-x="0.5411533742331288" data-y="0.7027009202453988" data-width="0.4588466257668712" data-height="0.06287883435582822" data-start-edge="bottom" data-speed="43" data-source-interval="1303" data-pixel-size="5" data-color-fg="#FF00CC" data-color-bg="#000000" data-source-type="binary-counter" style="left: 352.832px; top: 458.161px; width: 299.168px; height: 40.997px;"><canvas></canvas></div><div class="smear-container" data-x="0.2957162576687116" data-y="0.4594969325153374" data-width="0.12385046012269939" data-height="0.22607975460122698" data-start-edge="left" data-speed="51" data-source-interval="1298" data-pixel-size="4" data-color-fg="#FF00CC" data-color-bg="#000000" data-source-type="binary-counter" style="left: 192.807px; top: 299.592px; width: 80.7505px; height: 147.404px;"><canvas></canvas></div><div class="smear-container" data-x="0.10145950920245399" data-y="0.3067883435582822" data-width="0.10013696319018404" data-height="0.27716717791411044" data-start-edge="right" data-speed="47" data-source-interval="997" data-pixel-size="4" data-color-fg="#FFFFFF" data-color-bg="#CCCCCC" data-source-type="binary-counter" style="left: 66.1516px; top: 200.026px; width: 65.2893px; height: 180.713px;"><canvas></canvas></div><div class="smear-container" data-x="0" data-y="0.019546625766871165" data-width="0.7601625766871165" data-height="0.036402453987730066" data-start-edge="left" data-speed="84" data-source-interval="642" data-pixel-size="2" data-color-fg="#FFFFFF" data-color-bg="#CCCCCC" data-source-type="binary-counter" style="left: 0px; top: 12.7444px; width: 495.626px; height: 23.7344px;"><canvas></canvas></div><div class="smear-container" data-x="0.7443144171779141" data-y="0.47995245398773" data-width="0.11253466257668712" data-height="0.20562423312883438" data-start-edge="left" data-speed="78" data-source-interval="632" data-pixel-size="3" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="binary-counter" style="left: 485.293px; top: 312.929px; width: 73.3726px; height: 134.067px;"><canvas></canvas></div><div class="smear-container" data-x="0.20159662576687118" data-y="0.4594969325153374" data-width="0.09411978527607362" data-height="0.22607975460122698" data-start-edge="bottom" data-speed="99" data-source-interval="556" data-pixel-size="3" data-color-fg="#FF00CC" data-color-bg="#000000" data-source-type="binary-counter" style="left: 131.441px; top: 299.592px; width: 61.3661px; height: 147.404px;"><canvas></canvas></div><div class="smear-container" data-x="0" data-y="0.4827561349693252" data-width="0.10145950920245399" data-height="0.20282055214723926" data-start-edge="top" data-speed="82" data-source-interval="1596" data-pixel-size="6" data-color-fg="#FF00CC" data-color-bg="#000000" data-source-type="binary-counter" style="left: 0px; top: 314.757px; width: 66.1516px; height: 132.239px;"><canvas></canvas></div><div class="smear-container" data-x="0.7601625766871165" data-y="0" data-width="0.23983742331288344" data-height="0.0725159509202454" data-start-edge="right" data-speed="29" data-source-interval="925" data-pixel-size="4" data-color-fg="#FF00CC" data-color-bg="#000000" data-source-type="binary-counter" style="left: 495.626px; top: 0px; width: 156.374px; height: 47.2804px;"><canvas></canvas></div><div class="smear-container" data-x="0.19852914110429448" data-y="0.7956932515337424" data-width="0.0839355828220859" data-height="0.20430674846625765" data-start-edge="bottom" data-speed="85" data-source-interval="1601" data-pixel-size="6" data-color-fg="#FF00CC" data-color-bg="#000000" data-source-type="binary-counter" style="left: 129.441px; top: 518.792px; width: 54.726px; height: 133.208px;"><canvas></canvas></div><div class="smear-container" data-x="0" data-y="0.6855766871165644" data-width="1" data-height="0.017123312883435583" data-start-edge="top" data-speed="52" data-source-interval="706" data-pixel-size="1" data-color-fg="#FF00CC" data-color-bg="#000000" data-source-type="binary-counter" style="left: 0px; top: 446.996px; width: 652px; height: 11.1644px;"><canvas></canvas></div><div class="smear-container" data-x="0" data-y="0.7659141104294478" data-width="0.5411533742331288" data-height="0.02977883435582822" data-start-edge="bottom" data-speed="49" data-source-interval="576" data-pixel-size="2" data-color-fg="#FFFFFF" data-color-bg="#CCCCCC" data-source-type="binary-counter" style="left: 0px; top: 499.376px; width: 352.832px; height: 19.4158px;"><canvas></canvas></div><div class="smear-container" data-x="0.38844018404907976" data-y="0.4153819018404908" data-width="0.35587423312883437" data-height="0.04411564417177914" data-start-edge="right" data-speed="44" data-source-interval="1606" data-pixel-size="3" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="binary-counter" style="left: 253.263px; top: 270.829px; width: 232.03px; height: 28.7634px;"><canvas></canvas></div><div class="smear-container" data-x="0.10145950920245399" data-y="0.15239432515337423" data-width="0.10013696319018404" data-height="0.1543941717791411" data-start-edge="top" data-speed="94" data-source-interval="827" data-pixel-size="6" data-color-fg="#FFFFFF" data-color-bg="#CCCCCC" data-source-type="binary-counter" style="left: 66.1516px; top: 99.3611px; width: 65.2893px; height: 100.665px;"><canvas></canvas></div><div class="smear-container" data-x="0" data-y="0" data-width="0.7601625766871165" data-height="0.019546625766871165" data-start-edge="top" data-speed="32" data-source-interval="1916" data-pixel-size="6" data-color-fg="#FFFFFF" data-color-bg="#CCCCCC" data-source-type="binary-counter" style="left: 0px; top: 0px; width: 495.626px; height: 12.7444px;"><canvas></canvas></div><div class="smear-container" data-x="0.5411533742331288" data-y="0.7655797546012271" data-width="0.4588466257668712" data-height="0.030113957055214722" data-start-edge="left" data-speed="45" data-source-interval="1729" data-pixel-size="2" data-color-fg="#FFFFFF" data-color-bg="#CCCCCC" data-source-type="binary-counter" style="left: 352.832px; top: 499.158px; width: 299.168px; height: 19.6343px;"><canvas></canvas></div><div class="smear-container" data-x="0.6676518404907976" data-y="0.15239432515337423" data-width="0.07666273006134969" data-height="0.17404754601226993" data-start-edge="bottom" data-speed="70" data-source-interval="539" data-pixel-size="4" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="binary-counter" style="left: 435.309px; top: 99.3611px; width: 49.9841px; height: 113.479px;"><canvas></canvas></div><div class="smear-container" data-x="0.8334892638036809" data-y="0.0725159509202454" data-width="0.166510736196319" data-height="0.0798782208588957" data-start-edge="bottom" data-speed="59" data-source-interval="1995" data-pixel-size="1" data-color-fg="#FF00CC" data-color-bg="#000000" data-source-type="binary-counter" style="left: 543.435px; top: 47.2804px; width: 108.565px; height: 52.0806px;"><canvas></canvas></div><div class="smear-container" data-x="0" data-y="0.05594907975460123" data-width="0.7601625766871165" data-height="0.016566871165644172" data-start-edge="left" data-speed="42" data-source-interval="1096" data-pixel-size="3" data-color-fg="#FF00CC" data-color-bg="#000000" data-source-type="binary-counter" style="left: 0px; top: 36.4788px; width: 495.626px; height: 10.8016px;"><canvas></canvas></div><div class="smear-container" data-x="0.38844018404907976" data-y="0.28388650306748464" data-width="0.2792116564417178" data-height="0.0425558282208589" data-start-edge="left" data-speed="69" data-source-interval="1724" data-pixel-size="4" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="binary-counter" style="left: 253.263px; top: 185.094px; width: 182.046px; height: 27.7464px;"><canvas></canvas></div><div class="smear-container" data-x="0.6256978527607362" data-y="0.8797346625766871" data-width="0.3743021472392638" data-height="0.03087361963190184" data-start-edge="right" data-speed="59" data-source-interval="1717" data-pixel-size="2" data-color-fg="#FF00CC" data-color-bg="#000000" data-source-type="binary-counter" style="left: 407.955px; top: 573.587px; width: 244.045px; height: 20.1296px;"><canvas></canvas></div><div class="smear-container" data-x="0.20159662576687118" data-y="0.15239432515337423" data-width="0.03373496932515337" data-height="0.3071027607361963" data-start-edge="bottom" data-speed="77" data-source-interval="1170" data-pixel-size="4" data-color-fg="#FFFFFF" data-color-bg="#CCCCCC" data-source-type="binary-counter" style="left: 131.441px; top: 99.3611px; width: 21.9952px; height: 200.231px;"><canvas></canvas></div><div class="smear-container" data-x="0.41956748466257665" data-y="0.4594969325153374" data-width="0.04582009202453988" data-height="0.22607975460122698" data-start-edge="right" data-speed="72" data-source-interval="792" data-pixel-size="6" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="binary-counter" style="left: 273.558px; top: 299.592px; width: 29.8747px; height: 147.404px;"><canvas></canvas></div><div class="smear-container" data-x="0.10145950920245399" data-y="0.5839555214723926" data-width="0.10013696319018404" data-height="0.10162116564417178" data-start-edge="bottom" data-speed="35" data-source-interval="540" data-pixel-size="5" data-color-fg="#FF00CC" data-color-bg="#000000" data-source-type="binary-counter" style="left: 66.1516px; top: 380.739px; width: 65.2893px; height: 66.257px;"><canvas></canvas></div><div class="smear-container" data-x="0" data-y="0.7956932515337424" data-width="0.19852914110429448" data-height="0.045167638036809815" data-start-edge="left" data-speed="98" data-source-interval="1640" data-pixel-size="1" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="binary-counter" style="left: 0px; top: 518.792px; width: 129.441px; height: 29.4493px;"><canvas></canvas></div><div class="smear-container" data-x="0.2353312883435583" data-y="0.15239432515337423" data-width="0.02802254601226994" data-height="0.3071027607361963" data-start-edge="top" data-speed="65" data-source-interval="1098" data-pixel-size="6" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="binary-counter" style="left: 153.436px; top: 99.3611px; width: 18.2707px; height: 200.231px;"><canvas></canvas></div><div class="smear-container" data-x="0.9524662576687117" data-y="0.15239432515337423" data-width="0.04753328220858896" data-height="0.1637638036809816" data-start-edge="left" data-speed="32" data-source-interval="1510" data-pixel-size="1" data-color-fg="#FF00CC" data-color-bg="#000000" data-source-type="binary-counter" style="left: 621.008px; top: 99.3611px; width: 30.9917px; height: 106.774px;"><canvas></canvas></div><div class="smear-container" data-x="0.7443144171779141" data-y="0.3161579754601227" data-width="0.25568558282208587" data-height="0.024946472392638037" data-start-edge="bottom" data-speed="74" data-source-interval="1150" data-pixel-size="1" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="binary-counter" style="left: 485.293px; top: 206.135px; width: 166.707px; height: 16.2651px;"><canvas></canvas></div><div class="smear-container" data-x="0.2824647239263804" data-y="0.7956932515337424" data-width="0.035585122699386504" data-height="0.20430674846625765" data-start-edge="top" data-speed="26" data-source-interval="1812" data-pixel-size="1" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="binary-counter" style="left: 184.167px; top: 518.792px; width: 23.2015px; height: 133.208px;"><canvas></canvas></div><div class="smear-container" data-x="0.31805061349693253" data-y="0.7956932515337424" data-width="0.16233128834355828" data-height="0.20430674846625765" data-start-edge="left" data-speed="91" data-source-interval="834" data-pixel-size="2" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="binary-counter" style="left: 207.369px; top: 518.792px; width: 105.84px; height: 133.208px;"><canvas></canvas></div></div><script> class SmearCanvas { constructor(c) { this.container = c; this.canvas = c.querySelector("canvas") || document.createElement("canvas"); if (!c.querySelector("canvas")) c.appendChild(this.canvas); this.ctx = this.canvas.getContext("2d"); this.ctx.imageSmoothingEnabled = false; this.imageData = null; this.lastTime = 0; this.animationId = null; this.speed = parseInt(c.dataset.speed) || 50; this.pixelSize = parseInt(c.dataset.pixelSize) || 2; this.sourceInterval = parseInt(c.dataset.sourceInterval) || 1000; this.colorFg = c.dataset.colorFg || "#FFFFFF"; this.colorBg = c.dataset.colorBg || "#000000"; this.sourceType = c.dataset.sourceType || "noise"; this.startEdge = c.dataset.startEdge || "top"; this.fgRGB = this.hexToRGB(this.colorFg); this.bgRGB = this.hexToRGB(this.colorBg); this.moveSpeed = (1000 / 60) / this.speed; this.subPixelX = 0; this.subPixelY = 0; this.leadX = 0; this.leadY = 0; this.initDirection(); this.lastDirectionChange = 0; this.nextDirectionInterval = this.randomInterval(); this.sourceParams = this.generateSourceParams(); this.lastSourceTime = 0; this.resize(); this.initCanvas(); this.generateSourceEdge(); this.initLeadPosition(); this.startAnimation(); this.resizeObserver = new ResizeObserver(() => this.resize()); this.resizeObserver.observe(this.container); } 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 }; } initDirection() { switch (this.startEdge) { case "top": this.dx = 0; this.dy = 1; break; case "bottom": this.dx = 0; this.dy = -1; break; case "left": this.dx = 1; this.dy = 0; break; case "right": this.dx = -1; this.dy = 0; break; default: this.dx = 0; this.dy = 1; } } initLeadPosition() { switch (this.startEdge) { case "top": this.leadX = Math.floor(this.internalWidth / 2); this.leadY = 1; break; case "bottom": this.leadX = Math.floor(this.internalWidth / 2); this.leadY = this.internalHeight - 2; break; case "left": this.leadX = 1; this.leadY = Math.floor(this.internalHeight / 2); break; case "right": this.leadX = this.internalWidth - 2; this.leadY = Math.floor(this.internalHeight / 2); break; } } resize() { var rect = this.container.getBoundingClientRect(); if (rect.width === 0 || rect.height === 0) return; this.internalWidth = Math.ceil(rect.width / this.pixelSize); this.internalHeight = Math.ceil(rect.height / this.pixelSize); var oldImageData = this.imageData; var oldWidth = this.canvas.width; var oldHeight = this.canvas.height; this.canvas.width = this.internalWidth; this.canvas.height = this.internalHeight; this.imageData = this.ctx.createImageData(this.internalWidth, this.internalHeight); if (oldImageData && oldWidth > 0 && oldHeight > 0) { var minW = Math.min(oldWidth, this.internalWidth); var minH = Math.min(oldHeight, this.internalHeight); for (var y = 0; y < minH; y++) { for (var x = 0; x < minW; x++) { var oi = (y * oldWidth + x) * 4; var ni = (y * this.internalWidth + x) * 4; this.imageData.data[ni] = oldImageData.data[oi]; this.imageData.data[ni + 1] = oldImageData.data[oi + 1]; this.imageData.data[ni + 2] = oldImageData.data[oi + 2]; this.imageData.data[ni + 3] = oldImageData.data[oi + 3]; } } } } hexToRGB(hex) { var 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) { var t = pos / length; switch (this.sourceType) { case "noise": return Math.random() > 0.5 ? this.fgRGB : this.bgRGB; case "linear-gradient": return this.lerpColor(t); case "stepped-gradient": var 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 / (this.sourceParams.stripeWidth || 4)) % 2 === 0) ? this.fgRGB : this.bgRGB; case "checkerboard": return ((Math.floor(pos / (this.sourceParams.checkSize || 2)) + (this.sourceParams.phase || 0)) % 2 === 0) ? this.fgRGB : this.bgRGB; case "dashes": var 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": var sv = (Math.sin((t * (this.sourceParams.frequency || 2) * Math.PI * 2) + (this.sourceParams.sinePhase || 0)) + 1) / 2; return this.lerpColor(sv); case "perlin": var p1 = Math.sin(t * 3.7 + this.sourceParams.seed1) * 0.5; var p2 = Math.sin(t * 7.3 + this.sourceParams.seed2) * 0.25; var 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) { var np = 3 + Math.floor(Math.random() * 4); var cp = [0]; for (var i = 1; i < np - 1; i++) cp.push(Math.random()); cp.push(1); cp.sort((a, b) => a - b); var cv = cp.map(() => Math.random()); this.gradientCache = []; for (var i = 0; i < length; i++) { var t = i / length; var si = 0; for (var j = 0; j < cp.length - 1; j++) { if (t >= cp[j] && t <= cp[j + 1]) { si = j; break; } } var 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 (var i = 0; i < length; i++) this.caState.push(Math.random() > 0.5); } evolveCellularAutomata() { if (!this.caState) return; var rule = this.sourceParams.caRule || 30; var os = [...this.caState]; var len = this.caState.length; for (var i = 0; i < len; i++) { var 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() { switch (this.sourceType) { 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; } } randomInterval() { return 100 + Math.random() * 900; } changeDirection() { var dirs = [[0, 1], [1, 1], [1, 0], [1, -1], [0, -1], [-1, -1], [-1, 0], [-1, 1]]; var idx = dirs.findIndex(d => d[0] === this.dx && d[1] === this.dy); if (idx === -1) idx = 0; idx = Math.random() > 0.5 ? (idx + 1) % 8 : (idx + 7) % 8; this.dx = dirs[idx][0]; this.dy = dirs[idx][1]; } initCanvas() { if (!this.imageData) return; var data = this.imageData.data; var w = this.internalWidth, h = this.internalHeight; var isH = (this.startEdge === "top" || this.startEdge === "bottom"); for (var y = 0; y < h; y++) { for (var x = 0; x < w; x++) { var idx = (y * w + x) * 4; var col = this.getSourceValue(isH ? x : y, isH ? w : h); data[idx] = col.r; data[idx + 1] = col.g; data[idx + 2] = col.b; data[idx + 3] = 255; } } this.ctx.putImageData(this.imageData, 0, 0); } generateSourceEdge() { if (!this.imageData) return; this.updateSourceParams(); var data = this.imageData.data; var w = this.internalWidth, h = this.internalHeight; var gen = (getIdx, len) => { for (var i = 0; i < len; i++) { var idx = getIdx(i); var c = this.getSourceValue(i, len); data[idx] = c.r; data[idx + 1] = c.g; data[idx + 2] = c.b; data[idx + 3] = 255; } }; switch (this.startEdge) { case "top": gen(x => x * 4, w); break; case "bottom": gen(x => ((h - 1) * w + x) * 4, w); break; case "left": gen(y => (y * w) * 4, h); break; case "right": gen(y => (y * w + (w - 1)) * 4, h); break; } } getSourceEdgeCoord(x, y) { switch (this.startEdge) { case "top": return y === 0; case "bottom": return y === this.internalHeight - 1; case "left": return x === 0; case "right": return x === this.internalWidth - 1; } return false; } smear() { if (!this.imageData) return; var data = this.imageData.data; var w = this.internalWidth, h = this.internalHeight; this.subPixelX += this.dx * this.moveSpeed; this.subPixelY += this.dy * this.moveSpeed; var moveX = Math.trunc(this.subPixelX), moveY = Math.trunc(this.subPixelY); if (moveX === 0 && moveY === 0) return; this.subPixelX -= moveX; this.subPixelY -= moveY; this.leadX += moveX; this.leadY += moveY; if (this.leadX <= 0 || this.leadX >= w - 1) { this.dx = -this.dx; this.leadX = Math.max(0, Math.min(w - 1, this.leadX)); } if (this.leadY <= 0 || this.leadY >= h - 1) { this.dy = -this.dy; this.leadY = Math.max(0, Math.min(h - 1, this.leadY)); } var oldData = new Uint8ClampedArray(data); for (var y = 0; y < h; y++) { for (var x = 0; x < w; x++) { if (this.getSourceEdgeCoord(x, y)) continue; var srcX = Math.max(0, Math.min(w - 1, x - moveX)); var srcY = Math.max(0, Math.min(h - 1, y - moveY)); var dstIdx = (y * w + x) * 4, srcIdx = (srcY * w + srcX) * 4; data[dstIdx] = oldData[srcIdx]; data[dstIdx + 1] = oldData[srcIdx + 1]; data[dstIdx + 2] = oldData[srcIdx + 2]; data[dstIdx + 3] = oldData[srcIdx + 3]; } } } startAnimation() { var fi = 1000 / 60; var animate = (ts) => { if (!this.lastTime) this.lastTime = ts; if (!this.lastSourceTime) this.lastSourceTime = ts; if (!this.lastDirectionChange) this.lastDirectionChange = ts; if (ts - this.lastDirectionChange >= this.nextDirectionInterval) { this.changeDirection(); this.lastDirectionChange = ts; this.nextDirectionInterval = this.randomInterval(); } if (ts - this.lastSourceTime >= this.sourceInterval) { this.generateSourceEdge(); this.lastSourceTime = ts; } if (ts - this.lastTime >= fi) { this.smear(); if (this.imageData) this.ctx.putImageData(this.imageData, 0, 0); this.lastTime = ts; } this.animationId = requestAnimationFrame(animate); }; this.animationId = requestAnimationFrame(animate); } } function layoutSmears() { var vw = window.innerWidth, vh = window.innerHeight; document.querySelectorAll(".smear-container").forEach(function(div) { var x = parseFloat(div.dataset.x || 0); var y = parseFloat(div.dataset.y || 0); var w = parseFloat(div.dataset.width || 0); var h = parseFloat(div.dataset.height || 0); div.style.left = (x * vw) + "px"; div.style.top = (y * vh) + "px"; div.style.width = (w * vw) + "px"; div.style.height = (h * vh) + "px"; }); } function initSmears() { document.querySelectorAll(".smear-container").forEach(function(c) { if (!c._smearInstance) c._smearInstance = new SmearCanvas(c); }); } window.addEventListener("load", function() { layoutSmears(); initSmears(); }); window.addEventListener("resize", layoutSmears); layoutSmears(); initSmears(); </script></body></html>