asciify-engine 1.4.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2
- package/dist/core.cjs +1 -1
- package/dist/core.d.cts +2 -2
- package/dist/core.d.ts +2 -2
- package/dist/core.js +1 -1
- package/dist/hover.cjs +1 -1
- package/dist/hover.d.cts +1 -1
- package/dist/hover.d.ts +1 -1
- package/dist/hover.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/studio.cjs +1 -1
- package/dist/studio.d.cts +37 -1
- package/dist/studio.d.ts +37 -1
- package/dist/studio.js +1 -1
- package/dist/{types-w2CRgyk6.d.cts → types-Cixur2pN.d.cts} +3 -6
- package/dist/{types-w2CRgyk6.d.ts → types-Cixur2pN.d.ts} +3 -6
- package/package.json +1 -1
- package/skills/asciify-engine/SKILL.md +6 -2
- package/skills/asciify-engine/references/hero-finish.md +1 -1
- package/skills/asciify-engine/references/studio-workspace.md +14 -0
- package/skills/asciify-engine/references/upgrading.md +6 -0
package/dist/studio.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var t=["ascii","blocks","braille","dots","lines","cross","diagonal","diamond","mixed","pixel","mosaic","lego","voxel","disco","dither"],e=["none","bayer2","bayer4","bayer8","bayer16","floyd-steinberg","atkinson","stucki","sierra","sierra-lite","burkes","jarvis","halftone","lines","noise"],i=["source-over","multiply","screen","overlay","soft-light","hard-light","color-dodge","color-burn","hue","saturation","color","luminosity"],s={original:[],mono:["#080808","#f2f2e8"],asciify:["#080808","#625b38","#a19558","#e8b900"],gameboy:["#0f380f","#306230","#8bac0f","#9bbc0f"],cga:["#000000","#55ffff","#ff55ff","#ffffff"],pico8:["#000000","#1d2b53","#7e2553","#008751","#ab5236","#5f574f","#c2c3c7","#fff1e8","#ff004d","#ffa300","#ffec27","#00e436","#29adff","#83769c","#ff77a8","#ffccaa"],c64:["#000000","#ffffff","#880000","#aaffee","#cc44cc","#00cc55","#0000aa","#eeee77","#dd8855","#664400","#ff7777","#333333","#777777","#aaff66","#0088ff","#bbbbbb"],amber:["#100b00","#5f3b00","#c98014","#ffd17c"],ice:["#081b29","#25586e","#69a6b3","#d9ece7"],risograph:["#f4ebd0","#f2594b","#2853a5","#29232e"],sepia:["#201b17","#6b5039","#b49868","#f6e6c5"],nord:["#2e3440","#4c566a","#88c0d0","#eceff4"],dusk:["#211b35","#654271","#c3788c","#f5c9a3"],forest:["#101f1b","#355747","#87a16f","#e4e3ba"],ocean:["#071b33","#17577f","#3fa7a4","#d9efde"],newsprint:["#191919","#666666","#aaaaaa","#eee9df"],custom:["#080808","#e8b900"]},a={version:1,aspectRatio:"original",style:"ascii",cellSize:7,charset:" .:-=+*#%@",colorMode:"accent",ink:"#e8b900",crop:{x:.5,y:.5,zoom:1,rotation:0},backdrop:{mode:"solid",color:"#080808",color2:"#393323",blur:12,opacity:1},color:{brightness:0,contrast:1,saturation:1,grayscale:0,tint:"#e8b900",amount:0,blend:"source-over"},dither:{algorithm:"none",palette:"mono",colors:["#080808","#e8b900"],amount:1,scale:2,threshold:.5,motion:"none",speed:1},mask:{enabled:!1,invert:!1,shapes:[]},lights:[],effects:{bloom:0,characterBloom:0,grain:0,dust:0,scanlines:0,crt:0,prism:0,vignette:0,glitch:0,pixelate:0,blur:0,blurType:"gaussian",angle:0,focus:.5,halftone:0},motion:{type:"none",speed:1},hover:{effect:"trail",strength:.55,radius:.2,edgeSafe:!1}},r=t=>t&&"object"==typeof t&&!Array.isArray(t)?t:{},o=(t,e,i,s)=>"number"==typeof t&&Number.isFinite(t)?Math.min(s,Math.max(i,t)):e,n=(t,e)=>"string"==typeof t&&/^#[\da-f]{6}$/i.test(t)?t:e,h=(t,e,i)=>e.includes(t)?t:i;function l(l={}){const c=r(l),f=a;if(void 0!==c.version&&1!==c.version)throw new Error("Unsupported studio settings version. Update asciify-engine.");const d=r(c.crop),m=r(c.backdrop),u=r(c.color),g=r(c.dither),p=r(c.mask),M=r(c.effects),x=r(c.motion),v=r(c.hover),w={...f.effects};for(const t of["bloom","characterBloom","grain","dust","scanlines","crt","prism","vignette","glitch","pixelate","halftone"])w[t]=o(M[t],0,0,1);w.blur=o(M.blur,0,0,24),w.blurType=h(M.blurType,["gaussian","directional","radial","progressive"],f.effects.blurType),w.angle=o(M.angle,0,-180,180),w.focus=o(M.focus,.5,0,1);let b=2048;return{version:1,aspectRatio:h(c.aspectRatio,["original","16:9","9:16","1:1","4:3","3:4","21:9"],"original"),style:h(c.style,t,f.style),cellSize:o(c.cellSize,7,3,60),charset:"string"==typeof c.charset&&c.charset.length?Array.from(c.charset).slice(0,128).join(""):f.charset,colorMode:h(c.colorMode,["accent","source","gray"],f.colorMode),ink:n(c.ink,f.ink),crop:{x:o(d.x,.5,0,1),y:o(d.y,.5,0,1),zoom:o(d.zoom,1,1,5),rotation:90*Math.round(o(d.rotation,0,-360,360)/90)},backdrop:{mode:h(m.mode,["solid","transparent","source","blurred","gradient"],f.backdrop.mode),color:n(m.color,f.backdrop.color),color2:n(m.color2,f.backdrop.color2),blur:o(m.blur,12,0,32),opacity:o(m.opacity,1,0,1)},color:{brightness:o(u.brightness,0,-1,1),contrast:o(u.contrast,1,0,3),saturation:o(u.saturation,1,0,3),grayscale:o(u.grayscale,0,0,1),tint:n(u.tint,f.color.tint),amount:o(u.amount,0,0,1),blend:h(u.blend,i,f.color.blend)},dither:{algorithm:h(g.algorithm,e,"none"),palette:"string"==typeof g.palette&&Object.prototype.hasOwnProperty.call(s,g.palette)?g.palette:"mono",colors:Array.isArray(g.colors)&&g.colors.length>=2?g.colors.slice(0,32).map(t=>n(t,"#000000")):[...f.dither.colors],amount:o(g.amount,1,0,2),scale:Math.round(o(g.scale,2,1,12)),threshold:o(g.threshold,.5,0,1),motion:h(g.motion,["none","drift","shimmer"],"none"),speed:o(g.speed,1,.1,3)},mask:{enabled:!0===p.enabled,invert:!0===p.invert,shapes:Array.isArray(p.shapes)?p.shapes.slice(0,64).map(t=>{const e=r(t),i=h(e.kind,["rectangle","ellipse","brush"],"rectangle"),s="brush"===i&&Array.isArray(e.points)?e.points.slice(0,b).map(t=>Array.isArray(t)?[Math.round(1e4*o(t[0],0,0,1))/1e4,Math.round(1e4*o(t[1],0,0,1))/1e4]:[0,0]):[];return b-=s.length,{kind:i,x:o(e.x,0,0,1),y:o(e.y,0,0,1),width:o(e.width,.5,0,1),height:o(e.height,.5,0,1),size:o(e.size,.05,.005,.5),points:s}}):[]},lights:Array.isArray(c.lights)?c.lights.slice(0,4).map(t=>{const e=r(t);return{x:o(e.x,.5,0,1),y:o(e.y,.5,0,1),radius:o(e.radius,.3,.02,1),intensity:o(e.intensity,.5,0,1),color:n(e.color,"#ffffff")}}):[],effects:w,motion:{type:h(x.type,["none","breathe","wave","reveal","glitch","rainbow","hologram","fire","chrome","ripple","vapor"],"none"),speed:o(x.speed,1,.1,3)},hover:{effect:h(v.effect,["none","trail","water","contour","dissolve","silk","vortex"],"trail"),strength:o(v.strength,.55,0,1),radius:o(v.radius,.2,.1,1),edgeSafe:!0===v.edgeSafe}}}function c(t){return JSON.stringify(l(t))}function f(t){if(t.length>1e5)throw new Error("Settings exceed 100 KB.");return l(JSON.parse(t))}function d(t,e,i,s,a){const r=Math.abs(a.rotation/90)%2==1,o=r?e:t,n=r?t:e,h=Math.max(i/o,s/n)*a.zoom;return{width:o*h,height:n*h,x:(i-o*h)*a.x,y:(s-n*h)*a.y,scale:h,rotated:r}}function m(t,e,i){if(Math.abs(i.crop.rotation/90)%2==1&&([t,e]=[e,t]),"original"===i.aspectRatio)return[t,e];const[s,a]=i.aspectRatio.split(":").map(Number);return t/e>s/a?[Math.round(e*s/a),e]:[t,Math.round(t*a/s)]}function u(t,e){const i={...t,...e};for(const s of["crop","backdrop","color","dither","mask","effects","motion","hover"])e[s]&&Object.assign(i,{[s]:{...t[s],...e[s]}});return l(i)}var g=[["ascii","Signature ASCII","Brand ink and clean characters.",{}],["print","Newsprint","Fine diffusion on warm paper.",{style:"dither",dither:{algorithm:"floyd-steinberg",palette:"newsprint"}}],["handheld","Pocket camera","Four-tone ordered dither.",{style:"dither",dither:{algorithm:"bayer4",palette:"gameboy",scale:3}}],["riso","Two inks","Limited-color print texture.",{style:"dither",dither:{algorithm:"atkinson",palette:"risograph",scale:2}}],["night","Night signal","Gray characters and optical fringe.",{ink:"#888888",effects:{prism:.7,scanlines:.2,vignette:.3}}],["terminal","Phosphor","Green glyphs with a soft glow.",{ink:"#83efad",effects:{bloom:.4,scanlines:.35,crt:.2}}],["mosaic","Mosaic study","Separated color tiles.",{style:"mosaic",cellSize:14,colorMode:"source"}],["bricks","Brickwork","Colorful studded cells.",{style:"lego",cellSize:18,colorMode:"source"}],["voxel","Little volumes","Three-face isometric tiles.",{style:"voxel",cellSize:22,colorMode:"source"}],["disco","Mirror room","Faceted tiles and warm light.",{style:"disco",cellSize:18,colorMode:"source",lights:[{x:.35,y:.25,radius:.25,intensity:.45,color:"#fff2d4"}]}],["wallpaper","Wallpaper","Living ASCII over a softened source.",{backdrop:{mode:"blurred",blur:18,opacity:.55},ink:"#f2e9c9",motion:{type:"breathe",speed:.5}}],["blueprint","Blueprint","Linework in a cool monochrome.",{style:"lines",ink:"#9bccdf",backdrop:{mode:"solid",color:"#0a1e30"}}]].map(([t,e,i,s])=>({id:t,name:e,description:i,settings:l(s)}));function p(t){const e=g.find(e=>e.id===t);if(!e)throw new Error("Unknown studio look.");return l(e.settings)}function M(t,e=Math.random){const i=g.filter(e=>e.settings.style!==t.style||e.settings.ink!==t.ink),s=p(i[Math.min(i.length-1,Math.max(0,Math.floor(e()*i.length)))].id);return s.aspectRatio=t.aspectRatio,s.crop={...t.crop},s.mask=l(t).mask,s}var x=(t,e)=>{const i=43758.5453*Math.sin(127.1*t+311.7*e);return i-Math.floor(i)};function v(t,e,i){let s=0;for(let a=1;a<i;a*=2){const i=Math.floor(t/a)%2;s=4*s+[[0,2],[3,1]][Math.floor(e/a)%2][i]}return(s+.5)/(i*i)-.5}var w={"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]]},b=t=>[parseInt(t.slice(1,3),16),parseInt(t.slice(3,5),16),parseInt(t.slice(5,7),16)];function y(t,e,i){const s=Math.min(t*Math.max(1,i),(1-t)*Math.max(1,i),e*Math.max(1,1/i),(1-e)*Math.max(1,1/i)),a=Math.max(0,Math.min(1,(s-.035)/.105));return a*a*a*(a*(6*a-15)+10)}var k=class{constructor(t,e){this.edgeSafe=!1,this.previous=null,this.peak=0,this.mode="dissolve",this.width=t,this.height=e;const i=t*e;this.pixels=new Uint8Array(4*i),this.ink=new Float32Array(i),this.targetX=new Float32Array(i),this.targetY=new Float32Array(i),this.offsetX=new Float32Array(i),this.offsetY=new Float32Array(i),this.edge=new Float32Array(i);for(let i=0;i<e;i++)for(let s=0;s<t;s++)this.edge[i*t+s]=y(s/(t-1),i/(e-1),t/e);this.clear()}get active(){return this.peak>2e-4}setMode(t){t!==this.mode&&(this.mode=t,this.clear())}clear(){for(const t of[this.ink,this.targetX,this.targetY,this.offsetX,this.offsetY,this.pixels])t.fill(0);if(this.previous=null,this.peak=0,"dissolve"!==this.mode)for(let t=0;t<this.pixels.length;t+=4)this.pixels[t]=this.pixels[t+2]=128}leave(){this.previous=null}move(t,e,i){if(!Number.isFinite(t+e+i))return;t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e));const s=this.previous;this.previous={x:t,y:e};const a=this.width,r=this.height,o=Math.max(1,a/r),n=Math.max(1,r/a),h=s?(t-s.x)*o:0,l=s?(e-s.y)*n:0,c=Math.hypot(h,l);if(!s&&"dissolve"!==this.mode)return;if(s&&c<1e-4)return;const f=.035+.11*Math.max(.1,Math.min(1,i)),d=Math.min(128,Math.max(1,Math.ceil(c/(.45*f)))),m=c?h/c:1,u=c?l/c:0,g=Math.min(1,c/(f*d)*2.2);for(let i=0;i<d;i++){const h=(i+.5)/d,l=s?s.x+(t-s.x)*h:t,c=s?s.y+(e-s.y)*h:e,p=Math.max(0,Math.floor((l-2.5*f/o)*(a-1))),M=Math.min(a-1,Math.ceil((l+2.5*f/o)*(a-1))),x=Math.max(0,Math.floor((c-2.5*f/n)*(r-1))),v=Math.min(r-1,Math.ceil((c+2.5*f/n)*(r-1)));for(let t=x;t<=v;t++)for(let e=p;e<=M;e++){const i=(e/(a-1)-l)*o/f,s=(t/(r-1)-c)*n/f,h=Math.exp(1.5*-(i*i+s*s)),d=t*a+e;if("dissolve"===this.mode)this.ink[d]=Math.max(this.ink[d],h);else{const t=(-i*u+s*m)*h*2.8,e="silk"===this.mode?m*t:-s*h*2.5,a="silk"===this.mode?u*t:i*h*2.5;this.targetX[d]=Math.max(-1,Math.min(1,this.targetX[d]+e*g)),this.targetY[d]=Math.max(-1,Math.min(1,this.targetY[d]+a*g))}}}this.peak=1}step(t){if(!this.active||!Number.isFinite(t))return;const e=Math.max(0,Math.min(.05,t)),i=Math.exp(-("dissolve"===this.mode?2.15:3.2)*e),s=1-Math.exp(-22*e);let a=0;for(let t=0;t<this.ink.length;t++)if("dissolve"===this.mode){this.ink[t]*=i,a=Math.max(a,this.ink[t]);const e=Math.round(65535*this.ink[t]);this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e}else{this.targetX[t]*=i,this.targetY[t]*=i,this.offsetX[t]+=(this.targetX[t]-this.offsetX[t])*s,this.offsetY[t]+=(this.targetY[t]-this.offsetY[t])*s,a=Math.max(a,Math.abs(this.offsetX[t]),Math.abs(this.offsetY[t]),Math.abs(this.targetX[t]),Math.abs(this.targetY[t]));const e=Math.round(this.offsetX[t]*(this.edgeSafe?this.edge[t]:1)*32767+32768),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}this.peak=a,this.active||this.clear()}sample(t,e,i){const s=Math.max(0,Math.min(this.width-1.001,t*(this.width-1))),a=Math.max(0,Math.min(this.height-1.001,e*(this.height-1))),r=Math.floor(s),o=Math.floor(a),n=s-r,h=a-o,l=o*this.width+r,c=l+this.width,f=t=>(t[l]*(1-n)+t[l+1]*n)*(1-h)+(t[c]*(1-n)+t[c+1]*n)*h;i[0]=f(this.offsetX)*(this.edgeSafe?y(t,e,this.width/this.height):1)*.08,i[1]=f(this.offsetY)*(this.edgeSafe?y(t,e,this.width/this.height):1)*.08,i[2]="dissolve"===this.mode?6*-f(this.ink):0}},E=class{constructor(t,e){this.rings=[],this.previous=null,this.elapsed=1,this.echoPeak=0,this.width=t,this.height=e,this.pixels=new Uint8Array(t*e*4),this.echo=new Float32Array(t*e)}get active(){return this.rings.length>0||this.echoPeak>2e-4}clear(){this.rings=[],this.previous=null,this.elapsed=1,this.pixels.fill(0),this.echo.fill(0),this.echoPeak=0}leave(){this.previous=null}move(t,e,i){const s=Math.max(1,this.width/this.height),a=Math.max(1,this.height/this.width);this.previous&&(Math.hypot((t-this.previous.x)*s,(e-this.previous.y)*a)<.065||this.elapsed<.3)||4!==this.rings.length&&(this.previous={x:t,y:e},this.elapsed=0,this.rings.push({x:t,y:e,age:0,radius:i}))}ringSample(t,e){const i=Math.max(1,this.width/this.height),s=Math.max(1,this.height/this.width);let a=0;for(const 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)*s)-o)/n,l=Math.sin(Math.min(1,r.age/.07)*Math.PI/2)*Math.max(0,1-r.age/1.35)**2;a=Math.max(a,Math.exp(-h*h)*l)}return a}sample(t,e){const i=Math.max(0,Math.min(this.width-1,Math.round(t*(this.width-1)))),s=Math.max(0,Math.min(this.height-1,Math.round(e*(this.height-1))));return Math.max(this.ringSample(t,e),this.echo[s*this.width+i])}step(t){if(!Number.isFinite(t))return;const e=Math.max(0,Math.min(.05,t));this.elapsed+=e;for(const t of this.rings)t.age+=e;if(this.rings=this.rings.filter(t=>t.age<1.35),!this.active)return void this.pixels.fill(0);const i=Math.exp(-5.5*e);let s=0;for(let t=0;t<this.height;t++)for(let e=0;e<this.width;e++){const a=t*this.width+e;this.echo[a]=Math.max(this.ringSample(e/(this.width-1),t/(this.height-1)),this.echo[a]*i),s=Math.max(s,this.echo[a]);const r=Math.round(65535*this.echo[a]),o=4*a;this.pixels[o]=r>>>8,this.pixels[o+1]=255&r}this.echoPeak=s,this.active||(this.echo.fill(0),this.pixels.fill(0))}},S=class{constructor(t,e){this.previous=null,this.peak=0,this.width=t,this.height=e;const i=t*e;this.pixels=new Uint8Array(4*i),this.signal=new Float32Array(i),this.offsetX=new Float32Array(i),this.offsetY=new Float32Array(i),this.driftX=new Float32Array(i),this.driftY=new Float32Array(i),this.u=new Float32Array(i),this.v=new Float32Array(i),this.ink=new Float32Array(i),this.a=new Float32Array(i),this.b=new Float32Array(i),this.c=new Float32Array(i),this.pressure=new Float32Array(i),this.pressureNext=new Float32Array(i),this.divergence=new Float32Array(i),this.curl=new Float32Array(i)}get active(){return this.peak>2e-4}clear(){for(const t of[this.u,this.v,this.ink,this.a,this.b,this.c,this.pressure,this.pressureNext,this.divergence,this.curl,this.signal,this.pixels,this.offsetX,this.offsetY,this.driftX,this.driftY])t.fill(0);this.previous=null,this.peak=0}leave(){this.previous=null}move(t,e,i,s=performance.now()){if(!Number.isFinite(t+e+i+s))return;t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e)),i=Math.max(.1,Math.min(1,i));const a=this.previous;if(this.previous={x:t,y:e,time:s},!a)return;const r=(t-a.x)*(this.width-1),o=(e-a.y)*(this.height-1),n=Math.hypot(r,o);if(n<.001)return;const h=Math.min(this.width,this.height),l=s>a.time?Math.max(1/240,(s-a.time)/1e3):1/60,c=Math.min(12,n/h/l),f=1-Math.exp(-c/2.2),d=h*(.022+.075*i)*(.65+.95*f),m=Math.min(128,Math.max(1,Math.ceil(n/(.4*d)))),u=n/d*(.32+.22*f)/m,g=r/n,p=o/n,M=-p,x=g,v=n*(2+18*f)/m;for(let i=0;i<m;i++){const s=(i+.5)/m,r=(a.x+(t-a.x)*s)*(this.width-1),o=(a.y+(e-a.y)*s)*(this.height-1),n=Math.max(1,Math.floor(r-3*d)),h=Math.min(this.width-2,Math.ceil(r+3*d)),l=Math.max(1,Math.floor(o-3*d)),c=Math.min(this.height-2,Math.ceil(o+3*d));for(let t=l;t<=c;t++)for(let e=n;e<=h;e++){const i=((e-r)*g+(t-o)*p)/d,s=((e-r)*M+(t-o)*x)/d,a=Math.exp(-i*i*.65-s*s*1.7),n=t*this.width+e;this.ink[n]=1-(1-this.ink[n])*Math.exp(-a*u);const h=1-s*s*.55,l=i*s*.7;this.u[n]=Math.max(-80,Math.min(80,this.u[n]+(g*h+M*l)*a*v)),this.v[n]=Math.max(-80,Math.min(80,this.v[n]+(p*h+x*l)*a*v))}}this.peak=1}read(t,e,i){const s=0|(e=Math.max(.5,Math.min(this.width-1.5,e))),a=0|(i=Math.max(.5,Math.min(this.height-1.5,i))),r=e-s,o=i-a,n=a*this.width+s;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,s=this.height;for(;e>1e-7;){const t=Math.min(1/60,e);e-=t;const a=Math.exp(-1.9*t),r=Math.exp(-3.2*t);for(let e=1;e<s-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(s-1.5,e-this.v[n]*t)),c=0|h,f=0|l,d=h-c,m=l-f,u=f*i+c,g=(1-d)*(1-m),p=d*(1-m),M=(1-d)*m,x=d*m;this.a[n]=(this.u[u]*g+this.u[u+1]*p+this.u[u+i]*M+this.u[u+i+1]*x)*a,this.b[n]=(this.v[u]*g+this.v[u+1]*p+this.v[u+i]*M+this.v[u+i+1]*x)*a,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<s-1;t++)for(let e=1;e<i-1;e++){const s=t*i+e;this.curl[s]=.5*(this.v[s+1]-this.v[s-1]-this.u[s+i]+this.u[s-i])}for(let e=1;e<s-1;e++)for(let s=1;s<i-1;s++){const a=e*i+s,r=Math.abs(this.curl[a+1])-Math.abs(this.curl[a-1]),o=Math.abs(this.curl[a+i])-Math.abs(this.curl[a-i]),n=Math.hypot(r,o)+1e-4,h=this.curl[a]*t*10,l=Math.hypot(this.u[a],this.v[a]);this.u[a]+=o/n*h,this.v[a]-=r/n*h;const c=Math.min(1,l/(Math.hypot(this.u[a],this.v[a])+1e-6));this.u[a]*=c,this.v[a]*=c,this.divergence[a]=-.5*(this.u[a+1]-this.u[a-1]+this.v[a+i]-this.v[a-i])}this.pressure.fill(0);for(let t=0;t<4;t++){for(let t=1;t<s-1;t++)for(let e=1;e<i-1;e++){const s=t*i+e;this.pressureNext[s]=.25*(this.divergence[s]+this.pressure[s-1]+this.pressure[s+1]+this.pressure[s-i]+this.pressure[s+i])}[this.pressure,this.pressureNext]=[this.pressureNext,this.pressure]}let o=0;for(let e=1;e<s-1;e++)for(let s=1;s<i-1;s++){const a=e*i+s;this.u[a]=Math.max(-80,Math.min(80,this.u[a]-.5*(this.pressure[a+1]-this.pressure[a-1]))),this.v[a]=Math.max(-80,Math.min(80,this.v[a]-.5*(this.pressure[a+i]-this.pressure[a-i]))),this.driftX[a]+=(3.6*this.u[a]-58*this.offsetX[a]-12*this.driftX[a])*t,this.driftY[a]+=(3.6*this.v[a]-58*this.offsetY[a]-12*this.driftY[a])*t,this.offsetX[a]=Math.max(-2,Math.min(2,this.offsetX[a]+this.driftX[a]*t)),this.offsetY[a]=Math.max(-2,Math.min(2,this.offsetY[a]+this.driftY[a]*t)),this.signal[a]=1-Math.exp(.06*-Math.hypot(this.u[a],this.v[a])-.16*this.ink[a]),o=Math.max(o,this.signal[a])}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 A(t,e){const i=Math.max(0,Math.min(1,e/.38));return t+(1-2*t)*(i*i*(3-2*i))}var T=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]=y(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 S(this.columns,this.rows),this.contour=new E(this.columns,this.rows),this.afterimage=new k(this.columns,this.rows),this.clear()}get invertsDensity(){return"trail"===this.mode}get densityTrail(){return["trail","contour","dissolve"].includes(this.mode)}get hasRefraction(){return this.active||this.lensStrength>15e-5}get active(){return["dissolve","silk","vortex"].includes(this.mode)?this.afterimage.active:"contour"===this.mode?this.contour.active:"trail"===this.mode?this.trail.active:this.pending||this.energy>15e-5}setMode(t){t!==this.mode&&(this.clear(),this.mode=t,this.refraction.mode=t,"dissolve"!==t&&"silk"!==t&&"vortex"!==t||this.afterimage.setMode(t),this.refraction.pixels="trail"===t?this.trail.pixels:"contour"===t?this.contour.pixels:["dissolve","silk","vortex"].includes(t)?this.afterimage.pixels:this.waterPixels,this.refraction.strength="water"===t?30*this.amount/.55:"silk"===t?28*this.amount:"vortex"===t?38*this.amount:0)}configure(t,e=.55,i=.2,s=!1){this.setMode(t),this.refraction.edgeSafe=s,this.afterimage.edgeSafe=s,this.amount=Number.isFinite(e)?Math.max(0,Math.min(1,e)):.55,this.radius=Number.isFinite(i)?Math.max(.1,Math.min(1,i)):.2,this.refraction.strength="water"===t?30*this.amount/.55:"silk"===t?28*this.amount:"vortex"===t?38*this.amount:0,this.refraction.focus[2]=this.densityTrail?this.amount:this.lensStrength*this.amount,this.refraction.focus[3]=this.radius}move(t,e,i){if("none"===this.mode||0===this.amount)return;if(!Number.isFinite(t+e))return;if(t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e)),["dissolve","silk","vortex"].includes(this.mode))return void this.afterimage.move(t,e,this.radius);if("contour"===this.mode)return void this.contour.move(t,e,this.radius);if("trail"===this.mode)return void this.trail.move(t,e,this.radius,i);if("water"!==this.mode)return!this.previous&&this.lensStrength<.001&&(this.lensX=t,this.lensY=e),this.previous={x:t,y:e},void(this.pending=!0);if(!this.previous)return void(this.previous={x:t,y:e});const s=this.previous;this.previous={x:t,y:e};const a=(t-s.x)*this.xScale,r=(e-s.y)*this.yScale,o=Math.hypot(a,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 a=(i+.5)/l,r=s.x+(t-s.x)*a,o=s.y+(e-s.y)*a,f=Math.max(1,Math.floor((r-h/this.xScale)*(this.columns-1))),d=Math.min(this.columns-2,Math.ceil((r+h/this.xScale)*(this.columns-1))),m=Math.max(1,Math.floor((o-h/this.yScale)*(this.rows-1))),u=Math.min(this.rows-2,Math.ceil((o+h/this.yScale)*(this.rows-1)));for(let t=m;t<=u;t++)for(let e=f;e<=d;e++){const i=(e/(this.columns-1)-r)*this.xScale,s=(t/(this.rows-1)-o)*this.yScale,a=Math.exp(-(i*i+s*s)/(n*n))*c,h=t*this.columns+e;this.velocity[h]=Math.max(-12,this.velocity[h]-a)}}this.pending=!0}leave(){this.afterimage.leave(),this.contour.leave(),this.trail.leave(),this.previous=null,"water"!==this.mode&&this.lensStrength&&(this.pending=!0)}clear(){this.trail.clear(),this.contour.clear(),this.afterimage.clear(),this.heights.fill(0),this.velocity.fill(0),this.next.fill(0),this.normals.fill(0),this.refraction.focus[2]=0,this.previous=null,this.lensStrength=0,this.energy=0,this.pending=!1,this.remainder=0;for(let t=0;t<this.waterPixels.length;t+=4)this.waterPixels[t]=this.waterPixels[t+2]=128,this.waterPixels[t+1]=this.waterPixels[t+3]=0}step(t){if(!this.active||!Number.isFinite(t))return;if(["dissolve","silk","vortex"].includes(this.mode))return void this.afterimage.step(t);if("contour"===this.mode)return void this.contour.step(t);if("trail"===this.mode)return void this.trail.step(t);if("water"!==this.mode)return void this.stepLight(Math.max(0,Math.min(.05,t)));this.remainder+=Math.max(0,Math.min(.05,t));const e=1/120,i=Math.exp(-3.8*e),s=.3*Math.min(this.columns,this.rows);for(;this.remainder+1e-8>=e;){this.remainder-=e;let t=0;for(let a=1;a<this.rows-1;a++)for(let r=1;r<this.columns-1;r++){const o=a*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,a,this.columns-1-r,this.rows-1-a),c=l<5?.88+.024*l:1,f=(this.velocity[o]+(h*s*s-8*n)*e)*i*c;this.velocity[o]=f,this.next[o]=(n+f*e)*c,t=Math.max(t,Math.abs(this.next[o]),.1*Math.abs(f))}this.heights.set(this.next),this.energy=t,this.pending=!1}if(!this.active)return void this.clear();const a=.18*Math.min(this.columns,this.rows);for(let t=0;t<this.rows;t++)for(let e=0;e<this.columns;e++){const i=t*this.columns+e,s=(this.heights[t*this.columns+Math.max(0,e-1)]-this.heights[t*this.columns+Math.min(this.columns-1,e+1)])*a,r=(this.heights[Math.max(0,t-1)*this.columns+e]-this.heights[Math.min(this.rows-1,t+1)*this.columns+e])*a,o=Math.tanh(s)*(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),s=1-Math.exp(-12*t);e&&(this.lensX+=(e.x-this.lensX)*i,this.lensY+=(e.y-this.lensY)*i),this.lensStrength+=((e?1:0)-this.lensStrength)*s,this.energy=Math.max(e?Math.abs(e.x-this.lensX)+Math.abs(e.y-this.lensY):0,Math.abs((e?1:0)-this.lensStrength)),this.pending=!1,e||this.active?this.refraction.focus=[this.lensX,this.lensY,this.lensStrength*this.amount,this.radius]:this.clear()}sample(t,e,i){if(["dissolve","silk","vortex"].includes(this.mode))return this.afterimage.sample(t,e,i),i[0]*=this.amount,i[1]*=this.amount,void(i[2]*=this.amount);if("contour"===this.mode)return i[0]=i[1]=0,void(i[2]=this.contour.sample(t,e)*this.amount*3);if("trail"===this.mode)return i[0]=i[1]=0,void(i[2]=this.trail.sample(t,e)*this.amount*3);const s=Math.max(0,Math.min(this.columns-1.001,t*(this.columns-1))),a=Math.max(0,Math.min(this.rows-1.001,e*(this.rows-1))),r=Math.floor(s),o=Math.floor(a),n=s-r,h=a-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,s){const[a,r,o,n]=i.focus,h=(t-a)*Math.max(1,s)/n,l=(e-r)*Math.max(1,1/s)/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 F(t){return"videoWidth"in t?[t.videoWidth,t.videoHeight]:"naturalWidth"in t?[t.naturalWidth,t.naturalHeight]:[t.width,t.height]}var R=(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}},I=(t,e,i)=>{t.width===e&&t.height===i||(t.width=e,t.height=i)},P={blocks:" ░▒▓█",braille:" ⠁⠃⠇⡇⣇⣧⣷⣿",lines:" -═╪╬",cross:" ·+xX#",diagonal:" /╱╳",diamond:" ·◇◈◆",mixed:" .:+/◇#@"};function C(t,e={},i={}){const a=t.getContext("2d");if(!a)throw new Error("Canvas is already owned by another renderer.");const r=R(),o=R(!0),n=R(),h=R(),c=R(),f=R(),m=R(),u=R(),g=R();let p,M=l(e),y=0,k="",E=new Uint8ClampedArray(0),S=0,C=0,L=0,X=null,D="",U=new T,B=0;const N=[0,0,0],O=Math.max(64,Math.min(4096,Number.isFinite(i.maxDimension)?i.maxDimension:960)),Y=Math.max(256,Math.min(16e4,Number.isFinite(i.maxCells)?i.maxCells:12e3));let z=Y;const _=Math.max(.1,Math.min(8,i.pixelRatio??1));return{canvas:t,render:function(e,i=0,l=960,R=540){if(Number.isFinite(i)||(i=0),!Number.isFinite(l)||!Number.isFinite(R)||l<1||R<1)throw new Error("Render dimensions must be positive finite numbers.");const[Y,W]=F(e);if(!Y||!W)return;const G=Math.min(1,O/Math.max(l,R)),q=Math.max(2,Math.round(l*G)),j=Math.max(2,Math.round(R*G));I(t,q,j),I(r.canvas,q,j),I(n.canvas,q,j),I(h.canvas,q,j),I(c.canvas,q,j),B!==q/j&&(B=q/j,U=new T(B)),U.configure(M.hover.effect,M.hover.strength,M.hover.radius,M.hover.edgeSafe),U.step(Math.max(0,Math.min(.05,i-L))),L=i;const $="currentTime"in e?e.getVideoPlaybackQuality?.().totalVideoFrames??e.currentTime:0,V=[y,q,j,$].join(":"),H="dither"===M.style,J=(H?M.dither.scale:M.cellSize)*_,Q=Math.max(J,Math.sqrt(q*j/z)),K=H||["pixel","mosaic","lego","voxel","disco","dots"].includes(M.style)?Q:1.65*Q,Z=Math.max(1,Math.ceil(q/Q)),tt=Math.max(1,Math.ceil(j/K));if(k!==V||X!==e||S!==Z||C!==tt){X=e,k=V,S=Z,C=tt,r.ctx.clearRect(0,0,q,j),r.ctx.save();const t=d(Y,W,q,j,M.crop);r.ctx.translate(t.x+t.width/2,t.y+t.height/2),r.ctx.rotate(M.crop.rotation*Math.PI/180),r.ctx.drawImage(e,-Y*t.scale/2,-W*t.scale/2,Y*t.scale,W*t.scale),r.ctx.restore(),I(o.canvas,S,C),o.ctx.clearRect(0,0,S,C),o.ctx.drawImage(r.canvas,0,0,S,C),E=o.ctx.getImageData(0,0,S,C).data;const i=M.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 s=0;s<3;s++){const a=e+(E[t+s]-e)*i.saturation;E[t+s]=((a*(1-i.grayscale)+e*i.grayscale)/255-.5)*i.contrast*255+127.5+255*i.brightness}}}n.ctx.clearRect(0,0,q,j),n.ctx.globalAlpha=1,n.ctx.globalCompositeOperation="source-over";const et=i*M.motion.speed;if(H){const t=new Uint8ClampedArray(E),e=M.motion.type;if(U.active||"none"!==e)for(let i=0;i<C;i++)for(let s=0;s<S;s++){const a=s/S,r=i/C;let o=s,n=i,h=0,l=1,c=1;if(U.active&&(U.sample(a,r,N),o-=N[0]*S,n-=N[1]*C,h=N[2]/3),"wave"===e&&(n+=Math.sin(8*a+2*et+4*r)*C*.015),"ripple"===e){const t=a-.5,e=r-.5,i=.03*Math.sin(30*Math.hypot(t,e)-3*et);o+=t*i*S,n+=e*i*C}"breathe"===e&&(l=.92+.08*Math.sin(1.5*et+3*a)),"reveal"===e&&(c=Math.max(0,Math.min(1,4*(.7*Math.sin(.7*et)+.7-a)))),"glitch"===e&&x(i,Math.floor(6*et))>.93&&(o+=8*Math.sin(5*et)),"vapor"===e&&(n+=Math.sin(6*a+et)*C*.025),"fire"===e&&(n+=Math.sin(7*a+3*et+8*r)*C*.01,l=.8+.2*Math.sin(12*r-4*et)),"hologram"===e&&(c=.72+.28*Math.sin(.65*i+5*et)),"chrome"===e&&(l=.5+Math.abs(Math.sin(8*r+et)));const f=4*(i*S+s),d=4*(Math.max(0,Math.min(C-1,Math.round(n)))*S+Math.max(0,Math.min(S-1,Math.round(o))));for(let i=0;i<3;i++){const s=E[d+i]/255;let r=(["trail","contour"].includes(M.hover.effect)?A(s,h):"dissolve"===M.hover.effect?s*Math.max(0,1+h):s)*l;"rainbow"===e&&(r*=.65+.35*Math.sin(2*et+5*a+2.094*i)),"hologram"===e&&(r*=0===i?.4:1),"fire"===e&&(r*=0===i?1.3:1===i?.7:.3),t[f+i]=255*r}t[f+3]=E[d+3]*c}!function(t,e,i,a,r=0){const{algorithm:o,amount:n,threshold:h}=a,l=("custom"===a.palette?a.colors:s[a.palette]??s.mono).map(b),c=w[o],f=c?new Float32Array(3*e*3):null,d="drift"===a.motion?Math.floor(r*a.speed*3):0,m="shimmer"===a.motion?.15*Math.sin(r*a.speed*2):0;for(let s=0;s<i;s++)for(let a=0;a<e;a++){const r=4*(s*e+a),u=3*(s%3*e+a);if(0===t[r+3]){f&&(f[u]=f[u+1]=f[u+2]=0);continue}let g=0;o.startsWith("bayer")?g=v(a+d&15,s+d&15,Number(o.slice(5))):"noise"===o?g=x(a,s)-.5:"lines"===o?g=(s+d)%4/3-.5:"halftone"===o&&(g=Math.hypot(a%6-2.5,s%6-2.5)/3.54-.5);const p=128*(g*n+m+(.5-h)),M=t[r]+p+(f?.[u]??0),w=t[r+1]+p+(f?.[u+1]??0),b=t[r+2]+p+(f?.[u+2]??0);let y=0,k=0,E=0;if(l.length){let t=1/0;for(const e of l){const i=(M-e[0])**2*.299+(w-e[1])**2*.587+(b-e[2])**2*.114;i<t&&(t=i,[y,k,E]=e)}}else y=51*Math.round(M/51),k=51*Math.round(w/51),E=51*Math.round(b/51);if(t[r]=y,t[r+1]=k,t[r+2]=E,f&&c){f[u]=f[u+1]=f[u+2]=0;for(const[t,r,o]of c){const h=a+t;if(h<0||h>=e||s+r>=i)continue;const l=3*((s+r)%3*e+h);f[l]+=(M-y)*o*n,f[l+1]+=(w-k)*o*n,f[l+2]+=(b-E)*o*n}}}}(t,S,C,M.dither,i),o.ctx.putImageData(new ImageData(t,S,C),0,0),n.ctx.imageSmoothingEnabled=!1,n.ctx.drawImage(o.canvas,0,0,q,j)}else{const t=Array.from(P[M.style]??M.charset),e=n.ctx,i="ascii"===M.style||!!P[M.style],s=Math.max(3,Math.round(.92*K)),a=Math.ceil(Q+4),r=Math.ceil(K+4),o=[t.join(""),s,a,r,M.ink,M.colorMode].join(":");i&&o!==D&&(D=o,I(m.canvas,a*t.length,r),m.ctx.clearRect(0,0,m.canvas.width,r),m.ctx.font=`${s}px monospace`,m.ctx.textBaseline="middle",m.ctx.textAlign="center",m.ctx.fillStyle="accent"===M.colorMode?M.ink:"#ffffff",t.forEach((t,e)=>m.ctx.fillText(t,e*a+a/2,r/2))),e.font=`${s}px monospace`,e.textBaseline="middle",e.textAlign="center";for(let s=0;s<C;s++)for(let o=0;o<S;o++){let n=o,h=s,l=0;U.active&&(U.sample(o/S,s/C,N),n=Math.max(0,Math.min(S-1,o-N[0]*S)),h=Math.max(0,Math.min(C-1,s-N[1]*C)),l=N[2]/3);const c=4*(Math.floor(h)*S+Math.floor(n));if(!E[c+3])continue;const f=E[c],d=E[c+1],u=E[c+2],g=(.299*f+.587*d+.114*u)/255;let p=g;["trail","contour"].includes(M.hover.effect)&&l?p=A(p,l):"dissolve"===M.hover.effect&&(p*=Math.max(0,1+l));const v=M.motion.type;let w=o*Q,b=s*K,y=1;if("breathe"===v&&(p*=.92+.08*Math.sin(1.5*et+.03*o)),"wave"===v&&(b+=Math.sin(.12*o+2*et+.08*s)*K*.4),"ripple"===v){const t=o/S-.5,e=s/C-.5,i=Math.hypot(t,e),a=Math.sin(30*i-3*et)*Q*.65;w+=t*a,b+=e*a}"fire"===v&&(b-=Math.sin(.16*o+3*et+.09*s)*K*.35,p*=.85+.15*Math.sin(.3*s-4*et)),"hologram"===v&&(y=.72+.28*Math.sin(.65*s+5*et)),"reveal"===v&&(y=Math.max(0,Math.min(1,4*(.7*Math.sin(.7*et)+.7-o/S)))),"glitch"===v&&x(s,Math.floor(6*et))>.93&&(w+=Math.sin(5*et)*Q*3),"vapor"===v&&(b+=Math.sin(.04*o+et)*K),i||"accent"!==M.colorMode||(y*=p),e.globalAlpha=y;const k=255*(p-g);let T="source"===M.colorMode?`rgb(${f+k},${d+k},${u+k})`:"gray"===M.colorMode?`rgb(${Math.round(255*p)},${Math.round(255*p)},${Math.round(255*p)})`:M.ink;if("rainbow"===v&&(T=`hsl(${(o/S*180+40*et)%360} 70% 65%)`),"fire"===v&&(T=`hsl(${15+40*p} 90% ${30+45*p}%)`),"hologram"===v&&(T=`hsl(185 65% ${40+40*p}%)`),"chrome"===v&&(T=`hsl(210 12% ${25+70*Math.abs(Math.sin(.2*s+et))}%)`),e.fillStyle=T,i){const i=Math.max(0,Math.min(t.length-1,Math.floor(p*(t.length-1))));"accent"!==M.colorMode||["rainbow","fire","hologram","chrome"].includes(v)?e.fillText(t[i],w+Q/2,b+K/2):e.drawImage(m.canvas,i*a,0,a,r,w+(Q-a)/2,b+(K-r)/2,a,r)}else if("dots"===M.style)e.beginPath(),e.arc(w+Q/2,b+K/2,.48*Q*Math.sqrt(p),0,2*Math.PI),e.fill();else if("voxel"===M.style){const t=w+Q/2,i=b+K/2;e.beginPath(),e.moveTo(t,b),e.lineTo(w+Q,b+.25*K),e.lineTo(t,i),e.lineTo(w,b+.25*K),e.closePath(),e.fill(),e.globalAlpha=.72*y,e.beginPath(),e.moveTo(w,b+.25*K),e.lineTo(t,i),e.lineTo(t,b+K),e.lineTo(w,b+.75*K),e.closePath(),e.fill(),e.globalAlpha=.42*y,e.beginPath(),e.moveTo(t,i),e.lineTo(w+Q,b+.25*K),e.lineTo(w+Q,b+.75*K),e.lineTo(t,b+K),e.closePath(),e.fill()}else{const t="pixel"===M.style?0:Math.max(.5,.06*Q);e.fillRect(w,b,Q-t,K-t),"lego"===M.style&&(e.fillStyle="rgba(255,255,255,.2)",e.beginPath(),e.arc(w+Q/2,b+K/2,.28*Q,0,2*Math.PI),e.fill(),e.strokeStyle="rgba(0,0,0,.25)",e.stroke()),"disco"===M.style&&(e.fillStyle=`rgba(255,255,255,${.1+.25*x(o,s)})`,e.fillRect(w,b,Q-t,.35*K),e.fillStyle="rgba(0,0,0,.25)",e.fillRect(w,b+.65*K,Q-t,.35*K-t))}}}n.ctx.globalAlpha=1,(M.color.amount||M.lights.length)&&(I(u.canvas,q,j),u.ctx.clearRect(0,0,q,j),u.ctx.drawImage(n.canvas,0,0)),M.color.amount&&(n.ctx.save(),n.ctx.globalCompositeOperation=M.color.blend,n.ctx.globalAlpha=M.color.amount,n.ctx.fillStyle=M.color.tint,n.ctx.fillRect(0,0,q,j),n.ctx.restore());for(const t of M.lights){const e=t.radius*Math.max(q,j),i=n.ctx.createRadialGradient(t.x*q,t.y*j,0,t.x*q,t.y*j,e);i.addColorStop(0,t.color),i.addColorStop(1,"transparent"),n.ctx.save(),n.ctx.globalCompositeOperation="screen",n.ctx.globalAlpha=t.intensity,n.ctx.fillStyle=i,n.ctx.fillRect(0,0,q,j),n.ctx.restore()}if((M.color.amount||M.lights.length)&&(n.ctx.globalCompositeOperation="destination-in",n.ctx.drawImage(u.canvas,0,0),n.ctx.globalCompositeOperation="source-over"),M.mask.enabled&&M.mask.shapes.length){const t=c.ctx;t.clearRect(0,0,q,j),t.fillStyle="#fff",t.strokeStyle="#fff",t.lineCap="round",t.lineJoin="round";for(const e of M.mask.shapes){if(t.beginPath(),"ellipse"===e.kind)t.ellipse((e.x+e.width/2)*q,(e.y+e.height/2)*j,e.width*q/2,e.height*j/2,0,0,2*Math.PI);else{if("rectangle"!==e.kind){if(t.lineWidth=(e.size??.05)*q,1===e.points?.length){t.arc(e.points[0][0]*q,e.points[0][1]*j,t.lineWidth/2,0,2*Math.PI),t.fill();continue}e.points?.forEach(([e,i],s)=>s?t.lineTo(e*q,i*j):t.moveTo(e*q,i*j)),t.stroke();continue}t.rect(e.x*q,e.y*j,e.width*q,e.height*j)}t.fill()}n.ctx.globalCompositeOperation=M.mask.invert?"destination-out":"destination-in",n.ctx.drawImage(c.canvas,0,0),n.ctx.globalCompositeOperation="source-over"}const it=h.ctx;it.clearRect(0,0,q,j),it.globalAlpha=M.backdrop.opacity;const st=M.backdrop;if("solid"===st.mode&&(it.fillStyle=st.color,it.fillRect(0,0,q,j)),"gradient"===st.mode){const t=it.createLinearGradient(0,0,q,j);t.addColorStop(0,st.color),t.addColorStop(1,st.color2),it.fillStyle=t,it.fillRect(0,0,q,j)}if("source"===st.mode&&it.drawImage(r.canvas,0,0),"blurred"===st.mode){const t=Math.max(1,st.blur);I(f.canvas,Math.max(2,Math.round(q/t)),Math.max(2,Math.round(j/t))),f.ctx.drawImage(r.canvas,0,0,f.canvas.width,f.canvas.height),it.imageSmoothingEnabled=!0,it.drawImage(f.canvas,0,0,q,j)}it.globalAlpha=1,M.effects.characterBloom>0&&(I(g.canvas,Math.max(2,Math.round(q/3)),Math.max(2,Math.round(j/3))),g.ctx.clearRect(0,0,g.canvas.width,g.canvas.height),g.ctx.drawImage(n.canvas,0,0,g.canvas.width,g.canvas.height),it.save(),it.globalAlpha=.8*M.effects.characterBloom,it.globalCompositeOperation="screen",it.filter=`blur(${1+4*M.effects.characterBloom}px)`,it.drawImage(g.canvas,0,0,q,j),it.restore()),it.drawImage(n.canvas,0,0);const at=Object.entries(M.effects).some(([t,e])=>!["angle","focus","blurType","characterBloom"].includes(t)&&"number"==typeof e&&e>0);a.clearRect(0,0,q,j),at?(void 0===p&&(p=function(){const t=document.createElement("canvas"),e=t.getContext("webgl",{alpha:!0,premultipliedAlpha:!1,antialias:!1,preserveDrawingBuffer:!0});if(!e)return null;const i=[],s=(t,s)=>{const a=e.createShader(t);if(i.push(a),e.shaderSource(a,s),e.compileShader(a),!e.getShaderParameter(a,e.COMPILE_STATUS))throw new Error(e.getShaderInfoLog(a)||"Finish shader failed");return a},a=e.createProgram();if(e.attachShader(a,s(e.VERTEX_SHADER,"attribute vec2 p;varying vec2 uv;void main(){uv=(p+1.)*.5;gl_Position=vec4(p,0.,1.);}")),e.attachShader(a,s(e.FRAGMENT_SHADER,"precision mediump float;varying vec2 uv;uniform sampler2D src;uniform vec2 size;uniform float t,bloom,grain,dust,scanlines,crt,prism,vignette,glitch,pixelate,blur,blurMode,angle,focus,halftone;\n float hash(vec2 p){return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453);}\n vec4 sampleAt(vec2 p){if(min(min(p.x,p.y),min(1.-p.x,1.-p.y))<0.)return vec4(0.);return texture2D(src,vec2(p.x,1.-p.y));}\n void main(){vec2 q=uv,c=q-.5;q=c*(1.+dot(c,c)*crt*.25)+.5;\n if(glitch>0.)q.x+=(hash(vec2(floor(q.y*35.),floor(t*5.)))-.5)*.07*glitch*step(.82,hash(vec2(floor(q.y*35.),floor(t*5.)+3.)));\n if(pixelate>0.){vec2 grid=size/(1.+pixelate*20.);q=(floor(q*grid)+.5)/grid;}\n vec4 base=sampleAt(q);float edge=smoothstep(.12,.65,length(c));\n vec2 shift=vec2(prism*3.*edge/size.x,prism*edge/size.y);\n if(prism>0.)base.rgb=vec3(sampleAt(q+shift).r,base.g,sampleAt(q-shift).b);\n vec2 dir=vec2(cos(angle),sin(angle))/size;float amount=blur;\n if(blurMode>1.5&&blurMode<2.5){dir=normalize(c+vec2(.0001))/size;amount*=length(c)*2.;}\n if(blurMode>2.5)amount*=smoothstep(.05,.5,abs(q.y-focus));\n vec4 blurred=base;\n if(amount>0.){blurred=base*.2;for(int i=1;i<=4;i++){float f=float(i)*amount*.35;vec2 off=dir*f;if(blurMode<.5)off=vec2(cos(float(i)*1.57),sin(float(i)*1.57))*amount/size;blurred+=sampleAt(q+off)*.1+sampleAt(q-off)*.1;}}\n vec3 light=vec3(0.);if(bloom>0.)for(int i=0;i<4;i++){float a=float(i)*1.5708;vec3 s=sampleAt(q+vec2(cos(a),sin(a))*6./size).rgb;light+=max(vec3(0.),s-.35)*.25;}\n vec3 col=blurred.rgb+light*bloom;col*=1.-scanlines*.4*(.5+.5*cos(q.y*size.y*3.14159));\n col*=1.-vignette*smoothstep(.15,.72,length(c));\n col+=(hash(floor(q*size)+floor(t*12.))-.5)*grain*.2;\n if(dust>0.)col+=step(1.-dust*.002,hash(floor(q*size*.25)+floor(t*2.)))*.4;\n if(halftone>0.)col*=mix(1.,smoothstep(.1,.65,length(fract(q*size/6.)-.5)),halftone);\n gl_FragColor=vec4(clamp(col,0.,1.),blurred.a);}")),e.linkProgram(a),!e.getProgramParameter(a,e.LINK_STATUS))throw new Error("Finish link failed");e.useProgram(a);const 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(a,"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","vignette","glitch","pixelate","blur","blurMode","angle","focus","halftone"],l=Object.fromEntries(h.map(t=>[t,e.getUniformLocation(a,t)])),c=e.getUniformLocation(a,"size");return{canvas:t,render(i,s,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(a),e.bindTexture(e.TEXTURE_2D,n),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,i),e.uniform2f(c,t.width/o,t.height/o);for(const t of h)e.uniform1f(l[t],"t"===t?r:"blurMode"===t?["gaussian","directional","radial","progressive"].indexOf(s.blurType):"angle"===t?s.angle*Math.PI/180:s[t]??0);return e.drawArrays(e.TRIANGLE_STRIP,0,4),t},destroy(){e.deleteTexture(n),e.deleteBuffer(r),e.deleteProgram(a),i.forEach(t=>e.deleteShader(t)),t.width=t.height=1,e.getExtension("WEBGL_lose_context")?.loseContext()}}}()),p?a.drawImage(p.render(h.canvas,M.effects,i,_),0,0):a.drawImage(h.canvas,0,0),t.dataset.studioFinish=p?"gpu":"unavailable"):(a.drawImage(h.canvas,0,0),t.dataset.studioFinish="none")},setBudget(t){z=Math.max(1500,Math.min(Y,Math.round(t)))},get maxCells(){return z},configure(t){M=l(t),y++},pointer:(t,e,i)=>{U.configure(M.hover.effect,M.hover.strength,M.hover.radius,M.hover.edgeSafe),U.move(t,e,i)},leave(){U.leave()},get active(){return U.active},get settings(){return l(M)},get capabilities(){return{gpuFinish:null!==p}},invalidate(){k=""},destroy(){p?.destroy();for(const t of[r,o,n,h,c,f,m,u,g])t.canvas.width=t.canvas.height=1;X=null,E=new Uint8ClampedArray(0)}}}function L(t,e,i){return new Promise((s,a)=>{const r=()=>{l(),s()},o=()=>{l(),a(new Error("Unable to load this media. Check its format and cross-origin permissions."))},n=()=>{l(),a(new DOMException("Cancelled","AbortError"))},h=setTimeout(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 X(t,e){if("string"==typeof t&&t.startsWith("blob:")){const i=await fetch(t,{signal:e}),s=await i.blob();return X(new File([s],"Imported media",{type:s.type}),e)}const i="string"!=typeof t,s=i?t.name:t;if(i?"image/gif"===t.type:/\.gif(?:[?#]|$)/i.test(s)){const s=await import("gifuct-js"),{parseGIF:a,decompressFrames:r}="function"==typeof s.parseGIF?s:s.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=a(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 f=r(n,!0);if(f.length*h*l*4>128e6)throw new Error("GIF exceeds the 128 MB decoded budget. Use MP4 for long animations.");const d=document.createElement("canvas");d.width=h,d.height=l;const m=d.getContext("2d"),u=document.createElement("canvas"),g=u.getContext("2d"),p=f.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,s=0;for(;s<f.length-1&&(i+=Math.max(20,f[s].delay),!(e<i));s++);s<M&&(m.clearRect(0,0,h,l),M=-1,x=null);for(let t=M+1;t<=s;t++){const e=f[t-1];2===e?.disposalType&&m.clearRect(e.dims.left,e.dims.top,e.dims.width,e.dims.height),3===e?.disposalType&&x&&m.putImageData(x,0,0);const i=f[t];x=3===i.disposalType?m.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),m.drawImage(u,i.dims.left,i.dims.top)}return M=s,d};return v(0),{source:d,width:h,height:l,duration:p,animated:!0,seek:async()=>{},frame:v,destroy(){d.width=u.width=1,f.length=0,x=null}}}const a=i?t.type.startsWith("video/"):/\.(mp4|webm|mov)(?:[?#]|$)/i.test(s),r=i?URL.createObjectURL(t):t,o=a?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=L(o,a?"loadeddata":"load",e);o.src=r,await t;const i=o instanceof HTMLVideoElement?o.videoWidth:o.naturalWidth,s=o instanceof HTMLVideoElement?o.videoHeight:o.naturalHeight;return{source:o,width:i,height:s,duration:o instanceof HTMLVideoElement?o.duration:0,animated:a,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 s=L(o,"seeked",e);o.currentTime=i,await s},frame:()=>o,destroy:n}}catch(t){throw n(),t}}var D=t=>{if(t?.aborted)throw new DOMException("Export cancelled","AbortError")};async function U(t,e,i){const{format:s,signal:a}=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(s))throw new Error("Unknown export format.");if(void 0!==i.fps&&!Number.isFinite(i.fps))throw new Error("Frames per second must be finite.");const n=Math.max(1,Math.min(60,Math.round(i.fps??24))),h=i.duration??5;if(!Number.isFinite(h)||h<=0||h>60)throw new Error("Choose a duration from 0 to 60 seconds.");const c="png"===s||"jpeg"===s;if(!c&&r*o>8294400)throw new Error("Video exports support up to 3840 × 2160 pixels.");if("gif"===s&&(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"===s&&n>30)throw new Error("GIF exports support up to 30 fps. Choose MP4 or WebM for higher frame rates.");const f=document.createElement("canvas"),d=C(f,l(e),{maxDimension:4096,maxCells:i.maxCells??12e3,pixelRatio:r/(i.referenceWidth??Math.min(r,960))});let m;try{if(D(a),i.onProgress?.(0),c){if(d.render(await t.frame(0,a),0,r,o),"unavailable"===f.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");D(a);const e=await new Promise((t,e)=>f.toBlob(i=>i?t(i):e(new Error("Image export failed.")),"png"===s?"image/png":"image/jpeg",i.quality??.92));return i.onProgress?.(1),e}const e=Math.ceil(h*n);if("gif"===s){const s=await import("gifenc"),{GIFEncoder:l,quantize:c,applyPalette:m}="function"==typeof s.GIFEncoder?s:s.default,u=l(),g=f.getContext("2d");for(let s=0;s<e;s++){D(a);const l=s/n;if(d.invalidate(),d.render(await t.frame(l,a),l,r,o),"unavailable"===f.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=m(p,M);u.writeFrame(x,r,o,{palette:M,delay:10*(Math.round(100*Math.min((s+1)/n,h))-Math.round(100*s/n)),repeat:0}),i.onProgress?.((s+1)/e*.98),await new Promise(t=>setTimeout(t,0))}return u.finish(),i.onProgress?.(1),new Blob([new Uint8Array(u.bytes())],{type:"image/gif"})}const{Output:l,Mp4OutputFormat:u,WebMOutputFormat:g,BufferTarget:p,CanvasSource:M,canEncodeVideo:x}=await import("mediabunny"),v="mp4"===s?"avc":"vp9";if(!await x(v,{width:r,height:o}))throw new Error(`${s.toUpperCase()} encoding is unavailable in this browser. Try another format or a current browser with WebCodecs.`);const w=new l({format:"mp4"===s?new u({fastStart:"in-memory"}):new g,target:new p});f.width=r,f.height=o,m=()=>w.cancel();const b=new M(f,{codec:v,bitrate:Math.max(5e5,Math.round(r*o*n*.15))});w.addVideoTrack(b,{frameRate:n}),f.width=r,f.height=o,await w.start();for(let s=0;s<e;s++){D(a);const l=s/n;if(d.invalidate(),d.render(await t.frame(l,a),l,r,o),"unavailable"===f.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");await b.add(l,Math.min(1/n,h-l)),i.onProgress?.((s+1)/e*.98),s%4==0&&await new Promise(t=>setTimeout(t,0))}return b.close(),D(a),await w.finalize(),m=void 0,i.onProgress?.(1),new Blob([w.target.buffer],{type:"mp4"===s?"video/mp4":"video/webm"})}catch(t){throw await(m?.().catch(()=>{})),t}finally{d.destroy(),f.width=f.height=1}}async function B(t,e,i={}){const s=await X(e,i.signal);try{return N(t,s,i)}catch(t){throw s.destroy(),t}}function N(t,e,i={}){let s=l(i.settings),a=i.width??e.width,r=i.height??e.height;const o=C(t,s,i);let n=0,h=!1,c=!0,f=!1,d=!0,g=0,p=0,M=0,x=-1,v=0,w=0,b=0;const y=matchMedia("(prefers-reduced-motion: reduce)"),k=e.source instanceof HTMLVideoElement?e.source:null,E=()=>{h||n||!d||document.hidden||(n=requestAnimationFrame(T))},S=()=>!f&&!y.matches&&d&&!document.hidden,A=()=>{k&&(k.loop=!0,S()?k.play().catch(()=>{f=!0,c=!0,E()}):k.pause()),p=0,c=!0,E()};function T(t){if(n=0,h||!d||document.hidden)return;const l=S();l&&(g+=p?Math.min(.1,(t-p)/1e3):0),p=t;const u=l&&(e.animated||"none"!==s.motion.type||"none"!==s.dither.motion||s.effects.grain>0||s.effects.dust>0||s.effects.glitch>0),y=k?.getVideoPlaybackQuality?.().totalVideoFrames??-1,A="none"!==s.motion.type||"none"!==s.dither.motion||s.effects.grain>0||s.effects.dust>0||s.effects.glitch>0,T=!k||y<0||y!==x;if(c||o.active||u&&(T||A)&&t-M>=1e3/Math.max(1,Math.min(60,i.fps??60))-.5){const n=performance.now();try{e.animated&&!k&&o.invalidate();const[t,h]=m(a,r,s);o.render(e.frame(k?.currentTime??g),g,t,h);const l=performance.now()-n;i.onFrame?.(k?.currentTime??g,l),w=w?.9*w+.1*l:l,++v>20&&!1!==i.adaptive&&(b=w>13?b+1:0,b>=12&&o.maxCells>3e3&&(o.setBudget(Math.max(3e3,.8*o.maxCells)),i.onQualityChange?.(o.maxCells),b=0,w=0))}catch(t){f=!0,i.onError?.(t instanceof Error?t:new Error(String(t)))}c=!1,M=t,x=y}l&&(u||o.active)&&E()}const F=e=>{if(!S())return;const i=t.getBoundingClientRect();o.pointer((e.clientX-i.left)/i.width,(e.clientY-i.top)/i.height,e.timeStamp),E()},R=()=>{o.leave(),E()},I=new IntersectionObserver(([t])=>{d=t.isIntersecting,A()});I.observe(t),t.addEventListener("pointermove",F),t.addEventListener("pointerleave",R),t.addEventListener("pointercancel",R),document.addEventListener("visibilitychange",A),y.addEventListener("change",A);const P=()=>{h||(h=!0,cancelAnimationFrame(n),I.disconnect(),t.removeEventListener("pointermove",F),t.removeEventListener("pointerleave",R),t.removeEventListener("pointercancel",R),document.removeEventListener("visibilitychange",A),y.removeEventListener("change",A),i.signal?.removeEventListener("abort",P),o.destroy(),e.destroy())};if(i.signal?.addEventListener("abort",P,{once:!0}),i.signal?.aborted)throw P(),new DOMException("Cancelled","AbortError");return A(),{canvas:t,media:e,update(t){s=u(s,t),o.configure(s),c=!0,E()},resize(t,e){a=Math.max(2,t),r=Math.max(2,e),c=!0,E()},pause(t=!0){f=t,A()},async seek(t){g=Math.max(0,t),await e.seek(g),o.invalidate(),c=!0,E()},redraw(){o.invalidate(),c=!0,E()},get time(){return k?.currentTime??g},get paused(){return f||y.matches},get maxCells(){return o.maxCells},get capabilities(){return o.capabilities},destroy:P}}var O={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")},Y=Object.keys(O);async function z(t,e="Standard",i="#ffffff"){if(!Object.prototype.hasOwnProperty.call(O,e))throw new Error("Unknown text font.");const{default:s}=await import("figlet/browser"),a=await O[e]();s.parseFont(e,a.default),s.defaults({fetchFontIfMissing:!1});const r=s.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 f=c.getContext("2d");return f.fillStyle="#080808",f.fillRect(0,0,c.width,c.height),f.fillStyle=i,f.font=15*l+"px monospace",f.textBaseline="top",o.forEach((t,e)=>f.fillText(t,16,16+15*e*l)),{canvas:c,ascii:r}}export{i as BLEND_MODES,a as DEFAULT_STUDIO_SETTINGS,e as DITHER_ALGORITHMS,g as STUDIO_LOOKS,s as STUDIO_PALETTES,t as STUDIO_STYLES,Y as STUDIO_TEXT_FONTS,C as createStudioRenderer,z as createStudioText,U as exportStudio,X as loadStudioMedia,B as mountStudio,N as mountStudioMedia,l as normalizeStudioSettings,f as parseStudioSettings,M as restyleStudio,c as serializeStudioSettings,d as studioCrop,m as studioDimensions,p as studioLook,F as studioSourceSize,u as updateStudioSettings};//# sourceMappingURL=studio.js.map
|
|
1
|
+
var t=["ascii","blocks","braille","dots","lines","cross","diagonal","diamond","mixed","pixel","mosaic","lego","voxel","disco","dither"],e=["none","bayer2","bayer4","bayer8","bayer16","floyd-steinberg","atkinson","stucki","sierra","sierra-lite","burkes","jarvis","halftone","lines","noise"],i=["source-over","multiply","screen","overlay","soft-light","hard-light","color-dodge","color-burn","hue","saturation","color","luminosity"],s={original:[],mono:["#080808","#f2f2e8"],asciify:["#080808","#625b38","#a19558","#e8b900"],gameboy:["#0f380f","#306230","#8bac0f","#9bbc0f"],cga:["#000000","#55ffff","#ff55ff","#ffffff"],pico8:["#000000","#1d2b53","#7e2553","#008751","#ab5236","#5f574f","#c2c3c7","#fff1e8","#ff004d","#ffa300","#ffec27","#00e436","#29adff","#83769c","#ff77a8","#ffccaa"],c64:["#000000","#ffffff","#880000","#aaffee","#cc44cc","#00cc55","#0000aa","#eeee77","#dd8855","#664400","#ff7777","#333333","#777777","#aaff66","#0088ff","#bbbbbb"],amber:["#100b00","#5f3b00","#c98014","#ffd17c"],ice:["#081b29","#25586e","#69a6b3","#d9ece7"],risograph:["#f4ebd0","#f2594b","#2853a5","#29232e"],sepia:["#201b17","#6b5039","#b49868","#f6e6c5"],nord:["#2e3440","#4c566a","#88c0d0","#eceff4"],dusk:["#211b35","#654271","#c3788c","#f5c9a3"],forest:["#101f1b","#355747","#87a16f","#e4e3ba"],ocean:["#071b33","#17577f","#3fa7a4","#d9efde"],newsprint:["#191919","#666666","#aaaaaa","#eee9df"],custom:["#080808","#e8b900"]},a={version:1,aspectRatio:"original",style:"ascii",cellSize:7,charset:" .:-=+*#%@",colorMode:"accent",ink:"#e8b900",crop:{x:.5,y:.5,zoom:1,rotation:0},backdrop:{mode:"solid",color:"#080808",color2:"#393323",blur:12,opacity:1},color:{brightness:0,contrast:1,saturation:1,grayscale:0,tint:"#e8b900",amount:0,blend:"source-over"},dither:{algorithm:"none",palette:"mono",colors:["#080808","#e8b900"],amount:1,scale:2,threshold:.5,motion:"none",speed:1},mask:{enabled:!1,invert:!1,shapes:[]},lights:[],effects:{bloom:0,characterBloom:0,grain:0,dust:0,scanlines:0,crt:0,prism:0,vignette:0,glitch:0,pixelate:0,blur:0,blurType:"gaussian",angle:0,focus:.5,halftone:0},motion:{type:"none",speed:1},hover:{effect:"trail",strength:.55,radius:.2,edgeSafe:!1}},r=t=>t&&"object"==typeof t&&!Array.isArray(t)?t:{},o=(t,e,i,s)=>"number"==typeof t&&Number.isFinite(t)?Math.min(s,Math.max(i,t)):e,n=(t,e)=>"string"==typeof t&&/^#[\da-f]{6}$/i.test(t)?t:e,h=(t,e,i)=>e.includes(t)?t:i;function l(l={}){const c=r(l),f=a;if(void 0!==c.version&&1!==c.version)throw new Error("Unsupported studio settings version. Update asciify-engine.");const d=r(c.crop),m=r(c.backdrop),u=r(c.color),g=r(c.dither),p=r(c.mask),M=r(c.effects),x=r(c.motion),v=r(c.hover),w={...f.effects};for(const t of["bloom","characterBloom","grain","dust","scanlines","crt","prism","vignette","glitch","pixelate","halftone"])w[t]=o(M[t],0,0,1);w.blur=o(M.blur,0,0,24),w.blurType=h(M.blurType,["gaussian","directional","radial","progressive"],f.effects.blurType),w.angle=o(M.angle,0,-180,180),w.focus=o(M.focus,.5,0,1);let b=2048;return{version:1,aspectRatio:h(c.aspectRatio,["original","16:9","9:16","1:1","4:3","3:4","21:9"],"original"),style:h(c.style,t,f.style),cellSize:o(c.cellSize,7,3,60),charset:"string"==typeof c.charset&&c.charset.length?Array.from(c.charset).slice(0,128).join(""):f.charset,colorMode:h(c.colorMode,["accent","source","gray"],f.colorMode),ink:n(c.ink,f.ink),crop:{x:o(d.x,.5,0,1),y:o(d.y,.5,0,1),zoom:o(d.zoom,1,1,5),rotation:90*Math.round(o(d.rotation,0,-360,360)/90)},backdrop:{mode:h(m.mode,["solid","transparent","source","blurred","gradient"],f.backdrop.mode),color:n(m.color,f.backdrop.color),color2:n(m.color2,f.backdrop.color2),blur:o(m.blur,12,0,32),opacity:o(m.opacity,1,0,1)},color:{brightness:o(u.brightness,0,-1,1),contrast:o(u.contrast,1,0,3),saturation:o(u.saturation,1,0,3),grayscale:o(u.grayscale,0,0,1),tint:n(u.tint,f.color.tint),amount:o(u.amount,0,0,1),blend:h(u.blend,i,f.color.blend)},dither:{algorithm:h(g.algorithm,e,"none"),palette:"string"==typeof g.palette&&Object.prototype.hasOwnProperty.call(s,g.palette)?g.palette:"mono",colors:Array.isArray(g.colors)&&g.colors.length>=2?g.colors.slice(0,32).map(t=>n(t,"#000000")):[...f.dither.colors],amount:o(g.amount,1,0,2),scale:Math.round(o(g.scale,2,1,12)),threshold:o(g.threshold,.5,0,1),motion:h(g.motion,["none","drift","shimmer"],"none"),speed:o(g.speed,1,.1,3)},mask:{enabled:!0===p.enabled,invert:!0===p.invert,shapes:Array.isArray(p.shapes)?p.shapes.slice(0,64).map(t=>{const e=r(t),i=h(e.kind,["rectangle","ellipse","brush"],"rectangle"),s="brush"===i&&Array.isArray(e.points)?e.points.slice(0,b).map(t=>Array.isArray(t)?[Math.round(1e4*o(t[0],0,0,1))/1e4,Math.round(1e4*o(t[1],0,0,1))/1e4]:[0,0]):[];return b-=s.length,{kind:i,x:o(e.x,0,0,1),y:o(e.y,0,0,1),width:o(e.width,.5,0,1),height:o(e.height,.5,0,1),size:o(e.size,.05,.005,.5),points:s}}):[]},lights:Array.isArray(c.lights)?c.lights.slice(0,4).map(t=>{const e=r(t);return{x:o(e.x,.5,0,1),y:o(e.y,.5,0,1),radius:o(e.radius,.3,.02,1),intensity:o(e.intensity,.5,0,1),color:n(e.color,"#ffffff")}}):[],effects:w,motion:{type:h(x.type,["none","breathe","wave","reveal","glitch","rainbow","hologram","fire","chrome","ripple","vapor"],"none"),speed:o(x.speed,1,.1,3)},hover:{effect:h(v.effect,["none","trail","water","contour","dissolve","silk","vortex"],"trail"),strength:o(v.strength,.55,0,1),radius:o(v.radius,.2,.1,1),edgeSafe:!0===v.edgeSafe}}}function c(t){return JSON.stringify(l(t))}function f(t){if(t.length>1e5)throw new Error("Settings exceed 100 KB.");return l(JSON.parse(t))}function d(t,e,i,s,a){const r=Math.abs(a.rotation/90)%2==1,o=r?e:t,n=r?t:e,h=Math.max(i/o,s/n)*a.zoom;return{width:o*h,height:n*h,x:(i-o*h)*a.x,y:(s-n*h)*a.y,scale:h,rotated:r}}function m(t,e,i){if(Math.abs(i.crop.rotation/90)%2==1&&([t,e]=[e,t]),"original"===i.aspectRatio)return[t,e];const[s,a]=i.aspectRatio.split(":").map(Number);return t/e>s/a?[Math.round(e*s/a),e]:[t,Math.round(t*a/s)]}function u(t,e){const i={...t,...e};for(const s of["crop","backdrop","color","dither","mask","effects","motion","hover"])e[s]&&Object.assign(i,{[s]:{...t[s],...e[s]}});return l(i)}var g=[["ascii","Signature ASCII","Brand ink and clean characters.",{}],["print","Newsprint","Fine diffusion on warm paper.",{style:"dither",dither:{algorithm:"floyd-steinberg",palette:"newsprint"}}],["handheld","Pocket camera","Four-tone ordered dither.",{style:"dither",dither:{algorithm:"bayer4",palette:"gameboy",scale:3}}],["riso","Two inks","Limited-color print texture.",{style:"dither",dither:{algorithm:"atkinson",palette:"risograph",scale:2}}],["night","Night signal","Gray characters and optical fringe.",{ink:"#888888",effects:{prism:.7,scanlines:.2,vignette:.3}}],["terminal","Phosphor","Green glyphs with a soft glow.",{ink:"#83efad",effects:{bloom:.4,scanlines:.35,crt:.2}}],["mosaic","Mosaic study","Separated color tiles.",{style:"mosaic",cellSize:14,colorMode:"source"}],["bricks","Brickwork","Colorful studded cells.",{style:"lego",cellSize:18,colorMode:"source"}],["voxel","Little volumes","Three-face isometric tiles.",{style:"voxel",cellSize:22,colorMode:"source"}],["disco","Mirror room","Faceted tiles and warm light.",{style:"disco",cellSize:18,colorMode:"source",lights:[{x:.35,y:.25,radius:.25,intensity:.45,color:"#fff2d4"}]}],["wallpaper","Wallpaper","Living ASCII over a softened source.",{backdrop:{mode:"blurred",blur:18,opacity:.55},ink:"#f2e9c9",motion:{type:"breathe",speed:.5}}],["blueprint","Blueprint","Linework in a cool monochrome.",{style:"lines",ink:"#9bccdf",backdrop:{mode:"solid",color:"#0a1e30"}}]].map(([t,e,i,s])=>({id:t,name:e,description:i,settings:l(s)}));function p(t){const e=g.find(e=>e.id===t);if(!e)throw new Error("Unknown studio look.");return l(e.settings)}function M(t,e=Math.random){const i=g.filter(e=>e.settings.style!==t.style||e.settings.ink!==t.ink),s=p(i[Math.min(i.length-1,Math.max(0,Math.floor(e()*i.length)))].id);return s.aspectRatio=t.aspectRatio,s.crop={...t.crop},s.mask=l(t).mask,s}var x=(t,e)=>{const i=43758.5453*Math.sin(127.1*t+311.7*e);return i-Math.floor(i)};function v(t,e,i){let s=0;for(let a=1;a<i;a*=2){const i=Math.floor(t/a)%2;s=4*s+[[0,2],[3,1]][Math.floor(e/a)%2][i]}return(s+.5)/(i*i)-.5}var w={"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]]},b=t=>[parseInt(t.slice(1,3),16),parseInt(t.slice(3,5),16),parseInt(t.slice(5,7),16)];function y(t,e,i){const s=Math.min(t*Math.max(1,i),(1-t)*Math.max(1,i),e*Math.max(1,1/i),(1-e)*Math.max(1,1/i)),a=Math.max(0,Math.min(1,(s-.035)/.105));return a*a*a*(a*(6*a-15)+10)}var k=class{constructor(t,e){this.edgeSafe=!1,this.previous=null,this.peak=0,this.mode="dissolve",this.width=t,this.height=e;const i=t*e;this.pixels=new Uint8Array(4*i),this.ink=new Float32Array(i),this.targetX=new Float32Array(i),this.targetY=new Float32Array(i),this.offsetX=new Float32Array(i),this.offsetY=new Float32Array(i),this.edge=new Float32Array(i);for(let i=0;i<e;i++)for(let s=0;s<t;s++)this.edge[i*t+s]=y(s/(t-1),i/(e-1),t/e);this.clear()}get active(){return this.peak>2e-4}setMode(t){t!==this.mode&&(this.mode=t,this.clear())}clear(){for(const t of[this.ink,this.targetX,this.targetY,this.offsetX,this.offsetY,this.pixels])t.fill(0);if(this.previous=null,this.peak=0,"dissolve"!==this.mode)for(let t=0;t<this.pixels.length;t+=4)this.pixels[t]=this.pixels[t+2]=128}leave(){this.previous=null}move(t,e,i){if(!Number.isFinite(t+e+i))return;t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e));const s=this.previous;this.previous={x:t,y:e};const a=this.width,r=this.height,o=Math.max(1,a/r),n=Math.max(1,r/a),h=s?(t-s.x)*o:0,l=s?(e-s.y)*n:0,c=Math.hypot(h,l);if(!s&&"dissolve"!==this.mode)return;if(s&&c<1e-4)return;const f=.035+.11*Math.max(.1,Math.min(1,i)),d=Math.min(128,Math.max(1,Math.ceil(c/(.45*f)))),m=c?h/c:1,u=c?l/c:0,g=Math.min(1,c/(f*d)*2.2);for(let i=0;i<d;i++){const h=(i+.5)/d,l=s?s.x+(t-s.x)*h:t,c=s?s.y+(e-s.y)*h:e,p=Math.max(0,Math.floor((l-2.5*f/o)*(a-1))),M=Math.min(a-1,Math.ceil((l+2.5*f/o)*(a-1))),x=Math.max(0,Math.floor((c-2.5*f/n)*(r-1))),v=Math.min(r-1,Math.ceil((c+2.5*f/n)*(r-1)));for(let t=x;t<=v;t++)for(let e=p;e<=M;e++){const i=(e/(a-1)-l)*o/f,s=(t/(r-1)-c)*n/f,h=Math.exp(1.5*-(i*i+s*s)),d=t*a+e;if("dissolve"===this.mode)this.ink[d]=Math.max(this.ink[d],h);else{const t=(-i*u+s*m)*h*2.8,e="silk"===this.mode?m*t:-s*h*2.5,a="silk"===this.mode?u*t:i*h*2.5;this.targetX[d]=Math.max(-1,Math.min(1,this.targetX[d]+e*g)),this.targetY[d]=Math.max(-1,Math.min(1,this.targetY[d]+a*g))}}}this.peak=1}step(t){if(!this.active||!Number.isFinite(t))return;const e=Math.max(0,Math.min(.05,t)),i=Math.exp(-("dissolve"===this.mode?2.15:3.2)*e),s=1-Math.exp(-22*e);let a=0;for(let t=0;t<this.ink.length;t++)if("dissolve"===this.mode){this.ink[t]*=i,a=Math.max(a,this.ink[t]);const e=Math.round(65535*this.ink[t]);this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e}else{this.targetX[t]*=i,this.targetY[t]*=i,this.offsetX[t]+=(this.targetX[t]-this.offsetX[t])*s,this.offsetY[t]+=(this.targetY[t]-this.offsetY[t])*s,a=Math.max(a,Math.abs(this.offsetX[t]),Math.abs(this.offsetY[t]),Math.abs(this.targetX[t]),Math.abs(this.targetY[t]));const e=Math.round(this.offsetX[t]*(this.edgeSafe?this.edge[t]:1)*32767+32768),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}this.peak=a,this.active||this.clear()}sample(t,e,i){const s=Math.max(0,Math.min(this.width-1.001,t*(this.width-1))),a=Math.max(0,Math.min(this.height-1.001,e*(this.height-1))),r=Math.floor(s),o=Math.floor(a),n=s-r,h=a-o,l=o*this.width+r,c=l+this.width,f=t=>(t[l]*(1-n)+t[l+1]*n)*(1-h)+(t[c]*(1-n)+t[c+1]*n)*h;i[0]=f(this.offsetX)*(this.edgeSafe?y(t,e,this.width/this.height):1)*.08,i[1]=f(this.offsetY)*(this.edgeSafe?y(t,e,this.width/this.height):1)*.08,i[2]="dissolve"===this.mode?6*-f(this.ink):0}},E=class{constructor(t,e){this.rings=[],this.previous=null,this.elapsed=1,this.echoPeak=0,this.width=t,this.height=e,this.pixels=new Uint8Array(t*e*4),this.echo=new Float32Array(t*e)}get active(){return this.rings.length>0||this.echoPeak>2e-4}clear(){this.rings=[],this.previous=null,this.elapsed=1,this.pixels.fill(0),this.echo.fill(0),this.echoPeak=0}leave(){this.previous=null}move(t,e,i){const s=Math.max(1,this.width/this.height),a=Math.max(1,this.height/this.width);this.previous&&(Math.hypot((t-this.previous.x)*s,(e-this.previous.y)*a)<.065||this.elapsed<.3)||4!==this.rings.length&&(this.previous={x:t,y:e},this.elapsed=0,this.rings.push({x:t,y:e,age:0,radius:i}))}ringSample(t,e){const i=Math.max(1,this.width/this.height),s=Math.max(1,this.height/this.width);let a=0;for(const 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)*s)-o)/n,l=Math.sin(Math.min(1,r.age/.07)*Math.PI/2)*Math.max(0,1-r.age/1.35)**2;a=Math.max(a,Math.exp(-h*h)*l)}return a}sample(t,e){const i=Math.max(0,Math.min(this.width-1,Math.round(t*(this.width-1)))),s=Math.max(0,Math.min(this.height-1,Math.round(e*(this.height-1))));return Math.max(this.ringSample(t,e),this.echo[s*this.width+i])}step(t){if(!Number.isFinite(t))return;const e=Math.max(0,Math.min(.05,t));this.elapsed+=e;for(const t of this.rings)t.age+=e;if(this.rings=this.rings.filter(t=>t.age<1.35),!this.active)return void this.pixels.fill(0);const i=Math.exp(-5.5*e);let s=0;for(let t=0;t<this.height;t++)for(let e=0;e<this.width;e++){const a=t*this.width+e;this.echo[a]=Math.max(this.ringSample(e/(this.width-1),t/(this.height-1)),this.echo[a]*i),s=Math.max(s,this.echo[a]);const r=Math.round(65535*this.echo[a]),o=4*a;this.pixels[o]=r>>>8,this.pixels[o+1]=255&r}this.echoPeak=s,this.active||(this.echo.fill(0),this.pixels.fill(0))}},S=class{constructor(t,e){this.previous=null,this.peak=0,this.width=t,this.height=e;const i=t*e;this.pixels=new Uint8Array(4*i),this.signal=new Float32Array(i),this.offsetX=new Float32Array(i),this.offsetY=new Float32Array(i),this.driftX=new Float32Array(i),this.driftY=new Float32Array(i),this.u=new Float32Array(i),this.v=new Float32Array(i),this.ink=new Float32Array(i),this.a=new Float32Array(i),this.b=new Float32Array(i),this.c=new Float32Array(i),this.pressure=new Float32Array(i),this.pressureNext=new Float32Array(i),this.divergence=new Float32Array(i),this.curl=new Float32Array(i)}get active(){return this.peak>2e-4}clear(){for(const t of[this.u,this.v,this.ink,this.a,this.b,this.c,this.pressure,this.pressureNext,this.divergence,this.curl,this.signal,this.pixels,this.offsetX,this.offsetY,this.driftX,this.driftY])t.fill(0);this.previous=null,this.peak=0}leave(){this.previous=null}move(t,e,i,s=performance.now()){if(!Number.isFinite(t+e+i+s))return;t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e)),i=Math.max(.1,Math.min(1,i));const a=this.previous;if(this.previous={x:t,y:e,time:s},!a)return;const r=(t-a.x)*(this.width-1),o=(e-a.y)*(this.height-1),n=Math.hypot(r,o);if(n<.001)return;const h=Math.min(this.width,this.height),l=s>a.time?Math.max(1/240,(s-a.time)/1e3):1/60,c=Math.min(12,n/h/l),f=1-Math.exp(-c/2.2),d=h*(.022+.075*i)*(.65+.95*f),m=Math.min(128,Math.max(1,Math.ceil(n/(.4*d)))),u=n/d*(.32+.22*f)/m,g=r/n,p=o/n,M=-p,x=g,v=n*(2+18*f)/m;for(let i=0;i<m;i++){const s=(i+.5)/m,r=(a.x+(t-a.x)*s)*(this.width-1),o=(a.y+(e-a.y)*s)*(this.height-1),n=Math.max(1,Math.floor(r-3*d)),h=Math.min(this.width-2,Math.ceil(r+3*d)),l=Math.max(1,Math.floor(o-3*d)),c=Math.min(this.height-2,Math.ceil(o+3*d));for(let t=l;t<=c;t++)for(let e=n;e<=h;e++){const i=((e-r)*g+(t-o)*p)/d,s=((e-r)*M+(t-o)*x)/d,a=Math.exp(-i*i*.65-s*s*1.7),n=t*this.width+e;this.ink[n]=1-(1-this.ink[n])*Math.exp(-a*u);const h=1-s*s*.55,l=i*s*.7;this.u[n]=Math.max(-80,Math.min(80,this.u[n]+(g*h+M*l)*a*v)),this.v[n]=Math.max(-80,Math.min(80,this.v[n]+(p*h+x*l)*a*v))}}this.peak=1}read(t,e,i){const s=0|(e=Math.max(.5,Math.min(this.width-1.5,e))),a=0|(i=Math.max(.5,Math.min(this.height-1.5,i))),r=e-s,o=i-a,n=a*this.width+s;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,s=this.height;for(;e>1e-7;){const t=Math.min(1/60,e);e-=t;const a=Math.exp(-1.9*t),r=Math.exp(-3.2*t);for(let e=1;e<s-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(s-1.5,e-this.v[n]*t)),c=0|h,f=0|l,d=h-c,m=l-f,u=f*i+c,g=(1-d)*(1-m),p=d*(1-m),M=(1-d)*m,x=d*m;this.a[n]=(this.u[u]*g+this.u[u+1]*p+this.u[u+i]*M+this.u[u+i+1]*x)*a,this.b[n]=(this.v[u]*g+this.v[u+1]*p+this.v[u+i]*M+this.v[u+i+1]*x)*a,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<s-1;t++)for(let e=1;e<i-1;e++){const s=t*i+e;this.curl[s]=.5*(this.v[s+1]-this.v[s-1]-this.u[s+i]+this.u[s-i])}for(let e=1;e<s-1;e++)for(let s=1;s<i-1;s++){const a=e*i+s,r=Math.abs(this.curl[a+1])-Math.abs(this.curl[a-1]),o=Math.abs(this.curl[a+i])-Math.abs(this.curl[a-i]),n=Math.hypot(r,o)+1e-4,h=this.curl[a]*t*10,l=Math.hypot(this.u[a],this.v[a]);this.u[a]+=o/n*h,this.v[a]-=r/n*h;const c=Math.min(1,l/(Math.hypot(this.u[a],this.v[a])+1e-6));this.u[a]*=c,this.v[a]*=c,this.divergence[a]=-.5*(this.u[a+1]-this.u[a-1]+this.v[a+i]-this.v[a-i])}this.pressure.fill(0);for(let t=0;t<4;t++){for(let t=1;t<s-1;t++)for(let e=1;e<i-1;e++){const s=t*i+e;this.pressureNext[s]=.25*(this.divergence[s]+this.pressure[s-1]+this.pressure[s+1]+this.pressure[s-i]+this.pressure[s+i])}[this.pressure,this.pressureNext]=[this.pressureNext,this.pressure]}let o=0;for(let e=1;e<s-1;e++)for(let s=1;s<i-1;s++){const a=e*i+s;this.u[a]=Math.max(-80,Math.min(80,this.u[a]-.5*(this.pressure[a+1]-this.pressure[a-1]))),this.v[a]=Math.max(-80,Math.min(80,this.v[a]-.5*(this.pressure[a+i]-this.pressure[a-i]))),this.driftX[a]+=(3.6*this.u[a]-58*this.offsetX[a]-12*this.driftX[a])*t,this.driftY[a]+=(3.6*this.v[a]-58*this.offsetY[a]-12*this.driftY[a])*t,this.offsetX[a]=Math.max(-2,Math.min(2,this.offsetX[a]+this.driftX[a]*t)),this.offsetY[a]=Math.max(-2,Math.min(2,this.offsetY[a]+this.driftY[a]*t)),this.signal[a]=1-Math.exp(.06*-Math.hypot(this.u[a],this.v[a])-.16*this.ink[a]),o=Math.max(o,this.signal[a])}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 A(t,e){const i=Math.max(0,Math.min(1,e/.38));return t+(1-2*t)*(i*i*(3-2*i))}var T=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]=y(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 S(this.columns,this.rows),this.contour=new E(this.columns,this.rows),this.afterimage=new k(this.columns,this.rows),this.clear()}get invertsDensity(){return"trail"===this.mode}get densityTrail(){return["trail","contour","dissolve"].includes(this.mode)}get hasRefraction(){return this.active||this.lensStrength>15e-5}get active(){return["dissolve","silk","vortex"].includes(this.mode)?this.afterimage.active:"contour"===this.mode?this.contour.active:"trail"===this.mode?this.trail.active:this.pending||this.energy>15e-5}setMode(t){t!==this.mode&&(this.clear(),this.mode=t,this.refraction.mode=t,"dissolve"!==t&&"silk"!==t&&"vortex"!==t||this.afterimage.setMode(t),this.refraction.pixels="trail"===t?this.trail.pixels:"contour"===t?this.contour.pixels:["dissolve","silk","vortex"].includes(t)?this.afterimage.pixels:this.waterPixels,this.refraction.strength="water"===t?30*this.amount/.55:"silk"===t?28*this.amount:"vortex"===t?38*this.amount:0)}configure(t,e=.55,i=.2,s=!1){this.setMode(t),this.refraction.edgeSafe=s,this.afterimage.edgeSafe=s,this.amount=Number.isFinite(e)?Math.max(0,Math.min(1,e)):.55,this.radius=Number.isFinite(i)?Math.max(.1,Math.min(1,i)):.2,this.refraction.strength="water"===t?30*this.amount/.55:"silk"===t?28*this.amount:"vortex"===t?38*this.amount:0,this.refraction.focus[2]=this.densityTrail?this.amount:this.lensStrength*this.amount,this.refraction.focus[3]=this.radius}move(t,e,i){if("none"===this.mode||0===this.amount)return;if(!Number.isFinite(t+e))return;if(t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e)),["dissolve","silk","vortex"].includes(this.mode))return void this.afterimage.move(t,e,this.radius);if("contour"===this.mode)return void this.contour.move(t,e,this.radius);if("trail"===this.mode)return void this.trail.move(t,e,this.radius,i);if("water"!==this.mode)return!this.previous&&this.lensStrength<.001&&(this.lensX=t,this.lensY=e),this.previous={x:t,y:e},void(this.pending=!0);if(!this.previous)return void(this.previous={x:t,y:e});const s=this.previous;this.previous={x:t,y:e};const a=(t-s.x)*this.xScale,r=(e-s.y)*this.yScale,o=Math.hypot(a,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 a=(i+.5)/l,r=s.x+(t-s.x)*a,o=s.y+(e-s.y)*a,f=Math.max(1,Math.floor((r-h/this.xScale)*(this.columns-1))),d=Math.min(this.columns-2,Math.ceil((r+h/this.xScale)*(this.columns-1))),m=Math.max(1,Math.floor((o-h/this.yScale)*(this.rows-1))),u=Math.min(this.rows-2,Math.ceil((o+h/this.yScale)*(this.rows-1)));for(let t=m;t<=u;t++)for(let e=f;e<=d;e++){const i=(e/(this.columns-1)-r)*this.xScale,s=(t/(this.rows-1)-o)*this.yScale,a=Math.exp(-(i*i+s*s)/(n*n))*c,h=t*this.columns+e;this.velocity[h]=Math.max(-12,this.velocity[h]-a)}}this.pending=!0}leave(){this.afterimage.leave(),this.contour.leave(),this.trail.leave(),this.previous=null,"water"!==this.mode&&this.lensStrength&&(this.pending=!0)}clear(){this.trail.clear(),this.contour.clear(),this.afterimage.clear(),this.heights.fill(0),this.velocity.fill(0),this.next.fill(0),this.normals.fill(0),this.refraction.focus[2]=0,this.previous=null,this.lensStrength=0,this.energy=0,this.pending=!1,this.remainder=0;for(let t=0;t<this.waterPixels.length;t+=4)this.waterPixels[t]=this.waterPixels[t+2]=128,this.waterPixels[t+1]=this.waterPixels[t+3]=0}step(t){if(!this.active||!Number.isFinite(t))return;if(["dissolve","silk","vortex"].includes(this.mode))return void this.afterimage.step(t);if("contour"===this.mode)return void this.contour.step(t);if("trail"===this.mode)return void this.trail.step(t);if("water"!==this.mode)return void this.stepLight(Math.max(0,Math.min(.05,t)));this.remainder+=Math.max(0,Math.min(.05,t));const e=1/120,i=Math.exp(-3.8*e),s=.3*Math.min(this.columns,this.rows);for(;this.remainder+1e-8>=e;){this.remainder-=e;let t=0;for(let a=1;a<this.rows-1;a++)for(let r=1;r<this.columns-1;r++){const o=a*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,a,this.columns-1-r,this.rows-1-a),c=l<5?.88+.024*l:1,f=(this.velocity[o]+(h*s*s-8*n)*e)*i*c;this.velocity[o]=f,this.next[o]=(n+f*e)*c,t=Math.max(t,Math.abs(this.next[o]),.1*Math.abs(f))}this.heights.set(this.next),this.energy=t,this.pending=!1}if(!this.active)return void this.clear();const a=.18*Math.min(this.columns,this.rows);for(let t=0;t<this.rows;t++)for(let e=0;e<this.columns;e++){const i=t*this.columns+e,s=(this.heights[t*this.columns+Math.max(0,e-1)]-this.heights[t*this.columns+Math.min(this.columns-1,e+1)])*a,r=(this.heights[Math.max(0,t-1)*this.columns+e]-this.heights[Math.min(this.rows-1,t+1)*this.columns+e])*a,o=Math.tanh(s)*(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),s=1-Math.exp(-12*t);e&&(this.lensX+=(e.x-this.lensX)*i,this.lensY+=(e.y-this.lensY)*i),this.lensStrength+=((e?1:0)-this.lensStrength)*s,this.energy=Math.max(e?Math.abs(e.x-this.lensX)+Math.abs(e.y-this.lensY):0,Math.abs((e?1:0)-this.lensStrength)),this.pending=!1,e||this.active?this.refraction.focus=[this.lensX,this.lensY,this.lensStrength*this.amount,this.radius]:this.clear()}sample(t,e,i){if(["dissolve","silk","vortex"].includes(this.mode))return this.afterimage.sample(t,e,i),i[0]*=this.amount,i[1]*=this.amount,void(i[2]*=this.amount);if("contour"===this.mode)return i[0]=i[1]=0,void(i[2]=this.contour.sample(t,e)*this.amount*3);if("trail"===this.mode)return i[0]=i[1]=0,void(i[2]=this.trail.sample(t,e)*this.amount*3);const s=Math.max(0,Math.min(this.columns-1.001,t*(this.columns-1))),a=Math.max(0,Math.min(this.rows-1.001,e*(this.rows-1))),r=Math.floor(s),o=Math.floor(a),n=s-r,h=a-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,s){const[a,r,o,n]=i.focus,h=(t-a)*Math.max(1,s)/n,l=(e-r)*Math.max(1,1/s)/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 F(t){return"videoWidth"in t?[t.videoWidth,t.videoHeight]:"naturalWidth"in t?[t.naturalWidth,t.naturalHeight]:[t.width,t.height]}var I=(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}},R=(t,e,i)=>{t.width===e&&t.height===i||(t.width=e,t.height=i)},P={blocks:" ░▒▓█",braille:" ⠁⠃⠇⡇⣇⣧⣷⣿",lines:" -═╪╬",cross:" ·+xX#",diagonal:" /╱╳",diamond:" ·◇◈◆",mixed:" .:+/◇#@"};function C(t,e={},i={}){const a=t.getContext("2d");if(!a)throw new Error("Canvas is already owned by another renderer.");const r=I(),o=I(!0),n=I(),h=I(),c=I(),f=I(),m=I(),u=I(),g=I();let p,M=l(e),y=0,k="",E=new Uint8ClampedArray(0),S=0,C=0,L=0,X=null,D="",U=new T,B=0;const N=[0,0,0],Y=Math.max(64,Math.min(4096,Number.isFinite(i.maxDimension)?i.maxDimension:960)),O=Math.max(256,Math.min(16e4,Number.isFinite(i.maxCells)?i.maxCells:12e3));let _=O;const z=Math.max(.1,Math.min(8,i.pixelRatio??1));return{canvas:t,render:function(e,i=0,l=960,I=540){if(Number.isFinite(i)||(i=0),!Number.isFinite(l)||!Number.isFinite(I)||l<1||I<1)throw new Error("Render dimensions must be positive finite numbers.");const[O,W]=F(e);if(!O||!W)return;const G=Math.min(1,Y/Math.max(l,I)),q=Math.max(2,Math.round(l*G)),$=Math.max(2,Math.round(I*G));R(t,q,$),R(r.canvas,q,$),R(n.canvas,q,$),R(h.canvas,q,$),R(c.canvas,q,$),B!==q/$&&(B=q/$,U=new T(B)),U.configure(M.hover.effect,M.hover.strength,M.hover.radius,M.hover.edgeSafe),U.step(Math.max(0,Math.min(.05,i-L))),L=i;const j="currentTime"in e?e.getVideoPlaybackQuality?.().totalVideoFrames??e.currentTime:0,V=[y,q,$,j].join(":"),H="dither"===M.style,J=(H?M.dither.scale:M.cellSize)*z,Q=Math.max(J,Math.sqrt(q*$/_)),K=H||["pixel","mosaic","lego","voxel","disco","dots"].includes(M.style)?Q:1.65*Q,Z=Math.max(1,Math.ceil(q/Q)),tt=Math.max(1,Math.ceil($/K));if(k!==V||X!==e||S!==Z||C!==tt){X=e,k=V,S=Z,C=tt,r.ctx.clearRect(0,0,q,$),r.ctx.save();const t=d(O,W,q,$,M.crop);r.ctx.translate(t.x+t.width/2,t.y+t.height/2),r.ctx.rotate(M.crop.rotation*Math.PI/180),r.ctx.drawImage(e,-O*t.scale/2,-W*t.scale/2,O*t.scale,W*t.scale),r.ctx.restore(),R(o.canvas,S,C),o.ctx.clearRect(0,0,S,C),o.ctx.drawImage(r.canvas,0,0,S,C),E=o.ctx.getImageData(0,0,S,C).data;const i=M.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 s=0;s<3;s++){const a=e+(E[t+s]-e)*i.saturation;E[t+s]=((a*(1-i.grayscale)+e*i.grayscale)/255-.5)*i.contrast*255+127.5+255*i.brightness}}}n.ctx.clearRect(0,0,q,$),n.ctx.globalAlpha=1,n.ctx.globalCompositeOperation="source-over";const et=i*M.motion.speed;if(H){const t=new Uint8ClampedArray(E),e=M.motion.type;if(U.active||"none"!==e)for(let i=0;i<C;i++)for(let s=0;s<S;s++){const a=s/S,r=i/C;let o=s,n=i,h=0,l=1,c=1;if(U.active&&(U.sample(a,r,N),o-=N[0]*S,n-=N[1]*C,h=N[2]/3),"wave"===e&&(n+=Math.sin(8*a+2*et+4*r)*C*.015),"ripple"===e){const t=a-.5,e=r-.5,i=.03*Math.sin(30*Math.hypot(t,e)-3*et);o+=t*i*S,n+=e*i*C}"breathe"===e&&(l=.92+.08*Math.sin(1.5*et+3*a)),"reveal"===e&&(c=Math.max(0,Math.min(1,4*(.7*Math.sin(.7*et)+.7-a)))),"glitch"===e&&x(i,Math.floor(6*et))>.93&&(o+=8*Math.sin(5*et)),"vapor"===e&&(n+=Math.sin(6*a+et)*C*.025),"fire"===e&&(n+=Math.sin(7*a+3*et+8*r)*C*.01,l=.8+.2*Math.sin(12*r-4*et)),"hologram"===e&&(c=.72+.28*Math.sin(.65*i+5*et)),"chrome"===e&&(l=.5+Math.abs(Math.sin(8*r+et)));const f=4*(i*S+s),d=4*(Math.max(0,Math.min(C-1,Math.round(n)))*S+Math.max(0,Math.min(S-1,Math.round(o))));for(let i=0;i<3;i++){const s=E[d+i]/255;let r=(["trail","contour"].includes(M.hover.effect)?A(s,h):"dissolve"===M.hover.effect?s*Math.max(0,1+h):s)*l;"rainbow"===e&&(r*=.65+.35*Math.sin(2*et+5*a+2.094*i)),"hologram"===e&&(r*=0===i?.4:1),"fire"===e&&(r*=0===i?1.3:1===i?.7:.3),t[f+i]=255*r}t[f+3]=E[d+3]*c}!function(t,e,i,a,r=0){const{algorithm:o,amount:n,threshold:h}=a,l=("custom"===a.palette?a.colors:s[a.palette]??s.mono).map(b),c=w[o],f=c?new Float32Array(3*e*3):null,d="drift"===a.motion?Math.floor(r*a.speed*3):0,m="shimmer"===a.motion?.15*Math.sin(r*a.speed*2):0;for(let s=0;s<i;s++)for(let a=0;a<e;a++){const r=4*(s*e+a),u=3*(s%3*e+a);if(0===t[r+3]){f&&(f[u]=f[u+1]=f[u+2]=0);continue}let g=0;o.startsWith("bayer")?g=v(a+d&15,s+d&15,Number(o.slice(5))):"noise"===o?g=x(a,s)-.5:"lines"===o?g=(s+d)%4/3-.5:"halftone"===o&&(g=Math.hypot(a%6-2.5,s%6-2.5)/3.54-.5);const p=128*(g*n+m+(.5-h)),M=t[r]+p+(f?.[u]??0),w=t[r+1]+p+(f?.[u+1]??0),b=t[r+2]+p+(f?.[u+2]??0);let y=0,k=0,E=0;if(l.length){let t=1/0;for(const e of l){const i=(M-e[0])**2*.299+(w-e[1])**2*.587+(b-e[2])**2*.114;i<t&&(t=i,[y,k,E]=e)}}else y=51*Math.round(M/51),k=51*Math.round(w/51),E=51*Math.round(b/51);if(t[r]=y,t[r+1]=k,t[r+2]=E,f&&c){f[u]=f[u+1]=f[u+2]=0;for(const[t,r,o]of c){const h=a+t;if(h<0||h>=e||s+r>=i)continue;const l=3*((s+r)%3*e+h);f[l]+=(M-y)*o*n,f[l+1]+=(w-k)*o*n,f[l+2]+=(b-E)*o*n}}}}(t,S,C,M.dither,i),o.ctx.putImageData(new ImageData(t,S,C),0,0),n.ctx.imageSmoothingEnabled=!1,n.ctx.drawImage(o.canvas,0,0,q,$)}else{const t=Array.from(P[M.style]??M.charset),e=n.ctx,i="ascii"===M.style||!!P[M.style],s=Math.max(3,Math.round(.92*K)),a=Math.ceil(Q+4),r=Math.ceil(K+4),o=[t.join(""),s,a,r,M.ink,M.colorMode].join(":");i&&o!==D&&(D=o,R(m.canvas,a*t.length,r),m.ctx.clearRect(0,0,m.canvas.width,r),m.ctx.font=`${s}px monospace`,m.ctx.textBaseline="middle",m.ctx.textAlign="center",m.ctx.fillStyle="accent"===M.colorMode?M.ink:"#ffffff",t.forEach((t,e)=>m.ctx.fillText(t,e*a+a/2,r/2))),e.font=`${s}px monospace`,e.textBaseline="middle",e.textAlign="center";for(let s=0;s<C;s++)for(let o=0;o<S;o++){let n=o,h=s,l=0;U.active&&(U.sample(o/S,s/C,N),n=Math.max(0,Math.min(S-1,o-N[0]*S)),h=Math.max(0,Math.min(C-1,s-N[1]*C)),l=N[2]/3);const c=4*(Math.floor(h)*S+Math.floor(n));if(!E[c+3])continue;const f=E[c],d=E[c+1],u=E[c+2],g=(.299*f+.587*d+.114*u)/255;let p=g;["trail","contour"].includes(M.hover.effect)&&l?p=A(p,l):"dissolve"===M.hover.effect&&(p*=Math.max(0,1+l));const v=M.motion.type;let w=o*Q,b=s*K,y=1;if("breathe"===v&&(p*=.92+.08*Math.sin(1.5*et+.03*o)),"wave"===v&&(b+=Math.sin(.12*o+2*et+.08*s)*K*.4),"ripple"===v){const t=o/S-.5,e=s/C-.5,i=Math.hypot(t,e),a=Math.sin(30*i-3*et)*Q*.65;w+=t*a,b+=e*a}"fire"===v&&(b-=Math.sin(.16*o+3*et+.09*s)*K*.35,p*=.85+.15*Math.sin(.3*s-4*et)),"hologram"===v&&(y=.72+.28*Math.sin(.65*s+5*et)),"reveal"===v&&(y=Math.max(0,Math.min(1,4*(.7*Math.sin(.7*et)+.7-o/S)))),"glitch"===v&&x(s,Math.floor(6*et))>.93&&(w+=Math.sin(5*et)*Q*3),"vapor"===v&&(b+=Math.sin(.04*o+et)*K),i||"accent"!==M.colorMode||(y*=p),e.globalAlpha=y;const k=255*(p-g);let T="source"===M.colorMode?`rgb(${f+k},${d+k},${u+k})`:"gray"===M.colorMode?`rgb(${Math.round(255*p)},${Math.round(255*p)},${Math.round(255*p)})`:M.ink;if("rainbow"===v&&(T=`hsl(${(o/S*180+40*et)%360} 70% 65%)`),"fire"===v&&(T=`hsl(${15+40*p} 90% ${30+45*p}%)`),"hologram"===v&&(T=`hsl(185 65% ${40+40*p}%)`),"chrome"===v&&(T=`hsl(210 12% ${25+70*Math.abs(Math.sin(.2*s+et))}%)`),e.fillStyle=T,i){const i=Math.max(0,Math.min(t.length-1,Math.floor(p*(t.length-1))));"accent"!==M.colorMode||["rainbow","fire","hologram","chrome"].includes(v)?e.fillText(t[i],w+Q/2,b+K/2):e.drawImage(m.canvas,i*a,0,a,r,w+(Q-a)/2,b+(K-r)/2,a,r)}else if("dots"===M.style)e.beginPath(),e.arc(w+Q/2,b+K/2,.48*Q*Math.sqrt(p),0,2*Math.PI),e.fill();else if("voxel"===M.style){const t=w+Q/2,i=b+K/2;e.beginPath(),e.moveTo(t,b),e.lineTo(w+Q,b+.25*K),e.lineTo(t,i),e.lineTo(w,b+.25*K),e.closePath(),e.fill(),e.globalAlpha=.72*y,e.beginPath(),e.moveTo(w,b+.25*K),e.lineTo(t,i),e.lineTo(t,b+K),e.lineTo(w,b+.75*K),e.closePath(),e.fill(),e.globalAlpha=.42*y,e.beginPath(),e.moveTo(t,i),e.lineTo(w+Q,b+.25*K),e.lineTo(w+Q,b+.75*K),e.lineTo(t,b+K),e.closePath(),e.fill()}else{const t="pixel"===M.style?0:Math.max(.5,.06*Q);e.fillRect(w,b,Q-t,K-t),"lego"===M.style&&(e.fillStyle="rgba(255,255,255,.2)",e.beginPath(),e.arc(w+Q/2,b+K/2,.28*Q,0,2*Math.PI),e.fill(),e.strokeStyle="rgba(0,0,0,.25)",e.stroke()),"disco"===M.style&&(e.fillStyle=`rgba(255,255,255,${.1+.25*x(o,s)})`,e.fillRect(w,b,Q-t,.35*K),e.fillStyle="rgba(0,0,0,.25)",e.fillRect(w,b+.65*K,Q-t,.35*K-t))}}}n.ctx.globalAlpha=1,(M.color.amount||M.lights.length)&&(R(u.canvas,q,$),u.ctx.clearRect(0,0,q,$),u.ctx.drawImage(n.canvas,0,0)),M.color.amount&&(n.ctx.save(),n.ctx.globalCompositeOperation=M.color.blend,n.ctx.globalAlpha=M.color.amount,n.ctx.fillStyle=M.color.tint,n.ctx.fillRect(0,0,q,$),n.ctx.restore());for(const t of M.lights){const e=t.radius*Math.max(q,$),i=n.ctx.createRadialGradient(t.x*q,t.y*$,0,t.x*q,t.y*$,e);i.addColorStop(0,t.color),i.addColorStop(1,"transparent"),n.ctx.save(),n.ctx.globalCompositeOperation="screen",n.ctx.globalAlpha=t.intensity,n.ctx.fillStyle=i,n.ctx.fillRect(0,0,q,$),n.ctx.restore()}if((M.color.amount||M.lights.length)&&(n.ctx.globalCompositeOperation="destination-in",n.ctx.drawImage(u.canvas,0,0),n.ctx.globalCompositeOperation="source-over"),M.mask.enabled&&M.mask.shapes.length){const t=c.ctx;t.clearRect(0,0,q,$),t.fillStyle="#fff",t.strokeStyle="#fff",t.lineCap="round",t.lineJoin="round";for(const e of M.mask.shapes){if(t.beginPath(),"ellipse"===e.kind)t.ellipse((e.x+e.width/2)*q,(e.y+e.height/2)*$,e.width*q/2,e.height*$/2,0,0,2*Math.PI);else{if("rectangle"!==e.kind){if(t.lineWidth=(e.size??.05)*q,1===e.points?.length){t.arc(e.points[0][0]*q,e.points[0][1]*$,t.lineWidth/2,0,2*Math.PI),t.fill();continue}e.points?.forEach(([e,i],s)=>s?t.lineTo(e*q,i*$):t.moveTo(e*q,i*$)),t.stroke();continue}t.rect(e.x*q,e.y*$,e.width*q,e.height*$)}t.fill()}n.ctx.globalCompositeOperation=M.mask.invert?"destination-out":"destination-in",n.ctx.drawImage(c.canvas,0,0),n.ctx.globalCompositeOperation="source-over"}const it=h.ctx;it.clearRect(0,0,q,$),it.globalAlpha=M.backdrop.opacity;const st=M.backdrop;if("solid"===st.mode&&(it.fillStyle=st.color,it.fillRect(0,0,q,$)),"gradient"===st.mode){const t=it.createLinearGradient(0,0,q,$);t.addColorStop(0,st.color),t.addColorStop(1,st.color2),it.fillStyle=t,it.fillRect(0,0,q,$)}if("source"===st.mode&&it.drawImage(r.canvas,0,0),"blurred"===st.mode){const t=Math.max(1,st.blur);R(f.canvas,Math.max(2,Math.round(q/t)),Math.max(2,Math.round($/t))),f.ctx.drawImage(r.canvas,0,0,f.canvas.width,f.canvas.height),it.imageSmoothingEnabled=!0,it.drawImage(f.canvas,0,0,q,$)}it.globalAlpha=1,M.effects.characterBloom>0&&(R(g.canvas,Math.max(2,Math.round(q/3)),Math.max(2,Math.round($/3))),g.ctx.clearRect(0,0,g.canvas.width,g.canvas.height),g.ctx.drawImage(n.canvas,0,0,g.canvas.width,g.canvas.height),it.save(),it.globalAlpha=.8*M.effects.characterBloom,it.globalCompositeOperation="screen",it.filter=`blur(${1+4*M.effects.characterBloom}px)`,it.drawImage(g.canvas,0,0,q,$),it.restore()),it.drawImage(n.canvas,0,0);const at=Object.entries(M.effects).some(([t,e])=>!["angle","focus","blurType","characterBloom"].includes(t)&&"number"==typeof e&&e>0);a.clearRect(0,0,q,$),at?(void 0===p&&(p=function(){const t=document.createElement("canvas"),e=t.getContext("webgl",{alpha:!0,premultipliedAlpha:!1,antialias:!1,preserveDrawingBuffer:!0});if(!e)return null;const i=[],s=(t,s)=>{const a=e.createShader(t);if(i.push(a),e.shaderSource(a,s),e.compileShader(a),!e.getShaderParameter(a,e.COMPILE_STATUS))throw new Error(e.getShaderInfoLog(a)||"Finish shader failed");return a},a=e.createProgram();if(e.attachShader(a,s(e.VERTEX_SHADER,"attribute vec2 p;varying vec2 uv;void main(){uv=(p+1.)*.5;gl_Position=vec4(p,0.,1.);}")),e.attachShader(a,s(e.FRAGMENT_SHADER,"precision mediump float;varying vec2 uv;uniform sampler2D src;uniform vec2 size;uniform float t,bloom,grain,dust,scanlines,crt,prism,vignette,glitch,pixelate,blur,blurMode,angle,focus,halftone;\n float hash(vec2 p){return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453);}\n vec4 sampleAt(vec2 p){if(min(min(p.x,p.y),min(1.-p.x,1.-p.y))<0.)return vec4(0.);return texture2D(src,vec2(p.x,1.-p.y));}\n void main(){vec2 q=uv,c=q-.5;q=c*(1.+dot(c,c)*crt*.25)+.5;\n if(glitch>0.)q.x+=(hash(vec2(floor(q.y*35.),floor(t*5.)))-.5)*.07*glitch*step(.82,hash(vec2(floor(q.y*35.),floor(t*5.)+3.)));\n if(pixelate>0.){vec2 grid=size/(1.+pixelate*20.);q=(floor(q*grid)+.5)/grid;}\n vec4 base=sampleAt(q);float edge=smoothstep(.12,.65,length(c));\n vec2 shift=vec2(prism*3.*edge/size.x,prism*edge/size.y);\n if(prism>0.)base.rgb=vec3(sampleAt(q+shift).r,base.g,sampleAt(q-shift).b);\n vec2 dir=vec2(cos(angle),sin(angle))/size;float amount=blur;\n if(blurMode>1.5&&blurMode<2.5){dir=normalize(c+vec2(.0001))/size;amount*=length(c)*2.;}\n if(blurMode>2.5)amount*=smoothstep(.05,.5,abs(q.y-focus));\n vec4 blurred=base;\n if(amount>0.){blurred=base*.2;for(int i=1;i<=4;i++){float f=float(i)*amount*.35;vec2 off=dir*f;if(blurMode<.5)off=vec2(cos(float(i)*1.57),sin(float(i)*1.57))*amount/size;blurred+=sampleAt(q+off)*.1+sampleAt(q-off)*.1;}}\n vec3 light=vec3(0.);if(bloom>0.)for(int i=0;i<4;i++){float a=float(i)*1.5708;vec3 s=sampleAt(q+vec2(cos(a),sin(a))*6./size).rgb;light+=max(vec3(0.),s-.35)*.25;}\n vec3 col=blurred.rgb+light*bloom;col*=1.-scanlines*.4*(.5+.5*cos(q.y*size.y*3.14159));\n col*=1.-vignette*smoothstep(.15,.72,length(c));\n col+=(hash(floor(q*size)+floor(t*12.))-.5)*grain*.2;\n if(dust>0.)col+=step(1.-dust*.002,hash(floor(q*size*.25)+floor(t*2.)))*.4;\n if(halftone>0.)col*=mix(1.,smoothstep(.1,.65,length(fract(q*size/6.)-.5)),halftone);\n gl_FragColor=vec4(clamp(col,0.,1.),blurred.a);}")),e.linkProgram(a),!e.getProgramParameter(a,e.LINK_STATUS))throw new Error("Finish link failed");e.useProgram(a);const 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(a,"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","vignette","glitch","pixelate","blur","blurMode","angle","focus","halftone"],l=Object.fromEntries(h.map(t=>[t,e.getUniformLocation(a,t)])),c=e.getUniformLocation(a,"size");return{canvas:t,render(i,s,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(a),e.bindTexture(e.TEXTURE_2D,n),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,i),e.uniform2f(c,t.width/o,t.height/o);for(const t of h)e.uniform1f(l[t],"t"===t?r:"blurMode"===t?["gaussian","directional","radial","progressive"].indexOf(s.blurType):"angle"===t?s.angle*Math.PI/180:s[t]??0);return e.drawArrays(e.TRIANGLE_STRIP,0,4),t},destroy(){e.deleteTexture(n),e.deleteBuffer(r),e.deleteProgram(a),i.forEach(t=>e.deleteShader(t)),t.width=t.height=1,e.getExtension("WEBGL_lose_context")?.loseContext()}}}()),p?a.drawImage(p.render(h.canvas,M.effects,i,z),0,0):a.drawImage(h.canvas,0,0),t.dataset.studioFinish=p?"gpu":"unavailable"):(a.drawImage(h.canvas,0,0),t.dataset.studioFinish="none")},setBudget(t){_=Math.max(1500,Math.min(O,Math.round(t)))},get maxCells(){return _},configure(t){M=l(t),y++},pointer:(t,e,i)=>{U.configure(M.hover.effect,M.hover.strength,M.hover.radius,M.hover.edgeSafe),U.move(t,e,i)},leave(){U.leave()},get active(){return U.active},get settings(){return l(M)},get capabilities(){return{gpuFinish:null!==p}},invalidate(){k=""},destroy(){p?.destroy();for(const t of[r,o,n,h,c,f,m,u,g])t.canvas.width=t.canvas.height=1;X=null,E=new Uint8ClampedArray(0)}}}function L(t,e,i){return new Promise((s,a)=>{const r=()=>{l(),s()},o=()=>{l(),a(new Error("Unable to load this media. Check its format and cross-origin permissions."))},n=()=>{l(),a(new DOMException("Cancelled","AbortError"))},h=setTimeout(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 X(t,e){if("string"==typeof t&&t.startsWith("blob:")){const i=await fetch(t,{signal:e}),s=await i.blob();return X(new File([s],"Imported media",{type:s.type}),e)}const i="string"!=typeof t,s=i?t.name:t;if(i?"image/gif"===t.type:/\.gif(?:[?#]|$)/i.test(s)){const s=await import("gifuct-js"),{parseGIF:a,decompressFrames:r}="function"==typeof s.parseGIF?s:s.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=a(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 f=r(n,!0);if(f.length*h*l*4>128e6)throw new Error("GIF exceeds the 128 MB decoded budget. Use MP4 for long animations.");const d=document.createElement("canvas");d.width=h,d.height=l;const m=d.getContext("2d"),u=document.createElement("canvas"),g=u.getContext("2d"),p=f.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,s=0;for(;s<f.length-1&&(i+=Math.max(20,f[s].delay),!(e<i));s++);s<M&&(m.clearRect(0,0,h,l),M=-1,x=null);for(let t=M+1;t<=s;t++){const e=f[t-1];2===e?.disposalType&&m.clearRect(e.dims.left,e.dims.top,e.dims.width,e.dims.height),3===e?.disposalType&&x&&m.putImageData(x,0,0);const i=f[t];x=3===i.disposalType?m.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),m.drawImage(u,i.dims.left,i.dims.top)}return M=s,d};return v(0),{source:d,width:h,height:l,duration:p,animated:!0,seek:async()=>{},frame:v,destroy(){d.width=u.width=1,f.length=0,x=null}}}const a=i?t.type.startsWith("video/"):/\.(mp4|webm|mov)(?:[?#]|$)/i.test(s),r=i?URL.createObjectURL(t):t,o=a?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=L(o,a?"loadeddata":"load",e);o.src=r,await t;const i=o instanceof HTMLVideoElement?o.videoWidth:o.naturalWidth,s=o instanceof HTMLVideoElement?o.videoHeight:o.naturalHeight;return{source:o,width:i,height:s,duration:o instanceof HTMLVideoElement?o.duration:0,animated:a,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 s=L(o,"seeked",e);o.currentTime=i,await s},frame:()=>o,destroy:n}}catch(t){throw n(),t}}var D=t=>{if(t?.aborted)throw new DOMException("Export cancelled","AbortError")};async function U(t,e,i){const{format:s,signal:a}=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(s))throw new Error("Unknown export format.");if(void 0!==i.fps&&!Number.isFinite(i.fps))throw new Error("Frames per second must be finite.");const n=Math.max(1,Math.min(60,Math.round(i.fps??24))),h=i.duration??5;if(!Number.isFinite(h)||h<=0||h>60)throw new Error("Choose a duration from 0 to 60 seconds.");const c="png"===s||"jpeg"===s;if(!c&&r*o>8294400)throw new Error("Video exports support up to 3840 × 2160 pixels.");if("gif"===s&&(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"===s&&n>30)throw new Error("GIF exports support up to 30 fps. Choose MP4 or WebM for higher frame rates.");const f=document.createElement("canvas"),d=C(f,l(e),{maxDimension:4096,maxCells:i.maxCells??12e3,pixelRatio:r/(i.referenceWidth??Math.min(r,960))});let m;try{if(D(a),i.onProgress?.(0),c){if(d.render(await t.frame(0,a),0,r,o),"unavailable"===f.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");D(a);const e=await new Promise((t,e)=>f.toBlob(i=>i?t(i):e(new Error("Image export failed.")),"png"===s?"image/png":"image/jpeg",i.quality??.92));return i.onProgress?.(1),e}const e=Math.ceil(h*n);if("gif"===s){const s=await import("gifenc"),{GIFEncoder:l,quantize:c,applyPalette:m}="function"==typeof s.GIFEncoder?s:s.default,u=l(),g=f.getContext("2d");for(let s=0;s<e;s++){D(a);const l=s/n;if(d.invalidate(),d.render(await t.frame(l,a),l,r,o),"unavailable"===f.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=m(p,M);u.writeFrame(x,r,o,{palette:M,delay:10*(Math.round(100*Math.min((s+1)/n,h))-Math.round(100*s/n)),repeat:0}),i.onProgress?.((s+1)/e*.98),await new Promise(t=>setTimeout(t,0))}return u.finish(),i.onProgress?.(1),new Blob([new Uint8Array(u.bytes())],{type:"image/gif"})}const{Output:l,Mp4OutputFormat:u,WebMOutputFormat:g,BufferTarget:p,CanvasSource:M,canEncodeVideo:x}=await import("mediabunny"),v="mp4"===s?"avc":"vp9";if(!await x(v,{width:r,height:o}))throw new Error(`${s.toUpperCase()} encoding is unavailable in this browser. Try another format or a current browser with WebCodecs.`);const w=new l({format:"mp4"===s?new u({fastStart:"in-memory"}):new g,target:new p});f.width=r,f.height=o,m=()=>w.cancel();const b=new M(f,{codec:v,bitrate:Math.max(5e5,Math.round(r*o*n*.15))});w.addVideoTrack(b,{frameRate:n}),f.width=r,f.height=o,await w.start();for(let s=0;s<e;s++){D(a);const l=s/n;if(d.invalidate(),d.render(await t.frame(l,a),l,r,o),"unavailable"===f.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");await b.add(l,Math.min(1/n,h-l)),i.onProgress?.((s+1)/e*.98),s%4==0&&await new Promise(t=>setTimeout(t,0))}return b.close(),D(a),await w.finalize(),m=void 0,i.onProgress?.(1),new Blob([w.target.buffer],{type:"mp4"===s?"video/mp4":"video/webm"})}catch(t){throw await(m?.().catch(()=>{})),t}finally{d.destroy(),f.width=f.height=1}}async function B(t,e,i={}){const s=await X(e,i.signal);try{return N(t,s,i)}catch(t){throw s.destroy(),t}}function N(t,e,i={}){let s=l(i.settings),a=i.width??e.width,r=i.height??e.height;const o=C(t,s,i);let n=0,h=!1,c=!0,f=!1,d=!0,g=0,p=0,M=0,x=-1,v=0,w=0,b=0;const y=matchMedia("(prefers-reduced-motion: reduce)"),k=e.source instanceof HTMLVideoElement?e.source:null,E=()=>{h||n||!d||document.hidden||(n=requestAnimationFrame(T))},S=()=>!f&&!y.matches&&d&&!document.hidden,A=()=>{k&&(k.loop=!0,S()?k.play().catch(()=>{f=!0,c=!0,E()}):k.pause()),p=0,c=!0,E()};function T(t){if(n=0,h||!d||document.hidden)return;const l=S();l&&(g+=p?Math.min(.1,(t-p)/1e3):0),p=t;const u=l&&(e.animated||"none"!==s.motion.type||"none"!==s.dither.motion||s.effects.grain>0||s.effects.dust>0||s.effects.glitch>0),y=k?.getVideoPlaybackQuality?.().totalVideoFrames??-1,A="none"!==s.motion.type||"none"!==s.dither.motion||s.effects.grain>0||s.effects.dust>0||s.effects.glitch>0,T=!k||y<0||y!==x;if(c||o.active||u&&(T||A)&&t-M>=1e3/Math.max(1,Math.min(60,i.fps??60))-.5){const n=performance.now();try{e.animated&&!k&&o.invalidate();const[t,h]=m(a,r,s);o.render(e.frame(k?.currentTime??g),g,t,h);const l=performance.now()-n;i.onFrame?.(k?.currentTime??g,l),w=w?.9*w+.1*l:l,++v>20&&!1!==i.adaptive&&(b=w>13?b+1:0,b>=12&&o.maxCells>3e3&&(o.setBudget(Math.max(3e3,.8*o.maxCells)),i.onQualityChange?.(o.maxCells),b=0,w=0))}catch(t){f=!0,i.onError?.(t instanceof Error?t:new Error(String(t)))}c=!1,M=t,x=y}l&&(u||o.active)&&E()}const F=e=>{if(!S())return;const i=t.getBoundingClientRect();o.pointer((e.clientX-i.left)/i.width,(e.clientY-i.top)/i.height,e.timeStamp),E()},I=()=>{o.leave(),E()},R=new IntersectionObserver(([t])=>{d=t.isIntersecting,A()});R.observe(t),t.addEventListener("pointermove",F),t.addEventListener("pointerleave",I),t.addEventListener("pointercancel",I),document.addEventListener("visibilitychange",A),y.addEventListener("change",A);const P=()=>{h||(h=!0,cancelAnimationFrame(n),R.disconnect(),t.removeEventListener("pointermove",F),t.removeEventListener("pointerleave",I),t.removeEventListener("pointercancel",I),document.removeEventListener("visibilitychange",A),y.removeEventListener("change",A),i.signal?.removeEventListener("abort",P),o.destroy(),e.destroy())};if(i.signal?.addEventListener("abort",P,{once:!0}),i.signal?.aborted)throw P(),new DOMException("Cancelled","AbortError");return A(),{canvas:t,media:e,update(t){s=u(s,t),o.configure(s),c=!0,E()},resize(t,e){a=Math.max(2,t),r=Math.max(2,e),c=!0,E()},pause(t=!0){f=t,A()},async seek(t){g=Math.max(0,t),await e.seek(g),o.invalidate(),c=!0,E()},redraw(){o.invalidate(),c=!0,E()},get time(){return k?.currentTime??g},get paused(){return f||y.matches},get maxCells(){return o.maxCells},get capabilities(){return o.capabilities},destroy:P}}var Y={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")},O=Object.keys(Y);async function _(t,e="Standard",i="#ffffff"){if(!Object.prototype.hasOwnProperty.call(Y,e))throw new Error("Unknown text font.");const{default:s}=await import("figlet/browser"),a=await Y[e]();s.parseFont(e,a.default),s.defaults({fetchFontIfMissing:!1});const r=s.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 f=c.getContext("2d");return f.fillStyle="#080808",f.fillRect(0,0,c.width,c.height),f.fillStyle=i,f.font=15*l+"px monospace",f.textBaseline="top",o.forEach((t,e)=>f.fillText(t,16,16+15*e*l)),{canvas:c,ascii:r}}var z={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:" ⠁⠃⠇⡇⣇⣧⣷⣿"}};export{i as BLEND_MODES,a as DEFAULT_STUDIO_SETTINGS,e as DITHER_ALGORITHMS,z as STUDIO_CHARACTER_SETS,g as STUDIO_LOOKS,s as STUDIO_PALETTES,t as STUDIO_STYLES,O as STUDIO_TEXT_FONTS,C as createStudioRenderer,_ as createStudioText,U as exportStudio,X as loadStudioMedia,B as mountStudio,N as mountStudioMedia,l as normalizeStudioSettings,f as parseStudioSettings,M as restyleStudio,c as serializeStudioSettings,d as studioCrop,m as studioDimensions,p as studioLook,F as studioSourceSize,u as updateStudioSettings};//# sourceMappingURL=studio.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
type ColorMode = 'grayscale' | 'fullcolor' | 'matrix' | 'accent';
|
|
2
2
|
type RenderMode = 'ascii' | 'dots';
|
|
3
3
|
type AnimationStyle = 'none' | 'wave' | 'pulse' | 'rain' | 'breathe' | 'sparkle' | 'glitch' | 'spiral' | 'typewriter' | 'scatter' | 'waveField' | 'ripple' | 'melt' | 'orbit' | 'cellular';
|
|
4
|
-
type ArtStyle = 'classic' | 'particles' | 'letters' | 'claudeCode' | 'art' | 'terminal' | 'box' | 'lines' | 'braille' | 'katakana' | '
|
|
4
|
+
type ArtStyle = 'classic' | 'particles' | 'letters' | 'claudeCode' | 'art' | 'terminal' | 'box' | 'lines' | 'braille' | 'katakana' | 'circles' | 'shadows' | 'geometric' | 'pipes' | 'waves' | 'shards' | 'smoke' | 'ascii' | 'interface' | 'prompt' | 'data' | 'humanist' | 'mesh';
|
|
5
5
|
type HoverEffect = 'spotlight' | 'magnify' | 'repel' | 'glow' | 'colorShift' | 'attract' | 'shatter' | 'trail' | 'glitchText';
|
|
6
6
|
type HoverShape = 'circle' | 'box';
|
|
7
7
|
type HoverPreset = 'none' | 'subtle' | 'flashlight' | 'magnifier' | 'forceField' | 'neon' | 'fire' | 'ice' | 'gravity' | 'shatter' | 'ghost' | 'glitchReveal';
|
|
@@ -323,11 +323,8 @@ declare const CHARSETS: {
|
|
|
323
323
|
readonly lines: " ˗‐–—―━";
|
|
324
324
|
readonly braille: " ⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿⡀⡁⡂⡃⡄⡅⡆⡇⣀⣁⣂⣃⣄⣅⣆⣇⣈⣉⣊⣋⣌⣍⣎⣏⣐⣑⣒⣓⣔⣕⣖⣗⣘⣙⣚⣛⣜⣝⣞⣟⣠⣡⣢⣣⣤⣥⣦⣧⣨⣩⣪⣫⣬⣭⣮⣯⣰⣱⣲⣳⣴⣵⣶⣷⣸⣹⣺⣻⣼⣽⣾⣿";
|
|
325
325
|
readonly katakana: " ヲァィゥェォャュョッアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン";
|
|
326
|
-
readonly musical: " ♩♪♫♬♭♮♯";
|
|
327
|
-
readonly emoji: " ⬛🟫🟥🟧🟨🟩🟦🟪⬜";
|
|
328
326
|
readonly circles: " .·:∘○◦°•∙";
|
|
329
327
|
readonly shadows: " ·∘◦○◎⊙●◉";
|
|
330
|
-
readonly starfield: " ˙·∘∗✦✧★◆●";
|
|
331
328
|
readonly geometric: " ·△▷◇◈◆▣■█";
|
|
332
329
|
readonly pipes: " ╶─┐└├┤┬┴┼╬▒▓█";
|
|
333
330
|
readonly waves: " ˜∼≈〰≋∿∾∭∫";
|
|
@@ -355,7 +352,7 @@ declare const CHARSETS: {
|
|
|
355
352
|
* asciiBackground('#hero', { charsetFrames: CHARSET_SEQUENCES.cosmic })
|
|
356
353
|
*/
|
|
357
354
|
declare const CHARSET_SEQUENCES: {
|
|
358
|
-
/**
|
|
355
|
+
/** Sparse marks → circles → orbs — soft tonal texture */
|
|
359
356
|
readonly cosmic: string[];
|
|
360
357
|
/** Katakana → braille dots → binary — hacker rain */
|
|
361
358
|
readonly rain: string[];
|
|
@@ -369,7 +366,7 @@ declare const CHARSET_SEQUENCES: {
|
|
|
369
366
|
readonly pulse: string[];
|
|
370
367
|
/** Braille → shadows → smoke — ethereal / dream-like */
|
|
371
368
|
readonly dream: string[];
|
|
372
|
-
/** Geometric shapes → shards →
|
|
369
|
+
/** Geometric shapes → shards → blocks — angular texture */
|
|
373
370
|
readonly angular: string[];
|
|
374
371
|
/** Interface controls → prompts → data nodes — clean assistant/product motion */
|
|
375
372
|
readonly assistant: string[];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
type ColorMode = 'grayscale' | 'fullcolor' | 'matrix' | 'accent';
|
|
2
2
|
type RenderMode = 'ascii' | 'dots';
|
|
3
3
|
type AnimationStyle = 'none' | 'wave' | 'pulse' | 'rain' | 'breathe' | 'sparkle' | 'glitch' | 'spiral' | 'typewriter' | 'scatter' | 'waveField' | 'ripple' | 'melt' | 'orbit' | 'cellular';
|
|
4
|
-
type ArtStyle = 'classic' | 'particles' | 'letters' | 'claudeCode' | 'art' | 'terminal' | 'box' | 'lines' | 'braille' | 'katakana' | '
|
|
4
|
+
type ArtStyle = 'classic' | 'particles' | 'letters' | 'claudeCode' | 'art' | 'terminal' | 'box' | 'lines' | 'braille' | 'katakana' | 'circles' | 'shadows' | 'geometric' | 'pipes' | 'waves' | 'shards' | 'smoke' | 'ascii' | 'interface' | 'prompt' | 'data' | 'humanist' | 'mesh';
|
|
5
5
|
type HoverEffect = 'spotlight' | 'magnify' | 'repel' | 'glow' | 'colorShift' | 'attract' | 'shatter' | 'trail' | 'glitchText';
|
|
6
6
|
type HoverShape = 'circle' | 'box';
|
|
7
7
|
type HoverPreset = 'none' | 'subtle' | 'flashlight' | 'magnifier' | 'forceField' | 'neon' | 'fire' | 'ice' | 'gravity' | 'shatter' | 'ghost' | 'glitchReveal';
|
|
@@ -323,11 +323,8 @@ declare const CHARSETS: {
|
|
|
323
323
|
readonly lines: " ˗‐–—―━";
|
|
324
324
|
readonly braille: " ⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿⡀⡁⡂⡃⡄⡅⡆⡇⣀⣁⣂⣃⣄⣅⣆⣇⣈⣉⣊⣋⣌⣍⣎⣏⣐⣑⣒⣓⣔⣕⣖⣗⣘⣙⣚⣛⣜⣝⣞⣟⣠⣡⣢⣣⣤⣥⣦⣧⣨⣩⣪⣫⣬⣭⣮⣯⣰⣱⣲⣳⣴⣵⣶⣷⣸⣹⣺⣻⣼⣽⣾⣿";
|
|
325
325
|
readonly katakana: " ヲァィゥェォャュョッアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン";
|
|
326
|
-
readonly musical: " ♩♪♫♬♭♮♯";
|
|
327
|
-
readonly emoji: " ⬛🟫🟥🟧🟨🟩🟦🟪⬜";
|
|
328
326
|
readonly circles: " .·:∘○◦°•∙";
|
|
329
327
|
readonly shadows: " ·∘◦○◎⊙●◉";
|
|
330
|
-
readonly starfield: " ˙·∘∗✦✧★◆●";
|
|
331
328
|
readonly geometric: " ·△▷◇◈◆▣■█";
|
|
332
329
|
readonly pipes: " ╶─┐└├┤┬┴┼╬▒▓█";
|
|
333
330
|
readonly waves: " ˜∼≈〰≋∿∾∭∫";
|
|
@@ -355,7 +352,7 @@ declare const CHARSETS: {
|
|
|
355
352
|
* asciiBackground('#hero', { charsetFrames: CHARSET_SEQUENCES.cosmic })
|
|
356
353
|
*/
|
|
357
354
|
declare const CHARSET_SEQUENCES: {
|
|
358
|
-
/**
|
|
355
|
+
/** Sparse marks → circles → orbs — soft tonal texture */
|
|
359
356
|
readonly cosmic: string[];
|
|
360
357
|
/** Katakana → braille dots → binary — hacker rain */
|
|
361
358
|
readonly rain: string[];
|
|
@@ -369,7 +366,7 @@ declare const CHARSET_SEQUENCES: {
|
|
|
369
366
|
readonly pulse: string[];
|
|
370
367
|
/** Braille → shadows → smoke — ethereal / dream-like */
|
|
371
368
|
readonly dream: string[];
|
|
372
|
-
/** Geometric shapes → shards →
|
|
369
|
+
/** Geometric shapes → shards → blocks — angular texture */
|
|
373
370
|
readonly angular: string[];
|
|
374
371
|
/** Interface controls → prompts → data nodes — clean assistant/product motion */
|
|
375
372
|
readonly assistant: string[];
|
package/package.json
CHANGED
|
@@ -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: "
|
|
5
|
+
tested-engine: "2.0.0"
|
|
6
6
|
updated: "2026-09-09"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Asciify Engine
|
|
10
10
|
|
|
11
|
-
Use the published `asciify-engine` npm package for browser canvas rendering. Tested against **
|
|
11
|
+
Use the published `asciify-engine` npm package for browser canvas rendering. Tested against **2.0.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
|
|
@@ -135,3 +135,7 @@ Version 1.3.0 adds text-shaped charcoal cutouts (`textMask`), peripheral scanlin
|
|
|
135
135
|
## Studio composition and export
|
|
136
136
|
|
|
137
137
|
For optional wallpaper/backdrops, alternate renderers, palettes, masks, saved looks, text fonts, or deterministic MP4/GIF export, read [references/studio-workspace.md](references/studio-workspace.md). The new `/studio` API is separate from `/hover` and `AsciiOptions`; do not replace an existing hero pipeline just to add a backdrop. Use version 1.4.0 or newer for these APIs after verifying the installed package.
|
|
138
|
+
|
|
139
|
+
## Standard catalogs in 2.0
|
|
140
|
+
|
|
141
|
+
`CHARSETS` and `ART_STYLE_PRESETS` no longer include `emoji`, `musical` or `starfield`. Do not recommend or generate those names. For character selection in a Studio integration, use `STUDIO_CHARACTER_SETS` from `asciify-engine/studio` and assign an entry's `chars` to `settings.charset`. These ramps apply to the `ascii` style; other styles define their own marks. Custom Unicode strings remain supported. Read the upgrade reference when migrating 1.x preset names. The site now opens its primary workspace at `/editor`; `/editor/classic` preserves earlier workflows. Keep the engine imports modular: new editor defaults do not require importing Studio into an existing hero.
|
|
@@ -105,7 +105,7 @@ Do not promise a 120 FPS minimum on every mobile device or arbitrary character c
|
|
|
105
105
|
|
|
106
106
|
### Hero character catalog
|
|
107
107
|
|
|
108
|
-
Hero → Customize → Character set exposes every preset from the published engine `CHARSETS` catalog, plus the Asciify brand set. Selecting a set clears a custom-letter override; Apply letters modifies only the selected set, and Reset set restores it. Selection works while paused or with reduced motion. The hero remains gray
|
|
108
|
+
Hero → Customize → Character set exposes every preset from the published engine `CHARSETS` catalog, plus the Asciify brand set. Selecting a set clears a custom-letter override; Apply letters modifies only the selected set, and Reset set restores it. Selection works while paused or with reduced motion. The hero remains gray; these are character ramps, not the playground’s Halftone/Dither rendering modes. Prism at 95% with 35% edge softness is the default hero finish: red/cyan separation with short soft shoulders at the perimeter, a clear center, and no blur on HTML text or controls. The same Prism shader is used by the playground and optional engine hover surface.
|
|
109
109
|
|
|
110
110
|
The default Trail radius is now `0.45` in the hero, playground preset and optional engine mount. This widens the nominal fluid impulse by about 51% versus `0.2`, while preserving the same strength, bounded flow field. Pass `radius: 0.2` explicitly for the previous narrower reach. Other hover presets keep their existing sizes.
|
|
111
111
|
|
|
@@ -90,3 +90,17 @@ Bounds: 4096 pixels per side and 16 megapixels for stills; video at most 3840×2
|
|
|
90
90
|
`createStudioRenderer(canvas, settings, limits)` exposes `render(source, time, width, height)`, `configure`, `pointer`, `leave`, `invalidate`, and `destroy` for applications owning their own loop. Call `invalidate` when a canvas source changes in place; source identity alone does not indicate new pixels. Use an increasing time in seconds; pointer timestamps are milliseconds.
|
|
91
91
|
|
|
92
92
|
`mountStudio` pauses when hidden/offscreen and respects reduced motion. Still scenes sleep when their interaction settles. Video sampling caches decoded frames independently of display-rate pointer animation. Adaptive preview reduces its cell budget when sustained render cost is high; disable with `adaptive: false` for fixed measurement. It does not change saved settings or the standard ASCII editor. Exports use their own explicit budget. Measure sustained behavior on real target devices; no renderer can guarantee 60 fps on every device with arbitrary effects and density.
|
|
93
|
+
|
|
94
|
+
## Curated characters and the primary editor (2.0)
|
|
95
|
+
|
|
96
|
+
The site opens the workspace directly at `/editor`. Upload media, choose Style, then use Canvas for framing/backdrops/masks, Effects for motion/hover/finishing, Looks for reuse, and Export for downloads/code. Optical finish and Lighting expand on demand; they keep applied values when collapsed. The prior editor remains at `/editor/classic` for earlier workflows.
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import { STUDIO_CHARACTER_SETS, updateStudioSettings } from 'asciify-engine/studio';
|
|
100
|
+
settings = updateStudioSettings(settings, {
|
|
101
|
+
style: 'ascii', charset: STUDIO_CHARACTER_SETS.asciify.chars,
|
|
102
|
+
});
|
|
103
|
+
player.update(settings);
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Other renderer styles define their own marks, so character controls only apply to ASCII. Custom strings remain valid; Emoji, Musical and Starfield are no longer bundled presets.
|
|
@@ -27,3 +27,9 @@ npx skills update asciify-engine --global --yes
|
|
|
27
27
|
Use the scoped command matching the existing installation. Do not run an unqualified bulk update of every installed skill. If this skill is absent, install it with `npx skills add ayangabryl/asciify-engine --skill asciify-engine` and the appropriate scope/agent flags. Preserve agent selection; do not add `--all` unless requested. Inspect `npx skills --help` if CLI flags differ in the installed version. A manually copied skill can be refreshed from the same repository or the matching npm tarball's `skills/asciify-engine` directory; preserve unrelated files.
|
|
28
28
|
|
|
29
29
|
After updating, read the installed SKILL.md and its linked references, confirm its source/version and resource links, and report both the resolved npm version and whether the installed skill was refreshed. If an offline/registry/authentication error prevents either step, report the actual partial result; do not silently fall back to an unverified version. These consumer upgrade instructions do not authorize publishing npm packages or deploying a site.
|
|
30
|
+
|
|
31
|
+
## 2.0 catalog migration
|
|
32
|
+
|
|
33
|
+
2.0.0 removes the `emoji`, `musical`, and `starfield` keys from `CHARSETS`, `ArtStyle`, and `ART_STYLE_PRESETS`. Before upgrading, search application settings and saved presets for those names. Use `classic` plus a custom `charset` to retain an application-owned alphabet, or use `circles`, `braille`, or `geometric` for structural alternatives. The existing cosmic sequence now uses sparse marks/circles/shadows, and angular uses geometry/shards/blocks. Other core options and renderers retain their behavior. Do not pass retired keys or tell users that custom Unicode has been removed.
|
|
34
|
+
|
|
35
|
+
The curated `STUDIO_CHARACTER_SETS` export is available from `/studio` in 2.0.0. Its values contain `label` and `chars`; assign `chars` to Studio settings only for `style: 'ascii'`. The primary editor at `/editor` uses Studio; earlier webcam and classic-editor workflows remain at `/editor/classic`.
|