0x316042d3…fbe8sent to0x99a9b7c1…b069·#16,475,939·view on Etherscan
async function drawDot(t){allDots++,allDots%2e4==0&&await timeout(0),point(t.x,t.y)}function timeout(t){return new Promise(i=>setTimeout(i,t))}async function burn(t,i,e=7){blendMode(BURN),fill(30,30,90,e),noStroke(),circle(t.x,t.y,i*R.random(.4,1)),blendMode(BLEND)}async function dodge(t,i,e=7){blendMode(DODGE),fill(150,150,100,3),noStroke();for(let r=0;r<e;r++)circle(t.x+R.random(-i/2,i/2),t.y+R.random(-i/2,i/2),i*R.random(.4,1));blendMode(BLEND)}function getPointOnEllipse(t,i,e){return createVector(.5*t*cos(e),.5*i*sin(e))}function getEllipse(t,i,e=1,r=0,s=360){const a=[];for(let o=r;o<s;o+=e)a.push(getPointOnEllipse(t,i,o));return a}function toCrv(t){t.push(t[t.length-1]),t.splice(0,0,t[0]);const i=[];for(let e=0;e<t.length-3;e++){const r=t[e+1],s=t[e+2],a=p5.Vector.dist(r,s);for(let r=0;r<a;r++)x=curvePoint(t[e].x,t[e+1].x,t[e+2].x,t[e+3].x,r/a),y=curvePoint(t[e].y,t[e+1].y,t[e+2].y,t[e+3].y,r/a),i.push(createVector(x,y))}return i}function crvLength(t){l=0;for(let i=0;i<t.length-1;i++)l+=p5.Vector.dist(t[i],t[i+1]);return l}function placeOnCurve(t,i){let e=0;for(let r=0;r<t.length-1;r++)if(e+=sqrt((t[r].x-t[r+1].x)**2+(t[r].y-t[r+1].y)**2),e>=i)return t[r];return!1}function curveCrawler(t){this.crv=t,this.l=0,this.i=0,this.totalLength=crvLength(t),this.findPlace=(t=>{for(;this.i<this.crv.length-1;)if(this.l+=sqrt((this.crv[this.i].x-this.crv[this.i+1].x)**2+(this.crv[this.i].y-this.crv[this.i+1].y)**2),this.i++,this.l>=t)return this.crv[this.i];return!1})}function inCanvas(t){return t.x>0&&t.x<baseWidth&&t.y>0&&t.y<baseHeight}class Random{constructor(){this.useA=!1,this.sfc32=function(t){let i=parseInt(t.substr(0,8),16),e=parseInt(t.substr(8,8),16),r=parseInt(t.substr(16,8),16),s=parseInt(t.substr(24,8),16);return function(){i|=0,e|=0,r|=0,s|=0;let t=(i+e|0)+s|0;return s=s+1|0,i=e^e>>>9,e=r+(r<<3)|0,r=r<<21|r>>>11,r=r+t|0,(t>>>0)/4294967296}},this.prngA=new this.sfc32(tokenData.hash.substr(2,32)),this.prngB=new this.sfc32(tokenData.hash.substr(34,32));for(let t=0;t<1e6;t+=2)this.prngA(),this.prngB()}reset(t){this.prngA=new this.sfc32(tokenData.hash.substr(2,32)),this.prngB=new this.sfc32(tokenData.hash.substr(34,32));for(let t=0;t<1e6;t+=2)this.prngA(),this.prngB();for(let i=0;i<t;i++)this.random_dec()}random_dec(){return this.usage++,this.useA=!this.useA,this.useA?this.prngA():this.prngB()}random_num(t,i){return t+(i-t)*this.random_dec()}random_int(t,i){return Math.floor(this.random_num(t,i+1))}random_choice(t){return t[this.random_int(0,t.length-1)]}random(t=1,i=0){return this.random_num(t,i)}random_in(t){return this.random_num(t[0],t[1])}}let R=new Random;p5.Color.prototype.toRGB=function(){return color(red(this),green(this),blue(this),alpha(this))},Array.prototype.rotate=function(){return this.push(this.shift()),this[0]};const v=(t,i)=>createVector(t,i),v_rel=(t,i)=>createVector(t*baseWidth,i*baseHeight),vlerp=p5.Vector.lerp,vdist=p5.Vector.dist;vadd=p5.Vector.add,vsub=p5.Vector.sub;let allDots=0;warpSpacingMinMax=[.8,2],weftSpacingMinMax=[.8,1],startOffset=[2,1,0],patternTop=[2],patternBottom=[1];class Denim{constructor(t,i,e=.5){this.lp=t,this.color=i,this.visibleWhite=R.random(.5,1),this.darkness=R.random(.3),this.noiseScale=R.random(200,400),this.warpExtensions=[15,40],this.extendChance=.5,this.age=e,this.rotation=0,this.ripNoiseZ=R.random(1e3),this.ripThreshold=R.random(.18,.25),this.ripMin=R.random(50,100)*initialThreadSize,this.ripMax=R.random(this.ripMin,160)*initialThreadSize,this.ripExtendMasks=[]}rotate(t){return this.rotation=t,this}calc(){return this.ripThreshold+=.3*globalAge,this.age+=globalAge,this.ripMin-=30*globalAge,this.ripMax-=70*globalAge,this.warp||this.makeWarp(),this.weft||this.makeWeft(),this.trim(),this}async draw(t={}){threadSize=initialThreadSize,await this.drawWarp(),await this.drawWeft(t.colorFunc),await this.lp.drawStitches(this),t.dontFringe||await this.extendWarps()}async finishDraw(){this.hasRips&&await this.drawRips()}makeWarp(){const t=this.lp.rotatedContainingSquare(this.rotation),{pos:i,w:e,h:r,rotation:s}=t.getDimension(),a=p5.Vector.fromAngle(radians(s)).setMag(e),o=a.copy().rotate(PI/2).normalize(),n=5*initialThreadSize,h=i.copy().add(o.copy().setMag(n).mult(-1)),l=h.copy().add(a).add(),p=15,c=Array(p).fill(0).map((t,i)=>vlerp(h,l,i/(p-1)));c.forEach(t=>t.add(o.copy().mult(R.random(-n,n)))),this.warp=[c];let d=!0;for(;d;){const t=this.warp[this.warp.length-1],i=t.map(t=>t.copy());i.forEach(t=>t.add(o.copy().mult(threadSize*R.random(warpSpacingMinMax[0],warpSpacingMinMax[1])))),this.warp.push(i),d=!1,i.forEach((t,i)=>{vdist(t,c[i])<r&&(d=!0)})}this.warp=this.warp.map(t=>toCrv(t))}async drawWarp(){let t=0;threadSize=initialThreadSize/2;for(const i of this.warp){const e=lerpColor(color(warpColors[0]),color(warpColors[1]),R.random_dec());await thread(i,e,5),t++%10==0&&await timeout(0)}}async extendWarps(){for(const t of this.warp){if(R.random_dec()<this.extendChance){const i=vsub(t[0],t[1]);await franzim(t[0],i,threadSize*R.random_in(this.warpExtensions))}if(R.random_dec()<this.extendChance){const i=vsub(t[t.length-1],t[t.length-2]);await franzim(t[t.length-1],i,threadSize*R.random_in(this.warpExtensions))}await timeout(0)}}makeWeft(){threadSize=initialThreadSize,this.weft=[{column:this.warp.map(t=>t[0]),threadSize:threadSize}];const t=crvLength(this.warp.reduce((t,i)=>crvLength(t)>crvLength(i)?t:i)),i=this.warp.map(t=>new curveCrawler(t));for(let e=0;e<t;e+=threadSize*R.random_in(weftSpacingMinMax))this.weft.push({column:i.map(t=>t.findPlace(e)).filter(t=>0!=t),threadSize:threadSize}),threadSize=initialThreadSize*R.random(1,1.2);const e=color(this.color),r=lerpColor(e,color(255),this.visibleWhite);this.weft=this.weft.map(t=>{const i=[],s=[e,r];for(let t=0;t<startOffset[0]-1;t++)s.rotate();for(let e=startOffset.rotate();e<t.column.length;e+=patternBottom.rotate()){let r=t.column.slice(e,e+patternTop.rotate()+1);e+=patternTop[0];let a=s.rotate();a=lerpColor(a,color(0),noise(r[0].x/this.noiseScale,r[0].y/this.noiseScale)*this.darkness),i.push(new Loop(r,a,t.threadSize))}return i})}async drawWeft(t){let i=0;for(const e of this.weft){for(const i of e)i.applyColorFunc(t),await i.draw();i++%10==0&&await timeout(0)}}hasWeftOn(t){for(const i of this.weft)for(const e of i)for(const i of e.ps)if(i&&vdist(t,i)<5)return e;return!1}trim(){this.warp=this.warp.map(t=>t.filter(t=>this.lp.pointInPattern(t))),this.warp=this.warp.filter(t=>t.length>1),this.weft=this.weft.map(t=>t.filter(t=>t.ps.filter(t=>this.lp.pointInPattern(t)).length>1)),this.warp=this.warp.map(t=>t.filter(t=>t.x>=.1*-baseWidth&&t.x<=1.1*baseWidth&&t.y>=.1*-baseHeight&&t.y<=1.1*baseHeight))}unravel(){this.weft.forEach(t=>{t.length>4&&(t[0].ps.forEach(t=>t.add(threadSize*R.random(-.3,.3),threadSize*R.random(-.3,.3))),t[t.length-1].ps.forEach(t=>t.add(threadSize*R.random(-.3,.3),threadSize*R.random(-.3,.3))))})}pointInRip(t){return noise(ripNoiseScale[0]*t.x/baseWidth,ripNoiseScale[1]*t.y/baseHeight,this.ripNoiseZ)<this.ripThreshold}makeRips(){this.warpRips=[],this.weftRips=[];for(let t=0;t<this.warp.length;t++){const i=this.warp[t];let e=[];if(0!=i.length)for(let t=0;t<200;t++){const r=i[floor(i.length*t/200)];if(this.pointInRip(r))e.push(t);else{if(e.length>2){const t=e.map(t=>floor(t*i.length/200)),r=t.map(t=>i[t]),s=crvLength(r),a=r[0].copy(),o=r[1].copy(),n=r[r.length-1].copy(),h=r[r.length-2].copy(),l=vsub(a,o).rotate(90);if(s>this.ripMin&&s<this.ripMax){let e=[];const r=ceil(s/10);for(let t=0;t<=r;t++){const i=vlerp(a,n,t/r),s=40*noise(i.x/50,i.y/50)-20;e.push(i.add(l.copy().setMag(s)))}e=toCrv(e),i.splice(t[0],t[t.length-1]-t[0],...e)}s>this.ripMax&&(this.warpRips.push({pos:a,dir:vsub(o,a),len:s*R.random(.1,.5)}),this.warpRips.push({pos:n,dir:vsub(h,n),len:s*R.random(.1,.5)}),i.splice(t[0],t[t.length-1]-t[0]))}e=[]}}}let t=!0;return this.weft.forEach(i=>i.forEach((i,e)=>{const r=i.ps.filter(t=>!this.pointInRip(t)).length>0;if(r&&t||!r&&!t){let e=i.ps.filter(t=>null!=t)[0],s=vsub(i.ps[1],i.ps[0]);r?e.add(s):e.sub(s),this.weftRips.push({pos:e,dir:t?i.dir().mult(-1):i.dir()}),t=!t}})),this.weft.forEach(t=>t.forEach(t=>t.ps=t.ps.filter(t=>!this.pointInRip(t)))),this.hasRips=!0,this}async drawRips(){let t=0;for(const i of this.warpRips)await franzim(i.pos,i.dir,i.len,.6),t++%10==0&&await timeout(0);threadSize=initialThreadSize;let i=0;this.weftRips=this.weftRips.filter(t=>R.random_dec()<.7);for(const t of this.weftRips){let e=!1;for(const i of this.ripExtendMasks)i.hasWeftOn(t.pos)&&(e=!0);if(e)continue;let r=color(this.color);this.weft.forEach(i=>i.forEach(i=>i.ps.forEach(e=>{e&&vdist(e,t.pos)<10&&(r=i.getFinalColor())}))),r.setAlpha(50);let s=[t.pos.copy(),t.pos.copy()];const a=R.random_int(1,4);for(let e=1;e<4;e++){const o=t.dir.setMag(4*globalScale);for(let t=0;t<e*a;t++)o.rotate(R.random(-35,35)),s.push(s[s.length-1].copy().add(o));await thread(s,r,10,20),i++%30==0&&await timeout(0)}}}doAge(){floor(this.weft.length/2);this.weft.forEach((t,i)=>{for(let i=0;i<t.length;i++){const e=t[i].ps[0],r=1-dist(e.x,e.y,baseWidth/2,baseHeight/2)/(baseHeight/2);t[i].age=r*this.age/2,t[i].yellow=r*this.age/2}})}dropShadowOn(t){for(const i of t)this.lp.dropShadowOn(i)}foldedStitchings(){const t=this.lp,i=createGraphics(baseWidth,baseHeight);i.noStroke();const e=new LayoutPattern2(t.ps);if(i.fill(0,20),e.crv().forEach(t=>i.circle(t.x,t.y,R.random(10)*initialThreadSize)),2==t.stitchPlaces.length){let r=0;e.ps=t.getOffset(18),e.crv().forEach((t,e)=>{r+=R.random(15);const s=(sin(r)+1)/2;i.fill(150*s,100),i.circle(t.x,t.y,R.random(4,25)*initialThreadSize)})}i.fill(0,20);for(const r of t.stitchPlaces)e.ps=t.getOffset(r),e.crv().forEach(t=>i.circle(t.x,t.y,R.random(7))*initialThreadSize);return this.weft.forEach(t=>{t.forEach(t=>{if(t.ps.length>0){const e=t.ps[0],r=i.get(e.x,e.y);alpha(r)>0&&(t.age=brightness(r)/360*(alpha(r)/255),t.yellow&&(t.yellow=0),t.darkness=.4-brightness(r)/360*(alpha(r)/255)*.4)}})}),t.withStitches=!0,this}}