asciify-engine 4.6.0 → 4.8.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/dist/studio.js CHANGED
@@ -1 +1 @@
1
- var t=[{value:"none",label:"Off",group:"Still",description:"Keep the artwork still under the pointer."},{value:"trail",label:"Trail",group:"Change characters",description:"A fluid wake changes character density and settles behind your cursor."},{value:"dissolve",label:"Dissolve",group:"Change characters",description:"Erase a soft path through the characters; the image gradually reforms."},{value:"contour",label:"Contour",group:"Change characters",description:"Fine tonal rings trace your path without moving the grid."},{value:"etch",label:"Emboss",group:"Change characters",description:"Press a light-and-shadow impression into the characters; the grid stays fixed."},{value:"water",label:"Water",group:"Move the image",description:"Soft ripples refract the image and settle after your stroke."},{value:"silk",label:"Silk",group:"Move the image",description:"Directional folds follow the movement of your hand."},{value:"vortex",label:"Vortex",group:"Move the image",description:"A swirling wake curls through the image."},{value:"magnetic",label:"Magnetic Pull",group:"Move the image",description:"The image gathers toward your stroke, then relaxes."},{value:"scatter",label:"Scatter",group:"Move the image",description:"A textured outward scatter settles behind your cursor."},{value:"elastic",label:"Elastic",group:"Move the image",description:"Push the image with your stroke; it recoils and springs back into place."},{value:"rake",label:"Rake",group:"Move the image",description:"Comb the image into alternating ribbons that glide back into alignment."}],e=[{value:"none",mode:"none",group:"Still",label:"Off",description:"Keep the image still. Hover stays available."},{value:"caustics",mode:"caustics",group:"Light and texture",label:"Caustics",description:"Soft ribbons of light travel across a stationary character grid."},{value:"current",mode:"current",group:"Flow and depth",label:"Slow Current",description:"A gentle flow through the image, with steady edges."},{value:"reform",mode:"reform",group:"Rebuild",label:"Reveal & Reform",description:"Disperse, gather, then hold the complete image."},{value:"sheen",mode:"sheen",group:"Light and texture",label:"Sheen",description:"A broad diagonal light sweep; characters stay anchored."},{value:"tidal",mode:"tidal",group:"Flow and depth",label:"Tidal Rings",description:"Concentric currents travel outward, with protected edges."},{value:"grain",mode:"grain",group:"Light and texture",label:"Living Grain",description:"Slow, individually phased tonal changes on a stationary grid."},{value:"parallax",mode:"parallax",group:"Flow and depth",label:"Parallax",description:"A shallow, continuous drift through the image, with the edges held in place."},{value:"weave",mode:"weave",group:"Flow and depth",label:"Woven Flow",description:"Interlaced bands move in opposing directions, like a flexible printed fabric."},{value:"print",mode:"print",group:"Rebuild",label:"Print Shift",description:"Staggered rows lift, soften and register back into the image."},{value:"trace",mode:"trace",group:"Light and texture",label:"Contour Light",description:"Light follows the source image’s tonal contours; every character stays anchored."}],i=t=>Math.max(0,Math.min(1,t)),a=(t,e,a)=>{const s=i((a-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)},r=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,r,o,n,h=.5){if(n[0]=n[1]=n[2]=0,n[3]=1,"none"===t)return n;const l=o*Math.PI/6,c=a(0,.12,Math.min(e,1-e,r,1-r));if("caustics"===t){const t=Math.sin(9*e+5*r+l)+Math.sin(8*r-3*e-l),i=Math.pow(Math.max(0,1-.72*Math.abs(t)),3);n[2]=(.22*i-.045)*c}else if("current"===t)n[0]=Math.sin(9*r+l)*Math.cos(7*e-l)*10*c,n[1]=Math.cos(8*e+l)*Math.sin(6*r-l)*7*c;else if("sheen"===t)n[2]=.2*Math.pow(.5+.5*Math.cos(5*e+3*r-l),8)-.025;else if("tidal"===t){const t=e-.5,i=r-.5,a=Math.hypot(t,i),s=Math.sin(22*a-l)*c;n[0]=t*s*9,n[1]=i*s*9,n[2]=.035*s}else if("grain"===t){const t=s(Math.floor(160*e),Math.floor(100*r))*Math.PI*2;n[2]=.07*Math.sin(l+t)}else if("parallax"===t){const t=.45+.55*Math.max(0,1-1.4*Math.hypot(e-.5,r-.5));n[0]=12*Math.sin(l)*t*c,n[1]=6*(Math.cos(l)-1)*t*c}else if("weave"===t)n[0]=Math.sin(r*Math.PI*6+l)*Math.sin(l)*8*c,n[1]=Math.sin(e*Math.PI*6-l)*Math.sin(l)*6*c;else if("print"===t){const t=Math.floor(24*r),e=((o+3*s(t,3))%12+12)%12,i=a(1,2.5,e)*(1-a(3.5,5,e));n[0]=Math.sin(2.4*t)*i*9*c,n[1]=5*-i*c,n[2]=.22*-i,n[3]=1-.45*i}else if("trace"===t){const t=.5+.5*Math.cos(l);n[2]=.22*Math.pow(Math.max(0,1-Math.abs(i(h)-t)/.16),3)-.015}else if("reform"===t){const t=(o%12+12)%12,i=s(Math.floor(160*e),Math.floor(100*r)),h=.65*e+.2*r+.15*i+.08*Math.sin(8*e-5*r),m=a(1.8+1.2*h,3.8+1.2*h,t)*(1-a(5+1.7*h,7.2+1.7*h,t));n[0]=Math.sin(9*r+l)*m*(1-m)*24*c,n[1]=-m*(1-m)*(8+12*i)*c,n[2]=.45*-m,n[3]=1-.9*m}return n}function n(t,e){const a=Math.max(0,Math.min(2,Number.isFinite(e)?e:1));return t[0]*=a,t[1]*=a,t[2]*=a,t[3]=i(1+(t[3]-1)*a),t}var h=["rgb","red","green","blue"],l=t=>Math.max(0,Math.min(1,t));function c(t){const e=new Map([[0,0],[1,1]]);if(Array.isArray(t))for(const i of t.slice(0,64)){if(!Array.isArray(i)||i.length<2||"number"!=typeof i[0]||!Number.isFinite(i[0])||"number"!=typeof i[1]||!Number.isFinite(i[1]))continue;const t=Math.round(255*l(i[0]))/255;!e.has(t)&&e.size>=16||e.set(t,l(i[1]))}return[...e].sort((t,e)=>t[0]-e[0])}function m(t){const e=t&&"object"==typeof t?t:{};return Object.fromEntries(h.map(t=>[t,c(e[t])]))}function f(t){const e=c(t),i=e.length,a=e.slice(1).map((t,i)=>t[0]-e[i][0]),s=e.slice(1).map((t,i)=>(t[1]-e[i][1])/a[i]),r=new Float64Array(i);r[0]=s[0],r[i-1]=s[i-2];for(let t=1;t<i-1;t++){const e=s[t-1],i=s[t];if(e*i<=0)continue;const o=2*a[t]+a[t-1],n=a[t]+2*a[t-1];r[t]=(o+n)/(o/e+n/i)}const o=new Uint8Array(256);let n=0;for(let t=0;t<256;t++){const s=t/255;for(;n<i-2&&s>e[n+1][0];)n++;const h=a[n],c=(s-e[n][0])/h,m=c*c,f=m*c,d=(2*f-3*m+1)*e[n][1]+(f-2*m+c)*h*r[n]+(-2*f+3*m)*e[n+1][1]+(f-m)*h*r[n+1];o[t]=Math.round(255*l(d))}return o}var d=["ascii","blocks","braille","dots","lines","cross","diagonal","diamond","mixed","pixel","mosaic","lego","voxel","disco","dither","hex","led","cmyk"],u=["none","bayer2","bayer4","bayer8","bayer16","floyd-steinberg","atkinson","stucki","sierra","sierra-lite","burkes","jarvis","halftone","lines","noise","vertical-lines","diagonal-lines","radial","blue-noise"],g=["source-over","multiply","screen","overlay","soft-light","hard-light","color-dodge","color-burn","hue","saturation","color","luminosity"],p={original:[],gray4:["#000000","#555555","#aaaaaa","#ffffff"],gray8:["#000000","#242424","#494949","#6d6d6d","#929292","#b6b6b6","#dbdbdb","#ffffff"],rgb8:["#000000","#ff0000","#00ff00","#0000ff","#ffff00","#ff00ff","#00ffff","#ffffff"],cyberpunk:["#08081a","#3c1670","#ed299a","#29dfef","#fff7bf"],pastel:["#393448","#a5b4d4","#9ed9c6","#e7aac1","#f5e8be"],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"]},M={version:1,aspectRatio:"original",style:"ascii",cellSize:6,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",blackPoint:0,whitePoint:1,gamma:1,shadows:0,highlights:0,curves:{rgb:[[0,0],[1,1]],red:[[0,0],[1,1]],green:[[0,0],[1,1]],blue:[[0,0],[1,1]]},denoise:0},dither:{algorithm:"none",palette:"mono",colors:["#080808","#e8b900"],amount:1,scale:2,threshold:.5,motion:"none",speed:1,direction:45,colorSpace:"rgb"},mask:{enabled:!1,invert:!1,shapes:[]},lights:[],effects:{bloom:0,characterBloom:0,grain:0,dust:0,scanlines:0,crt:0,prism:0,rgbSplit:0,sharpen:0,vignette:0,glitch:0,pixelate:0,blur:0,blurType:"gaussian",angle:0,focus:.5,halftone:0},motion:{type:"none",speed:1,amount:1},hover:{effect:"trail",strength:.55,radius:.2,edgeSafe:!1}},x=t=>t&&"object"==typeof t&&!Array.isArray(t)?t:{},v=(t,e,i,a)=>"number"==typeof t&&Number.isFinite(t)?Math.min(a,Math.max(i,t)):e,b=(t,e)=>"string"==typeof t&&/^#[\da-f]{6}$/i.test(t)?t:e,w=(t,e,i)=>e.includes(t)?t:i;function y(i={}){const a=x(i),s=M;if(void 0!==a.version&&1!==a.version)throw new Error("Unsupported studio settings version. Update asciify-engine.");const r=x(a.crop),o=x(a.backdrop),n=x(a.color),h=x(a.dither),l=x(a.mask),c=x(a.effects),f=x(a.motion),y=x(a.hover),k={...s.effects};for(const t of["bloom","characterBloom","grain","dust","scanlines","crt","prism","rgbSplit","sharpen","vignette","glitch","pixelate","halftone"])k[t]=v(c[t],0,0,1);k.blur=v(c.blur,0,0,24),k.blurType=w(c.blurType,["gaussian","directional","radial","progressive"],s.effects.blurType),k.angle=v(c.angle,0,-180,180),k.focus=v(c.focus,.5,0,1);let S=2048;return{version:1,aspectRatio:w(a.aspectRatio,["original","16:9","9:16","1:1","4:3","3:4","21:9"],"original"),style:w(a.style,d,s.style),cellSize:v(a.cellSize,s.cellSize,["pixel","mosaic","lego","voxel","disco","dots","hex","led","cmyk"].includes(String(a.style))?1:3,60),charset:"string"==typeof a.charset&&a.charset.length?Array.from(a.charset).slice(0,128).join(""):s.charset,colorMode:w(a.colorMode,["accent","source","gray"],s.colorMode),ink:b(a.ink,s.ink),crop:{x:v(r.x,.5,0,1),y:v(r.y,.5,0,1),zoom:v(r.zoom,1,1,5),rotation:90*Math.round(v(r.rotation,0,-360,360)/90)},backdrop:{mode:w(o.mode,["solid","transparent","source","blurred","gradient"],s.backdrop.mode),color:b(o.color,s.backdrop.color),color2:b(o.color2,s.backdrop.color2),blur:v(o.blur,12,0,32),opacity:v(o.opacity,1,0,1)},color:{brightness:v(n.brightness,0,-1,1),contrast:v(n.contrast,1,0,3),saturation:v(n.saturation,1,0,3),grayscale:v(n.grayscale,0,0,1),tint:b(n.tint,s.color.tint),amount:v(n.amount,0,0,1),blend:w(n.blend,g,s.color.blend),blackPoint:v(n.blackPoint,0,0,.99),whitePoint:Math.max(v(n.blackPoint,0,0,.99)+1/255,v(n.whitePoint,1,1/255,1)),gamma:v(n.gamma,1,.25,4),shadows:v(n.shadows,0,-1,1),highlights:v(n.highlights,0,-1,1),curves:m(n.curves),denoise:v(n.denoise,0,0,1)},dither:{algorithm:w(h.algorithm,u,"none"),palette:"string"==typeof h.palette&&Object.prototype.hasOwnProperty.call(p,h.palette)?h.palette:"mono",colors:Array.isArray(h.colors)&&h.colors.length>=2?h.colors.slice(0,32).map(t=>b(t,"#000000")):[...s.dither.colors],amount:v(h.amount,1,0,2),scale:Math.round(v(h.scale,2,1,12)),threshold:v(h.threshold,.5,0,1),motion:w(h.motion,["none","drift","shimmer"],"none"),speed:v(h.speed,1,.1,3),direction:v(h.direction,45,-180,180),colorSpace:w(h.colorSpace,["rgb","luminance"],"rgb")},mask:{enabled:!0===l.enabled,invert:!0===l.invert,shapes:Array.isArray(l.shapes)?l.shapes.slice(0,64).map(t=>{const e=x(t),i=w(e.kind,["rectangle","ellipse","brush"],"rectangle"),a="brush"===i&&Array.isArray(e.points)?e.points.slice(0,S).map(t=>Array.isArray(t)?[Math.round(1e4*v(t[0],0,0,1))/1e4,Math.round(1e4*v(t[1],0,0,1))/1e4]:[0,0]):[];return S-=a.length,{kind:i,x:v(e.x,0,0,1),y:v(e.y,0,0,1),width:v(e.width,.5,0,1),height:v(e.height,.5,0,1),size:v(e.size,.05,.005,.5),points:a}}):[]},lights:Array.isArray(a.lights)?a.lights.slice(0,4).map(t=>{const e=x(t);return{x:v(e.x,.5,0,1),y:v(e.y,.5,0,1),radius:v(e.radius,.3,.02,1),intensity:v(e.intensity,.5,0,1),color:b(e.color,"#ffffff")}}):[],effects:k,motion:{type:w(f.type,e.map(t=>t.mode),"none"),speed:v(f.speed,1,.1,3),amount:v(f.amount,1,0,2)},hover:{effect:w(y.effect,t.map(t=>t.value),"trail"),strength:v(y.strength,.55,0,1),radius:v(y.radius,.2,.1,1),edgeSafe:!0===y.edgeSafe}}}function k(t){return JSON.stringify(y(t))}function S(t){if(t.length>1e5)throw new Error("Settings exceed 100 KB.");return y(JSON.parse(t))}function A(t,e,i,a,s){const r=Math.abs(s.rotation/90)%2==1,o=r?e:t,n=r?t:e,h=Math.max(i/o,a/n)*s.zoom;return{width:o*h,height:n*h,x:(i-o*h)*s.x,y:(a-n*h)*s.y,scale:h,rotated:r}}function E(t,e,i){if(Math.abs(i.crop.rotation/90)%2==1&&([t,e]=[e,t]),"original"===i.aspectRatio)return[t,e];const[a,s]=i.aspectRatio.split(":").map(Number);return t/e>a/s?[Math.round(e*a/s),e]:[t,Math.round(t*s/a)]}function F(t,e){const i={...t,...e};for(const a of["crop","backdrop","color","dither","mask","effects","motion","hover"])e[a]&&Object.assign(i,{[a]:{...t[a],...e[a]}});return e.color?.curves&&(i.color.curves={...t.color.curves,...e.color.curves}),y(i)}function T(t,e,i,a=12e3,s=1){const r=Math.max(2,Number.isFinite(t)?t:960),o=Math.max(2,Number.isFinite(e)?e:540),n=Math.max(1,Math.floor(Number.isFinite(a)?a:12e3)),h=Math.max(.01,Number.isFinite(s)?s:1),l=["dither","pixel","mosaic","lego","voxel","disco","dots","hex","led","cmyk"].includes(i.style)?1:1.65;let c=Math.max(1,Math.ceil(Math.sqrt(r*o/(n*l))/h));for(;Math.ceil(r/(c*h))*Math.ceil(o/(c*h*l))>n;)c++;const m="dither"===i.style?i.dither.scale:i.cellSize,f=Math.max(c,m)*h;return{cell:f,rowHeight:f*l,columns:Math.ceil(r/f),rows:Math.ceil(o/(f*l)),minimum:c,limited:m<c}}var P=[["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:"caustics",speed:.5}}],["blueprint","Blueprint","Linework in a cool monochrome.",{style:"lines",ink:"#9bccdf",backdrop:{mode:"solid",color:"#0a1e30"}}]].map(([t,e,i,a])=>({id:t,name:e,description:i,settings:y(a)}));function I(t){const e=P.find(e=>e.id===t);if(!e)throw new Error("Unknown studio look.");return y(e.settings)}function R(t,e=Math.random){const i=P.filter(e=>e.settings.style!==t.style||e.settings.ink!==t.ink),a=I(i[Math.min(i.length-1,Math.max(0,Math.floor(e()*i.length)))].id);return a.aspectRatio=t.aspectRatio,a.crop={...t.crop},a.mask=y(t).mask,a}function C(t,e,i,a,s,r){a=Math.max(0,Math.min(e-1,a)),s=Math.max(0,Math.min(i-1,s));const o=Math.floor(a),n=Math.floor(s),h=a-o,l=s-n,c=4*(n*e+o);if(0===h&&0===l){for(let e=0;e<4;e++)r[e]=t[c+e];return}const m=4*(n*e+Math.min(e-1,o+1)),f=4*(Math.min(i-1,n+1)*e+o),d=4*(Math.min(i-1,n+1)*e+Math.min(e-1,o+1)),u=(1-h)*(1-l)*t[c+3],g=h*(1-l)*t[m+3],p=(1-h)*l*t[f+3],M=h*l*t[d+3],x=u+g+p+M;for(let e=0;e<3;e++)r[e]=x?(t[c+e]*u+t[m+e]*g+t[f+e]*p+t[d+e]*M)/x:0;r[3]=x}function L(t){const e=function(t){const e=t.blackPoint??0,i=t.whitePoint??1,a=t.gamma??1,s=t.shadows??0,r=t.highlights??0;if(0===e&&1===i&&1===a&&0===s&&0===r)return null;const o=[0,.25+.2*s,.5,.75+.2*r,1],n=o.slice(1).map((t,e)=>4*(t-o[e])),h=[n[0],...n.slice(1).map((t,e)=>2*t*n[e]/(t+n[e])),n[3]],l=new Uint8Array(256);for(let t=0;t<256;t++){const s=Math.pow(Math.max(0,Math.min(1,(t/255-e)/(i-e))),1/a),r=Math.min(3,Math.floor(4*s)),n=4*s-r,c=n*n,m=c*n,f=(2*m-3*c+1)*o[r]+(m-2*c+n)*h[r]/4+(-2*m+3*c)*o[r+1]+(m-c)*h[r+1]/4;l[t]=Math.round(255*Math.max(0,Math.min(1,f)))}return l}(t),i=t.curves;if(!e&&(!i||Object.values(i).every(t=>t.every(([t,e])=>t===e))))return null;const a=f(i?.rgb),s=[i?.red,i?.green,i?.blue].map(f),r=new Uint8Array(768);for(let t=0;t<256;t++)for(let i=0;i<3;i++)r[256*i+t]=s[i][a[e?e[t]:t]];return r}var X=class{constructor(t=0){this.amount=0,this.weights=new Float32Array(256),this.source=new Uint8ClampedArray(0),this.configure(t)}configure(t=0){const e=Math.max(0,Math.min(1,Number.isFinite(t)?t:0));if(e===this.amount)return;if(this.amount=e,0===e)return void(this.source=new Uint8ClampedArray(0));const i=8+24*e;for(let t=0;t<256;t++)this.weights[t]=Math.exp(-t*t/(2*i*i))}apply(t,e,i){if(!this.amount)return;if(!Number.isInteger(e)||!Number.isInteger(i)||e<1||i<1||e*i*4!==t.length)throw new Error("Denoise dimensions do not match the source.");this.source.length!==t.length&&(this.source=new Uint8ClampedArray(t.length));const a=this.source;a.set(t);for(let s=0;s<i;s++)for(let r=0;r<e;r++){const o=4*(s*e+r);if(!a[o+3])continue;const n=a[o],h=a[o+1],l=a[o+2];let c=0,m=0,f=0,d=0;for(let t=-1;t<=1;t++){const o=s+t;if(!(o<0||o>=i))for(let i=-1;i<=1;i++){const s=r+i;if(s<0||s>=e)continue;const u=4*(o*e+s);if(!a[u+3])continue;const g=Math.max(Math.abs(a[u]-n),Math.abs(a[u+1]-h),Math.abs(a[u+2]-l)),p=this.weights[g]*(0===i?1:.6)*(0===t?1:.6)*a[u+3];c+=a[u]*p,m+=a[u+1]*p,f+=a[u+2]*p,d+=p}}t[o]=n+(c/d-n)*this.amount,t[o+1]=h+(m/d-h)*this.amount,t[o+2]=l+(f/d-l)*this.amount}}},N=new Set(["none","floyd-steinberg","atkinson","stucki","sierra","sierra-lite","burkes","jarvis"]);function D(t){return"dither"===t.style&&("shimmer"===t.dither.motion||"drift"===t.dither.motion&&t.dither.amount>0&&!N.has(t.dither.algorithm))}function U(t){return"none"!==t.motion.type&&(t.motion.amount??1)>0}var O="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",Y="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",B=new Uint16Array(4096);for(let t=0;t<B.length;t++)B[t]=O.indexOf(Y[2*t])<<6|O.indexOf(Y[2*t+1]);var z=(t,e)=>{const i=43758.5453*Math.sin(127.1*t+311.7*e);return i-Math.floor(i)};var W=new Map([2,4,8,16].map(t=>[t,Float64Array.from({length:t*t},(e,i)=>function(t,e,i){let a=0;for(let s=1;s<i;s*=2){const i=(Math.floor(t/s)%2+2)%2;a=4*a+[[0,2],[3,1]][(Math.floor(e/s)%2+2)%2][i]}return(a+.5)/(i*i)-.5}(i%t,Math.floor(i/t),t))])),q={"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]]},G=t=>[parseInt(t.slice(1,3),16),parseInt(t.slice(3,5),16),parseInt(t.slice(5,7),16)];function j(t,e,i){const a=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)),s=Math.max(0,Math.min(1,(a-.035)/.105));return s*s*s*(s*(6*s-15)+10)}var V=t=>["dissolve","silk","vortex","magnetic","scatter","etch","elastic","rake"].includes(t),H=class{constructor(t,e){this.edgeSafe=!1,this.previous=null,this.peak=0,this.scatterDirections=null,this.springX=null,this.springY=null,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 a=0;a<t;a++)this.edge[i*t+a]=j(a/(t-1),i/(e-1),t/e);this.clear()}get active(){return this.peak>2e-4}setMode(t){if("elastic"!==t||this.springX||(this.springX=new Float32Array(this.ink.length),this.springY=new Float32Array(this.ink.length)),"scatter"===t&&!this.scatterDirections){const t=this.scatterDirections=new Float64Array(this.width*this.height*2);for(let e=0;e<this.height;e++)for(let i=0;i<this.width;i++){const a=43758.5453*Math.sin(127.1*i+311.7*e),s=(a-Math.floor(a))*Math.PI*2,r=2*(e*this.width+i);t[r]=.7*Math.cos(s),t[r+1]=.7*Math.sin(s)}}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,this.springX?.fill(0),this.springY?.fill(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 a=this.previous;this.previous={x:t,y:e};const s=this.width,r=this.height,o=Math.max(1,s/r),n=Math.max(1,r/s),h=a?(t-a.x)*o:0,l=a?(e-a.y)*n:0,c=Math.hypot(h,l);if(!a&&"dissolve"!==this.mode&&"etch"!==this.mode)return;if(a&&c<1e-4)return;const m=.035+.11*Math.max(.1,Math.min(1,i)),f=Math.min(128,Math.max(1,Math.ceil(c/(.45*m)))),d=c?h/c:1,u=c?l/c:0,g=Math.min(1,c/(m*f)*2.2);for(let i=0;i<f;i++){const h=(i+.5)/f,l=a?a.x+(t-a.x)*h:t,c=a?a.y+(e-a.y)*h:e,p=Math.max(0,Math.floor((l-2.5*m/o)*(s-1))),M=Math.min(s-1,Math.ceil((l+2.5*m/o)*(s-1))),x=Math.max(0,Math.floor((c-2.5*m/n)*(r-1))),v=Math.min(r-1,Math.ceil((c+2.5*m/n)*(r-1)));for(let t=x;t<=v;t++)for(let e=p;e<=M;e++){const i=(e/(s-1)-l)*o/m,a=(t/(r-1)-c)*n/m,h=Math.exp(1.5*-(i*i+a*a)),f=t*s+e;if("dissolve"===this.mode||"etch"===this.mode)this.ink[f]=Math.max(this.ink[f],h);else if("elastic"===this.mode)this.springX[f]=Math.max(-24,Math.min(24,this.springX[f]+d*h*g*8)),this.springY[f]=Math.max(-24,Math.min(24,this.springY[f]+u*h*g*8));else{const s=(-i*u+a*d)*h*2.8,r="rake"===this.mode?d*Math.sin(t*Math.PI/3)*h*2:"magnetic"===this.mode?-i*h*2.5:"scatter"===this.mode?(i+this.scatterDirections[2*f])*h*2:"silk"===this.mode?d*s:-a*h*2.5,o="rake"===this.mode?u*Math.sin(e*Math.PI/3)*h*2:"magnetic"===this.mode?-a*h*2.5:"scatter"===this.mode?(a+this.scatterDirections[2*f+1])*h*2:"silk"===this.mode?u*s:i*h*2.5;this.targetX[f]=Math.max(-1,Math.min(1,this.targetX[f]+r*g)),this.targetY[f]=Math.max(-1,Math.min(1,this.targetY[f]+o*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),a=1-Math.exp(-22*e);let s=0;const r=Math.sqrt(336),o=Math.exp(-8*e),n=Math.cos(r*e),h=Math.sin(r*e)/r;for(let t=0;t<this.ink.length;t++)if("etch"===this.mode)this.ink[t]*=i,s=Math.max(s,this.ink[t]);else if("dissolve"===this.mode){this.ink[t]*=i,s=Math.max(s,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{if("elastic"===this.mode){const e=this.offsetX[t],i=this.offsetY[t],a=this.springX[t],r=this.springY[t];this.offsetX[t]=Math.max(-1,Math.min(1,o*(e*n+(a+8*e)*h))),this.offsetY[t]=Math.max(-1,Math.min(1,o*(i*n+(r+8*i)*h))),this.springX[t]=o*(a*n-(8*a+400*e)*h),this.springY[t]=o*(r*n-(8*r+400*i)*h),s=Math.max(s,.05*Math.abs(this.springX[t]),.05*Math.abs(this.springY[t]))}else this.targetX[t]*=i,this.targetY[t]*=i,this.offsetX[t]+=(this.targetX[t]-this.offsetX[t])*a,this.offsetY[t]+=(this.targetY[t]-this.offsetY[t])*a;s=Math.max(s,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),r=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]=r>>>8,this.pixels[4*t+3]=255&r}if("etch"===this.mode)for(let t=0;t<this.height;t++)for(let e=0;e<this.width;e++){const i=t*this.width+e,a=3*(this.ink[t*this.width+Math.max(0,e-1)]-this.ink[t*this.width+Math.min(this.width-1,e+1)]+this.ink[Math.max(0,t-1)*this.width+e]-this.ink[Math.min(this.height-1,t+1)*this.width+e]);this.offsetX[i]=Math.max(-1,Math.min(1,a))*(this.edgeSafe?this.edge[i]:1);const s=Math.round(32767*this.offsetX[i]+32768);this.pixels[4*i]=s>>>8,this.pixels[4*i+1]=255&s}this.peak=s,this.active||this.clear()}sample(t,e,i){const a=Math.max(0,Math.min(this.width-1.001,t*(this.width-1))),s=Math.max(0,Math.min(this.height-1.001,e*(this.height-1))),r=Math.floor(a),o=Math.floor(s),n=a-r,h=s-o,l=o*this.width+r,c=l+this.width,m=t=>(t[l]*(1-n)+t[l+1]*n)*(1-h)+(t[c]*(1-n)+t[c+1]*n)*h;if("etch"===this.mode)return i[0]=i[1]=0,void(i[2]=3*m(this.offsetX));i[0]=m(this.offsetX)*(this.edgeSafe?j(t,e,this.width/this.height):1)*.08,i[1]=m(this.offsetY)*(this.edgeSafe?j(t,e,this.width/this.height):1)*.08,i[2]="dissolve"===this.mode?6*-m(this.ink):0}},K=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 a=Math.max(1,this.width/this.height),s=Math.max(1,this.height/this.width);this.previous&&(Math.hypot((t-this.previous.x)*a,(e-this.previous.y)*s)<.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),a=Math.max(1,this.height/this.width);let s=0;for(const r of this.rings){const o=.015+r.age*(.15+.22*r.radius),n=.009+.014*r.radius,h=(Math.hypot((t-r.x)*i,(e-r.y)*a)-o)/n,l=Math.sin(Math.min(1,r.age/.07)*Math.PI/2)*Math.max(0,1-r.age/1.35)**2;s=Math.max(s,Math.exp(-h*h)*l)}return s}sample(t,e){const i=Math.max(0,Math.min(this.width-1,Math.round(t*(this.width-1)))),a=Math.max(0,Math.min(this.height-1,Math.round(e*(this.height-1))));return Math.max(this.ringSample(t,e),this.echo[a*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 a=0;for(let t=0;t<this.height;t++)for(let e=0;e<this.width;e++){const s=t*this.width+e;this.echo[s]=Math.max(this.ringSample(e/(this.width-1),t/(this.height-1)),this.echo[s]*i),a=Math.max(a,this.echo[s]);const r=Math.round(65535*this.echo[s]),o=4*s;this.pixels[o]=r>>>8,this.pixels[o+1]=255&r}this.echoPeak=a,this.active||(this.echo.fill(0),this.pixels.fill(0))}},Q=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,a=performance.now()){if(!Number.isFinite(t+e+i+a))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 s=this.previous;if(this.previous={x:t,y:e,time:a},!s)return;const r=(t-s.x)*(this.width-1),o=(e-s.y)*(this.height-1),n=Math.hypot(r,o);if(n<.001)return;const h=Math.min(this.width,this.height),l=a>s.time?Math.max(1/240,(a-s.time)/1e3):1/60,c=Math.min(12,n/h/l),m=1-Math.exp(-c/2.2),f=h*(.022+.075*i)*(.65+.95*m),d=Math.min(128,Math.max(1,Math.ceil(n/(.4*f)))),u=n/f*(.32+.22*m)/d,g=r/n,p=o/n,M=-p,x=g,v=n*(2+18*m)/d;for(let i=0;i<d;i++){const a=(i+.5)/d,r=(s.x+(t-s.x)*a)*(this.width-1),o=(s.y+(e-s.y)*a)*(this.height-1),n=Math.max(1,Math.floor(r-3*f)),h=Math.min(this.width-2,Math.ceil(r+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=n;e<=h;e++){const i=((e-r)*g+(t-o)*p)/f,a=((e-r)*M+(t-o)*x)/f,s=Math.exp(-i*i*.65-a*a*1.7),n=t*this.width+e;this.ink[n]=1-(1-this.ink[n])*Math.exp(-s*u);const h=1-a*a*.55,l=i*a*.7;this.u[n]=Math.max(-80,Math.min(80,this.u[n]+(g*h+M*l)*s*v)),this.v[n]=Math.max(-80,Math.min(80,this.v[n]+(p*h+x*l)*s*v))}}this.peak=1}read(t,e,i){const a=0|(e=Math.max(.5,Math.min(this.width-1.5,e))),s=0|(i=Math.max(.5,Math.min(this.height-1.5,i))),r=e-a,o=i-s,n=s*this.width+a;return(t[n]*(1-r)+t[n+1]*r)*(1-o)+(t[n+this.width]*(1-r)+t[n+this.width+1]*r)*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,a=this.height;for(;e>1e-7;){const t=Math.min(1/60,e);e-=t;const s=Math.exp(-1.9*t),r=Math.exp(-3.2*t);for(let e=1;e<a-1;e++)for(let o=1;o<i-1;o++){const n=e*i+o,h=Math.max(.5,Math.min(i-1.5,o-this.u[n]*t)),l=Math.max(.5,Math.min(a-1.5,e-this.v[n]*t)),c=0|h,m=0|l,f=h-c,d=l-m,u=m*i+c,g=(1-f)*(1-d),p=f*(1-d),M=(1-f)*d,x=f*d;this.a[n]=(this.u[u]*g+this.u[u+1]*p+this.u[u+i]*M+this.u[u+i+1]*x)*s,this.b[n]=(this.v[u]*g+this.v[u+1]*p+this.v[u+i]*M+this.v[u+i+1]*x)*s,this.c[n]=(this.ink[u]*g+this.ink[u+1]*p+this.ink[u+i]*M+this.ink[u+i+1]*x)*r}[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<a-1;t++)for(let e=1;e<i-1;e++){const a=t*i+e;this.curl[a]=.5*(this.v[a+1]-this.v[a-1]-this.u[a+i]+this.u[a-i])}for(let e=1;e<a-1;e++)for(let a=1;a<i-1;a++){const s=e*i+a,r=Math.abs(this.curl[s+1])-Math.abs(this.curl[s-1]),o=Math.abs(this.curl[s+i])-Math.abs(this.curl[s-i]),n=Math.hypot(r,o)+1e-4,h=this.curl[s]*t*10,l=Math.hypot(this.u[s],this.v[s]);this.u[s]+=o/n*h,this.v[s]-=r/n*h;const c=Math.min(1,l/(Math.hypot(this.u[s],this.v[s])+1e-6));this.u[s]*=c,this.v[s]*=c,this.divergence[s]=-.5*(this.u[s+1]-this.u[s-1]+this.v[s+i]-this.v[s-i])}this.pressure.fill(0);for(let t=0;t<4;t++){for(let t=1;t<a-1;t++)for(let e=1;e<i-1;e++){const a=t*i+e;this.pressureNext[a]=.25*(this.divergence[a]+this.pressure[a-1]+this.pressure[a+1]+this.pressure[a-i]+this.pressure[a+i])}[this.pressure,this.pressureNext]=[this.pressureNext,this.pressure]}let o=0;for(let e=1;e<a-1;e++)for(let a=1;a<i-1;a++){const s=e*i+a;this.u[s]=Math.max(-80,Math.min(80,this.u[s]-.5*(this.pressure[s+1]-this.pressure[s-1]))),this.v[s]=Math.max(-80,Math.min(80,this.v[s]-.5*(this.pressure[s+i]-this.pressure[s-i]))),this.driftX[s]+=(3.6*this.u[s]-58*this.offsetX[s]-12*this.driftX[s])*t,this.driftY[s]+=(3.6*this.v[s]-58*this.offsetY[s]-12*this.driftY[s])*t,this.offsetX[s]=Math.max(-2,Math.min(2,this.offsetX[s]+this.driftX[s]*t)),this.offsetY[s]=Math.max(-2,Math.min(2,this.offsetY[s]+this.driftY[s]*t)),this.signal[s]=1-Math.exp(.06*-Math.hypot(this.u[s],this.v[s])-.16*this.ink[s]),o=Math.max(o,this.signal[s])}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()}};function J(t,e){const i=Math.max(0,Math.min(1,e/.38));return t+(1-2*t)*(i*i*(3-2*i))}var Z=(t,e)=>"water"===t?30*e/.55:"silk"===t?28*e:"vortex"===t?38*e:["magnetic","scatter","elastic","rake"].includes(t)?32*e:0,_=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]=j(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 Q(this.columns,this.rows),this.contour=new K(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","etch"].includes(this.mode)}get hasRefraction(){return this.active||this.lensStrength>15e-5}get active(){return V(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,V(t)&&this.afterimage.setMode(t),this.refraction.pixels="trail"===t?this.trail.pixels:"contour"===t?this.contour.pixels:V(t)?this.afterimage.pixels:this.waterPixels,this.refraction.strength=Z(t,this.amount))}configure(t,e=.55,i=.2,a=!1){this.setMode(t),this.refraction.edgeSafe=a,this.afterimage.edgeSafe=a,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=Z(t,this.amount),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)),V(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 a=this.previous;this.previous={x:t,y:e};const s=(t-a.x)*this.xScale,r=(e-a.y)*this.yScale,o=Math.hypot(s,r);if(o<1e-5)return;const n=.035+.1*this.radius,h=3*n,l=Math.min(192,Math.max(1,Math.ceil(o/(.5*n)))),c=95*Math.min(o,1)/l;for(let i=0;i<l;i++){const s=(i+.5)/l,r=a.x+(t-a.x)*s,o=a.y+(e-a.y)*s,m=Math.max(1,Math.floor((r-h/this.xScale)*(this.columns-1))),f=Math.min(this.columns-2,Math.ceil((r+h/this.xScale)*(this.columns-1))),d=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=d;t<=u;t++)for(let e=m;e<=f;e++){const i=(e/(this.columns-1)-r)*this.xScale,a=(t/(this.rows-1)-o)*this.yScale,s=Math.exp(-(i*i+a*a)/(n*n))*c,h=t*this.columns+e;this.velocity[h]=Math.max(-12,this.velocity[h]-s)}}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(V(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),a=.3*Math.min(this.columns,this.rows);for(;this.remainder+1e-8>=e;){this.remainder-=e;let t=0;for(let s=1;s<this.rows-1;s++)for(let r=1;r<this.columns-1;r++){const o=s*this.columns+r,n=this.heights[o],h=this.heights[o-1]+this.heights[o+1]+this.heights[o-this.columns]+this.heights[o+this.columns]-4*n,l=Math.min(r,s,this.columns-1-r,this.rows-1-s),c=l<5?.88+.024*l:1,m=(this.velocity[o]+(h*a*a-8*n)*e)*i*c;this.velocity[o]=m,this.next[o]=(n+m*e)*c,t=Math.max(t,Math.abs(this.next[o]),.1*Math.abs(m))}this.heights.set(this.next),this.energy=t,this.pending=!1}if(!this.active)return void this.clear();const s=.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,a=(this.heights[t*this.columns+Math.max(0,e-1)]-this.heights[t*this.columns+Math.min(this.columns-1,e+1)])*s,r=(this.heights[Math.max(0,t-1)*this.columns+e]-this.heights[Math.min(this.rows-1,t+1)*this.columns+e])*s,o=Math.tanh(a)*(this.refraction.edgeSafe?this.edgeMask[i]:1),n=Math.tanh(r)*(this.refraction.edgeSafe?this.edgeMask[i]:1);this.normals[2*i]=o,this.normals[2*i+1]=n;const h=Math.round(32767*o+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),a=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)*a,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(V(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 a=Math.max(0,Math.min(this.columns-1.001,t*(this.columns-1))),s=Math.max(0,Math.min(this.rows-1.001,e*(this.rows-1))),r=Math.floor(a),o=Math.floor(s),n=a-r,h=s-o,l=2*(o*this.columns+r),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,a){const[s,r,o,n]=i.focus,h=(t-s)*Math.max(1,a)/n,l=(e-r)*Math.max(1,1/a)/n;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}};function $(t){return"videoWidth"in t?[t.videoWidth,t.videoHeight]:"naturalWidth"in t?[t.naturalWidth,t.naturalHeight]:[t.width,t.height]}var tt=(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}},et=(t,e,i)=>{t.width===e&&t.height===i||(t.width=e,t.height=i)},it={blocks:" ░▒▓█",braille:" ⠁⠃⠇⡇⣇⣧⣷⣿",lines:" -═╪╬",cross:" ·+xX#",diagonal:" /╱╳",diamond:" ·◇◈◆",mixed:" .:+/◇#@"};function at(t,e={},i={}){const a=t.getContext("2d");if(!a)throw new Error("Canvas is already owned by another renderer.");const s=tt(),r=tt(!0),h=tt(),l=tt(),c=tt(),m=tt(),f=tt(),d=tt(),u=tt(),g=tt();let M,x=0,v=y(e),b=0,w="",k="",S="",E=new Uint8ClampedArray(0),F=new Uint8ClampedArray(0),P=0,I=0,R=0,N=null,O="",Y=new _,j=0;const V=[0,0,0],H=[0,0,0,1],K=[0,0,0,0];let Q=L(v.color);const Z=new X(v.color.denoise),at=Math.max(64,Math.min(4096,Number.isFinite(i.maxDimension)?i.maxDimension:960)),st=Math.max(256,Math.min(1048576,Number.isFinite(i.maxCells)?i.maxCells:12e3));let rt=st,ot=Math.max(.1,Math.min(8,i.pixelRatio??1));return{canvas:t,render:function(e,i=0,y=960,L=540,X=i*v.motion.speed){if(Number.isFinite(i)||(i=0),!Number.isFinite(y)||!Number.isFinite(L)||y<1||L<1)throw new Error("Render dimensions must be positive finite numbers.");const[tt,st]=$(e);if(!tt||!st)return;const nt=Math.min(1,at/Math.max(y,L)),ht=Math.max(2,Math.round(y*nt)),lt=Math.max(2,Math.round(L*nt));et(t,ht,lt),et(s.canvas,ht,lt),et(h.canvas,ht,lt),et(l.canvas,ht,lt),et(c.canvas,ht,lt),j!==ht/lt&&(j=ht/lt,Y=new _(j)),Y.configure(v.hover.effect,v.hover.strength,v.hover.radius,v.hover.edgeSafe),Y.step(Math.max(0,Math.min(.05,i-R))),R=i;const ct="currentTime"in e?e.getVideoPlaybackQuality?.().totalVideoFrames??e.currentTime:0,mt=[b,ht,lt,ct].join(":"),ft="dither"===v.style,dt=T(ht,lt,v,rt,ot),ut=dt.cell,gt=dt.rowHeight,pt=dt.columns,Mt=dt.rows;if(w!==mt||N!==e||P!==pt||I!==Mt){N=e,w=mt,k="",S="",P=pt,I=Mt,s.ctx.clearRect(0,0,ht,lt),s.ctx.save();const t=A(tt,st,ht,lt,v.crop);s.ctx.translate(t.x+t.width/2,t.y+t.height/2),s.ctx.rotate(v.crop.rotation*Math.PI/180),s.ctx.drawImage(e,-tt*t.scale/2,-st*t.scale/2,tt*t.scale,st*t.scale),s.ctx.restore(),et(r.canvas,P,I),r.ctx.clearRect(0,0,P,I),r.ctx.drawImage(s.canvas,0,0,P,I),E=r.ctx.getImageData(0,0,P,I).data,Z.apply(E,P,I);const i=v.color;for(let t=0;t<E.length;t+=4){const e=.299*E[t]+.587*E[t+1]+.114*E[t+2];for(let a=0;a<3;a++){const s=e+(E[t+a]-e)*i.saturation;E[t+a]=((s*(1-i.grayscale)+e*i.grayscale)/255-.5)*i.contrast*255+127.5+255*i.brightness}}Q&&function(t,e){for(let i=0;i<t.length;i+=4)t[i+3]&&(t[i]=e[t[i]],t[i+1]=e[256+t[i+1]],t[i+2]=e[512+t[i+2]])}(E,Q)}const xt=U(v),vt=D(v),bt=!Y.active&&!xt&&!vt,wt=[mt,P,I,ut,gt,ot].join(":");if(!bt||S!==wt){h.ctx.clearRect(0,0,ht,lt),h.ctx.globalAlpha=1,h.ctx.globalCompositeOperation="source-over";const t=X,e=xt?v.motion.type:"none",a=["none","caustics","sheen","grain","trace"].includes(e);if(ft){const a=bt;if(!a||k!==mt){F.length!==E.length&&(F=new Uint8ClampedArray(E.length));const s=F;if(s.set(E),Y.active||"none"!==e)for(let i=0;i<I;i++)for(let a=0;a<P;a++){const r=a/P,h=i/I;let l=a,c=i,m=0,f=1,d=1;Y.active&&(Y.sample(r,h,V),l-=V[0]*P,c-=V[1]*I,m=V[2]/3);const u=4*(i*P+a);o(e,r,h,t,H,(.299*E[u]+.587*E[u+1]+.114*E[u+2])/255),n(H,v.motion.amount??1),l-=H[0]/960*P,c-=H[1]/960*I,f=1+H[2],d=H[3],l=Math.max(0,Math.min(P-1,l)),c=Math.max(0,Math.min(I-1,c));const g=Math.floor(l),p=Math.floor(c),M=l-g,x=c-p,b=4*(i*P+a),w=4*(p*P+g),y=4*(p*P+Math.min(P-1,g+1)),k=4*(Math.min(I-1,p+1)*P+g),S=4*(Math.min(I-1,p+1)*P+Math.min(P-1,g+1));for(let t=0;t<3;t++){const e=((E[w+t]*(1-M)+E[y+t]*M)*(1-x)+(E[k+t]*(1-M)+E[S+t]*M)*x)/255;let i=(["trail","contour"].includes(v.hover.effect)?J(e,m):"etch"===v.hover.effect?Math.max(0,Math.min(1,e+.35*m)):"dissolve"===v.hover.effect?e*Math.max(0,1+m):e)*f;s[b+t]=255*i}s[b+3]=E[w+3]*d}!function(t,e,i,a,s=0){const{algorithm:r,amount:o,threshold:n}=a,h="blue-noise"===r,l=r.startsWith("bayer")?Number(r.slice(5)):0,c=W.get(l),m=l-1,f="luminance"===a.colorSpace,d=("custom"===a.palette?a.colors:p[a.palette]??p.mono).map(G),u=q[r],g=u?new Float32Array(3*e*3):null,M="drift"===a.motion?s*a.speed*3:0,x=(a.direction??45)*Math.PI/180,v=Math.round(Math.cos(x)*M),b=Math.round(Math.sin(x)*M),w=(t,e)=>(t%e+e)%e,y=d.map(t=>.299*t[0]+.587*t[1]+.114*t[2]),k="shimmer"===a.motion?.15*Math.sin(s*a.speed*2):0;for(let a=0;a<i;a++)for(let s=0;s<e;s++){const p=4*(a*e+s),x=3*(a%3*e+s);if(0===t[p+3]){g&&(g[x]=g[x+1]=g[x+2]=0);continue}let S=0;const A=h?(B[64*(a-b&63)+(s-v&63)]+.5)/B.length:0;c?S=c[(a-b&m)*l+(s-v&m)]:"noise"===r?S=z(s-v,a-b)-.5:"lines"===r?S=w(a-b,4)/3-.5:"vertical-lines"===r?S=w(s-v,4)/3-.5:"diagonal-lines"===r?S=w(s-v+a-b,4)/3-.5:"radial"===r?S=w(Math.hypot(s-e/2,a-i/2)-M,6)/6-.5:"halftone"===r&&(S=Math.hypot(w(s-v,6)-2.5,w(a-b,6)-2.5)/3.54-.5);const E=128*(S*o+k+(.5-n)),F=t[p]+E+(g?.[x]??0),T=t[p+1]+E+(g?.[x+1]??0),P=t[p+2]+E+(g?.[x+2]??0);let I=0,R=0,C=0;if(d.length){let t=1/0,e=1/0,i=0,a=0;const s=.299*F+.587*T+.114*P;for(let r=0;r<d.length;r++){const o=d[r],n=f?(s-y[r])**2:(F-o[0])**2*.299+(T-o[1])**2*.587+(P-o[2])**2*.114;n<t?(h&&(e=t,a=i,i=r),t=n,[I,R,C]=o):h&&n<e&&(e=n,a=r)}if(h&&o>0&&Number.isFinite(e)){const t=d[a],e=t[0]-I,r=t[1]-R,n=t[2]-C,h=y[a]-y[i],l=f?h*h:e*e*.299+r*r*.587+n*n*.114,c=f?(s-y[i])*h:(F-I)*e*.299+(T-R)*r*.587+(P-C)*n*.114;A<(l?Math.max(0,Math.min(1,c/l*o)):0)&&([I,R,C]=t)}}else if(h){const t=Math.max(0,Math.min(1,.5+(A-.5)*o));I=51*Math.floor(F/51+1-t),R=51*Math.floor(T/51+1-t),C=51*Math.floor(P/51+1-t)}else I=51*Math.round(F/51),R=51*Math.round(T/51),C=51*Math.round(P/51);if(t[p]=I,t[p+1]=R,t[p+2]=C,g&&u){g[x]=g[x+1]=g[x+2]=0;for(const[t,r,n]of u){const h=s+t;if(h<0||h>=e||a+r>=i)continue;const l=3*((a+r)%3*e+h);g[l]+=(F-I)*n*o,g[l+1]+=(T-R)*n*o,g[l+2]+=(P-C)*n*o}}}}(s,P,I,v.dither,i),r.ctx.putImageData(new ImageData(s,P,I),0,0),k=a?mt:""}h.ctx.imageSmoothingEnabled=!1,h.ctx.drawImage(r.canvas,0,0,ht,lt)}else{const i=Array.from(it[v.style]??v.charset),s=h.ctx,r=G(v.ink),l="ascii"===v.style||!!it[v.style],c=Math.max(3,Math.round(.92*gt)),m=Math.ceil(ut+4),d=Math.ceil(gt+4),u=[i.join(""),c,m,d,v.ink,v.colorMode].join(":");if(l&&u!==O&&(O=u,et(f.canvas,m*i.length,d),f.ctx.clearRect(0,0,f.canvas.width,d),f.ctx.font=`${c}px monospace`,f.ctx.textBaseline="middle",f.ctx.textAlign="center",f.ctx.fillStyle="accent"===v.colorMode?v.ink:"#ffffff",i.forEach((t,e)=>f.ctx.fillText(t,e*m+m/2,d/2))),"lego"===v.style&&x!==ut){x=ut,et(g.canvas,Math.ceil(ut),Math.ceil(gt));const t=g.ctx;t.clearRect(0,0,g.canvas.width,g.canvas.height),t.fillStyle="rgba(255,255,255,.2)",t.strokeStyle="rgba(0,0,0,.25)",t.lineWidth=Math.max(.5,.6*ot),t.beginPath(),t.arc(ut/2,gt/2,.28*ut,0,2*Math.PI),t.fill(),t.stroke()}s.font=`${c}px monospace`,s.textBaseline="middle",s.textAlign="center";for(let h=0;h<I;h++)for(let c=0;c<P;c++){let u=c,p=h,M=0;if(Y.active&&(Y.sample(c/P,h/I,V),u=Math.max(0,Math.min(P-1,c-V[0]*P)),p=Math.max(0,Math.min(I-1,h-V[1]*I)),M=V[2]/3),C(E,P,I,u,p,K),!K[3])continue;const x=K[0],b=K[1],w=K[2],y=(.299*x+.587*b+.114*w)/255;let k=y;["trail","contour"].includes(v.hover.effect)&&M?k=J(k,M):"etch"===v.hover.effect?k=Math.max(0,Math.min(1,k+.35*M)):"dissolve"===v.hover.effect&&(k*=Math.max(0,1+M));let S=c*ut,A=h*gt,F=1;o(e,c/P,h/I,t,H,y),n(H,v.motion.amount??1),S+=H[0]*ht/960,A+=H[1]*lt/960,k=Math.max(0,Math.min(1,k+H[2])),F=H[3]*K[3]/255,l||"accent"!==v.colorMode||"cmyk"===v.style||(F*=k),s.globalAlpha=F;const T=255*(k-y),R="source"===v.colorMode?`rgb(${x+T},${b+T},${w+T})`:"gray"===v.colorMode?`rgb(${Math.round(255*k)},${Math.round(255*k)},${Math.round(255*k)})`:v.ink;if(s.fillStyle=R,l){const t=Math.max(0,Math.min(i.length-1,Math.round(k*(i.length-1))));"accent"===v.colorMode?s.drawImage(f.canvas,t*m,0,m,d,a?Math.round(S+(ut-m)/2):S+(ut-m)/2,a?Math.round(A+(gt-d)/2):A+(gt-d)/2,m,d):s.fillText(i[t],S+ut/2,A+gt/2)}else if("dots"===v.style)s.beginPath(),s.arc(S+ut/2,A+gt/2,.48*ut*Math.sqrt(k),0,2*Math.PI),s.fill();else if("led"===v.style)s.beginPath(),s.arc(S+ut/2,A+gt/2,.39*ut,0,2*Math.PI),s.fill(),s.globalAlpha=.35*F,s.fillStyle="#ffffff",s.beginPath(),s.arc(S+.43*ut,A+.4*gt,.11*ut,0,2*Math.PI),s.fill();else if("hex"===v.style){const t=S+ut/2,e=A+gt/2;s.beginPath();for(let i=0;i<6;i++){const a=Math.PI/3*i,r=t+Math.cos(a)*ut*.49,o=e+Math.sin(a)*gt*.49;0===i?s.moveTo(r,o):s.lineTo(r,o)}s.closePath(),s.fill()}else if("cmyk"===v.style){s.fillStyle="#ffffff",s.fillRect(S,A,ut,gt);const t=(t,e)=>Math.max(0,Math.min(255,"source"===v.colorMode?t+T:"gray"===v.colorMode?255*k:e*k)),e=t(x,r[0]),i=t(b,r[1]),a=t(w,r[2]),o=1-Math.max(e,i,a)/255,n=Math.max(.001,1-o),h=[["#00ffff",(1-e/255-o)/n,.36,.36],["#ff00ff",(1-i/255-o)/n,.64,.36],["#ffff00",(1-a/255-o)/n,.5,.66],["#000000",o,.5,.5]];s.globalCompositeOperation="multiply";for(const[t,e,i,a]of h)s.fillStyle=t,s.beginPath(),s.arc(S+ut*i,A+gt*a,.48*ut*Math.sqrt(Math.max(0,e)),0,2*Math.PI),s.fill();s.globalCompositeOperation="source-over"}else if("voxel"===v.style){const t=S+ut/2,e=A+gt/2;s.beginPath(),s.moveTo(t,A),s.lineTo(S+ut,A+.25*gt),s.lineTo(t,e),s.lineTo(S,A+.25*gt),s.closePath(),s.fill(),s.globalAlpha=.72*F,s.beginPath(),s.moveTo(S,A+.25*gt),s.lineTo(t,e),s.lineTo(t,A+gt),s.lineTo(S,A+.75*gt),s.closePath(),s.fill(),s.globalAlpha=.42*F,s.beginPath(),s.moveTo(t,e),s.lineTo(S+ut,A+.25*gt),s.lineTo(S+ut,A+.75*gt),s.lineTo(t,A+gt),s.closePath(),s.fill()}else{const t="pixel"===v.style?0:Math.max(.5,.06*ut);s.fillRect(S,A,ut-t,gt-t),"lego"===v.style&&s.drawImage(g.canvas,S,A),"disco"===v.style&&(s.fillStyle=`rgba(255,255,255,${.1+.25*z(c,h)})`,s.fillRect(S,A,ut-t,.35*gt),s.fillStyle="rgba(0,0,0,.25)",s.fillRect(S,A+.65*gt,ut-t,.35*gt-t))}}}h.ctx.globalAlpha=1,(v.color.amount||v.lights.length)&&(et(d.canvas,ht,lt),d.ctx.clearRect(0,0,ht,lt),d.ctx.drawImage(h.canvas,0,0)),v.color.amount&&(h.ctx.save(),h.ctx.globalCompositeOperation=v.color.blend,h.ctx.globalAlpha=v.color.amount,h.ctx.fillStyle=v.color.tint,h.ctx.fillRect(0,0,ht,lt),h.ctx.restore());for(const t of v.lights){const e=t.radius*Math.max(ht,lt),i=h.ctx.createRadialGradient(t.x*ht,t.y*lt,0,t.x*ht,t.y*lt,e);i.addColorStop(0,t.color),i.addColorStop(1,"transparent"),h.ctx.save(),h.ctx.globalCompositeOperation="screen",h.ctx.globalAlpha=t.intensity,h.ctx.fillStyle=i,h.ctx.fillRect(0,0,ht,lt),h.ctx.restore()}if((v.color.amount||v.lights.length)&&(h.ctx.globalCompositeOperation="destination-in",h.ctx.drawImage(d.canvas,0,0),h.ctx.globalCompositeOperation="source-over"),v.mask.enabled&&v.mask.shapes.length){const t=c.ctx;t.clearRect(0,0,ht,lt),t.fillStyle="#fff",t.strokeStyle="#fff",t.lineCap="round",t.lineJoin="round";for(const e of v.mask.shapes){if(t.beginPath(),"ellipse"===e.kind)t.ellipse((e.x+e.width/2)*ht,(e.y+e.height/2)*lt,e.width*ht/2,e.height*lt/2,0,0,2*Math.PI);else{if("rectangle"!==e.kind){if(t.lineWidth=(e.size??.05)*ht,1===e.points?.length){t.arc(e.points[0][0]*ht,e.points[0][1]*lt,t.lineWidth/2,0,2*Math.PI),t.fill();continue}e.points?.forEach(([e,i],a)=>a?t.lineTo(e*ht,i*lt):t.moveTo(e*ht,i*lt)),t.stroke();continue}t.rect(e.x*ht,e.y*lt,e.width*ht,e.height*lt)}t.fill()}h.ctx.globalCompositeOperation=v.mask.invert?"destination-out":"destination-in",h.ctx.drawImage(c.canvas,0,0),h.ctx.globalCompositeOperation="source-over"}const M=l.ctx;M.clearRect(0,0,ht,lt),M.globalAlpha=v.backdrop.opacity;const b=v.backdrop;if("solid"===b.mode&&(M.fillStyle=b.color,M.fillRect(0,0,ht,lt)),"gradient"===b.mode){const t=M.createLinearGradient(0,0,ht,lt);t.addColorStop(0,b.color),t.addColorStop(1,b.color2),M.fillStyle=t,M.fillRect(0,0,ht,lt)}if("source"===b.mode&&M.drawImage(s.canvas,0,0),"blurred"===b.mode){const t=Math.max(1,b.blur);et(m.canvas,Math.max(2,Math.round(ht/t)),Math.max(2,Math.round(lt/t))),m.ctx.drawImage(s.canvas,0,0,m.canvas.width,m.canvas.height),M.imageSmoothingEnabled=!0,M.drawImage(m.canvas,0,0,ht,lt)}M.globalAlpha=1,v.effects.characterBloom>0&&(et(u.canvas,Math.max(2,Math.round(ht/3)),Math.max(2,Math.round(lt/3))),u.ctx.clearRect(0,0,u.canvas.width,u.canvas.height),u.ctx.drawImage(h.canvas,0,0,u.canvas.width,u.canvas.height),M.save(),M.globalAlpha=.8*v.effects.characterBloom,M.globalCompositeOperation="screen",M.filter=`blur(${1+4*v.effects.characterBloom}px)`,M.drawImage(u.canvas,0,0,ht,lt),M.restore()),M.drawImage(h.canvas,0,0),S=bt?wt:""}const yt=Object.entries(v.effects).some(([t,e])=>!["angle","focus","blurType","characterBloom"].includes(t)&&"number"==typeof e&&e>0);a.clearRect(0,0,ht,lt),yt?(void 0===M&&(M=function(){const t=document.createElement("canvas"),e=t.getContext("webgl",{alpha:!0,premultipliedAlpha:!1,antialias:!1,preserveDrawingBuffer:!0});if(!e)return null;const i=[],a=(t,a)=>{const s=e.createShader(t);if(i.push(s),e.shaderSource(s,a),e.compileShader(s),!e.getShaderParameter(s,e.COMPILE_STATUS))throw new Error(e.getShaderInfoLog(s)||"Finish shader failed");return s},s=e.createProgram();if(e.attachShader(s,a(e.VERTEX_SHADER,"attribute vec2 p;varying vec2 uv;void main(){uv=(p+1.)*.5;gl_Position=vec4(p,0.,1.);}")),e.attachShader(s,a(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,rgbSplit,sharpen;\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+rgbSplit*8.)/size.x,prism*edge/size.y);\n if(prism>0.||rgbSplit>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;\n if(sharpen>0.){vec2 px=1./size;vec3 near=sampleAt(q+vec2(px.x,0.)).rgb+sampleAt(q-vec2(px.x,0.)).rgb+sampleAt(q+vec2(0.,px.y)).rgb+sampleAt(q-vec2(0.,px.y)).rgb;col+=(base.rgb*4.-near)*sharpen*.5;}\ncol*=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(s),!e.getProgramParameter(s,e.LINK_STATUS))throw new Error("Finish link failed");e.useProgram(s);const r=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,r),e.bufferData(e.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,1]),e.STATIC_DRAW);const o=e.getAttribLocation(s,"p");e.enableVertexAttribArray(o),e.vertexAttribPointer(o,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","rgbSplit","sharpen","vignette","glitch","pixelate","blur","blurMode","angle","focus","halftone"],l=Object.fromEntries(h.map(t=>[t,e.getUniformLocation(s,t)])),c=e.getUniformLocation(s,"size");return{canvas:t,render(i,a,r,o=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(s),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/o,t.height/o);for(const t of h)e.uniform1f(l[t],"t"===t?r:"blurMode"===t?["gaussian","directional","radial","progressive"].indexOf(a.blurType):"angle"===t?a.angle*Math.PI/180:a[t]??0);return e.drawArrays(e.TRIANGLE_STRIP,0,4),t},destroy(){e.deleteTexture(n),e.deleteBuffer(r),e.deleteProgram(s),i.forEach(t=>e.deleteShader(t)),t.width=t.height=1,e.getExtension("WEBGL_lose_context")?.loseContext()}}}()),M?a.drawImage(M.render(l.canvas,v.effects,i,ot),0,0):a.drawImage(l.canvas,0,0),t.dataset.studioFinish=M?"gpu":"unavailable"):(a.drawImage(l.canvas,0,0),t.dataset.studioFinish="none")},setPixelRatio(t){ot=Math.max(.1,Math.min(8,Number.isFinite(t)?t:1))},get pixelRatio(){return ot},setBudget(t){rt=Math.max(256,Math.min(st,Number.isFinite(t)?Math.round(t):st))},get maxCells(){return rt},configure(t){v=y(t),Q=L(v.color),Z.configure(v.color.denoise),b++},pointer:(t,e,i)=>{Y.configure(v.hover.effect,v.hover.strength,v.hover.radius,v.hover.edgeSafe),Y.move(t,e,i)},leave(){Y.leave()},get active(){return Y.active},get settings(){return y(v)},get capabilities(){return{gpuFinish:null!==M}},invalidate(){w=""},destroy(){M?.destroy();for(const t of[s,r,h,l,c,m,f,d,u,g])t.canvas.width=t.canvas.height=1;N=null,E=new Uint8ClampedArray(0)}}}function st(t,e,i){return new Promise((a,s)=>{const r=()=>{l(),a()},o=()=>{l(),s(new Error("Unable to load this media. Check its format and cross-origin permissions."))},n=()=>{l(),s(new DOMException("Cancelled","AbortError"))},h=setTimeout(o,2e4),l=()=>{clearTimeout(h),t.removeEventListener(e,r),t.removeEventListener("error",o),i?.removeEventListener("abort",n)};t.addEventListener(e,r,{once:!0}),t.addEventListener("error",o,{once:!0}),i?.addEventListener("abort",n,{once:!0}),i?.aborted&&n()})}async function rt(t,e){if("string"==typeof t&&t.startsWith("blob:")){const i=await fetch(t,{signal:e}),a=await i.blob();return rt(new File([a],"Imported media",{type:a.type}),e)}const i="string"!=typeof t,a=i?t.name:t;if(i?"image/gif"===t.type:/\.gif(?:[?#]|$)/i.test(a)){const a=await import("gifuct-js"),{parseGIF:s,decompressFrames:r}="function"==typeof a.parseGIF?a:a.default,o=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=s(o),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 m=r(n,!0);if(m.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 d=f.getContext("2d"),u=document.createElement("canvas"),g=u.getContext("2d"),p=m.reduce((t,e)=>t+Math.max(20,e.delay),0)/1e3;let M=-1,x=null;const v=t=>{const e=(t%p+p)%p*1e3;let i=0,a=0;for(;a<m.length-1&&(i+=Math.max(20,m[a].delay),!(e<i));a++);a<M&&(d.clearRect(0,0,h,l),M=-1,x=null);for(let t=M+1;t<=a;t++){const e=m[t-1];2===e?.disposalType&&d.clearRect(e.dims.left,e.dims.top,e.dims.width,e.dims.height),3===e?.disposalType&&x&&d.putImageData(x,0,0);const i=m[t];x=3===i.disposalType?d.getImageData(0,0,h,l):null,u.width=i.dims.width,u.height=i.dims.height,g.putImageData(new ImageData(new Uint8ClampedArray(i.patch),u.width,u.height),0,0),d.drawImage(u,i.dims.left,i.dims.top)}return M=a,f};return v(0),{source:f,width:h,height:l,duration:p,animated:!0,seek:async()=>{},frame:v,destroy(){f.width=u.width=1,m.length=0,x=null}}}const s=i?t.type.startsWith("video/"):/\.(mp4|webm|mov)(?:[?#]|$)/i.test(a),r=i?URL.createObjectURL(t):t,o=s?document.createElement("video"):new Image;o.crossOrigin="anonymous",o instanceof HTMLVideoElement&&(o.muted=!0,o.playsInline=!0,o.preload="auto");const n=()=>{o instanceof HTMLVideoElement?(o.pause(),o.removeAttribute("src"),o.load()):o.src="",i&&URL.revokeObjectURL(r)};try{const t=st(o,s?"loadeddata":"load",e);o.src=r,await t;const i=o instanceof HTMLVideoElement?o.videoWidth:o.naturalWidth,a=o instanceof HTMLVideoElement?o.videoHeight:o.naturalHeight;return{source:o,width:i,height:a,duration:o instanceof HTMLVideoElement?o.duration:0,animated:s,async seek(t,e){if(!(o instanceof HTMLVideoElement))return;if(!Number.isFinite(o.duration)||o.duration<=0)throw new Error("Video duration is unavailable.");const i=Math.max(0,Math.min(o.duration-.001,t%o.duration));if(Math.abs(o.currentTime-i)<.001&&o.readyState>=2)return;const a=st(o,"seeked",e);o.currentTime=i,await a},frame:()=>o,destroy:n}}catch(t){throw n(),t}}var ot=t=>{if(t?.aborted)throw new DOMException("Export cancelled","AbortError")};async function nt(t,e,i){const{format:a,signal:s}=i,r=Math.round(i.width),o=Math.round(i.height);if(!Number.isFinite(r)||!Number.isFinite(o)||r<2||o<2||r>4096||o>4096||r*o>16777216)throw new Error("Choose export dimensions between 2 and 4096 pixels.");if(!["png","jpeg","mp4","webm","gif"].includes(a))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 l="png"===a||"jpeg"===a,c=i.time??0;if(!Number.isFinite(c)||c<0)throw new Error("Image time must be a finite non-negative number.");if(void 0!==i.motionTime&&(!Number.isFinite(i.motionTime)||i.motionTime<0))throw new Error("Motion time must be a finite non-negative number.");if(!l&&r*o>8294400)throw new Error("Video exports support up to 3840 × 2160 pixels.");if("gif"===a&&(r*o>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"===a&&n>30)throw new Error("GIF exports support up to 30 fps. Choose MP4 or WebM for higher frame rates.");const m=document.createElement("canvas"),f=at(m,y(e),{maxDimension:4096,maxCells:i.maxCells??12e3,pixelRatio:r/(i.referenceWidth??Math.min(r,960))});let d;try{if(ot(s),i.onProgress?.(0),l){if(f.render(await t.frame(c,s),c,r,o,i.motionTime),"unavailable"===m.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");ot(s);const e=await new Promise((t,e)=>m.toBlob(i=>i?t(i):e(new Error("Image export failed.")),"png"===a?"image/png":"image/jpeg",i.quality??.92));return i.onProgress?.(1),e}const e=Math.ceil(h*n);if("gif"===a){const a=await import("gifenc"),{GIFEncoder:l,quantize:c,applyPalette:d}="function"==typeof a.GIFEncoder?a:a.default,u=l(),g=m.getContext("2d");for(let a=0;a<e;a++){ot(s);const l=a/n;if(f.invalidate(),f.render(await t.frame(l,s),l,r,o),"unavailable"===m.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");const p=g.getImageData(0,0,r,o).data,M=c(p,256),x=d(p,M);u.writeFrame(x,r,o,{palette:M,delay:10*(Math.round(100*Math.min((a+1)/n,h))-Math.round(100*a/n)),repeat:0}),i.onProgress?.((a+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:u,Mp4OutputFormat:g,WebMOutputFormat:p,BufferTarget:M,CanvasSource:x,canEncodeVideo:v}=await import("mediabunny"),b="mp4"===a?"avc":"vp9";if(!await v(b,{width:r,height:o}))throw new Error(`${a.toUpperCase()} encoding is unavailable in this browser. Try another format or a current browser with WebCodecs.`);const w=new u({format:"mp4"===a?new g({fastStart:"in-memory"}):new p,target:new M});m.width=r,m.height=o,d=()=>w.cancel();const y=new x(m,{codec:b,bitrate:Math.max(5e5,Math.round(r*o*n*.15))});w.addVideoTrack(y,{frameRate:n}),m.width=r,m.height=o,await w.start();for(let a=0;a<e;a++){ot(s);const l=a/n;if(f.invalidate(),f.render(await t.frame(l,s),l,r,o),"unavailable"===m.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");await y.add(l,Math.min(1/n,h-l)),i.onProgress?.((a+1)/e*.98),a%4==0&&await new Promise(t=>setTimeout(t,0))}return y.close(),ot(s),await w.finalize(),d=void 0,i.onProgress?.(1),new Blob([w.target.buffer],{type:"mp4"===a?"video/mp4":"video/webm"})}catch(t){throw await(d?.().catch(()=>{})),t}finally{f.destroy(),m.width=m.height=1}}async function ht(t,e,i={}){const a=await rt(e,i.signal);try{return lt(t,a,i)}catch(t){throw a.destroy(),t}}function lt(t,e,i={}){let a=y(i.settings),s=i.width??e.width,o=i.height??e.height;const n=at(t,a,i),h=new r;let l=0,c=!1,m=!0,f=!1,d=!0,u=0,g=0,p=0,M=0,x=-1,v=!1!==i.adaptive,b=0,w=0,k=0;const S=matchMedia("(prefers-reduced-motion: reduce)"),A=e.source instanceof HTMLVideoElement?e.source:null,T=()=>{c||l||!d||document.hidden||(l=requestAnimationFrame(R))},P=()=>!f&&!S.matches&&d&&!document.hidden,I=()=>{A&&(A.loop=!0,P()?A.play().catch(()=>{f=!0,m=!0,T()}):A.pause()),p=0,m=!0,T()};function R(t){if(l=0,c||!d||document.hidden)return;const r=P();r&&(u+=p?Math.min(.1,(t-p)/1e3):0),p=t;const y=function(t){return U(t)||D(t)||t.effects.grain>0||t.effects.dust>0||t.effects.glitch>0}(a),S=r&&(e.animated||y),F=A?.getVideoPlaybackQuality?.().totalVideoFrames??-1,I=!A||F<0||F!==x;if(m||n.active||S&&(I||y)&&t-M>=1e3/Math.max(1,Math.min(60,i.fps??60))-.5){const r=performance.now();try{e.animated&&!A&&n.invalidate();const[t,l]=E(s,o,a);g=h.update(u,a.motion.type,a.motion.speed),n.render(e.frame(A?.currentTime??u),u,t,l,g);const c=performance.now()-r;i.onFrame?.(A?.currentTime??u,c),w=w?.9*w+.1*c:c,++b>20&&v&&(S||n.active)&&(k=w>13?k+1:0,k>=12&&n.maxCells>3e3&&(n.setBudget(Math.max(3e3,.8*n.maxCells)),i.onQualityChange?.(n.maxCells),k=0,w=0))}catch(t){f=!0,i.onError?.(t instanceof Error?t:new Error(String(t)))}m=!1,M=t,x=F}r&&(S||n.active)&&T()}const C=e=>{if(!P())return;const i=t.getBoundingClientRect();n.pointer((e.clientX-i.left)/i.width,(e.clientY-i.top)/i.height,e.timeStamp),T()},L=()=>{n.leave(),T()},X=new IntersectionObserver(([t])=>{d=t.isIntersecting,I()});X.observe(t),t.addEventListener("pointermove",C),t.addEventListener("pointerleave",L),t.addEventListener("pointercancel",L),document.addEventListener("visibilitychange",I),S.addEventListener("change",I);const N=()=>{c||(c=!0,cancelAnimationFrame(l),X.disconnect(),t.removeEventListener("pointermove",C),t.removeEventListener("pointerleave",L),t.removeEventListener("pointercancel",L),document.removeEventListener("visibilitychange",I),S.removeEventListener("change",I),i.signal?.removeEventListener("abort",N),n.destroy(),e.destroy())};if(i.signal?.addEventListener("abort",N,{once:!0}),i.signal?.aborted)throw N(),new DOMException("Cancelled","AbortError");return I(),{canvas:t,media:e,update(t){a=F(a,t),n.configure(a),m=!0,T()},resize(t,e,i){void 0!==i&&n.setPixelRatio(i),s=Math.max(2,t),o=Math.max(2,e),m=!0,T()},pause(t=!0){f=t,I()},async seek(t){u=Math.max(0,t),await e.seek(u),n.invalidate(),m=!0,T()},redraw(){n.invalidate(),m=!0,T()},get time(){return A?.currentTime??u},get settings(){return y(a)},get motionTime(){return g},get paused(){return f||S.matches},setAdaptive(t){v=t,b=k=w=0},setBudget(t){n.setBudget(t),i.onQualityChange?.(n.maxCells),m=!0,T()},get pixelRatio(){return n.pixelRatio},get maxCells(){return n.maxCells},get capabilities(){return n.capabilities},destroy:N}}var ct={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")},mt=Object.keys(ct);async function ft(t,e="Standard",i="#ffffff"){if(!Object.prototype.hasOwnProperty.call(ct,e))throw new Error("Unknown text font.");const{default:a}=await import("figlet/browser"),s=await ct[e]();a.parseFont(e,s.default),a.defaults({fetchFontIfMissing:!1});const r=a.textSync(t.slice(0,120),{font:e}),o=r.split("\n"),n=Math.max(1,...o.map(t=>t.length)),h=Math.max(1,o.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 m=c.getContext("2d");return m.fillStyle="#080808",m.fillRect(0,0,c.width,c.height),m.fillStyle=i,m.font=15*l+"px monospace",m.textBaseline="top",o.forEach((t,e)=>m.fillText(t,16,16+15*e*l)),{canvas:c,ascii:r}}var dt={standard:{label:"Classic ASCII",chars:" .:-=+*#%@"},asciify:{label:"Asciify",chars:" .:-=+ASCIIFY#@"},minimal:{label:"Minimal",chars:" .:+"},detailed:{label:"Detailed",chars:" .,:;i1tfLCG08@"},letters:{label:"Letters",chars:" .ilLCFTYASMW"},technical:{label:"Technical",chars:" .:;>_/[{}]=+*#@$"},blocks:{label:"Tonal blocks",chars:" ░▒▓█"},braille:{label:"Braille",chars:" ⠁⠃⠇⡇⣇⣧⣷⣿"}},ut=dt;export{g as BLEND_MODES,dt as CHARACTER_SETS,M as DEFAULT_STUDIO_SETTINGS,u as DITHER_ALGORITHMS,ut as STUDIO_CHARACTER_SETS,h as STUDIO_CURVE_CHANNELS,t as STUDIO_HOVERS,P as STUDIO_LOOKS,e as STUDIO_MOTIONS,p as STUDIO_PALETTES,d as STUDIO_STYLES,mt as STUDIO_TEXT_FONTS,f as createStudioCurveLookup,at as createStudioRenderer,ft as createStudioText,nt as exportStudio,rt as loadStudioMedia,ht as mountStudio,lt as mountStudioMedia,c as normalizeStudioCurve,m as normalizeStudioCurves,y as normalizeStudioSettings,S as parseStudioSettings,R as restyleStudio,k as serializeStudioSettings,A as studioCrop,E as studioDimensions,T as studioGrid,I as studioLook,$ as studioSourceSize,F as updateStudioSettings};//# sourceMappingURL=studio.js.map
1
+ var t=[{value:"none",label:"Off",group:"Still",description:"Keep the artwork still under the pointer."},{value:"trail",label:"Trail",group:"Change characters",description:"A fluid wake changes character density and settles behind your cursor."},{value:"dissolve",label:"Dissolve",group:"Change characters",description:"Erase a soft path through the characters; the image gradually reforms."},{value:"contour",label:"Contour",group:"Change characters",description:"Fine tonal rings trace your path without moving the grid."},{value:"etch",label:"Emboss",group:"Change characters",description:"Press a light-and-shadow impression into the characters; the grid stays fixed."},{value:"water",label:"Water",group:"Move the image",description:"Soft ripples refract the image and settle after your stroke."},{value:"silk",label:"Silk",group:"Move the image",description:"Directional folds follow the movement of your hand."},{value:"vortex",label:"Vortex",group:"Move the image",description:"A swirling wake curls through the image."},{value:"magnetic",label:"Magnetic Pull",group:"Move the image",description:"The image gathers toward your stroke, then relaxes."},{value:"scatter",label:"Scatter",group:"Move the image",description:"A textured outward scatter settles behind your cursor."},{value:"elastic",label:"Elastic",group:"Move the image",description:"Push the image with your stroke; it recoils and springs back into place."},{value:"rake",label:"Rake",group:"Move the image",description:"Comb the image into alternating ribbons that glide back into alignment."}],e=[{value:"none",mode:"none",group:"Still",label:"Off",description:"Keep the image still. Hover stays available."},{value:"caustics",mode:"caustics",group:"Light and texture",label:"Caustics",description:"Soft ribbons of light travel across a stationary character grid."},{value:"current",mode:"current",group:"Flow and depth",label:"Slow Current",description:"A gentle flow through the image, with steady edges."},{value:"reform",mode:"reform",group:"Rebuild",label:"Reveal & Reform",description:"Disperse, gather, then hold the complete image."},{value:"sheen",mode:"sheen",group:"Light and texture",label:"Sheen",description:"A broad diagonal light sweep; characters stay anchored."},{value:"tidal",mode:"tidal",group:"Flow and depth",label:"Tidal Rings",description:"Concentric currents travel outward, with protected edges."},{value:"grain",mode:"grain",group:"Light and texture",label:"Living Grain",description:"Slow, individually phased tonal changes on a stationary grid."},{value:"parallax",mode:"parallax",group:"Flow and depth",label:"Parallax",description:"A shallow, continuous drift through the image, with the edges held in place."},{value:"weave",mode:"weave",group:"Flow and depth",label:"Woven Flow",description:"Interlaced bands move in opposing directions, like a flexible printed fabric."},{value:"print",mode:"print",group:"Rebuild",label:"Print Shift",description:"Staggered rows lift, soften and register back into the image."},{value:"trace",mode:"trace",group:"Light and texture",label:"Contour Light",description:"Light follows the source image’s tonal contours; every character stays anchored."}],i=t=>Math.max(0,Math.min(1,t)),a=(t,e,a)=>{const s=i((a-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)},r=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 n(t,e,r,n,o,h=.5){if(o[0]=o[1]=o[2]=0,o[3]=1,"none"===t)return o;const l=n*Math.PI/6,c=a(0,.12,Math.min(e,1-e,r,1-r));if("caustics"===t){const t=Math.sin(9*e+5*r+l)+Math.sin(8*r-3*e-l),i=Math.pow(Math.max(0,1-.72*Math.abs(t)),3);o[2]=(.22*i-.045)*c}else if("current"===t)o[0]=Math.sin(9*r+l)*Math.cos(7*e-l)*10*c,o[1]=Math.cos(8*e+l)*Math.sin(6*r-l)*7*c;else if("sheen"===t)o[2]=.2*Math.pow(.5+.5*Math.cos(5*e+3*r-l),8)-.025;else if("tidal"===t){const t=e-.5,i=r-.5,a=Math.hypot(t,i),s=Math.sin(22*a-l)*c;o[0]=t*s*9,o[1]=i*s*9,o[2]=.035*s}else if("grain"===t){const t=s(Math.floor(160*e),Math.floor(100*r))*Math.PI*2;o[2]=.07*Math.sin(l+t)}else if("parallax"===t){const t=.45+.55*Math.max(0,1-1.4*Math.hypot(e-.5,r-.5));o[0]=12*Math.sin(l)*t*c,o[1]=6*(Math.cos(l)-1)*t*c}else if("weave"===t)o[0]=Math.sin(r*Math.PI*6+l)*Math.sin(l)*8*c,o[1]=Math.sin(e*Math.PI*6-l)*Math.sin(l)*6*c;else if("print"===t){const t=Math.floor(24*r),e=((n+3*s(t,3))%12+12)%12,i=a(1,2.5,e)*(1-a(3.5,5,e));o[0]=Math.sin(2.4*t)*i*9*c,o[1]=5*-i*c,o[2]=.22*-i,o[3]=1-.45*i}else if("trace"===t){const t=.5+.5*Math.cos(l);o[2]=.22*Math.pow(Math.max(0,1-Math.abs(i(h)-t)/.16),3)-.015}else if("reform"===t){const t=(n%12+12)%12,i=s(Math.floor(160*e),Math.floor(100*r)),h=.65*e+.2*r+.15*i+.08*Math.sin(8*e-5*r),d=a(1.8+1.2*h,3.8+1.2*h,t)*(1-a(5+1.7*h,7.2+1.7*h,t));o[0]=Math.sin(9*r+l)*d*(1-d)*24*c,o[1]=-d*(1-d)*(8+12*i)*c,o[2]=.45*-d,o[3]=1-.9*d}return o}function o(t,e){const a=Math.max(0,Math.min(2,Number.isFinite(e)?e:1));return t[0]*=a,t[1]*=a,t[2]*=a,t[3]=i(1+(t[3]-1)*a),t}var h=["rgb","red","green","blue"],l=t=>Math.max(0,Math.min(1,t));function c(t){const e=new Map([[0,0],[1,1]]);if(Array.isArray(t))for(const i of t.slice(0,64)){if(!Array.isArray(i)||i.length<2||"number"!=typeof i[0]||!Number.isFinite(i[0])||"number"!=typeof i[1]||!Number.isFinite(i[1]))continue;const t=Math.round(255*l(i[0]))/255;!e.has(t)&&e.size>=16||e.set(t,l(i[1]))}return[...e].sort((t,e)=>t[0]-e[0])}function d(t){const e=t&&"object"==typeof t?t:{};return Object.fromEntries(h.map(t=>[t,c(e[t])]))}function m(t){const e=c(t),i=e.length,a=e.slice(1).map((t,i)=>t[0]-e[i][0]),s=e.slice(1).map((t,i)=>(t[1]-e[i][1])/a[i]),r=new Float64Array(i);r[0]=s[0],r[i-1]=s[i-2];for(let t=1;t<i-1;t++){const e=s[t-1],i=s[t];if(e*i<=0)continue;const n=2*a[t]+a[t-1],o=a[t]+2*a[t-1];r[t]=(n+o)/(n/e+o/i)}const n=new Uint8Array(256);let o=0;for(let t=0;t<256;t++){const s=t/255;for(;o<i-2&&s>e[o+1][0];)o++;const h=a[o],c=(s-e[o][0])/h,d=c*c,m=d*c,f=(2*m-3*d+1)*e[o][1]+(m-2*d+c)*h*r[o]+(-2*m+3*d)*e[o+1][1]+(m-d)*h*r[o+1];n[t]=Math.round(255*l(f))}return n}function f(t,e,i,a,s,r){a=Math.max(0,Math.min(e-1,a)),s=Math.max(0,Math.min(i-1,s));const n=Math.floor(a),o=Math.floor(s),h=a-n,l=s-o,c=4*(o*e+n);if(0===h&&0===l){for(let e=0;e<4;e++)r[e]=t[c+e];return}const d=4*(o*e+Math.min(e-1,n+1)),m=4*(Math.min(i-1,o+1)*e+n),f=4*(Math.min(i-1,o+1)*e+Math.min(e-1,n+1)),u=(1-h)*(1-l)*t[c+3],g=h*(1-l)*t[d+3],p=(1-h)*l*t[m+3],M=h*l*t[f+3],w=u+g+p+M;for(let e=0;e<3;e++)r[e]=w?(t[c+e]*u+t[d+e]*g+t[m+e]*p+t[f+e]*M)/w:0;r[3]=w}function u(t,e,i,a,s,r){if(a>=0&&a<=e-1&&s>=0&&s<=i-1)return f(t,e,i,a,s,r);if(r[0]=r[1]=r[2]=r[3]=0,a<=-1||a>=e||s<=-1||s>=i)return;const n=Math.floor(a),o=Math.floor(s),h=a-n,l=s-o;for(let a=0;a<=1;a++)for(let s=0;s<=1;s++){const c=n+s,d=o+a;if(c<0||c>=e||d<0||d>=i)continue;const m=4*(d*e+c),f=(s?h:1-h)*(a?l:1-l)*t[m+3];r[0]+=t[m]*f,r[1]+=t[m+1]*f,r[2]+=t[m+2]*f,r[3]+=f}r[3]&&(r[0]/=r[3],r[1]/=r[3],r[2]/=r[3])}var g=[{value:"twirl",label:"Twirl",description:"Rotate the center into a smooth spiral; the outer boundary stays fixed.",direction:!1,frequency:!1},{value:"pinch",label:"Pinch",description:"Contract the center, or expand it with negative strength.",direction:!1,frequency:!1},{value:"sphere",label:"Spherize",description:"Magnify a rounded lens through the source; negative strength recedes.",direction:!1,frequency:!1},{value:"ripple",label:"Ripple",description:"Bend the image through concentric, soft-edged waves.",direction:!1,frequency:!0},{value:"zigzag",label:"Zigzag",description:"Alternate the twist in sharp, concentric bands.",direction:!1,frequency:!0},{value:"shear",label:"Shear",description:"Slant a region along an adjustable direction.",direction:!0,frequency:!1},{value:"smudge",label:"Smudge",description:"Draw a soft region of the source along one direction.",direction:!0,frequency:!1},{value:"polar",label:"Polar",description:"Unwrap a region into polar coordinates; negative strength wraps it.",direction:!0,frequency:!1},{value:"fragment",label:"Fragment",description:"Offset small source tiles into a stable fractured texture.",direction:!0,frequency:!0}],p=8,M=(t,e,i,a)=>"number"==typeof t&&Number.isFinite(t)?Math.max(i,Math.min(a,t)):e;function w(t){if(!Array.isArray(t))return[];const e=[];for(const i of t.slice(0,64))if(i&&"object"==typeof i&&g.some(t=>t.value===i.type)&&(e.push({type:i.type,enabled:!1!==i.enabled,amount:M(i.amount,.35,-1,1),x:M(i.x,.5,0,1),y:M(i.y,.5,0,1),radius:M(i.radius,.55,.05,2),angle:M(i.angle,0,-180,180),frequency:M(i.frequency,5,1,24)}),8===e.length))break;return e}var v=2*Math.PI,b=(t,e)=>{let i=Math.imul(t,374761393)^Math.imul(e,668265263);return i=Math.imul(i^i>>>13,1274126177),((i^i>>>16)>>>0)/4294967296},y=class{constructor(t=[],e="clamp"){this.warps=[],this.signature="",this.geometry="",this.coordinates=new Float32Array(0),this.output=new Uint8ClampedArray(0),this.sampled=[0,0,0,0],this.edge="clamp",this.configure(t,e)}configure(t=[],e="clamp"){const i=w(t).filter(t=>t.enabled&&0!==t.amount),a=JSON.stringify(i);this.edge="transparent"===e?"transparent":"clamp",a!==this.signature&&(this.signature=a,this.geometry="",this.warps=i.map(t=>({...t,cos:Math.cos(t.angle*Math.PI/180),sin:Math.sin(t.angle*Math.PI/180)})),i.length||this.clear())}get active(){return this.warps.length>0}apply(t,e,i,a=e/i){if(!this.active)return t;if(!Number.isInteger(e)||!Number.isInteger(i)||e<1||i<1||e*i*4!==t.length||!Number.isFinite(a)||a<=0)throw new Error("Warp dimensions do not match the source.");const s=`${e}:${i}:${a}`;if(s!==this.geometry){this.coordinates.length!==e*i*2&&(this.coordinates=new Float32Array(e*i*2));const t=Math.max(1,a),r=Math.max(1,1/a);for(let a=0;a<i;a++)for(let s=0;s<e;s++){let n=(s+.5)/e,o=(a+.5)/i;for(let e=this.warps.length-1;e>=0;e--){const i=this.warps[e],a=(n-i.x)*t/i.radius,s=(o-i.y)*r/i.radius,h=a*a+s*s;if(h>=1)continue;const l=Math.sqrt(h),c=(1-h)*(1-h),d=i.amount;let m=a,f=s;if("twirl"===i.type||"zigzag"===i.type){const t="twirl"===i.type?-d*v*c:.65*d*(2/Math.PI*Math.asin(Math.sin(l*v*i.frequency)))*c,e=Math.cos(t),r=Math.sin(t);m=a*e-s*r,f=a*r+s*e}else if("pinch"===i.type){const t=Math.exp(2*d*c);m=a*t,f=s*t}else if("sphere"===i.type&&l>0){const t=1+d*c*(2*Math.asin(l)/Math.PI/l-1);m=a*t,f=s*t}else if("ripple"===i.type&&l>0){const t=1+.12*d*Math.sin(l*v*i.frequency)*c/l;m=a*t,f=s*t}else if("shear"===i.type){const t=-a*i.sin+s*i.cos;m-=d*t*.9*c*i.cos,f-=d*t*.9*c*i.sin}else if("smudge"===i.type)m-=.65*d*c*i.cos,f-=.65*d*c*i.sin;else if("polar"===i.type){const t=a*i.cos+s*i.sin,e=-a*i.sin+s*i.cos,r=Math.atan2(e,t),n=d>0?r/Math.PI:Math.cos(t*Math.PI)*(e+1)/2,o=d>0?2*l-1:Math.sin(t*Math.PI)*(e+1)/2,h=n*i.cos-o*i.sin,u=n*i.sin+o*i.cos;m+=(h-a)*Math.abs(d)*c,f+=(u-s)*Math.abs(d)*c}else if("fragment"===i.type){const t=Math.floor((a*i.cos+s*i.sin)*i.frequency),e=Math.floor((-a*i.sin+s*i.cos)*i.frequency),r=(b(t,e)-.5)*d*.5*c,n=(b(e+71,t-31)-.5)*d*.5*c;m+=r*i.cos-n*i.sin,f+=r*i.sin+n*i.cos}n=i.x+m*i.radius/t,o=i.y+f*i.radius/r}const h=2*(a*e+s);this.coordinates[h]=n*e-.5,this.coordinates[h+1]=o*i-.5}this.geometry=s}this.output.length!==t.length&&(this.output=new Uint8ClampedArray(t.length));const r=t===this.output?t.slice():t,n="transparent"===this.edge?u:f;for(let a=0,s=0;a<t.length;a+=4,s+=2){n(r,e,i,this.coordinates[s],this.coordinates[s+1],this.sampled);for(let t=0;t<4;t++)this.output[a+t]=this.sampled[t]}return this.output}clear(){this.coordinates=new Float32Array(0),this.output=new Uint8ClampedArray(0),this.geometry=""}},x=["ascii","blocks","braille","dots","lines","cross","diagonal","diamond","mixed","pixel","mosaic","lego","voxel","disco","dither","hex","led","cmyk"],E=["none","bayer2","bayer4","bayer8","bayer16","floyd-steinberg","atkinson","stucki","sierra","sierra-lite","burkes","jarvis","halftone","lines","noise","vertical-lines","diagonal-lines","radial","blue-noise"],k=["source-over","multiply","screen","overlay","soft-light","hard-light","color-dodge","color-burn","hue","saturation","color","luminosity"],A={original:[],gray4:["#000000","#555555","#aaaaaa","#ffffff"],gray8:["#000000","#242424","#494949","#6d6d6d","#929292","#b6b6b6","#dbdbdb","#ffffff"],rgb8:["#000000","#ff0000","#00ff00","#0000ff","#ffff00","#ff00ff","#00ffff","#ffffff"],cyberpunk:["#08081a","#3c1670","#ed299a","#29dfef","#fff7bf"],pastel:["#393448","#a5b4d4","#9ed9c6","#e7aac1","#f5e8be"],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"]},S={version:1,aspectRatio:"original",style:"ascii",cellSize:6,charset:" .:-=+*#%@",colorMode:"accent",ink:"#e8b900",crop:{x:.5,y:.5,zoom:1,rotation:0},warps:[],warpEdge:"clamp",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",blackPoint:0,whitePoint:1,gamma:1,shadows:0,highlights:0,curves:{rgb:[[0,0],[1,1]],red:[[0,0],[1,1]],green:[[0,0],[1,1]],blue:[[0,0],[1,1]]},denoise:0},dither:{algorithm:"none",palette:"mono",colors:["#080808","#e8b900"],amount:1,scale:2,threshold:.5,motion:"none",speed:1,direction:45,colorSpace:"rgb"},mask:{enabled:!1,invert:!1,shapes:[]},lights:[],effects:{bloom:0,characterBloom:0,grain:0,dust:0,scanlines:0,crt:0,prism:0,rgbSplit:0,sharpen:0,vignette:0,glitch:0,pixelate:0,blur:0,blurType:"gaussian",angle:0,focus:.5,halftone:0},motion:{type:"none",speed:1,amount:1},hover:{effect:"trail",strength:.55,radius:.2,edgeSafe:!1}},F=t=>t&&"object"==typeof t&&!Array.isArray(t)?t:{},P=(t,e,i,a)=>"number"==typeof t&&Number.isFinite(t)?Math.min(a,Math.max(i,t)):e,T=(t,e)=>"string"==typeof t&&/^#[\da-f]{6}$/i.test(t)?t:e,C=(t,e,i)=>e.includes(t)?t:i;function I(i={}){const a=F(i),s=S;if(void 0!==a.version&&1!==a.version)throw new Error("Unsupported studio settings version. Update asciify-engine.");const r=F(a.crop),n=F(a.backdrop),o=F(a.color),h=F(a.dither),l=F(a.mask),c=F(a.effects),m=F(a.motion),f=F(a.hover),u={...s.effects};for(const t of["bloom","characterBloom","grain","dust","scanlines","crt","prism","rgbSplit","sharpen","vignette","glitch","pixelate","halftone"])u[t]=P(c[t],0,0,1);u.blur=P(c.blur,0,0,24),u.blurType=C(c.blurType,["gaussian","directional","radial","progressive"],s.effects.blurType),u.angle=P(c.angle,0,-180,180),u.focus=P(c.focus,.5,0,1);let g=2048;return{version:1,aspectRatio:C(a.aspectRatio,["original","16:9","9:16","1:1","4:3","3:4","21:9"],"original"),style:C(a.style,x,s.style),cellSize:P(a.cellSize,s.cellSize,["pixel","mosaic","lego","voxel","disco","dots","hex","led","cmyk"].includes(String(a.style))?1:3,60),charset:"string"==typeof a.charset&&a.charset.length?Array.from(a.charset).slice(0,128).join(""):s.charset,colorMode:C(a.colorMode,["accent","source","gray"],s.colorMode),ink:T(a.ink,s.ink),warps:w(a.warps),warpEdge:C(a.warpEdge,["clamp","transparent"],"clamp"),crop:{x:P(r.x,.5,0,1),y:P(r.y,.5,0,1),zoom:P(r.zoom,1,1,5),rotation:90*Math.round(P(r.rotation,0,-360,360)/90)},backdrop:{mode:C(n.mode,["solid","transparent","source","blurred","gradient"],s.backdrop.mode),color:T(n.color,s.backdrop.color),color2:T(n.color2,s.backdrop.color2),blur:P(n.blur,12,0,32),opacity:P(n.opacity,1,0,1)},color:{brightness:P(o.brightness,0,-1,1),contrast:P(o.contrast,1,0,3),saturation:P(o.saturation,1,0,3),grayscale:P(o.grayscale,0,0,1),tint:T(o.tint,s.color.tint),amount:P(o.amount,0,0,1),blend:C(o.blend,k,s.color.blend),blackPoint:P(o.blackPoint,0,0,.99),whitePoint:Math.max(P(o.blackPoint,0,0,.99)+1/255,P(o.whitePoint,1,1/255,1)),gamma:P(o.gamma,1,.25,4),shadows:P(o.shadows,0,-1,1),highlights:P(o.highlights,0,-1,1),curves:d(o.curves),denoise:P(o.denoise,0,0,1)},dither:{algorithm:C(h.algorithm,E,"none"),palette:"string"==typeof h.palette&&Object.prototype.hasOwnProperty.call(A,h.palette)?h.palette:"mono",colors:Array.isArray(h.colors)&&h.colors.length>=2?h.colors.slice(0,32).map(t=>T(t,"#000000")):[...s.dither.colors],amount:P(h.amount,1,0,2),scale:Math.round(P(h.scale,2,1,12)),threshold:P(h.threshold,.5,0,1),motion:C(h.motion,["none","drift","shimmer"],"none"),speed:P(h.speed,1,.1,3),direction:P(h.direction,45,-180,180),colorSpace:C(h.colorSpace,["rgb","luminance"],"rgb")},mask:{enabled:!0===l.enabled,invert:!0===l.invert,shapes:Array.isArray(l.shapes)?l.shapes.slice(0,64).map(t=>{const e=F(t),i=C(e.kind,["rectangle","ellipse","brush"],"rectangle"),a="brush"===i&&Array.isArray(e.points)?e.points.slice(0,g).map(t=>Array.isArray(t)?[Math.round(1e4*P(t[0],0,0,1))/1e4,Math.round(1e4*P(t[1],0,0,1))/1e4]:[0,0]):[];return g-=a.length,{kind:i,x:P(e.x,0,0,1),y:P(e.y,0,0,1),width:P(e.width,.5,0,1),height:P(e.height,.5,0,1),size:P(e.size,.05,.005,.5),points:a}}):[]},lights:Array.isArray(a.lights)?a.lights.slice(0,4).map(t=>{const e=F(t);return{x:P(e.x,.5,0,1),y:P(e.y,.5,0,1),radius:P(e.radius,.3,.02,1),intensity:P(e.intensity,.5,0,1),color:T(e.color,"#ffffff")}}):[],effects:u,motion:{type:C(m.type,e.map(t=>t.mode),"none"),speed:P(m.speed,1,.1,3),amount:P(m.amount,1,0,2)},hover:{effect:C(f.effect,t.map(t=>t.value),"trail"),strength:P(f.strength,.55,0,1),radius:P(f.radius,.2,.1,1),edgeSafe:!0===f.edgeSafe}}}function R(t){return JSON.stringify(I(t))}function L(t){if(t.length>1e5)throw new Error("Settings exceed 100 KB.");return I(JSON.parse(t))}function N(t,e,i,a,s){const r=Math.abs(s.rotation/90)%2==1,n=r?e:t,o=r?t:e,h=Math.max(i/n,a/o)*s.zoom;return{width:n*h,height:o*h,x:(i-n*h)*s.x,y:(a-o*h)*s.y,scale:h,rotated:r}}function O(t,e,i){if(Math.abs(i.crop.rotation/90)%2==1&&([t,e]=[e,t]),"original"===i.aspectRatio)return[t,e];const[a,s]=i.aspectRatio.split(":").map(Number);return t/e>a/s?[Math.round(e*a/s),e]:[t,Math.round(t*s/a)]}function D(t,e){const i={...t,...e};for(const a of["crop","backdrop","color","dither","mask","effects","motion","hover"])e[a]&&Object.assign(i,{[a]:{...t[a],...e[a]}});return e.color?.curves&&(i.color.curves={...t.color.curves,...e.color.curves}),I(i)}function X(t,e,i,a=12e3,s=1){const r=Math.max(2,Number.isFinite(t)?t:960),n=Math.max(2,Number.isFinite(e)?e:540),o=Math.max(1,Math.floor(Number.isFinite(a)?a:12e3)),h=Math.max(.01,Number.isFinite(s)?s:1),l=["dither","pixel","mosaic","lego","voxel","disco","dots","hex","led","cmyk"].includes(i.style)?1:1.65;let c=Math.max(1,Math.ceil(Math.sqrt(r*n/(o*l))/h));for(;Math.ceil(r/(c*h))*Math.ceil(n/(c*h*l))>o;)c++;const d="dither"===i.style?i.dither.scale:i.cellSize,m=Math.max(c,d)*h;return{cell:m,rowHeight:m*l,columns:Math.ceil(r/m),rows:Math.ceil(n/(m*l)),minimum:c,limited:d<c}}var U=[["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:"caustics",speed:.5}}],["blueprint","Blueprint","Linework in a cool monochrome.",{style:"lines",ink:"#9bccdf",backdrop:{mode:"solid",color:"#0a1e30"}}]].map(([t,e,i,a])=>({id:t,name:e,description:i,settings:I(a)}));function j(t){const e=U.find(e=>e.id===t);if(!e)throw new Error("Unknown studio look.");return I(e.settings)}function Y(t,e=Math.random){const i=U.filter(e=>e.settings.style!==t.style||e.settings.ink!==t.ink),a=j(i[Math.min(i.length-1,Math.max(0,Math.floor(e()*i.length)))].id);return a.aspectRatio=t.aspectRatio,a.crop={...t.crop},a.mask=I(t).mask,a}function q(t){const e=function(t){const e=t.blackPoint??0,i=t.whitePoint??1,a=t.gamma??1,s=t.shadows??0,r=t.highlights??0;if(0===e&&1===i&&1===a&&0===s&&0===r)return null;const n=[0,.25+.2*s,.5,.75+.2*r,1],o=n.slice(1).map((t,e)=>4*(t-n[e])),h=[o[0],...o.slice(1).map((t,e)=>2*t*o[e]/(t+o[e])),o[3]],l=new Uint8Array(256);for(let t=0;t<256;t++){const s=Math.pow(Math.max(0,Math.min(1,(t/255-e)/(i-e))),1/a),r=Math.min(3,Math.floor(4*s)),o=4*s-r,c=o*o,d=c*o,m=(2*d-3*c+1)*n[r]+(d-2*c+o)*h[r]/4+(-2*d+3*c)*n[r+1]+(d-c)*h[r+1]/4;l[t]=Math.round(255*Math.max(0,Math.min(1,m)))}return l}(t),i=t.curves;if(!e&&(!i||Object.values(i).every(t=>t.every(([t,e])=>t===e))))return null;const a=m(i?.rgb),s=[i?.red,i?.green,i?.blue].map(m),r=new Uint8Array(768);for(let t=0;t<256;t++)for(let i=0;i<3;i++)r[256*i+t]=s[i][a[e?e[t]:t]];return r}var B=class{constructor(t=0){this.amount=0,this.weights=new Float32Array(256),this.source=new Uint8ClampedArray(0),this.configure(t)}configure(t=0){const e=Math.max(0,Math.min(1,Number.isFinite(t)?t:0));if(e===this.amount)return;if(this.amount=e,0===e)return void(this.source=new Uint8ClampedArray(0));const i=8+24*e;for(let t=0;t<256;t++)this.weights[t]=Math.exp(-t*t/(2*i*i))}apply(t,e,i){if(!this.amount)return;if(!Number.isInteger(e)||!Number.isInteger(i)||e<1||i<1||e*i*4!==t.length)throw new Error("Denoise dimensions do not match the source.");this.source.length!==t.length&&(this.source=new Uint8ClampedArray(t.length));const a=this.source;a.set(t);for(let s=0;s<i;s++)for(let r=0;r<e;r++){const n=4*(s*e+r);if(!a[n+3])continue;const o=a[n],h=a[n+1],l=a[n+2];let c=0,d=0,m=0,f=0;for(let t=-1;t<=1;t++){const n=s+t;if(!(n<0||n>=i))for(let i=-1;i<=1;i++){const s=r+i;if(s<0||s>=e)continue;const u=4*(n*e+s);if(!a[u+3])continue;const g=Math.max(Math.abs(a[u]-o),Math.abs(a[u+1]-h),Math.abs(a[u+2]-l)),p=this.weights[g]*(0===i?1:.6)*(0===t?1:.6)*a[u+3];c+=a[u]*p,d+=a[u+1]*p,m+=a[u+2]*p,f+=p}}t[n]=o+(c/f-o)*this.amount,t[n+1]=h+(d/f-h)*this.amount,t[n+2]=l+(m/f-l)*this.amount}}},z=new Set(["none","floyd-steinberg","atkinson","stucki","sierra","sierra-lite","burkes","jarvis"]);function W(t){return"dither"===t.style&&("shimmer"===t.dither.motion||"drift"===t.dither.motion&&t.dither.amount>0&&!z.has(t.dither.algorithm))}function G(t){return"none"!==t.motion.type&&(t.motion.amount??1)>0}function V(t){return G(t)||W(t)||t.effects.grain>0||t.effects.dust>0||t.effects.glitch>0}var H="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",J="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",Q=new Uint16Array(4096);for(let t=0;t<Q.length;t++)Q[t]=H.indexOf(J[2*t])<<6|H.indexOf(J[2*t+1]);var K=(t,e)=>{const i=43758.5453*Math.sin(127.1*t+311.7*e);return i-Math.floor(i)};var Z=new Map([2,4,8,16].map(t=>[t,Float64Array.from({length:t*t},(e,i)=>function(t,e,i){let a=0;for(let s=1;s<i;s*=2){const i=(Math.floor(t/s)%2+2)%2;a=4*a+[[0,2],[3,1]][(Math.floor(e/s)%2+2)%2][i]}return(a+.5)/(i*i)-.5}(i%t,Math.floor(i/t),t))])),_={"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]]},$=t=>[parseInt(t.slice(1,3),16),parseInt(t.slice(3,5),16),parseInt(t.slice(5,7),16)];function tt(t,e,i){const a=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)),s=Math.max(0,Math.min(1,(a-.035)/.105));return s*s*s*(s*(6*s-15)+10)}var et=t=>["dissolve","silk","vortex","magnetic","scatter","etch","elastic","rake"].includes(t),it=class{constructor(t,e){this.edgeSafe=!1,this.previous=null,this.peak=0,this.scatterDirections=null,this.springX=null,this.springY=null,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 a=0;a<t;a++)this.edge[i*t+a]=tt(a/(t-1),i/(e-1),t/e);this.clear()}get active(){return this.peak>2e-4}setMode(t){if("elastic"!==t||this.springX||(this.springX=new Float32Array(this.ink.length),this.springY=new Float32Array(this.ink.length)),"scatter"===t&&!this.scatterDirections){const t=this.scatterDirections=new Float64Array(this.width*this.height*2);for(let e=0;e<this.height;e++)for(let i=0;i<this.width;i++){const a=43758.5453*Math.sin(127.1*i+311.7*e),s=(a-Math.floor(a))*Math.PI*2,r=2*(e*this.width+i);t[r]=.7*Math.cos(s),t[r+1]=.7*Math.sin(s)}}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,this.springX?.fill(0),this.springY?.fill(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 a=this.previous;this.previous={x:t,y:e};const s=this.width,r=this.height,n=Math.max(1,s/r),o=Math.max(1,r/s),h=a?(t-a.x)*n:0,l=a?(e-a.y)*o:0,c=Math.hypot(h,l);if(!a&&"dissolve"!==this.mode&&"etch"!==this.mode)return;if(a&&c<1e-4)return;const d=.035+.11*Math.max(.1,Math.min(1,i)),m=Math.min(128,Math.max(1,Math.ceil(c/(.45*d)))),f=c?h/c:1,u=c?l/c:0,g=Math.min(1,c/(d*m)*2.2);for(let i=0;i<m;i++){const h=(i+.5)/m,l=a?a.x+(t-a.x)*h:t,c=a?a.y+(e-a.y)*h:e,p=Math.max(0,Math.floor((l-2.5*d/n)*(s-1))),M=Math.min(s-1,Math.ceil((l+2.5*d/n)*(s-1))),w=Math.max(0,Math.floor((c-2.5*d/o)*(r-1))),v=Math.min(r-1,Math.ceil((c+2.5*d/o)*(r-1)));for(let t=w;t<=v;t++)for(let e=p;e<=M;e++){const i=(e/(s-1)-l)*n/d,a=(t/(r-1)-c)*o/d,h=Math.exp(1.5*-(i*i+a*a)),m=t*s+e;if("dissolve"===this.mode||"etch"===this.mode)this.ink[m]=Math.max(this.ink[m],h);else if("elastic"===this.mode)this.springX[m]=Math.max(-24,Math.min(24,this.springX[m]+f*h*g*8)),this.springY[m]=Math.max(-24,Math.min(24,this.springY[m]+u*h*g*8));else{const s=(-i*u+a*f)*h*2.8,r="rake"===this.mode?f*Math.sin(t*Math.PI/3)*h*2:"magnetic"===this.mode?-i*h*2.5:"scatter"===this.mode?(i+this.scatterDirections[2*m])*h*2:"silk"===this.mode?f*s:-a*h*2.5,n="rake"===this.mode?u*Math.sin(e*Math.PI/3)*h*2:"magnetic"===this.mode?-a*h*2.5:"scatter"===this.mode?(a+this.scatterDirections[2*m+1])*h*2:"silk"===this.mode?u*s:i*h*2.5;this.targetX[m]=Math.max(-1,Math.min(1,this.targetX[m]+r*g)),this.targetY[m]=Math.max(-1,Math.min(1,this.targetY[m]+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),a=1-Math.exp(-22*e);let s=0;const r=Math.sqrt(336),n=Math.exp(-8*e),o=Math.cos(r*e),h=Math.sin(r*e)/r;for(let t=0;t<this.ink.length;t++)if("etch"===this.mode)this.ink[t]*=i,s=Math.max(s,this.ink[t]);else if("dissolve"===this.mode){this.ink[t]*=i,s=Math.max(s,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{if("elastic"===this.mode){const e=this.offsetX[t],i=this.offsetY[t],a=this.springX[t],r=this.springY[t];this.offsetX[t]=Math.max(-1,Math.min(1,n*(e*o+(a+8*e)*h))),this.offsetY[t]=Math.max(-1,Math.min(1,n*(i*o+(r+8*i)*h))),this.springX[t]=n*(a*o-(8*a+400*e)*h),this.springY[t]=n*(r*o-(8*r+400*i)*h),s=Math.max(s,.05*Math.abs(this.springX[t]),.05*Math.abs(this.springY[t]))}else this.targetX[t]*=i,this.targetY[t]*=i,this.offsetX[t]+=(this.targetX[t]-this.offsetX[t])*a,this.offsetY[t]+=(this.targetY[t]-this.offsetY[t])*a;s=Math.max(s,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),r=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]=r>>>8,this.pixels[4*t+3]=255&r}if("etch"===this.mode)for(let t=0;t<this.height;t++)for(let e=0;e<this.width;e++){const i=t*this.width+e,a=3*(this.ink[t*this.width+Math.max(0,e-1)]-this.ink[t*this.width+Math.min(this.width-1,e+1)]+this.ink[Math.max(0,t-1)*this.width+e]-this.ink[Math.min(this.height-1,t+1)*this.width+e]);this.offsetX[i]=Math.max(-1,Math.min(1,a))*(this.edgeSafe?this.edge[i]:1);const s=Math.round(32767*this.offsetX[i]+32768);this.pixels[4*i]=s>>>8,this.pixels[4*i+1]=255&s}this.peak=s,this.active||this.clear()}sample(t,e,i){const a=Math.max(0,Math.min(this.width-1.001,t*(this.width-1))),s=Math.max(0,Math.min(this.height-1.001,e*(this.height-1))),r=Math.floor(a),n=Math.floor(s),o=a-r,h=s-n,l=n*this.width+r,c=l+this.width,d=t=>(t[l]*(1-o)+t[l+1]*o)*(1-h)+(t[c]*(1-o)+t[c+1]*o)*h;if("etch"===this.mode)return i[0]=i[1]=0,void(i[2]=3*d(this.offsetX));i[0]=d(this.offsetX)*(this.edgeSafe?tt(t,e,this.width/this.height):1)*.08,i[1]=d(this.offsetY)*(this.edgeSafe?tt(t,e,this.width/this.height):1)*.08,i[2]="dissolve"===this.mode?6*-d(this.ink):0}},at=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 a=Math.max(1,this.width/this.height),s=Math.max(1,this.height/this.width);this.previous&&(Math.hypot((t-this.previous.x)*a,(e-this.previous.y)*s)<.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),a=Math.max(1,this.height/this.width);let s=0;for(const r of this.rings){const n=.015+r.age*(.15+.22*r.radius),o=.009+.014*r.radius,h=(Math.hypot((t-r.x)*i,(e-r.y)*a)-n)/o,l=Math.sin(Math.min(1,r.age/.07)*Math.PI/2)*Math.max(0,1-r.age/1.35)**2;s=Math.max(s,Math.exp(-h*h)*l)}return s}sample(t,e){const i=Math.max(0,Math.min(this.width-1,Math.round(t*(this.width-1)))),a=Math.max(0,Math.min(this.height-1,Math.round(e*(this.height-1))));return Math.max(this.ringSample(t,e),this.echo[a*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 a=0;for(let t=0;t<this.height;t++)for(let e=0;e<this.width;e++){const s=t*this.width+e;this.echo[s]=Math.max(this.ringSample(e/(this.width-1),t/(this.height-1)),this.echo[s]*i),a=Math.max(a,this.echo[s]);const r=Math.round(65535*this.echo[s]),n=4*s;this.pixels[n]=r>>>8,this.pixels[n+1]=255&r}this.echoPeak=a,this.active||(this.echo.fill(0),this.pixels.fill(0))}},st=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,a=performance.now()){if(!Number.isFinite(t+e+i+a))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 s=this.previous;if(this.previous={x:t,y:e,time:a},!s)return;const r=(t-s.x)*(this.width-1),n=(e-s.y)*(this.height-1),o=Math.hypot(r,n);if(o<.001)return;const h=Math.min(this.width,this.height),l=a>s.time?Math.max(1/240,(a-s.time)/1e3):1/60,c=Math.min(12,o/h/l),d=1-Math.exp(-c/2.2),m=h*(.022+.075*i)*(.65+.95*d),f=Math.min(128,Math.max(1,Math.ceil(o/(.4*m)))),u=o/m*(.32+.22*d)/f,g=r/o,p=n/o,M=-p,w=g,v=o*(2+18*d)/f;for(let i=0;i<f;i++){const a=(i+.5)/f,r=(s.x+(t-s.x)*a)*(this.width-1),n=(s.y+(e-s.y)*a)*(this.height-1),o=Math.max(1,Math.floor(r-3*m)),h=Math.min(this.width-2,Math.ceil(r+3*m)),l=Math.max(1,Math.floor(n-3*m)),c=Math.min(this.height-2,Math.ceil(n+3*m));for(let t=l;t<=c;t++)for(let e=o;e<=h;e++){const i=((e-r)*g+(t-n)*p)/m,a=((e-r)*M+(t-n)*w)/m,s=Math.exp(-i*i*.65-a*a*1.7),o=t*this.width+e;this.ink[o]=1-(1-this.ink[o])*Math.exp(-s*u);const h=1-a*a*.55,l=i*a*.7;this.u[o]=Math.max(-80,Math.min(80,this.u[o]+(g*h+M*l)*s*v)),this.v[o]=Math.max(-80,Math.min(80,this.v[o]+(p*h+w*l)*s*v))}}this.peak=1}read(t,e,i){const a=0|(e=Math.max(.5,Math.min(this.width-1.5,e))),s=0|(i=Math.max(.5,Math.min(this.height-1.5,i))),r=e-a,n=i-s,o=s*this.width+a;return(t[o]*(1-r)+t[o+1]*r)*(1-n)+(t[o+this.width]*(1-r)+t[o+this.width+1]*r)*n}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,a=this.height;for(;e>1e-7;){const t=Math.min(1/60,e);e-=t;const s=Math.exp(-1.9*t),r=Math.exp(-3.2*t);for(let e=1;e<a-1;e++)for(let n=1;n<i-1;n++){const o=e*i+n,h=Math.max(.5,Math.min(i-1.5,n-this.u[o]*t)),l=Math.max(.5,Math.min(a-1.5,e-this.v[o]*t)),c=0|h,d=0|l,m=h-c,f=l-d,u=d*i+c,g=(1-m)*(1-f),p=m*(1-f),M=(1-m)*f,w=m*f;this.a[o]=(this.u[u]*g+this.u[u+1]*p+this.u[u+i]*M+this.u[u+i+1]*w)*s,this.b[o]=(this.v[u]*g+this.v[u+1]*p+this.v[u+i]*M+this.v[u+i+1]*w)*s,this.c[o]=(this.ink[u]*g+this.ink[u+1]*p+this.ink[u+i]*M+this.ink[u+i+1]*w)*r}[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<a-1;t++)for(let e=1;e<i-1;e++){const a=t*i+e;this.curl[a]=.5*(this.v[a+1]-this.v[a-1]-this.u[a+i]+this.u[a-i])}for(let e=1;e<a-1;e++)for(let a=1;a<i-1;a++){const s=e*i+a,r=Math.abs(this.curl[s+1])-Math.abs(this.curl[s-1]),n=Math.abs(this.curl[s+i])-Math.abs(this.curl[s-i]),o=Math.hypot(r,n)+1e-4,h=this.curl[s]*t*10,l=Math.hypot(this.u[s],this.v[s]);this.u[s]+=n/o*h,this.v[s]-=r/o*h;const c=Math.min(1,l/(Math.hypot(this.u[s],this.v[s])+1e-6));this.u[s]*=c,this.v[s]*=c,this.divergence[s]=-.5*(this.u[s+1]-this.u[s-1]+this.v[s+i]-this.v[s-i])}this.pressure.fill(0);for(let t=0;t<4;t++){for(let t=1;t<a-1;t++)for(let e=1;e<i-1;e++){const a=t*i+e;this.pressureNext[a]=.25*(this.divergence[a]+this.pressure[a-1]+this.pressure[a+1]+this.pressure[a-i]+this.pressure[a+i])}[this.pressure,this.pressureNext]=[this.pressureNext,this.pressure]}let n=0;for(let e=1;e<a-1;e++)for(let a=1;a<i-1;a++){const s=e*i+a;this.u[s]=Math.max(-80,Math.min(80,this.u[s]-.5*(this.pressure[s+1]-this.pressure[s-1]))),this.v[s]=Math.max(-80,Math.min(80,this.v[s]-.5*(this.pressure[s+i]-this.pressure[s-i]))),this.driftX[s]+=(3.6*this.u[s]-58*this.offsetX[s]-12*this.driftX[s])*t,this.driftY[s]+=(3.6*this.v[s]-58*this.offsetY[s]-12*this.driftY[s])*t,this.offsetX[s]=Math.max(-2,Math.min(2,this.offsetX[s]+this.driftX[s]*t)),this.offsetY[s]=Math.max(-2,Math.min(2,this.offsetY[s]+this.driftY[s]*t)),this.signal[s]=1-Math.exp(.06*-Math.hypot(this.u[s],this.v[s])-.16*this.ink[s]),n=Math.max(n,this.signal[s])}this.peak=n}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 rt(t,e){const i=Math.max(0,Math.min(1,e/.38));return t+(1-2*t)*(i*i*(3-2*i))}var nt=(t,e)=>"water"===t?30*e/.55:"silk"===t?28*e:"vortex"===t?38*e:["magnetic","scatter","elastic","rake"].includes(t)?32*e:0,ot=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]=tt(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 st(this.columns,this.rows),this.contour=new at(this.columns,this.rows),this.afterimage=new it(this.columns,this.rows),this.clear()}get invertsDensity(){return"trail"===this.mode}get densityTrail(){return["trail","contour","dissolve","etch"].includes(this.mode)}get hasRefraction(){return this.active||this.lensStrength>15e-5}get active(){return et(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,et(t)&&this.afterimage.setMode(t),this.refraction.pixels="trail"===t?this.trail.pixels:"contour"===t?this.contour.pixels:et(t)?this.afterimage.pixels:this.waterPixels,this.refraction.strength=nt(t,this.amount))}configure(t,e=.55,i=.2,a=!1){this.setMode(t),this.refraction.edgeSafe=a,this.afterimage.edgeSafe=a,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=nt(t,this.amount),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)),et(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 a=this.previous;this.previous={x:t,y:e};const s=(t-a.x)*this.xScale,r=(e-a.y)*this.yScale,n=Math.hypot(s,r);if(n<1e-5)return;const o=.035+.1*this.radius,h=3*o,l=Math.min(192,Math.max(1,Math.ceil(n/(.5*o)))),c=95*Math.min(n,1)/l;for(let i=0;i<l;i++){const s=(i+.5)/l,r=a.x+(t-a.x)*s,n=a.y+(e-a.y)*s,d=Math.max(1,Math.floor((r-h/this.xScale)*(this.columns-1))),m=Math.min(this.columns-2,Math.ceil((r+h/this.xScale)*(this.columns-1))),f=Math.max(1,Math.floor((n-h/this.yScale)*(this.rows-1))),u=Math.min(this.rows-2,Math.ceil((n+h/this.yScale)*(this.rows-1)));for(let t=f;t<=u;t++)for(let e=d;e<=m;e++){const i=(e/(this.columns-1)-r)*this.xScale,a=(t/(this.rows-1)-n)*this.yScale,s=Math.exp(-(i*i+a*a)/(o*o))*c,h=t*this.columns+e;this.velocity[h]=Math.max(-12,this.velocity[h]-s)}}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(et(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),a=.3*Math.min(this.columns,this.rows);for(;this.remainder+1e-8>=e;){this.remainder-=e;let t=0;for(let s=1;s<this.rows-1;s++)for(let r=1;r<this.columns-1;r++){const n=s*this.columns+r,o=this.heights[n],h=this.heights[n-1]+this.heights[n+1]+this.heights[n-this.columns]+this.heights[n+this.columns]-4*o,l=Math.min(r,s,this.columns-1-r,this.rows-1-s),c=l<5?.88+.024*l:1,d=(this.velocity[n]+(h*a*a-8*o)*e)*i*c;this.velocity[n]=d,this.next[n]=(o+d*e)*c,t=Math.max(t,Math.abs(this.next[n]),.1*Math.abs(d))}this.heights.set(this.next),this.energy=t,this.pending=!1}if(!this.active)return void this.clear();const s=.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,a=(this.heights[t*this.columns+Math.max(0,e-1)]-this.heights[t*this.columns+Math.min(this.columns-1,e+1)])*s,r=(this.heights[Math.max(0,t-1)*this.columns+e]-this.heights[Math.min(this.rows-1,t+1)*this.columns+e])*s,n=Math.tanh(a)*(this.refraction.edgeSafe?this.edgeMask[i]:1),o=Math.tanh(r)*(this.refraction.edgeSafe?this.edgeMask[i]:1);this.normals[2*i]=n,this.normals[2*i+1]=o;const h=Math.round(32767*n+32768),l=Math.round(32767*o+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),a=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)*a,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(et(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 a=Math.max(0,Math.min(this.columns-1.001,t*(this.columns-1))),s=Math.max(0,Math.min(this.rows-1.001,e*(this.rows-1))),r=Math.floor(a),n=Math.floor(s),o=a-r,h=s-n,l=2*(n*this.columns+r),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-h)+(this.normals[c+t]*(1-o)+this.normals[c+2+t]*o)*h);i[0]*=this.amount/.55,i[1]*=this.amount/.55,i[2]="light"===this.mode||"scan"===this.mode?function(t,e,i,a){const[s,r,n,o]=i.focus,h=(t-s)*Math.max(1,a)/o,l=(e-r)*Math.max(1,1/a)/o;return"light"===i.mode?Math.exp(-3*(h*h+l*l))*n:"scan"===i.mode?(1.3*Math.exp(-h*h*110)-.3*Math.exp(-h*h*12))*Math.exp(-l*l*1.8)*n:0}(t,e,this.refraction,this.xScale/this.yScale):0}};function ht(t){return"videoWidth"in t?[t.videoWidth,t.videoHeight]:"naturalWidth"in t?[t.naturalWidth,t.naturalHeight]:[t.width,t.height]}var lt=(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}},ct=(t,e,i)=>{t.width===e&&t.height===i||(t.width=e,t.height=i)},dt={blocks:" ░▒▓█",braille:" ⠁⠃⠇⡇⣇⣧⣷⣿",lines:" -═╪╬",cross:" ·+xX#",diagonal:" /╱╳",diamond:" ·◇◈◆",mixed:" .:+/◇#@"};function mt(t,e={},i={}){const a=t.getContext("2d");if(!a)throw new Error("Canvas is already owned by another renderer.");const s=lt(),r=lt(!0),h=lt(),l=lt(),c=lt(),d=lt(),m=lt(),u=lt(),g=lt(),p=lt();let M,w=0,v=I(e),b=0,x="",E="",k="",S=new Uint8ClampedArray(0),F=new Uint8ClampedArray(0),P=0,T=0,C=0,R=null,L="",O=new ot,D=0;const U=[0,0,0],j=[0,0,0,1],Y=[0,0,0,0];let z=q(v.color);const V=new B(v.color.denoise),H=new y(v.warps,v.warpEdge),J=Math.max(64,Math.min(4096,Number.isFinite(i.maxDimension)?i.maxDimension:960)),tt=Math.max(256,Math.min(1048576,Number.isFinite(i.maxCells)?i.maxCells:12e3));let et=tt,it=Math.max(.1,Math.min(8,i.pixelRatio??1));return{canvas:t,render:function(e,i=0,y=960,I=540,q=i*v.motion.speed){if(Number.isFinite(i)||(i=0),!Number.isFinite(y)||!Number.isFinite(I)||y<1||I<1)throw new Error("Render dimensions must be positive finite numbers.");const[B,tt]=ht(e);if(!B||!tt)return;const at=Math.min(1,J/Math.max(y,I)),st=Math.max(2,Math.round(y*at)),nt=Math.max(2,Math.round(I*at));ct(t,st,nt),ct(s.canvas,st,nt),ct(h.canvas,st,nt),ct(l.canvas,st,nt),ct(c.canvas,st,nt),D!==st/nt&&(D=st/nt,O=new ot(D)),O.configure(v.hover.effect,v.hover.strength,v.hover.radius,v.hover.edgeSafe),O.step(Math.max(0,Math.min(.05,i-C))),C=i;const lt="currentTime"in e?e.getVideoPlaybackQuality?.().totalVideoFrames??e.currentTime:0,mt=[b,st,nt,lt].join(":"),ft="dither"===v.style,ut=X(st,nt,v,et,it),gt=ut.cell,pt=ut.rowHeight,Mt=ut.columns,wt=ut.rows;if(x!==mt||R!==e||P!==Mt||T!==wt){R=e,x=mt,E="",k="",P=Mt,T=wt,s.ctx.clearRect(0,0,st,nt),s.ctx.save();const t=N(B,tt,st,nt,v.crop);s.ctx.translate(t.x+t.width/2,t.y+t.height/2),s.ctx.rotate(v.crop.rotation*Math.PI/180),s.ctx.drawImage(e,-B*t.scale/2,-tt*t.scale/2,B*t.scale,tt*t.scale),s.ctx.restore(),ct(r.canvas,P,T),r.ctx.clearRect(0,0,P,T),r.ctx.drawImage(s.canvas,0,0,P,T),S=r.ctx.getImageData(0,0,P,T).data,V.apply(S,P,T);const i=v.color;for(let t=0;t<S.length;t+=4){const e=.299*S[t]+.587*S[t+1]+.114*S[t+2];for(let a=0;a<3;a++){const s=e+(S[t+a]-e)*i.saturation;S[t+a]=((s*(1-i.grayscale)+e*i.grayscale)/255-.5)*i.contrast*255+127.5+255*i.brightness}}z&&function(t,e){for(let i=0;i<t.length;i+=4)t[i+3]&&(t[i]=e[t[i]],t[i+1]=e[256+t[i+1]],t[i+2]=e[512+t[i+2]])}(S,z),S=H.apply(S,P,T,st/nt)}const vt=G(v),bt=W(v),yt=!O.active&&!vt&&!bt,xt=[mt,P,T,gt,pt,it].join(":");if(!yt||k!==xt){h.ctx.clearRect(0,0,st,nt),h.ctx.globalAlpha=1,h.ctx.globalCompositeOperation="source-over";const t=q,e=vt?v.motion.type:"none",a=["none","caustics","sheen","grain","trace"].includes(e);if(ft){const a=yt;if(!a||E!==mt){F.length!==S.length&&(F=new Uint8ClampedArray(S.length));const s=F;if(s.set(S),O.active||"none"!==e)for(let i=0;i<T;i++)for(let a=0;a<P;a++){const r=a/P,h=i/T;let l=a,c=i,d=0,m=1,u=1;O.active&&(O.sample(r,h,U),l-=U[0]*P,c-=U[1]*T,d=U[2]/3);const g=4*(i*P+a);n(e,r,h,t,j,(.299*S[g]+.587*S[g+1]+.114*S[g+2])/255),o(j,v.motion.amount??1),l-=j[0]/960*P,c-=j[1]/960*T,m=1+j[2],u=j[3];const p=4*(i*P+a);f(S,P,T,l,c,Y);for(let t=0;t<3;t++){const e=Y[t]/255;let i=(["trail","contour"].includes(v.hover.effect)?rt(e,d):"etch"===v.hover.effect?Math.max(0,Math.min(1,e+.35*d)):"dissolve"===v.hover.effect?e*Math.max(0,1+d):e)*m;s[p+t]=255*i}s[p+3]=Y[3]*u}!function(t,e,i,a,s=0){const{algorithm:r,amount:n,threshold:o}=a,h="blue-noise"===r,l=r.startsWith("bayer")?Number(r.slice(5)):0,c=Z.get(l),d=l-1,m="luminance"===a.colorSpace,f=("custom"===a.palette?a.colors:A[a.palette]??A.mono).map($),u=_[r],g=u?new Float32Array(3*e*3):null,p="drift"===a.motion?s*a.speed*3:0,M=(a.direction??45)*Math.PI/180,w=Math.round(Math.cos(M)*p),v=Math.round(Math.sin(M)*p),b=(t,e)=>(t%e+e)%e,y=f.map(t=>.299*t[0]+.587*t[1]+.114*t[2]),x="shimmer"===a.motion?.15*Math.sin(s*a.speed*2):0;for(let a=0;a<i;a++)for(let s=0;s<e;s++){const M=4*(a*e+s),E=3*(a%3*e+s);if(0===t[M+3]){g&&(g[E]=g[E+1]=g[E+2]=0);continue}let k=0;const A=h?(Q[64*(a-v&63)+(s-w&63)]+.5)/Q.length:0;c?k=c[(a-v&d)*l+(s-w&d)]:"noise"===r?k=K(s-w,a-v)-.5:"lines"===r?k=b(a-v,4)/3-.5:"vertical-lines"===r?k=b(s-w,4)/3-.5:"diagonal-lines"===r?k=b(s-w+a-v,4)/3-.5:"radial"===r?k=b(Math.hypot(s-e/2,a-i/2)-p,6)/6-.5:"halftone"===r&&(k=Math.hypot(b(s-w,6)-2.5,b(a-v,6)-2.5)/3.54-.5);const S=128*(k*n+x+(.5-o)),F=t[M]+S+(g?.[E]??0),P=t[M+1]+S+(g?.[E+1]??0),T=t[M+2]+S+(g?.[E+2]??0);let C=0,I=0,R=0;if(f.length){let t=1/0,e=1/0,i=0,a=0;const s=.299*F+.587*P+.114*T;for(let r=0;r<f.length;r++){const n=f[r],o=m?(s-y[r])**2:(F-n[0])**2*.299+(P-n[1])**2*.587+(T-n[2])**2*.114;o<t?(h&&(e=t,a=i,i=r),t=o,[C,I,R]=n):h&&o<e&&(e=o,a=r)}if(h&&n>0&&Number.isFinite(e)){const t=f[a],e=t[0]-C,r=t[1]-I,o=t[2]-R,h=y[a]-y[i],l=m?h*h:e*e*.299+r*r*.587+o*o*.114,c=m?(s-y[i])*h:(F-C)*e*.299+(P-I)*r*.587+(T-R)*o*.114;A<(l?Math.max(0,Math.min(1,c/l*n)):0)&&([C,I,R]=t)}}else if(h){const t=Math.max(0,Math.min(1,.5+(A-.5)*n));C=51*Math.floor(F/51+1-t),I=51*Math.floor(P/51+1-t),R=51*Math.floor(T/51+1-t)}else C=51*Math.round(F/51),I=51*Math.round(P/51),R=51*Math.round(T/51);if(t[M]=C,t[M+1]=I,t[M+2]=R,g&&u){g[E]=g[E+1]=g[E+2]=0;for(const[t,r,o]of u){const h=s+t;if(h<0||h>=e||a+r>=i)continue;const l=3*((a+r)%3*e+h);g[l]+=(F-C)*o*n,g[l+1]+=(P-I)*o*n,g[l+2]+=(T-R)*o*n}}}}(s,P,T,v.dither,i),r.ctx.putImageData(new ImageData(s,P,T),0,0),E=a?mt:""}h.ctx.imageSmoothingEnabled=!1,h.ctx.drawImage(r.canvas,0,0,st,nt)}else{const i=Array.from(dt[v.style]??v.charset),s=h.ctx,r=$(v.ink),l="ascii"===v.style||!!dt[v.style],c=Math.max(3,Math.round(.92*pt)),d=Math.ceil(gt+4),u=Math.ceil(pt+4),g=[i.join(""),c,d,u,v.ink,v.colorMode].join(":");if(l&&g!==L&&(L=g,ct(m.canvas,d*i.length,u),m.ctx.clearRect(0,0,m.canvas.width,u),m.ctx.font=`${c}px monospace`,m.ctx.textBaseline="middle",m.ctx.textAlign="center",m.ctx.fillStyle="accent"===v.colorMode?v.ink:"#ffffff",i.forEach((t,e)=>m.ctx.fillText(t,e*d+d/2,u/2))),"lego"===v.style&&w!==gt){w=gt,ct(p.canvas,Math.ceil(gt),Math.ceil(pt));const t=p.ctx;t.clearRect(0,0,p.canvas.width,p.canvas.height),t.fillStyle="rgba(255,255,255,.2)",t.strokeStyle="rgba(0,0,0,.25)",t.lineWidth=Math.max(.5,.6*it),t.beginPath(),t.arc(gt/2,pt/2,.28*gt,0,2*Math.PI),t.fill(),t.stroke()}s.font=`${c}px monospace`,s.textBaseline="middle",s.textAlign="center";for(let h=0;h<T;h++)for(let c=0;c<P;c++){let g=c,M=h,w=0;if(O.active&&(O.sample(c/P,h/T,U),g=Math.max(0,Math.min(P-1,c-U[0]*P)),M=Math.max(0,Math.min(T-1,h-U[1]*T)),w=U[2]/3),f(S,P,T,g,M,Y),!Y[3])continue;const b=Y[0],y=Y[1],x=Y[2],E=(.299*b+.587*y+.114*x)/255;let k=E;["trail","contour"].includes(v.hover.effect)&&w?k=rt(k,w):"etch"===v.hover.effect?k=Math.max(0,Math.min(1,k+.35*w)):"dissolve"===v.hover.effect&&(k*=Math.max(0,1+w));let A=c*gt,F=h*pt,C=1;n(e,c/P,h/T,t,j,E),o(j,v.motion.amount??1),A+=j[0]*st/960,F+=j[1]*nt/960,k=Math.max(0,Math.min(1,k+j[2])),C=j[3]*Y[3]/255,l||"accent"!==v.colorMode||"cmyk"===v.style||(C*=k),s.globalAlpha=C;const I=255*(k-E),R="source"===v.colorMode?`rgb(${b+I},${y+I},${x+I})`:"gray"===v.colorMode?`rgb(${Math.round(255*k)},${Math.round(255*k)},${Math.round(255*k)})`:v.ink;if(s.fillStyle=R,l){const t=Math.max(0,Math.min(i.length-1,Math.round(k*(i.length-1))));"accent"===v.colorMode?s.drawImage(m.canvas,t*d,0,d,u,a?Math.round(A+(gt-d)/2):A+(gt-d)/2,a?Math.round(F+(pt-u)/2):F+(pt-u)/2,d,u):s.fillText(i[t],A+gt/2,F+pt/2)}else if("dots"===v.style)s.beginPath(),s.arc(A+gt/2,F+pt/2,.48*gt*Math.sqrt(k),0,2*Math.PI),s.fill();else if("led"===v.style)s.beginPath(),s.arc(A+gt/2,F+pt/2,.39*gt,0,2*Math.PI),s.fill(),s.globalAlpha=.35*C,s.fillStyle="#ffffff",s.beginPath(),s.arc(A+.43*gt,F+.4*pt,.11*gt,0,2*Math.PI),s.fill();else if("hex"===v.style){const t=A+gt/2,e=F+pt/2;s.beginPath();for(let i=0;i<6;i++){const a=Math.PI/3*i,r=t+Math.cos(a)*gt*.49,n=e+Math.sin(a)*pt*.49;0===i?s.moveTo(r,n):s.lineTo(r,n)}s.closePath(),s.fill()}else if("cmyk"===v.style){s.fillStyle="#ffffff",s.fillRect(A,F,gt,pt);const t=(t,e)=>Math.max(0,Math.min(255,"source"===v.colorMode?t+I:"gray"===v.colorMode?255*k:e*k)),e=t(b,r[0]),i=t(y,r[1]),a=t(x,r[2]),n=1-Math.max(e,i,a)/255,o=Math.max(.001,1-n),h=[["#00ffff",(1-e/255-n)/o,.36,.36],["#ff00ff",(1-i/255-n)/o,.64,.36],["#ffff00",(1-a/255-n)/o,.5,.66],["#000000",n,.5,.5]];s.globalCompositeOperation="multiply";for(const[t,e,i,a]of h)s.fillStyle=t,s.beginPath(),s.arc(A+gt*i,F+pt*a,.48*gt*Math.sqrt(Math.max(0,e)),0,2*Math.PI),s.fill();s.globalCompositeOperation="source-over"}else if("voxel"===v.style){const t=A+gt/2,e=F+pt/2;s.beginPath(),s.moveTo(t,F),s.lineTo(A+gt,F+.25*pt),s.lineTo(t,e),s.lineTo(A,F+.25*pt),s.closePath(),s.fill(),s.globalAlpha=.72*C,s.beginPath(),s.moveTo(A,F+.25*pt),s.lineTo(t,e),s.lineTo(t,F+pt),s.lineTo(A,F+.75*pt),s.closePath(),s.fill(),s.globalAlpha=.42*C,s.beginPath(),s.moveTo(t,e),s.lineTo(A+gt,F+.25*pt),s.lineTo(A+gt,F+.75*pt),s.lineTo(t,F+pt),s.closePath(),s.fill()}else{const t="pixel"===v.style?0:Math.max(.5,.06*gt);s.fillRect(A,F,gt-t,pt-t),"lego"===v.style&&s.drawImage(p.canvas,A,F),"disco"===v.style&&(s.fillStyle=`rgba(255,255,255,${.1+.25*K(c,h)})`,s.fillRect(A,F,gt-t,.35*pt),s.fillStyle="rgba(0,0,0,.25)",s.fillRect(A,F+.65*pt,gt-t,.35*pt-t))}}}h.ctx.globalAlpha=1,(v.color.amount||v.lights.length)&&(ct(u.canvas,st,nt),u.ctx.clearRect(0,0,st,nt),u.ctx.drawImage(h.canvas,0,0)),v.color.amount&&(h.ctx.save(),h.ctx.globalCompositeOperation=v.color.blend,h.ctx.globalAlpha=v.color.amount,h.ctx.fillStyle=v.color.tint,h.ctx.fillRect(0,0,st,nt),h.ctx.restore());for(const t of v.lights){const e=t.radius*Math.max(st,nt),i=h.ctx.createRadialGradient(t.x*st,t.y*nt,0,t.x*st,t.y*nt,e);i.addColorStop(0,t.color),i.addColorStop(1,"transparent"),h.ctx.save(),h.ctx.globalCompositeOperation="screen",h.ctx.globalAlpha=t.intensity,h.ctx.fillStyle=i,h.ctx.fillRect(0,0,st,nt),h.ctx.restore()}if((v.color.amount||v.lights.length)&&(h.ctx.globalCompositeOperation="destination-in",h.ctx.drawImage(u.canvas,0,0),h.ctx.globalCompositeOperation="source-over"),v.mask.enabled&&v.mask.shapes.length){const t=c.ctx;t.clearRect(0,0,st,nt),t.fillStyle="#fff",t.strokeStyle="#fff",t.lineCap="round",t.lineJoin="round";for(const e of v.mask.shapes){if(t.beginPath(),"ellipse"===e.kind)t.ellipse((e.x+e.width/2)*st,(e.y+e.height/2)*nt,e.width*st/2,e.height*nt/2,0,0,2*Math.PI);else{if("rectangle"!==e.kind){if(t.lineWidth=(e.size??.05)*st,1===e.points?.length){t.arc(e.points[0][0]*st,e.points[0][1]*nt,t.lineWidth/2,0,2*Math.PI),t.fill();continue}e.points?.forEach(([e,i],a)=>a?t.lineTo(e*st,i*nt):t.moveTo(e*st,i*nt)),t.stroke();continue}t.rect(e.x*st,e.y*nt,e.width*st,e.height*nt)}t.fill()}h.ctx.globalCompositeOperation=v.mask.invert?"destination-out":"destination-in",h.ctx.drawImage(c.canvas,0,0),h.ctx.globalCompositeOperation="source-over"}const M=l.ctx;M.clearRect(0,0,st,nt),M.globalAlpha=v.backdrop.opacity;const b=v.backdrop;if("solid"===b.mode&&(M.fillStyle=b.color,M.fillRect(0,0,st,nt)),"gradient"===b.mode){const t=M.createLinearGradient(0,0,st,nt);t.addColorStop(0,b.color),t.addColorStop(1,b.color2),M.fillStyle=t,M.fillRect(0,0,st,nt)}if("source"===b.mode&&M.drawImage(s.canvas,0,0),"blurred"===b.mode){const t=Math.max(1,b.blur);ct(d.canvas,Math.max(2,Math.round(st/t)),Math.max(2,Math.round(nt/t))),d.ctx.drawImage(s.canvas,0,0,d.canvas.width,d.canvas.height),M.imageSmoothingEnabled=!0,M.drawImage(d.canvas,0,0,st,nt)}M.globalAlpha=1,v.effects.characterBloom>0&&(ct(g.canvas,Math.max(2,Math.round(st/3)),Math.max(2,Math.round(nt/3))),g.ctx.clearRect(0,0,g.canvas.width,g.canvas.height),g.ctx.drawImage(h.canvas,0,0,g.canvas.width,g.canvas.height),M.save(),M.globalAlpha=.8*v.effects.characterBloom,M.globalCompositeOperation="screen",M.filter=`blur(${1+4*v.effects.characterBloom}px)`,M.drawImage(g.canvas,0,0,st,nt),M.restore()),M.drawImage(h.canvas,0,0),k=yt?xt:""}const Et=Object.entries(v.effects).some(([t,e])=>!["angle","focus","blurType","characterBloom"].includes(t)&&"number"==typeof e&&e>0);a.clearRect(0,0,st,nt),Et?(void 0===M&&(M=function(){const t=document.createElement("canvas"),e=t.getContext("webgl",{alpha:!0,premultipliedAlpha:!1,antialias:!1,preserveDrawingBuffer:!0});if(!e)return null;const i=[],a=(t,a)=>{const s=e.createShader(t);if(i.push(s),e.shaderSource(s,a),e.compileShader(s),!e.getShaderParameter(s,e.COMPILE_STATUS))throw new Error(e.getShaderInfoLog(s)||"Finish shader failed");return s},s=e.createProgram();if(e.attachShader(s,a(e.VERTEX_SHADER,"attribute vec2 p;varying vec2 uv;void main(){uv=(p+1.)*.5;gl_Position=vec4(p,0.,1.);}")),e.attachShader(s,a(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,rgbSplit,sharpen;\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+rgbSplit*8.)/size.x,prism*edge/size.y);\n if(prism>0.||rgbSplit>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;\n if(sharpen>0.){vec2 px=1./size;vec3 near=sampleAt(q+vec2(px.x,0.)).rgb+sampleAt(q-vec2(px.x,0.)).rgb+sampleAt(q+vec2(0.,px.y)).rgb+sampleAt(q-vec2(0.,px.y)).rgb;col+=(base.rgb*4.-near)*sharpen*.5;}\ncol*=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(s),!e.getProgramParameter(s,e.LINK_STATUS))throw new Error("Finish link failed");e.useProgram(s);const r=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,r),e.bufferData(e.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,1]),e.STATIC_DRAW);const n=e.getAttribLocation(s,"p");e.enableVertexAttribArray(n),e.vertexAttribPointer(n,2,e.FLOAT,!1,0,0);const o=e.createTexture();e.bindTexture(e.TEXTURE_2D,o),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","rgbSplit","sharpen","vignette","glitch","pixelate","blur","blurMode","angle","focus","halftone"],l=Object.fromEntries(h.map(t=>[t,e.getUniformLocation(s,t)])),c=e.getUniformLocation(s,"size");return{canvas:t,render(i,a,r,n=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(s),e.bindTexture(e.TEXTURE_2D,o),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,i),e.uniform2f(c,t.width/n,t.height/n);for(const t of h)e.uniform1f(l[t],"t"===t?r:"blurMode"===t?["gaussian","directional","radial","progressive"].indexOf(a.blurType):"angle"===t?a.angle*Math.PI/180:a[t]??0);return e.drawArrays(e.TRIANGLE_STRIP,0,4),t},destroy(){e.deleteTexture(o),e.deleteBuffer(r),e.deleteProgram(s),i.forEach(t=>e.deleteShader(t)),t.width=t.height=1,e.getExtension("WEBGL_lose_context")?.loseContext()}}}()),M?a.drawImage(M.render(l.canvas,v.effects,i,it),0,0):a.drawImage(l.canvas,0,0),t.dataset.studioFinish=M?"gpu":"unavailable"):(a.drawImage(l.canvas,0,0),t.dataset.studioFinish="none")},setPixelRatio(t){it=Math.max(.1,Math.min(8,Number.isFinite(t)?t:1))},get pixelRatio(){return it},setBudget(t){et=Math.max(256,Math.min(tt,Number.isFinite(t)?Math.round(t):tt))},get maxCells(){return et},configure(t){v=I(t),z=q(v.color),V.configure(v.color.denoise),H.configure(v.warps,v.warpEdge),b++},pointer:(t,e,i)=>{O.configure(v.hover.effect,v.hover.strength,v.hover.radius,v.hover.edgeSafe),O.move(t,e,i)},leave(){O.leave()},get active(){return O.active},get settings(){return I(v)},get capabilities(){return{gpuFinish:null!==M}},invalidate(){x=""},destroy(){M?.destroy(),H.clear(),V.configure(0);for(const t of[s,r,h,l,c,d,m,u,g,p])t.canvas.width=t.canvas.height=1;R=null,S=new Uint8ClampedArray(0),F=new Uint8ClampedArray(0)}}}function ft(t,e,i){return new Promise((a,s)=>{const r=()=>{l(),a()},n=()=>{l(),s(new Error("Unable to load this media. Check its format and cross-origin permissions."))},o=()=>{l(),s(new DOMException("Cancelled","AbortError"))},h=setTimeout(n,2e4),l=()=>{clearTimeout(h),t.removeEventListener(e,r),t.removeEventListener("error",n),i?.removeEventListener("abort",o)};t.addEventListener(e,r,{once:!0}),t.addEventListener("error",n,{once:!0}),i?.addEventListener("abort",o,{once:!0}),i?.aborted&&o()})}async function ut(t,e){if("string"==typeof t&&t.startsWith("blob:")){const i=await fetch(t,{signal:e}),a=await i.blob();return ut(new File([a],"Imported media",{type:a.type}),e)}const i="string"!=typeof t,a=i?t.name:t;if(i?"image/gif"===t.type:/\.gif(?:[?#]|$)/i.test(a)){const a=await import("gifuct-js"),{parseGIF:s,decompressFrames:r}="function"==typeof a.parseGIF?a:a.default,n=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 o=s(n),h=o.lsd.width,l=o.lsd.height;if(h*l>4e6)throw new Error("GIF is too large. Use a smaller GIF or an MP4.");const c=o.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=r(o,!0);if(d.length*h*l*4>128e6)throw new Error("GIF exceeds the 128 MB decoded budget. Use MP4 for long animations.");const m=document.createElement("canvas");m.width=h,m.height=l;const f=m.getContext("2d"),u=document.createElement("canvas"),g=u.getContext("2d"),p=d.reduce((t,e)=>t+Math.max(20,e.delay),0)/1e3;let M=-1,w=null;const v=t=>{const e=(t%p+p)%p*1e3;let i=0,a=0;for(;a<d.length-1&&(i+=Math.max(20,d[a].delay),!(e<i));a++);a<M&&(f.clearRect(0,0,h,l),M=-1,w=null);for(let t=M+1;t<=a;t++){const e=d[t-1];2===e?.disposalType&&f.clearRect(e.dims.left,e.dims.top,e.dims.width,e.dims.height),3===e?.disposalType&&w&&f.putImageData(w,0,0);const i=d[t];w=3===i.disposalType?f.getImageData(0,0,h,l):null,u.width=i.dims.width,u.height=i.dims.height,g.putImageData(new ImageData(new Uint8ClampedArray(i.patch),u.width,u.height),0,0),f.drawImage(u,i.dims.left,i.dims.top)}return M=a,m};return v(0),{source:m,width:h,height:l,duration:p,animated:!0,seek:async()=>{},frame:v,destroy(){m.width=u.width=1,d.length=0,w=null}}}const s=i?t.type.startsWith("video/"):/\.(mp4|webm|mov)(?:[?#]|$)/i.test(a),r=i?URL.createObjectURL(t):t,n=s?document.createElement("video"):new Image;n.crossOrigin="anonymous",n instanceof HTMLVideoElement&&(n.muted=!0,n.playsInline=!0,n.preload="auto");const o=()=>{n instanceof HTMLVideoElement?(n.pause(),n.removeAttribute("src"),n.load()):n.src="",i&&URL.revokeObjectURL(r)};try{const t=ft(n,s?"loadeddata":"load",e);n.src=r,await t;const i=n instanceof HTMLVideoElement?n.videoWidth:n.naturalWidth,a=n instanceof HTMLVideoElement?n.videoHeight:n.naturalHeight;return{source:n,width:i,height:a,duration:n instanceof HTMLVideoElement?n.duration:0,animated:s,async seek(t,e){if(!(n instanceof HTMLVideoElement))return;if(!Number.isFinite(n.duration)||n.duration<=0)throw new Error("Video duration is unavailable.");const i=Math.max(0,Math.min(n.duration-.001,t%n.duration));if(Math.abs(n.currentTime-i)<.001&&n.readyState>=2)return;const a=ft(n,"seeked",e);n.currentTime=i,await a},frame:()=>n,destroy:o}}catch(t){throw o(),t}}var gt=t=>{if(t?.aborted)throw new DOMException("Export cancelled","AbortError")};async function pt(t,e){const{format:i,signal:a}=e,s=Math.round(e.width),r=Math.round(e.height);if(!Number.isFinite(s)||!Number.isFinite(r)||s<2||r<2||s>4096||r>4096||s*r>16777216)throw new Error("Choose export dimensions between 2 and 4096 pixels.");if(!["png","jpeg","mp4","webm","gif"].includes(i))throw new Error("Unknown export format.");if(void 0!==e.fps&&!Number.isFinite(e.fps))throw new Error("Frames per second must be finite.");const n=Math.max(1,Math.min(60,Math.round(e.fps??24))),o=e.duration??5;if(!Number.isFinite(o)||o<=0||o>60)throw new Error("Choose a duration from 0 to 60 seconds.");const h="png"===i||"jpeg"===i,l=e.time??0;if(!Number.isFinite(l)||l<0)throw new Error("Image time must be a finite non-negative number.");if(void 0!==e.motionTime&&(!Number.isFinite(e.motionTime)||e.motionTime<0))throw new Error("Motion time must be a finite non-negative number.");if(!h&&s*r>8294400)throw new Error("Video exports support up to 3840 × 2160 pixels.");if("gif"===i&&(s*r>921600||o*n>600))throw new Error("GIF export supports up to 1280 × 720 and 600 frames. Use MP4 for larger exports.");if(void 0!==e.referenceWidth&&(!Number.isFinite(e.referenceWidth)||e.referenceWidth<1))throw new Error("Reference width must be a positive number.");if("gif"===i&&n>30)throw new Error("GIF exports support up to 30 fps. Choose MP4 or WebM for higher frame rates.");const c=document.createElement("canvas");let d;try{if(gt(a),e.onProgress?.(0),h){if(await t(c,l,s,r,a,e.motionTime),"unavailable"===c.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");gt(a);const n=await new Promise((t,a)=>c.toBlob(e=>e?t(e):a(new Error("Image export failed.")),"png"===i?"image/png":"image/jpeg",e.quality??.92));return gt(a),e.onProgress?.(1),n}const m=Math.ceil(o*n);if("gif"===i){const i=await import("gifenc"),{GIFEncoder:h,quantize:l,applyPalette:d}="function"==typeof i.GIFEncoder?i:i.default,f=h(),u=c.getContext("2d");for(let i=0;i<m;i++){gt(a);const h=i/n;if(await t(c,h,s,r,a),gt(a),"unavailable"===c.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");const g=u.getImageData(0,0,s,r).data,p=l(g,256),M=d(g,p);f.writeFrame(M,s,r,{palette:p,delay:10*(Math.round(100*Math.min((i+1)/n,o))-Math.round(100*i/n)),repeat:0}),e.onProgress?.((i+1)/m*.98),await new Promise(t=>setTimeout(t,0))}return gt(a),f.finish(),e.onProgress?.(1),new Blob([new Uint8Array(f.bytes())],{type:"image/gif"})}const{Output:f,Mp4OutputFormat:u,WebMOutputFormat:g,BufferTarget:p,CanvasSource:M,canEncodeVideo:w}=await import("mediabunny"),v="mp4"===i?"avc":"vp9";if(!await w(v,{width:s,height:r}))throw new Error(`${i.toUpperCase()} encoding is unavailable in this browser. Try another format or a current browser with WebCodecs.`);const b=new f({format:"mp4"===i?new u({fastStart:"in-memory"}):new g,target:new p});c.width=s,c.height=r,d=()=>b.cancel();const y=new M(c,{codec:v,bitrate:Math.max(5e5,Math.round(s*r*n*.15))});b.addVideoTrack(y,{frameRate:n}),c.width=s,c.height=r,await b.start();for(let i=0;i<m;i++){gt(a);const h=i/n;if(await t(c,h,s,r,a),gt(a),"unavailable"===c.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");await y.add(h,Math.min(1/n,o-h)),e.onProgress?.((i+1)/m*.98),i%4==0&&await new Promise(t=>setTimeout(t,0))}return y.close(),gt(a),await b.finalize(),gt(a),d=void 0,e.onProgress?.(1),new Blob([b.target.buffer],{type:"mp4"===i?"video/mp4":"video/webm"})}catch(t){throw await(d?.().catch(()=>{})),t}finally{c.width=c.height=1}}async function Mt(t,e,i){let a;const s=I(e),r="png"!==i.format&&"jpeg"!==i.format;try{return await pt(async(e,n,o,h,l,c)=>{a??(a=mt(e,s,{maxDimension:4096,maxCells:i.maxCells??12e3,pixelRatio:o/(i.referenceWidth??Math.min(o,960))})),r&&a.invalidate(),a.render(await t.frame(n,l),n,o,h,c)},i)}finally{a?.destroy()}}async function wt(t,e,i={}){const a=await ut(e,i.signal);try{return vt(t,a,i)}catch(t){throw a.destroy(),t}}function vt(t,e,i={}){let a=I(i.settings),s=i.width??e.width,n=i.height??e.height;const o=mt(t,a,i),h=new r;let l=0,c=!1,d=!0,m=!1,f=!0,u=0,g=0,p=0,M=0,w=-1,v=!1!==i.adaptive,b=0,y=0,x=0;const E=matchMedia("(prefers-reduced-motion: reduce)"),k=e.source instanceof HTMLVideoElement?e.source:null,A=()=>{c||l||!f||document.hidden||(l=requestAnimationFrame(P))},S=()=>!m&&!E.matches&&f&&!document.hidden,F=()=>{k&&(k.loop=!0,S()?k.play().catch(()=>{m=!0,d=!0,A()}):k.pause()),p=0,d=!0,A()};function P(t){if(l=0,c||!f||document.hidden)return;const r=S();r&&(u+=p?Math.min(.1,(t-p)/1e3):0),p=t;const E=V(a),F=r&&(e.animated||E),P=k?.getVideoPlaybackQuality?.().totalVideoFrames??-1,T=!k||P<0||P!==w;if(d||o.active||F&&(T||E)&&t-M>=1e3/Math.max(1,Math.min(60,i.fps??60))-.5){const r=performance.now();try{e.animated&&!k&&o.invalidate();const[t,l]=O(s,n,a);g=h.update(u,a.motion.type,a.motion.speed),o.render(e.frame(k?.currentTime??u),u,t,l,g);const c=performance.now()-r;i.onFrame?.(k?.currentTime??u,c),y=y?.9*y+.1*c:c,++b>20&&v&&(F||o.active)&&(x=y>13?x+1:0,x>=12&&o.maxCells>3e3&&(o.setBudget(Math.max(3e3,.8*o.maxCells)),i.onQualityChange?.(o.maxCells),x=0,y=0))}catch(t){m=!0,i.onError?.(t instanceof Error?t:new Error(String(t)))}d=!1,M=t,w=P}r&&(F||o.active)&&A()}const T=e=>{if(!S())return;const i=t.getBoundingClientRect();o.pointer((e.clientX-i.left)/i.width,(e.clientY-i.top)/i.height,e.timeStamp),A()},C=()=>{o.leave(),A()},R=new IntersectionObserver(([t])=>{f=t.isIntersecting,F()});R.observe(t),t.addEventListener("pointermove",T),t.addEventListener("pointerleave",C),t.addEventListener("pointercancel",C),document.addEventListener("visibilitychange",F),E.addEventListener("change",F);const L=()=>{c||(c=!0,cancelAnimationFrame(l),R.disconnect(),t.removeEventListener("pointermove",T),t.removeEventListener("pointerleave",C),t.removeEventListener("pointercancel",C),document.removeEventListener("visibilitychange",F),E.removeEventListener("change",F),i.signal?.removeEventListener("abort",L),o.destroy(),e.destroy())};if(i.signal?.addEventListener("abort",L,{once:!0}),i.signal?.aborted)throw L(),new DOMException("Cancelled","AbortError");return F(),{canvas:t,media:e,update(t){a=D(a,t),o.configure(a),d=!0,A()},resize(t,e,i){void 0!==i&&o.setPixelRatio(i),s=Math.max(2,t),n=Math.max(2,e),d=!0,A()},pause(t=!0){m=t,F()},async seek(t){u=Math.max(0,t),await e.seek(u),o.invalidate(),d=!0,A()},redraw(){o.invalidate(),d=!0,A()},get time(){return k?.currentTime??u},get settings(){return I(a)},get motionTime(){return g},get paused(){return m||E.matches},setAdaptive(t){v=t,b=x=y=0},setBudget(t){o.setBudget(t),i.onQualityChange?.(o.maxCells),d=!0,A()},get pixelRatio(){return o.pixelRatio},get maxCells(){return o.maxCells},get capabilities(){return o.capabilities},destroy:L}}var bt={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")},yt=Object.keys(bt);async function xt(t,e="Standard",i="#ffffff",a="#080808"){if(!Object.prototype.hasOwnProperty.call(bt,e))throw new Error("Unknown text font.");const{default:s}=await import("figlet/browser"),r=await bt[e]();s.parseFont(e,r.default),s.defaults({fetchFontIfMissing:!1});const n=s.textSync(t.slice(0,120),{font:e}),o=n.split("\n"),h=Math.max(1,...o.map(t=>t.length)),l=Math.max(1,o.length),c=Math.min(1,2048/(9*h)),d=document.createElement("canvas");d.width=Math.ceil(9*h*c+32),d.height=Math.ceil(15*l*c+32);const m=d.getContext("2d");return null!==a&&(m.fillStyle=a,m.fillRect(0,0,d.width,d.height)),m.fillStyle=i,m.font=15*c+"px monospace",m.textBaseline="top",o.forEach((t,e)=>m.fillText(t,16,16+15*e*c)),{canvas:d,ascii:n}}var Et={standard:{label:"Classic ASCII",chars:" .:-=+*#%@"},asciify:{label:"Asciify",chars:" .:-=+ASCIIFY#@"},minimal:{label:"Minimal",chars:" .:+"},detailed:{label:"Detailed",chars:" .,:;i1tfLCG08@"},letters:{label:"Letters",chars:" .ilLCFTYASMW"},technical:{label:"Technical",chars:" .:;>_/[{}]=+*#@$"},blocks:{label:"Tonal blocks",chars:" ░▒▓█"},braille:{label:"Braille",chars:" ⠁⠃⠇⡇⣇⣧⣷⣿"}},kt=Et,At=8,St=t=>t&&"object"==typeof t&&!Array.isArray(t)?t:{},Ft=(t,e,i,a)=>"number"==typeof t&&Number.isFinite(t)?Math.max(i,Math.min(a,t)):e,Pt=(t,e)=>{if("string"!=typeof t||!/^[a-zA-Z0-9][a-zA-Z0-9:_-]{0,63}$/.test(t))throw new Error(`${e} must be 1–64 letters, numbers, colons, dashes or underscores, starting with a letter or number.`);return t};function Tt(t={}){const e=St(t);if(void 0!==e.kind&&"asciify-project"!==e.kind||void 0!==e.version&&1!==e.version)throw new Error("Unsupported Studio project. Update asciify-engine.");if(void 0!==e.layers&&!Array.isArray(e.layers))throw new Error("Project layers must be an array.");const i=Array.isArray(e.layers)?e.layers:[];if(i.length>8)throw new Error("A project supports up to 8 layers.");const a=new Set;return{kind:"asciify-project",version:1,width:Math.round(Ft(e.width,1280,2,4096)),height:Math.round(Ft(e.height,720,2,4096)),background:null===e.background?null:"string"==typeof e.background&&/^#[a-f\d]{6}$/i.test(e.background)?e.background:"#0c1711",pointerMode:"all"===e.pointerMode?"all":"top",layers:i.map((t,e)=>{const i=St(t),s=St(i.placement),r=St(i.settings),n=St(r.backdrop),o=Pt(i.id,"Layer id"),h=Pt(i.source,"Source key");if(a.has(o))throw new Error(`Duplicate layer id: ${o}`);return a.add(o),{id:o,source:h,name:"string"==typeof i.name?i.name.slice(0,80):`Layer ${e+1}`,visible:!1!==i.visible,opacity:Ft(i.opacity,1,0,1),blend:k.includes(i.blend)?i.blend:"source-over",placement:{x:Ft(s.x,.5,-1,2),y:Ft(s.y,.5,-1,2),width:Ft(s.width,1,.01,2),height:Ft(s.height,1,.01,2),rotation:Ft(s.rotation,0,-180,180),flipX:!0===s.flipX,flipY:!0===s.flipY},settings:I({...r,backdrop:{mode:"transparent",...n}})}})}}function Ct(t,e,i){if(!t.layers.some(t=>t.id===e))throw new Error(`Unknown layer: ${e}`);return Tt({...t,layers:t.layers.map(t=>t.id!==e?t:{...t,...i,id:e,placement:{...t.placement,...i.placement},settings:D(t.settings,i.settings??{})})})}var It=t=>JSON.stringify(Tt(t));function Rt(t){if(t.length>1e6)throw new Error("Project exceeds the 1 MB settings limit.");const e=JSON.parse(t);if("asciify-project"!==e?.kind||1!==e.version||!Array.isArray(e.layers))throw new Error("This is not an Asciify layered project.");return Tt(e)}function Lt(t,e,i,a,s){const r=t.placement,n=r.rotation*Math.PI/180,o=Math.cos(n),h=Math.sin(n),l=(e-r.x)*a,c=(i-r.y)*s,d=(l*o+c*h)/(r.width*a),m=(-l*h+c*o)/(r.height*s);return[.5+d*(r.flipX?-1:1),.5+m*(r.flipY?-1:1)]}function Nt(t){return t.layers.filter(e=>{if(!e.visible||e.opacity<=0)return!1;const i=e.placement,a=i.rotation*Math.PI/180,s=Math.abs(Math.cos(a)),r=Math.abs(Math.sin(a)),n=(s*i.width*t.width+r*i.height*t.height)/2,o=(r*i.width*t.width+s*i.height*t.height)/2;return i.x*t.width+n>0&&i.x*t.width-n<t.width&&i.y*t.height+o>0&&i.y*t.height-o<t.height})}function Ot(t,e=24e3,i=4194304,a=t.width,s=t.height){const r=Nt(t),n=Math.round(Ft(e,24e3,2048,1048576)),o=Ft(i,4194304,65536,16777216),h=r.map(t=>t.placement.width*t.placement.height),l=h.reduce((t,e)=>t+e,0),c=n-256*r.length,d=r.map(t=>{const e=a*t.placement.width,i=s*t.placement.height,r=Math.min(1,4096/Math.max(e,i));return{width:Math.max(2,e*r),height:Math.max(2,i*r)}}),m=d.reduce((t,e)=>t+e.width*e.height,0);let f=0,u=0;return r.map((t,e)=>{const i=e===r.length-1?n-f:256+Math.floor(c*h[e]/l);f+=i;const a=d[e],s=e===r.length-1?o-u:4+Math.floor((o-4*r.length)*a.width*a.height/Math.max(1,m));u+=s;const g=Math.min(1,Math.sqrt(s/(a.width*a.height)));let p=Math.max(2,Math.floor(a.width*g)),M=Math.max(2,Math.floor(a.height*g));return p*M>s&&(p>=M?p=Math.max(2,Math.floor(s/M)):M=Math.max(2,Math.floor(s/p))),{id:t.id,maxCells:i,width:p,height:M}})}function Dt(t,e={},i={}){const a=t.getContext("2d");if(!a)throw new Error("Project canvas is already owned by another renderer.");let s=Tt(e),r=!0,n=!1,o=new Map(s.layers.map(t=>[t.id,JSON.stringify(t.settings)]));const h=Math.max(64,Math.min(4096,Number.isFinite(i.maxDimension)?i.maxDimension:960)),l=Math.max(2048,Math.min(1048576,Number.isFinite(i.maxCells)?i.maxCells:24e3));let c=l,d=Math.max(.1,Math.min(8,Number.isFinite(i.pixelRatio)?i.pixelRatio:1)),m=[];const f=new Map,u=()=>{if(n)throw new Error("Project renderer has been destroyed.")};return{canvas:t,render(e,n=0,g=s.width,p=s.height,M={}){if(u(),!Number.isFinite(g)||!Number.isFinite(p)||g<2||p<2)throw new Error("Project dimensions must be positive finite numbers.");const w=Math.min(1,h/Math.max(g,p)),v=Math.max(2,Math.round(g*w)),b=Math.max(2,Math.round(p*w));t.width===v&&t.height===b||(t.width=v,t.height=b,r=!0);const y={...s,width:v,height:b},x=Nt(y);for(const t of x)if(!e.has(t.source))throw new Error(`Missing project source: ${t.source}`);const E=new Set(x.map(t=>t.id));for(const[t,e]of f)E.has(t)||(e.renderer.destroy(),f.delete(t),r=!0);m=Ot(y,c,i.maxRasterPixels,v,b);for(let t=0;t<x.length;t++){const i=x[t],a=m[t],s=e.get(i.source);if(!s)throw new Error(`Missing project source: ${i.source}`);let h=f.get(i.id);const c=o.get(i.id);h?h.signature!==c&&(h.renderer.configure(i.settings),h.signature=c,h.dirty=!0):(h={renderer:mt(document.createElement("canvas"),i.settings,{maxDimension:4096,maxCells:l}),signature:c,dirty:!0,geometry:""},f.set(i.id,h));const u=d*a.width/(g*i.placement.width),p=`${a.width}:${a.height}:${a.maxCells}:${u}`;h.geometry!==p&&(h.renderer.setBudget(a.maxCells),h.renderer.setPixelRatio(u),h.geometry=p,h.dirty=!0);const w="currentTime"in s?s.getVideoPlaybackQuality?.().totalVideoFrames??s.currentTime:0;if(h.dirty||h.source!==s||h.stamp!==w||h.renderer.active||V(i.settings)){const t=Object.prototype.hasOwnProperty.call(M,i.id)?M[i.id]:void 0;h.renderer.render(s,n,a.width,a.height,t),h.dirty=!1,h.source=s,h.stamp=w,r=!0}}if(!r)return!1;a.clearRect(0,0,v,b),a.globalCompositeOperation="source-over",a.globalAlpha=1,null!==s.background&&(a.fillStyle=s.background,a.fillRect(0,0,v,b));let k="none";for(const t of x){const e=f.get(t.id),i=t.placement;a.save(),a.globalAlpha=t.opacity,a.globalCompositeOperation=t.blend;try{a.translate(i.x*v,i.y*b),a.rotate(i.rotation*Math.PI/180),a.scale(i.flipX?-1:1,i.flipY?-1:1),a.drawImage(e.renderer.canvas,-i.width*v/2,-i.height*b/2,i.width*v,i.height*b)}finally{a.restore()}"unavailable"===e.renderer.canvas.dataset.studioFinish?k="unavailable":"unavailable"!==k&&"gpu"===e.renderer.canvas.dataset.studioFinish&&(k="gpu")}return a.globalAlpha=1,a.globalCompositeOperation="source-over",t.dataset.studioFinish=k,r=!1,!0},configure(t){u(),s=Tt(t),o=new Map(s.layers.map(t=>[t.id,JSON.stringify(t.settings)])),(()=>{const t=new Set(Nt(s).map(t=>t.id));for(const[e,i]of f)t.has(e)||(i.renderer.destroy(),f.delete(e))})(),r=!0},pointer(e,i,a){if(n||!Number.isFinite(e)||!Number.isFinite(i))return;if(e<0||e>1||i<0||i>1){for(const t of f.values())t.renderer.leave();return}let r=!1;for(const n of Nt({...s,width:t.width,height:t.height}).reverse()){const o=f.get(n.id);if(!o)continue;const[h,l]=Lt(n,e,i,t.width,t.height);(!r||"all"===s.pointerMode)&&h>=0&&h<=1&&l>=0&&l<=1&&"none"!==n.settings.hover.effect&&n.settings.hover.strength>0?(o.renderer.pointer(h,l,a),r=!0):o.renderer.leave()}},leave(){for(const t of f.values())t.renderer.leave()},invalidate(t){u();for(const e of s.layers)if(void 0===t||t===e.source){const t=f.get(e.id);t&&(t.renderer.invalidate(),t.dirty=!0)}r=!0},setBudget(t){u(),c=Math.max(2048,Math.min(l,Number.isFinite(t)?Math.round(t):l)),r=!0},setPixelRatio(t){u(),d=Math.max(.1,Math.min(8,Number.isFinite(t)?t:1)),r=!0},get maxCells(){return c},get pixelRatio(){return d},get quality(){return m.map(t=>({...t}))},get active(){return[...f.values()].some(t=>t.renderer.active)},destroy(){if(!n){n=!0;for(const t of f.values())t.renderer.destroy();f.clear(),t.width=t.height=1}}}}function Xt(t,e){for(const i of t.layers)if(!e.has(i.source))throw new Error(`Missing project source: ${i.source}`)}async function Ut(t,e,i){const a=Object.entries(e),s=new Map;if(a.length>8)throw new Error("A project supports up to 8 media bindings.");Xt(t,new Map(a));try{for(const[t,e]of a){if(i?.aborted)throw new DOMException("Cancelled","AbortError");if("string"==typeof e||"undefined"!=typeof File&&e instanceof File)s.set(t,await ut(e,i));else{if(!e||"object"!=typeof e||!("text"in e)||"string"!=typeof e.text)throw new Error(`Invalid project source: ${t}`);{const i=e,{canvas:a}=await xt(i.text,i.font,i.ink??"#ffffff",null);s.set(t,{source:a,width:a.width,height:a.height,duration:0,animated:!1,frame:()=>a,seek:async()=>{},destroy:()=>{a.width=a.height=1}})}}}if(i?.aborted)throw new DOMException("Cancelled","AbortError");return s}catch(t){for(const t of s.values())t.destroy();throw t}}async function jt(t,e,i,a={}){const s=Tt(e),r=await Ut(s,i,a.signal);try{return Yt(t,s,r,a)}catch(t){for(const t of new Set(r.values()))t.destroy();throw t}}function Yt(t,e,i,a={}){if((i=new Map(i)).size>8)throw new Error("A project supports up to 8 media bindings.");let s=Tt(e);if(Xt(s,i),a.signal?.aborted)throw new DOMException("Cancelled","AbortError");const n=Dt(t,s,a),o=matchMedia("(prefers-reduced-motion: reduce)"),h=[...new Set(i.values())],l=h.filter(t=>t.source instanceof HTMLVideoElement).map(t=>t.source),c=new Map;let d,m={},f=0,u=0,g=0,p=0,M=!0,w=!1,v=!0,b=!1,y=!1!==a.adaptive,x=0,E=0,k=0,A=s.width,S=s.height,F=0,P=!1;const T=new WeakSet,C=Math.max(1,Math.min(60,Number.isFinite(a.fps)?a.fps:60)),I=()=>!b&&!w&&!P&&!o.matches&&v&&!document.hidden,R=()=>{b||p||!v||document.hidden||(p=requestAnimationFrame(D))},L=()=>new Set(Nt({...s,width:A,height:S}).map(t=>i.get(t.source).source)),N=()=>{const t=L();for(const e of l)e.loop=!0,I()&&t.has(e)?e.paused&&!T.has(e)&&(T.add(e),e.play().then(()=>{T.delete(e),I()&&L().has(e)||e.pause()}).catch(t=>{T.delete(e),b||(w=!0,N(),a.onError?.(t instanceof Error?t:new Error(String(t))),M=!0,R())})):e.pause()},O=()=>{u=0,M=!0,N(),R()};function D(t){if(p=0,b||!v||document.hidden)return;const e=I();e&&(f+=u?Math.min(.1,(t-u)/1e3):0),u=t;const o=Nt({...s,width:A,height:S}),h=o.some(t=>i.get(t.source).animated||V(t.settings));if(M||e&&n.active||e&&h&&t-g>=1e3/C-.5){const s=performance.now();try{const t=new Map,l=new Set(o.map(t=>t.source));for(const a of l){const s=i.get(a);!s.animated||s.source instanceof HTMLVideoElement||!e||n.invalidate(a),t.set(a,s.frame(f))}m={};for(const t of o){let e=c.get(t.id);e||(e=new r,c.set(t.id,e)),m[t.id]=e.update(f,t.settings.motion.type,t.settings.motion.speed)}n.render(t,f,A,S,m);const d=performance.now()-s;a.onFrame?.(f,d),E=E?.9*E+.1*d:d,++x>20&&y&&e&&(h||n.active)&&(k=E>13?k+1:0,k>=12&&n.maxCells>2048&&(n.setBudget(Math.max(2048,.8*n.maxCells)),a.onQualityChange?.(n.maxCells),E=k=0,M=!0))}catch(t){w=!0,N(),a.onError?.(t instanceof Error?t:new Error(String(t)))}M=!1,g=t}e&&(h||n.active)&&R()}const X=e=>{if(!I())return;const i=t.getBoundingClientRect();i.width&&i.height&&(n.pointer((e.clientX-i.left)/i.width,(e.clientY-i.top)/i.height,e.timeStamp),R())},U=()=>{n.leave(),R()},j=new IntersectionObserver(([t])=>{v=t.isIntersecting,O()});j.observe(t),t.addEventListener("pointermove",X),t.addEventListener("pointerleave",U),t.addEventListener("pointercancel",U),document.addEventListener("visibilitychange",O),o.addEventListener("change",O);const Y=()=>{if(!b){b=!0,F++,d?.abort(),cancelAnimationFrame(p),p=0,j.disconnect(),t.removeEventListener("pointermove",X),t.removeEventListener("pointerleave",U),t.removeEventListener("pointercancel",U),document.removeEventListener("visibilitychange",O),o.removeEventListener("change",O),a.signal?.removeEventListener("abort",Y),n.destroy();for(const t of h)t.destroy();c.clear()}};a.signal?.addEventListener("abort",Y,{once:!0});const q=()=>{if(b)throw new Error("Project player has been destroyed.")},B=t=>{q();const e=Tt(t);Xt(e,i),A===s.width&&S===s.height&&(A=e.width,S=e.height),s=e,n.configure(s);for(const t of c.keys())s.layers.some(e=>e.id===t)||c.delete(t);O()};return O(),{canvas:t,get project(){return Tt(s)},get time(){return f},get motionTimes(){return{...m}},get paused(){return w||o.matches},get maxCells(){return n.maxCells},get pixelRatio(){return n.pixelRatio},get quality(){return n.quality},update:B,updateLayer:(t,e)=>B(Ct(s,t,e)),resize(t,e,i){if(q(),!Number.isFinite(t)||!Number.isFinite(e)||t<2||e<2)throw new Error("Project dimensions must be positive finite numbers.");A=t,S=e,void 0!==i&&n.setPixelRatio(i),O()},pause(t=!0){q(),w=t,O()},async seek(t){if(q(),!Number.isFinite(t)||t<0)throw new Error("Project time must be finite and non-negative.");const e=++F;d?.abort(),d=new AbortController;const i=d.signal;P=!0,N();try{if(await Promise.all(h.map(e=>e.seek(t,i))),b||e!==F)return;f=t,c.clear(),n.invalidate()}finally{b||e!==F||(P=!1,O())}},redraw(){q(),n.invalidate(),M=!0,R()},setBudget(t){q(),n.setBudget(t),a.onQualityChange?.(n.maxCells),M=!0,R()},setAdaptive(t){y=t,x=k=E=0},destroy:Y}}async function qt(t,e,i){const a=Tt(t),s={...i.motionTimes};if(Object.values(s).some(t=>!Number.isFinite(t)||t<0))throw new Error("Layer motion times must be finite non-negative numbers.");const r=Object.fromEntries(Object.entries(e).map(([t,e])=>[t,e&&"object"==typeof e&&"text"in e&&"string"==typeof e.text?{...e}:e]));let n,o;const h=new AbortController,l=()=>h.abort();i.signal?.aborted?l():i.signal?.addEventListener("abort",l,{once:!0});const c="png"===i.format||"jpeg"===i.format;try{return await pt(async(t,e,h,l,d)=>{o??(o=await Ut(a,r,d)),n??(n=Dt(t,a,{maxDimension:4096,maxCells:i.maxCells??24e3,maxRasterPixels:i.maxRasterPixels,pixelRatio:h/(i.referenceWidth??Math.min(h,960))}));const m=new Set(Nt({...a,width:h,height:l}).map(t=>t.source)),f=new Map;await Promise.all([...m].map(async t=>{const i=o.get(t);await i.seek(e,d),f.set(t,i.frame(e)),i.animated&&n.invalidate(t)})),n.render(f,e,h,l,c?s:{})},{...i,signal:h.signal})}finally{if(h.abort(),i.signal?.removeEventListener("abort",l),n?.destroy(),o)for(const t of new Set(o.values()))t.destroy()}}export{k as BLEND_MODES,Et as CHARACTER_SETS,S as DEFAULT_STUDIO_SETTINGS,E as DITHER_ALGORITHMS,At as MAX_STUDIO_LAYERS,p as MAX_STUDIO_WARPS,kt as STUDIO_CHARACTER_SETS,h as STUDIO_CURVE_CHANNELS,t as STUDIO_HOVERS,U as STUDIO_LOOKS,e as STUDIO_MOTIONS,A as STUDIO_PALETTES,x as STUDIO_STYLES,yt as STUDIO_TEXT_FONTS,g as STUDIO_WARPS,m as createStudioCurveLookup,Dt as createStudioProjectRenderer,mt as createStudioRenderer,xt as createStudioText,Mt as exportStudio,qt as exportStudioProject,ut as loadStudioMedia,wt as mountStudio,vt as mountStudioMedia,jt as mountStudioProject,Yt as mountStudioProjectMedia,c as normalizeStudioCurve,d as normalizeStudioCurves,Tt as normalizeStudioProject,I as normalizeStudioSettings,w as normalizeStudioWarps,Rt as parseStudioProject,L as parseStudioSettings,Y as restyleStudio,It as serializeStudioProject,R as serializeStudioSettings,N as studioCrop,O as studioDimensions,X as studioGrid,Lt as studioLayerPoint,j as studioLook,Ot as studioProjectBudget,ht as studioSourceSize,Ct as updateStudioProjectLayer,D as updateStudioSettings,Nt as visibleStudioLayers};//# sourceMappingURL=studio.js.map
@@ -0,0 +1,24 @@
1
+ import { mountStudioProject, exportStudioProject, normalizeStudioProject, serializeStudioProject, parseStudioProject,
2
+ type StudioLayerPatch, type StudioProjectSources } from 'asciify-engine/studio';
3
+
4
+ /** A live local component; accessible titles and controls stay in HTML. */
5
+ export async function createLayeredComposition(canvas:HTMLCanvasElement,photo:File|string,signal?:AbortSignal) {
6
+ const sources:StudioProjectSources={photo,headline:{text:'ASCIIFY',font:'Small'}};
7
+ const project=normalizeStudioProject({width:1280,height:720,background:'#0c1711',layers:[
8
+ {id:'photo',source:'photo',name:'Photograph',settings:{ink:'#97b6a0',motion:{type:'parallax',amount:.3,speed:1},hover:{effect:'trail',radius:.45,strength:.55}}},
9
+ {id:'title',source:'headline',name:'Title',placement:{width:.8,height:.25},settings:{ink:'#b3ed82',cellSize:3,hover:{effect:'elastic',radius:.4,strength:.5}}},
10
+ ]});
11
+ const player=await mountStudioProject(canvas,project,sources,{maxDimension:1280,maxCells:24000,maxRasterPixels:2097152,signal});
12
+ return {player,
13
+ updateLayer:(id:string,patch:StudioLayerPatch)=>player.updateLayer(id,patch),
14
+ save:()=>serializeStudioProject(player.project),
15
+ restore:(json:string)=>player.update(parseStudioProject(json)),
16
+ exportPng:(signal?:AbortSignal)=>exportStudioProject(player.project,sources,{format:'png',width:1280,height:720,
17
+ referenceWidth:canvas.width/player.pixelRatio,maxCells:player.maxCells,time:player.time,motionTimes:player.motionTimes,signal}),
18
+ // One moving layer has a 12-second cycle. Media, other speeds and
19
+ // temporal finishing can change the combined loop period.
20
+ exportMp4:(signal?:AbortSignal)=>exportStudioProject(player.project,sources,{format:'mp4',width:1280,height:720,duration:12,fps:24,
21
+ referenceWidth:canvas.width/player.pixelRatio,maxCells:player.maxCells,signal}),
22
+ destroy:()=>player.destroy(),
23
+ };
24
+ }
@@ -3,7 +3,6 @@ import {
3
3
  loadStudioMedia,
4
4
  exportStudio,
5
5
  normalizeStudioSettings,
6
- updateStudioSettings,
7
6
  serializeStudioSettings,
8
7
  parseStudioSettings,
9
8
  type StudioInput,
@@ -16,7 +15,7 @@ export async function createComposition(
16
15
  source: File | string,
17
16
  signal?: AbortSignal,
18
17
  ) {
19
- let settings = normalizeStudioSettings({
18
+ const settings = normalizeStudioSettings({
20
19
  style: 'ascii',
21
20
  cellSize: 6,
22
21
  ink: '#b3ed82',
@@ -55,13 +54,11 @@ export async function createComposition(
55
54
  return {
56
55
  player,
57
56
  update(patch: StudioInput) {
58
- settings = updateStudioSettings(settings, patch);
59
- player.update(settings);
57
+ player.update(patch);
60
58
  },
61
- saveLook: () => serializeStudioSettings(settings),
59
+ saveLook: () => serializeStudioSettings(player.settings),
62
60
  restoreLook(json: string) {
63
- settings = parseStudioSettings(json);
64
- player.update(settings);
61
+ player.update(parseStudioSettings(json));
65
62
  },
66
63
  exportPng: (signal?: AbortSignal) => exportComposition('png', signal),
67
64
  exportMp4: (signal?: AbortSignal) => exportComposition('mp4', signal),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "asciify-engine",
3
- "version": "4.6.0",
3
+ "version": "4.8.0",
4
4
  "description": "Framework-agnostic ASCII art engine. Convert images, videos, and GIFs into ASCII art rendered on canvas.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -56,6 +56,7 @@
56
56
  "LICENSE",
57
57
  "examples/media-background.ts",
58
58
  "examples/studio-composition.ts",
59
+ "examples/layered-composition.ts",
59
60
  "THIRD_PARTY.md",
60
61
  "licenses"
61
62
  ],
@@ -2,13 +2,13 @@
2
2
  name: asciify-engine
3
3
  description: Build and tune browser ASCII images, video, GIFs, text, and interactive heroes with asciify-engine. Use for media conversion, character and color choices, hover integration, layered HTML typography, scroll-synced video, and rendering performance in apps using this package.
4
4
  metadata:
5
- tested-engine: "4.6.0"
5
+ tested-engine: "4.8.0"
6
6
  updated: "2026-10-07"
7
7
  ---
8
8
 
9
9
  # Asciify Engine
10
10
 
11
- Use the published `asciify-engine` npm package for browser canvas rendering. Tested against **4.6.0**. Check the application's installed version and its public types before using newer options; a local checkout can contain unpublished changes.
11
+ Use the published `asciify-engine` npm package for browser canvas rendering. Tested against **4.8.0**. Check the application's installed version and its public types before using newer options; a local checkout can contain unpublished changes.
12
12
 
13
13
  - Agent entry: https://asciify.org/skill (redirects to this Markdown document).
14
14
  - Playground: https://asciify.org/editor
@@ -141,6 +141,8 @@ For optional wallpaper/backdrops, alternate renderers, palettes, masks, saved lo
141
141
 
142
142
  ## Current catalogs
143
143
 
144
+ For multiple media/text layers in one live component, use 4.8+ `mountStudioProject` and read [layered-projects.md](references/layered-projects.md). It shares one playback loop and rendering budgets across up to eight independently styled layers. Persist source keys separately from media, and use `exportStudioProject` for independent exports. Do not create one mounted Studio instance per layer or rasterize accessible interface text.
145
+
144
146
  Legacy `CHARSETS`, `ART_STYLE_PRESETS`, `CHARSET_SEQUENCES`, `LIVING_STYLE_PRESETS` and their key types are removed. Do not import them or generate old names such as Katakana, Binary, Waves or Smoke. Use the 18 `STUDIO_STYLES` for render-style selectors and `/studio` rendering. For ASCII-only character ramps use `CHARACTER_SETS` from `/core` or `STUDIO_CHARACTER_SETS` from `/studio`; custom Unicode and user-provided frame arrays remain supported. Core `artStyle` only accepts `classic`; use explicit options instead of preset shortcuts. Despite the requested 4.1.0 version number, migrating these removed APIs is a breaking change.
145
147
 
146
148
 
@@ -151,3 +153,5 @@ Studio adds `hex`, `led`, and `cmyk` render styles, directional/radial dither pa
151
153
  From 4.5, `dither.algorithm: 'blue-noise'` uses a precomputed dispersed threshold tile, separate from white `noise`. Studio `color` also accepts `blackPoint`, `whitePoint`, `gamma`, `shadows` and `highlights` to shape detail before conversion. All are neutral by default. Read [tonal detail and blue noise](references/studio-workspace.md#tonal-detail-and-blue-noise-45) before adding these controls; they belong to `/studio`, not core `AsciiOptions`.
152
154
 
153
155
  From 4.6, Studio adds `color.curves` (RGB, red, green, blue) and optional edge-preserving `color.denoise`. `player.settings` returns a detached snapshot for saving or exporting after updates. Read [channel curves and source noise](references/studio-workspace.md#channel-curves-and-source-noise-46) for point limits, update semantics and the processing budget. Do not turn noise reduction on by default or apply it again to the already-rendered characters.
156
+
157
+ From 4.7, Studio supports up to eight ordered source warps: Twirl, Pinch, Spherize, Ripple, Zigzag, Shear, Smudge, Polar and Fragment. Build controls from `STUDIO_WARPS`, retain array order, and read [source shaping](references/source-shaping.md) for bounds, alpha/edge policy and cached-map performance. These shape the source; use `motion.type` to bring a still image to life and `hover.effect` for pointer interaction. Keep them independent, with an empty warp stack by default.
@@ -1,8 +1,8 @@
1
1
  interface:
2
2
  display_name: "Asciify Engine"
3
3
  short_description: "Build fast ASCII media effects"
4
- brand_color: "#E8B900"
5
- default_prompt: "Use $asciify-engine to build a layered ASCII hero with readable HTML text, appropriate performance settings, and lifecycle cleanup."
4
+ brand_color: "#B3ED82"
5
+ default_prompt: "Use $asciify-engine to build interactive ASCII media or layered compositions, keeping HTML controls readable, rendering budgets explicit, and media lifecycles isolated."
6
6
 
7
7
  policy:
8
8
  allow_implicit_invocation: true