0x3160…fbe8

All memos sent from and to 0x3160…fbe8.

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
const vert=` attribute vec3 aPosition; attribute vec2 aTexCoord; varying vec2 vTexCoord; void main() { vTexCoord = aTexCoord; vec4 positionVec4 = vec4(aPosition, 1.0); positionVec4.xy = positionVec4.xy * 2.0 - 1.0; gl_Position = positionVec4; } `;const fragSwirl=` precision mediump float; #define PI 3.1415926535897932384626433832795 varying vec2 vTexCoord; uniform sampler2D texture; uniform vec2 resolution; uniform vec2 pos; uniform float radius; uniform float strength; vec2 rotate(vec2 v, float a) { float s = sin(a / 180.0 * PI); float c = cos(a / 180.0 * PI); mat2 m = mat2(c, -s, s, c); return m * v; } float easeOutQuad(float t) { return t * (2.0 - t); } void main() { vec2 pixel = vTexCoord * resolution; vec4 origTex = texture2D(texture,vTexCoord); float dist = distance(pixel, pos); if (dist > radius) { gl_FragColor = origTex; return; } float rotation = strength * (1. - easeOutQuad(dist / radius)); vec2 relPos = rotate(pixel - pos, rotation); vec2 p2 = pos + relPos; p2.x = clamp(p2.x, 0.0, resolution.x); p2.y = clamp(p2.y, 0.0, resolution.y); vec4 col = texture2D(texture, p2/resolution); gl_FragColor = col; } `;const fragVoronoi=` precision mediump float; varying vec2 vTexCoord; uniform vec2 resolution; uniform float seed; uniform float scale; vec2 hash22(vec2 p) { return fract(vec2(262144, 32768)*sin(dot(p, vec2(41. + seed, 289. + seed)))); } float smin(float a, float b, float k){ float h = clamp(.5 + .5*(b - a)/k, 0., 1.); return mix(b, a, h) - k*h*(1. - h); } float smin2(float a, float b, float r){ float f = max(0., 1. - abs(b - a)/r);return min(a, b) - r*.25*f*f;} float sminExp(float a, float b, float k){ return -log(exp(-k*a) + exp(-k*b))/k; } float Voronoi(in vec2 p){vec2 g = floor(p), o; p -= g;vec3 d = vec3(8.);for(int j = -1; j < 2; j++){for(int i = -1; i < 2; i++){o = vec2(i, j);o += hash22(g + o) - p;d.z = length(o); d.y = max(d.x, smin(d.y, d.z, .4));d.x = smin(d.x, d.z, .2);}} return d.y - d.x; } void main(){vec2 uv = vTexCoord.xy * .5; uv.y *= .5;gl_FragColor = vec4(sqrt(vec3(Voronoi(uv*(.5 + length(uv)*1.3) * scale*5.))), 1.);} `;let scaler;const ms=x=>scaler*x;const rs=(a,b)=>scaler*R(a,b);function createHeightMap(){let c_map=createGraphics(round(height),round(height/2));c_map.background(R(50,120));const mapSize=V(c_map.width,c_map.height);scaler=mapSize.x/100;const mapType=R3([0,0,0,0,1,1,1,1,2,2,2,3]);print(mapType);if(mapType==0||mapType==1){const pathCreator=new PathCreator(mapSize.x,mapSize.y);const pointGenerator=new PointGenerator(mapSize.x,mapSize.y);const painter=new Painter(c_map);if(mapType==0){const sumCircles=R(100,1e3);const options=Array(4).fill(0).map((_,i)=>R3([0,1,2]));for(let i=0;i<sumCircles;i++){const ct=R3(options);const pt=pointGenerator.getPoint();if(ct==0)painter.drawCircle(pt,rs(1,10));if(ct==1)painter.hole(pt,rs(.5,4));if(ct==2)painter.crater(pt,rs(.5,4))}}else if(mapType==1){const numLines=R(200,800);for(let i=0;i<numLines;i++){path=pathCreator.createPath(pointGenerator.getPoint());painter.drawLine(path)}}}else if(mapType==2){c_map.loadPixels();const ratioNoiseScale=R(10);const ratioForce=R(5);const noiseScale=R(2,6);for(let y=0;y<mapSize.y;y++){const percY=y/mapSize.y;for(let x=0;x<mapSize.x;x++){const percX=x/mapSize.x;const ratio=noise(percX*ratioNoiseScale,percY*ratioNoiseScale);const noiseScaleX=noiseScale+ratioForce*ratio;const noiseScaleY=noiseScale+ratioForce/ratio;const n=noise(noiseScaleX*percX,noiseScaleY*percY);c_map.set(x,y,n*255)}}c_map.updatePixels()}else if(mapType==3){initShaderGraphics(c_map,false,true);shaderGraphics.noStroke();shaderGraphics.shader(voronoiShader);voronoiShader.setUniform("resolution",[c_map.width,c_map.height]);voronoiShader.setUniform("seed",R(1e3));voronoiShader.setUniform("scale",R(.4,7));shaderGraphics.rect(0,0,c_map.width,c_map.height);c_map.image(shaderGraphics,0,0,c_map.width,c_map.height)}RANDOM.reset();for(let i=1;i<4;i++){const deformType=R3([0,1,2,2]);if(deformType==0)c_map=swirl(c_map,V(R(mapSize.x),R(mapSize.y)),ms(60),R(mapSize.x/4));if(deformType==1)c_map=smear(c_map,rs(4,16),rs(2,6))}const sumAmmonites=R()<.8?0:R(2,5);for(let i=0;i<sumAmmonites;i++)ammonite(c_map,V(R(mapSize.x),R(mapSize.y)),rs(1,5));const sumBushes=R()<.4?0:R(2,5);for(let i=0;i<sumBushes;i++)bush(c_map,V(R(mapSize.x),R(mapSize.y)),rs(1,5));c_map.loadPixels();return c_map}class Painter{constructor(img){this.img=img;this.clrthr=R()*R();this.fllthr=constrain(R()<.5?R()*R():1-R()*R(),.1,.9)}getColor=()=>R()<this.clrthr?0:255;getFill=()=>R()>this.fllthr;getAlpha=()=>R(100,255);getBlur=()=>rs(0,3);drawPath(path,offset=V(0,0)){this.img.beginShape();for(let i=0;i<path.length;i++){const pos=path[i];this.img.vertex(pos.x+offset.x,pos.y+offset.y)}this.img.endShape()}drawLine(path){if(this.getFill()){this.img.noStroke();this.img.fill(this.getColor(),this.getAlpha())}else{this.img.stroke(this.getColor(),this.getAlpha());this.img.strokeWeight(rs(0,1));this.img.noFill()}this.img.drawingContext.filter=`blur(${this.getBlur()}px)`;this.drawPath(path)}drawCircle(pos,r){let shape=[];for(let a=0;a<360;a+=10){shape.push(V(pos.x+r*cos(a),pos.y+r*sin(a)))}shape=toCrv(shape);this.drawLine(shape)}hole(pos,r){this.img.fill(0,100);this.img.drawingContext.filter=`blur(${r*R(.5,1.5)}px)`;this.img.circle(pos.x,pos.y,r);this.img.circle(pos.x,pos.y,r/2)}crater(pos,r){let shape=[];for(let a=0;a<360;a+=30){const shapePos=angleVec(a,r);const n=noise(shapePos.x,shapePos.y)+.5;shapePos.mult(n).add(pos);shape.push(shapePos)}shape=toCrv(shape);this.img.noStroke();this.img.drawingContext.filter=`blur(${rs(1,4)}px)`;this.img.fill(255,R(100,255));this.drawPath(shape,V(ms(2),ms(2)));this.img.fill(0,R(100,255));this.drawPath(shape)}}let shaderGraphics,shaderResultGraphics,swirlShader,voronoiShader;function initShaderGraphics(img,initSwirlShader=false,initVoronoiShader=false){if(!shaderGraphics)shaderGraphics=createGraphics(img.width,img.height,WEBGL);if(!shaderResultGraphics)shaderResultGraphics=createGraphics(img.width,img.height);if(initSwirlShader&&!swirlShader)swirlShader=shaderGraphics.createShader(vert,fragSwirl);if(initVoronoiShader&&!voronoiShader)voronoiShader=shaderGraphics.createShader(vert,fragVoronoi)}function swirl(img,pos,ammount,r){initShaderGraphics(img,true,false);shaderGraphics.noStroke();shaderGraphics.shader(swirlShader);swirlShader.setUniform("texture",img);swirlShader.setUniform("resolution",[img.width,img.height]);swirlShader.setUniform("pos",[pos.x,pos.y]);swirlShader.setUniform("strength",ammount);swirlShader.setUniform("radius",r);shaderGraphics.rect(0,0,img.width,img.height);shaderResultGraphics.image(shaderGraphics,0,0,shaderResultGraphics.width,shaderResultGraphics.height);return shaderResultGraphics}function smear(img,strength,r){const p1=V(R(img.width),R(img.height));const p2=V(R(img.width),R(img.height));const middle=vadd(p1,p2).div(2);const dir=vsub(p2,p1).rotate(90).normalize(R(-500,500)*PS);const center=vadd(middle,dir);const angleStart=(vsub(p1,center).heading()+360)%360;const angleEnd=(vsub(p2,center).heading()+360)%360;const angleA=min(angleStart,angleEnd);const angleB=max(angleStart,angleEnd);const radius=vsub(p1,center).mag();func=pos=>{const rel=vsub(pos,center);const heading=(rel.heading()+360)%360;if(heading<=angleB&&heading>=angleA){const distToEdge=max(heading-angleA,angleB-heading);const relStrength=1-distToEdge/(angleB-angleA);return[abs(vsub(pos,center).mag()-radius),relStrength]}return[1e3,0]};smearFunc=(pos,strength)=>vsub(pos,center).rotate(strength).add(center);const c=createGraphics(img.width,img.height);c.image(img,0,0);c.loadPixels();for(let x=0;x<c.width;x++){for(let y=0;y<c.height;y++){const mapPos=V(x,y);const[d,relativeStrength]=func(mapPos);if(d>r)continue;const relativeStrength2=(1-easeOutQuad(d/r))*strength;const p2=smearFunc(mapPos,relativeStrength2*relativeStrength);const c2=c.get(constrain(p2.x,0,c.width-1),constrain(p2.y,0,c.height-1));c.set(x,y,c2)}}c.updatePixels();return c}function ammonite(img,pos,maxr){const c=createGraphics(img.width,img.height);c.strokeWeight(4);const revolutions=R(2,5);let spiralPath=[];for(let r=0;r<maxr;r+=1.5){const a=map(r,0,maxr,0,360*revolutions);const p=angleVec(a,r);spiralPath.push(vadd(p,pos))}spiralPath=toCrv(spiralPath);const rl=spiralPath.length/(revolutions*3);for(let i=0;i<spiralPath.length;i++){const pathPoint=spiralPath[i];const normal=vsub(pathPoint,pos).normalize();const d=maxr;for(let j=0;j<=d;j+=1){const newPos=vadd(pathPoint,vmul(normal,j));const roundVal=sin(180*j/d);const ridgeVal=1-sin(180*(i%rl)/rl);c.stroke(50+ridgeVal*roundVal*200,100);c.line(newPos.x,newPos.y,newPos.x,newPos.y)}}img.image(c,0,0);img.resetMatrix()}function bush(img,pos,r){const bushImg=createGraphics(img.width,img.height);bushImg.translate(pos.x,pos.y);for(let i=0;i<200;i++){const rot_z=R(180);const rot=R(360);const d=cos(rot_z)*r;const p2=angleVec(rot,d);for(let j=0;j<d;j++){const x=p2.x/d*j;const y=p2.y/d*j;const val=j/d;bushImg.stroke(255,val*255);bushImg.line(x,y,x,y)}}img.image(bushImg,0,0)}class PathCreator{constructor(w,h,pathType){if(!pathType)pathType=R3(Object.values(PathCreator.pathTypes));this.w=w;this.h=h;this.pathType=pathType;this.segmentLength=this.w*R(.001,.01);this.pathLengths=R3([null,R(50,300)]);this.pathType.init(this)}createPath(startingPoint){this.pathType.initPath(this);let pos=this.pathType.getStartingPoint(this)||startingPoint||V(R(this.w),R(this.h));const path=[];const l=this.pathLengths||R(50,300);while(path.length<l){const dir=this.pathType.getDirection(this,pos);pos=pos.add(dir);path.push(pos.copy())}const crv=toCrv(path);return crv}static pathTypes={noiseField:{name:"noise field",init:pathCreator=>pathCreator.noiseScale=pathCreator.w*R(.02,.2),initPath:()=>{},getStartingPoint:()=>{},getDirection:(pathCreator,pos)=>{const n=noise(1e3+pos.x/pathCreator.noiseScale,1e3+pos.y/pathCreator.noiseScale);return angleVec(n*360,R(pathCreator.segmentLength))}},randomWalker:{name:"random walker",init:()=>{},initPath:()=>{},getStartingPoint:()=>{},getDirection:(pathCreator,pos)=>angleVec(R(360),pathCreator.segmentLength*R(10))},straightLines:{name:"straight lines",init:()=>{},initPath:pathCreator=>pathCreator.direction=R(360),getStartingPoint:()=>{},getDirection:(pathCreator,pos)=>angleVec(pathCreator.direction,R(pathCreator.segmentLength))},outwards:{name:"outwards",init:pc=>{pc.center=V(R(pc.w),R(pc.h));pc.pathLengths=pc.w},initPath:pc=>{pc.angle=R(360);if(R()<.01)pc.center=V(R(pc.w),R(pc.h))},getStartingPoint:pc=>pc.center.copy(),getDirection:(pc,pos)=>{if(vdist(pos,pc.center)>pc.w/4)pc.angle+=R(-2,2);return angleVec(pc.angle,R(pc.segmentLength))}}}}class PointGenerator{constructor(w,h,generatorType,data){this.generatorType=generatorType||R3(Object.values(PointGenerator.gts));this.w=w;this.h=h;this.generatorType.init(this);if(data)this.data=data}getPoint(){return this.generatorType.getPoint(this)}static gts={random:{name:"random",init:()=>{},getPoint:pg=>V(pg.w*R(),pg.h*R())},grid:{name:"grid",init:pg=>{pg.data=pg.w*R(.02,.1)},getPoint:pg=>{let y=R2(0,pg.h/pg.data);let x=R2(0,pg.w/pg.data);return V(x*pg.data,y*pg.data)}},hexGrid:{name:"hex grid",init:pg=>{pg.data=pg.w*R(.02,.1)},getPoint:pg=>{let y=R2(0,pg.h/pg.data);let x=R2(0,pg.w/pg.data);if(y%2==0)x-=.5;return V(x*pg.data,y*pg.data)}},distribution:{name:"distribution",init:pg=>{pg.data=pg.w*R(.1,.5);pg.points=[]},getPoint:pg=>{if(pg.points.length==0){pg.points.push(V(R(pg.w),R(pg.h)));return pg.points[0]}let tries=0;while(tries<100){const pos=V(R(pg.w),R(pg.h));for(const pos2 of pg.points){if(vdist(pos,pos2)<pg.data){tries++;continue}}pg.points.push(pos);return pos}}}}}
class Random{constructor(){this.usage=0;this.useA=false;this.sfc32=function(uint128Hex){let a=parseInt(uint128Hex.substr(0,8),16);let b=parseInt(uint128Hex.substr(8,8),16);let c=parseInt(uint128Hex.substr(16,8),16);let d=parseInt(uint128Hex.substr(24,8),16);return function(){a|=0;b|=0;c|=0;d|=0;let t=(a+b|0)+d|0;d=d+1|0;a=b^b>>>9;b=c+(c<<3)|0;c=c<<21|c>>>11;c=c+t|0;return(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 i=0;i<1e6;i+=2){this.prngA();this.prngB()}}reset(times){this.prngA=new this.sfc32(tokenData.hash.substr(2,32));this.prngB=new this.sfc32(tokenData.hash.substr(34,32));for(let i=0;i<1e6;i+=2){this.prngA();this.prngB()}for(let i=0;i<times;i++){this.random_dec()}}random_dec(){this.usage++;this.useA=!this.useA;return this.useA?this.prngA():this.prngB()}random_num(a,b){return a+(b-a)*this.random_dec()}random_int(a,b){return Math.floor(this.random_num(a,b+1))}random_choice(list){return list[this.random_int(0,list.length-1)]}random(a=1,b=0){return this.random_num(a,b)}}const RANDOM=new Random;function timeout(ms){return new Promise(resolve=>setTimeout(resolve,ms))}function toCrv(crv){crv.push(crv[crv.length-1]);crv.splice(0,0,crv[0]);const newCrv=[];for(let i=0;i<crv.length-3;i++){const nextP=crv[i+1];const nextnextP=crv[i+2];const l=vdist(nextP,nextnextP);for(let t=0;t<l;t++){x=curvePoint(crv[i].x,crv[i+1].x,crv[i+2].x,crv[i+3].x,t/l);y=curvePoint(crv[i].y,crv[i+1].y,crv[i+2].y,crv[i+3].y,t/l);newCrv.push(v(x,y))}}return newCrv}const v=(x,y)=>createVector(x,y),vdist=p5.Vector.dist;vadd=p5.Vector.add,vmul=p5.Vector.mult,vsub=p5.Vector.sub;const angleVec=(a,d)=>v(cos(a)*d,sin(a)*d);const R=(a=1,b=0)=>RANDOM.random(a,b);const R2=(a=1,b=0)=>Math.floor(R(a,b+1));const R3=arr=>arr[Math.floor(R(arr.length))];const easeInOutExpo=x=>x===0?0:x===1?1:x<.5?pow(2,20*x-10)/2:(2-pow(2,-20*x+10))/2;const easeOutQuad=x=>1-(1-x)*(1-x);const easeOutQuad_reverse=x=>1-sqrt(1-x);projections=[(x,y)=>{x*=-1;let r=sqrt(x*x+y*y)*2;r=easeOutQuad_reverse(r)/2;const a=atan2(y,x);if(r>.5||!r)return null;const lat=r*180-90;const long=a;return V(lat,long)},(x,y)=>{const lat=y*180;const long=x*360;if(abs(lat)>90||abs(long)>180)return null;return V(lat,long)},(x,y)=>{x*=-1;y=(y+.25)/1.5;let r=sqrt(x*x+y*y);r=(r-.05)/.45;r=easeOutQuad_reverse(r);const lat=r*180-90;if(r<0||!r)return null;const a=(atan2(y,x)+360)%360;let long=null;if(a<200)long=(a+20)/220*360-180;if(a>340)long=(a-340)/220*360-180;if(!long)return null;return V(lat,long)},(origx,origy)=>{x=origx*pi*2;y=origy*halfPi*2.5;var delta;var sy=sign(y);y=abs(y)/pi;var x1=sign(x)*x/halfPi,D=(x1*x1-1+4*y*y)/abs(x1),D2=D*D,B=y*(2-(y>.5?min(y,abs(x)):0)),r=x*x+y*y,i=50;do{var B2=B*B,C=(8*B-B2*(B2+2)-5)/(2*B2*(B-1)),C_=(3*B-B2*B-10)/(2*B2*B),C2=C*C,BC=B*C,B_C=B+C,B_C2=B_C*B_C,B_3C=B+3*C,F=B_C2*(B2+C2*D2-1)+(1-B2)*(B2*(B_3C*B_3C+4*C2)+C2*(12*BC+4*C2)),F_=-2*B_C*(4*BC*C2+(1-4*B2+3*B2*B2)*(1+C_)+C2*(-6+14*B2-D2+(-8+8*B2-2*D2)*C_)+BC*(-8+12*B2+(-10+10*B2-D2)*C_)),sqrtF=sqrt(F),f=D*(B_C2+C2-1)+2*sqrtF-x1*(4*B_C2+D2),f_=D*(2*C*C_+2*B_C*(1+C_))+F_/sqrtF-8*B_C*(D*(-1+C2+B_C2)+2*sqrtF)*(1+C_)/(D2+4*B_C2);B-=delta=f/f_}while(delta*r*r>epsilon&&--i>0);let lon=sign(x)*(sqrt(D*D+4)+D)*pi/4;let lat=sy*halfPi*B;lat=lat/halfPi*90;lon=lon/pi*180;if(!lat||!lon)return null;if(abs(lat)>90||abs(lon)>180)return null;return V(lat,lon)},(origx,origy)=>{if(abs(origy)>.45)return null;x=origx*pi*2;y=origy*halfPi*2;var phi=y,i=25,delta,phi2,phi4,phi6;do{phi2=phi*phi;phi4=phi2*phi2;phi-=delta=(phi*(1.01183+phi4*phi4*(-.02625+.01926*phi2-.00396*phi4))-y)/(1.01183+phi4*phi4*(9*-.02625+11*.01926*phi2+13*-.00396*phi4))}while(abs(delta)>epsilon2&&--i>0);phi2=phi*phi;phi4=phi2*phi2;phi6=phi2*phi4;let lon=x/(.84719-.13063*phi2+phi6*phi6*(-.04515+.05494*phi2-.02326*phi4+.00331*phi6)),lat=phi;lat=lat/halfPi*90;lon=lon/pi*180;if(abs(lat)>90||abs(lon)>180)return null;return V(lat,lon)},(x,y)=>{x*=2;y*=2;const lat=y*90;const w=sqrt(1-abs(y)**2)/2;let lon=200;lon=map(abs(x),.5-w,.5+w,0,180);if(lon>180||lon<0)return null;if(abs(lat)>90||abs(lon)>180)return null;lon*=sign(x);return V(lat,lon)},(origx,origy)=>{const x=origx*pi*2;const y=origy*halfPi*2.5;const z=sqrt(x*x+y*y),c=2*asin(z/2),sc=sin(c),cc=cos(c);let lon=atan2(x*sc,z*cc),lat=asin(z&&y*sc/z);if(abs(lat)>90||abs(lon)>180)return null;if(!lat&&!lon)return null;return V(lat,lon)}];function ellipticJi(u,v,m){var a,b,c;if(!u){b=ellipticJ(v,1-m);return[[0,b[0]/b[1]],[1/b[1],0],[b[2]/b[1],0]]}a=ellipticJ(u,m);if(!v)return[[a[0],0],[a[1],0],[a[2],0]];b=ellipticJ(v,1-m);c=b[1]*b[1]+m*a[0]*a[0]*b[0]*b[0];return[[a[0]*b[2]/c,a[1]*a[2]*b[0]*b[1]/c],[a[1]*b[1]/c,-a[0]*a[2]*b[0]*b[2]/c],[a[2]*b[1]*b[2]/c,-m*a[0]*a[1]*b[0]/c]]}function ellipticJ(u,m){var ai,b,phi,t,twon;if(m<epsilon){t=sin(u);b=cos(u);ai=m*(u-t*b)/4;return[t-ai*b,b+ai*t,1-m*t*t/2,u-ai]}if(m>=1-epsilon){ai=(1-m)/4;b=cosh(u);t=tanh(u);phi=1/b;twon=b*sinh(u);return[t+ai*(twon-u)/(b*b),phi-ai*t*phi*(twon-u),phi+ai*t*phi*(twon+u),2*atan(exp(u))-halfPi+ai*(twon-u)/b]}var a=[1,0,0,0,0,0,0,0,0],c=[sqrt(m),0,0,0,0,0,0,0,0],i=0;b=sqrt(1-m);twon=1;while(abs(c[i]/a[i])>epsilon&&i<8){ai=a[i++];c[i]=(ai-b)/2;a[i]=(ai+b)/2;b=sqrt(ai*b);twon*=2}phi=twon*a[i]*u;do{t=c[i]*sin(b=phi)/a[i];phi=(asin(t)+phi)/2}while(--i);return[sin(phi),t=cos(phi),t/cos(phi-b),phi]}function ellipticFi(phi,psi,m){var r=abs(phi),i=abs(psi),sinhPsi=sinh(i);if(r){var cscPhi=1/sin(r),cotPhi2=1/(tan(r)*tan(r)),b=-(cotPhi2+m*(sinhPsi*sinhPsi*cscPhi*cscPhi)-1+m),c=(m-1)*cotPhi2,cotLambda2=(-b+sqrt(b*b-4*c))/2;return[ellipticF(atan(1/sqrt(cotLambda2)),m)*sign(phi),ellipticF(atan(sqrt((cotLambda2/cotPhi2-1)/m)),1-m)*sign(psi)]}return[0,ellipticF(atan(sinhPsi),1-m)*sign(psi)]}function ellipticF(phi,m){if(!m)return phi;if(m===1)return log(tan(phi/2+quarterPi));var a=1,b=sqrt(1-m),c=sqrt(m);for(var i=0;abs(c)>epsilon;i++){if(phi%pi){var dPhi=atan(b*tan(phi)/a);if(dPhi<0)dPhi+=pi;phi+=dPhi+~~(phi/pi)*pi}else phi+=phi;c=(a+b)/2;b=sqrt(a*b);c=((a=c)-b)/2}return phi/(pow(2,i)*a)}var abs=Math.abs;var atan=Math.atan;var atan2=Math.atan2;var ceil=Math.ceil;var cos=Math.cos;var exp=Math.exp;var floor=Math.floor;var log=Math.log;var max=Math.max;var min=Math.min;var pow=Math.pow;var round=Math.round;var sign=Math.sign||function(x){return x>0?1:x<0?-1:0};var sin=Math.sin;var tan=Math.tan;var epsilon=1e-6;var epsilon2=1e-12;var pi=Math.PI;var halfPi=pi/2;var quarterPi=pi/4;var sqrt1_2=Math.SQRT1_2;var sqrt2=sqrt(2);var sqrtPi=sqrt(pi);var tau=pi*2;var degrees=180/pi;var radians=pi/180;function sinci(x){return x?x/Math.sin(x):1}function asin(x){return x>1?halfPi:x<-1?-halfPi:Math.asin(x)}function acos(x){return x>1?0:x<-1?pi:Math.acos(x)}function sqrt(x){return x>0?Math.sqrt(x):0}function tanh(x){x=exp(2*x);return(x-1)/(x+1)}function sinh(x){return(exp(x)-exp(-x))/2}function cosh(x){return(exp(x)+exp(-x))/2}function arsinh(x){return log(x+sqrt(x*x+1))}function arcosh(x){return log(x+sqrt(x*x-1))}backgroundColors=[[245,245,220],[239,208,184],[219,206,160],[234,234,234],[50,50,50]];goldColors=[[194,175,80],[114,84,15],[210,186,92],[255,230,140]];greenColors=[[85,166,48],[0,127,95],[128,185,24],[43,147,72]];ribbonColors=[[255,71,55],[210,186,92]];const toColor=colorArray=>color(colorArray[0],colorArray[1],colorArray[2]);let onMap,brightColor,depth,col,slope;let lightHeight,hitMap,lastDepth,pos;let slopeMultiplier,ribbon;function setup(){const ratio=9/16;if(windowWidth<windowHeight*ratio)createCanvas(round(windowWidth),round(windowWidth/ratio));else createCanvas(round(windowHeight*ratio),round(windowHeight));setAttributes("willReadFrequently",true);PS=width/1e3;noiseSeed(R2(1e3));angleMode(DEGREES);V=createVector;backgroundColor=R3(backgroundColors);paperColor=[255,215,200].sort(()=>R()-.5);paperColor=[255,255,255];pencilDarkColor=[0,0,R()<.5?0:50];pencilBrightColor=R()<.7||backgroundColor[0]<100?[255,255,255]:backgroundColor;renderType=R3([1,2]);if(renderType==1)moreColors=R3([goldColors,greenColors]);withWallShadow=R()<.5;makeImage()}async function makeImage(){makeBackground();await timeout();projection=R3(projections);fillDir=R(30,80)*(R()<.5?1:-1);gridAspectRatio=projections.indexOf(projection)==5?2:1.5;const horizontalMargin=width*.1;gridWidth=width-horizontalMargin*2;gridHeight=gridWidth*gridAspectRatio;if(gridHeight>height-horizontalMargin*2){gridHeight=height-horizontalMargin*2;gridWidth=gridHeight/gridAspectRatio}heightMap=createHeightMap();drawArea=withWallShadow?[width,height]:[gridWidth,gridHeight];RANDOM.reset();const d=pixelDensity();console.time("phase - draw relief");translate(-width/2,height/2);if(R()<.3){ribbonStart=V(drawArea[0]*R(-.4,.4),-drawArea[1]*.4);ribbonCenter=V(drawArea[0]*R(-.3,.3),0);ribbonEnd=V(drawArea[0]*R(-.4,.4),drawArea[1]*.4);ribbonStartDir=vsub(ribbonCenter,ribbonStart).rotate(R(-45,45)).normalize(100*PS);ribbonEndDir=vsub(ribbonCenter,ribbonEnd).rotate(R(-45,45)).normalize(100*PS);ribbonPath=[ribbonStart,ribbonStart.add(ribbonStartDir),ribbonCenter,ribbonEnd.add(ribbonEndDir),ribbonEnd];ribbonPath=toCrv(ribbonPath);ribbon={path:ribbonPath,width:PS*R(80,200),color:R3(ribbonColors)};ribbon.mask=createGraphics(width,height);ribbon.mask.strokeWeight(ribbon.width/2);for(let i=0;i<ribbon.path.length;i++){const pos=ribbon.path[i];ribbon.mask.point(width/2+pos.x,height/2+pos.y)}ribbon.mask.loadPixels();applyRibbon=()=>{const x=round(pos.x+width/2);const y=round(pos.y+height/2);const i=(y*d*width*d+x*d)*4;const inRibbonMask=ribbon.mask.pixels[i+3]>0;if(inRibbonMask){brightColor=ribbon.color;depth+=lerp(abs(pos.y)/gridHeight,1,.5)*60;hitMap=true;onMap=true}}}const shadowMultiplier=R(.2,.8);applyLights=()=>{if(!depth)return;if(depth>lightHeight)col+=200;lightHeight=max(lightHeight,depth);const distToLight=V(pos.x,pos.y).div(gridHeight,gridWidth).add(.5,.5).sub(lightPos).mag();const lightStep=map(distToLight,0,2,1,.2)*shadowMultiplier;lightHeight-=lightStep};if(renderType==1){prepareRender=()=>{let finalColor=brightColor;if(col<slopeMultiplier*.3)finalColor=pencilDarkColor;else if(col<slopeMultiplier*.8)finalColor=brightColor==pencilBrightColor?R3(moreColors):brightColor;stroke(finalColor[0],finalColor[1],finalColor[2])};slopeMultiplier=255}else if(renderType==2){prepareRender=()=>{stroke(lerp(pencilDarkColor[0],brightColor[0],col/255),lerp(pencilDarkColor[1],brightColor[1],col/255),lerp(pencilDarkColor[2],brightColor[2],col/255))};slopeMultiplier=30}shouldFilterHits=withWallShadow?()=>!hitMap||!onMap&&depth>lightHeight:()=>!hitMap||!onMap;lightPos=V(fillDir>0?0:1,0);offsetX=drawArea[1]*tan(90-fillDir);startX=fillDir>0?-drawArea[0]/2-offsetX:-drawArea[0]/2;endX=fillDir>0?drawArea[0]/2:drawArea[0]/2-offsetX;moveX=PS*Math.sign(fillDir)*cos(fillDir)*.25;moveY=PS*Math.sign(fillDir)*sin(fillDir)*.25;strokeWeight(PS*2);for(let x=startX;x<endX;x+=1*PS){lightHeight=0;hitMap=false;lastDepth=0;pos=V(x,-drawArea[1]/2);while(pos.y<drawArea[1]/2){pos.y+=moveY;pos.x+=moveX;if(pos.x<-drawArea[0]/2||pos.x>drawArea[0]/2||pos.y<-drawArea[1]/2||pos.y>drawArea[1]/2)continue;const relX=pos.x/gridWidth;const relY=pos.y/gridHeight;onMap=false;brightColor=pencilBrightColor;depth=0;col=0;slope=0;const pos2d=projection(relY,relX);if(pos2d){const i=4*(Math.round((pos2d.x+90)/180*heightMap.height)*d*(heightMap.width*d)+Math.round((pos2d.y+180)/360*heightMap.width)*d);depth+=heightMap.pixels[i];slope=depth-lastDepth;col=slope*slopeMultiplier;lastDepth=depth;hitMap=true;onMap=true}applyRibbon();if(shouldFilterHits())continue;applyLights();col=constrain(col,0,255);strokeWeight(PS*(depth/255+1)*2);prepareRender();const drawPos=distortPos(pos);line(drawPos.x+width,drawPos.y,drawPos.x+width,drawPos.y+.1)}pos.x++;await timeout()}console.timeEnd("phase - draw relief")}function shouldFilterHits(){}function applyRibbon(){}function applyLights(){}function prepareRender(){}function makeBackground(){background(220);fill(backgroundColor);noStroke();rect(20*PS,20*PS,width-40*PS,height-40*PS,2*PS);const paperColorHex=`#${num2hex(pencilDarkColor[0])}${num2hex(pencilDarkColor[1])}${num2hex(pencilDarkColor[2])}`;for(let i=0;i<10;i++){const x=R(width);const y=R(height);const gradient=drawingContext.createRadialGradient(x,y,0,x,y,width*R(.25,.75));gradient.addColorStop(0,paperColorHex+"31");gradient.addColorStop(1,paperColorHex+"00");drawingContext.fillStyle=gradient;rect(0,0,width,height)}let x=0;loadPixels();for(let i=0;i<pixels.length;i+=4){x++;const n=noise(x/100,i/100)*10-5;pixels[i]+=n;pixels[i+1]+=n;pixels[i+2]+=n}updatePixels()}function num2hex(n){return n.toString(16).padStart(2,"0")}function distortPos(pos){const mag=pos.mag();const angle=pos.heading();const newDist=mag*(1+noise(mag/(PS*100),angle/100)*.15-.075);return angleVec(angle,newDist)}
"Discover a world beyond our own with the Petrography Case." This artwork invites viewers to explore a plaster relief contained within, reminiscent of the rugged surface of the moon. The intricate texture and details of the relief draw the viewer in on a journey of discovery. The Petrography Case serves as a window into a world of imagination, a testament to the power of art to transport us to new and exciting places. Come and see what secrets the Petrography Case holds..
Initially worn by miners and cowboys, roughly half of the world’s population wears denim on a given day, and the range of styles is–literally–endless. A new pair of jeans might be acid bleached, sandblasted, stonewashed, or tie-dyed; it can have hand-sanded rips and tears, followed by visible mendings, patches, intentional paint stains, and more. In an epic attempt to crack the genetic code of denim, Jenim playfully but carefully observes and translates the warp and weft of denim into generative code, weaving unique iterations of irregular, distorted, or hyper-realistic textile crops. Ironically, imitating aging, a pair of jeans produced today generates more pollution and labor than most average garments. In response, Jenim’s minted iterations go beyond wearables and into infinity. Each year that passes, the color might fade slightly; the rips might expand. Who knows what these artworks will look like ten or even fifty years from now?
function roundPatch(e,n=v_rel(.5,.5),t){let a=[];return a=getEllipse(e*R.random(.8,1.2)*threadSize,e*R.random(.8,1.2)*threadSize,45),a.forEach(e=>e.mult(R.random(.8,2))),a.forEach(e=>e.add(n)),a=toCrv(a),makePatch(a,t)}function rectPatch(e,n){const t=R.random(100,700),a=R.random(100,700),i=new SquarePatternShape(e.x-t/2,e.y-a/2,t,a);return i.fillet(R.random(50)),i.rotate(R.random(-15,15)),ps=i.ps,makePatch(ps,n)}function makePatch(e,n){const t=new LayoutPattern2(e),a=new Denim(t,n,0).rotate(R.random(360)).calc();a.warpExtensions=[5,20],a.extendChance=R.random(.2,.4),applyPatchShadow(a);const i=patchStitches(a).filter(e=>R.random_dec()>globalAge),o=R.random_dec()<.3;return{denim:a,stitches:i,fringe:o}}function applyPatchShadow(e){innerPattern=new LayoutPattern2(e.lp.getOffset(-3*globalScale)),innerPattern.ps.forEach(e=>e.add(5*globalScale,5*globalScale)),innerPattern.toCrv();const n=createGraphics(width,height);n.background(255),n.noStroke(),n.fill(0),n.beginShape(),innerPattern.crv().forEach(e=>n.vertex(e.x,e.y)),n.endShape(),n.filter(BLUR,10*globalScale),e.weft.forEach(e=>{e.forEach(e=>{if(e.ps.length>0){const t=e.ps[0],a=n.get(t.x,t.y);brightness(a)<360&&(e.darkness=brightness(a)/1500)}})})}function applyPatch3dEffect(e,n){innerPattern=new LayoutPattern2(e.lp.getOffset(0)),innerPattern.ps.forEach(e=>e.add(5,5)),innerPattern.toCrv();const t=createGraphics(width,height);t.background(0),t.noStroke(),t.fill(255,20),innerPattern.crv().forEach(e=>t.circle(e.x,e.y,R.random(50))),innerPattern.crv().forEach(e=>t.circle(e.x,e.y,R.random(30))),innerPattern.crv().forEach(e=>t.circle(e.x,e.y,R.random(10))),n.weft.forEach(e=>{e.forEach(e=>{if(e.ps.length>0){const n=e.ps[0],a=t.get(n.x,n.y);brightness(a)<360&&(e.age=brightness(a)/1500)}})})}function patchStitches(e,n){threadSize=initialThreadSize;let t=[];const a=n||R.random_choice([1,2,3]);if(1==a)t=crossStitches(e.lp);else if(2==a){if(t=e.lp.stitches(6,5,5,!0),R.random_dec()<.5&&(t=t.concat(e.lp.stitches(7,5,5,!0))),R.random_dec()<.4)for(let n=1;n<R.random(3);n++)t=t.concat(e.lp.stitches(6+R.random(5,40),5,5,!0))}else 3==a&&(t=e.lp.stitches(-6,5,5,!0),R.random_dec()<.5&&(t=t.concat(e.lp.stitches(-7,5,5,!0))),R.random_dec()<.7&&(t=t.concat(e.lp.stitches(-3,5,5,!0))));return t}async function drawStitches(e){for(const n of e){const e=n.slice(0,2),t=vsub(e[1],e[0]).rotate(-90).setMag(5*globalScale),a=toCrv(e).map(e=>e.mult(globalScale));for(const e of a)await burn(vsub(e,t),12*globalScale,4);for(const e of a)await dodge(vadd(e,t),12*globalScale,4);await new Loop(n.slice(0,2),n[2]?n[2]:patchStitchColor,1.3*initialThreadSize).wiggle().shadow().draw(),await timeout(0)}}function crossStitches(e){let n=e.stitches(1,R.random(5,15),R.random(5,10),!0).map(e=>{const n=round(R.random(1,2)),t=vdist(e[0],e[1]),a=vsub(e[1],e[0]),i=a.copy().rotate(90),o=[];for(let r=1;r<t;r+=t/n){const n=vsub(e[0],i.setMag(10)),t=vadd(n,a.setMag(r+.5)),d=vadd(t,i.setMag(30));o.push([t,d])}return o}).flat();return n}async function simple(){denim=new Denim(fullPattern,denimColor).rotate(R.random(360)),denim.calc().makeRips(),background(BG),await denim.draw({colorFunc:dyePattern1}),await denim.finishDraw()}async function patches(){denim=new Denim(fullPattern,denimColor).rotate(R.random(360)),denim.ripThreshold=.1,denim.calc().makeRips(),background(BG),await denim.draw({colorFunc:dyePattern1}),R.reset(100);const e=R.random_dec()<.3?1:R.random(3),n=[];for(let t=0;t<e;t++){const e=R.random()<.5?v_rel(.5,.5):v_rel(R.random(.2,.8),R.random(.2,.8));R.random_dec()<.5?n.push(roundPatch(baseWidth*R.random(.1,.25),e,denimColor)):n.push(rectPatch(e,denimColor))}for(let e=0;e<n.length;e++)denim.ripExtendMasks.push(n[e].denim);threadSize=1.5*initialThreadSize;for(let e=0;e<n.length;e++)await n[e].denim.draw({dontFringe:1-n[e].fringe}),await drawStitches(n[e].stitches),await n[e].denim.finishDraw();await denim.finishDraw()}async function singleHole(){denim_bg=new Denim(fullPattern,denimColor).rotate(R.random(360)),denim_bg.visibleWhite=1,denim_bg.darkness=.7,denim_bg.calc(),background(BG),await denim_bg.draw({dontFringe:!0}),R.reset(100),denim=new Denim(fullPattern,denimColor).rotate(R.random(360));const e=R.random(2,4)-3*globalAge;denim.pointInRip=(n=>{const t=e*n.dist(v_rel(.5,.5))/baseHeight;return noise(ripNoiseScale[0]*n.x/baseWidth,ripNoiseScale[1]*n.y/baseHeight,denim.ripNoiseZ)>t}),R.random()<.5&&(denim.ripMin=0,denim.ripMax=0),denim.calc().makeRips(),R.reset(100);const n=R.random(5);if(denim.warpRips.forEach(e=>e.len*=R.random(.2)*n),await denim.draw({colorFunc:dyePattern1}),await denim.finishDraw(),R.reset(100),R.random()<.3){const e=findCurve(denim.weftRips.map(e=>e.pos)),n=[];for(let t=0;t<e.length-1;t++){const a=e[t],i=e[t+1],o=vsub(i,a).rotate(-90).setMag(R.random(20,150)),r=vadd(a,i).mult(.5).add(o);n.push([a,r]),n.push([r,i])}let t=[];for(let e=0;e<n.length;e++){const a=n[e][0],i=n[e][1],o=vdist(a,i),r=vsub(i,a);for(let e=0;e<o;e+=25){const n=vadd(a,r.copy().setMag(e)),i=vadd(a,r.copy().setMag(e+15));t.push([n,i,color(0)])}}t=filter(e=>R.random_dec()>globalAge),await drawStitches(t)}}function findCurve(e){const n=v_rel(.5,.5),t=[];for(let a=0;a<360;a+=10){const i=e.reduce((e,t)=>abs(getAngle(e,n)-a)<abs(getAngle(t,n)-a)?e:t);t.push(i)}return t.push(t[0]),t}function getAngle(e,n){return(vsub(e,n).heading()+360)%360}async function mending(){denim=new Denim(fullPattern,denimColor).rotate(R.random(360));const e=R.random()<.5;let n;const t=R.random()<.5?v_rel(.5,.5):v_rel(R.random(.2,.8),R.random(.2,.8));n=R.random_dec()<.5?roundPatch(baseWidth*R.random(.1,.25),t,denimColor):rectPatch(t,denimColor),n.stitches=patchStitches(n.denim,3);const a=R.random()<.3;stitches=[];const i=R.random_choice([1,2,3]);let o=R.random_choice([color(255,0,0),color(0),color(255)]);const r=n.denim.lp.bounds(),d=1==i?15:0,s=R.random(),c=R.random(),m=R.random()<.8?0:R.random()<.8?1:2;for(let e=r.left-100;e<r.right+100;e+=R.random(20,30)){1==m&&(o=R.random_choice([color(255,0,0),color(0),color(255)]));for(let n=r.top-R.random(100);n<r.bottom+R.random(100);n+=R.random(20,30)){2==m&&(o=R.random_choice([color(255,0,0),color(0),color(255)]));const t=R.random(20,30);let a=!0,i=!0;R.random()<s&&(R.random()<c?a=!1:i=!1),R.random()>globalAge&&(a&&stitches.push([v(e+d,n),v(e-d,n+t),o]),i&&stitches.push([v(e+t/2,n+t/2+d),v(e-t/2,n+t/2-d),o])),n+=t}e+=R.random(30,40)}stitches=stitches.filter(e=>R.random_dec()>globalAge),denim.ripThreshold=R.random(.1),denim.calc().makeRips(),stitches=stitches.filter(e=>denim.hasWeftOn(e[0])&&denim.hasWeftOn(e[1])||n.denim.hasWeftOn(e[0])&&n.denim.hasWeftOn(e[1])),denim.ripExtendMasks.push(n.denim),applyPatch3dEffect(n.denim,denim),background(BG),await denim.draw({dontFringe:!e,colorFunc:dyePattern1}),threadSize=1.5*initialThreadSize,await n.denim.draw({dontFringe:n.fringe}),a&&await drawStitches(n.stitches),await n.denim.finishDraw(),await drawStitches(stitches),await denim.finishDraw()}async function largeRips(){denim=new Denim(fullPattern,neighborColor(denimColor,0,0,-150)).rotate(R.random(360)),denim.visibleWhite=1,denim.darkness=.3,denim.calc(),denim2=new Denim(fullPattern,denimColor).rotate(R.random(360)),ripNoiseScale=[R.random(4,8),R.random(4,8)],denim2.ripThreshold=R.random(.3,.5),denim2.ripMax*=R.random(2),denim2.calc().makeRips(),denim2.dropShadowOn([denim]),background(BG),await denim.draw({dontFringe:!0}),await denim2.draw({colorFunc:dyePattern1}),await denim2.finishDraw()}async function fringeComp(){withFringe=!0,await withDivide()}async function withDivide(){const e=!!withFringe||R.random()<.5;flipped=R.random()<.5,pos1=R.random_choice(["left","right","top","bottom"]),pos2=R.random()<.15&&R.random_choice(["left","right","top","bottom"]),pos2&&R.random()<.5&&("left"==pos1?pos2="right":"right"==pos1?pos2="left":"top"==pos1?pos2="bottom":"bottom"==pos1&&(pos2="top")),denim_bg=new Denim(fullPattern,denimColor).rotate(R.random(360)).calc(),denim_top1=divideTopDenim(pos1),denim_bg.ripExtendMasks.push(denim_top1),pos2&&(denim_top2=divideTopDenim(pos2),denim_top1.ripExtendMasks.push(denim_top2),denim_bg.ripExtendMasks.push(denim_top2)),background(BG),await denim_bg.draw({dontFringe:!0,colorFunc:dyePattern1}),await denim_bg.finishDraw(),await denim_top1.draw({dontFringe:!e}),await denim_top1.finishDraw(),pos2&&(await denim_top2.draw({dontFringe:!e,colorFunc:dyePattern2}),await denim_top2.finishDraw())}function divideTopDenim(e){let n,t;["left","right"].includes(e)?(n=v(.2*-baseWidth,baseHeight*R.random(.25,.75)),t=v(1.2*baseWidth,baseHeight*R.random(.25,.75))):(n=v(baseWidth*R.random(.25,.75),.2*-baseHeight),t=v(baseWidth*R.random(.25,.75),1.2*baseHeight));const a=[n,t];let i,o;"left"==e?(i=v(.2*-baseWidth,.2*-baseHeight),o=v(1.2*baseWidth,.2*-baseHeight)):"right"==e?(a.reverse(),i=v(1.2*baseWidth,1.2*baseHeight),o=v(.2*-baseWidth,1.2*baseHeight)):"top"==e?(a.reverse(),i=v(.2*-baseWidth,1.2*baseHeight),o=v(.2*-baseWidth,.2*-baseHeight)):(i=v(1.2*baseWidth,.2*-baseHeight),o=v(1.2*baseWidth,1.2*baseHeight));const r=[i,...a,o];return pattern_top=new LayoutPattern2(r).fillet(80),newDenim=new Denim(pattern_top,denimColor).rotate(R.random(-360)),flipped&&(newDenim.visibleWhite=1),newDenim.age=.2,newDenim.ripThreshold=R.random(.1,.45),withFringe||newDenim.lp.prepareFoldedStitchings(),newDenim.calc().makeRips(),newDenim.dropShadowOn([denim_bg]),withFringe?(newDenim.warpExtensions=[R.random(120,250),R.random(250,540)],newDenim.extendChance=R.random(.7,1)):newDenim.foldedStitchings(),newDenim}function initFeatures(){composition=R.random_choice([withDivide,patches,largeRips,simple,mending,singleHole,fringeComp]),getBaseColor(),dyePattern1=getColorFunc(),dyePattern2=R.random()<.5?dyePattern1:getColorFunc()}function setup(){initFeatures(),noiseSeed(R.random_int(2e4)),1.4*windowWidth>windowHeight?canvas=createCanvas(windowHeight/1.4,windowHeight):canvas=createCanvas(windowWidth,1.4*windowWidth),globalScale=width/baseWidth,initialThreadSize=R.random(1.3,2),threadSize=initialThreadSize,dyePattern1=initColorFunc(dyePattern1),dyePattern2=initColorFunc(dyePattern2),initBaseColor(),ripNoiseScale=[R.random(5,10),R.random(5,10)],angleMode(DEGREES),noLoop(),noStroke(),noFill();const e=new Date,n=e.getFullYear()-2023,t=n+e.getMonth()/12;globalAge=constrain(t/10,0,1),fullPattern=new SquarePatternShape(0,0,baseWidth,baseHeight),makeImage()}async function makeImage(){background(BG),fill(255),textSize(10),textAlign(CENTER,CENTER),text("Loading Jenim",width/2,height/2),noFill(),await timeout(30),await composition(),print("done")}let withFringe=!1;const warpColors=natural;let stitchColor;const BG="#666",baseWidth=1e3,baseHeight=1.4*baseWidth;let globalScale;
function checkers(){const t=R.random(120,220)*initialThreadSize,o=t/2;return(e,r,a)=>((r%t<o&&a%t<o||r%t>o&&a%t>o)&&(e=lerpColor(e,color(0),.4)),e)}function bleach_gradient(){return(t,o,e)=>(t=lerpColor(t,color(255),1-e/baseHeight),t)}function bleach_noise(){const t=R.random(50,150)*initialThreadSize,o=R.random(1e4),e=R.random(1e4),r=R.random(.2,.8),a=R.random(.1),i=round(R.random());return(s,n,l)=>{const h=noise(n/t+o,l/t+e,R.random(.3)*i);return h<r?s=lerpColor(s,color(255),h+.5):h<r+a&&(s=lerpColor(s,color(255),map(h,r,r+a,r+.5,0))),s}}function bleach_large(){const t=R.random(20,100)*initialThreadSize,o=R.random(1e4),e=R.random(1e4);return(r,a,i)=>(val=i/baseHeight,noise(a/t+o,i/t+e)<val&&(r=lerpColor(r,color(255),val)),r)}function strips(){const t=R.random(3),o=R.random(90,180);return(e,r,a)=>((r+floor(a/t))%(o*initialThreadSize)<o/2*initialThreadSize&&(e=lerpColor(e,color(255),.4)),e)}function painters_camo(){camoColors.sort(()=>R.random_dec()-.5);for(let t=0;t<4;t++)paintersLayers.push({s:R.random(100,400),val:R.random(.4,.6),z:R.random(10),color:color(camoColors[t])});return(t,o,e)=>{for(let r=paintersLayers.length-1;r>=0;r--){const a=paintersLayers[r];noise(o/a.s,e/a.s,a.z)<a.val&&(t=lerpColor(t,a.color,.8))}return t}}function painters_grad(){const t=R.random(360);for(let o=0;o<2;o++)paintersLayers.push({s:R.random(100,400),val:R.random(.4,.6),z:R.random(10),color:makeColor((t+R.random(-60,60))%360,360,R.random(200,360))});return(t,o,e)=>{for(let r=paintersLayers.length-1;r>=0;r--){const a=paintersLayers[r];t=lerpColor(t,a.color,noise(o/a.s,e/a.s,a.z)*(1-e/baseHeight))}return t}}function painters_pollock(){polockImage=createGraphics(baseWidth,baseHeight);const t=map(initialThreadSize,.5,2,500,150),o=R.random();for(let e=0;e<t;e++){polockImage.fill(R.random_choice([color(0),color(255)])),polockImage.noStroke();const t=v(R.random(baseWidth),R.random(baseHeight)),e=v(R.random(-.1,.1),R.random(-.1,.1)),r=R.random(200,30)*initialThreadSize*o;let a=R.random(100);for(let o=0;o<r;o++){const i=noise(a,10)**2*map(o,0,r,45,5)*initialThreadSize;a+=.02,polockImage.circle(t.x,t.y,i),t.add(e),e.rotate(R.random(-4,4)),e.setMag(1.04*e.mag())}}return(t,o,e)=>{const r=polockImage.get(o,e);return r[3]>0?lerpColor(t,color(r),.7):t}}function getColorFunc(){let t=R.random_dec();if(t<.5)return null;let o=[bleach_gradient,bleach_large,bleach_noise,strips,checkers,painters_pollock,null];return["largeRips","fringeComp"].includes(composition.name)||o.push(painters_camo),"withDivide"==composition.name&&(o=[bleach_gradient,bleach_large,bleach_noise,strips,checkers]),res=R.random_choice(o),res}function initColorFunc(t){return t?{func:t(),offsetX:R.random(-35,35),offsetY:R.random(-35,35)}:null}function makeColor(t,o=360,e=360){colorMode(HSB,360);let r=color(t,o,e);return colorMode(RGB),r=r.toRGB(),r}function neighborColor(t,o=0,e=null,r=null){colorMode(HSB,360);const a=hue(t)+o,i=null==e?R.random(360):map(saturation(t),0,100,0,360)+e,s=null==r?R.random(360):brightness(t)+r;let n=color(a,i,s);return colorMode(RGB),n=n.toRGB(),n}async function franzim(t,o,e,r=.9){windTarget||(windTarget=R.random(360)),threadSize=initialThreadSize*r,o.setMag(1);let a=[t];const i=o.copy().rotate(90),s=ceil(e/10);for(let t=0;t<=s;t++){const t=a[a.length-1],e=40*noise(t.x/50,t.y/50)-20,r=noise(35*a[a.length-1].x/baseWidth,35*a[a.length-1].y/baseHeight),s=60*(r-.5),n=Math.sign(windTarget-o.heading()),l=s+R.random(-2,2)+n;o.rotate(l),i.rotate(l);const h=t.copy().add(o.copy().mult(10));h.add(i.copy().mult(e)),a.push(h)}if(a=toCrv(a),a.length<2)return;for(let t=0;t<a.length;t++)await burn(a[t].copy().add(6*t/a.length,6*t/a.length).mult(globalScale),threadSize*globalScale*map(t,0,a.length,1,4),5);const n=color(R.random_choice(warpColors));n.setAlpha(150),await thread(a,n,5,50)}async function thread(t,o,e=1,r=120){if(t[0].x<0||t[0].y<0||t[0].x>baseWidth||t[0].y>baseHeight)return;newPs=t.map(t=>t.copy().mult(globalScale)),noFill(),noStroke();let a=newPs.map(t=>t.copy());if(!(a.length<2||crvLength(a)<1)){newPs.length<10&&(a=toCrv(newPs)),fill(o),a.forEach(t=>circle(t.x,t.y,threadSize*globalScale)),noFill(),strokeWeight(.2*threadSize*globalScale),o.setAlpha(r),stroke(o),e*=width/1e3;for(let t=0;t<e;t++)for(let t=0;t<a.length;t++)await tinyThread(a[t])}}async function tinyThread(t,o=1){noFill(),beginShape(),curveVertex(t.x,t.y),curveVertex(t.x,t.y),curveVertex(t.x+threadSize*globalScale*cos(tinyThreadDir+=35)*o,t.y+threadSize*globalScale*sin(tinyThreadDir+=35)*o),curveVertex(t.x+threadSize*globalScale*sin(tinyThreadDir+=70)*o,t.y+threadSize*globalScale*cos(tinyThreadDir+=70)*o),curveVertex(t.x+threadSize*globalScale*cos(tinyThreadDir+=100)*o,t.y+threadSize*globalScale*sin(tinyThreadDir+=105)*o),endShape(),tinyThreadDir>1e4&&(tinyThreadDir=0)}class PatternShape{constructor(t){this.ps=t}draw(){beginShape(),this.ps.forEach(t=>vertex(t.x,t.y)),endShape(CLOSE)}center(){let t=v(0,0);return this.ps.forEach(o=>t.add(o)),t.div(this.ps.length),t}rotate(t){const o=this.center();this.rotateAround(o,t)}rotateAround(t,o){const e=this.ps.map(o=>o.copy().sub(t));e.forEach(t=>t.rotate(o)),e.forEach(o=>o.add(t)),this.ps=e}rotatedContainingSquare(t){const o=this.center();this.rotate(-t);const e=this.containingSquare();return e.rotateAround(o,t),this.rotate(t),e}bounds(){return{top:this.ps.reduce((t,o)=>t.y<o.y?t:o).y,bottom:this.ps.reduce((t,o)=>t.y>o.y?t:o).y,left:this.ps.reduce((t,o)=>t.x<o.x?t:o).x,right:this.ps.reduce((t,o)=>t.x>o.x?t:o).x}}containingSquare(){const t=this.bounds();return new SquarePatternShape(t.left,t.top,t.right-t.left,t.bottom-t.top)}toCrv(){this.ps=this.crv()}crv(){let t=[];for(let o=0;o<this.ps.length;o++){const e=toCrv([this.ps[o],this.ps[(o+1)%this.ps.length]]);t=t.concat(e.slice(0,e.length-1))}return t}goAlong(t){for(const o of this.ps)t(o)}async asyncGoAlong(t){for(const o of this.ps)await t(o)}fillet(t){const o=[];for(let e=0;e<this.ps.length;e++){const r=this.ps[e],a=this.ps[(e+1)%this.ps.length],i=this.ps[(e+2)%this.ps.length],s=vsub(a,r).setMag(t),n=vsub(a,i).setMag(t);o.push(vadd(a,n)),o.push(vadd(a,s))}return this.ps=o,this}}const p2i=(t,o,e)=>4*((round(t)-1/e)*e+(round(o)-1/e)*e*(round(baseWidth)*e));class LayoutPattern2 extends PatternShape{constructor(t){super(t)}makeGraphics(){this.graphics=createGraphics(baseWidth,baseHeight),this.graphics.beginShape(),this.ps.forEach(t=>this.graphics.vertex(t.x,t.y)),this.graphics.endShape(CLOSE),this.graphicsDensity=this.graphics.pixelDensity(),this.graphics.loadPixels()}pointInPattern(t){return this.graphics||this.makeGraphics(),this.graphics.get(t.x,t.y)[3]>0}getOffset(t){let o=[...this.ps];return o.push(this.ps[0]),o=o.map((o,e)=>{const r=this.ps[(e+1)%this.ps.length],a=this.ps[(e+2)%this.ps.length],i=vsub(r,o),s=vsub(r,a);let n=s.angleBetween(i);return n<0&&(n+=360),s.rotate(n/2).setMag(t*initialThreadSize),vadd(r,s)}),o}stitches(t,o,e,r=!1){const a=new LayoutPattern2(this.getOffset(t)),i=a.crv(),s=[];o*=initialThreadSize,e*=initialThreadSize;for(let t=0;t<crvLength(i)-o;t+=r?e*R.random(.9,1.6):e){const e=placeOnCurve(i,t);if(!e)continue;t+=r?o*R.random(.9,1.6):o;const a=placeOnCurve(i,t);if(!a)break;(inCanvas(e)||inCanvas(a))&&s.push([e,a])}return s}dropShadowOn(t){const o=createGraphics(baseWidth,baseHeight);o.noStroke(),o.fill(0,10),o.beginShape(),this.crv().forEach(t=>o.vertex(t.x,t.y)),o.endShape(),this.crv().forEach(t=>o.circle(t.x,t.y,threadSize*R.random(15))),t.weft.forEach(t=>{t.forEach(t=>{if(t.ps.length>0){const e=t.ps[0],r=o.get(e.x,e.y);alpha(r)>0&&(t.darkness=.4-brightness(r)/360*(alpha(r)/255)*.4)}})})}prepareFoldedStitchings(){this.stitchPlaces=R.random()<.5?[12]:[9,25],this.stitchType=2==this.stitchPlaces.length?R.random_choice(["normal","doubleTrim","force"]):R.random_choice(["normal","trim","zigzag","force"]),this.extraStitchColor=R.random_choice([stitchColor,R.random_choice([color(0),color(255,0,0),color(255)])])}async drawStitches(t=null){if(!this.withStitches)return;let o=[];for(const t of this.stitchPlaces)o.push(this.stitches(t,12,4));["trim","doubleTrim"].includes(this.stitchType)&&o[o.length-1].splice(round(o[o.length-1].length*R.random(.3,.7)));for(let e of o)for(let o of e){const e=t.hasWeftOn(o[0]);if(e){const t=new Loop(o,stitchColor,1.3*initialThreadSize).wiggle().shadow();t.age=e.age,await t.draw(),await timeout()}}if("doubleTrim"==this.stitchType){const e=o[1][o[1].length-1],r=vsub(e[1],e[0]).setMag(5),a=r.copy().rotate(90),i=this.stitchPlaces[1]-this.stitchPlaces[0];for(let o=-1*globalScale;o<i+2*globalScale;o+=R.random(5)*globalScale){const i=vadd(e[0].add(r.copy().setMag(R.random(-2,2)*globalScale)),a.copy().setMag(o)),s=vadd(e[1].add(r.copy().setMag(R.random(-2,2)*globalScale)),a.copy().setMag(o)),n=t.hasWeftOn(i);if(n){const t=new Loop([i,s],this.extraStitchColor,1.3*initialThreadSize).wiggle().shadow();t.age=n.age,await t.draw(),await timeout()}}}if(["trim","force"].includes(this.stitchType)){const e=o[o.length-1],r="trim"==this.stitchType?e[e.length-1]:R.random_choice(e),a=vsub(r[1],r[0]),i=a.copy().rotate(90),s=R.random(50,100);for(let o=1;o<s;o+=R.random(5)){const e=vadd(r[1],a.copy().setMag(o*globalScale)),s=i.copy().rotate(R.random(-10,10)).setMag(R.random(5,10)*globalScale),n=vadd(e,s),l=vsub(e,s),h=t.hasWeftOn(n);if(h){const t=new Loop([n,l],this.extraStitchColor,1.3*initialThreadSize).wiggle().shadow();t.age=h.age,await t.draw(),await timeout()}}}if("zigzag"==this.stitchType){const t=round(o[0].length*R.random(.1,.7)),e=floor(R.random(t,.9*o[0].length));for(let r=t;r<e;r++){const t=o[0][r],e=vsub(t[1],t[0]).rotate(45),a=vadd(t[0],e);let i=new Loop([t[0],a],this.extraStitchColor,1.3*initialThreadSize).wiggle().shadow();await i.draw(),i=new Loop([a,t[1]],this.extraStitchColor,1.3*initialThreadSize).wiggle().shadow(),await i.draw(),await timeout()}}}}class SquarePatternShape extends LayoutPattern2{constructor(t,o,e,r){super([v(t,o),v(t,o+r),v(t+e,o+r),v(t+e,o)]),this.rotation=0}rotateAround(t,o){this.rotation=o,super.rotateAround(t,o)}getDimension(){const t=this.ps[0],o=vdist(this.ps[0],this.ps[3]),e=vdist(this.ps[0],this.ps[1]);return{pos:t,w:o,h:e,rotation:this.rotation}}}const gold=["#a67c00","#bf9b30","#ffbf00","#ffcf40","#ffdc73"],natural=["#ede8d3","#fafaf7","#fcfcfc"];let paintersLayers=[];const camoColors=["#2E2C24","#AC9F7C","#503F38","#56583D","#E5E7EB","#9D2328"],getBaseColor=()=>{let t=R.random_dec();t<.7?(patchStitch=R.random_choice([color(255,0,0),color(0),color(255)]),coloring={color:"Indigo",denimStitch:"Ochre",patchStitch:patchStitch}):coloring=t<.8?{color:"Charcoal",denimStitch:"White",patchStitch:"Black"}:{color:"Colored",denimStitch:"White",patchStitch:"Black"}},initBaseColor=()=>{if("Indigo"==coloring.color){const t=R.random(195,240);denimColor=makeColor(t,map(abs(t-220),0,25,360,250),R.random(180,360)),stitchColor=color("orange"),patchStitchColor=coloring.patchStitch}else"Charcoal"==coloring.color?(denimColor=makeColor(0,0,0),stitchColor=color(255),patchStitchColor=color(255)):(denimColor=makeColor(R.random(0,70),R.random(200,360),R.random(100,250)),stitchColor=color(255),patchStitchColor=color(0))};let windTarget;class Loop{constructor(t,o,e){this.threadSize=e||threadSize,this.originalColor=o,this.color=o,this.ps=t,this.age=0,this.darkness=0}wiggle(){const t=this.ps[0],o=this.ps[this.ps.length-1],e=vadd(t,o).div(2),r=vsub(t,o).rotate(90).normalize().mult(vdist(t,o)*R.random(-.05,.05));return e.add(r),this.ps=[t,e,o],this}shadow(t=!0,o={times:2,size:2,opacity:30,offset:v(2,0)}){return this.withShadow=!!t&&o,this}getFinalColor(){let t=this.color;return this.age&&(t=lerpColor(t,color(R.random_choice(natural)),this.age)),this.yellow&&(t=lerpColor(t,color("#ebe1a2"),this.yellow)),0!=this.darkness&&(t=neighborColor(t,0,.5*this.darkness*360,-.5*this.darkness*360)),t}applyColorFunc(t){if(t&&this.ps.length>0){const o=this.ps[0];this.color=t.func(this.color,o.x+t.offsetX,o.y+t.offsetY)}}async draw(){if(!(this.ps.length<=1)){if(this.withShadow)for(let t=0;t<this.withShadow.times;t++)for(const t of toCrv(this.ps))await burn(t.copy().add(this.withShadow.offset).mult(globalScale),this.threadSize*globalScale*(this.withShadow.size+R.random(-1,1)),this.withShadow.size.opacity);this.age&&(this.color=lerpColor(this.color,color(R.random_choice(natural)),this.age)),this.yellow&&(this.color=lerpColor(this.color,color("#ebe1a2"),this.yellow)),0!=this.darkness&&(this.color=neighborColor(this.color,0,0,-.5*this.darkness*360)),threadSize=this.threadSize,await thread(this.ps,this.color,3)}}dir(){return this.ps.length<=1?v(0,0):vsub(this.ps[this.ps.length-1],this.ps[0])}}let t1=0,tinyThreadDir=0;
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}}
Initially worn by gold miners and cowboys, roughly half of the world’s population wears denim on a given day, and the range of styles is–literally–endless. A new pair of jeans might be acid bleached, sandblasted, stonewashed, or tie-dyed; it can have hand-sanded rips and tears, followed by visible mendings, patches, intentional paint stains, and more. In an epic attempt to crack the genetic code of Denim, Jenim playfully but carefully observes and translates the warp and weft of Denim into generative code, weaving unique iterations of irregular, distorted, or hyper-realistic textile crops. Ironically, imitating aging, a pair of jeans produced today generates more pollution and labor than most average garments. In response, Jenim’s minted iterations go beyond wearables and into infinity. Each year that passes, the color might fade slightly; the rips might expand. Who knows what these artworks will look like ten or even fifty years from now?