asciify-engine 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -0
- package/THIRD_PARTY.md +14 -0
- package/dist/hover.cjs +1 -1
- package/dist/hover.d.cts +31 -1
- package/dist/hover.d.ts +31 -1
- package/dist/hover.js +1 -1
- package/dist/studio.cjs +1 -0
- package/dist/studio.d.cts +286 -0
- package/dist/studio.d.ts +286 -0
- package/dist/studio.js +1 -0
- package/examples/studio-composition.ts +65 -0
- package/licenses/Mediabunny-MPL-2.0.txt +373 -0
- package/package.json +22 -4
- package/skills/asciify-engine/SKILL.md +15 -6
- package/skills/asciify-engine/references/hero-finish.md +123 -0
- package/skills/asciify-engine/references/layered-hero.md +5 -0
- package/skills/asciify-engine/references/studio-effects.md +5 -0
- package/skills/asciify-engine/references/studio-workspace.md +92 -0
- package/skills/asciify-engine/references/upgrading.md +29 -0
package/dist/hover.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var t=[{value:"none",mode:"none",label:"Off",description:"Keep the image still. Hover stays available."},{value:"breathe",mode:"print",label:"Living Print",description:"Soft tonal movement. The character grid stays still."},{value:"wave",mode:"current",label:"Slow Current",description:"A gentle flow through the image, with steady edges."},{value:"rain",mode:"reform",label:"Reveal & Reform",description:"Disperse, gather, then hold the complete image."}];function e(e){return"orbit"===e?"current":t.find(t=>t.value===e||t.mode===e)?.mode??"none"}var i=(t,e,i)=>{const s=(t=>Math.max(0,Math.min(1,t)))((i-t)/(e-t));return s*s*(3-2*s)},s=(t,e)=>{const i=(.06711056*t+.00583715*e)%1*52.9829189;return i-Math.floor(i)},n=class{constructor(){this.last=null,this.mode="none",this.phase=0}update(t,e,i=1){return Number.isFinite(t)?((e!==this.mode||null!==this.last&&t<this.last)&&(this.mode=e,this.phase=0,this.last=t),null!==this.last&&(this.phase+=Math.max(0,t-this.last)*Math.max(.1,Math.min(3,Number.isFinite(i)?i:1))),this.last=t,this.phase):this.phase}};function h(t,e,s,n,h){const a=n*Math.PI/6,o=i(0,.12,Math.min(e,1-e,s,1-s));if(h[0]=h[1]=h[2]=0,h[3]=1,"print"===t)h[2]=Math.sin(9*e+5*s+a)*Math.cos(8*s-3*e-a)*.065*o,h[3]=.9+.1*Math.sin(6*e-4*s+a);else if("current"===t)h[0]=Math.sin(9*s+a)*Math.cos(7*e-a)*6*o,h[1]=Math.cos(8*e+a)*Math.sin(6*s-a)*4*o;else if("reform"===t){const t=(n%12+12)%12,a=.8*e+.2*s+.08*Math.sin(8*e-5*s),o=i(1.8+1.2*a,3.8+1.2*a,t)*(1-i(5+1.7*a,7.2+1.7*a,t));h[2]=.95*-o,h[3]=1-.82*o}return h}function a(t,e,i){const s=Math.min(t*Math.max(1,i),(1-t)*Math.max(1,i),e*Math.max(1,1/i),(1-e)*Math.max(1,1/i)),n=Math.max(0,Math.min(1,(s-.035)/.105));return n*n*n*(n*(6*n-15)+10)}var o=class{constructor(t,e){this.previous=null,this.peak=0,this.mode="dissolve",this.width=t,this.height=e;const i=t*e;this.pixels=new Uint8Array(4*i),this.ink=new Float32Array(i),this.targetX=new Float32Array(i),this.targetY=new Float32Array(i),this.offsetX=new Float32Array(i),this.offsetY=new Float32Array(i),this.edge=new Float32Array(i);for(let i=0;i<e;i++)for(let s=0;s<t;s++)this.edge[i*t+s]=a(s/(t-1),i/(e-1),t/e);this.clear()}get active(){return this.peak>2e-4}setMode(t){t!==this.mode&&(this.mode=t,this.clear())}clear(){for(const t of[this.ink,this.targetX,this.targetY,this.offsetX,this.offsetY,this.pixels])t.fill(0);if(this.previous=null,this.peak=0,"dissolve"!==this.mode)for(let t=0;t<this.pixels.length;t+=4)this.pixels[t]=this.pixels[t+2]=128}leave(){this.previous=null}move(t,e,i){if(!Number.isFinite(t+e+i))return;t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e));const s=this.previous;this.previous={x:t,y:e};const n=this.width,h=this.height,a=Math.max(1,n/h),o=Math.max(1,h/n),r=s?(t-s.x)*a:0,l=s?(e-s.y)*o:0,c=Math.hypot(r,l);if(!s&&"dissolve"!==this.mode)return;if(s&&c<1e-4)return;const m=.035+.11*Math.max(.1,Math.min(1,i)),d=Math.min(128,Math.max(1,Math.ceil(c/(.45*m)))),u=c?r/c:1,f=c?l/c:0,g=Math.min(1,c/(m*d)*2.2);for(let i=0;i<d;i++){const r=(i+.5)/d,l=s?s.x+(t-s.x)*r:t,c=s?s.y+(e-s.y)*r:e,p=Math.max(0,Math.floor((l-2.5*m/a)*(n-1))),x=Math.min(n-1,Math.ceil((l+2.5*m/a)*(n-1))),v=Math.max(0,Math.floor((c-2.5*m/o)*(h-1))),M=Math.min(h-1,Math.ceil((c+2.5*m/o)*(h-1)));for(let t=v;t<=M;t++)for(let e=p;e<=x;e++){const i=(e/(n-1)-l)*a/m,s=(t/(h-1)-c)*o/m,r=Math.exp(1.5*-(i*i+s*s)),d=t*n+e;if("dissolve"===this.mode)this.ink[d]=Math.max(this.ink[d],r);else{const t=(-i*f+s*u)*r*2.8,e="silk"===this.mode?u*t:-s*r*2.5,n="silk"===this.mode?f*t:i*r*2.5;this.targetX[d]=Math.max(-1,Math.min(1,this.targetX[d]+e*g)),this.targetY[d]=Math.max(-1,Math.min(1,this.targetY[d]+n*g))}}}this.peak=1}step(t){if(!this.active||!Number.isFinite(t))return;const e=Math.max(0,Math.min(.05,t)),i=Math.exp(-("dissolve"===this.mode?2.15:3.2)*e),s=1-Math.exp(-22*e);let n=0;for(let t=0;t<this.ink.length;t++)if("dissolve"===this.mode){this.ink[t]*=i,n=Math.max(n,this.ink[t]);const e=Math.round(65535*this.ink[t]);this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e}else{this.targetX[t]*=i,this.targetY[t]*=i,this.offsetX[t]+=(this.targetX[t]-this.offsetX[t])*s,this.offsetY[t]+=(this.targetY[t]-this.offsetY[t])*s,n=Math.max(n,Math.abs(this.offsetX[t]),Math.abs(this.offsetY[t]),Math.abs(this.targetX[t]),Math.abs(this.targetY[t]));const e=Math.round(this.offsetX[t]*this.edge[t]*32767+32768),h=Math.round(this.offsetY[t]*this.edge[t]*32767+32768);this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e,this.pixels[4*t+2]=h>>>8,this.pixels[4*t+3]=255&h}this.peak=n,this.active||this.clear()}sample(t,e,i){const s=Math.max(0,Math.min(this.width-1.001,t*(this.width-1))),n=Math.max(0,Math.min(this.height-1.001,e*(this.height-1))),h=Math.floor(s),o=Math.floor(n),r=s-h,l=n-o,c=o*this.width+h,m=c+this.width,d=t=>(t[c]*(1-r)+t[c+1]*r)*(1-l)+(t[m]*(1-r)+t[m+1]*r)*l;i[0]=d(this.offsetX)*a(t,e,this.width/this.height)*.08,i[1]=d(this.offsetY)*a(t,e,this.width/this.height)*.08,i[2]="dissolve"===this.mode?6*-d(this.ink):0}},r=class{constructor(t,e){this.rings=[],this.previous=null,this.elapsed=1,this.echoPeak=0,this.width=t,this.height=e,this.pixels=new Uint8Array(t*e*4),this.echo=new Float32Array(t*e)}get active(){return this.rings.length>0||this.echoPeak>2e-4}clear(){this.rings=[],this.previous=null,this.elapsed=1,this.pixels.fill(0),this.echo.fill(0),this.echoPeak=0}leave(){this.previous=null}move(t,e,i){const s=Math.max(1,this.width/this.height),n=Math.max(1,this.height/this.width);this.previous&&(Math.hypot((t-this.previous.x)*s,(e-this.previous.y)*n)<.065||this.elapsed<.3)||4!==this.rings.length&&(this.previous={x:t,y:e},this.elapsed=0,this.rings.push({x:t,y:e,age:0,radius:i}))}ringSample(t,e){const i=Math.max(1,this.width/this.height),s=Math.max(1,this.height/this.width);let n=0;for(const h of this.rings){const a=.015+h.age*(.15+.22*h.radius),o=.009+.014*h.radius,r=(Math.hypot((t-h.x)*i,(e-h.y)*s)-a)/o,l=Math.sin(Math.min(1,h.age/.07)*Math.PI/2)*Math.max(0,1-h.age/1.35)**2;n=Math.max(n,Math.exp(-r*r)*l)}return n}sample(t,e){const i=Math.max(0,Math.min(this.width-1,Math.round(t*(this.width-1)))),s=Math.max(0,Math.min(this.height-1,Math.round(e*(this.height-1))));return Math.max(this.ringSample(t,e),this.echo[s*this.width+i])}step(t){if(!Number.isFinite(t))return;const e=Math.max(0,Math.min(.05,t));this.elapsed+=e;for(const t of this.rings)t.age+=e;if(this.rings=this.rings.filter(t=>t.age<1.35),!this.active)return void this.pixels.fill(0);const i=Math.exp(-5.5*e);let s=0;for(let t=0;t<this.height;t++)for(let e=0;e<this.width;e++){const n=t*this.width+e;this.echo[n]=Math.max(this.ringSample(e/(this.width-1),t/(this.height-1)),this.echo[n]*i),s=Math.max(s,this.echo[n]);const h=Math.round(65535*this.echo[n]),a=4*n;this.pixels[a]=h>>>8,this.pixels[a+1]=255&h}this.echoPeak=s,this.active||(this.echo.fill(0),this.pixels.fill(0))}},l=class{constructor(t,e){this.previous=null,this.remainder=0,this.peak=0,this.width=t,this.height=e;const i=t*e;this.pixels=new Uint8Array(4*i),this.u=new Float32Array(i),this.v=new Float32Array(i),this.ink=new Float32Array(i),this.a=new Float32Array(i),this.b=new Float32Array(i),this.c=new Float32Array(i),this.pressure=new Float32Array(i),this.pressureNext=new Float32Array(i),this.divergence=new Float32Array(i),this.curl=new Float32Array(i)}get active(){return this.peak>2e-4}clear(){for(const t of[this.u,this.v,this.ink,this.a,this.b,this.c,this.pressure,this.pressureNext,this.divergence,this.curl,this.pixels])t.fill(0);this.previous=null,this.peak=0,this.remainder=0}leave(){this.previous=null}move(t,e,i){const s=this.previous;if(this.previous={x:t,y:e},!s)return;const n=(t-s.x)*(this.width-1),h=(e-s.y)*(this.height-1),a=Math.hypot(n,h);if(a<.001)return;const o=Math.min(this.width,this.height)*(.038+.12*i),r=Math.min(128,Math.max(1,Math.ceil(a/(.5*o)))),l=a/o*.95/r;for(let i=0;i<r;i++){const a=(i+.5)/r,c=(s.x+(t-s.x)*a)*(this.width-1),m=(s.y+(e-s.y)*a)*(this.height-1),d=Math.max(1,Math.floor(c-2.5*o)),u=Math.min(this.width-2,Math.ceil(c+2.5*o)),f=Math.max(1,Math.floor(m-2.5*o)),g=Math.min(this.height-2,Math.ceil(m+2.5*o));for(let t=f;t<=g;t++)for(let e=d;e<=u;e++){const i=Math.exp(-((e-c)**2+(t-m)**2)/(o*o)),s=t*this.width+e;this.ink[s]=Math.min(1,this.ink[s]+i*l),this.u[s]=Math.max(-50,Math.min(50,this.u[s]+n*i*5/r)),this.v[s]=Math.max(-50,Math.min(50,this.v[s]+h*i*5/r))}}this.peak=1}read(t,e,i){const s=0|(e=Math.max(.5,Math.min(this.width-1.5,e))),n=0|(i=Math.max(.5,Math.min(this.height-1.5,i))),h=e-s,a=i-n,o=n*this.width+s;return(t[o]*(1-h)+t[o+1]*h)*(1-a)+(t[o+this.width]*(1-h)+t[o+this.width+1]*h)*a}sample(t,e){return this.read(this.ink,t*(this.width-1),e*(this.height-1))}step(t){if(!this.active||!Number.isFinite(t))return;this.remainder+=Math.max(0,Math.min(.05,t));const e=1/60,i=this.width,s=this.height;for(;this.remainder+1e-8>=e;){this.remainder-=e;for(let t=1;t<s-1;t++)for(let s=1;s<i-1;s++){const n=t*i+s,h=s-this.u[n]*e,a=t-this.v[n]*e;this.a[n]=.972*this.read(this.u,h,a),this.b[n]=.972*this.read(this.v,h,a),this.c[n]=.964*this.read(this.ink,h,a)}[this.u,this.a]=[this.a,this.u],[this.v,this.b]=[this.b,this.v],[this.ink,this.c]=[this.c,this.ink];for(let t=1;t<s-1;t++)for(let e=1;e<i-1;e++){const s=t*i+e;this.curl[s]=.5*(this.v[s+1]-this.v[s-1]-this.u[s+i]+this.u[s-i])}for(let t=1;t<s-1;t++)for(let s=1;s<i-1;s++){const n=t*i+s,h=Math.abs(this.curl[n+1])-Math.abs(this.curl[n-1]),a=Math.abs(this.curl[n+i])-Math.abs(this.curl[n-i]),o=Math.hypot(h,a)+1e-4,r=this.curl[n]*e*5;this.u[n]+=a/o*r,this.v[n]-=h/o*r,this.divergence[n]=-.5*(this.u[n+1]-this.u[n-1]+this.v[n+i]-this.v[n-i])}this.pressure.fill(0);for(let t=0;t<4;t++){for(let t=1;t<s-1;t++)for(let e=1;e<i-1;e++){const s=t*i+e;this.pressureNext[s]=.25*(this.divergence[s]+this.pressure[s-1]+this.pressure[s+1]+this.pressure[s-i]+this.pressure[s+i])}[this.pressure,this.pressureNext]=[this.pressureNext,this.pressure]}let t=0;for(let e=1;e<s-1;e++)for(let s=1;s<i-1;s++){const n=e*i+s;this.u[n]=Math.max(-50,Math.min(50,this.u[n]-.5*(this.pressure[n+1]-this.pressure[n-1]))),this.v[n]=Math.max(-50,Math.min(50,this.v[n]-.5*(this.pressure[n+i]-this.pressure[n-i]))),t=Math.max(t,this.ink[n])}this.peak=t}if(this.active)for(let t=0;t<this.ink.length;t++){const e=Math.round(65535*Math.min(1,this.ink[t]));this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e}else this.clear()}},c=t=>["trail","contour","dissolve"].includes(t),m=class{constructor(t=1){this.mode="water",this.amount=.55,this.radius=.2,this.lensX=.5,this.lensY=.5,this.lensStrength=0,this.previous=null,this.energy=0,this.pending=!1,this.remainder=0,t=Math.max(.25,Math.min(4,t)),this.columns=Math.round(t>=1?128:128*t),this.rows=Math.round(t>=1?128/t:128),this.xScale=Math.max(1,t),this.yScale=Math.max(1,1/t),this.heights=new Float32Array(this.columns*this.rows),this.velocity=new Float32Array(this.heights.length),this.next=new Float32Array(this.heights.length),this.normals=new Float32Array(2*this.heights.length),this.edgeMask=new Float32Array(this.heights.length);for(let e=0;e<this.rows;e++)for(let i=0;i<this.columns;i++)this.edgeMask[e*this.columns+i]=a(i/(this.columns-1),e/(this.rows-1),t);this.refraction={width:this.columns,height:this.rows,pixels:new Uint8Array(4*this.heights.length),strength:30,mode:"water",focus:[.5,.5,0,.2]},this.waterPixels=this.refraction.pixels,this.trail=new l(this.columns,this.rows),this.contour=new r(this.columns,this.rows),this.afterimage=new o(this.columns,this.rows),this.clear()}get densityTrail(){return["trail","contour","dissolve"].includes(this.mode)}get hasRefraction(){return this.active||this.lensStrength>15e-5}get active(){return["dissolve","silk","vortex"].includes(this.mode)?this.afterimage.active:"contour"===this.mode?this.contour.active:"trail"===this.mode?this.trail.active:this.pending||this.energy>15e-5}setMode(t){t!==this.mode&&(this.clear(),this.mode=t,this.refraction.mode=t,"dissolve"!==t&&"silk"!==t&&"vortex"!==t||this.afterimage.setMode(t),this.refraction.pixels="trail"===t?this.trail.pixels:"contour"===t?this.contour.pixels:["dissolve","silk","vortex"].includes(t)?this.afterimage.pixels:this.waterPixels,this.refraction.strength="water"===t?30*this.amount/.55:"silk"===t?28*this.amount:"vortex"===t?38*this.amount:0)}configure(t,e=.55,i=.2){this.setMode(t),this.amount=Number.isFinite(e)?Math.max(0,Math.min(1,e)):.55,this.radius=Number.isFinite(i)?Math.max(.1,Math.min(1,i)):.2,this.refraction.strength="water"===t?30*this.amount/.55:"silk"===t?28*this.amount:"vortex"===t?38*this.amount:0,this.refraction.focus[2]=this.densityTrail?this.amount:this.lensStrength*this.amount,this.refraction.focus[3]=this.radius}move(t,e){if("none"===this.mode||0===this.amount)return;if(!Number.isFinite(t+e))return;if(t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e)),["dissolve","silk","vortex"].includes(this.mode))return void this.afterimage.move(t,e,this.radius);if("contour"===this.mode)return void this.contour.move(t,e,this.radius);if("trail"===this.mode)return void this.trail.move(t,e,this.radius);if("water"!==this.mode)return!this.previous&&this.lensStrength<.001&&(this.lensX=t,this.lensY=e),this.previous={x:t,y:e},void(this.pending=!0);if(!this.previous)return void(this.previous={x:t,y:e});const i=this.previous;this.previous={x:t,y:e};const s=(t-i.x)*this.xScale,n=(e-i.y)*this.yScale,h=Math.hypot(s,n);if(h<1e-5)return;const a=.035+.1*this.radius,o=3*a,r=Math.min(192,Math.max(1,Math.ceil(h/(.5*a)))),l=95*Math.min(h,1)/r;for(let s=0;s<r;s++){const n=(s+.5)/r,h=i.x+(t-i.x)*n,c=i.y+(e-i.y)*n,m=Math.max(1,Math.floor((h-o/this.xScale)*(this.columns-1))),d=Math.min(this.columns-2,Math.ceil((h+o/this.xScale)*(this.columns-1))),u=Math.max(1,Math.floor((c-o/this.yScale)*(this.rows-1))),f=Math.min(this.rows-2,Math.ceil((c+o/this.yScale)*(this.rows-1)));for(let t=u;t<=f;t++)for(let e=m;e<=d;e++){const i=(e/(this.columns-1)-h)*this.xScale,s=(t/(this.rows-1)-c)*this.yScale,n=Math.exp(-(i*i+s*s)/(a*a))*l,o=t*this.columns+e;this.velocity[o]=Math.max(-12,this.velocity[o]-n)}}this.pending=!0}leave(){this.afterimage.leave(),this.contour.leave(),this.trail.leave(),this.previous=null,"water"!==this.mode&&this.lensStrength&&(this.pending=!0)}clear(){this.trail.clear(),this.contour.clear(),this.afterimage.clear(),this.heights.fill(0),this.velocity.fill(0),this.next.fill(0),this.normals.fill(0),this.refraction.focus[2]=0,this.previous=null,this.lensStrength=0,this.energy=0,this.pending=!1,this.remainder=0;for(let t=0;t<this.waterPixels.length;t+=4)this.waterPixels[t]=this.waterPixels[t+2]=128,this.waterPixels[t+1]=this.waterPixels[t+3]=0}step(t){if(!this.active||!Number.isFinite(t))return;if(["dissolve","silk","vortex"].includes(this.mode))return void this.afterimage.step(t);if("contour"===this.mode)return void this.contour.step(t);if("trail"===this.mode)return void this.trail.step(t);if("water"!==this.mode)return void this.stepLight(Math.max(0,Math.min(.05,t)));this.remainder+=Math.max(0,Math.min(.05,t));const e=1/120,i=Math.exp(-3.8*e),s=.3*Math.min(this.columns,this.rows);for(;this.remainder+1e-8>=e;){this.remainder-=e;let t=0;for(let n=1;n<this.rows-1;n++)for(let h=1;h<this.columns-1;h++){const a=n*this.columns+h,o=this.heights[a],r=this.heights[a-1]+this.heights[a+1]+this.heights[a-this.columns]+this.heights[a+this.columns]-4*o,l=Math.min(h,n,this.columns-1-h,this.rows-1-n),c=l<5?.88+.024*l:1,m=(this.velocity[a]+(r*s*s-8*o)*e)*i*c;this.velocity[a]=m,this.next[a]=(o+m*e)*c,t=Math.max(t,Math.abs(this.next[a]),.1*Math.abs(m))}this.heights.set(this.next),this.energy=t,this.pending=!1}if(!this.active)return void this.clear();const n=.18*Math.min(this.columns,this.rows);for(let t=0;t<this.rows;t++)for(let e=0;e<this.columns;e++){const i=t*this.columns+e,s=(this.heights[t*this.columns+Math.max(0,e-1)]-this.heights[t*this.columns+Math.min(this.columns-1,e+1)])*n,h=(this.heights[Math.max(0,t-1)*this.columns+e]-this.heights[Math.min(this.rows-1,t+1)*this.columns+e])*n,a=Math.tanh(s)*this.edgeMask[i],o=Math.tanh(h)*this.edgeMask[i];this.normals[2*i]=a,this.normals[2*i+1]=o;const r=Math.round(32767*a+32768),l=Math.round(32767*o+32768);this.refraction.pixels[4*i]=r>>>8,this.refraction.pixels[4*i+1]=255&r,this.refraction.pixels[4*i+2]=l>>>8,this.refraction.pixels[4*i+3]=255&l}}stepLight(t){const e=this.previous,i=1-Math.exp(-30*t),s=1-Math.exp(-12*t);e&&(this.lensX+=(e.x-this.lensX)*i,this.lensY+=(e.y-this.lensY)*i),this.lensStrength+=((e?1:0)-this.lensStrength)*s,this.energy=Math.max(e?Math.abs(e.x-this.lensX)+Math.abs(e.y-this.lensY):0,Math.abs((e?1:0)-this.lensStrength)),this.pending=!1,e||this.active?this.refraction.focus=[this.lensX,this.lensY,this.lensStrength*this.amount,this.radius]:this.clear()}sample(t,e,i){if(["dissolve","silk","vortex"].includes(this.mode))return this.afterimage.sample(t,e,i),i[0]*=this.amount,i[1]*=this.amount,void(i[2]*=this.amount);if("contour"===this.mode)return i[0]=i[1]=0,void(i[2]=this.contour.sample(t,e)*this.amount*3);if("trail"===this.mode)return i[0]=i[1]=0,void(i[2]=this.trail.sample(t,e)*this.amount*3);const s=Math.max(0,Math.min(this.columns-1.001,t*(this.columns-1))),n=Math.max(0,Math.min(this.rows-1.001,e*(this.rows-1))),h=Math.floor(s),a=Math.floor(n),o=s-h,r=n-a,l=2*(a*this.columns+h),c=l+2*this.columns;for(let t=0;t<2;t++)i[t]=.08*((this.normals[l+t]*(1-o)+this.normals[l+2+t]*o)*(1-r)+(this.normals[c+t]*(1-o)+this.normals[c+2+t]*o)*r);i[0]*=this.amount/.55,i[1]*=this.amount/.55,i[2]="light"===this.mode||"scan"===this.mode?function(t,e,i,s){const[n,h,a,o]=i.focus,r=(t-n)*Math.max(1,s)/o,l=(e-h)*Math.max(1,1/s)/o;return"light"===i.mode?Math.exp(-3*(r*r+l*l))*a:"scan"===i.mode?(1.3*Math.exp(-r*r*110)-.3*Math.exp(-r*r*12))*Math.exp(-l*l*1.8)*a:0}(t,e,this.refraction,this.xScale/this.yScale):0}};function d(t){const e=Intl.Segmenter;return e?Array.from(new e(void 0,{granularity:"grapheme"}).segment(t),t=>t.segment):Array.from(t)}function u(){const t=document.createElement("canvas"),e=document.createElement("canvas"),i=t.getContext("2d"),s=e.getContext("2d",{willReadFrequently:!0});let n,h=null;return{update(a,o,r,l,c,m,u,f){const g=u?.[0]?.length??Math.max(1,Math.round(o/l)),p=u?.length??Math.max(1,Math.round(r/c)),x=f??{charset:" .:-=+*#%@",customText:"",colorMode:"fullcolor"},v=x.charset+(x.charsetFrames?.join("")??""),M=function(t,e,i,s,n,h,a,o=4096,r=0){if(![i,s,n,h,a,o].every(t=>Number.isFinite(t)&&t>0))throw new Error("Glyph atlas dimensions must be positive and finite.");const l=JSON.stringify([e.charset,e.customText,i,s,n,h,a,o,r]);if(t?.key===l)return t;const c=[...new Set([" ",...d(e.charset),...d(e.customText??"")])];if(c.length>65536)throw new Error("This character set exceeds the glyph texture capacity.");const m=i/h,u=s/a,f=.9*Math.min(m/.55,u),g=Math.ceil(m*n)+4,p=Math.ceil(u*n)+4,x=Math.min(c.length,Math.floor(o/g));if(x<1||Math.ceil(c.length/x)*p>o)throw new Error("The glyph atlas exceeds the available GPU texture size.");return{key:l,glyphs:c,indices:new Map(c.map((t,e)=>[t,e])),cellWidth:m,cellHeight:u,fontSize:f,padding:2,tileWidth:g,tileHeight:p,atlasColumns:x,atlasWidth:x*g,atlasHeight:Math.ceil(c.length/x)*p}}(h,{...x,charset:v},o,r,m,g,p);if(M!==h&&(t.width=M.atlasWidth,t.height=M.atlasHeight,i.font=M.fontSize*m+'px "JetBrains Mono", monospace',i.textAlign="center",i.textBaseline="middle",i.fillStyle="#fff",M.glyphs.forEach((t,e)=>i.fillText(t,e%M.atlasColumns*M.tileWidth+M.padding+M.cellWidth*m*.5,Math.floor(e/M.atlasColumns)*M.tileHeight+M.padding+M.cellHeight*m*.5))),h=M,u){n=function(t,e,i,s,n=!1){const h=t.length,a=t[0]?.length??0,o=s?.cols===a&&s.rows===h?s:{cols:a,rows:h,indices:new Uint8Array(a*h*4),colors:new Uint8ClampedArray(a*h*4)};o.indices.fill(0),o.colors.fill(0);const r="accent"===i.colorMode?[1,3,5].map(t=>parseInt(i.accentColor.slice(t,t+2),16)):null;for(let s=0;s<h;s++){if(t[s].length!==a)throw new Error("Glyph frames must have a rectangular cell grid.");for(let h=0;h<a;h++){const l=t[s][h];if(!l.char||!n&&" "===l.char||l.a<10)continue;const c=e.get(l.char);if(void 0===c)throw new Error(`Glyph is absent from the configured character set: ${l.char}`);const m=4*(s*a+h);let d=l.r,u=l.g,f=l.b;if(r)[d,u,f]=r;else if("fullcolor"!==i.colorMode){const t=.299*d+.587*u+.114*f|0;d="matrix"===i.colorMode?0:t,u=t,f=d}(n||0!==d||0!==u||0!==f)&&(o.indices[m]=255&c,o.indices[m+1]=c>>>8,o.colors[m]=d,o.colors[m+1]=u,o.colors[m+2]=f,o.colors[m+3]=l.a)}}return o}(u,h.indices,x,n,!0);for(let t=0;t<p;t++)for(let e=0;e<g;e++){const i=u[t][e],s=4*(t*g+e);n.indices[s+2]=Math.round(.299*i.r+.587*i.g+.114*i.b)}}else{e.width=g,e.height=p,s.drawImage(a,0,0,g,p);const t=s.getImageData(0,0,g,p).data;n={cols:g,rows:p,indices:new Uint8Array(g*p*4),colors:new Uint8ClampedArray(t)};for(let e=0;e<t.length;e+=4){const i=Math.min(1,(.299*t[e]+.587*t[e+1]+.114*t[e+2])/255*(t[e+3]/255)*3);n.indices[e+2]=Math.round(255*i),n.indices[e]=Math.min(h.glyphs.length-1,Math.floor(i*h.glyphs.length))}}return{plan:h,packed:n,atlas:t,dots:"dots"===x.renderMode,dotSize:x.dotSizeRatio??.72}},destroy(){t.width=t.height=e.width=e.height=1,n=void 0,h=null}}}function f(t,i,a={}){let o={effect:"trail",strength:.55,radius:.2,animated:!1,fps:30,fontSize:7,charAspect:.58,charSpacing:1,paused:!1,charset:" .:-=+*#%@",customText:"",renderMode:"ascii",dotSizeRatio:.72,...a},r=new m(i.clientWidth/Math.max(1,i.clientHeight)),l=!1,d=!1,f=!0,g=0,p=0,x=-1/0,v=0,M=null,w=!1;const y=matchMedia("(prefers-reduced-motion: reduce)"),S=()=>{l||!d||document.hidden||g||(g=requestAnimationFrame(b))},E=function(t,i,a){const o=i.style.visibility;let r=document.createElement("canvas"),l=null,m=null,d=null,f=null;const g=[],p=[];let x=!1,v=!1,M=4096;const w=document.createElement("canvas"),y=document.createElement("canvas"),S=w.getContext("2d"),E=y.getContext("2d");let b=!1;const T=new n,A=u();let k=null,R={};const z=()=>{r.className="ascii-hover-surface",r.style.cssText="position:absolute;inset:0;width:100%;height:100%;pointer-events:none",r.setAttribute("role","img"),r.setAttribute("aria-label","ASCII artwork preview"),r.dataset.renderer=l?"surface-gpu":"surface-canvas",t.prepend(r),i.style.visibility="hidden"},_=()=>{l&&(g.forEach(t=>l.deleteTexture(t)),p.forEach(t=>l.deleteShader(t)),d&&l.deleteProgram(d),f&&l.deleteBuffer(f))},D=()=>{x||m||(r.removeEventListener("webglcontextlost",D),_(),r.remove(),l=null,r=document.createElement("canvas"),m=r.getContext("2d"),z(),a())};try{if(l=r.getContext("webgl",{alpha:!0,antialias:!1,depth:!1,stencil:!1,premultipliedAlpha:!0,preserveDrawingBuffer:!0}),!l)throw new Error("WebGL unavailable");M=l.getParameter(l.MAX_TEXTURE_SIZE);const t=(t,e)=>{const i=l.createShader(t);if(p.push(i),l.shaderSource(i,e),l.compileShader(i),!l.getShaderParameter(i,l.COMPILE_STATUS))throw new Error(l.getShaderInfoLog(i)||"Shader compilation failed");return i};if(d=l.createProgram(),l.attachShader(d,t(l.VERTEX_SHADER,"attribute vec2 position; void main(){gl_Position=vec4(position,0.,1.);}")),l.attachShader(d,t(l.FRAGMENT_SHADER,"\n precision highp float;\n uniform sampler2D artwork; uniform sampler2D surface;\n uniform vec2 resolution; uniform vec2 sceneSize; uniform vec2 cellSize;\n uniform vec2 surfaceSize; uniform float strength;\n \nuniform float hoverMode;\nuniform vec4 hoverFocus;\nfloat surfaceLight(vec2 uv, vec2 size) {\n vec2 delta = (uv - hoverFocus.xy) * size / min(size.x, size.y) / hoverFocus.w;\n float light = exp(-3.0 * dot(delta, delta));\n if (hoverMode > 1.5) light = (exp(-delta.x * delta.x * 110.0) * 1.3 - exp(-delta.x * delta.x * 12.0) * .3) * exp(-delta.y * delta.y * 1.8);\n return hoverMode > .5 ? light * hoverFocus.z : 0.0;\n}\nvec3 illuminate(vec3 ink, float light) {\n return mix(ink, vec3(1.0), max(0.0, light) * .82) * (1.0 + min(0.0, light));\n}\n\n uniform sampler2D codes; uniform sampler2D cellColors; uniform sampler2D glyphAtlas;\n uniform vec2 gridSize; uniform vec2 atlasSize; uniform vec2 tileSize;\n uniform float atlasColumns; uniform float padding; uniform float glyphCount;\n uniform float dots; uniform float dotSize;\n \nuniform float trailAmount;\nuniform float trailKind;\nfloat trailDensity(vec2 address) {\n vec2 encodedInk = texture2D(surface, (address * (surfaceSize - 1.0) + .5) / surfaceSize).rg;\n return (encodedInk.r * 65280.0 + encodedInk.g * 255.0) / 65535.0 * trailAmount;\n}\nvec3 trailInk(vec3 ink, float density) {\n float peak=max(ink.r,max(ink.g,ink.b));\n float raised=trailKind>1.5?peak:max(peak,min(.44,density*.75));\n return peak>.001 ? ink*(raised/peak) : vec3(raised);\n}\nfloat trailIndex(float index, float count, float density, vec2 cell) {\n // A stable cell pattern gives Dissolve a granular edge without random flicker.\n float grain=fract((cell.x*cell.x*17.0+cell.y*cell.y*23.0+cell.x*cell.y*19.0)*.0137);\n if(trailKind>1.5) return max(0.0,index-floor(density*count*(1.35+grain*.9)));\n return min(count - 1.0, index + floor(density * count * .85));\n}\n\n \n uniform float motionMode; uniform float motionTime; uniform float fineDither; uniform float ditherAmount;\n float printGrain(vec2 p) { return fract(52.9829189*fract(dot(p,vec2(.06711056,.00583715)))); }\n vec4 ambientAt(vec2 uv) {\n float p=motionTime*.5235987756;\n float edge=smoothstep(0.,.12,min(min(uv.x,1.-uv.x),min(uv.y,1.-uv.y)));\n if(motionMode<.5) return vec4(0.,0.,0.,1.);\n if(motionMode<1.5) return vec4(0.,0.,sin(uv.x*9.+uv.y*5.+p)*cos(uv.y*8.-uv.x*3.-p)*.065*edge,.9+.1*sin(uv.x*6.-uv.y*4.+p));\n if(motionMode<2.5) return vec4(sin(uv.y*9.+p)*cos(uv.x*7.-p)*6.*edge,cos(uv.x*8.+p)*sin(uv.y*6.-p)*4.*edge,0.,1.);\n float cycle=mod(motionTime,12.);\n float order=uv.x*.8+uv.y*.2+sin(uv.x*8.-uv.y*5.)*.08;\n float gone=smoothstep(1.8+order*1.2,3.8+order*1.2,cycle)*(1.-smoothstep(5.+order*1.7,7.2+order*1.7,cycle));\n return vec4(0.,0.,-gone*.95,1.-gone*.82);\n }\n\n float toneAt(vec2 uv) {\n vec2 p=uv*gridSize-.5, b=floor(p), f=fract(p);\n return mix(mix(texture2D(codes,(b+.5)/gridSize).b,texture2D(codes,(b+vec2(1.5,.5))/gridSize).b,f.x),mix(texture2D(codes,(b+vec2(.5,1.5))/gridSize).b,texture2D(codes,(b+1.5)/gridSize).b,f.x),f.y);\n }\n void main(){\n vec2 uv = vec2(gl_FragCoord.x, resolution.y - gl_FragCoord.y) / resolution;\n vec2 pixel = uv * sceneSize;\n if (strength > 0.) {\n vec4 normal = texture2D(surface, (uv * (surfaceSize - 1.) + .5) / surfaceSize) * 255.;\n vec2 slope = (vec2(normal.r * 256. + normal.g, normal.b * 256. + normal.a) - 32768.) / 32767.;\n vec2 edge = min(pixel, sceneSize - pixel) / cellSize;\n uv -= slope * strength * smoothstep(2.,8.,min(edge.x,edge.y)) / sceneSize;\n }\n vec4 ambient=ambientAt(uv);\n uv -= ambient.xy/sceneSize;\n pixel=uv*sceneSize;\n vec4 ink = texture2D(artwork, uv);\n if (fineDither > .5) {\n vec2 cell=floor(pixel/cellSize),address=(cell+.5)/gridSize;\n vec4 color=texture2D(cellColors,address);\n float density=trailAmount>0.?trailDensity(address):0.;\n float tone=clamp(toneAt(uv)+ambient.z+(trailKind>1.5?-density:density)*.65,0.,1.);\n float pitch=max(1.,min(cellSize.x,cellSize.y)*.32);\n float grain=.5+(printGrain(floor(pixel/pitch))-.5)*ditherAmount;\n float alpha=(tone<.001?0.:tone>.999?1.:smoothstep(grain-.035,grain+.035,tone))*color.a*ambient.w;\n // Preserve hue; tone is carried by mark coverage rather than muddy ink.\n vec3 hue=color.rgb/max(.001,max(color.r,max(color.g,color.b)));\n gl_FragColor=vec4(hue*alpha,alpha); return;\n }\n if (trailAmount > 0. || motionMode > .5) {\n vec2 cell=floor(pixel/cellSize), address=(cell+.5)/gridSize;\n float density=trailAmount>0.?trailDensity(address):0.;\n vec4 encoded=texture2D(codes,address);\n float original=floor(encoded.r*255.+.5)+floor(encoded.g*255.+.5)*256.;\n float index=trailIndex(original,glyphCount,density,cell);\n if(original>.5) index=clamp(floor(index+ambient.z*(glyphCount-1.)+printGrain(cell)),0.,glyphCount-1.);\n vec4 color=texture2D(cellColors,address);\n if((index!=original || motionMode>.5) && color.a>.01) {\n vec2 local=(pixel-cell*cellSize)*resolution/sceneSize;\n vec2 slot=vec2(mod(index,atlasColumns),floor(index/atlasColumns));\n float alpha=texture2D(glyphAtlas,(slot*tileSize+padding+local)/atlasSize).a;\n if(dots>.5) {\n vec2 d=(pixel-(cell+.5)*cellSize)/min(cellSize.x,cellSize.y);\n float r=min(.48,(index/(glyphCount-1.))*.5*dotSize);\n alpha=1.-smoothstep(r-.06,r+.02,length(d));\n }\n // Replace the cell, rather than blending two glyphs into a ghost.\n vec3 rgb=trailInk(color.rgb,density);\n ink=vec4(rgb*alpha*color.a,alpha*color.a);\n }\n }\n vec3 straightInk = ink.a > .0 ? ink.rgb / ink.a : vec3(.0);\n float value = max(straightInk.r, max(straightInk.g, straightInk.b));\n // Lighting belongs to character ink; black/transparent gaps stay empty.\n float light = surfaceLight((floor(pixel / cellSize) + .5) * cellSize / sceneSize, sceneSize);\n vec3 lit = illuminate(straightInk, light * smoothstep(0., .22, value)) * ink.a;\n gl_FragColor = vec4(lit, ink.a)*ambient.w;\n }")),l.linkProgram(d),!l.getProgramParameter(d,l.LINK_STATUS))throw new Error("Surface shader link failed");l.useProgram(d),f=l.createBuffer(),l.bindBuffer(l.ARRAY_BUFFER,f),l.bufferData(l.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,1]),l.STATIC_DRAW);const e=l.getAttribLocation(d,"position");l.enableVertexAttribArray(e),l.vertexAttribPointer(e,2,l.FLOAT,!1,0,0),R=Object.fromEntries(["artwork","surface","resolution","sceneSize","cellSize","surfaceSize","strength","hoverMode","hoverFocus","codes","cellColors","glyphAtlas","gridSize","atlasSize","tileSize","atlasColumns","padding","glyphCount","dots","dotSize","trailKind","trailAmount","motionMode","motionTime","fineDither","ditherAmount"].map(t=>[t,l.getUniformLocation(d,t)]));for(let t=0;t<5;t++){const e=l.createTexture();g.push(e),l.activeTexture(l.TEXTURE0+t),l.bindTexture(l.TEXTURE_2D,e),l.texParameteri(l.TEXTURE_2D,l.TEXTURE_MIN_FILTER,l.LINEAR),l.texParameteri(l.TEXTURE_2D,l.TEXTURE_MAG_FILTER,l.LINEAR),l.texImage2D(l.TEXTURE_2D,0,l.RGBA,1,1,0,l.RGBA,l.UNSIGNED_BYTE,new Uint8Array(4)),l.texParameteri(l.TEXTURE_2D,l.TEXTURE_WRAP_S,l.CLAMP_TO_EDGE),l.texParameteri(l.TEXTURE_2D,l.TEXTURE_WRAP_T,l.CLAMP_TO_EDGE)}l.uniform1i(R.codes,2),l.uniform1i(R.cellColors,3),l.uniform1i(R.glyphAtlas,4),l.uniform1i(R.artwork,0),l.uniform1i(R.surface,1),l.pixelStorei(l.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1),l.disable(l.BLEND),l.disable(l.DEPTH_TEST),r.addEventListener("webglcontextlost",D),z()}catch{D()}return{get canvas(){return r},render(t,n,a,o,d,u,f,p,z=0){const _=e(p?.animationStyle),C=T.update(z,_,p?.animationSpeed),F=(t=>"terminal"===t?.artStyle&&!t.customText&&!t.charsetFrames?.length&&!/[A-Za-z]/.test(t.charset??""))(p);if(x||!a||!o||!i.width||!i.height)return;const I=Math.min(i.width/a,1.5,Math.sqrt(4e6/(a*o))),P=Math.max(1,Math.round(a*I)),U=Math.max(1,Math.round(o*I));if(r.width===P&&r.height===U||(r.width=P,r.height=U,v=!1),l&&(i.width>M||i.height>M)&&D(),(c(n.mode)||"none"!==_||F)&&(t||!v||!k)&&(k=A.update(i,a,o,d,u,I,f,p),l)){const{plan:t,packed:e,atlas:i}=k;for(const[t,i]of[[2,e.indices],[3,e.colors]])l.activeTexture(l.TEXTURE0+t),l.bindTexture(l.TEXTURE_2D,g[t]),l.texParameteri(l.TEXTURE_2D,l.TEXTURE_MIN_FILTER,l.NEAREST),l.texParameteri(l.TEXTURE_2D,l.TEXTURE_MAG_FILTER,l.NEAREST),l.texImage2D(l.TEXTURE_2D,0,l.RGBA,e.cols,e.rows,0,l.RGBA,l.UNSIGNED_BYTE,i);l.activeTexture(l.TEXTURE4),l.bindTexture(l.TEXTURE_2D,g[4]),l.texImage2D(l.TEXTURE_2D,0,l.RGBA,l.RGBA,l.UNSIGNED_BYTE,i),l.uniform2f(R.gridSize,e.cols,e.rows),l.uniform2f(R.atlasSize,t.atlasWidth,t.atlasHeight),l.uniform2f(R.tileSize,t.tileWidth,t.tileHeight),l.uniform1f(R.atlasColumns,t.atlasColumns),l.uniform1f(R.padding,t.padding),l.uniform1f(R.glyphCount,t.glyphs.length),l.uniform1f(R.dots,k.dots?1:0),l.uniform1f(R.dotSize,k.dotSize)}if(l)l.uniform1f(R.motionMode,(t=>["none","print","current","reform"].indexOf(t))(_)),l.uniform1f(R.motionTime,C),l.uniform1f(R.fineDither,F?1:0),l.uniform1f(R.ditherAmount,Math.max(0,Math.min(2,p?.ditherStrength??1))),l.uniform1f(R.trailKind,"dissolve"===n.mode?2:0),l.uniform1f(R.trailAmount,c(n.mode)?n.focus[2]:0),l.viewport(0,0,P,U),!t&&v||(l.activeTexture(l.TEXTURE0),l.bindTexture(l.TEXTURE_2D,g[0]),l.pixelStorei(l.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!0),l.texImage2D(l.TEXTURE_2D,0,l.RGBA,l.RGBA,l.UNSIGNED_BYTE,i),l.pixelStorei(l.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1),v=!0),l.activeTexture(l.TEXTURE1),l.bindTexture(l.TEXTURE_2D,g[1]),l.texImage2D(l.TEXTURE_2D,0,l.RGBA,n.width,n.height,0,l.RGBA,l.UNSIGNED_BYTE,n.pixels),l.uniform2f(R.resolution,P,U),l.uniform2f(R.sceneSize,a,o),l.uniform2f(R.cellSize,d,u),l.uniform2f(R.surfaceSize,n.width,n.height),l.uniform1f(R.strength,n.strength),l.uniform1f(R.hoverMode,"light"===n.mode?1:"scan"===n.mode?2:0),l.uniform4fv(R.hoverFocus,n.focus),l.drawArrays(l.TRIANGLE_STRIP,0,4);else if(m)if(m.setTransform(I,0,0,I,0,0),m.clearRect(0,0,a,o),m.drawImage(i,0,0,a,o),("none"!==_||F)&&k){m.clearRect(0,0,a,o);const{plan:t,packed:e,atlas:i}=k,r=[0,0,0,1],l=Math.max(1,.32*Math.min(d,u));for(let a=0;a<e.rows;a++)for(let o=0;o<e.cols;o++){const f=(o+.5)/e.cols,g=(a+.5)/e.rows,x=4*(a*e.cols+o);if(e.colors[x+3]<10)continue;h(_,f,g,C,r);const v=4*(Math.min(n.height-1,Math.round(g*(n.height-1)))*n.width+Math.min(n.width-1,Math.round(f*(n.width-1)))),M=c(n.mode)?(256*n.pixels[v]+n.pixels[v+1])/65535*n.focus[2]:0,w=e.indices[x]+256*e.indices[x+1];let y="dissolve"===n.mode?w-Math.floor(M*t.glyphs.length*1.8):w+Math.floor(M*t.glyphs.length*.85);w>0&&(y+=r[2]*(t.glyphs.length-1)),y=Math.max(0,Math.min(t.glyphs.length-1,Math.floor(y+s(o,a))));let S=r[0],E=r[1];n.strength>0&&(S+=(256*n.pixels[v]+n.pixels[v+1]-32768)/32767*n.strength,E+=(256*n.pixels[v+2]+n.pixels[v+3]-32768)/32767*n.strength);const b=o*d+S,T=a*u+E,A=e.colors[x+3]/255*r[3],R=F?Math.max(1,e.colors[x],e.colors[x+1],e.colors[x+2]):255,z=`rgb(${e.colors[x]/R*255},${e.colors[x+1]/R*255},${e.colors[x+2]/R*255})`;if(m.fillStyle=z,F){const t=Math.max(0,Math.min(1,e.indices[x+2]/255+r[2]+.65*("dissolve"===n.mode?-M:M)));m.globalAlpha=A;for(let e=0;e<u;e+=l)for(let i=0;i<d;i+=l)t>.5+(s(Math.floor((b+i)/l),Math.floor((T+e)/l))-.5)*Math.max(0,Math.min(2,p?.ditherStrength??1))&&m.fillRect(b+i,T+e,Math.min(l,d-i),Math.min(l,u-e))}else if(y>0)if(m.globalAlpha=A,k.dots){const e=Math.min(.48,y/(t.glyphs.length-1)*.5*k.dotSize)*Math.min(d,u);m.beginPath(),m.arc(b+.5*d,T+.5*u,e,0,2*Math.PI),m.fill()}else m.drawImage(i,y%t.atlasColumns*t.tileWidth+t.padding,Math.floor(y/t.atlasColumns)*t.tileHeight+t.padding,t.cellWidth*I,t.cellHeight*I,b,T,d,u),m.globalAlpha=1,m.globalCompositeOperation="source-atop",m.fillRect(b,T,d,u),m.globalCompositeOperation="source-over"}m.globalAlpha=1}else if(c(n.mode)&&k){const{plan:t,packed:e,atlas:i}=k;for(let s=0;s<e.rows;s++)for(let h=0;h<e.cols;h++){const a=4*(Math.min(n.height-1,Math.round((s+.5)/e.rows*(n.height-1)))*n.width+Math.min(n.width-1,Math.round((h+.5)/e.cols*(n.width-1)))),o=(256*n.pixels[a]+n.pixels[a+1])/65535*n.focus[2],r=4*(s*e.cols+h),l=.0137*(h*h*17+s*s*23+h*s*19),c=l-Math.floor(l),f=e.indices[r]+256*e.indices[r+1],g="dissolve"===n.mode?Math.max(0,f-Math.floor(o*t.glyphs.length*(1.35+.9*c))):Math.min(t.glyphs.length-1,f+Math.floor(o*t.glyphs.length*.85));if(g===f||e.colors[r+3]<10)continue;const p=h*d,x=s*u;if(m.clearRect(p,x,d,u),m.globalAlpha=e.colors[r+3]/255,k.dots){const e=Math.min(.48,g/(t.glyphs.length-1)*.5*k.dotSize)*Math.min(d,u);m.fillStyle="#fff",m.beginPath(),m.arc(p+.5*d,x+.5*u,e,0,2*Math.PI),m.fill()}else m.drawImage(i,g%t.atlasColumns*t.tileWidth+t.padding,Math.floor(g/t.atlasColumns)*t.tileHeight+t.padding,t.cellWidth*I,t.cellHeight*I,p,x,d,u);m.globalAlpha=1,m.globalCompositeOperation="source-atop";const v=Math.max(e.colors[r],e.colors[r+1],e.colors[r+2]),M="dissolve"===n.mode?v:Math.max(v,Math.min(112,191*o)),w=v?M/v:0;m.fillStyle=`rgb(${v?e.colors[r]*w:M},${v?e.colors[r+1]*w:M},${v?e.colors[r+2]*w:M})`,m.fillRect(p,x,d,u),m.globalCompositeOperation="source-over"}}else if("light"===n.mode||"scan"===n.mode){!t&&b&&w.width===P&&w.height===U||(w.width=P,w.height=U,y.width=P,y.height=U,S.filter="brightness(3)",S.drawImage(i,0,0,P,U),S.filter="none",b=!0);const[e,s,h,r]=n.focus;if(h>.001){E.setTransform(1,0,0,1,0,0),E.clearRect(0,0,P,U),E.drawImage(w,0,0),E.globalCompositeOperation="destination-in",E.save(),E.translate(e*P,s*U),E.scale("scan"===n.mode?.13:1,1);const t=r*Math.min(P,U),i=E.createRadialGradient(0,0,0,0,0,t);i.addColorStop(0,`rgba(255,255,255,${h})`),i.addColorStop(.5,`rgba(255,255,255,${.4*h})`),i.addColorStop(1,"rgba(255,255,255,0)"),E.fillStyle=i,E.fillRect(10*-P,10*-U,20*P,20*U),E.restore(),E.globalCompositeOperation="source-over",m.globalCompositeOperation="source-atop",m.drawImage(y,0,0,a,o),m.globalCompositeOperation="source-over"}}else if(n.strength>0){const t=32,e=18,s=a/t,h=o/e;for(let r=0;r<e;r++)for(let l=0;l<t;l++){const c=(l+.5)/t,f=(r+.5)/e,g=Math.min(n.width-1,Math.round(c*(n.width-1))),p=4*(Math.min(n.height-1,Math.round(f*(n.height-1)))*n.width+g),x=n.pixels,v=Math.min(l*s/d,(a-(l+1)*s)/d,r*h/u,(o-(r+1)*h)/u),M=Math.max(0,Math.min(1,(v-2)/6)),w=M*M*(3-2*M),y=(256*x[p]+x[p+1]-32768)/32767*n.strength*w,S=(256*x[p+2]+x[p+3]-32768)/32767*n.strength*w;Math.abs(y)+Math.abs(S)<.02||(m.clearRect(l*s,r*h,s,h),m.drawImage(i,Math.max(0,Math.min(a-s,l*s-y))*i.width/a,Math.max(0,Math.min(o-h,r*h-S))*i.height/o,s*i.width/a,h*i.height/o,l*s,r*h,s,h))}}},destroy(){x=!0,A.destroy(),r.removeEventListener("webglcontextlost",D),_(),r.remove(),w.width=w.height=y.width=y.height=1,i.style.visibility=o,l?.getExtension("WEBGL_lose_context")?.loseContext()}}}(t,i,()=>queueMicrotask(()=>{f=!0,S()}));function b(t){if(g=0,l||!d||document.hidden)return;const s=i.clientWidth,n=i.clientHeight;if(!s||!n)return;const h=y.matches||o.paused;r.configure(o.effect,o.strength,o.radius);const a=r.active;if(!h){if(v+=p?Math.min(.1,(t-p)/1e3):0,w){const t=i.getBoundingClientRect();M&&t.width&&t.height?r.move((M.x-t.left)/t.width,(M.y-t.top)/t.height):r.leave(),w=!1}r.step(p?(t-p)/1e3:1/60)}const c=f||o.animated&&!h&&t-x>=1e3/Math.max(1,Math.min(60,o.fps))-.5;(c||a||r.active||!h&&"none"!==e(o.motion))&&(E.render(c,r.refraction,s,n,o.fontSize*o.charSpacing,o.fontSize/o.charAspect*o.charSpacing,c?o.getFrame?.():void 0,{charset:o.charset,customText:o.customText,renderMode:o.renderMode,dotSizeRatio:o.dotSizeRatio,colorMode:"fullcolor",animationStyle:o.motion,animationSpeed:o.motionSpeed??1,artStyle:o.fineDither?"terminal":"classic",ditherStrength:o.ditherStrength??1},v),c&&(x=t),f=!1),p=t,h||!o.animated&&!r.active&&"none"===e(o.motion)||S()}const T=()=>{r.clear(),M=null,w=!1,p=0,f=!0,cancelAnimationFrame(g),g=0,S()},A=t=>{if("touch"===t.pointerType||o.paused||y.matches)return;if(t.target instanceof Element&&t.target.closest("button,a,input,summary,select"))return void k();const e=i.getBoundingClientRect();t.clientX<e.left||t.clientX>e.right||t.clientY<e.top||t.clientY>e.bottom?k():(M={x:t.clientX,y:t.clientY},w=!0,S())},k=()=>{M=null,w=!0,S()},R=new IntersectionObserver(([t])=>{d=t.isIntersecting,T()});R.observe(t);const z=new ResizeObserver(()=>{r=new m(i.clientWidth/Math.max(1,i.clientHeight)),T()});return z.observe(i),t.addEventListener("pointermove",A),t.addEventListener("pointerleave",k),t.addEventListener("pointercancel",k),document.addEventListener("visibilitychange",T),y.addEventListener("change",T),{get canvas(){return E.canvas},invalidate(){f=!0,S()},update(t){o={...o,...t},T()},destroy(){l||(l=!0,cancelAnimationFrame(g),R.disconnect(),z.disconnect(),E.destroy(),t.removeEventListener("pointermove",A),t.removeEventListener("pointerleave",k),t.removeEventListener("pointercancel",k),document.removeEventListener("visibilitychange",T),y.removeEventListener("change",T))}}}export{f as mountHover,f as mountStudioHover};//# sourceMappingURL=hover.js.map
|
|
1
|
+
function t(t,e,i=()=>{}){const s=Array.isArray(e)?e:[e],n=document.createElement("canvas"),a=n.getContext("2d");let o,r=!0,h=!1,l=0;const c=()=>{h||(r=!0,i())},d=new ResizeObserver(c);d.observe(t),s.forEach(t=>d.observe(t));const f=new MutationObserver(c);return s.forEach(t=>f.observe(t,{subtree:!0,childList:!0,characterData:!0,attributes:!0})),document.fonts?.addEventListener("loadingdone",c),document.fonts?.ready.then(c),window.addEventListener("resize",c),{invalidate:c,read(){if(h)return;if(!r)return o;r=!1;const e=t.getBoundingClientRect(),i=Math.min(devicePixelRatio||1,1.5,Math.sqrt(4e6/Math.max(1,e.width*e.height)));n.width=Math.max(1,Math.round(e.width*i)),n.height=Math.max(1,Math.round(e.height*i)),a.setTransform(i,0,0,i,0,0),a.fillStyle="#fff",a.textBaseline="alphabetic";for(const t of s){const i=document.createTreeWalker(t,NodeFilter.SHOW_TEXT);for(let t=i.nextNode();t;t=i.nextNode()){const i=t.parentElement;if(!i)continue;const s=getComputedStyle(i);if("hidden"===s.visibility||"none"===s.display)continue;a.font=`${s.fontStyle} ${s.fontWeight} ${s.fontSize} ${s.fontFamily}`;const n=a.measureText("Hg"),o=n.fontBoundingBoxAscent??.8*parseFloat(s.fontSize),r=n.fontBoundingBoxDescent??.2*parseFloat(s.fontSize),h=t.textContent??"",l=document.createRange();let c=0;for(const i of h){if(l.setStart(t,c),c+=i.length,l.setEnd(t,c),/\s/.test(i))continue;const s=l.getBoundingClientRect();s.width&&s.height&&a.fillText(i,s.left-e.left,s.top-e.top+(s.height-o-r)/2+o)}}}return o={canvas:n,revision:++l},o},destroy(){h=!0,d.disconnect(),f.disconnect(),document.fonts?.removeEventListener("loadingdone",c),window.removeEventListener("resize",c),n.width=n.height=1,o=void 0}}}var e=[{value:"none",mode:"none",label:"Off",description:"Keep the image still. Hover stays available."},{value:"breathe",mode:"print",label:"Living Print",description:"Soft tonal movement. The character grid stays still."},{value:"wave",mode:"current",label:"Slow Current",description:"A gentle flow through the image, with steady edges."},{value:"rain",mode:"reform",label:"Reveal & Reform",description:"Disperse, gather, then hold the complete image."}];function i(t){return"orbit"===t?"current":e.find(e=>e.value===t||e.mode===t)?.mode??"none"}var s=(t,e,i)=>{const s=(t=>Math.max(0,Math.min(1,t)))((i-t)/(e-t));return s*s*(3-2*s)},n=(t,e)=>{const i=(.06711056*t+.00583715*e)%1*52.9829189;return i-Math.floor(i)},a=class{constructor(){this.last=null,this.mode="none",this.phase=0}update(t,e,i=1){return Number.isFinite(t)?((e!==this.mode||null!==this.last&&t<this.last)&&(this.mode=e,this.phase=0,this.last=t),null!==this.last&&(this.phase+=Math.max(0,t-this.last)*Math.max(.1,Math.min(3,Number.isFinite(i)?i:1))),this.last=t,this.phase):this.phase}};function o(t,e,i,n,a){const o=n*Math.PI/6,r=s(0,.12,Math.min(e,1-e,i,1-i));if(a[0]=a[1]=a[2]=0,a[3]=1,"print"===t)a[2]=Math.sin(9*e+5*i+o)*Math.cos(8*i-3*e-o)*.065*r,a[3]=.9+.1*Math.sin(6*e-4*i+o);else if("current"===t)a[0]=Math.sin(9*i+o)*Math.cos(7*e-o)*6*r,a[1]=Math.cos(8*e+o)*Math.sin(6*i-o)*4*r;else if("reform"===t){const t=(n%12+12)%12,o=.8*e+.2*i+.08*Math.sin(8*e-5*i),r=s(1.8+1.2*o,3.8+1.2*o,t)*(1-s(5+1.7*o,7.2+1.7*o,t));a[2]=.95*-r,a[3]=1-.82*r}return a}function r(t,e,i){const s=Math.min(t*Math.max(1,i),(1-t)*Math.max(1,i),e*Math.max(1,1/i),(1-e)*Math.max(1,1/i)),n=Math.max(0,Math.min(1,(s-.035)/.105));return n*n*n*(n*(6*n-15)+10)}var h=class{constructor(t,e){this.edgeSafe=!1,this.previous=null,this.peak=0,this.mode="dissolve",this.width=t,this.height=e;const i=t*e;this.pixels=new Uint8Array(4*i),this.ink=new Float32Array(i),this.targetX=new Float32Array(i),this.targetY=new Float32Array(i),this.offsetX=new Float32Array(i),this.offsetY=new Float32Array(i),this.edge=new Float32Array(i);for(let i=0;i<e;i++)for(let s=0;s<t;s++)this.edge[i*t+s]=r(s/(t-1),i/(e-1),t/e);this.clear()}get active(){return this.peak>2e-4}setMode(t){t!==this.mode&&(this.mode=t,this.clear())}clear(){for(const t of[this.ink,this.targetX,this.targetY,this.offsetX,this.offsetY,this.pixels])t.fill(0);if(this.previous=null,this.peak=0,"dissolve"!==this.mode)for(let t=0;t<this.pixels.length;t+=4)this.pixels[t]=this.pixels[t+2]=128}leave(){this.previous=null}move(t,e,i){if(!Number.isFinite(t+e+i))return;t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e));const s=this.previous;this.previous={x:t,y:e};const n=this.width,a=this.height,o=Math.max(1,n/a),r=Math.max(1,a/n),h=s?(t-s.x)*o:0,l=s?(e-s.y)*r:0,c=Math.hypot(h,l);if(!s&&"dissolve"!==this.mode)return;if(s&&c<1e-4)return;const d=.035+.11*Math.max(.1,Math.min(1,i)),f=Math.min(128,Math.max(1,Math.ceil(c/(.45*d)))),m=c?h/c:1,u=c?l/c:0,g=Math.min(1,c/(d*f)*2.2);for(let i=0;i<f;i++){const h=(i+.5)/f,l=s?s.x+(t-s.x)*h:t,c=s?s.y+(e-s.y)*h:e,p=Math.max(0,Math.floor((l-2.5*d/o)*(n-1))),x=Math.min(n-1,Math.ceil((l+2.5*d/o)*(n-1))),v=Math.max(0,Math.floor((c-2.5*d/r)*(a-1))),M=Math.min(a-1,Math.ceil((c+2.5*d/r)*(a-1)));for(let t=v;t<=M;t++)for(let e=p;e<=x;e++){const i=(e/(n-1)-l)*o/d,s=(t/(a-1)-c)*r/d,h=Math.exp(1.5*-(i*i+s*s)),f=t*n+e;if("dissolve"===this.mode)this.ink[f]=Math.max(this.ink[f],h);else{const t=(-i*u+s*m)*h*2.8,e="silk"===this.mode?m*t:-s*h*2.5,n="silk"===this.mode?u*t:i*h*2.5;this.targetX[f]=Math.max(-1,Math.min(1,this.targetX[f]+e*g)),this.targetY[f]=Math.max(-1,Math.min(1,this.targetY[f]+n*g))}}}this.peak=1}step(t){if(!this.active||!Number.isFinite(t))return;const e=Math.max(0,Math.min(.05,t)),i=Math.exp(-("dissolve"===this.mode?2.15:3.2)*e),s=1-Math.exp(-22*e);let n=0;for(let t=0;t<this.ink.length;t++)if("dissolve"===this.mode){this.ink[t]*=i,n=Math.max(n,this.ink[t]);const e=Math.round(65535*this.ink[t]);this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e}else{this.targetX[t]*=i,this.targetY[t]*=i,this.offsetX[t]+=(this.targetX[t]-this.offsetX[t])*s,this.offsetY[t]+=(this.targetY[t]-this.offsetY[t])*s,n=Math.max(n,Math.abs(this.offsetX[t]),Math.abs(this.offsetY[t]),Math.abs(this.targetX[t]),Math.abs(this.targetY[t]));const e=Math.round(this.offsetX[t]*(this.edgeSafe?this.edge[t]:1)*32767+32768),a=Math.round(this.offsetY[t]*(this.edgeSafe?this.edge[t]:1)*32767+32768);this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e,this.pixels[4*t+2]=a>>>8,this.pixels[4*t+3]=255&a}this.peak=n,this.active||this.clear()}sample(t,e,i){const s=Math.max(0,Math.min(this.width-1.001,t*(this.width-1))),n=Math.max(0,Math.min(this.height-1.001,e*(this.height-1))),a=Math.floor(s),o=Math.floor(n),h=s-a,l=n-o,c=o*this.width+a,d=c+this.width,f=t=>(t[c]*(1-h)+t[c+1]*h)*(1-l)+(t[d]*(1-h)+t[d+1]*h)*l;i[0]=f(this.offsetX)*(this.edgeSafe?r(t,e,this.width/this.height):1)*.08,i[1]=f(this.offsetY)*(this.edgeSafe?r(t,e,this.width/this.height):1)*.08,i[2]="dissolve"===this.mode?6*-f(this.ink):0}},l=class{constructor(t,e){this.rings=[],this.previous=null,this.elapsed=1,this.echoPeak=0,this.width=t,this.height=e,this.pixels=new Uint8Array(t*e*4),this.echo=new Float32Array(t*e)}get active(){return this.rings.length>0||this.echoPeak>2e-4}clear(){this.rings=[],this.previous=null,this.elapsed=1,this.pixels.fill(0),this.echo.fill(0),this.echoPeak=0}leave(){this.previous=null}move(t,e,i){const s=Math.max(1,this.width/this.height),n=Math.max(1,this.height/this.width);this.previous&&(Math.hypot((t-this.previous.x)*s,(e-this.previous.y)*n)<.065||this.elapsed<.3)||4!==this.rings.length&&(this.previous={x:t,y:e},this.elapsed=0,this.rings.push({x:t,y:e,age:0,radius:i}))}ringSample(t,e){const i=Math.max(1,this.width/this.height),s=Math.max(1,this.height/this.width);let n=0;for(const a of this.rings){const o=.015+a.age*(.15+.22*a.radius),r=.009+.014*a.radius,h=(Math.hypot((t-a.x)*i,(e-a.y)*s)-o)/r,l=Math.sin(Math.min(1,a.age/.07)*Math.PI/2)*Math.max(0,1-a.age/1.35)**2;n=Math.max(n,Math.exp(-h*h)*l)}return n}sample(t,e){const i=Math.max(0,Math.min(this.width-1,Math.round(t*(this.width-1)))),s=Math.max(0,Math.min(this.height-1,Math.round(e*(this.height-1))));return Math.max(this.ringSample(t,e),this.echo[s*this.width+i])}step(t){if(!Number.isFinite(t))return;const e=Math.max(0,Math.min(.05,t));this.elapsed+=e;for(const t of this.rings)t.age+=e;if(this.rings=this.rings.filter(t=>t.age<1.35),!this.active)return void this.pixels.fill(0);const i=Math.exp(-5.5*e);let s=0;for(let t=0;t<this.height;t++)for(let e=0;e<this.width;e++){const n=t*this.width+e;this.echo[n]=Math.max(this.ringSample(e/(this.width-1),t/(this.height-1)),this.echo[n]*i),s=Math.max(s,this.echo[n]);const a=Math.round(65535*this.echo[n]),o=4*n;this.pixels[o]=a>>>8,this.pixels[o+1]=255&a}this.echoPeak=s,this.active||(this.echo.fill(0),this.pixels.fill(0))}},c=class{constructor(t,e){this.previous=null,this.peak=0,this.width=t,this.height=e;const i=t*e;this.pixels=new Uint8Array(4*i),this.signal=new Float32Array(i),this.offsetX=new Float32Array(i),this.offsetY=new Float32Array(i),this.driftX=new Float32Array(i),this.driftY=new Float32Array(i),this.u=new Float32Array(i),this.v=new Float32Array(i),this.ink=new Float32Array(i),this.a=new Float32Array(i),this.b=new Float32Array(i),this.c=new Float32Array(i),this.pressure=new Float32Array(i),this.pressureNext=new Float32Array(i),this.divergence=new Float32Array(i),this.curl=new Float32Array(i)}get active(){return this.peak>2e-4}clear(){for(const t of[this.u,this.v,this.ink,this.a,this.b,this.c,this.pressure,this.pressureNext,this.divergence,this.curl,this.signal,this.pixels,this.offsetX,this.offsetY,this.driftX,this.driftY])t.fill(0);this.previous=null,this.peak=0}leave(){this.previous=null}move(t,e,i,s=performance.now()){if(!Number.isFinite(t+e+i+s))return;t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e)),i=Math.max(.1,Math.min(1,i));const n=this.previous;if(this.previous={x:t,y:e,time:s},!n)return;const a=(t-n.x)*(this.width-1),o=(e-n.y)*(this.height-1),r=Math.hypot(a,o);if(r<.001)return;const h=Math.min(this.width,this.height),l=s>n.time?Math.max(1/240,(s-n.time)/1e3):1/60,c=Math.min(12,r/h/l),d=1-Math.exp(-c/2.2),f=h*(.022+.075*i)*(.65+.95*d),m=Math.min(128,Math.max(1,Math.ceil(r/(.4*f)))),u=r/f*(.32+.22*d)/m,g=a/r,p=o/r,x=-p,v=g,M=r*(2+18*d)/m;for(let i=0;i<m;i++){const s=(i+.5)/m,a=(n.x+(t-n.x)*s)*(this.width-1),o=(n.y+(e-n.y)*s)*(this.height-1),r=Math.max(1,Math.floor(a-3*f)),h=Math.min(this.width-2,Math.ceil(a+3*f)),l=Math.max(1,Math.floor(o-3*f)),c=Math.min(this.height-2,Math.ceil(o+3*f));for(let t=l;t<=c;t++)for(let e=r;e<=h;e++){const i=((e-a)*g+(t-o)*p)/f,s=((e-a)*x+(t-o)*v)/f,n=Math.exp(-i*i*.65-s*s*1.7),r=t*this.width+e;this.ink[r]=1-(1-this.ink[r])*Math.exp(-n*u);const h=1-s*s*.55,l=i*s*.7;this.u[r]=Math.max(-80,Math.min(80,this.u[r]+(g*h+x*l)*n*M)),this.v[r]=Math.max(-80,Math.min(80,this.v[r]+(p*h+v*l)*n*M))}}this.peak=1}read(t,e,i){const s=0|(e=Math.max(.5,Math.min(this.width-1.5,e))),n=0|(i=Math.max(.5,Math.min(this.height-1.5,i))),a=e-s,o=i-n,r=n*this.width+s;return(t[r]*(1-a)+t[r+1]*a)*(1-o)+(t[r+this.width]*(1-a)+t[r+this.width+1]*a)*o}sample(t,e){return this.read(this.signal,t*(this.width-1),e*(this.height-1))}displacement(t,e,i){i[0]=this.read(this.offsetX,t*(this.width-1),e*(this.height-1)),i[1]=this.read(this.offsetY,t*(this.width-1),e*(this.height-1))}step(t){if(!this.active||!Number.isFinite(t))return;let e=Math.max(0,Math.min(.05,t));const i=this.width,s=this.height;for(;e>1e-7;){const t=Math.min(1/60,e);e-=t;const n=Math.exp(-1.9*t),a=Math.exp(-3.2*t);for(let e=1;e<s-1;e++)for(let o=1;o<i-1;o++){const r=e*i+o,h=Math.max(.5,Math.min(i-1.5,o-this.u[r]*t)),l=Math.max(.5,Math.min(s-1.5,e-this.v[r]*t)),c=0|h,d=0|l,f=h-c,m=l-d,u=d*i+c,g=(1-f)*(1-m),p=f*(1-m),x=(1-f)*m,v=f*m;this.a[r]=(this.u[u]*g+this.u[u+1]*p+this.u[u+i]*x+this.u[u+i+1]*v)*n,this.b[r]=(this.v[u]*g+this.v[u+1]*p+this.v[u+i]*x+this.v[u+i+1]*v)*n,this.c[r]=(this.ink[u]*g+this.ink[u+1]*p+this.ink[u+i]*x+this.ink[u+i+1]*v)*a}[this.u,this.a]=[this.a,this.u],[this.v,this.b]=[this.b,this.v],[this.ink,this.c]=[this.c,this.ink];for(let t=1;t<s-1;t++)for(let e=1;e<i-1;e++){const s=t*i+e;this.curl[s]=.5*(this.v[s+1]-this.v[s-1]-this.u[s+i]+this.u[s-i])}for(let e=1;e<s-1;e++)for(let s=1;s<i-1;s++){const n=e*i+s,a=Math.abs(this.curl[n+1])-Math.abs(this.curl[n-1]),o=Math.abs(this.curl[n+i])-Math.abs(this.curl[n-i]),r=Math.hypot(a,o)+1e-4,h=this.curl[n]*t*10,l=Math.hypot(this.u[n],this.v[n]);this.u[n]+=o/r*h,this.v[n]-=a/r*h;const c=Math.min(1,l/(Math.hypot(this.u[n],this.v[n])+1e-6));this.u[n]*=c,this.v[n]*=c,this.divergence[n]=-.5*(this.u[n+1]-this.u[n-1]+this.v[n+i]-this.v[n-i])}this.pressure.fill(0);for(let t=0;t<4;t++){for(let t=1;t<s-1;t++)for(let e=1;e<i-1;e++){const s=t*i+e;this.pressureNext[s]=.25*(this.divergence[s]+this.pressure[s-1]+this.pressure[s+1]+this.pressure[s-i]+this.pressure[s+i])}[this.pressure,this.pressureNext]=[this.pressureNext,this.pressure]}let o=0;for(let e=1;e<s-1;e++)for(let s=1;s<i-1;s++){const n=e*i+s;this.u[n]=Math.max(-80,Math.min(80,this.u[n]-.5*(this.pressure[n+1]-this.pressure[n-1]))),this.v[n]=Math.max(-80,Math.min(80,this.v[n]-.5*(this.pressure[n+i]-this.pressure[n-i]))),this.driftX[n]+=(3.6*this.u[n]-58*this.offsetX[n]-12*this.driftX[n])*t,this.driftY[n]+=(3.6*this.v[n]-58*this.offsetY[n]-12*this.driftY[n])*t,this.offsetX[n]=Math.max(-2,Math.min(2,this.offsetX[n]+this.driftX[n]*t)),this.offsetY[n]=Math.max(-2,Math.min(2,this.offsetY[n]+this.driftY[n]*t)),this.signal[n]=1-Math.exp(.06*-Math.hypot(this.u[n],this.v[n])-.16*this.ink[n]),o=Math.max(o,this.signal[n])}this.peak=o}if(this.active)for(let t=0;t<this.ink.length;t++){const e=Math.round(65535*Math.min(1,this.signal[t]));this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e,this.pixels[4*t+2]=Math.round(128+63.5*this.offsetX[t]),this.pixels[4*t+3]=Math.round(128+63.5*this.offsetY[t])}else this.clear()}},d=t=>["trail","contour","dissolve"].includes(t);function f(t,e,i){const s=Math.max(0,e-1),n=1-Math.exp(3.5*-Math.max(0,i));return Math.max(0,s-Math.abs(s-(t+n*s*2.1)))}function m(t,e,i,s,n,a,o,r,h,l,c,d=!1){const m=Math.min(n,a,i-1-n,s-1-a),u=Math.max(0,Math.min(1,(m-1)/4)),g=d?u*u*(3-2*u):1;o*=g;const p=1-Math.exp(3.5*-Math.max(0,o)),x=Math.max(0,Math.min(i-1,n-r*p*.026*i*g)),v=Math.max(0,Math.min(s-1,a-h*p*.026*s*g)),M=Math.floor(x),y=Math.floor(v),w=x-M,S=v-y;c.fill(0);for(let n=0;n<2;n++)for(let a=0;a<2;a++){const o=4*(Math.min(s-1,y+n)*i+Math.min(i-1,M+a)),r=(a?w:1-w)*(n?S:1-S);c[0]+=(t[o]+256*t[o+1])*r,c[1]+=t[o+2]/255*r;for(let t=0;t<4;t++)c[t+2]+=e[o+t]*r}const b=43758.5453*Math.sin(127.1*n+311.7*a),E=b-Math.floor(b);c[0]=Math.max(0,f(c[0],l,o)-p*(1-p)*E*3)}var u=class{constructor(t=1){this.mode="water",this.amount=.55,this.radius=.2,this.lensX=.5,this.lensY=.5,this.lensStrength=0,this.previous=null,this.energy=0,this.pending=!1,this.remainder=0,t=Math.max(.25,Math.min(4,t)),this.columns=Math.round(t>=1?128:128*t),this.rows=Math.round(t>=1?128/t:128),this.xScale=Math.max(1,t),this.yScale=Math.max(1,1/t),this.heights=new Float32Array(this.columns*this.rows),this.velocity=new Float32Array(this.heights.length),this.next=new Float32Array(this.heights.length),this.normals=new Float32Array(2*this.heights.length),this.edgeMask=new Float32Array(this.heights.length);for(let e=0;e<this.rows;e++)for(let i=0;i<this.columns;i++)this.edgeMask[e*this.columns+i]=r(i/(this.columns-1),e/(this.rows-1),t);this.refraction={width:this.columns,height:this.rows,pixels:new Uint8Array(4*this.heights.length),strength:30,mode:"water",focus:[.5,.5,0,.2]},this.waterPixels=this.refraction.pixels,this.trail=new c(this.columns,this.rows),this.contour=new l(this.columns,this.rows),this.afterimage=new h(this.columns,this.rows),this.clear()}get invertsDensity(){return"trail"===this.mode}get densityTrail(){return["trail","contour","dissolve"].includes(this.mode)}get hasRefraction(){return this.active||this.lensStrength>15e-5}get active(){return["dissolve","silk","vortex"].includes(this.mode)?this.afterimage.active:"contour"===this.mode?this.contour.active:"trail"===this.mode?this.trail.active:this.pending||this.energy>15e-5}setMode(t){t!==this.mode&&(this.clear(),this.mode=t,this.refraction.mode=t,"dissolve"!==t&&"silk"!==t&&"vortex"!==t||this.afterimage.setMode(t),this.refraction.pixels="trail"===t?this.trail.pixels:"contour"===t?this.contour.pixels:["dissolve","silk","vortex"].includes(t)?this.afterimage.pixels:this.waterPixels,this.refraction.strength="water"===t?30*this.amount/.55:"silk"===t?28*this.amount:"vortex"===t?38*this.amount:0)}configure(t,e=.55,i=.2,s=!1){this.setMode(t),this.refraction.edgeSafe=s,this.afterimage.edgeSafe=s,this.amount=Number.isFinite(e)?Math.max(0,Math.min(1,e)):.55,this.radius=Number.isFinite(i)?Math.max(.1,Math.min(1,i)):.2,this.refraction.strength="water"===t?30*this.amount/.55:"silk"===t?28*this.amount:"vortex"===t?38*this.amount:0,this.refraction.focus[2]=this.densityTrail?this.amount:this.lensStrength*this.amount,this.refraction.focus[3]=this.radius}move(t,e,i){if("none"===this.mode||0===this.amount)return;if(!Number.isFinite(t+e))return;if(t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e)),["dissolve","silk","vortex"].includes(this.mode))return void this.afterimage.move(t,e,this.radius);if("contour"===this.mode)return void this.contour.move(t,e,this.radius);if("trail"===this.mode)return void this.trail.move(t,e,this.radius,i);if("water"!==this.mode)return!this.previous&&this.lensStrength<.001&&(this.lensX=t,this.lensY=e),this.previous={x:t,y:e},void(this.pending=!0);if(!this.previous)return void(this.previous={x:t,y:e});const s=this.previous;this.previous={x:t,y:e};const n=(t-s.x)*this.xScale,a=(e-s.y)*this.yScale,o=Math.hypot(n,a);if(o<1e-5)return;const r=.035+.1*this.radius,h=3*r,l=Math.min(192,Math.max(1,Math.ceil(o/(.5*r)))),c=95*Math.min(o,1)/l;for(let i=0;i<l;i++){const n=(i+.5)/l,a=s.x+(t-s.x)*n,o=s.y+(e-s.y)*n,d=Math.max(1,Math.floor((a-h/this.xScale)*(this.columns-1))),f=Math.min(this.columns-2,Math.ceil((a+h/this.xScale)*(this.columns-1))),m=Math.max(1,Math.floor((o-h/this.yScale)*(this.rows-1))),u=Math.min(this.rows-2,Math.ceil((o+h/this.yScale)*(this.rows-1)));for(let t=m;t<=u;t++)for(let e=d;e<=f;e++){const i=(e/(this.columns-1)-a)*this.xScale,s=(t/(this.rows-1)-o)*this.yScale,n=Math.exp(-(i*i+s*s)/(r*r))*c,h=t*this.columns+e;this.velocity[h]=Math.max(-12,this.velocity[h]-n)}}this.pending=!0}leave(){this.afterimage.leave(),this.contour.leave(),this.trail.leave(),this.previous=null,"water"!==this.mode&&this.lensStrength&&(this.pending=!0)}clear(){this.trail.clear(),this.contour.clear(),this.afterimage.clear(),this.heights.fill(0),this.velocity.fill(0),this.next.fill(0),this.normals.fill(0),this.refraction.focus[2]=0,this.previous=null,this.lensStrength=0,this.energy=0,this.pending=!1,this.remainder=0;for(let t=0;t<this.waterPixels.length;t+=4)this.waterPixels[t]=this.waterPixels[t+2]=128,this.waterPixels[t+1]=this.waterPixels[t+3]=0}step(t){if(!this.active||!Number.isFinite(t))return;if(["dissolve","silk","vortex"].includes(this.mode))return void this.afterimage.step(t);if("contour"===this.mode)return void this.contour.step(t);if("trail"===this.mode)return void this.trail.step(t);if("water"!==this.mode)return void this.stepLight(Math.max(0,Math.min(.05,t)));this.remainder+=Math.max(0,Math.min(.05,t));const e=1/120,i=Math.exp(-3.8*e),s=.3*Math.min(this.columns,this.rows);for(;this.remainder+1e-8>=e;){this.remainder-=e;let t=0;for(let n=1;n<this.rows-1;n++)for(let a=1;a<this.columns-1;a++){const o=n*this.columns+a,r=this.heights[o],h=this.heights[o-1]+this.heights[o+1]+this.heights[o-this.columns]+this.heights[o+this.columns]-4*r,l=Math.min(a,n,this.columns-1-a,this.rows-1-n),c=l<5?.88+.024*l:1,d=(this.velocity[o]+(h*s*s-8*r)*e)*i*c;this.velocity[o]=d,this.next[o]=(r+d*e)*c,t=Math.max(t,Math.abs(this.next[o]),.1*Math.abs(d))}this.heights.set(this.next),this.energy=t,this.pending=!1}if(!this.active)return void this.clear();const n=.18*Math.min(this.columns,this.rows);for(let t=0;t<this.rows;t++)for(let e=0;e<this.columns;e++){const i=t*this.columns+e,s=(this.heights[t*this.columns+Math.max(0,e-1)]-this.heights[t*this.columns+Math.min(this.columns-1,e+1)])*n,a=(this.heights[Math.max(0,t-1)*this.columns+e]-this.heights[Math.min(this.rows-1,t+1)*this.columns+e])*n,o=Math.tanh(s)*(this.refraction.edgeSafe?this.edgeMask[i]:1),r=Math.tanh(a)*(this.refraction.edgeSafe?this.edgeMask[i]:1);this.normals[2*i]=o,this.normals[2*i+1]=r;const h=Math.round(32767*o+32768),l=Math.round(32767*r+32768);this.refraction.pixels[4*i]=h>>>8,this.refraction.pixels[4*i+1]=255&h,this.refraction.pixels[4*i+2]=l>>>8,this.refraction.pixels[4*i+3]=255&l}}stepLight(t){const e=this.previous,i=1-Math.exp(-30*t),s=1-Math.exp(-12*t);e&&(this.lensX+=(e.x-this.lensX)*i,this.lensY+=(e.y-this.lensY)*i),this.lensStrength+=((e?1:0)-this.lensStrength)*s,this.energy=Math.max(e?Math.abs(e.x-this.lensX)+Math.abs(e.y-this.lensY):0,Math.abs((e?1:0)-this.lensStrength)),this.pending=!1,e||this.active?this.refraction.focus=[this.lensX,this.lensY,this.lensStrength*this.amount,this.radius]:this.clear()}sample(t,e,i){if(["dissolve","silk","vortex"].includes(this.mode))return this.afterimage.sample(t,e,i),i[0]*=this.amount,i[1]*=this.amount,void(i[2]*=this.amount);if("contour"===this.mode)return i[0]=i[1]=0,void(i[2]=this.contour.sample(t,e)*this.amount*3);if("trail"===this.mode)return i[0]=i[1]=0,void(i[2]=this.trail.sample(t,e)*this.amount*3);const s=Math.max(0,Math.min(this.columns-1.001,t*(this.columns-1))),n=Math.max(0,Math.min(this.rows-1.001,e*(this.rows-1))),a=Math.floor(s),o=Math.floor(n),r=s-a,h=n-o,l=2*(o*this.columns+a),c=l+2*this.columns;for(let t=0;t<2;t++)i[t]=.08*((this.normals[l+t]*(1-r)+this.normals[l+2+t]*r)*(1-h)+(this.normals[c+t]*(1-r)+this.normals[c+2+t]*r)*h);i[0]*=this.amount/.55,i[1]*=this.amount/.55,i[2]="light"===this.mode||"scan"===this.mode?function(t,e,i,s){const[n,a,o,r]=i.focus,h=(t-n)*Math.max(1,s)/r,l=(e-a)*Math.max(1,1/s)/r;return"light"===i.mode?Math.exp(-3*(h*h+l*l))*o:"scan"===i.mode?(1.3*Math.exp(-h*h*110)-.3*Math.exp(-h*h*12))*Math.exp(-l*l*1.8)*o:0}(t,e,this.refraction,this.xScale/this.yScale):0}};var g=[{value:"clean",label:"Clean",description:"Crisp characters with no optical texture."},{value:"signal",label:"Signal",description:"Broken scanlines at the edges, with a clear center."},{value:"prism",label:"Prism",description:"Soft red/cyan separation at the edges, with a crisp center."},{value:"etch",label:"Etch",description:"A fine engraved texture, keeping the ink monochrome."}];function p(t){const e=Intl.Segmenter;return e?Array.from(new e(void 0,{granularity:"grapheme"}).segment(t),t=>t.segment):Array.from(t)}function x(){const t=document.createElement("canvas"),e=document.createElement("canvas"),i=t.getContext("2d"),s=e.getContext("2d",{willReadFrequently:!0}),n=function(){const t=new WeakMap;return(e,i,s="")=>{if(!e)return i;let n=t.get(e);if(!n){const i=new Set;for(const t of e)for(const e of t)e.char&&i.add(e.char);n=[...i].sort(),t.set(e,n)}const a=i+s;return i+n.filter(t=>!a.includes(t)).join("")}}();let a,o=null;return{update(r,h,l,c,d,f,m,u){const g=m?.[0]?.length??Math.max(1,Math.round(h/c)),x=m?.length??Math.max(1,Math.round(l/d)),v=u??{charset:" .:-=+*#%@",customText:"",colorMode:"fullcolor"},M=n(m,v.charset+(v.charsetFrames?.join("")??""),v.customText),y=function(t,e,i,s,n,a,o,r=4096,h=0,l=1){if(![i,s,n,a,o,r].every(t=>Number.isFinite(t)&&t>0))throw new Error("Glyph atlas dimensions must be positive and finite.");const c=JSON.stringify([e.charset,e.customText,i,s,n,a,o,r,h,l]);if(t?.key===c)return t;const d=[...new Set([" ",...p(e.charset),...p(e.customText??"")])];if(d.length>65536)throw new Error("This character set exceeds the glyph texture capacity.");const f=i/a,m=s/o,u=.9*Math.min(f/.55,m)*l,g=Math.ceil(f*n)+6,x=Math.ceil(m*n)+6,v=Math.min(d.length,Math.floor(r/g));if(v<1||Math.ceil(d.length/v)*x>r)throw new Error("The glyph atlas exceeds the available GPU texture size.");return{key:c,glyphs:d,indices:new Map(d.map((t,e)=>[t,e])),cellWidth:f,cellHeight:m,fontSize:u,padding:3,tileWidth:g,tileHeight:x,atlasColumns:v,atlasWidth:v*g,atlasHeight:Math.ceil(d.length/v)*x}}(o,{...v,charset:M},h,l,f,g,x);if(y!==o&&(t.width=y.atlasWidth,t.height=y.atlasHeight,i.font=y.fontSize*f+'px "JetBrains Mono", monospace',i.textAlign="center",i.textBaseline="middle",i.fillStyle="#fff",y.glyphs.forEach((t,e)=>i.fillText(t,e%y.atlasColumns*y.tileWidth+y.padding+y.cellWidth*f*.5,Math.floor(e/y.atlasColumns)*y.tileHeight+y.padding+y.cellHeight*f*.5))),o=y,m)a=function(t,e,i,s,n=!1){const a=t.length,o=t[0]?.length??0,r=s?.cols===o&&s.rows===a?s:{cols:o,rows:a,indices:new Uint8Array(o*a*4),colors:new Uint8ClampedArray(o*a*4)};r.indices.fill(0),r.colors.fill(0);const h="accent"===i.colorMode?[1,3,5].map(t=>parseInt(i.accentColor.slice(t,t+2),16)):null;for(let s=0;s<a;s++){if(t[s].length!==o)throw new Error("Glyph frames must have a rectangular cell grid.");for(let a=0;a<o;a++){const l=t[s][a];if(!l.char||!n&&" "===l.char||l.a<10)continue;const c=e.get(l.char);if(void 0===c)throw new Error(`Glyph is absent from the configured character set: ${l.char}`);const d=4*(s*o+a);let f=l.r,m=l.g,u=l.b;if(h)[f,m,u]=h;else if("fullcolor"!==i.colorMode){const t=.299*f+.587*m+.114*u|0;f="matrix"===i.colorMode?0:t,m=t,u=f}(n||0!==f||0!==m||0!==u)&&(r.indices[d]=255&c,r.indices[d+1]=c>>>8,r.indices[d+2]=Math.round(.299*l.r+.587*l.g+.114*l.b),r.colors[d]=f,r.colors[d+1]=m,r.colors[d+2]=u,r.colors[d+3]=l.a)}}return r}(m,o.indices,v,a,!0);else{e.width=g,e.height=x,s.drawImage(r,0,0,g,x);const t=s.getImageData(0,0,g,x).data;a={cols:g,rows:x,indices:new Uint8Array(g*x*4),colors:new Uint8ClampedArray(t)};for(let e=0;e<t.length;e+=4){const i=Math.min(1,(.299*t[e]+.587*t[e+1]+.114*t[e+2])/255*(t[e+3]/255)*3);a.indices[e+2]=Math.round(255*i),a.indices[e]=Math.min(o.glyphs.length-1,Math.floor(i*o.glyphs.length))}}return{plan:o,packed:a,atlas:t,dots:"dots"===v.renderMode,dotSize:v.dotSizeRatio??.72}},reset(){o=null},destroy(){t.width=t.height=e.width=e.height=1,a=void 0,o=null}}}function v(t){return!!t&&"ascii"===t.renderMode&&"emoji"!==t.artStyle&&!t.charsetFrames?.length&&["fullcolor","grayscale","matrix","accent"].includes(t.colorMode)&&("accent"!==t.colorMode||/^#[\da-f]{6}$/i.test(t.accentColor))}function M(t){for(let e=t;e;e=e.parentElement){const t=getComputedStyle(e).backgroundColor.match(/[\d.]+/g)?.map(Number);if(t&&t.length>=3&&(t[3]??1)>.5)return(.299*t[0]+.587*t[1]+.114*t[2])/255<.4?[10/255,10/255,10/255,1]:[250/255,249/255,247/255,1]}const e=document.documentElement.dataset.theme;if("dark"!==e&&"light"!==e&&!t.isConnected&&document.body)return M(document.body);return"dark"===e||"light"!==e&&(document.documentElement.classList.contains("dark")||matchMedia("(prefers-color-scheme: dark)").matches)?[10/255,10/255,10/255,1]:[250/255,249/255,247/255,1]}function y(t,e,s){const r=e.style.visibility;let h=document.createElement("canvas"),l=null,c=null,u=null,p=null;const y=[],w=[];let S=!1,b=!1,E=4096,T=null,A=0,k=0,z=0,R=0,D=!1;const C=function(){const t=document.createElement("canvas"),e=t.getContext("2d");return{paint(i,s,n,a){s&&(t.width===i.canvas.width&&t.height===i.canvas.height||(t.width=i.canvas.width,t.height=i.canvas.height),e.globalCompositeOperation="copy",e.drawImage(i.canvas,0,0),e.globalCompositeOperation="destination-in",e.drawImage(s.canvas,0,0,t.width,t.height),e.globalCompositeOperation="source-in",e.fillStyle="#090909",e.fillRect(0,0,t.width,t.height),e.globalCompositeOperation="source-over",i.drawImage(t,0,0,n,a))},destroy(){t.width=t.height=1}}}();let F;const _=document.createElement("canvas"),I=document.createElement("canvas"),X=_.getContext("2d"),P=I.getContext("2d");let L=!1;const U=new a,N=x();let G=null,Y={};const B=()=>{h.className="ascii-hover-surface",h.style.cssText="position:absolute;inset:0;width:100%;height:100%;pointer-events:none",h.setAttribute("role","img"),h.setAttribute("aria-label","ASCII artwork preview"),h.dataset.renderer=l?"surface-gpu":"surface-canvas",t.prepend(h),e.style.visibility="hidden"},W=()=>{l&&(y.forEach(t=>l.deleteTexture(t)),w.forEach(t=>l.deleteShader(t)),u&&l.deleteProgram(u),p&&l.deleteBuffer(p))},H=()=>{S||c||(h.removeEventListener("webglcontextlost",H),W(),h.remove(),l=null,h=document.createElement("canvas"),c=h.getContext("2d"),B(),s())};try{if(l=h.getContext("webgl",{alpha:!0,antialias:!1,depth:!1,stencil:!1,premultipliedAlpha:!0,preserveDrawingBuffer:!0}),!l)throw new Error("WebGL unavailable");E=l.getParameter(l.MAX_TEXTURE_SIZE);const t=(t,e)=>{const i=l.createShader(t);if(w.push(i),l.shaderSource(i,e),l.compileShader(i),!l.getShaderParameter(i,l.COMPILE_STATUS))throw new Error(l.getShaderInfoLog(i)||"Shader compilation failed");return i};if(u=l.createProgram(),l.attachShader(u,t(l.VERTEX_SHADER,"attribute vec2 position; void main(){gl_Position=vec4(position,0.,1.);}")),l.attachShader(u,t(l.FRAGMENT_SHADER,"\n precision highp float;\n uniform sampler2D artwork; uniform sampler2D surface;\n uniform vec2 resolution; uniform vec2 sceneSize; uniform vec2 cellSize;\n uniform vec2 surfaceSize; uniform float strength;\n \nuniform float hoverMode;\nuniform vec4 hoverFocus;\nfloat surfaceLight(vec2 uv, vec2 size) {\n vec2 delta = (uv - hoverFocus.xy) * size / min(size.x, size.y) / hoverFocus.w;\n float light = exp(-3.0 * dot(delta, delta));\n if (hoverMode > 1.5) light = (exp(-delta.x * delta.x * 110.0) * 1.3 - exp(-delta.x * delta.x * 12.0) * .3) * exp(-delta.y * delta.y * 1.8);\n return hoverMode > .5 ? light * hoverFocus.z : 0.0;\n}\nvec3 illuminate(vec3 ink, float light) {\n return mix(ink, vec3(1.0), max(0.0, light) * .82) * (1.0 + min(0.0, light));\n}\n\n uniform sampler2D codes; uniform sampler2D cellColors; uniform sampler2D glyphAtlas;\n uniform vec2 gridSize; uniform vec2 atlasSize; uniform vec2 tileSize;\n uniform float atlasColumns; uniform float padding; uniform float glyphCount;\n uniform float dots; uniform float dotSize; uniform float directGlyphs; uniform vec4 backdrop;\n uniform float edgeEffect; uniform sampler2D textMask; uniform float hasTextMask;\n \nuniform float finishMode;\nuniform float finishPixelRatio;\nuniform float finishSoftness;\nvec3 edgeCoverage(sampler2D sheet, vec2 uv, vec2 atlas, vec2 pixel, vec2 viewport, float amount) {\n float a=texture2D(sheet,uv).a;\n if(amount<=0.0 || finishMode<.5) return vec3(a);\n vec2 radial=(pixel/viewport-.5)*2.0;\n float edge=smoothstep(.3,1.05,length(radial));\n float strength=clamp(amount,0.0,1.0)*edge;\n if(strength<=0.0) return vec3(a);\n vec2 cssPixel=pixel/max(1.0,finishPixelRatio);\n // Etch is a single texture sample: linework, not an opacity wash.\n if(finishMode>1.5 && finishMode<2.5) {\n float hatch=step(.68,fract((cssPixel.y+cssPixel.x*.22)*.5));\n return vec3(a*(1.0-hatch*strength*.64));\n }\n // Samples remain inside the current atlas tile's three-pixel padding.\n if(finishMode>2.5) {\n float band=floor(cssPixel.y/3.0);\n float phase=fract(sin(band*12.9898)*43758.5453);\n float tear=(phase-.5)*3.6*strength;\n float displaced=texture2D(sheet,uv+vec2(tear,0.0)/atlas).a;\n float cut=step(.72,fract(cssPixel.y*.5));\n return vec3(mix(a,displaced,strength)*(1.0-cut*.55*strength));\n }\n // A five-tap lens: opposed red/cyan edges with a short soft shoulder.\n // The center remains untouched; all offsets stay within three atlas texels.\n vec2 direction=normalize(vec2(radial.x-radial.y*.3,radial.y+radial.x*.3)+vec2(.00001));\n vec2 shift=direction*(2.35+.45*finishSoftness)*strength/atlas;\n float left=texture2D(sheet,uv-shift).a,right=texture2D(sheet,uv+shift).a;\n float softLeft=texture2D(sheet,uv-shift*.45).a,softRight=texture2D(sheet,uv+shift*.45).a;\n float red=left*.7+softLeft*.22+a*.08;\n float cyan=right*.7+softRight*.22+a*.08;\n // Reuse the same taps for a short optical blur and peripheral fade.\n // No whole-canvas blur, extra pass or softened HTML controls.\n float soft=a*.4+(left+right+softLeft+softRight)*.15;\n vec3 fringe=mix(vec3(red,cyan,cyan),vec3(soft),finishSoftness*.45);\n return mix(vec3(a),fringe,strength)*(1.-finishSoftness*strength*.32);\n\n}\n\n \nuniform float edgeSafe;\nuniform float trailAmount;\nuniform float trailKind;\nvec4 trailField(vec2 address) {\n return texture2D(surface,(address*(surfaceSize-1.0)+.5)/surfaceSize);\n}\nfloat trailFieldDensity(vec4 field) {\n return (field.r*65280.0+field.g*255.0)/65535.0*trailAmount;\n}\nfloat trailDensity(vec2 address) { return trailFieldDensity(trailField(address)); }\nfloat trailPin(vec2 cell, vec2 grid) {\n vec2 edge=min(cell,grid-1.0-cell);\n return mix(1.,smoothstep(1.0,5.0,min(edge.x,edge.y)),edgeSafe);\n}\nvec2 trailSource(vec2 cell, vec2 grid, vec4 field) {\n vec2 home=(cell+.5)/grid;\n if(trailKind>.5 || trailAmount<=0.) return home;\n float pin=trailPin(cell,grid);\n float response=1.-exp(-trailFieldDensity(field)*pin*3.5);\n vec2 drift=(field.ba*255.-128.)/127.;\n return clamp(home-drift*response*.026*pin,.5/grid,1.-.5/grid);\n}\nvec2 decodedGlyph(vec4 code) {\n return vec2(floor(code.r*255.+.5)+floor(code.g*255.+.5)*256.,code.b);\n}\n// Bilinear interpolation happens before glyph selection, never between bitmap\n// letters. Four small metadata reads replace the old four full-glyph gathers.\nvec2 flowGlyph(sampler2D codes,vec2 uv,vec2 grid) {\n vec2 p=uv*grid-.5,b=floor(p),f=fract(p);\n return mix(mix(decodedGlyph(texture2D(codes,(b+.5)/grid)),decodedGlyph(texture2D(codes,(b+vec2(1.5,.5))/grid)),f.x),\n mix(decodedGlyph(texture2D(codes,(b+vec2(.5,1.5))/grid)),decodedGlyph(texture2D(codes,(b+1.5)/grid)),f.x),f.y);\n}\nvec3 trailInk(vec3 ink, float density) {\n if (trailKind < .5) return ink;\n float peak=max(ink.r,max(ink.g,ink.b));\n float raised=trailKind>1.5?peak:max(peak,min(.44,density*.75));\n return peak>.001 ? ink*(raised/peak) : vec3(raised);\n}\nfloat flowIndex(float index,float count,float density) {\n float last=max(0.,count-1.);\n float response=1.-exp(-max(0.,density)*3.5);\n return max(0.,last-abs(last-(index+response*last*2.1)));\n}\nfloat trailTone(float tone, float density) {\n if (trailKind < .5) return flowIndex(tone,2.,density);\n return clamp(tone + (trailKind > 1.5 ? -density : density) * .65, 0.0, 1.0);\n}\nfloat trailIndex(float index, float count, float density, vec2 cell) {\n float grain=fract((cell.x*cell.x*17.0+cell.y*cell.y*23.0+cell.x*cell.y*19.0)*.0137);\n if(trailKind>1.5) return max(0.0,index-floor(density*count*(1.35+grain*.9)));\n if(trailKind<.5) {\n float seed=fract(sin(dot(cell,vec2(127.1,311.7)))*43758.5453);\n float response=1.-exp(-max(0.,density)*3.5);\n return floor(max(0.,flowIndex(index,count,density)-response*(1.-response)*seed*3.)+.5);\n }\n return min(count-1.0,index+floor(density*count*.85));\n}\n\n \n uniform float motionMode; uniform float motionTime; uniform float fineDither; uniform float ditherAmount;\n float printGrain(vec2 p) { return fract(52.9829189*fract(dot(p,vec2(.06711056,.00583715)))); }\n vec4 ambientAt(vec2 uv) {\n float p=motionTime*.5235987756;\n float edge=smoothstep(0.,.12,min(min(uv.x,1.-uv.x),min(uv.y,1.-uv.y)));\n if(motionMode<.5) return vec4(0.,0.,0.,1.);\n if(motionMode<1.5) return vec4(0.,0.,sin(uv.x*9.+uv.y*5.+p)*cos(uv.y*8.-uv.x*3.-p)*.065*edge,.9+.1*sin(uv.x*6.-uv.y*4.+p));\n if(motionMode<2.5) return vec4(sin(uv.y*9.+p)*cos(uv.x*7.-p)*6.*edge,cos(uv.x*8.+p)*sin(uv.y*6.-p)*4.*edge,0.,1.);\n float cycle=mod(motionTime,12.);\n float order=uv.x*.8+uv.y*.2+sin(uv.x*8.-uv.y*5.)*.08;\n float gone=smoothstep(1.8+order*1.2,3.8+order*1.2,cycle)*(1.-smoothstep(5.+order*1.7,7.2+order*1.7,cycle));\n return vec4(0.,0.,-gone*.95,1.-gone*.82);\n }\n\n float toneAt(vec2 uv) {\n vec2 p=uv*gridSize-.5, b=floor(p), f=fract(p);\n return mix(mix(texture2D(codes,(b+.5)/gridSize).b,texture2D(codes,(b+vec2(1.5,.5))/gridSize).b,f.x),mix(texture2D(codes,(b+vec2(.5,1.5))/gridSize).b,texture2D(codes,(b+1.5)/gridSize).b,f.x),f.y);\n }\n vec4 flowingCharacter(vec2 pixel, vec2 cell, vec4 ambient) {\n if(cell.x<0. || cell.y<0. || cell.x>=gridSize.x || cell.y>=gridSize.y) return vec4(0.);\n vec2 address=(cell+.5)/gridSize;\n vec4 field=trailField(address);\n vec2 local=pixel-cell*cellSize;\n if(local.x<0. || local.y<0. || local.x>=cellSize.x || local.y>=cellSize.y) return vec4(0.);\n vec2 source=trailSource(cell,gridSize,field);\n vec2 encoded=flowGlyph(codes,source,gridSize);\n vec4 color=texture2D(cellColors,source);\n float original=encoded.x;\n float density=trailFieldDensity(field)*trailPin(cell,gridSize),index=trailIndex(original,glyphCount,density,cell);\n if(original>.5) index=clamp(floor(index+ambient.z*(glyphCount-1.)+printGrain(cell)),0.,glyphCount-1.);\n if(index<.5 || color.a<.01) return vec4(0.);\n vec2 slot=vec2(mod(index,atlasColumns),floor(index/atlasColumns));\n float alpha=texture2D(glyphAtlas,(slot*tileSize+padding+local*resolution/sceneSize)/atlasSize).a;\n if(dots>.5) {\n vec2 d=(local-cellSize*.5)/min(cellSize.x,cellSize.y);\n float r=min(.48,(index/(glyphCount-1.))*.5*dotSize);\n alpha=1.-smoothstep(r-.06,r+.02,length(d));\n }\n vec3 coverage=dots>.5?vec3(alpha):edgeCoverage(glyphAtlas,(slot*tileSize+padding+local*resolution/sceneSize)/atlasSize,atlasSize,pixel,sceneSize,edgeEffect);\n coverage*=color.a;alpha=max(coverage.r,max(coverage.g,coverage.b));\n return vec4(trailInk(color.rgb,density)*coverage,alpha);\n }\n void main(){\n vec2 uv = vec2(gl_FragCoord.x, resolution.y - gl_FragCoord.y) / resolution;\n vec2 pixel = uv * sceneSize;\n if (strength > 0.) {\n vec4 normal = texture2D(surface, (uv * (surfaceSize - 1.) + .5) / surfaceSize) * 255.;\n vec2 slope = (vec2(normal.r * 256. + normal.g, normal.b * 256. + normal.a) - 32768.) / 32767.;\n vec2 edge = min(pixel, sceneSize - pixel) / cellSize;\n uv -= slope * strength * mix(1.,smoothstep(2.,8.,min(edge.x,edge.y)),edgeSafe) / sceneSize;\n }\n vec4 ambient=ambientAt(uv);\n uv -= ambient.xy/sceneSize;\n pixel=uv*sceneSize;\n vec4 ink = vec4(0.);\n if (directGlyphs > .5) {\n vec2 cell=floor(pixel/cellSize), address=(cell+.5)/gridSize;\n vec4 encoded=texture2D(codes,address), color=texture2D(cellColors,address);\n float index=floor(encoded.r*255.+.5)+floor(encoded.g*255.+.5)*256.;\n if(index>.5 && color.a>.01) {\n vec2 local=(pixel-cell*cellSize)*resolution/sceneSize;\n vec2 slot=vec2(mod(index,atlasColumns),floor(index/atlasColumns));\n float alpha=texture2D(glyphAtlas,(slot*tileSize+padding+local)/atlasSize).a*color.a;\n vec3 coverage=edgeCoverage(glyphAtlas,(slot*tileSize+padding+local)/atlasSize,atlasSize,pixel,sceneSize,edgeEffect)*color.a;\n ink=vec4(color.rgb*coverage,max(coverage.r,max(coverage.g,coverage.b)));\n }\n } else ink = texture2D(artwork, uv);\n if (fineDither > .5) {\n vec2 cell=floor(pixel/cellSize),address=(cell+.5)/gridSize;\n vec4 color=texture2D(cellColors,address);\n float density=trailAmount>0.?trailDensity(address):0.;\n vec2 source=trailAmount>0. && trailKind<.5?trailSource(cell,gridSize,trailField(address)):uv;\n float tone=trailTone(clamp(toneAt(source)+ambient.z,0.,1.),density*(trailKind<.5?trailPin(cell,gridSize):1.));\n float pitch=max(1.,min(cellSize.x,cellSize.y)*.32);\n float grain=.5+(printGrain(floor(pixel/pitch))-.5)*ditherAmount;\n float alpha=(tone<.001?0.:tone>.999?1.:smoothstep(grain-.035,grain+.035,tone))*color.a*ambient.w;\n // Preserve hue; tone is carried by mark coverage rather than muddy ink.\n vec3 hue=color.rgb/max(.001,max(color.r,max(color.g,color.b)));\n if(hasTextMask>.5) hue=mix(hue,vec3(.035),texture2D(textMask,vec2(gl_FragCoord.x,resolution.y-gl_FragCoord.y)/resolution).a);\n gl_FragColor=vec4(hue*alpha,alpha); return;\n }\n if ((trailAmount > 0. && trailKind > .5) || motionMode > .5) {\n vec2 cell=floor(pixel/cellSize), address=(cell+.5)/gridSize;\n float density=trailAmount>0.?trailDensity(address):0.;\n vec4 encoded=texture2D(codes,address);\n float original=floor(encoded.r*255.+.5)+floor(encoded.g*255.+.5)*256.;\n float index=trailIndex(original,glyphCount,density,cell);\n if(original>.5) index=clamp(floor(index+ambient.z*(glyphCount-1.)+printGrain(cell)),0.,glyphCount-1.);\n vec4 color=texture2D(cellColors,address);\n if((index!=original || motionMode>.5) && color.a>.01) {\n vec2 local=(pixel-cell*cellSize)*resolution/sceneSize;\n vec2 slot=vec2(mod(index,atlasColumns),floor(index/atlasColumns));\n float alpha=texture2D(glyphAtlas,(slot*tileSize+padding+local)/atlasSize).a;\n if(dots>.5) {\n vec2 d=(pixel-(cell+.5)*cellSize)/min(cellSize.x,cellSize.y);\n float r=min(.48,(index/(glyphCount-1.))*.5*dotSize);\n alpha=1.-smoothstep(r-.06,r+.02,length(d));\n }\n // Replace the cell, rather than blending two glyphs into a ghost.\n vec3 rgb=trailInk(color.rgb,density);\n ink=vec4(rgb*alpha*color.a,alpha*color.a);\n }\n }\n if(trailAmount>0. && trailKind<.5 && trailDensity((floor(pixel/cellSize)+.5)/gridSize)>.001) {\n ink=flowingCharacter(pixel,floor(pixel/cellSize),ambient);\n }\n vec3 straightInk = ink.a > .0 ? ink.rgb / ink.a : vec3(.0);\n float value = max(straightInk.r, max(straightInk.g, straightInk.b));\n // Lighting belongs to character ink; black/transparent gaps stay empty.\n float light = surfaceLight((floor(pixel / cellSize) + .5) * cellSize / sceneSize, sceneSize);\n vec3 lit = illuminate(straightInk, light * smoothstep(0., .22, value)) * ink.a;\n if(hasTextMask>.5) lit=mix(lit,vec3(.035)*ink.a,texture2D(textMask,vec2(gl_FragCoord.x,resolution.y-gl_FragCoord.y)/resolution).a);\n vec4 result = vec4(lit, ink.a)*ambient.w;\n gl_FragColor = directGlyphs > .5 ? result + backdrop*(1.-result.a) : result;\n }")),l.linkProgram(u),!l.getProgramParameter(u,l.LINK_STATUS))throw new Error("Surface shader link failed");l.useProgram(u),p=l.createBuffer(),l.bindBuffer(l.ARRAY_BUFFER,p),l.bufferData(l.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,1]),l.STATIC_DRAW);const e=l.getAttribLocation(u,"position");l.enableVertexAttribArray(e),l.vertexAttribPointer(e,2,l.FLOAT,!1,0,0),Y=Object.fromEntries(["finishSoftness","finishMode","finishPixelRatio","edgeEffect","textMask","hasTextMask","artwork","surface","resolution","sceneSize","cellSize","surfaceSize","strength","hoverMode","hoverFocus","codes","cellColors","glyphAtlas","gridSize","atlasSize","tileSize","atlasColumns","padding","glyphCount","dots","dotSize","directGlyphs","backdrop","trailKind","edgeSafe","trailAmount","motionMode","motionTime","fineDither","ditherAmount"].map(t=>[t,l.getUniformLocation(u,t)]));for(let t=0;t<6;t++){const e=l.createTexture();y.push(e),l.activeTexture(l.TEXTURE0+t),l.bindTexture(l.TEXTURE_2D,e),l.texParameteri(l.TEXTURE_2D,l.TEXTURE_MIN_FILTER,l.LINEAR),l.texParameteri(l.TEXTURE_2D,l.TEXTURE_MAG_FILTER,l.LINEAR),l.texImage2D(l.TEXTURE_2D,0,l.RGBA,1,1,0,l.RGBA,l.UNSIGNED_BYTE,new Uint8Array(4)),l.texParameteri(l.TEXTURE_2D,l.TEXTURE_WRAP_S,l.CLAMP_TO_EDGE),l.texParameteri(l.TEXTURE_2D,l.TEXTURE_WRAP_T,l.CLAMP_TO_EDGE)}l.uniform1i(Y.textMask,5),l.uniform1i(Y.codes,2),l.uniform1i(Y.cellColors,3),l.uniform1i(Y.glyphAtlas,4),l.uniform1i(Y.artwork,0),l.uniform1i(Y.surface,1),l.pixelStorei(l.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1),l.disable(l.BLEND),l.disable(l.DEPTH_TEST),h.addEventListener("webglcontextlost",H),B()}catch{H()}const O=()=>{S||(N.reset(),G=null,b=!1,s())};return document.fonts?.addEventListener("loadingdone",O),document.fonts?.ready.then(O),{get canvas(){return h},canRenderGlyphs:t=>!!l&&!S&&v(t),render(t,s,a,r,u,p,x,w,B=0,W={}){const O=i(w?.animationStyle),K=U.update(B,O,w?.animationSpeed),$=(t=>"terminal"===t?.artStyle&&!t.customText&&!t.charsetFrames?.length&&!/[A-Za-z]/.test(t.charset??""))(w),q=!!l&&!!x&&v(w);if(q!==D&&(b=!1,D=q),S||!a||!r||!e.width||!e.height)return;const j=Math.min(e.width/a,1.5,Math.sqrt(4e6/(a*r))),J=Math.max(1,Math.round(a*j)),V=Math.max(1,Math.round(r*j));if(h.width===J&&h.height===V||(h.width=J,h.height=V,b=!1),l&&(e.width>E||e.height>E)&&H(),(q||d(s.mode)||"none"!==O||$)&&(t||!b||!G)&&(G=N.update(e,a,r,u,p,j,x,w),l)){const{plan:t,packed:e,atlas:i}=G;for(const[t,i]of[[2,e.indices],[3,e.colors]])l.activeTexture(l.TEXTURE0+t),l.bindTexture(l.TEXTURE_2D,y[t]),l.texParameteri(l.TEXTURE_2D,l.TEXTURE_MIN_FILTER,3===t?l.LINEAR:l.NEAREST),l.texParameteri(l.TEXTURE_2D,l.TEXTURE_MAG_FILTER,3===t?l.LINEAR:l.NEAREST),A!==e.cols||k!==e.rows?l.texImage2D(l.TEXTURE_2D,0,l.RGBA,e.cols,e.rows,0,l.RGBA,l.UNSIGNED_BYTE,i):l.texSubImage2D(l.TEXTURE_2D,0,0,0,e.cols,e.rows,l.RGBA,l.UNSIGNED_BYTE,i);A=e.cols,k=e.rows,T!==t&&(l.activeTexture(l.TEXTURE4),l.bindTexture(l.TEXTURE_2D,y[4]),l.texImage2D(l.TEXTURE_2D,0,l.RGBA,l.RGBA,l.UNSIGNED_BYTE,i),T=t),l.uniform2f(Y.gridSize,e.cols,e.rows),l.uniform2f(Y.atlasSize,t.atlasWidth,t.atlasHeight),l.uniform2f(Y.tileSize,t.tileWidth,t.tileHeight),l.uniform1f(Y.atlasColumns,t.atlasColumns),l.uniform1f(Y.padding,t.padding),l.uniform1f(Y.glyphCount,t.glyphs.length),l.uniform1f(Y.dots,G.dots?1:0),l.uniform1f(Y.dotSize,G.dotSize)}if(l){l.uniform1f(Y.motionMode,(t=>["none","print","current","reform"].indexOf(t))(O)),l.uniform1f(Y.motionTime,K),l.uniform1f(Y.fineDither,$?1:0),l.uniform1f(Y.ditherAmount,Math.max(0,Math.min(2,w?.ditherStrength??1))),l.uniform1f(Y.trailKind,"dissolve"===s.mode?2:"contour"===s.mode?1:0),l.uniform1f(Y.edgeSafe,s.edgeSafe?1:0),l.uniform1f(Y.trailAmount,d(s.mode)?s.focus[2]:0),l.viewport(0,0,J,V),q||!t&&b||(l.activeTexture(l.TEXTURE0),l.bindTexture(l.TEXTURE_2D,y[0]),l.pixelStorei(l.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!0),l.texImage2D(l.TEXTURE_2D,0,l.RGBA,l.RGBA,l.UNSIGNED_BYTE,e),l.pixelStorei(l.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!1)),l.uniform1f(Y.directGlyphs,q?1:0),!q||!t&&b||l.uniform4fv(Y.backdrop,W.textMask||function(t){const e=t.length,i=t[0]?.length??0;for(let s=0;s<e;s+=Math.max(1,e>>2))for(let e=0;e<i;e+=Math.max(1,i>>2))if(t[s][e].a<200)return!0;return!1}(x)?[0,0,0,0]:M(e)),b=!0,l.activeTexture(l.TEXTURE1),l.bindTexture(l.TEXTURE_2D,y[1]),z!==s.width||R!==s.height?(l.texImage2D(l.TEXTURE_2D,0,l.RGBA,s.width,s.height,0,l.RGBA,l.UNSIGNED_BYTE,s.pixels),z=s.width,R=s.height):l.texSubImage2D(l.TEXTURE_2D,0,0,0,s.width,s.height,l.RGBA,l.UNSIGNED_BYTE,s.pixels),l.uniform2f(Y.resolution,J,V),l.uniform2f(Y.sceneSize,a,r),l.uniform2f(Y.cellSize,u,p),l.uniform2f(Y.surfaceSize,s.width,s.height),l.uniform1f(Y.strength,s.strength),l.uniform1f(Y.hoverMode,"light"===s.mode?1:"scan"===s.mode?2:0),l.uniform4fv(Y.hoverFocus,s.focus),W.textMask&&W.textMask!==F&&(l.activeTexture(l.TEXTURE5),l.bindTexture(l.TEXTURE_2D,y[5]),l.texImage2D(l.TEXTURE_2D,0,l.RGBA,l.RGBA,l.UNSIGNED_BYTE,W.textMask.canvas),F=W.textMask),l.uniform1f(Y.hasTextMask,W.textMask?1:0);const i=function(t={}){const e=g.some(e=>e.value===t.filter)?t.filter:"prism",i=Number.isFinite(t.edgeEffect)?Math.max(0,Math.min(1,t.edgeEffect)):t.filter?1:0,s=Number.isFinite(t.edgeSoftness)?Math.max(0,Math.min(1,t.edgeSoftness)):0;return{mode:["clean","prism","etch","signal"].indexOf(e),amount:"clean"===e?0:i,softness:"prism"===e?s:0}}(W);l.uniform1f(Y.edgeEffect,i.amount),l.uniform1f(Y.finishMode,i.mode),l.uniform1f(Y.finishSoftness,i.softness),l.uniform1f(Y.finishPixelRatio,1),l.drawArrays(l.TRIANGLE_STRIP,0,4)}else if(c){if(c.setTransform(j,0,0,j,0,0),c.clearRect(0,0,a,r),c.drawImage(e,0,0,a,r),("none"!==O||$)&&G){c.clearRect(0,0,a,r);const{plan:t,packed:e,atlas:i}=G,h=[0,0,0,1],l=[0,0,0,0,0,0],g=Math.max(1,.32*Math.min(u,p));for(let a=0;a<e.rows;a++)for(let r=0;r<e.cols;r++){const x=(r+.5)/e.cols,v=(a+.5)/e.rows,M=4*(a*e.cols+r);if(e.colors[M+3]<10)continue;o(O,x,v,K,h);const y=4*(Math.min(s.height-1,Math.round(v*(s.height-1)))*s.width+Math.min(s.width-1,Math.round(x*(s.width-1)))),S=d(s.mode)?(256*s.pixels[y]+s.pixels[y+1])/65535*s.focus[2]:0,b=e.indices[M]+256*e.indices[M+1];"trail"===s.mode&&m(e.indices,e.colors,e.cols,e.rows,r,a,S,(s.pixels[y+2]-128)/127,(s.pixels[y+3]-128)/127,t.glyphs.length,l,s.edgeSafe);let E="trail"===s.mode?l[0]:"dissolve"===s.mode?b-Math.floor(S*t.glyphs.length*1.8):b+Math.floor(S*t.glyphs.length*.85);b>0&&(E+=h[2]*(t.glyphs.length-1)),E=Math.max(0,Math.min(t.glyphs.length-1,Math.floor(E+n(r,a))));let T=h[0],A=h[1];s.strength>0&&(T+=(256*s.pixels[y]+s.pixels[y+1]-32768)/32767*s.strength,A+=(256*s.pixels[y+2]+s.pixels[y+3]-32768)/32767*s.strength);const k=r*u+T,z=a*p+A,R=("trail"===s.mode?l[5]:e.colors[M+3])/255*h[3],D="trail"===s.mode?l[2]:e.colors[M],C="trail"===s.mode?l[3]:e.colors[M+1],F="trail"===s.mode?l[4]:e.colors[M+2],_=$?Math.max(1,D,C,F):255,I=`rgb(${D/_*255},${C/_*255},${F/_*255})`;if(c.fillStyle=I,$){const t="trail"===s.mode?f(Math.max(0,Math.min(1,l[1]+h[2])),2,S):Math.max(0,Math.min(1,e.indices[M+2]/255+h[2]+.65*("dissolve"===s.mode?-S:S)));c.globalAlpha=R;for(let e=0;e<p;e+=g)for(let i=0;i<u;i+=g)t>.5+(n(Math.floor((k+i)/g),Math.floor((z+e)/g))-.5)*Math.max(0,Math.min(2,w?.ditherStrength??1))&&c.fillRect(k+i,z+e,Math.min(g,u-i),Math.min(g,p-e))}else if(E>0)if(c.globalAlpha=R,G.dots){const e=Math.min(.48,E/(t.glyphs.length-1)*.5*G.dotSize)*Math.min(u,p);c.beginPath(),c.arc(k+.5*u,z+.5*p,e,0,2*Math.PI),c.fill()}else c.drawImage(i,E%t.atlasColumns*t.tileWidth+t.padding,Math.floor(E/t.atlasColumns)*t.tileHeight+t.padding,t.cellWidth*j,t.cellHeight*j,k,z,u,p),c.globalAlpha=1,c.globalCompositeOperation="source-atop",c.fillRect(k,z,u,p),c.globalCompositeOperation="source-over"}c.globalAlpha=1}else if(d(s.mode)&&G){const{plan:t,packed:e,atlas:i}=G,n=[0,0,0,0,0,0];for(let a=0;a<e.rows;a++)for(let o=0;o<e.cols;o++){const r=4*(Math.min(s.height-1,Math.round((a+.5)/e.rows*(s.height-1)))*s.width+Math.min(s.width-1,Math.round((o+.5)/e.cols*(s.width-1)))),h=(256*s.pixels[r]+s.pixels[r+1])/65535*s.focus[2],l=4*(a*e.cols+o),d=.0137*(o*o*17+a*a*23+o*a*19),f=d-Math.floor(d);"trail"===s.mode&&m(e.indices,e.colors,e.cols,e.rows,o,a,h,(s.pixels[r+2]-128)/127,(s.pixels[r+3]-128)/127,t.glyphs.length,n,s.edgeSafe);const g=e.indices[l]+256*e.indices[l+1],x="trail"===s.mode?Math.round(n[0]):"dissolve"===s.mode?Math.max(0,g-Math.floor(h*t.glyphs.length*(1.35+.9*f))):Math.min(t.glyphs.length-1,g+Math.floor(h*t.glyphs.length*.85));if(x===g&&("trail"!==s.mode||h<1e-4)||e.colors[l+3]<10)continue;const v=o*u,M=a*p;if(c.clearRect(v,M,u,p),c.globalAlpha=("trail"===s.mode?n[5]:e.colors[l+3])/255,G.dots){const e=Math.min(.48,x/(t.glyphs.length-1)*.5*G.dotSize)*Math.min(u,p);c.fillStyle="#fff",c.beginPath(),c.arc(v+.5*u,M+.5*p,e,0,2*Math.PI),c.fill()}else c.drawImage(i,x%t.atlasColumns*t.tileWidth+t.padding,Math.floor(x/t.atlasColumns)*t.tileHeight+t.padding,t.cellWidth*j,t.cellHeight*j,v,M,u,p);c.globalAlpha=1,c.globalCompositeOperation="source-atop";const y="trail"===s.mode?n[2]:e.colors[l],w="trail"===s.mode?n[3]:e.colors[l+1],S="trail"===s.mode?n[4]:e.colors[l+2],b=Math.max(y,w,S),E="dissolve"===s.mode||"trail"===s.mode?b:Math.max(b,Math.min(112,191*h)),T=b?E/b:0;c.fillStyle=`rgb(${b?y*T:E},${b?w*T:E},${b?S*T:E})`,c.fillRect(v,M,u,p),c.globalCompositeOperation="source-over"}}else if("light"===s.mode||"scan"===s.mode){!t&&L&&_.width===J&&_.height===V||(_.width=J,_.height=V,I.width=J,I.height=V,X.filter="brightness(3)",X.drawImage(e,0,0,J,V),X.filter="none",L=!0);const[i,n,o,h]=s.focus;if(o>.001){P.setTransform(1,0,0,1,0,0),P.clearRect(0,0,J,V),P.drawImage(_,0,0),P.globalCompositeOperation="destination-in",P.save(),P.translate(i*J,n*V),P.scale("scan"===s.mode?.13:1,1);const t=h*Math.min(J,V),e=P.createRadialGradient(0,0,0,0,0,t);e.addColorStop(0,`rgba(255,255,255,${o})`),e.addColorStop(.5,`rgba(255,255,255,${.4*o})`),e.addColorStop(1,"rgba(255,255,255,0)"),P.fillStyle=e,P.fillRect(10*-J,10*-V,20*J,20*V),P.restore(),P.globalCompositeOperation="source-over",c.globalCompositeOperation="source-atop",c.drawImage(I,0,0,a,r),c.globalCompositeOperation="source-over"}}else if(s.strength>0){const t=32,i=18,n=a/t,o=r/i;for(let h=0;h<i;h++)for(let l=0;l<t;l++){const d=(l+.5)/t,f=(h+.5)/i,m=Math.min(s.width-1,Math.round(d*(s.width-1))),g=4*(Math.min(s.height-1,Math.round(f*(s.height-1)))*s.width+m),x=s.pixels,v=Math.min(l*n/u,(a-(l+1)*n)/u,h*o/p,(r-(h+1)*o)/p),M=Math.max(0,Math.min(1,(v-2)/6)),y=s.edgeSafe?M*M*(3-2*M):1,w=(256*x[g]+x[g+1]-32768)/32767*s.strength*y,S=(256*x[g+2]+x[g+3]-32768)/32767*s.strength*y;Math.abs(w)+Math.abs(S)<.02||(c.clearRect(l*n,h*o,n,o),c.drawImage(e,Math.max(0,Math.min(a-n,l*n-w))*e.width/a,Math.max(0,Math.min(r-o,h*o-S))*e.height/r,n*e.width/a,o*e.height/r,l*n,h*o,n,o))}}C.paint(c,W.textMask,a,r)}},destroy(){S=!0,C.destroy(),document.fonts?.removeEventListener("loadingdone",O),N.destroy(),h.removeEventListener("webglcontextlost",H),W(),h.remove(),_.width=_.height=I.width=I.height=1,e.style.visibility=r,l?.getExtension("WEBGL_lose_context")?.loseContext()}}}function w(e,s,n={}){let a,o,r={effect:"trail",strength:.55,radius:n.effect&&"trail"!==n.effect?.2:.45,animated:!1,fps:30,fontSize:7,charAspect:.58,charSpacing:1,paused:!1,charset:" .:-=+*#%@",customText:"",renderMode:"ascii",dotSizeRatio:.72,...n},h=new u(s.clientWidth/Math.max(1,s.clientHeight)),l=!1,c=!1,d=!0,f=0,m=0,g=-1/0,p=0,x=null,v=!1,M=[];const w=matchMedia("(prefers-reduced-motion: reduce)"),S=()=>{l||!c||document.hidden||f||(f=requestAnimationFrame(E))},b=y(e,s,()=>queueMicrotask(()=>{d=!0,S()}));function E(t){if(f=0,l||!c||document.hidden)return;const e=s.clientWidth,n=s.clientHeight;if(!e||!n)return;const u=w.matches||r.paused;h.configure(r.effect,r.strength,r.radius,r.edgeSafe);const y=h.active;if(!u){if(p+=m?Math.min(.1,(t-m)/1e3):0,v){const t=s.getBoundingClientRect();if(t.width&&t.height)for(const e of M)h.move((e.x-t.left)/t.width,(e.y-t.top)/t.height,e.time);M=[],x||h.leave(),v=!1}h.step(m?(t-m)/1e3:1/60)}const E=d||r.animated&&!u&&t-g>=1e3/Math.max(1,Math.min(60,r.fps))-.5;(E||y||h.active||!u&&"none"!==i(r.motion))&&(E&&(a=r.getFrame?.()),b.render(E,h.refraction,e,n,r.fontSize*r.charSpacing,r.fontSize/r.charAspect*r.charSpacing,a,{charset:r.charset,customText:r.customText,renderMode:r.renderMode,dotSizeRatio:r.dotSizeRatio,colorMode:r.colorMode??"fullcolor",accentColor:r.accentColor??"#888888",animationStyle:r.motion,animationSpeed:r.motionSpeed??1,artStyle:r.fineDither?"terminal":"classic",ditherStrength:r.ditherStrength??1},p,{filter:r.filter,edgeEffect:r.edgeEffect,edgeSoftness:r.edgeSoftness,textMask:o?.read()}),E&&(g=t),d=!1),m=t,u||!r.animated&&!h.active&&"none"===i(r.motion)||S()}r.textMask&&(o=t(e,r.textMask,()=>{d=!0,S()}));const T=()=>{h.clear(),x=null,M=[],v=!1,m=0,d=!0,cancelAnimationFrame(f),f=0,S()},A=t=>{if("touch"===t.pointerType||r.paused||w.matches)return;if(t.target instanceof Element&&t.target.closest("button,a,input,summary,select"))return void k();const e=s.getBoundingClientRect();t.clientX<e.left||t.clientX>e.right||t.clientY<e.top||t.clientY>e.bottom?k():(x={x:t.clientX,y:t.clientY,time:t.timeStamp},M.push(x),M.length>6&&M.shift(),v=!0,S())},k=()=>{x=null,v=!0,S()},z=new IntersectionObserver(([t])=>{c=t.isIntersecting,T()});z.observe(e);const R=new ResizeObserver(()=>{h=new u(s.clientWidth/Math.max(1,s.clientHeight)),T()});return R.observe(s),e.addEventListener("pointermove",A),e.addEventListener("pointerleave",k),e.addEventListener("pointercancel",k),document.addEventListener("visibilitychange",T),w.addEventListener("change",T),{get canvas(){return b.canvas},invalidate(){o?.invalidate(),d=!0,S()},update(i){"textMask"in i&&(o?.destroy(),o=i.textMask?t(e,i.textMask,()=>{d=!0,S()}):void 0),r={...r,...i},T()},destroy(){l||(l=!0,cancelAnimationFrame(f),z.disconnect(),R.disconnect(),b.destroy(),o?.destroy(),e.removeEventListener("pointermove",A),e.removeEventListener("pointerleave",k),e.removeEventListener("pointercancel",k),document.removeEventListener("visibilitychange",T),w.removeEventListener("change",T))}}}export{t as createTextMask,w as mountHover,w as mountStudioHover};//# sourceMappingURL=hover.js.map
|
package/dist/studio.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var t=["ascii","blocks","braille","dots","lines","cross","diagonal","diamond","mixed","pixel","mosaic","lego","voxel","disco","dither"],e=["none","bayer2","bayer4","bayer8","bayer16","floyd-steinberg","atkinson","stucki","sierra","sierra-lite","burkes","jarvis","halftone","lines","noise"],i=["source-over","multiply","screen","overlay","soft-light","hard-light","color-dodge","color-burn","hue","saturation","color","luminosity"],s={original:[],mono:["#080808","#f2f2e8"],asciify:["#080808","#625b38","#a19558","#e8b900"],gameboy:["#0f380f","#306230","#8bac0f","#9bbc0f"],cga:["#000000","#55ffff","#ff55ff","#ffffff"],pico8:["#000000","#1d2b53","#7e2553","#008751","#ab5236","#5f574f","#c2c3c7","#fff1e8","#ff004d","#ffa300","#ffec27","#00e436","#29adff","#83769c","#ff77a8","#ffccaa"],c64:["#000000","#ffffff","#880000","#aaffee","#cc44cc","#00cc55","#0000aa","#eeee77","#dd8855","#664400","#ff7777","#333333","#777777","#aaff66","#0088ff","#bbbbbb"],amber:["#100b00","#5f3b00","#c98014","#ffd17c"],ice:["#081b29","#25586e","#69a6b3","#d9ece7"],risograph:["#f4ebd0","#f2594b","#2853a5","#29232e"],sepia:["#201b17","#6b5039","#b49868","#f6e6c5"],nord:["#2e3440","#4c566a","#88c0d0","#eceff4"],dusk:["#211b35","#654271","#c3788c","#f5c9a3"],forest:["#101f1b","#355747","#87a16f","#e4e3ba"],ocean:["#071b33","#17577f","#3fa7a4","#d9efde"],newsprint:["#191919","#666666","#aaaaaa","#eee9df"],custom:["#080808","#e8b900"]},a={version:1,aspectRatio:"original",style:"ascii",cellSize:7,charset:" .:-=+*#%@",colorMode:"accent",ink:"#e8b900",crop:{x:.5,y:.5,zoom:1,rotation:0},backdrop:{mode:"solid",color:"#080808",color2:"#393323",blur:12,opacity:1},color:{brightness:0,contrast:1,saturation:1,grayscale:0,tint:"#e8b900",amount:0,blend:"source-over"},dither:{algorithm:"none",palette:"mono",colors:["#080808","#e8b900"],amount:1,scale:2,threshold:.5,motion:"none",speed:1},mask:{enabled:!1,invert:!1,shapes:[]},lights:[],effects:{bloom:0,characterBloom:0,grain:0,dust:0,scanlines:0,crt:0,prism:0,vignette:0,glitch:0,pixelate:0,blur:0,blurType:"gaussian",angle:0,focus:.5,halftone:0},motion:{type:"none",speed:1},hover:{effect:"trail",strength:.55,radius:.2,edgeSafe:!1}},o=t=>t&&"object"==typeof t&&!Array.isArray(t)?t:{},r=(t,e,i,s)=>"number"==typeof t&&Number.isFinite(t)?Math.min(s,Math.max(i,t)):e,n=(t,e)=>"string"==typeof t&&/^#[\da-f]{6}$/i.test(t)?t:e,h=(t,e,i)=>e.includes(t)?t:i;function l(l={}){const c=o(l),d=a;if(void 0!==c.version&&1!==c.version)throw new Error("Unsupported studio settings version. Update asciify-engine.");const f=o(c.crop),m=o(c.backdrop),u=o(c.color),p=o(c.dither),g=o(c.mask),M=o(c.effects),x=o(c.motion),v=o(c.hover),w={...d.effects};for(const t of["bloom","characterBloom","grain","dust","scanlines","crt","prism","vignette","glitch","pixelate","halftone"])w[t]=r(M[t],0,0,1);w.blur=r(M.blur,0,0,24),w.blurType=h(M.blurType,["gaussian","directional","radial","progressive"],d.effects.blurType),w.angle=r(M.angle,0,-180,180),w.focus=r(M.focus,.5,0,1);let b=2048;return{version:1,aspectRatio:h(c.aspectRatio,["original","16:9","9:16","1:1","4:3","3:4","21:9"],"original"),style:h(c.style,t,d.style),cellSize:r(c.cellSize,7,3,60),charset:"string"==typeof c.charset&&c.charset.length?Array.from(c.charset).slice(0,128).join(""):d.charset,colorMode:h(c.colorMode,["accent","source","gray"],d.colorMode),ink:n(c.ink,d.ink),crop:{x:r(f.x,.5,0,1),y:r(f.y,.5,0,1),zoom:r(f.zoom,1,1,5),rotation:90*Math.round(r(f.rotation,0,-360,360)/90)},backdrop:{mode:h(m.mode,["solid","transparent","source","blurred","gradient"],d.backdrop.mode),color:n(m.color,d.backdrop.color),color2:n(m.color2,d.backdrop.color2),blur:r(m.blur,12,0,32),opacity:r(m.opacity,1,0,1)},color:{brightness:r(u.brightness,0,-1,1),contrast:r(u.contrast,1,0,3),saturation:r(u.saturation,1,0,3),grayscale:r(u.grayscale,0,0,1),tint:n(u.tint,d.color.tint),amount:r(u.amount,0,0,1),blend:h(u.blend,i,d.color.blend)},dither:{algorithm:h(p.algorithm,e,"none"),palette:"string"==typeof p.palette&&Object.prototype.hasOwnProperty.call(s,p.palette)?p.palette:"mono",colors:Array.isArray(p.colors)&&p.colors.length>=2?p.colors.slice(0,32).map(t=>n(t,"#000000")):[...d.dither.colors],amount:r(p.amount,1,0,2),scale:Math.round(r(p.scale,2,1,12)),threshold:r(p.threshold,.5,0,1),motion:h(p.motion,["none","drift","shimmer"],"none"),speed:r(p.speed,1,.1,3)},mask:{enabled:!0===g.enabled,invert:!0===g.invert,shapes:Array.isArray(g.shapes)?g.shapes.slice(0,64).map(t=>{const e=o(t),i=h(e.kind,["rectangle","ellipse","brush"],"rectangle"),s="brush"===i&&Array.isArray(e.points)?e.points.slice(0,b).map(t=>Array.isArray(t)?[Math.round(1e4*r(t[0],0,0,1))/1e4,Math.round(1e4*r(t[1],0,0,1))/1e4]:[0,0]):[];return b-=s.length,{kind:i,x:r(e.x,0,0,1),y:r(e.y,0,0,1),width:r(e.width,.5,0,1),height:r(e.height,.5,0,1),size:r(e.size,.05,.005,.5),points:s}}):[]},lights:Array.isArray(c.lights)?c.lights.slice(0,4).map(t=>{const e=o(t);return{x:r(e.x,.5,0,1),y:r(e.y,.5,0,1),radius:r(e.radius,.3,.02,1),intensity:r(e.intensity,.5,0,1),color:n(e.color,"#ffffff")}}):[],effects:w,motion:{type:h(x.type,["none","breathe","wave","reveal","glitch","rainbow","hologram","fire","chrome","ripple","vapor"],"none"),speed:r(x.speed,1,.1,3)},hover:{effect:h(v.effect,["none","trail","water","contour","dissolve","silk","vortex"],"trail"),strength:r(v.strength,.55,0,1),radius:r(v.radius,.2,.1,1),edgeSafe:!0===v.edgeSafe}}}function c(t,e,i,s,a){const o=Math.abs(a.rotation/90)%2==1,r=o?e:t,n=o?t:e,h=Math.max(i/r,s/n)*a.zoom;return{width:r*h,height:n*h,x:(i-r*h)*a.x,y:(s-n*h)*a.y,scale:h,rotated:o}}function d(t,e,i){if(Math.abs(i.crop.rotation/90)%2==1&&([t,e]=[e,t]),"original"===i.aspectRatio)return[t,e];const[s,a]=i.aspectRatio.split(":").map(Number);return t/e>s/a?[Math.round(e*s/a),e]:[t,Math.round(t*a/s)]}function f(t,e){const i={...t,...e};for(const s of["crop","backdrop","color","dither","mask","effects","motion","hover"])e[s]&&Object.assign(i,{[s]:{...t[s],...e[s]}});return l(i)}var m=[["ascii","Signature ASCII","Brand ink and clean characters.",{}],["print","Newsprint","Fine diffusion on warm paper.",{style:"dither",dither:{algorithm:"floyd-steinberg",palette:"newsprint"}}],["handheld","Pocket camera","Four-tone ordered dither.",{style:"dither",dither:{algorithm:"bayer4",palette:"gameboy",scale:3}}],["riso","Two inks","Limited-color print texture.",{style:"dither",dither:{algorithm:"atkinson",palette:"risograph",scale:2}}],["night","Night signal","Gray characters and optical fringe.",{ink:"#888888",effects:{prism:.7,scanlines:.2,vignette:.3}}],["terminal","Phosphor","Green glyphs with a soft glow.",{ink:"#83efad",effects:{bloom:.4,scanlines:.35,crt:.2}}],["mosaic","Mosaic study","Separated color tiles.",{style:"mosaic",cellSize:14,colorMode:"source"}],["bricks","Brickwork","Colorful studded cells.",{style:"lego",cellSize:18,colorMode:"source"}],["voxel","Little volumes","Three-face isometric tiles.",{style:"voxel",cellSize:22,colorMode:"source"}],["disco","Mirror room","Faceted tiles and warm light.",{style:"disco",cellSize:18,colorMode:"source",lights:[{x:.35,y:.25,radius:.25,intensity:.45,color:"#fff2d4"}]}],["wallpaper","Wallpaper","Living ASCII over a softened source.",{backdrop:{mode:"blurred",blur:18,opacity:.55},ink:"#f2e9c9",motion:{type:"breathe",speed:.5}}],["blueprint","Blueprint","Linework in a cool monochrome.",{style:"lines",ink:"#9bccdf",backdrop:{mode:"solid",color:"#0a1e30"}}]].map(([t,e,i,s])=>({id:t,name:e,description:i,settings:l(s)}));function u(t){const e=m.find(e=>e.id===t);if(!e)throw new Error("Unknown studio look.");return l(e.settings)}var p=(t,e)=>{const i=43758.5453*Math.sin(127.1*t+311.7*e);return i-Math.floor(i)};function g(t,e,i){let s=0;for(let a=1;a<i;a*=2){const i=Math.floor(t/a)%2;s=4*s+[[0,2],[3,1]][Math.floor(e/a)%2][i]}return(s+.5)/(i*i)-.5}var M={"floyd-steinberg":[[1,0,7/16],[-1,1,3/16],[0,1,5/16],[1,1,1/16]],atkinson:[[1,0,.125],[2,0,.125],[-1,1,.125],[0,1,.125],[1,1,.125],[0,2,.125]],stucki:[[1,0,8/42],[2,0,4/42],[-2,1,2/42],[-1,1,4/42],[0,1,8/42],[1,1,4/42],[2,1,2/42],[-2,2,1/42],[-1,2,2/42],[0,2,4/42],[1,2,2/42],[2,2,1/42]],sierra:[[1,0,5/32],[2,0,3/32],[-2,1,2/32],[-1,1,4/32],[0,1,5/32],[1,1,4/32],[2,1,2/32],[-1,2,2/32],[0,2,3/32],[1,2,2/32]],"sierra-lite":[[1,0,.5],[-1,1,.25],[0,1,.25]],burkes:[[1,0,.25],[2,0,4/32],[-2,1,2/32],[-1,1,4/32],[0,1,.25],[1,1,4/32],[2,1,2/32]],jarvis:[[1,0,7/48],[2,0,5/48],[-2,1,3/48],[-1,1,5/48],[0,1,7/48],[1,1,5/48],[2,1,3/48],[-2,2,1/48],[-1,2,3/48],[0,2,5/48],[1,2,3/48],[2,2,1/48]]},x=t=>[parseInt(t.slice(1,3),16),parseInt(t.slice(3,5),16),parseInt(t.slice(5,7),16)];function v(t,e,i){const s=Math.min(t*Math.max(1,i),(1-t)*Math.max(1,i),e*Math.max(1,1/i),(1-e)*Math.max(1,1/i)),a=Math.max(0,Math.min(1,(s-.035)/.105));return a*a*a*(a*(6*a-15)+10)}var w=class{constructor(t,e){this.edgeSafe=!1,this.previous=null,this.peak=0,this.mode="dissolve",this.width=t,this.height=e;const i=t*e;this.pixels=new Uint8Array(4*i),this.ink=new Float32Array(i),this.targetX=new Float32Array(i),this.targetY=new Float32Array(i),this.offsetX=new Float32Array(i),this.offsetY=new Float32Array(i),this.edge=new Float32Array(i);for(let i=0;i<e;i++)for(let s=0;s<t;s++)this.edge[i*t+s]=v(s/(t-1),i/(e-1),t/e);this.clear()}get active(){return this.peak>2e-4}setMode(t){t!==this.mode&&(this.mode=t,this.clear())}clear(){for(const t of[this.ink,this.targetX,this.targetY,this.offsetX,this.offsetY,this.pixels])t.fill(0);if(this.previous=null,this.peak=0,"dissolve"!==this.mode)for(let t=0;t<this.pixels.length;t+=4)this.pixels[t]=this.pixels[t+2]=128}leave(){this.previous=null}move(t,e,i){if(!Number.isFinite(t+e+i))return;t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e));const s=this.previous;this.previous={x:t,y:e};const a=this.width,o=this.height,r=Math.max(1,a/o),n=Math.max(1,o/a),h=s?(t-s.x)*r:0,l=s?(e-s.y)*n:0,c=Math.hypot(h,l);if(!s&&"dissolve"!==this.mode)return;if(s&&c<1e-4)return;const d=.035+.11*Math.max(.1,Math.min(1,i)),f=Math.min(128,Math.max(1,Math.ceil(c/(.45*d)))),m=c?h/c:1,u=c?l/c:0,p=Math.min(1,c/(d*f)*2.2);for(let i=0;i<f;i++){const h=(i+.5)/f,l=s?s.x+(t-s.x)*h:t,c=s?s.y+(e-s.y)*h:e,g=Math.max(0,Math.floor((l-2.5*d/r)*(a-1))),M=Math.min(a-1,Math.ceil((l+2.5*d/r)*(a-1))),x=Math.max(0,Math.floor((c-2.5*d/n)*(o-1))),v=Math.min(o-1,Math.ceil((c+2.5*d/n)*(o-1)));for(let t=x;t<=v;t++)for(let e=g;e<=M;e++){const i=(e/(a-1)-l)*r/d,s=(t/(o-1)-c)*n/d,h=Math.exp(1.5*-(i*i+s*s)),f=t*a+e;if("dissolve"===this.mode)this.ink[f]=Math.max(this.ink[f],h);else{const t=(-i*u+s*m)*h*2.8,e="silk"===this.mode?m*t:-s*h*2.5,a="silk"===this.mode?u*t:i*h*2.5;this.targetX[f]=Math.max(-1,Math.min(1,this.targetX[f]+e*p)),this.targetY[f]=Math.max(-1,Math.min(1,this.targetY[f]+a*p))}}}this.peak=1}step(t){if(!this.active||!Number.isFinite(t))return;const e=Math.max(0,Math.min(.05,t)),i=Math.exp(-("dissolve"===this.mode?2.15:3.2)*e),s=1-Math.exp(-22*e);let a=0;for(let t=0;t<this.ink.length;t++)if("dissolve"===this.mode){this.ink[t]*=i,a=Math.max(a,this.ink[t]);const e=Math.round(65535*this.ink[t]);this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e}else{this.targetX[t]*=i,this.targetY[t]*=i,this.offsetX[t]+=(this.targetX[t]-this.offsetX[t])*s,this.offsetY[t]+=(this.targetY[t]-this.offsetY[t])*s,a=Math.max(a,Math.abs(this.offsetX[t]),Math.abs(this.offsetY[t]),Math.abs(this.targetX[t]),Math.abs(this.targetY[t]));const e=Math.round(this.offsetX[t]*(this.edgeSafe?this.edge[t]:1)*32767+32768),o=Math.round(this.offsetY[t]*(this.edgeSafe?this.edge[t]:1)*32767+32768);this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e,this.pixels[4*t+2]=o>>>8,this.pixels[4*t+3]=255&o}this.peak=a,this.active||this.clear()}sample(t,e,i){const s=Math.max(0,Math.min(this.width-1.001,t*(this.width-1))),a=Math.max(0,Math.min(this.height-1.001,e*(this.height-1))),o=Math.floor(s),r=Math.floor(a),n=s-o,h=a-r,l=r*this.width+o,c=l+this.width,d=t=>(t[l]*(1-n)+t[l+1]*n)*(1-h)+(t[c]*(1-n)+t[c+1]*n)*h;i[0]=d(this.offsetX)*(this.edgeSafe?v(t,e,this.width/this.height):1)*.08,i[1]=d(this.offsetY)*(this.edgeSafe?v(t,e,this.width/this.height):1)*.08,i[2]="dissolve"===this.mode?6*-d(this.ink):0}},b=class{constructor(t,e){this.rings=[],this.previous=null,this.elapsed=1,this.echoPeak=0,this.width=t,this.height=e,this.pixels=new Uint8Array(t*e*4),this.echo=new Float32Array(t*e)}get active(){return this.rings.length>0||this.echoPeak>2e-4}clear(){this.rings=[],this.previous=null,this.elapsed=1,this.pixels.fill(0),this.echo.fill(0),this.echoPeak=0}leave(){this.previous=null}move(t,e,i){const s=Math.max(1,this.width/this.height),a=Math.max(1,this.height/this.width);this.previous&&(Math.hypot((t-this.previous.x)*s,(e-this.previous.y)*a)<.065||this.elapsed<.3)||4!==this.rings.length&&(this.previous={x:t,y:e},this.elapsed=0,this.rings.push({x:t,y:e,age:0,radius:i}))}ringSample(t,e){const i=Math.max(1,this.width/this.height),s=Math.max(1,this.height/this.width);let a=0;for(const o of this.rings){const r=.015+o.age*(.15+.22*o.radius),n=.009+.014*o.radius,h=(Math.hypot((t-o.x)*i,(e-o.y)*s)-r)/n,l=Math.sin(Math.min(1,o.age/.07)*Math.PI/2)*Math.max(0,1-o.age/1.35)**2;a=Math.max(a,Math.exp(-h*h)*l)}return a}sample(t,e){const i=Math.max(0,Math.min(this.width-1,Math.round(t*(this.width-1)))),s=Math.max(0,Math.min(this.height-1,Math.round(e*(this.height-1))));return Math.max(this.ringSample(t,e),this.echo[s*this.width+i])}step(t){if(!Number.isFinite(t))return;const e=Math.max(0,Math.min(.05,t));this.elapsed+=e;for(const t of this.rings)t.age+=e;if(this.rings=this.rings.filter(t=>t.age<1.35),!this.active)return void this.pixels.fill(0);const i=Math.exp(-5.5*e);let s=0;for(let t=0;t<this.height;t++)for(let e=0;e<this.width;e++){const a=t*this.width+e;this.echo[a]=Math.max(this.ringSample(e/(this.width-1),t/(this.height-1)),this.echo[a]*i),s=Math.max(s,this.echo[a]);const o=Math.round(65535*this.echo[a]),r=4*a;this.pixels[r]=o>>>8,this.pixels[r+1]=255&o}this.echoPeak=s,this.active||(this.echo.fill(0),this.pixels.fill(0))}},y=class{constructor(t,e){this.previous=null,this.peak=0,this.width=t,this.height=e;const i=t*e;this.pixels=new Uint8Array(4*i),this.signal=new Float32Array(i),this.offsetX=new Float32Array(i),this.offsetY=new Float32Array(i),this.driftX=new Float32Array(i),this.driftY=new Float32Array(i),this.u=new Float32Array(i),this.v=new Float32Array(i),this.ink=new Float32Array(i),this.a=new Float32Array(i),this.b=new Float32Array(i),this.c=new Float32Array(i),this.pressure=new Float32Array(i),this.pressureNext=new Float32Array(i),this.divergence=new Float32Array(i),this.curl=new Float32Array(i)}get active(){return this.peak>2e-4}clear(){for(const t of[this.u,this.v,this.ink,this.a,this.b,this.c,this.pressure,this.pressureNext,this.divergence,this.curl,this.signal,this.pixels,this.offsetX,this.offsetY,this.driftX,this.driftY])t.fill(0);this.previous=null,this.peak=0}leave(){this.previous=null}move(t,e,i,s=performance.now()){if(!Number.isFinite(t+e+i+s))return;t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e)),i=Math.max(.1,Math.min(1,i));const a=this.previous;if(this.previous={x:t,y:e,time:s},!a)return;const o=(t-a.x)*(this.width-1),r=(e-a.y)*(this.height-1),n=Math.hypot(o,r);if(n<.001)return;const h=Math.min(this.width,this.height),l=s>a.time?Math.max(1/240,(s-a.time)/1e3):1/60,c=Math.min(12,n/h/l),d=1-Math.exp(-c/2.2),f=h*(.022+.075*i)*(.65+.95*d),m=Math.min(128,Math.max(1,Math.ceil(n/(.4*f)))),u=n/f*(.32+.22*d)/m,p=o/n,g=r/n,M=-g,x=p,v=n*(2+18*d)/m;for(let i=0;i<m;i++){const s=(i+.5)/m,o=(a.x+(t-a.x)*s)*(this.width-1),r=(a.y+(e-a.y)*s)*(this.height-1),n=Math.max(1,Math.floor(o-3*f)),h=Math.min(this.width-2,Math.ceil(o+3*f)),l=Math.max(1,Math.floor(r-3*f)),c=Math.min(this.height-2,Math.ceil(r+3*f));for(let t=l;t<=c;t++)for(let e=n;e<=h;e++){const i=((e-o)*p+(t-r)*g)/f,s=((e-o)*M+(t-r)*x)/f,a=Math.exp(-i*i*.65-s*s*1.7),n=t*this.width+e;this.ink[n]=1-(1-this.ink[n])*Math.exp(-a*u);const h=1-s*s*.55,l=i*s*.7;this.u[n]=Math.max(-80,Math.min(80,this.u[n]+(p*h+M*l)*a*v)),this.v[n]=Math.max(-80,Math.min(80,this.v[n]+(g*h+x*l)*a*v))}}this.peak=1}read(t,e,i){const s=0|(e=Math.max(.5,Math.min(this.width-1.5,e))),a=0|(i=Math.max(.5,Math.min(this.height-1.5,i))),o=e-s,r=i-a,n=a*this.width+s;return(t[n]*(1-o)+t[n+1]*o)*(1-r)+(t[n+this.width]*(1-o)+t[n+this.width+1]*o)*r}sample(t,e){return this.read(this.signal,t*(this.width-1),e*(this.height-1))}displacement(t,e,i){i[0]=this.read(this.offsetX,t*(this.width-1),e*(this.height-1)),i[1]=this.read(this.offsetY,t*(this.width-1),e*(this.height-1))}step(t){if(!this.active||!Number.isFinite(t))return;let e=Math.max(0,Math.min(.05,t));const i=this.width,s=this.height;for(;e>1e-7;){const t=Math.min(1/60,e);e-=t;const a=Math.exp(-1.9*t),o=Math.exp(-3.2*t);for(let e=1;e<s-1;e++)for(let r=1;r<i-1;r++){const n=e*i+r,h=Math.max(.5,Math.min(i-1.5,r-this.u[n]*t)),l=Math.max(.5,Math.min(s-1.5,e-this.v[n]*t)),c=0|h,d=0|l,f=h-c,m=l-d,u=d*i+c,p=(1-f)*(1-m),g=f*(1-m),M=(1-f)*m,x=f*m;this.a[n]=(this.u[u]*p+this.u[u+1]*g+this.u[u+i]*M+this.u[u+i+1]*x)*a,this.b[n]=(this.v[u]*p+this.v[u+1]*g+this.v[u+i]*M+this.v[u+i+1]*x)*a,this.c[n]=(this.ink[u]*p+this.ink[u+1]*g+this.ink[u+i]*M+this.ink[u+i+1]*x)*o}[this.u,this.a]=[this.a,this.u],[this.v,this.b]=[this.b,this.v],[this.ink,this.c]=[this.c,this.ink];for(let t=1;t<s-1;t++)for(let e=1;e<i-1;e++){const s=t*i+e;this.curl[s]=.5*(this.v[s+1]-this.v[s-1]-this.u[s+i]+this.u[s-i])}for(let e=1;e<s-1;e++)for(let s=1;s<i-1;s++){const a=e*i+s,o=Math.abs(this.curl[a+1])-Math.abs(this.curl[a-1]),r=Math.abs(this.curl[a+i])-Math.abs(this.curl[a-i]),n=Math.hypot(o,r)+1e-4,h=this.curl[a]*t*10,l=Math.hypot(this.u[a],this.v[a]);this.u[a]+=r/n*h,this.v[a]-=o/n*h;const c=Math.min(1,l/(Math.hypot(this.u[a],this.v[a])+1e-6));this.u[a]*=c,this.v[a]*=c,this.divergence[a]=-.5*(this.u[a+1]-this.u[a-1]+this.v[a+i]-this.v[a-i])}this.pressure.fill(0);for(let t=0;t<4;t++){for(let t=1;t<s-1;t++)for(let e=1;e<i-1;e++){const s=t*i+e;this.pressureNext[s]=.25*(this.divergence[s]+this.pressure[s-1]+this.pressure[s+1]+this.pressure[s-i]+this.pressure[s+i])}[this.pressure,this.pressureNext]=[this.pressureNext,this.pressure]}let r=0;for(let e=1;e<s-1;e++)for(let s=1;s<i-1;s++){const a=e*i+s;this.u[a]=Math.max(-80,Math.min(80,this.u[a]-.5*(this.pressure[a+1]-this.pressure[a-1]))),this.v[a]=Math.max(-80,Math.min(80,this.v[a]-.5*(this.pressure[a+i]-this.pressure[a-i]))),this.driftX[a]+=(3.6*this.u[a]-58*this.offsetX[a]-12*this.driftX[a])*t,this.driftY[a]+=(3.6*this.v[a]-58*this.offsetY[a]-12*this.driftY[a])*t,this.offsetX[a]=Math.max(-2,Math.min(2,this.offsetX[a]+this.driftX[a]*t)),this.offsetY[a]=Math.max(-2,Math.min(2,this.offsetY[a]+this.driftY[a]*t)),this.signal[a]=1-Math.exp(.06*-Math.hypot(this.u[a],this.v[a])-.16*this.ink[a]),r=Math.max(r,this.signal[a])}this.peak=r}if(this.active)for(let t=0;t<this.ink.length;t++){const e=Math.round(65535*Math.min(1,this.signal[t]));this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e,this.pixels[4*t+2]=Math.round(128+63.5*this.offsetX[t]),this.pixels[4*t+3]=Math.round(128+63.5*this.offsetY[t])}else this.clear()}};function S(t,e){const i=Math.max(0,Math.min(1,e/.38));return t+(1-2*t)*(i*i*(3-2*i))}var E=class{constructor(t=1){this.mode="water",this.amount=.55,this.radius=.2,this.lensX=.5,this.lensY=.5,this.lensStrength=0,this.previous=null,this.energy=0,this.pending=!1,this.remainder=0,t=Math.max(.25,Math.min(4,t)),this.columns=Math.round(t>=1?128:128*t),this.rows=Math.round(t>=1?128/t:128),this.xScale=Math.max(1,t),this.yScale=Math.max(1,1/t),this.heights=new Float32Array(this.columns*this.rows),this.velocity=new Float32Array(this.heights.length),this.next=new Float32Array(this.heights.length),this.normals=new Float32Array(2*this.heights.length),this.edgeMask=new Float32Array(this.heights.length);for(let e=0;e<this.rows;e++)for(let i=0;i<this.columns;i++)this.edgeMask[e*this.columns+i]=v(i/(this.columns-1),e/(this.rows-1),t);this.refraction={width:this.columns,height:this.rows,pixels:new Uint8Array(4*this.heights.length),strength:30,mode:"water",focus:[.5,.5,0,.2]},this.waterPixels=this.refraction.pixels,this.trail=new y(this.columns,this.rows),this.contour=new b(this.columns,this.rows),this.afterimage=new w(this.columns,this.rows),this.clear()}get invertsDensity(){return"trail"===this.mode}get densityTrail(){return["trail","contour","dissolve"].includes(this.mode)}get hasRefraction(){return this.active||this.lensStrength>15e-5}get active(){return["dissolve","silk","vortex"].includes(this.mode)?this.afterimage.active:"contour"===this.mode?this.contour.active:"trail"===this.mode?this.trail.active:this.pending||this.energy>15e-5}setMode(t){t!==this.mode&&(this.clear(),this.mode=t,this.refraction.mode=t,"dissolve"!==t&&"silk"!==t&&"vortex"!==t||this.afterimage.setMode(t),this.refraction.pixels="trail"===t?this.trail.pixels:"contour"===t?this.contour.pixels:["dissolve","silk","vortex"].includes(t)?this.afterimage.pixels:this.waterPixels,this.refraction.strength="water"===t?30*this.amount/.55:"silk"===t?28*this.amount:"vortex"===t?38*this.amount:0)}configure(t,e=.55,i=.2,s=!1){this.setMode(t),this.refraction.edgeSafe=s,this.afterimage.edgeSafe=s,this.amount=Number.isFinite(e)?Math.max(0,Math.min(1,e)):.55,this.radius=Number.isFinite(i)?Math.max(.1,Math.min(1,i)):.2,this.refraction.strength="water"===t?30*this.amount/.55:"silk"===t?28*this.amount:"vortex"===t?38*this.amount:0,this.refraction.focus[2]=this.densityTrail?this.amount:this.lensStrength*this.amount,this.refraction.focus[3]=this.radius}move(t,e,i){if("none"===this.mode||0===this.amount)return;if(!Number.isFinite(t+e))return;if(t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e)),["dissolve","silk","vortex"].includes(this.mode))return void this.afterimage.move(t,e,this.radius);if("contour"===this.mode)return void this.contour.move(t,e,this.radius);if("trail"===this.mode)return void this.trail.move(t,e,this.radius,i);if("water"!==this.mode)return!this.previous&&this.lensStrength<.001&&(this.lensX=t,this.lensY=e),this.previous={x:t,y:e},void(this.pending=!0);if(!this.previous)return void(this.previous={x:t,y:e});const s=this.previous;this.previous={x:t,y:e};const a=(t-s.x)*this.xScale,o=(e-s.y)*this.yScale,r=Math.hypot(a,o);if(r<1e-5)return;const n=.035+.1*this.radius,h=3*n,l=Math.min(192,Math.max(1,Math.ceil(r/(.5*n)))),c=95*Math.min(r,1)/l;for(let i=0;i<l;i++){const a=(i+.5)/l,o=s.x+(t-s.x)*a,r=s.y+(e-s.y)*a,d=Math.max(1,Math.floor((o-h/this.xScale)*(this.columns-1))),f=Math.min(this.columns-2,Math.ceil((o+h/this.xScale)*(this.columns-1))),m=Math.max(1,Math.floor((r-h/this.yScale)*(this.rows-1))),u=Math.min(this.rows-2,Math.ceil((r+h/this.yScale)*(this.rows-1)));for(let t=m;t<=u;t++)for(let e=d;e<=f;e++){const i=(e/(this.columns-1)-o)*this.xScale,s=(t/(this.rows-1)-r)*this.yScale,a=Math.exp(-(i*i+s*s)/(n*n))*c,h=t*this.columns+e;this.velocity[h]=Math.max(-12,this.velocity[h]-a)}}this.pending=!0}leave(){this.afterimage.leave(),this.contour.leave(),this.trail.leave(),this.previous=null,"water"!==this.mode&&this.lensStrength&&(this.pending=!0)}clear(){this.trail.clear(),this.contour.clear(),this.afterimage.clear(),this.heights.fill(0),this.velocity.fill(0),this.next.fill(0),this.normals.fill(0),this.refraction.focus[2]=0,this.previous=null,this.lensStrength=0,this.energy=0,this.pending=!1,this.remainder=0;for(let t=0;t<this.waterPixels.length;t+=4)this.waterPixels[t]=this.waterPixels[t+2]=128,this.waterPixels[t+1]=this.waterPixels[t+3]=0}step(t){if(!this.active||!Number.isFinite(t))return;if(["dissolve","silk","vortex"].includes(this.mode))return void this.afterimage.step(t);if("contour"===this.mode)return void this.contour.step(t);if("trail"===this.mode)return void this.trail.step(t);if("water"!==this.mode)return void this.stepLight(Math.max(0,Math.min(.05,t)));this.remainder+=Math.max(0,Math.min(.05,t));const e=1/120,i=Math.exp(-3.8*e),s=.3*Math.min(this.columns,this.rows);for(;this.remainder+1e-8>=e;){this.remainder-=e;let t=0;for(let a=1;a<this.rows-1;a++)for(let o=1;o<this.columns-1;o++){const r=a*this.columns+o,n=this.heights[r],h=this.heights[r-1]+this.heights[r+1]+this.heights[r-this.columns]+this.heights[r+this.columns]-4*n,l=Math.min(o,a,this.columns-1-o,this.rows-1-a),c=l<5?.88+.024*l:1,d=(this.velocity[r]+(h*s*s-8*n)*e)*i*c;this.velocity[r]=d,this.next[r]=(n+d*e)*c,t=Math.max(t,Math.abs(this.next[r]),.1*Math.abs(d))}this.heights.set(this.next),this.energy=t,this.pending=!1}if(!this.active)return void this.clear();const a=.18*Math.min(this.columns,this.rows);for(let t=0;t<this.rows;t++)for(let e=0;e<this.columns;e++){const i=t*this.columns+e,s=(this.heights[t*this.columns+Math.max(0,e-1)]-this.heights[t*this.columns+Math.min(this.columns-1,e+1)])*a,o=(this.heights[Math.max(0,t-1)*this.columns+e]-this.heights[Math.min(this.rows-1,t+1)*this.columns+e])*a,r=Math.tanh(s)*(this.refraction.edgeSafe?this.edgeMask[i]:1),n=Math.tanh(o)*(this.refraction.edgeSafe?this.edgeMask[i]:1);this.normals[2*i]=r,this.normals[2*i+1]=n;const h=Math.round(32767*r+32768),l=Math.round(32767*n+32768);this.refraction.pixels[4*i]=h>>>8,this.refraction.pixels[4*i+1]=255&h,this.refraction.pixels[4*i+2]=l>>>8,this.refraction.pixels[4*i+3]=255&l}}stepLight(t){const e=this.previous,i=1-Math.exp(-30*t),s=1-Math.exp(-12*t);e&&(this.lensX+=(e.x-this.lensX)*i,this.lensY+=(e.y-this.lensY)*i),this.lensStrength+=((e?1:0)-this.lensStrength)*s,this.energy=Math.max(e?Math.abs(e.x-this.lensX)+Math.abs(e.y-this.lensY):0,Math.abs((e?1:0)-this.lensStrength)),this.pending=!1,e||this.active?this.refraction.focus=[this.lensX,this.lensY,this.lensStrength*this.amount,this.radius]:this.clear()}sample(t,e,i){if(["dissolve","silk","vortex"].includes(this.mode))return this.afterimage.sample(t,e,i),i[0]*=this.amount,i[1]*=this.amount,void(i[2]*=this.amount);if("contour"===this.mode)return i[0]=i[1]=0,void(i[2]=this.contour.sample(t,e)*this.amount*3);if("trail"===this.mode)return i[0]=i[1]=0,void(i[2]=this.trail.sample(t,e)*this.amount*3);const s=Math.max(0,Math.min(this.columns-1.001,t*(this.columns-1))),a=Math.max(0,Math.min(this.rows-1.001,e*(this.rows-1))),o=Math.floor(s),r=Math.floor(a),n=s-o,h=a-r,l=2*(r*this.columns+o),c=l+2*this.columns;for(let t=0;t<2;t++)i[t]=.08*((this.normals[l+t]*(1-n)+this.normals[l+2+t]*n)*(1-h)+(this.normals[c+t]*(1-n)+this.normals[c+2+t]*n)*h);i[0]*=this.amount/.55,i[1]*=this.amount/.55,i[2]="light"===this.mode||"scan"===this.mode?function(t,e,i,s){const[a,o,r,n]=i.focus,h=(t-a)*Math.max(1,s)/n,l=(e-o)*Math.max(1,1/s)/n;return"light"===i.mode?Math.exp(-3*(h*h+l*l))*r:"scan"===i.mode?(1.3*Math.exp(-h*h*110)-.3*Math.exp(-h*h*12))*Math.exp(-l*l*1.8)*r:0}(t,e,this.refraction,this.xScale/this.yScale):0}};function k(t){return"videoWidth"in t?[t.videoWidth,t.videoHeight]:"naturalWidth"in t?[t.naturalWidth,t.naturalHeight]:[t.width,t.height]}var T=(t=!1)=>{const e=document.createElement("canvas"),i=e.getContext("2d",{willReadFrequently:t});if(!i)throw new Error("Canvas 2D is unavailable.");return{canvas:e,ctx:i}},A=(t,e,i)=>{t.width===e&&t.height===i||(t.width=e,t.height=i)},F={blocks:" ░▒▓█",braille:" ⠁⠃⠇⡇⣇⣧⣷⣿",lines:" -═╪╬",cross:" ·+xX#",diagonal:" /╱╳",diamond:" ·◇◈◆",mixed:" .:+/◇#@"};function I(t,e={},i={}){const a=t.getContext("2d");if(!a)throw new Error("Canvas is already owned by another renderer.");const o=T(),r=T(!0),n=T(),h=T(),d=T(),f=T(),m=T(),u=T(),v=T();let w,b=l(e),y=0,I="",R=new Uint8ClampedArray(0),P=0,L=0,C=0,D=null,U="",O=new E,X=0;const N=[0,0,0],B=Math.max(64,Math.min(4096,Number.isFinite(i.maxDimension)?i.maxDimension:960)),_=Math.max(256,Math.min(16e4,Number.isFinite(i.maxCells)?i.maxCells:12e3));let Y=_;const z=Math.max(.1,Math.min(8,i.pixelRatio??1));return{canvas:t,render:function(e,i=0,l=960,T=540){if(Number.isFinite(i)||(i=0),!Number.isFinite(l)||!Number.isFinite(T)||l<1||T<1)throw new Error("Render dimensions must be positive finite numbers.");const[_,G]=k(e);if(!_||!G)return;const W=Math.min(1,B/Math.max(l,T)),q=Math.max(2,Math.round(l*W)),j=Math.max(2,Math.round(T*W));A(t,q,j),A(o.canvas,q,j),A(n.canvas,q,j),A(h.canvas,q,j),A(d.canvas,q,j),X!==q/j&&(X=q/j,O=new E(X)),O.configure(b.hover.effect,b.hover.strength,b.hover.radius,b.hover.edgeSafe),O.step(Math.max(0,Math.min(.05,i-C))),C=i;const $="currentTime"in e?e.getVideoPlaybackQuality?.().totalVideoFrames??e.currentTime:0,V=[y,q,j,$].join(":"),H="dither"===b.style,J=(H?b.dither.scale:b.cellSize)*z,K=Math.max(J,Math.sqrt(q*j/Y)),Q=H||["pixel","mosaic","lego","voxel","disco","dots"].includes(b.style)?K:1.65*K,Z=Math.max(1,Math.ceil(q/K)),tt=Math.max(1,Math.ceil(j/Q));if(I!==V||D!==e||P!==Z||L!==tt){D=e,I=V,P=Z,L=tt,o.ctx.clearRect(0,0,q,j),o.ctx.save();const t=c(_,G,q,j,b.crop);o.ctx.translate(t.x+t.width/2,t.y+t.height/2),o.ctx.rotate(b.crop.rotation*Math.PI/180),o.ctx.drawImage(e,-_*t.scale/2,-G*t.scale/2,_*t.scale,G*t.scale),o.ctx.restore(),A(r.canvas,P,L),r.ctx.clearRect(0,0,P,L),r.ctx.drawImage(o.canvas,0,0,P,L),R=r.ctx.getImageData(0,0,P,L).data;const i=b.color;for(let t=0;t<R.length;t+=4){const e=.299*R[t]+.587*R[t+1]+.114*R[t+2];for(let s=0;s<3;s++){const a=e+(R[t+s]-e)*i.saturation;R[t+s]=((a*(1-i.grayscale)+e*i.grayscale)/255-.5)*i.contrast*255+127.5+255*i.brightness}}}n.ctx.clearRect(0,0,q,j),n.ctx.globalAlpha=1,n.ctx.globalCompositeOperation="source-over";const et=i*b.motion.speed;if(H){const t=new Uint8ClampedArray(R),e=b.motion.type;if(O.active||"none"!==e)for(let i=0;i<L;i++)for(let s=0;s<P;s++){const a=s/P,o=i/L;let r=s,n=i,h=0,l=1,c=1;if(O.active&&(O.sample(a,o,N),r-=N[0]*P,n-=N[1]*L,h=N[2]/3),"wave"===e&&(n+=Math.sin(8*a+2*et+4*o)*L*.015),"ripple"===e){const t=a-.5,e=o-.5,i=.03*Math.sin(30*Math.hypot(t,e)-3*et);r+=t*i*P,n+=e*i*L}"breathe"===e&&(l=.92+.08*Math.sin(1.5*et+3*a)),"reveal"===e&&(c=Math.max(0,Math.min(1,4*(.7*Math.sin(.7*et)+.7-a)))),"glitch"===e&&p(i,Math.floor(6*et))>.93&&(r+=8*Math.sin(5*et)),"vapor"===e&&(n+=Math.sin(6*a+et)*L*.025),"fire"===e&&(n+=Math.sin(7*a+3*et+8*o)*L*.01,l=.8+.2*Math.sin(12*o-4*et)),"hologram"===e&&(c=.72+.28*Math.sin(.65*i+5*et)),"chrome"===e&&(l=.5+Math.abs(Math.sin(8*o+et)));const d=4*(i*P+s),f=4*(Math.max(0,Math.min(L-1,Math.round(n)))*P+Math.max(0,Math.min(P-1,Math.round(r))));for(let i=0;i<3;i++){const s=R[f+i]/255;let o=(["trail","contour"].includes(b.hover.effect)?S(s,h):"dissolve"===b.hover.effect?s*Math.max(0,1+h):s)*l;"rainbow"===e&&(o*=.65+.35*Math.sin(2*et+5*a+2.094*i)),"hologram"===e&&(o*=0===i?.4:1),"fire"===e&&(o*=0===i?1.3:1===i?.7:.3),t[d+i]=255*o}t[d+3]=R[f+3]*c}!function(t,e,i,a,o=0){const{algorithm:r,amount:n,threshold:h}=a,l=("custom"===a.palette?a.colors:s[a.palette]??s.mono).map(x),c=M[r],d=c?new Float32Array(3*e*3):null,f="drift"===a.motion?Math.floor(o*a.speed*3):0,m="shimmer"===a.motion?.15*Math.sin(o*a.speed*2):0;for(let s=0;s<i;s++)for(let a=0;a<e;a++){const o=4*(s*e+a),u=3*(s%3*e+a);if(0===t[o+3]){d&&(d[u]=d[u+1]=d[u+2]=0);continue}let M=0;r.startsWith("bayer")?M=g(a+f&15,s+f&15,Number(r.slice(5))):"noise"===r?M=p(a,s)-.5:"lines"===r?M=(s+f)%4/3-.5:"halftone"===r&&(M=Math.hypot(a%6-2.5,s%6-2.5)/3.54-.5);const x=128*(M*n+m+(.5-h)),v=t[o]+x+(d?.[u]??0),w=t[o+1]+x+(d?.[u+1]??0),b=t[o+2]+x+(d?.[u+2]??0);let y=0,S=0,E=0;if(l.length){let t=1/0;for(const e of l){const i=(v-e[0])**2*.299+(w-e[1])**2*.587+(b-e[2])**2*.114;i<t&&(t=i,[y,S,E]=e)}}else y=51*Math.round(v/51),S=51*Math.round(w/51),E=51*Math.round(b/51);if(t[o]=y,t[o+1]=S,t[o+2]=E,d&&c){d[u]=d[u+1]=d[u+2]=0;for(const[t,o,r]of c){const h=a+t;if(h<0||h>=e||s+o>=i)continue;const l=3*((s+o)%3*e+h);d[l]+=(v-y)*r*n,d[l+1]+=(w-S)*r*n,d[l+2]+=(b-E)*r*n}}}}(t,P,L,b.dither,i),r.ctx.putImageData(new ImageData(t,P,L),0,0),n.ctx.imageSmoothingEnabled=!1,n.ctx.drawImage(r.canvas,0,0,q,j)}else{const t=Array.from(F[b.style]??b.charset),e=n.ctx,i="ascii"===b.style||!!F[b.style],s=Math.max(3,Math.round(.92*Q)),a=Math.ceil(K+4),o=Math.ceil(Q+4),r=[t.join(""),s,a,o,b.ink,b.colorMode].join(":");i&&r!==U&&(U=r,A(m.canvas,a*t.length,o),m.ctx.clearRect(0,0,m.canvas.width,o),m.ctx.font=`${s}px monospace`,m.ctx.textBaseline="middle",m.ctx.textAlign="center",m.ctx.fillStyle="accent"===b.colorMode?b.ink:"#ffffff",t.forEach((t,e)=>m.ctx.fillText(t,e*a+a/2,o/2))),e.font=`${s}px monospace`,e.textBaseline="middle",e.textAlign="center";for(let s=0;s<L;s++)for(let r=0;r<P;r++){let n=r,h=s,l=0;O.active&&(O.sample(r/P,s/L,N),n=Math.max(0,Math.min(P-1,r-N[0]*P)),h=Math.max(0,Math.min(L-1,s-N[1]*L)),l=N[2]/3);const c=4*(Math.floor(h)*P+Math.floor(n));if(!R[c+3])continue;const d=R[c],f=R[c+1],u=R[c+2],g=(.299*d+.587*f+.114*u)/255;let M=g;["trail","contour"].includes(b.hover.effect)&&l?M=S(M,l):"dissolve"===b.hover.effect&&(M*=Math.max(0,1+l));const x=b.motion.type;let v=r*K,w=s*Q,y=1;if("breathe"===x&&(M*=.92+.08*Math.sin(1.5*et+.03*r)),"wave"===x&&(w+=Math.sin(.12*r+2*et+.08*s)*Q*.4),"ripple"===x){const t=r/P-.5,e=s/L-.5,i=Math.hypot(t,e),a=Math.sin(30*i-3*et)*K*.65;v+=t*a,w+=e*a}"fire"===x&&(w-=Math.sin(.16*r+3*et+.09*s)*Q*.35,M*=.85+.15*Math.sin(.3*s-4*et)),"hologram"===x&&(y=.72+.28*Math.sin(.65*s+5*et)),"reveal"===x&&(y=Math.max(0,Math.min(1,4*(.7*Math.sin(.7*et)+.7-r/P)))),"glitch"===x&&p(s,Math.floor(6*et))>.93&&(v+=Math.sin(5*et)*K*3),"vapor"===x&&(w+=Math.sin(.04*r+et)*Q),i||"accent"!==b.colorMode||(y*=M),e.globalAlpha=y;const E=255*(M-g);let k="source"===b.colorMode?`rgb(${d+E},${f+E},${u+E})`:"gray"===b.colorMode?`rgb(${Math.round(255*M)},${Math.round(255*M)},${Math.round(255*M)})`:b.ink;if("rainbow"===x&&(k=`hsl(${(r/P*180+40*et)%360} 70% 65%)`),"fire"===x&&(k=`hsl(${15+40*M} 90% ${30+45*M}%)`),"hologram"===x&&(k=`hsl(185 65% ${40+40*M}%)`),"chrome"===x&&(k=`hsl(210 12% ${25+70*Math.abs(Math.sin(.2*s+et))}%)`),e.fillStyle=k,i){const i=Math.max(0,Math.min(t.length-1,Math.floor(M*(t.length-1))));"accent"!==b.colorMode||["rainbow","fire","hologram","chrome"].includes(x)?e.fillText(t[i],v+K/2,w+Q/2):e.drawImage(m.canvas,i*a,0,a,o,v+(K-a)/2,w+(Q-o)/2,a,o)}else if("dots"===b.style)e.beginPath(),e.arc(v+K/2,w+Q/2,.48*K*Math.sqrt(M),0,2*Math.PI),e.fill();else if("voxel"===b.style){const t=v+K/2,i=w+Q/2;e.beginPath(),e.moveTo(t,w),e.lineTo(v+K,w+.25*Q),e.lineTo(t,i),e.lineTo(v,w+.25*Q),e.closePath(),e.fill(),e.globalAlpha=.72*y,e.beginPath(),e.moveTo(v,w+.25*Q),e.lineTo(t,i),e.lineTo(t,w+Q),e.lineTo(v,w+.75*Q),e.closePath(),e.fill(),e.globalAlpha=.42*y,e.beginPath(),e.moveTo(t,i),e.lineTo(v+K,w+.25*Q),e.lineTo(v+K,w+.75*Q),e.lineTo(t,w+Q),e.closePath(),e.fill()}else{const t="pixel"===b.style?0:Math.max(.5,.06*K);e.fillRect(v,w,K-t,Q-t),"lego"===b.style&&(e.fillStyle="rgba(255,255,255,.2)",e.beginPath(),e.arc(v+K/2,w+Q/2,.28*K,0,2*Math.PI),e.fill(),e.strokeStyle="rgba(0,0,0,.25)",e.stroke()),"disco"===b.style&&(e.fillStyle=`rgba(255,255,255,${.1+.25*p(r,s)})`,e.fillRect(v,w,K-t,.35*Q),e.fillStyle="rgba(0,0,0,.25)",e.fillRect(v,w+.65*Q,K-t,.35*Q-t))}}}n.ctx.globalAlpha=1,(b.color.amount||b.lights.length)&&(A(u.canvas,q,j),u.ctx.clearRect(0,0,q,j),u.ctx.drawImage(n.canvas,0,0)),b.color.amount&&(n.ctx.save(),n.ctx.globalCompositeOperation=b.color.blend,n.ctx.globalAlpha=b.color.amount,n.ctx.fillStyle=b.color.tint,n.ctx.fillRect(0,0,q,j),n.ctx.restore());for(const t of b.lights){const e=t.radius*Math.max(q,j),i=n.ctx.createRadialGradient(t.x*q,t.y*j,0,t.x*q,t.y*j,e);i.addColorStop(0,t.color),i.addColorStop(1,"transparent"),n.ctx.save(),n.ctx.globalCompositeOperation="screen",n.ctx.globalAlpha=t.intensity,n.ctx.fillStyle=i,n.ctx.fillRect(0,0,q,j),n.ctx.restore()}if((b.color.amount||b.lights.length)&&(n.ctx.globalCompositeOperation="destination-in",n.ctx.drawImage(u.canvas,0,0),n.ctx.globalCompositeOperation="source-over"),b.mask.enabled&&b.mask.shapes.length){const t=d.ctx;t.clearRect(0,0,q,j),t.fillStyle="#fff",t.strokeStyle="#fff",t.lineCap="round",t.lineJoin="round";for(const e of b.mask.shapes){if(t.beginPath(),"ellipse"===e.kind)t.ellipse((e.x+e.width/2)*q,(e.y+e.height/2)*j,e.width*q/2,e.height*j/2,0,0,2*Math.PI);else{if("rectangle"!==e.kind){if(t.lineWidth=(e.size??.05)*q,1===e.points?.length){t.arc(e.points[0][0]*q,e.points[0][1]*j,t.lineWidth/2,0,2*Math.PI),t.fill();continue}e.points?.forEach(([e,i],s)=>s?t.lineTo(e*q,i*j):t.moveTo(e*q,i*j)),t.stroke();continue}t.rect(e.x*q,e.y*j,e.width*q,e.height*j)}t.fill()}n.ctx.globalCompositeOperation=b.mask.invert?"destination-out":"destination-in",n.ctx.drawImage(d.canvas,0,0),n.ctx.globalCompositeOperation="source-over"}const it=h.ctx;it.clearRect(0,0,q,j),it.globalAlpha=b.backdrop.opacity;const st=b.backdrop;if("solid"===st.mode&&(it.fillStyle=st.color,it.fillRect(0,0,q,j)),"gradient"===st.mode){const t=it.createLinearGradient(0,0,q,j);t.addColorStop(0,st.color),t.addColorStop(1,st.color2),it.fillStyle=t,it.fillRect(0,0,q,j)}if("source"===st.mode&&it.drawImage(o.canvas,0,0),"blurred"===st.mode){const t=Math.max(1,st.blur);A(f.canvas,Math.max(2,Math.round(q/t)),Math.max(2,Math.round(j/t))),f.ctx.drawImage(o.canvas,0,0,f.canvas.width,f.canvas.height),it.imageSmoothingEnabled=!0,it.drawImage(f.canvas,0,0,q,j)}it.globalAlpha=1,b.effects.characterBloom>0&&(A(v.canvas,Math.max(2,Math.round(q/3)),Math.max(2,Math.round(j/3))),v.ctx.clearRect(0,0,v.canvas.width,v.canvas.height),v.ctx.drawImage(n.canvas,0,0,v.canvas.width,v.canvas.height),it.save(),it.globalAlpha=.8*b.effects.characterBloom,it.globalCompositeOperation="screen",it.filter=`blur(${1+4*b.effects.characterBloom}px)`,it.drawImage(v.canvas,0,0,q,j),it.restore()),it.drawImage(n.canvas,0,0);const at=Object.entries(b.effects).some(([t,e])=>!["angle","focus","blurType","characterBloom"].includes(t)&&"number"==typeof e&&e>0);a.clearRect(0,0,q,j),at?(void 0===w&&(w=function(){const t=document.createElement("canvas"),e=t.getContext("webgl",{alpha:!0,premultipliedAlpha:!1,antialias:!1,preserveDrawingBuffer:!0});if(!e)return null;const i=[],s=(t,s)=>{const a=e.createShader(t);if(i.push(a),e.shaderSource(a,s),e.compileShader(a),!e.getShaderParameter(a,e.COMPILE_STATUS))throw new Error(e.getShaderInfoLog(a)||"Finish shader failed");return a},a=e.createProgram();if(e.attachShader(a,s(e.VERTEX_SHADER,"attribute vec2 p;varying vec2 uv;void main(){uv=(p+1.)*.5;gl_Position=vec4(p,0.,1.);}")),e.attachShader(a,s(e.FRAGMENT_SHADER,"precision mediump float;varying vec2 uv;uniform sampler2D src;uniform vec2 size;uniform float t,bloom,grain,dust,scanlines,crt,prism,vignette,glitch,pixelate,blur,blurMode,angle,focus,halftone;\n float hash(vec2 p){return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453);}\n vec4 sampleAt(vec2 p){if(min(min(p.x,p.y),min(1.-p.x,1.-p.y))<0.)return vec4(0.);return texture2D(src,vec2(p.x,1.-p.y));}\n void main(){vec2 q=uv,c=q-.5;q=c*(1.+dot(c,c)*crt*.25)+.5;\n if(glitch>0.)q.x+=(hash(vec2(floor(q.y*35.),floor(t*5.)))-.5)*.07*glitch*step(.82,hash(vec2(floor(q.y*35.),floor(t*5.)+3.)));\n if(pixelate>0.){vec2 grid=size/(1.+pixelate*20.);q=(floor(q*grid)+.5)/grid;}\n vec4 base=sampleAt(q);float edge=smoothstep(.12,.65,length(c));\n vec2 shift=vec2(prism*3.*edge/size.x,prism*edge/size.y);\n if(prism>0.)base.rgb=vec3(sampleAt(q+shift).r,base.g,sampleAt(q-shift).b);\n vec2 dir=vec2(cos(angle),sin(angle))/size;float amount=blur;\n if(blurMode>1.5&&blurMode<2.5){dir=normalize(c+vec2(.0001))/size;amount*=length(c)*2.;}\n if(blurMode>2.5)amount*=smoothstep(.05,.5,abs(q.y-focus));\n vec4 blurred=base;\n if(amount>0.){blurred=base*.2;for(int i=1;i<=4;i++){float f=float(i)*amount*.35;vec2 off=dir*f;if(blurMode<.5)off=vec2(cos(float(i)*1.57),sin(float(i)*1.57))*amount/size;blurred+=sampleAt(q+off)*.1+sampleAt(q-off)*.1;}}\n vec3 light=vec3(0.);if(bloom>0.)for(int i=0;i<4;i++){float a=float(i)*1.5708;vec3 s=sampleAt(q+vec2(cos(a),sin(a))*6./size).rgb;light+=max(vec3(0.),s-.35)*.25;}\n vec3 col=blurred.rgb+light*bloom;col*=1.-scanlines*.4*(.5+.5*cos(q.y*size.y*3.14159));\n col*=1.-vignette*smoothstep(.15,.72,length(c));\n col+=(hash(floor(q*size)+floor(t*12.))-.5)*grain*.2;\n if(dust>0.)col+=step(1.-dust*.002,hash(floor(q*size*.25)+floor(t*2.)))*.4;\n if(halftone>0.)col*=mix(1.,smoothstep(.1,.65,length(fract(q*size/6.)-.5)),halftone);\n gl_FragColor=vec4(clamp(col,0.,1.),blurred.a);}")),e.linkProgram(a),!e.getProgramParameter(a,e.LINK_STATUS))throw new Error("Finish link failed");e.useProgram(a);const o=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,o),e.bufferData(e.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,1]),e.STATIC_DRAW);const r=e.getAttribLocation(a,"p");e.enableVertexAttribArray(r),e.vertexAttribPointer(r,2,e.FLOAT,!1,0,0);const n=e.createTexture();e.bindTexture(e.TEXTURE_2D,n),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE);const h=["t","bloom","grain","dust","scanlines","crt","prism","vignette","glitch","pixelate","blur","blurMode","angle","focus","halftone"],l=Object.fromEntries(h.map(t=>[t,e.getUniformLocation(a,t)])),c=e.getUniformLocation(a,"size");return{canvas:t,render(i,s,o,r=1){t.width===i.width&&t.height===i.height||(t.width=i.width,t.height=i.height,e.viewport(0,0,t.width,t.height)),e.useProgram(a),e.bindTexture(e.TEXTURE_2D,n),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,i),e.uniform2f(c,t.width/r,t.height/r);for(const t of h)e.uniform1f(l[t],"t"===t?o:"blurMode"===t?["gaussian","directional","radial","progressive"].indexOf(s.blurType):"angle"===t?s.angle*Math.PI/180:s[t]??0);return e.drawArrays(e.TRIANGLE_STRIP,0,4),t},destroy(){e.deleteTexture(n),e.deleteBuffer(o),e.deleteProgram(a),i.forEach(t=>e.deleteShader(t)),t.width=t.height=1,e.getExtension("WEBGL_lose_context")?.loseContext()}}}()),w?a.drawImage(w.render(h.canvas,b.effects,i,z),0,0):a.drawImage(h.canvas,0,0),t.dataset.studioFinish=w?"gpu":"unavailable"):(a.drawImage(h.canvas,0,0),t.dataset.studioFinish="none")},setBudget(t){Y=Math.max(1500,Math.min(_,Math.round(t)))},get maxCells(){return Y},configure(t){b=l(t),y++},pointer:(t,e,i)=>{O.configure(b.hover.effect,b.hover.strength,b.hover.radius,b.hover.edgeSafe),O.move(t,e,i)},leave(){O.leave()},get active(){return O.active},get settings(){return l(b)},get capabilities(){return{gpuFinish:null!==w}},invalidate(){I=""},destroy(){w?.destroy();for(const t of[o,r,n,h,d,f,m,u,v])t.canvas.width=t.canvas.height=1;D=null,R=new Uint8ClampedArray(0)}}}function R(t,e,i){return new Promise((s,a)=>{const o=()=>{l(),s()},r=()=>{l(),a(new Error("Unable to load this media. Check its format and cross-origin permissions."))},n=()=>{l(),a(new DOMException("Cancelled","AbortError"))},h=setTimeout(r,2e4),l=()=>{clearTimeout(h),t.removeEventListener(e,o),t.removeEventListener("error",r),i?.removeEventListener("abort",n)};t.addEventListener(e,o,{once:!0}),t.addEventListener("error",r,{once:!0}),i?.addEventListener("abort",n,{once:!0}),i?.aborted&&n()})}async function P(t,e){if("string"==typeof t&&t.startsWith("blob:")){const i=await fetch(t,{signal:e}),s=await i.blob();return P(new File([s],"Imported media",{type:s.type}),e)}const i="string"!=typeof t,s=i?t.name:t;if(i?"image/gif"===t.type:/\.gif(?:[?#]|$)/i.test(s)){const s=await import("gifuct-js"),{parseGIF:a,decompressFrames:o}="function"==typeof s.parseGIF?s:s.default,r=i?await t.arrayBuffer():await fetch(t,{signal:e}).then(t=>{if(!t.ok)throw new Error("GIF download failed.");return t.arrayBuffer()});if(e?.aborted)throw new DOMException("Cancelled","AbortError");const n=a(r),h=n.lsd.width,l=n.lsd.height;if(h*l>4e6)throw new Error("GIF is too large. Use a smaller GIF or an MP4.");const c=n.frames.filter(t=>"image"in t).length;if(!c||c*h*l*4>128e6)throw new Error("GIF exceeds the decoded memory budget. Use MP4 for long animations.");const d=o(n,!0);if(d.length*h*l*4>128e6)throw new Error("GIF exceeds the 128 MB decoded budget. Use MP4 for long animations.");const f=document.createElement("canvas");f.width=h,f.height=l;const m=f.getContext("2d"),u=document.createElement("canvas"),p=u.getContext("2d"),g=d.reduce((t,e)=>t+Math.max(20,e.delay),0)/1e3;let M=-1,x=null;const v=t=>{const e=(t%g+g)%g*1e3;let i=0,s=0;for(;s<d.length-1&&(i+=Math.max(20,d[s].delay),!(e<i));s++);s<M&&(m.clearRect(0,0,h,l),M=-1,x=null);for(let t=M+1;t<=s;t++){const e=d[t-1];2===e?.disposalType&&m.clearRect(e.dims.left,e.dims.top,e.dims.width,e.dims.height),3===e?.disposalType&&x&&m.putImageData(x,0,0);const i=d[t];x=3===i.disposalType?m.getImageData(0,0,h,l):null,u.width=i.dims.width,u.height=i.dims.height,p.putImageData(new ImageData(new Uint8ClampedArray(i.patch),u.width,u.height),0,0),m.drawImage(u,i.dims.left,i.dims.top)}return M=s,f};return v(0),{source:f,width:h,height:l,duration:g,animated:!0,seek:async()=>{},frame:v,destroy(){f.width=u.width=1,d.length=0,x=null}}}const a=i?t.type.startsWith("video/"):/\.(mp4|webm|mov)(?:[?#]|$)/i.test(s),o=i?URL.createObjectURL(t):t,r=a?document.createElement("video"):new Image;r.crossOrigin="anonymous",r instanceof HTMLVideoElement&&(r.muted=!0,r.playsInline=!0,r.preload="auto");const n=()=>{r instanceof HTMLVideoElement?(r.pause(),r.removeAttribute("src"),r.load()):r.src="",i&&URL.revokeObjectURL(o)};try{const t=R(r,a?"loadeddata":"load",e);r.src=o,await t;const i=r instanceof HTMLVideoElement?r.videoWidth:r.naturalWidth,s=r instanceof HTMLVideoElement?r.videoHeight:r.naturalHeight;return{source:r,width:i,height:s,duration:r instanceof HTMLVideoElement?r.duration:0,animated:a,async seek(t,e){if(!(r instanceof HTMLVideoElement))return;if(!Number.isFinite(r.duration)||r.duration<=0)throw new Error("Video duration is unavailable.");const i=Math.max(0,Math.min(r.duration-.001,t%r.duration));if(Math.abs(r.currentTime-i)<.001&&r.readyState>=2)return;const s=R(r,"seeked",e);r.currentTime=i,await s},frame:()=>r,destroy:n}}catch(t){throw n(),t}}var L=t=>{if(t?.aborted)throw new DOMException("Export cancelled","AbortError")};function C(t,e,i={}){let s=l(i.settings),a=i.width??e.width,o=i.height??e.height;const r=I(t,s,i);let n=0,h=!1,c=!0,m=!1,u=!0,p=0,g=0,M=0,x=-1,v=0,w=0,b=0;const y=matchMedia("(prefers-reduced-motion: reduce)"),S=e.source instanceof HTMLVideoElement?e.source:null,E=()=>{h||n||!u||document.hidden||(n=requestAnimationFrame(A))},k=()=>!m&&!y.matches&&u&&!document.hidden,T=()=>{S&&(S.loop=!0,k()?S.play().catch(()=>{m=!0,c=!0,E()}):S.pause()),g=0,c=!0,E()};function A(t){if(n=0,h||!u||document.hidden)return;const l=k();l&&(p+=g?Math.min(.1,(t-g)/1e3):0),g=t;const f=l&&(e.animated||"none"!==s.motion.type||"none"!==s.dither.motion||s.effects.grain>0||s.effects.dust>0||s.effects.glitch>0),y=S?.getVideoPlaybackQuality?.().totalVideoFrames??-1,T="none"!==s.motion.type||"none"!==s.dither.motion||s.effects.grain>0||s.effects.dust>0||s.effects.glitch>0,A=!S||y<0||y!==x;if(c||r.active||f&&(A||T)&&t-M>=1e3/Math.max(1,Math.min(60,i.fps??60))-.5){const n=performance.now();try{e.animated&&!S&&r.invalidate();const[t,h]=d(a,o,s);r.render(e.frame(S?.currentTime??p),p,t,h);const l=performance.now()-n;i.onFrame?.(S?.currentTime??p,l),w=w?.9*w+.1*l:l,++v>20&&!1!==i.adaptive&&(b=w>13?b+1:0,b>=12&&r.maxCells>3e3&&(r.setBudget(Math.max(3e3,.8*r.maxCells)),i.onQualityChange?.(r.maxCells),b=0,w=0))}catch(t){m=!0,i.onError?.(t instanceof Error?t:new Error(String(t)))}c=!1,M=t,x=y}l&&(f||r.active)&&E()}const F=e=>{if(!k())return;const i=t.getBoundingClientRect();r.pointer((e.clientX-i.left)/i.width,(e.clientY-i.top)/i.height,e.timeStamp),E()},R=()=>{r.leave(),E()},P=new IntersectionObserver(([t])=>{u=t.isIntersecting,T()});P.observe(t),t.addEventListener("pointermove",F),t.addEventListener("pointerleave",R),t.addEventListener("pointercancel",R),document.addEventListener("visibilitychange",T),y.addEventListener("change",T);const L=()=>{h||(h=!0,cancelAnimationFrame(n),P.disconnect(),t.removeEventListener("pointermove",F),t.removeEventListener("pointerleave",R),t.removeEventListener("pointercancel",R),document.removeEventListener("visibilitychange",T),y.removeEventListener("change",T),i.signal?.removeEventListener("abort",L),r.destroy(),e.destroy())};if(i.signal?.addEventListener("abort",L,{once:!0}),i.signal?.aborted)throw L(),new DOMException("Cancelled","AbortError");return T(),{canvas:t,media:e,update(t){s=f(s,t),r.configure(s),c=!0,E()},resize(t,e){a=Math.max(2,t),o=Math.max(2,e),c=!0,E()},pause(t=!0){m=t,T()},async seek(t){p=Math.max(0,t),await e.seek(p),r.invalidate(),c=!0,E()},redraw(){r.invalidate(),c=!0,E()},get time(){return S?.currentTime??p},get paused(){return m||y.matches},get maxCells(){return r.maxCells},get capabilities(){return r.capabilities},destroy:L}}var D={Standard:()=>import("figlet/fonts/Standard"),Slant:()=>import("figlet/fonts/Slant"),Small:()=>import("figlet/fonts/Small"),Big:()=>import("figlet/fonts/Big"),Banner:()=>import("figlet/fonts/Banner"),Block:()=>import("figlet/fonts/Block"),Bubble:()=>import("figlet/fonts/Bubble"),Digital:()=>import("figlet/fonts/Digital"),Doom:()=>import("figlet/fonts/Doom"),Lean:()=>import("figlet/fonts/Lean"),Mini:()=>import("figlet/fonts/Mini"),Script:()=>import("figlet/fonts/Script"),Shadow:()=>import("figlet/fonts/Shadow"),Speed:()=>import("figlet/fonts/Speed"),Starwars:()=>import("figlet/fonts/Star Wars"),Stop:()=>import("figlet/fonts/Stop"),Straight:()=>import("figlet/fonts/Straight"),Thin:()=>import("figlet/fonts/Thin"),ThreeD:()=>import("figlet/fonts/3-D"),Univers:()=>import("figlet/fonts/Univers"),Wavy:()=>import("figlet/fonts/Wavy")},U=Object.keys(D);exports.BLEND_MODES=i,exports.DEFAULT_STUDIO_SETTINGS=a,exports.DITHER_ALGORITHMS=e,exports.STUDIO_LOOKS=m,exports.STUDIO_PALETTES=s,exports.STUDIO_STYLES=t,exports.STUDIO_TEXT_FONTS=U,exports.createStudioRenderer=I,exports.createStudioText=async function(t,e="Standard",i="#ffffff"){if(!Object.prototype.hasOwnProperty.call(D,e))throw new Error("Unknown text font.");const{default:s}=await import("figlet/browser"),a=await D[e]();s.parseFont(e,a.default),s.defaults({fetchFontIfMissing:!1});const o=s.textSync(t.slice(0,120),{font:e}),r=o.split("\n"),n=Math.max(1,...r.map(t=>t.length)),h=Math.max(1,r.length),l=Math.min(1,2048/(9*n)),c=document.createElement("canvas");c.width=Math.ceil(9*n*l+32),c.height=Math.ceil(15*h*l+32);const d=c.getContext("2d");return d.fillStyle="#080808",d.fillRect(0,0,c.width,c.height),d.fillStyle=i,d.font=15*l+"px monospace",d.textBaseline="top",r.forEach((t,e)=>d.fillText(t,16,16+15*e*l)),{canvas:c,ascii:o}},exports.exportStudio=async function(t,e,i){const{format:s,signal:a}=i,o=Math.round(i.width),r=Math.round(i.height);if(!Number.isFinite(o)||!Number.isFinite(r)||o<2||r<2||o>4096||r>4096||o*r>16777216)throw new Error("Choose export dimensions between 2 and 4096 pixels.");if(!["png","jpeg","mp4","webm","gif"].includes(s))throw new Error("Unknown export format.");if(void 0!==i.fps&&!Number.isFinite(i.fps))throw new Error("Frames per second must be finite.");const n=Math.max(1,Math.min(60,Math.round(i.fps??24))),h=i.duration??5;if(!Number.isFinite(h)||h<=0||h>60)throw new Error("Choose a duration from 0 to 60 seconds.");const c="png"===s||"jpeg"===s;if(!c&&o*r>8294400)throw new Error("Video exports support up to 3840 × 2160 pixels.");if("gif"===s&&(o*r>921600||h*n>600))throw new Error("GIF export supports up to 1280 × 720 and 600 frames. Use MP4 for larger exports.");if(void 0!==i.referenceWidth&&(!Number.isFinite(i.referenceWidth)||i.referenceWidth<1))throw new Error("Reference width must be a positive number.");if("gif"===s&&n>30)throw new Error("GIF exports support up to 30 fps. Choose MP4 or WebM for higher frame rates.");const d=document.createElement("canvas"),f=I(d,l(e),{maxDimension:4096,maxCells:i.maxCells??12e3,pixelRatio:o/(i.referenceWidth??Math.min(o,960))});let m;try{if(L(a),i.onProgress?.(0),c){if(f.render(await t.frame(0,a),0,o,r),"unavailable"===d.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");L(a);const e=await new Promise((t,e)=>d.toBlob(i=>i?t(i):e(new Error("Image export failed.")),"png"===s?"image/png":"image/jpeg",i.quality??.92));return i.onProgress?.(1),e}const e=Math.ceil(h*n);if("gif"===s){const s=await import("gifenc"),{GIFEncoder:l,quantize:c,applyPalette:m}="function"==typeof s.GIFEncoder?s:s.default,u=l(),p=d.getContext("2d");for(let s=0;s<e;s++){L(a);const l=s/n;if(f.invalidate(),f.render(await t.frame(l,a),l,o,r),"unavailable"===d.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");const g=p.getImageData(0,0,o,r).data,M=c(g,256),x=m(g,M);u.writeFrame(x,o,r,{palette:M,delay:10*(Math.round(100*Math.min((s+1)/n,h))-Math.round(100*s/n)),repeat:0}),i.onProgress?.((s+1)/e*.98),await new Promise(t=>setTimeout(t,0))}return u.finish(),i.onProgress?.(1),new Blob([new Uint8Array(u.bytes())],{type:"image/gif"})}const{Output:l,Mp4OutputFormat:u,WebMOutputFormat:p,BufferTarget:g,CanvasSource:M,canEncodeVideo:x}=await import("mediabunny"),v="mp4"===s?"avc":"vp9";if(!await x(v,{width:o,height:r}))throw new Error(`${s.toUpperCase()} encoding is unavailable in this browser. Try another format or a current browser with WebCodecs.`);const w=new l({format:"mp4"===s?new u({fastStart:"in-memory"}):new p,target:new g});d.width=o,d.height=r,m=()=>w.cancel();const b=new M(d,{codec:v,bitrate:Math.max(5e5,Math.round(o*r*n*.15))});w.addVideoTrack(b,{frameRate:n}),d.width=o,d.height=r,await w.start();for(let s=0;s<e;s++){L(a);const l=s/n;if(f.invalidate(),f.render(await t.frame(l,a),l,o,r),"unavailable"===d.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");await b.add(l,Math.min(1/n,h-l)),i.onProgress?.((s+1)/e*.98),s%4==0&&await new Promise(t=>setTimeout(t,0))}return b.close(),L(a),await w.finalize(),m=void 0,i.onProgress?.(1),new Blob([w.target.buffer],{type:"mp4"===s?"video/mp4":"video/webm"})}catch(t){throw await(m?.().catch(()=>{})),t}finally{f.destroy(),d.width=d.height=1}},exports.loadStudioMedia=P,exports.mountStudio=async function(t,e,i={}){const s=await P(e,i.signal);try{return C(t,s,i)}catch(t){throw s.destroy(),t}},exports.mountStudioMedia=C,exports.normalizeStudioSettings=l,exports.parseStudioSettings=function(t){if(t.length>1e5)throw new Error("Settings exceed 100 KB.");return l(JSON.parse(t))},exports.restyleStudio=function(t,e=Math.random){const i=m.filter(e=>e.settings.style!==t.style||e.settings.ink!==t.ink),s=u(i[Math.min(i.length-1,Math.max(0,Math.floor(e()*i.length)))].id);return s.aspectRatio=t.aspectRatio,s.crop={...t.crop},s.mask=l(t).mask,s},exports.serializeStudioSettings=function(t){return JSON.stringify(l(t))},exports.studioCrop=c,exports.studioDimensions=d,exports.studioLook=u,exports.studioSourceSize=k,exports.updateStudioSettings=f;//# sourceMappingURL=studio.cjs.map
|