0xb8952959…ccf4sent to0x6a4aa35b…a79e·#23,976,720·view on Etherscan
<!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" data-y="0" data-width="0.22094938650306747" data-height="0.35574693251533746" data-start-edge="top" data-speed="65" data-source-interval="1155" data-pixel-size="3" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 0px; top: 0px; width: 144.059px; height: 231.947px;"><canvas></canvas></div><div class="smear-container" data-x="0" data-y="0.35574693251533746" data-width="0.22094938650306747" data-height="0.20559509202453988" data-start-edge="right" data-speed="40" data-source-interval="993" data-pixel-size="1" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 0px; top: 231.947px; width: 144.059px; height: 134.048px;"><canvas></canvas></div><div class="smear-container" data-x="0" data-y="0.5613404907975461" data-width="0.22094938650306747" data-height="0.3453389570552147" data-start-edge="right" data-speed="52" data-source-interval="899" data-pixel-size="2" data-color-fg="#FFFF00" data-color-bg="#000000" data-source-type="dots" style="left: 0px; top: 365.994px; width: 144.059px; height: 225.161px;"><canvas></canvas></div><div class="smear-container" data-x="0" data-y="0.9066809815950919" data-width="0.22094938650306747" data-height="0.09331963190184049" data-start-edge="left" data-speed="64" data-source-interval="1790" data-pixel-size="5" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 0px; top: 591.156px; width: 144.059px; height: 60.8444px;"><canvas></canvas></div><div class="smear-container" data-x="0.22094938650306747" data-y="0" data-width="0.036445092024539875" data-height="0.06184432515337423" data-start-edge="left" data-speed="82" data-source-interval="1975" data-pixel-size="3" data-color-fg="#FFFF00" data-color-bg="#000000" data-source-type="dots" style="left: 144.059px; top: 0px; width: 23.7622px; height: 40.3225px;"><canvas></canvas></div><div class="smear-container" data-x="0.22094938650306747" data-y="0.06184432515337423" data-width="0.036445092024539875" data-height="0.13459141104294478" data-start-edge="left" data-speed="73" data-source-interval="972" data-pixel-size="2" data-color-fg="#FFFF00" data-color-bg="#000000" data-source-type="dots" style="left: 144.059px; top: 40.3225px; width: 23.7622px; height: 87.7536px;"><canvas></canvas></div><div class="smear-container" data-x="0.22094938650306747" data-y="0.19643558282208587" data-width="0.036445092024539875" data-height="0.12556641104294478" data-start-edge="left" data-speed="98" data-source-interval="1787" data-pixel-size="2" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 144.059px; top: 128.076px; width: 23.7622px; height: 81.8693px;"><canvas></canvas></div><div class="smear-container" data-x="0.22094938650306747" data-y="0.32200153374233126" data-width="0.036445092024539875" data-height="0.15084693251533743" data-start-edge="bottom" data-speed="26" data-source-interval="785" data-pixel-size="2" data-color-fg="#FFFF00" data-color-bg="#000000" data-source-type="dots" style="left: 144.059px; top: 209.945px; width: 23.7622px; height: 98.3522px;"><canvas></canvas></div><div class="smear-container" data-x="0.22094938650306747" data-y="0.47284969325153375" data-width="0.036445092024539875" data-height="0.06728067484662577" data-start-edge="right" data-speed="84" data-source-interval="663" data-pixel-size="2" data-color-fg="#FFFF00" data-color-bg="#000000" data-source-type="dots" style="left: 144.059px; top: 308.298px; width: 23.7622px; height: 43.867px;"><canvas></canvas></div><div class="smear-container" data-x="0.22094938650306747" data-y="0.5401303680981595" data-width="0.036445092024539875" data-height="0.084725" data-start-edge="top" data-speed="45" data-source-interval="1281" data-pixel-size="6" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 144.059px; top: 352.165px; width: 23.7622px; height: 55.2407px;"><canvas></canvas></div><div class="smear-container" data-x="0.22094938650306747" data-y="0.6248542944785276" data-width="0.036445092024539875" data-height="0.16785736196319018" data-start-edge="right" data-speed="38" data-source-interval="874" data-pixel-size="4" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 144.059px; top: 407.405px; width: 23.7622px; height: 109.443px;"><canvas></canvas></div><div class="smear-container" data-x="0.22094938650306747" data-y="0.7927116564417177" data-width="0.036445092024539875" data-height="0.20728834355828218" data-start-edge="right" data-speed="28" data-source-interval="1746" data-pixel-size="6" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 144.059px; top: 516.848px; width: 23.7622px; height: 135.152px;"><canvas></canvas></div><div class="smear-container" data-x="0.2573957055214724" data-y="0" data-width="0.18555061349693253" data-height="0.06498588957055215" data-start-edge="top" data-speed="83" data-source-interval="1174" data-pixel-size="6" data-color-fg="#FFFF00" data-color-bg="#000000" data-source-type="dots" style="left: 167.822px; top: 0px; width: 120.979px; height: 42.3708px;"><canvas></canvas></div><div class="smear-container" data-x="0.2573957055214724" data-y="0.06498588957055215" data-width="0.18555061349693253" data-height="0.23339877300613496" data-start-edge="bottom" data-speed="61" data-source-interval="1558" data-pixel-size="6" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 167.822px; top: 42.3708px; width: 120.979px; height: 152.176px;"><canvas></canvas></div><div class="smear-container" data-x="0.2573957055214724" data-y="0.29838496932515335" data-width="0.18555061349693253" data-height="0.20301226993865032" data-start-edge="top" data-speed="87" data-source-interval="823" data-pixel-size="3" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 167.822px; top: 194.547px; width: 120.979px; height: 132.364px;"><canvas></canvas></div><div class="smear-container" data-x="0.2573957055214724" data-y="0.5013987730061349" data-width="0.18555061349693253" data-height="0.045666411042944784" data-start-edge="left" data-speed="77" data-source-interval="530" data-pixel-size="6" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 167.822px; top: 326.912px; width: 120.979px; height: 29.7745px;"><canvas></canvas></div><div class="smear-container" data-x="0.2573957055214724" data-y="0.5470644171779141" data-width="0.18555061349693253" data-height="0.07304539877300613" data-start-edge="top" data-speed="66" data-source-interval="1928" data-pixel-size="1" data-color-fg="#FFFF00" data-color-bg="#000000" data-source-type="dots" style="left: 167.822px; top: 356.686px; width: 120.979px; height: 47.6256px;"><canvas></canvas></div><div class="smear-container" data-x="0.2573957055214724" data-y="0.6201104294478528" data-width="0.18555061349693253" data-height="0.216090490797546" data-start-edge="top" data-speed="93" data-source-interval="1718" data-pixel-size="1" data-color-fg="#FFFF00" data-color-bg="#000000" data-source-type="dots" style="left: 167.822px; top: 404.312px; width: 120.979px; height: 140.891px;"><canvas></canvas></div><div class="smear-container" data-x="0.2573957055214724" data-y="0.8362009202453987" data-width="0.18555061349693253" data-height="0.16379907975460123" data-start-edge="bottom" data-speed="46" data-source-interval="1813" data-pixel-size="5" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 167.822px; top: 545.203px; width: 120.979px; height: 106.797px;"><canvas></canvas></div><div class="smear-container" data-x="0.44294631901840487" data-y="0" data-width="0.040365337423312886" data-height="0.09197147239263805" data-start-edge="bottom" data-speed="96" data-source-interval="822" data-pixel-size="1" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 288.801px; top: 0px; width: 26.3182px; height: 59.9654px;"><canvas></canvas></div><div class="smear-container" data-x="0.44294631901840487" data-y="0.09197147239263805" data-width="0.040365337423312886" data-height="0.17137423312883437" data-start-edge="top" data-speed="47" data-source-interval="640" data-pixel-size="1" data-color-fg="#FFFF00" data-color-bg="#000000" data-source-type="dots" style="left: 288.801px; top: 59.9654px; width: 26.3182px; height: 111.736px;"><canvas></canvas></div><div class="smear-container" data-x="0.44294631901840487" data-y="0.2633466257668712" data-width="0.040365337423312886" data-height="0.022131901840490797" data-start-edge="right" data-speed="78" data-source-interval="1531" data-pixel-size="2" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 288.801px; top: 171.702px; width: 26.3182px; height: 14.43px;"><canvas></canvas></div><div class="smear-container" data-x="0.44294631901840487" data-y="0.285478527607362" data-width="0.040365337423312886" data-height="0.16240184049079753" data-start-edge="right" data-speed="41" data-source-interval="599" data-pixel-size="6" data-color-fg="#FFFF00" data-color-bg="#000000" data-source-type="dots" style="left: 288.801px; top: 186.132px; width: 26.3182px; height: 105.886px;"><canvas></canvas></div><div class="smear-container" data-x="0.44294631901840487" data-y="0.44788036809815945" data-width="0.040365337423312886" data-height="0.07035122699386503" data-start-edge="top" data-speed="44" data-source-interval="1454" data-pixel-size="6" data-color-fg="#FFFF00" data-color-bg="#000000" data-source-type="dots" style="left: 288.801px; top: 292.018px; width: 26.3182px; height: 45.869px;"><canvas></canvas></div><div class="smear-container" data-x="0.44294631901840487" data-y="0.5182315950920245" data-width="0.040365337423312886" data-height="0.044792331288343555" data-start-edge="right" data-speed="62" data-source-interval="561" data-pixel-size="1" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 288.801px; top: 337.887px; width: 26.3182px; height: 29.2046px;"><canvas></canvas></div><div class="smear-container" data-x="0.44294631901840487" data-y="0.5630245398773006" data-width="0.040365337423312886" data-height="0.16731134969325154" data-start-edge="top" data-speed="39" data-source-interval="1118" data-pixel-size="5" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 288.801px; top: 367.092px; width: 26.3182px; height: 109.087px;"><canvas></canvas></div><div class="smear-container" data-x="0.44294631901840487" data-y="0.7303358895705521" data-width="0.040365337423312886" data-height="0.06410015337423314" data-start-edge="right" data-speed="48" data-source-interval="1367" data-pixel-size="1" data-color-fg="#FFFF00" data-color-bg="#000000" data-source-type="dots" style="left: 288.801px; top: 476.179px; width: 26.3182px; height: 41.7933px;"><canvas></canvas></div><div class="smear-container" data-x="0.44294631901840487" data-y="0.7944355828220858" data-width="0.040365337423312886" data-height="0.1614340490797546" data-start-edge="right" data-speed="47" data-source-interval="1394" data-pixel-size="6" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 288.801px; top: 517.972px; width: 26.3182px; height: 105.255px;"><canvas></canvas></div><div class="smear-container" data-x="0.44294631901840487" data-y="0.9558696319018405" data-width="0.040365337423312886" data-height="0.044130674846625764" data-start-edge="top" data-speed="55" data-source-interval="1212" data-pixel-size="6" data-color-fg="#FFFF00" data-color-bg="#000000" data-source-type="dots" style="left: 288.801px; top: 623.227px; width: 26.3182px; height: 28.7732px;"><canvas></canvas></div><div class="smear-container" data-x="0.48331134969325157" data-y="0" data-width="0.13332668711656442" data-height="0.1985889570552147" data-start-edge="left" data-speed="45" data-source-interval="1902" data-pixel-size="3" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 315.119px; top: 0px; width: 86.929px; height: 129.48px;"><canvas></canvas></div><div class="smear-container" data-x="0.48331134969325157" data-y="0.1985889570552147" data-width="0.13332668711656442" data-height="0.41922852760736196" data-start-edge="bottom" data-speed="38" data-source-interval="1613" data-pixel-size="2" data-color-fg="#FFFF00" data-color-bg="#000000" data-source-type="dots" style="left: 315.119px; top: 129.48px; width: 86.929px; height: 273.337px;"><canvas></canvas></div><div class="smear-container" data-x="0.48331134969325157" data-y="0.6178174846625767" data-width="0.13332668711656442" data-height="0.12270536809815952" data-start-edge="right" data-speed="95" data-source-interval="1176" data-pixel-size="3" data-color-fg="#FFFF00" data-color-bg="#000000" data-source-type="dots" style="left: 315.119px; top: 402.817px; width: 86.929px; height: 80.0039px;"><canvas></canvas></div><div class="smear-container" data-x="0.48331134969325157" data-y="0.7405230061349694" data-width="0.13332668711656442" data-height="0.2594769938650307" data-start-edge="bottom" data-speed="52" data-source-interval="719" data-pixel-size="2" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 315.119px; top: 482.821px; width: 86.929px; height: 169.179px;"><canvas></canvas></div><div class="smear-container" data-x="0.616638036809816" data-y="0" data-width="0.19976380368098162" data-height="0.1449644171779141" data-start-edge="bottom" data-speed="36" data-source-interval="990" data-pixel-size="6" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 402.048px; top: 0px; width: 130.246px; height: 94.5168px;"><canvas></canvas></div><div class="smear-container" data-x="0.616638036809816" data-y="0.1449644171779141" data-width="0.19976380368098162" data-height="0.1264691717791411" data-start-edge="bottom" data-speed="91" data-source-interval="1251" data-pixel-size="3" data-color-fg="#FFFF00" data-color-bg="#000000" data-source-type="dots" style="left: 402.048px; top: 94.5168px; width: 130.246px; height: 82.4579px;"><canvas></canvas></div><div class="smear-container" data-x="0.616638036809816" data-y="0.2714340490797546" data-width="0.19976380368098162" data-height="0.12495015337423312" data-start-edge="right" data-speed="70" data-source-interval="1874" data-pixel-size="6" data-color-fg="#FFFF00" data-color-bg="#000000" data-source-type="dots" style="left: 402.048px; top: 176.975px; width: 130.246px; height: 81.4675px;"><canvas></canvas></div><div class="smear-container" data-x="0.616638036809816" data-y="0.3963834355828221" data-width="0.19976380368098162" data-height="0.08160030674846626" data-start-edge="left" data-speed="92" data-source-interval="755" data-pixel-size="5" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 402.048px; top: 258.442px; width: 130.246px; height: 53.2034px;"><canvas></canvas></div><div class="smear-container" data-x="0.616638036809816" data-y="0.47798466257668715" data-width="0.19976380368098162" data-height="0.1457222392638037" data-start-edge="right" data-speed="36" data-source-interval="1912" data-pixel-size="6" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 402.048px; top: 311.646px; width: 130.246px; height: 95.0109px;"><canvas></canvas></div><div class="smear-container" data-x="0.616638036809816" data-y="0.6237070552147239" data-width="0.19976380368098162" data-height="0.049105981595092024" data-start-edge="top" data-speed="47" data-source-interval="943" data-pixel-size="3" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 402.048px; top: 406.657px; width: 130.246px; height: 32.0171px;"><canvas></canvas></div><div class="smear-container" data-x="0.616638036809816" data-y="0.6728128834355828" data-width="0.19976380368098162" data-height="0.1269756134969325" data-start-edge="right" data-speed="35" data-source-interval="1263" data-pixel-size="1" data-color-fg="#FFFF00" data-color-bg="#000000" data-source-type="dots" style="left: 402.048px; top: 438.674px; width: 130.246px; height: 82.7881px;"><canvas></canvas></div><div class="smear-container" data-x="0.616638036809816" data-y="0.7997883435582822" data-width="0.19976380368098162" data-height="0.02351993865030675" data-start-edge="bottom" data-speed="69" data-source-interval="534" data-pixel-size="2" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 402.048px; top: 521.462px; width: 130.246px; height: 15.335px;"><canvas></canvas></div><div class="smear-container" data-x="0.616638036809816" data-y="0.823308282208589" data-width="0.19976380368098162" data-height="0.08364693251533742" data-start-edge="left" data-speed="55" data-source-interval="815" data-pixel-size="1" data-color-fg="#FFFF00" data-color-bg="#000000" data-source-type="dots" style="left: 402.048px; top: 536.797px; width: 130.246px; height: 54.5378px;"><canvas></canvas></div><div class="smear-container" data-x="0.616638036809816" data-y="0.9069555214723927" data-width="0.19976380368098162" data-height="0.09304493865030675" data-start-edge="right" data-speed="42" data-source-interval="1646" data-pixel-size="1" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 402.048px; top: 591.335px; width: 130.246px; height: 60.6653px;"><canvas></canvas></div><div class="smear-container" data-x="0.8164018404907976" data-y="0" data-width="0.18359815950920247" data-height="0.037021625766871166" data-start-edge="bottom" data-speed="98" data-source-interval="962" data-pixel-size="5" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 532.294px; top: 0px; width: 119.706px; height: 24.1381px;"><canvas></canvas></div><div class="smear-container" data-x="0.8164018404907976" data-y="0.037021625766871166" data-width="0.18359815950920247" data-height="0.0348532208588957" data-start-edge="left" data-speed="93" data-source-interval="527" data-pixel-size="2" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 532.294px; top: 24.1381px; width: 119.706px; height: 22.7243px;"><canvas></canvas></div><div class="smear-container" data-x="0.8164018404907976" data-y="0.07187484662576687" data-width="0.18359815950920247" data-height="0.13058803680981595" data-start-edge="top" data-speed="25" data-source-interval="1718" data-pixel-size="5" data-color-fg="#FFFF00" data-color-bg="#000000" data-source-type="dots" style="left: 532.294px; top: 46.8624px; width: 119.706px; height: 85.1434px;"><canvas></canvas></div><div class="smear-container" data-x="0.8164018404907976" data-y="0.20246319018404907" data-width="0.18359815950920247" data-height="0.05281733128834356" data-start-edge="bottom" data-speed="30" data-source-interval="536" data-pixel-size="5" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 532.294px; top: 132.006px; width: 119.706px; height: 34.4369px;"><canvas></canvas></div><div class="smear-container" data-x="0.8164018404907976" data-y="0.2552806748466258" data-width="0.18359815950920247" data-height="0.08331472392638037" data-start-edge="bottom" data-speed="33" data-source-interval="1130" data-pixel-size="6" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 532.294px; top: 166.443px; width: 119.706px; height: 54.3212px;"><canvas></canvas></div><div class="smear-container" data-x="0.8164018404907976" data-y="0.3385950920245399" data-width="0.18359815950920247" data-height="0.1446553680981595" data-start-edge="bottom" data-speed="41" data-source-interval="1046" data-pixel-size="5" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 532.294px; top: 220.764px; width: 119.706px; height: 94.3153px;"><canvas></canvas></div><div class="smear-container" data-x="0.8164018404907976" data-y="0.48325" data-width="0.18359815950920247" data-height="0.027403527607361963" data-start-edge="right" data-speed="74" data-source-interval="758" data-pixel-size="4" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 532.294px; top: 315.079px; width: 119.706px; height: 17.8671px;"><canvas></canvas></div><div class="smear-container" data-x="0.8164018404907976" data-y="0.5106533742331288" data-width="0.18359815950920247" data-height="0.13679585889570553" data-start-edge="left" data-speed="25" data-source-interval="832" data-pixel-size="1" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 532.294px; top: 332.946px; width: 119.706px; height: 89.1909px;"><canvas></canvas></div><div class="smear-container" data-x="0.8164018404907976" data-y="0.6474493865030675" data-width="0.18359815950920247" data-height="0.08463972392638036" data-start-edge="right" data-speed="42" data-source-interval="1534" data-pixel-size="2" data-color-fg="#FFFF00" data-color-bg="#000000" data-source-type="dots" style="left: 532.294px; top: 422.137px; width: 119.706px; height: 55.1851px;"><canvas></canvas></div><div class="smear-container" data-x="0.8164018404907976" data-y="0.7320889570552147" data-width="0.18359815950920247" data-height="0.016112423312883435" data-start-edge="right" data-speed="59" data-source-interval="1743" data-pixel-size="2" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 532.294px; top: 477.322px; width: 119.706px; height: 10.5053px;"><canvas></canvas></div><div class="smear-container" data-x="0.8164018404907976" data-y="0.74820245398773" data-width="0.18359815950920247" data-height="0.1270187116564417" data-start-edge="left" data-speed="79" data-source-interval="1147" data-pixel-size="6" data-color-fg="#FFFFFF" data-color-bg="#000000" data-source-type="dots" style="left: 532.294px; top: 487.828px; width: 119.706px; height: 82.8162px;"><canvas></canvas></div><div class="smear-container" data-x="0.8164018404907976" data-y="0.8752208588957056" data-width="0.18359815950920247" data-height="0.12477944785276074" data-start-edge="left" data-speed="87" data-source-interval="651" data-pixel-size="6" data-color-fg="#FFFF00" data-color-bg="#000000" data-source-type="dots" style="left: 532.294px; top: 570.644px; width: 119.706px; height: 81.3562px;"><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>