asciify-engine 2.0.0 → 2.0.1
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 +4 -0
- package/dist/studio.cjs +1 -1
- package/dist/studio.d.cts +14 -1
- package/dist/studio.d.ts +14 -1
- package/dist/studio.js +1 -1
- package/package.json +1 -1
- package/skills/asciify-engine/SKILL.md +2 -2
- package/skills/asciify-engine/references/studio-workspace.md +6 -0
- package/skills/asciify-engine/references/upgrading.md +2 -0
package/README.md
CHANGED
|
@@ -516,3 +516,7 @@ See the [Studio API guide](skills/asciify-engine/references/studio-workspace.md)
|
|
|
516
516
|
Emoji, Musical and Starfield preset keys have been removed from `CHARSETS`, `ArtStyle` and `ART_STYLE_PRESETS`. Use `classic` with an application-owned `charset` to retain a custom alphabet, or choose structural presets such as braille/circles/geometric. General Unicode support remains. Cosmic and angular character sequences now use structural marks. Existing core rendering and hover APIs remain modular.
|
|
517
517
|
|
|
518
518
|
`STUDIO_CHARACTER_SETS` from `asciify-engine/studio` provides named ramps with `{ label, chars }`; assign `chars` to Studio `charset` with `style: 'ascii'`. The website's new default workspace is [/editor](https://asciify.org/editor); earlier workflows remain in [/editor/classic](https://asciify.org/editor/classic).
|
|
519
|
+
|
|
520
|
+
### 2.0.1 size and export fixes
|
|
521
|
+
|
|
522
|
+
`studioGrid` exposes the effective grid and minimum cell size for a bounded preview. Dither uses `dither.scale`; other styles use `cellSize`. Pass `time` to `exportStudio` for a PNG/JPEG of the current frame. Animation exports continue to start at zero. See the Studio guide for the shared preview/export density contract.
|
package/dist/studio.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var t=["ascii","blocks","braille","dots","lines","cross","diagonal","diamond","mixed","pixel","mosaic","lego","voxel","disco","dither"],e=["none","bayer2","bayer4","bayer8","bayer16","floyd-steinberg","atkinson","stucki","sierra","sierra-lite","burkes","jarvis","halftone","lines","noise"],i=["source-over","multiply","screen","overlay","soft-light","hard-light","color-dodge","color-burn","hue","saturation","color","luminosity"],s={original:[],mono:["#080808","#f2f2e8"],asciify:["#080808","#625b38","#a19558","#e8b900"],gameboy:["#0f380f","#306230","#8bac0f","#9bbc0f"],cga:["#000000","#55ffff","#ff55ff","#ffffff"],pico8:["#000000","#1d2b53","#7e2553","#008751","#ab5236","#5f574f","#c2c3c7","#fff1e8","#ff004d","#ffa300","#ffec27","#00e436","#29adff","#83769c","#ff77a8","#ffccaa"],c64:["#000000","#ffffff","#880000","#aaffee","#cc44cc","#00cc55","#0000aa","#eeee77","#dd8855","#664400","#ff7777","#333333","#777777","#aaff66","#0088ff","#bbbbbb"],amber:["#100b00","#5f3b00","#c98014","#ffd17c"],ice:["#081b29","#25586e","#69a6b3","#d9ece7"],risograph:["#f4ebd0","#f2594b","#2853a5","#29232e"],sepia:["#201b17","#6b5039","#b49868","#f6e6c5"],nord:["#2e3440","#4c566a","#88c0d0","#eceff4"],dusk:["#211b35","#654271","#c3788c","#f5c9a3"],forest:["#101f1b","#355747","#87a16f","#e4e3ba"],ocean:["#071b33","#17577f","#3fa7a4","#d9efde"],newsprint:["#191919","#666666","#aaaaaa","#eee9df"],custom:["#080808","#e8b900"]},a={version:1,aspectRatio:"original",style:"ascii",cellSize:7,charset:" .:-=+*#%@",colorMode:"accent",ink:"#e8b900",crop:{x:.5,y:.5,zoom:1,rotation:0},backdrop:{mode:"solid",color:"#080808",color2:"#393323",blur:12,opacity:1},color:{brightness:0,contrast:1,saturation:1,grayscale:0,tint:"#e8b900",amount:0,blend:"source-over"},dither:{algorithm:"none",palette:"mono",colors:["#080808","#e8b900"],amount:1,scale:2,threshold:.5,motion:"none",speed:1},mask:{enabled:!1,invert:!1,shapes:[]},lights:[],effects:{bloom:0,characterBloom:0,grain:0,dust:0,scanlines:0,crt:0,prism:0,vignette:0,glitch:0,pixelate:0,blur:0,blurType:"gaussian",angle:0,focus:.5,halftone:0},motion:{type:"none",speed:1},hover:{effect:"trail",strength:.55,radius:.2,edgeSafe:!1}},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),d=a;if(void 0!==c.version&&1!==c.version)throw new Error("Unsupported studio settings version. Update asciify-engine.");const f=r(c.crop),m=r(c.backdrop),u=r(c.color),p=r(c.dither),g=r(c.mask),M=r(c.effects),x=r(c.motion),v=r(c.hover),w={...d.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"],d.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,d.style),cellSize:o(c.cellSize,7,3,60),charset:"string"==typeof c.charset&&c.charset.length?Array.from(c.charset).slice(0,128).join(""):d.charset,colorMode:h(c.colorMode,["accent","source","gray"],d.colorMode),ink:n(c.ink,d.ink),crop:{x:o(f.x,.5,0,1),y:o(f.y,.5,0,1),zoom:o(f.zoom,1,1,5),rotation:90*Math.round(o(f.rotation,0,-360,360)/90)},backdrop:{mode:h(m.mode,["solid","transparent","source","blurred","gradient"],d.backdrop.mode),color:n(m.color,d.backdrop.color),color2:n(m.color2,d.backdrop.color2),blur: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,d.color.tint),amount:o(u.amount,0,0,1),blend:h(u.blend,i,d.color.blend)},dither:{algorithm:h(p.algorithm,e,"none"),palette:"string"==typeof p.palette&&Object.prototype.hasOwnProperty.call(s,p.palette)?p.palette:"mono",colors:Array.isArray(p.colors)&&p.colors.length>=2?p.colors.slice(0,32).map(t=>n(t,"#000000")):[...d.dither.colors],amount:o(p.amount,1,0,2),scale:Math.round(o(p.scale,2,1,12)),threshold:o(p.threshold,.5,0,1),motion:h(p.motion,["none","drift","shimmer"],"none"),speed:o(p.speed,1,.1,3)},mask:{enabled:!0===g.enabled,invert:!0===g.invert,shapes:Array.isArray(g.shapes)?g.shapes.slice(0,64).map(t=>{const e=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,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 d(t,e,i){if(Math.abs(i.crop.rotation/90)%2==1&&([t,e]=[e,t]),"original"===i.aspectRatio)return[t,e];const[s,a]=i.aspectRatio.split(":").map(Number);return t/e>s/a?[Math.round(e*s/a),e]:[t,Math.round(t*a/s)]}function f(t,e){const i={...t,...e};for(const s of["crop","backdrop","color","dither","mask","effects","motion","hover"])e[s]&&Object.assign(i,{[s]:{...t[s],...e[s]}});return l(i)}var m=[["ascii","Signature ASCII","Brand ink and clean characters.",{}],["print","Newsprint","Fine diffusion on warm paper.",{style:"dither",dither:{algorithm:"floyd-steinberg",palette:"newsprint"}}],["handheld","Pocket camera","Four-tone ordered dither.",{style:"dither",dither:{algorithm:"bayer4",palette:"gameboy",scale:3}}],["riso","Two inks","Limited-color print texture.",{style:"dither",dither:{algorithm:"atkinson",palette:"risograph",scale:2}}],["night","Night signal","Gray characters and optical fringe.",{ink:"#888888",effects:{prism:.7,scanlines:.2,vignette:.3}}],["terminal","Phosphor","Green glyphs with a soft glow.",{ink:"#83efad",effects:{bloom:.4,scanlines:.35,crt:.2}}],["mosaic","Mosaic study","Separated color tiles.",{style:"mosaic",cellSize:14,colorMode:"source"}],["bricks","Brickwork","Colorful studded cells.",{style:"lego",cellSize:18,colorMode:"source"}],["voxel","Little volumes","Three-face isometric tiles.",{style:"voxel",cellSize:22,colorMode:"source"}],["disco","Mirror room","Faceted tiles and warm light.",{style:"disco",cellSize:18,colorMode:"source",lights:[{x:.35,y:.25,radius:.25,intensity:.45,color:"#fff2d4"}]}],["wallpaper","Wallpaper","Living ASCII over a softened source.",{backdrop:{mode:"blurred",blur:18,opacity:.55},ink:"#f2e9c9",motion:{type:"breathe",speed:.5}}],["blueprint","Blueprint","Linework in a cool monochrome.",{style:"lines",ink:"#9bccdf",backdrop:{mode:"solid",color:"#0a1e30"}}]].map(([t,e,i,s])=>({id:t,name:e,description:i,settings:l(s)}));function u(t){const e=m.find(e=>e.id===t);if(!e)throw new Error("Unknown studio look.");return l(e.settings)}var p=(t,e)=>{const i=43758.5453*Math.sin(127.1*t+311.7*e);return i-Math.floor(i)};function g(t,e,i){let s=0;for(let a=1;a<i;a*=2){const i=Math.floor(t/a)%2;s=4*s+[[0,2],[3,1]][Math.floor(e/a)%2][i]}return(s+.5)/(i*i)-.5}var M={"floyd-steinberg":[[1,0,7/16],[-1,1,3/16],[0,1,5/16],[1,1,1/16]],atkinson:[[1,0,.125],[2,0,.125],[-1,1,.125],[0,1,.125],[1,1,.125],[0,2,.125]],stucki:[[1,0,8/42],[2,0,4/42],[-2,1,2/42],[-1,1,4/42],[0,1,8/42],[1,1,4/42],[2,1,2/42],[-2,2,1/42],[-1,2,2/42],[0,2,4/42],[1,2,2/42],[2,2,1/42]],sierra:[[1,0,5/32],[2,0,3/32],[-2,1,2/32],[-1,1,4/32],[0,1,5/32],[1,1,4/32],[2,1,2/32],[-1,2,2/32],[0,2,3/32],[1,2,2/32]],"sierra-lite":[[1,0,.5],[-1,1,.25],[0,1,.25]],burkes:[[1,0,.25],[2,0,4/32],[-2,1,2/32],[-1,1,4/32],[0,1,.25],[1,1,4/32],[2,1,2/32]],jarvis:[[1,0,7/48],[2,0,5/48],[-2,1,3/48],[-1,1,5/48],[0,1,7/48],[1,1,5/48],[2,1,3/48],[-2,2,1/48],[-1,2,3/48],[0,2,5/48],[1,2,3/48],[2,2,1/48]]},x=t=>[parseInt(t.slice(1,3),16),parseInt(t.slice(3,5),16),parseInt(t.slice(5,7),16)];function v(t,e,i){const s=Math.min(t*Math.max(1,i),(1-t)*Math.max(1,i),e*Math.max(1,1/i),(1-e)*Math.max(1,1/i)),a=Math.max(0,Math.min(1,(s-.035)/.105));return a*a*a*(a*(6*a-15)+10)}var w=class{constructor(t,e){this.edgeSafe=!1,this.previous=null,this.peak=0,this.mode="dissolve",this.width=t,this.height=e;const i=t*e;this.pixels=new Uint8Array(4*i),this.ink=new Float32Array(i),this.targetX=new Float32Array(i),this.targetY=new Float32Array(i),this.offsetX=new Float32Array(i),this.offsetY=new Float32Array(i),this.edge=new Float32Array(i);for(let i=0;i<e;i++)for(let s=0;s<t;s++)this.edge[i*t+s]=v(s/(t-1),i/(e-1),t/e);this.clear()}get active(){return this.peak>2e-4}setMode(t){t!==this.mode&&(this.mode=t,this.clear())}clear(){for(const t of[this.ink,this.targetX,this.targetY,this.offsetX,this.offsetY,this.pixels])t.fill(0);if(this.previous=null,this.peak=0,"dissolve"!==this.mode)for(let t=0;t<this.pixels.length;t+=4)this.pixels[t]=this.pixels[t+2]=128}leave(){this.previous=null}move(t,e,i){if(!Number.isFinite(t+e+i))return;t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e));const s=this.previous;this.previous={x:t,y:e};const a=this.width,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 d=.035+.11*Math.max(.1,Math.min(1,i)),f=Math.min(128,Math.max(1,Math.ceil(c/(.45*d)))),m=c?h/c:1,u=c?l/c:0,p=Math.min(1,c/(d*f)*2.2);for(let i=0;i<f;i++){const h=(i+.5)/f,l=s?s.x+(t-s.x)*h:t,c=s?s.y+(e-s.y)*h:e,g=Math.max(0,Math.floor((l-2.5*d/o)*(a-1))),M=Math.min(a-1,Math.ceil((l+2.5*d/o)*(a-1))),x=Math.max(0,Math.floor((c-2.5*d/n)*(r-1))),v=Math.min(r-1,Math.ceil((c+2.5*d/n)*(r-1)));for(let t=x;t<=v;t++)for(let e=g;e<=M;e++){const i=(e/(a-1)-l)*o/d,s=(t/(r-1)-c)*n/d,h=Math.exp(1.5*-(i*i+s*s)),f=t*a+e;if("dissolve"===this.mode)this.ink[f]=Math.max(this.ink[f],h);else{const t=(-i*u+s*m)*h*2.8,e="silk"===this.mode?m*t:-s*h*2.5,a="silk"===this.mode?u*t:i*h*2.5;this.targetX[f]=Math.max(-1,Math.min(1,this.targetX[f]+e*p)),this.targetY[f]=Math.max(-1,Math.min(1,this.targetY[f]+a*p))}}}this.peak=1}step(t){if(!this.active||!Number.isFinite(t))return;const e=Math.max(0,Math.min(.05,t)),i=Math.exp(-("dissolve"===this.mode?2.15:3.2)*e),s=1-Math.exp(-22*e);let a=0;for(let t=0;t<this.ink.length;t++)if("dissolve"===this.mode){this.ink[t]*=i,a=Math.max(a,this.ink[t]);const e=Math.round(65535*this.ink[t]);this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e}else{this.targetX[t]*=i,this.targetY[t]*=i,this.offsetX[t]+=(this.targetX[t]-this.offsetX[t])*s,this.offsetY[t]+=(this.targetY[t]-this.offsetY[t])*s,a=Math.max(a,Math.abs(this.offsetX[t]),Math.abs(this.offsetY[t]),Math.abs(this.targetX[t]),Math.abs(this.targetY[t]));const e=Math.round(this.offsetX[t]*(this.edgeSafe?this.edge[t]:1)*32767+32768),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,d=t=>(t[l]*(1-n)+t[l+1]*n)*(1-h)+(t[c]*(1-n)+t[c+1]*n)*h;i[0]=d(this.offsetX)*(this.edgeSafe?v(t,e,this.width/this.height):1)*.08,i[1]=d(this.offsetY)*(this.edgeSafe?v(t,e,this.width/this.height):1)*.08,i[2]="dissolve"===this.mode?6*-d(this.ink):0}},b=class{constructor(t,e){this.rings=[],this.previous=null,this.elapsed=1,this.echoPeak=0,this.width=t,this.height=e,this.pixels=new Uint8Array(t*e*4),this.echo=new Float32Array(t*e)}get active(){return this.rings.length>0||this.echoPeak>2e-4}clear(){this.rings=[],this.previous=null,this.elapsed=1,this.pixels.fill(0),this.echo.fill(0),this.echoPeak=0}leave(){this.previous=null}move(t,e,i){const s=Math.max(1,this.width/this.height),a=Math.max(1,this.height/this.width);this.previous&&(Math.hypot((t-this.previous.x)*s,(e-this.previous.y)*a)<.065||this.elapsed<.3)||4!==this.rings.length&&(this.previous={x:t,y:e},this.elapsed=0,this.rings.push({x:t,y:e,age:0,radius:i}))}ringSample(t,e){const i=Math.max(1,this.width/this.height),s=Math.max(1,this.height/this.width);let a=0;for(const 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))}},y=class{constructor(t,e){this.previous=null,this.peak=0,this.width=t,this.height=e;const i=t*e;this.pixels=new Uint8Array(4*i),this.signal=new Float32Array(i),this.offsetX=new Float32Array(i),this.offsetY=new Float32Array(i),this.driftX=new Float32Array(i),this.driftY=new Float32Array(i),this.u=new Float32Array(i),this.v=new Float32Array(i),this.ink=new Float32Array(i),this.a=new Float32Array(i),this.b=new Float32Array(i),this.c=new Float32Array(i),this.pressure=new Float32Array(i),this.pressureNext=new Float32Array(i),this.divergence=new Float32Array(i),this.curl=new Float32Array(i)}get active(){return this.peak>2e-4}clear(){for(const t of[this.u,this.v,this.ink,this.a,this.b,this.c,this.pressure,this.pressureNext,this.divergence,this.curl,this.signal,this.pixels,this.offsetX,this.offsetY,this.driftX,this.driftY])t.fill(0);this.previous=null,this.peak=0}leave(){this.previous=null}move(t,e,i,s=performance.now()){if(!Number.isFinite(t+e+i+s))return;t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e)),i=Math.max(.1,Math.min(1,i));const a=this.previous;if(this.previous={x:t,y:e,time:s},!a)return;const 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),d=1-Math.exp(-c/2.2),f=h*(.022+.075*i)*(.65+.95*d),m=Math.min(128,Math.max(1,Math.ceil(n/(.4*f)))),u=n/f*(.32+.22*d)/m,p=r/n,g=o/n,M=-g,x=p,v=n*(2+18*d)/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*f)),h=Math.min(this.width-2,Math.ceil(r+3*f)),l=Math.max(1,Math.floor(o-3*f)),c=Math.min(this.height-2,Math.ceil(o+3*f));for(let t=l;t<=c;t++)for(let e=n;e<=h;e++){const i=((e-r)*p+(t-o)*g)/f,s=((e-r)*M+(t-o)*x)/f,a=Math.exp(-i*i*.65-s*s*1.7),n=t*this.width+e;this.ink[n]=1-(1-this.ink[n])*Math.exp(-a*u);const h=1-s*s*.55,l=i*s*.7;this.u[n]=Math.max(-80,Math.min(80,this.u[n]+(p*h+M*l)*a*v)),this.v[n]=Math.max(-80,Math.min(80,this.v[n]+(g*h+x*l)*a*v))}}this.peak=1}read(t,e,i){const s=0|(e=Math.max(.5,Math.min(this.width-1.5,e))),a=0|(i=Math.max(.5,Math.min(this.height-1.5,i))),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,d=0|l,f=h-c,m=l-d,u=d*i+c,p=(1-f)*(1-m),g=f*(1-m),M=(1-f)*m,x=f*m;this.a[n]=(this.u[u]*p+this.u[u+1]*g+this.u[u+i]*M+this.u[u+i+1]*x)*a,this.b[n]=(this.v[u]*p+this.v[u+1]*g+this.v[u+i]*M+this.v[u+i+1]*x)*a,this.c[n]=(this.ink[u]*p+this.ink[u+1]*g+this.ink[u+i]*M+this.ink[u+i+1]*x)*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 S(t,e){const i=Math.max(0,Math.min(1,e/.38));return t+(1-2*t)*(i*i*(3-2*i))}var E=class{constructor(t=1){this.mode="water",this.amount=.55,this.radius=.2,this.lensX=.5,this.lensY=.5,this.lensStrength=0,this.previous=null,this.energy=0,this.pending=!1,this.remainder=0,t=Math.max(.25,Math.min(4,t)),this.columns=Math.round(t>=1?128:128*t),this.rows=Math.round(t>=1?128/t:128),this.xScale=Math.max(1,t),this.yScale=Math.max(1,1/t),this.heights=new Float32Array(this.columns*this.rows),this.velocity=new Float32Array(this.heights.length),this.next=new Float32Array(this.heights.length),this.normals=new Float32Array(2*this.heights.length),this.edgeMask=new Float32Array(this.heights.length);for(let e=0;e<this.rows;e++)for(let i=0;i<this.columns;i++)this.edgeMask[e*this.columns+i]=v(i/(this.columns-1),e/(this.rows-1),t);this.refraction={width:this.columns,height:this.rows,pixels:new Uint8Array(4*this.heights.length),strength:30,mode:"water",focus:[.5,.5,0,.2]},this.waterPixels=this.refraction.pixels,this.trail=new y(this.columns,this.rows),this.contour=new b(this.columns,this.rows),this.afterimage=new w(this.columns,this.rows),this.clear()}get invertsDensity(){return"trail"===this.mode}get densityTrail(){return["trail","contour","dissolve"].includes(this.mode)}get hasRefraction(){return this.active||this.lensStrength>15e-5}get active(){return["dissolve","silk","vortex"].includes(this.mode)?this.afterimage.active:"contour"===this.mode?this.contour.active:"trail"===this.mode?this.trail.active:this.pending||this.energy>15e-5}setMode(t){t!==this.mode&&(this.clear(),this.mode=t,this.refraction.mode=t,"dissolve"!==t&&"silk"!==t&&"vortex"!==t||this.afterimage.setMode(t),this.refraction.pixels="trail"===t?this.trail.pixels:"contour"===t?this.contour.pixels:["dissolve","silk","vortex"].includes(t)?this.afterimage.pixels:this.waterPixels,this.refraction.strength="water"===t?30*this.amount/.55:"silk"===t?28*this.amount:"vortex"===t?38*this.amount:0)}configure(t,e=.55,i=.2,s=!1){this.setMode(t),this.refraction.edgeSafe=s,this.afterimage.edgeSafe=s,this.amount=Number.isFinite(e)?Math.max(0,Math.min(1,e)):.55,this.radius=Number.isFinite(i)?Math.max(.1,Math.min(1,i)):.2,this.refraction.strength="water"===t?30*this.amount/.55:"silk"===t?28*this.amount:"vortex"===t?38*this.amount:0,this.refraction.focus[2]=this.densityTrail?this.amount:this.lensStrength*this.amount,this.refraction.focus[3]=this.radius}move(t,e,i){if("none"===this.mode||0===this.amount)return;if(!Number.isFinite(t+e))return;if(t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e)),["dissolve","silk","vortex"].includes(this.mode))return void this.afterimage.move(t,e,this.radius);if("contour"===this.mode)return void this.contour.move(t,e,this.radius);if("trail"===this.mode)return void this.trail.move(t,e,this.radius,i);if("water"!==this.mode)return!this.previous&&this.lensStrength<.001&&(this.lensX=t,this.lensY=e),this.previous={x:t,y:e},void(this.pending=!0);if(!this.previous)return void(this.previous={x:t,y:e});const s=this.previous;this.previous={x:t,y:e};const a=(t-s.x)*this.xScale,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,d=Math.max(1,Math.floor((r-h/this.xScale)*(this.columns-1))),f=Math.min(this.columns-2,Math.ceil((r+h/this.xScale)*(this.columns-1))),m=Math.max(1,Math.floor((o-h/this.yScale)*(this.rows-1))),u=Math.min(this.rows-2,Math.ceil((o+h/this.yScale)*(this.rows-1)));for(let t=m;t<=u;t++)for(let e=d;e<=f;e++){const i=(e/(this.columns-1)-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,d=(this.velocity[o]+(h*s*s-8*n)*e)*i*c;this.velocity[o]=d,this.next[o]=(n+d*e)*c,t=Math.max(t,Math.abs(this.next[o]),.1*Math.abs(d))}this.heights.set(this.next),this.energy=t,this.pending=!1}if(!this.active)return void this.clear();const 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 k(t){return"videoWidth"in t?[t.videoWidth,t.videoHeight]:"naturalWidth"in t?[t.naturalWidth,t.naturalHeight]:[t.width,t.height]}var T=(t=!1)=>{const e=document.createElement("canvas"),i=e.getContext("2d",{willReadFrequently:t});if(!i)throw new Error("Canvas 2D is unavailable.");return{canvas:e,ctx:i}},A=(t,e,i)=>{t.width===e&&t.height===i||(t.width=e,t.height=i)},F={blocks:" ░▒▓█",braille:" ⠁⠃⠇⡇⣇⣧⣷⣿",lines:" -═╪╬",cross:" ·+xX#",diagonal:" /╱╳",diamond:" ·◇◈◆",mixed:" .:+/◇#@"};function I(t,e={},i={}){const a=t.getContext("2d");if(!a)throw new Error("Canvas is already owned by another renderer.");const r=T(),o=T(!0),n=T(),h=T(),d=T(),f=T(),m=T(),u=T(),v=T();let w,b=l(e),y=0,I="",R=new Uint8ClampedArray(0),P=0,L=0,C=0,D=null,U="",O=new E,X=0;const _=[0,0,0],B=Math.max(64,Math.min(4096,Number.isFinite(i.maxDimension)?i.maxDimension:960)),N=Math.max(256,Math.min(16e4,Number.isFinite(i.maxCells)?i.maxCells:12e3));let Y=N;const z=Math.max(.1,Math.min(8,i.pixelRatio??1));return{canvas:t,render:function(e,i=0,l=960,T=540){if(Number.isFinite(i)||(i=0),!Number.isFinite(l)||!Number.isFinite(T)||l<1||T<1)throw new Error("Render dimensions must be positive finite numbers.");const[N,G]=k(e);if(!N||!G)return;const W=Math.min(1,B/Math.max(l,T)),q=Math.max(2,Math.round(l*W)),$=Math.max(2,Math.round(T*W));A(t,q,$),A(r.canvas,q,$),A(n.canvas,q,$),A(h.canvas,q,$),A(d.canvas,q,$),X!==q/$&&(X=q/$,O=new E(X)),O.configure(b.hover.effect,b.hover.strength,b.hover.radius,b.hover.edgeSafe),O.step(Math.max(0,Math.min(.05,i-C))),C=i;const j="currentTime"in e?e.getVideoPlaybackQuality?.().totalVideoFrames??e.currentTime:0,V=[y,q,$,j].join(":"),H="dither"===b.style,J=(H?b.dither.scale:b.cellSize)*z,K=Math.max(J,Math.sqrt(q*$/Y)),Q=H||["pixel","mosaic","lego","voxel","disco","dots"].includes(b.style)?K:1.65*K,Z=Math.max(1,Math.ceil(q/K)),tt=Math.max(1,Math.ceil($/Q));if(I!==V||D!==e||P!==Z||L!==tt){D=e,I=V,P=Z,L=tt,r.ctx.clearRect(0,0,q,$),r.ctx.save();const t=c(N,G,q,$,b.crop);r.ctx.translate(t.x+t.width/2,t.y+t.height/2),r.ctx.rotate(b.crop.rotation*Math.PI/180),r.ctx.drawImage(e,-N*t.scale/2,-G*t.scale/2,N*t.scale,G*t.scale),r.ctx.restore(),A(o.canvas,P,L),o.ctx.clearRect(0,0,P,L),o.ctx.drawImage(r.canvas,0,0,P,L),R=o.ctx.getImageData(0,0,P,L).data;const i=b.color;for(let t=0;t<R.length;t+=4){const e=.299*R[t]+.587*R[t+1]+.114*R[t+2];for(let s=0;s<3;s++){const a=e+(R[t+s]-e)*i.saturation;R[t+s]=((a*(1-i.grayscale)+e*i.grayscale)/255-.5)*i.contrast*255+127.5+255*i.brightness}}}n.ctx.clearRect(0,0,q,$),n.ctx.globalAlpha=1,n.ctx.globalCompositeOperation="source-over";const et=i*b.motion.speed;if(H){const t=new Uint8ClampedArray(R),e=b.motion.type;if(O.active||"none"!==e)for(let i=0;i<L;i++)for(let s=0;s<P;s++){const a=s/P,r=i/L;let o=s,n=i,h=0,l=1,c=1;if(O.active&&(O.sample(a,r,_),o-=_[0]*P,n-=_[1]*L,h=_[2]/3),"wave"===e&&(n+=Math.sin(8*a+2*et+4*r)*L*.015),"ripple"===e){const t=a-.5,e=r-.5,i=.03*Math.sin(30*Math.hypot(t,e)-3*et);o+=t*i*P,n+=e*i*L}"breathe"===e&&(l=.92+.08*Math.sin(1.5*et+3*a)),"reveal"===e&&(c=Math.max(0,Math.min(1,4*(.7*Math.sin(.7*et)+.7-a)))),"glitch"===e&&p(i,Math.floor(6*et))>.93&&(o+=8*Math.sin(5*et)),"vapor"===e&&(n+=Math.sin(6*a+et)*L*.025),"fire"===e&&(n+=Math.sin(7*a+3*et+8*r)*L*.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 d=4*(i*P+s),f=4*(Math.max(0,Math.min(L-1,Math.round(n)))*P+Math.max(0,Math.min(P-1,Math.round(o))));for(let i=0;i<3;i++){const s=R[f+i]/255;let r=(["trail","contour"].includes(b.hover.effect)?S(s,h):"dissolve"===b.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[d+i]=255*r}t[d+3]=R[f+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(x),c=M[o],d=c?new Float32Array(3*e*3):null,f="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]){d&&(d[u]=d[u+1]=d[u+2]=0);continue}let M=0;o.startsWith("bayer")?M=g(a+f&15,s+f&15,Number(o.slice(5))):"noise"===o?M=p(a,s)-.5:"lines"===o?M=(s+f)%4/3-.5:"halftone"===o&&(M=Math.hypot(a%6-2.5,s%6-2.5)/3.54-.5);const x=128*(M*n+m+(.5-h)),v=t[r]+x+(d?.[u]??0),w=t[r+1]+x+(d?.[u+1]??0),b=t[r+2]+x+(d?.[u+2]??0);let y=0,S=0,E=0;if(l.length){let t=1/0;for(const e of l){const i=(v-e[0])**2*.299+(w-e[1])**2*.587+(b-e[2])**2*.114;i<t&&(t=i,[y,S,E]=e)}}else y=51*Math.round(v/51),S=51*Math.round(w/51),E=51*Math.round(b/51);if(t[r]=y,t[r+1]=S,t[r+2]=E,d&&c){d[u]=d[u+1]=d[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);d[l]+=(v-y)*o*n,d[l+1]+=(w-S)*o*n,d[l+2]+=(b-E)*o*n}}}}(t,P,L,b.dither,i),o.ctx.putImageData(new ImageData(t,P,L),0,0),n.ctx.imageSmoothingEnabled=!1,n.ctx.drawImage(o.canvas,0,0,q,$)}else{const t=Array.from(F[b.style]??b.charset),e=n.ctx,i="ascii"===b.style||!!F[b.style],s=Math.max(3,Math.round(.92*Q)),a=Math.ceil(K+4),r=Math.ceil(Q+4),o=[t.join(""),s,a,r,b.ink,b.colorMode].join(":");i&&o!==U&&(U=o,A(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"===b.colorMode?b.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<L;s++)for(let o=0;o<P;o++){let n=o,h=s,l=0;O.active&&(O.sample(o/P,s/L,_),n=Math.max(0,Math.min(P-1,o-_[0]*P)),h=Math.max(0,Math.min(L-1,s-_[1]*L)),l=_[2]/3);const c=4*(Math.floor(h)*P+Math.floor(n));if(!R[c+3])continue;const d=R[c],f=R[c+1],u=R[c+2],g=(.299*d+.587*f+.114*u)/255;let M=g;["trail","contour"].includes(b.hover.effect)&&l?M=S(M,l):"dissolve"===b.hover.effect&&(M*=Math.max(0,1+l));const x=b.motion.type;let v=o*K,w=s*Q,y=1;if("breathe"===x&&(M*=.92+.08*Math.sin(1.5*et+.03*o)),"wave"===x&&(w+=Math.sin(.12*o+2*et+.08*s)*Q*.4),"ripple"===x){const t=o/P-.5,e=s/L-.5,i=Math.hypot(t,e),a=Math.sin(30*i-3*et)*K*.65;v+=t*a,w+=e*a}"fire"===x&&(w-=Math.sin(.16*o+3*et+.09*s)*Q*.35,M*=.85+.15*Math.sin(.3*s-4*et)),"hologram"===x&&(y=.72+.28*Math.sin(.65*s+5*et)),"reveal"===x&&(y=Math.max(0,Math.min(1,4*(.7*Math.sin(.7*et)+.7-o/P)))),"glitch"===x&&p(s,Math.floor(6*et))>.93&&(v+=Math.sin(5*et)*K*3),"vapor"===x&&(w+=Math.sin(.04*o+et)*Q),i||"accent"!==b.colorMode||(y*=M),e.globalAlpha=y;const E=255*(M-g);let k="source"===b.colorMode?`rgb(${d+E},${f+E},${u+E})`:"gray"===b.colorMode?`rgb(${Math.round(255*M)},${Math.round(255*M)},${Math.round(255*M)})`:b.ink;if("rainbow"===x&&(k=`hsl(${(o/P*180+40*et)%360} 70% 65%)`),"fire"===x&&(k=`hsl(${15+40*M} 90% ${30+45*M}%)`),"hologram"===x&&(k=`hsl(185 65% ${40+40*M}%)`),"chrome"===x&&(k=`hsl(210 12% ${25+70*Math.abs(Math.sin(.2*s+et))}%)`),e.fillStyle=k,i){const i=Math.max(0,Math.min(t.length-1,Math.floor(M*(t.length-1))));"accent"!==b.colorMode||["rainbow","fire","hologram","chrome"].includes(x)?e.fillText(t[i],v+K/2,w+Q/2):e.drawImage(m.canvas,i*a,0,a,r,v+(K-a)/2,w+(Q-r)/2,a,r)}else if("dots"===b.style)e.beginPath(),e.arc(v+K/2,w+Q/2,.48*K*Math.sqrt(M),0,2*Math.PI),e.fill();else if("voxel"===b.style){const t=v+K/2,i=w+Q/2;e.beginPath(),e.moveTo(t,w),e.lineTo(v+K,w+.25*Q),e.lineTo(t,i),e.lineTo(v,w+.25*Q),e.closePath(),e.fill(),e.globalAlpha=.72*y,e.beginPath(),e.moveTo(v,w+.25*Q),e.lineTo(t,i),e.lineTo(t,w+Q),e.lineTo(v,w+.75*Q),e.closePath(),e.fill(),e.globalAlpha=.42*y,e.beginPath(),e.moveTo(t,i),e.lineTo(v+K,w+.25*Q),e.lineTo(v+K,w+.75*Q),e.lineTo(t,w+Q),e.closePath(),e.fill()}else{const t="pixel"===b.style?0:Math.max(.5,.06*K);e.fillRect(v,w,K-t,Q-t),"lego"===b.style&&(e.fillStyle="rgba(255,255,255,.2)",e.beginPath(),e.arc(v+K/2,w+Q/2,.28*K,0,2*Math.PI),e.fill(),e.strokeStyle="rgba(0,0,0,.25)",e.stroke()),"disco"===b.style&&(e.fillStyle=`rgba(255,255,255,${.1+.25*p(o,s)})`,e.fillRect(v,w,K-t,.35*Q),e.fillStyle="rgba(0,0,0,.25)",e.fillRect(v,w+.65*Q,K-t,.35*Q-t))}}}n.ctx.globalAlpha=1,(b.color.amount||b.lights.length)&&(A(u.canvas,q,$),u.ctx.clearRect(0,0,q,$),u.ctx.drawImage(n.canvas,0,0)),b.color.amount&&(n.ctx.save(),n.ctx.globalCompositeOperation=b.color.blend,n.ctx.globalAlpha=b.color.amount,n.ctx.fillStyle=b.color.tint,n.ctx.fillRect(0,0,q,$),n.ctx.restore());for(const t of b.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((b.color.amount||b.lights.length)&&(n.ctx.globalCompositeOperation="destination-in",n.ctx.drawImage(u.canvas,0,0),n.ctx.globalCompositeOperation="source-over"),b.mask.enabled&&b.mask.shapes.length){const t=d.ctx;t.clearRect(0,0,q,$),t.fillStyle="#fff",t.strokeStyle="#fff",t.lineCap="round",t.lineJoin="round";for(const e of b.mask.shapes){if(t.beginPath(),"ellipse"===e.kind)t.ellipse((e.x+e.width/2)*q,(e.y+e.height/2)*$,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=b.mask.invert?"destination-out":"destination-in",n.ctx.drawImage(d.canvas,0,0),n.ctx.globalCompositeOperation="source-over"}const it=h.ctx;it.clearRect(0,0,q,$),it.globalAlpha=b.backdrop.opacity;const st=b.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);A(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,b.effects.characterBloom>0&&(A(v.canvas,Math.max(2,Math.round(q/3)),Math.max(2,Math.round($/3))),v.ctx.clearRect(0,0,v.canvas.width,v.canvas.height),v.ctx.drawImage(n.canvas,0,0,v.canvas.width,v.canvas.height),it.save(),it.globalAlpha=.8*b.effects.characterBloom,it.globalCompositeOperation="screen",it.filter=`blur(${1+4*b.effects.characterBloom}px)`,it.drawImage(v.canvas,0,0,q,$),it.restore()),it.drawImage(n.canvas,0,0);const at=Object.entries(b.effects).some(([t,e])=>!["angle","focus","blurType","characterBloom"].includes(t)&&"number"==typeof e&&e>0);a.clearRect(0,0,q,$),at?(void 0===w&&(w=function(){const t=document.createElement("canvas"),e=t.getContext("webgl",{alpha:!0,premultipliedAlpha:!1,antialias:!1,preserveDrawingBuffer:!0});if(!e)return null;const i=[],s=(t,s)=>{const a=e.createShader(t);if(i.push(a),e.shaderSource(a,s),e.compileShader(a),!e.getShaderParameter(a,e.COMPILE_STATUS))throw new Error(e.getShaderInfoLog(a)||"Finish shader failed");return a},a=e.createProgram();if(e.attachShader(a,s(e.VERTEX_SHADER,"attribute vec2 p;varying vec2 uv;void main(){uv=(p+1.)*.5;gl_Position=vec4(p,0.,1.);}")),e.attachShader(a,s(e.FRAGMENT_SHADER,"precision mediump float;varying vec2 uv;uniform sampler2D src;uniform vec2 size;uniform float t,bloom,grain,dust,scanlines,crt,prism,vignette,glitch,pixelate,blur,blurMode,angle,focus,halftone;\n float hash(vec2 p){return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453);}\n vec4 sampleAt(vec2 p){if(min(min(p.x,p.y),min(1.-p.x,1.-p.y))<0.)return vec4(0.);return texture2D(src,vec2(p.x,1.-p.y));}\n void main(){vec2 q=uv,c=q-.5;q=c*(1.+dot(c,c)*crt*.25)+.5;\n if(glitch>0.)q.x+=(hash(vec2(floor(q.y*35.),floor(t*5.)))-.5)*.07*glitch*step(.82,hash(vec2(floor(q.y*35.),floor(t*5.)+3.)));\n if(pixelate>0.){vec2 grid=size/(1.+pixelate*20.);q=(floor(q*grid)+.5)/grid;}\n vec4 base=sampleAt(q);float edge=smoothstep(.12,.65,length(c));\n vec2 shift=vec2(prism*3.*edge/size.x,prism*edge/size.y);\n if(prism>0.)base.rgb=vec3(sampleAt(q+shift).r,base.g,sampleAt(q-shift).b);\n vec2 dir=vec2(cos(angle),sin(angle))/size;float amount=blur;\n if(blurMode>1.5&&blurMode<2.5){dir=normalize(c+vec2(.0001))/size;amount*=length(c)*2.;}\n if(blurMode>2.5)amount*=smoothstep(.05,.5,abs(q.y-focus));\n vec4 blurred=base;\n if(amount>0.){blurred=base*.2;for(int i=1;i<=4;i++){float f=float(i)*amount*.35;vec2 off=dir*f;if(blurMode<.5)off=vec2(cos(float(i)*1.57),sin(float(i)*1.57))*amount/size;blurred+=sampleAt(q+off)*.1+sampleAt(q-off)*.1;}}\n vec3 light=vec3(0.);if(bloom>0.)for(int i=0;i<4;i++){float a=float(i)*1.5708;vec3 s=sampleAt(q+vec2(cos(a),sin(a))*6./size).rgb;light+=max(vec3(0.),s-.35)*.25;}\n vec3 col=blurred.rgb+light*bloom;col*=1.-scanlines*.4*(.5+.5*cos(q.y*size.y*3.14159));\n col*=1.-vignette*smoothstep(.15,.72,length(c));\n col+=(hash(floor(q*size)+floor(t*12.))-.5)*grain*.2;\n if(dust>0.)col+=step(1.-dust*.002,hash(floor(q*size*.25)+floor(t*2.)))*.4;\n if(halftone>0.)col*=mix(1.,smoothstep(.1,.65,length(fract(q*size/6.)-.5)),halftone);\n gl_FragColor=vec4(clamp(col,0.,1.),blurred.a);}")),e.linkProgram(a),!e.getProgramParameter(a,e.LINK_STATUS))throw new Error("Finish link failed");e.useProgram(a);const 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()}}}()),w?a.drawImage(w.render(h.canvas,b.effects,i,z),0,0):a.drawImage(h.canvas,0,0),t.dataset.studioFinish=w?"gpu":"unavailable"):(a.drawImage(h.canvas,0,0),t.dataset.studioFinish="none")},setBudget(t){Y=Math.max(1500,Math.min(N,Math.round(t)))},get maxCells(){return Y},configure(t){b=l(t),y++},pointer:(t,e,i)=>{O.configure(b.hover.effect,b.hover.strength,b.hover.radius,b.hover.edgeSafe),O.move(t,e,i)},leave(){O.leave()},get active(){return O.active},get settings(){return l(b)},get capabilities(){return{gpuFinish:null!==w}},invalidate(){I=""},destroy(){w?.destroy();for(const t of[r,o,n,h,d,f,m,u,v])t.canvas.width=t.canvas.height=1;D=null,R=new Uint8ClampedArray(0)}}}function R(t,e,i){return new Promise((s,a)=>{const 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 P(t,e){if("string"==typeof t&&t.startsWith("blob:")){const i=await fetch(t,{signal:e}),s=await i.blob();return P(new File([s],"Imported media",{type:s.type}),e)}const i="string"!=typeof t,s=i?t.name:t;if(i?"image/gif"===t.type:/\.gif(?:[?#]|$)/i.test(s)){const s=await import("gifuct-js"),{parseGIF:a,decompressFrames: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 d=r(n,!0);if(d.length*h*l*4>128e6)throw new Error("GIF exceeds the 128 MB decoded budget. Use MP4 for long animations.");const f=document.createElement("canvas");f.width=h,f.height=l;const m=f.getContext("2d"),u=document.createElement("canvas"),p=u.getContext("2d"),g=d.reduce((t,e)=>t+Math.max(20,e.delay),0)/1e3;let M=-1,x=null;const v=t=>{const e=(t%g+g)%g*1e3;let i=0,s=0;for(;s<d.length-1&&(i+=Math.max(20,d[s].delay),!(e<i));s++);s<M&&(m.clearRect(0,0,h,l),M=-1,x=null);for(let t=M+1;t<=s;t++){const e=d[t-1];2===e?.disposalType&&m.clearRect(e.dims.left,e.dims.top,e.dims.width,e.dims.height),3===e?.disposalType&&x&&m.putImageData(x,0,0);const i=d[t];x=3===i.disposalType?m.getImageData(0,0,h,l):null,u.width=i.dims.width,u.height=i.dims.height,p.putImageData(new ImageData(new Uint8ClampedArray(i.patch),u.width,u.height),0,0),m.drawImage(u,i.dims.left,i.dims.top)}return M=s,f};return v(0),{source:f,width:h,height:l,duration:g,animated:!0,seek:async()=>{},frame:v,destroy(){f.width=u.width=1,d.length=0,x=null}}}const a=i?t.type.startsWith("video/"):/\.(mp4|webm|mov)(?:[?#]|$)/i.test(s),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=R(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=R(o,"seeked",e);o.currentTime=i,await s},frame:()=>o,destroy:n}}catch(t){throw n(),t}}var L=t=>{if(t?.aborted)throw new DOMException("Export cancelled","AbortError")};function C(t,e,i={}){let s=l(i.settings),a=i.width??e.width,r=i.height??e.height;const o=I(t,s,i);let n=0,h=!1,c=!0,m=!1,u=!0,p=0,g=0,M=0,x=-1,v=0,w=0,b=0;const y=matchMedia("(prefers-reduced-motion: reduce)"),S=e.source instanceof HTMLVideoElement?e.source:null,E=()=>{h||n||!u||document.hidden||(n=requestAnimationFrame(A))},k=()=>!m&&!y.matches&&u&&!document.hidden,T=()=>{S&&(S.loop=!0,k()?S.play().catch(()=>{m=!0,c=!0,E()}):S.pause()),g=0,c=!0,E()};function A(t){if(n=0,h||!u||document.hidden)return;const l=k();l&&(p+=g?Math.min(.1,(t-g)/1e3):0),g=t;const f=l&&(e.animated||"none"!==s.motion.type||"none"!==s.dither.motion||s.effects.grain>0||s.effects.dust>0||s.effects.glitch>0),y=S?.getVideoPlaybackQuality?.().totalVideoFrames??-1,T="none"!==s.motion.type||"none"!==s.dither.motion||s.effects.grain>0||s.effects.dust>0||s.effects.glitch>0,A=!S||y<0||y!==x;if(c||o.active||f&&(A||T)&&t-M>=1e3/Math.max(1,Math.min(60,i.fps??60))-.5){const n=performance.now();try{e.animated&&!S&&o.invalidate();const[t,h]=d(a,r,s);o.render(e.frame(S?.currentTime??p),p,t,h);const l=performance.now()-n;i.onFrame?.(S?.currentTime??p,l),w=w?.9*w+.1*l:l,++v>20&&!1!==i.adaptive&&(b=w>13?b+1:0,b>=12&&o.maxCells>3e3&&(o.setBudget(Math.max(3e3,.8*o.maxCells)),i.onQualityChange?.(o.maxCells),b=0,w=0))}catch(t){m=!0,i.onError?.(t instanceof Error?t:new Error(String(t)))}c=!1,M=t,x=y}l&&(f||o.active)&&E()}const F=e=>{if(!k())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()},P=new IntersectionObserver(([t])=>{u=t.isIntersecting,T()});P.observe(t),t.addEventListener("pointermove",F),t.addEventListener("pointerleave",R),t.addEventListener("pointercancel",R),document.addEventListener("visibilitychange",T),y.addEventListener("change",T);const L=()=>{h||(h=!0,cancelAnimationFrame(n),P.disconnect(),t.removeEventListener("pointermove",F),t.removeEventListener("pointerleave",R),t.removeEventListener("pointercancel",R),document.removeEventListener("visibilitychange",T),y.removeEventListener("change",T),i.signal?.removeEventListener("abort",L),o.destroy(),e.destroy())};if(i.signal?.addEventListener("abort",L,{once:!0}),i.signal?.aborted)throw L(),new DOMException("Cancelled","AbortError");return T(),{canvas:t,media:e,update(t){s=f(s,t),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){m=t,T()},async seek(t){p=Math.max(0,t),await e.seek(p),o.invalidate(),c=!0,E()},redraw(){o.invalidate(),c=!0,E()},get time(){return S?.currentTime??p},get paused(){return m||y.matches},get maxCells(){return o.maxCells},get capabilities(){return o.capabilities},destroy:L}}var D={Standard:()=>import("figlet/fonts/Standard"),Slant:()=>import("figlet/fonts/Slant"),Small:()=>import("figlet/fonts/Small"),Big:()=>import("figlet/fonts/Big"),Banner:()=>import("figlet/fonts/Banner"),Block:()=>import("figlet/fonts/Block"),Bubble:()=>import("figlet/fonts/Bubble"),Digital:()=>import("figlet/fonts/Digital"),Doom:()=>import("figlet/fonts/Doom"),Lean:()=>import("figlet/fonts/Lean"),Mini:()=>import("figlet/fonts/Mini"),Script:()=>import("figlet/fonts/Script"),Shadow:()=>import("figlet/fonts/Shadow"),Speed:()=>import("figlet/fonts/Speed"),Starwars:()=>import("figlet/fonts/Star Wars"),Stop:()=>import("figlet/fonts/Stop"),Straight:()=>import("figlet/fonts/Straight"),Thin:()=>import("figlet/fonts/Thin"),ThreeD:()=>import("figlet/fonts/3-D"),Univers:()=>import("figlet/fonts/Univers"),Wavy:()=>import("figlet/fonts/Wavy")},U=Object.keys(D);exports.BLEND_MODES=i,exports.DEFAULT_STUDIO_SETTINGS=a,exports.DITHER_ALGORITHMS=e,exports.STUDIO_CHARACTER_SETS={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:" ⠁⠃⠇⡇⣇⣧⣷⣿"}},exports.STUDIO_LOOKS=m,exports.STUDIO_PALETTES=s,exports.STUDIO_STYLES=t,exports.STUDIO_TEXT_FONTS=U,exports.createStudioRenderer=I,exports.createStudioText=async function(t,e="Standard",i="#ffffff"){if(!Object.prototype.hasOwnProperty.call(D,e))throw new Error("Unknown text font.");const{default:s}=await import("figlet/browser"),a=await D[e]();s.parseFont(e,a.default),s.defaults({fetchFontIfMissing:!1});const 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 d=c.getContext("2d");return d.fillStyle="#080808",d.fillRect(0,0,c.width,c.height),d.fillStyle=i,d.font=15*l+"px monospace",d.textBaseline="top",o.forEach((t,e)=>d.fillText(t,16,16+15*e*l)),{canvas:c,ascii:r}},exports.exportStudio=async function(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 d=document.createElement("canvas"),f=I(d,l(e),{maxDimension:4096,maxCells:i.maxCells??12e3,pixelRatio:r/(i.referenceWidth??Math.min(r,960))});let m;try{if(L(a),i.onProgress?.(0),c){if(f.render(await t.frame(0,a),0,r,o),"unavailable"===d.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");L(a);const e=await new Promise((t,e)=>d.toBlob(i=>i?t(i):e(new Error("Image export failed.")),"png"===s?"image/png":"image/jpeg",i.quality??.92));return i.onProgress?.(1),e}const e=Math.ceil(h*n);if("gif"===s){const s=await import("gifenc"),{GIFEncoder:l,quantize:c,applyPalette:m}="function"==typeof s.GIFEncoder?s:s.default,u=l(),p=d.getContext("2d");for(let s=0;s<e;s++){L(a);const l=s/n;if(f.invalidate(),f.render(await t.frame(l,a),l,r,o),"unavailable"===d.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");const g=p.getImageData(0,0,r,o).data,M=c(g,256),x=m(g,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:p,BufferTarget:g,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 p,target:new g});d.width=r,d.height=o,m=()=>w.cancel();const b=new M(d,{codec:v,bitrate:Math.max(5e5,Math.round(r*o*n*.15))});w.addVideoTrack(b,{frameRate:n}),d.width=r,d.height=o,await w.start();for(let s=0;s<e;s++){L(a);const l=s/n;if(f.invalidate(),f.render(await t.frame(l,a),l,r,o),"unavailable"===d.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");await b.add(l,Math.min(1/n,h-l)),i.onProgress?.((s+1)/e*.98),s%4==0&&await new Promise(t=>setTimeout(t,0))}return b.close(),L(a),await w.finalize(),m=void 0,i.onProgress?.(1),new Blob([w.target.buffer],{type:"mp4"===s?"video/mp4":"video/webm"})}catch(t){throw await(m?.().catch(()=>{})),t}finally{f.destroy(),d.width=d.height=1}},exports.loadStudioMedia=P,exports.mountStudio=async function(t,e,i={}){const s=await P(e,i.signal);try{return C(t,s,i)}catch(t){throw s.destroy(),t}},exports.mountStudioMedia=C,exports.normalizeStudioSettings=l,exports.parseStudioSettings=function(t){if(t.length>1e5)throw new Error("Settings exceed 100 KB.");return l(JSON.parse(t))},exports.restyleStudio=function(t,e=Math.random){const i=m.filter(e=>e.settings.style!==t.style||e.settings.ink!==t.ink),s=u(i[Math.min(i.length-1,Math.max(0,Math.floor(e()*i.length)))].id);return s.aspectRatio=t.aspectRatio,s.crop={...t.crop},s.mask=l(t).mask,s},exports.serializeStudioSettings=function(t){return JSON.stringify(l(t))},exports.studioCrop=c,exports.studioDimensions=d,exports.studioLook=u,exports.studioSourceSize=k,exports.updateStudioSettings=f;//# sourceMappingURL=studio.cjs.map
|
|
1
|
+
"use strict";var t=["ascii","blocks","braille","dots","lines","cross","diagonal","diamond","mixed","pixel","mosaic","lego","voxel","disco","dither"],e=["none","bayer2","bayer4","bayer8","bayer16","floyd-steinberg","atkinson","stucki","sierra","sierra-lite","burkes","jarvis","halftone","lines","noise"],i=["source-over","multiply","screen","overlay","soft-light","hard-light","color-dodge","color-burn","hue","saturation","color","luminosity"],s={original:[],mono:["#080808","#f2f2e8"],asciify:["#080808","#625b38","#a19558","#e8b900"],gameboy:["#0f380f","#306230","#8bac0f","#9bbc0f"],cga:["#000000","#55ffff","#ff55ff","#ffffff"],pico8:["#000000","#1d2b53","#7e2553","#008751","#ab5236","#5f574f","#c2c3c7","#fff1e8","#ff004d","#ffa300","#ffec27","#00e436","#29adff","#83769c","#ff77a8","#ffccaa"],c64:["#000000","#ffffff","#880000","#aaffee","#cc44cc","#00cc55","#0000aa","#eeee77","#dd8855","#664400","#ff7777","#333333","#777777","#aaff66","#0088ff","#bbbbbb"],amber:["#100b00","#5f3b00","#c98014","#ffd17c"],ice:["#081b29","#25586e","#69a6b3","#d9ece7"],risograph:["#f4ebd0","#f2594b","#2853a5","#29232e"],sepia:["#201b17","#6b5039","#b49868","#f6e6c5"],nord:["#2e3440","#4c566a","#88c0d0","#eceff4"],dusk:["#211b35","#654271","#c3788c","#f5c9a3"],forest:["#101f1b","#355747","#87a16f","#e4e3ba"],ocean:["#071b33","#17577f","#3fa7a4","#d9efde"],newsprint:["#191919","#666666","#aaaaaa","#eee9df"],custom:["#080808","#e8b900"]},a={version:1,aspectRatio:"original",style:"ascii",cellSize:7,charset:" .:-=+*#%@",colorMode:"accent",ink:"#e8b900",crop:{x:.5,y:.5,zoom:1,rotation:0},backdrop:{mode:"solid",color:"#080808",color2:"#393323",blur:12,opacity:1},color:{brightness:0,contrast:1,saturation:1,grayscale:0,tint:"#e8b900",amount:0,blend:"source-over"},dither:{algorithm:"none",palette:"mono",colors:["#080808","#e8b900"],amount:1,scale:2,threshold:.5,motion:"none",speed:1},mask:{enabled:!1,invert:!1,shapes:[]},lights:[],effects:{bloom:0,characterBloom:0,grain:0,dust:0,scanlines:0,crt:0,prism:0,vignette:0,glitch:0,pixelate:0,blur:0,blurType:"gaussian",angle:0,focus:.5,halftone:0},motion:{type:"none",speed:1},hover:{effect:"trail",strength:.55,radius:.2,edgeSafe:!1}},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),d=a;if(void 0!==c.version&&1!==c.version)throw new Error("Unsupported studio settings version. Update asciify-engine.");const m=r(c.crop),f=r(c.backdrop),u=r(c.color),p=r(c.dither),g=r(c.mask),M=r(c.effects),x=r(c.motion),v=r(c.hover),w={...d.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"],d.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,d.style),cellSize:o(c.cellSize,7,3,60),charset:"string"==typeof c.charset&&c.charset.length?Array.from(c.charset).slice(0,128).join(""):d.charset,colorMode:h(c.colorMode,["accent","source","gray"],d.colorMode),ink:n(c.ink,d.ink),crop:{x:o(m.x,.5,0,1),y:o(m.y,.5,0,1),zoom:o(m.zoom,1,1,5),rotation:90*Math.round(o(m.rotation,0,-360,360)/90)},backdrop:{mode:h(f.mode,["solid","transparent","source","blurred","gradient"],d.backdrop.mode),color:n(f.color,d.backdrop.color),color2:n(f.color2,d.backdrop.color2),blur:o(f.blur,12,0,32),opacity:o(f.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,d.color.tint),amount:o(u.amount,0,0,1),blend:h(u.blend,i,d.color.blend)},dither:{algorithm:h(p.algorithm,e,"none"),palette:"string"==typeof p.palette&&Object.prototype.hasOwnProperty.call(s,p.palette)?p.palette:"mono",colors:Array.isArray(p.colors)&&p.colors.length>=2?p.colors.slice(0,32).map(t=>n(t,"#000000")):[...d.dither.colors],amount:o(p.amount,1,0,2),scale:Math.round(o(p.scale,2,1,12)),threshold:o(p.threshold,.5,0,1),motion:h(p.motion,["none","drift","shimmer"],"none"),speed:o(p.speed,1,.1,3)},mask:{enabled:!0===g.enabled,invert:!0===g.invert,shapes:Array.isArray(g.shapes)?g.shapes.slice(0,64).map(t=>{const e=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,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 d(t,e,i){if(Math.abs(i.crop.rotation/90)%2==1&&([t,e]=[e,t]),"original"===i.aspectRatio)return[t,e];const[s,a]=i.aspectRatio.split(":").map(Number);return t/e>s/a?[Math.round(e*s/a),e]:[t,Math.round(t*a/s)]}function m(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)}function f(t,e,i,s=12e3,a=1){const r=Math.max(2,Number.isFinite(t)?t:960),o=Math.max(2,Number.isFinite(e)?e:540),n=Math.max(1,Math.floor(Number.isFinite(s)?s:12e3)),h=Math.max(.01,Number.isFinite(a)?a:1),l=["dither","pixel","mosaic","lego","voxel","disco","dots"].includes(i.style)?1:1.65;let c=Math.max(1,Math.ceil(Math.sqrt(r*o/(n*l))/h));for(;Math.ceil(r/(c*h))*Math.ceil(o/(c*h*l))>n;)c++;const d="dither"===i.style?i.dither.scale:i.cellSize,m=Math.max(c,d)*h;return{cell:m,rowHeight:m*l,columns:Math.ceil(r/m),rows:Math.ceil(o/(m*l)),minimum:c,limited:d<c}}var u=[["ascii","Signature ASCII","Brand ink and clean characters.",{}],["print","Newsprint","Fine diffusion on warm paper.",{style:"dither",dither:{algorithm:"floyd-steinberg",palette:"newsprint"}}],["handheld","Pocket camera","Four-tone ordered dither.",{style:"dither",dither:{algorithm:"bayer4",palette:"gameboy",scale:3}}],["riso","Two inks","Limited-color print texture.",{style:"dither",dither:{algorithm:"atkinson",palette:"risograph",scale:2}}],["night","Night signal","Gray characters and optical fringe.",{ink:"#888888",effects:{prism:.7,scanlines:.2,vignette:.3}}],["terminal","Phosphor","Green glyphs with a soft glow.",{ink:"#83efad",effects:{bloom:.4,scanlines:.35,crt:.2}}],["mosaic","Mosaic study","Separated color tiles.",{style:"mosaic",cellSize:14,colorMode:"source"}],["bricks","Brickwork","Colorful studded cells.",{style:"lego",cellSize:18,colorMode:"source"}],["voxel","Little volumes","Three-face isometric tiles.",{style:"voxel",cellSize:22,colorMode:"source"}],["disco","Mirror room","Faceted tiles and warm light.",{style:"disco",cellSize:18,colorMode:"source",lights:[{x:.35,y:.25,radius:.25,intensity:.45,color:"#fff2d4"}]}],["wallpaper","Wallpaper","Living ASCII over a softened source.",{backdrop:{mode:"blurred",blur:18,opacity:.55},ink:"#f2e9c9",motion:{type:"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=u.find(e=>e.id===t);if(!e)throw new Error("Unknown studio look.");return l(e.settings)}var g=(t,e)=>{const i=43758.5453*Math.sin(127.1*t+311.7*e);return i-Math.floor(i)};function M(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 x={"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]]},v=t=>[parseInt(t.slice(1,3),16),parseInt(t.slice(3,5),16),parseInt(t.slice(5,7),16)];function w(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 b=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]=w(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 d=.035+.11*Math.max(.1,Math.min(1,i)),m=Math.min(128,Math.max(1,Math.ceil(c/(.45*d)))),f=c?h/c:1,u=c?l/c:0,p=Math.min(1,c/(d*m)*2.2);for(let i=0;i<m;i++){const h=(i+.5)/m,l=s?s.x+(t-s.x)*h:t,c=s?s.y+(e-s.y)*h:e,g=Math.max(0,Math.floor((l-2.5*d/o)*(a-1))),M=Math.min(a-1,Math.ceil((l+2.5*d/o)*(a-1))),x=Math.max(0,Math.floor((c-2.5*d/n)*(r-1))),v=Math.min(r-1,Math.ceil((c+2.5*d/n)*(r-1)));for(let t=x;t<=v;t++)for(let e=g;e<=M;e++){const i=(e/(a-1)-l)*o/d,s=(t/(r-1)-c)*n/d,h=Math.exp(1.5*-(i*i+s*s)),m=t*a+e;if("dissolve"===this.mode)this.ink[m]=Math.max(this.ink[m],h);else{const t=(-i*u+s*f)*h*2.8,e="silk"===this.mode?f*t:-s*h*2.5,a="silk"===this.mode?u*t:i*h*2.5;this.targetX[m]=Math.max(-1,Math.min(1,this.targetX[m]+e*p)),this.targetY[m]=Math.max(-1,Math.min(1,this.targetY[m]+a*p))}}}this.peak=1}step(t){if(!this.active||!Number.isFinite(t))return;const e=Math.max(0,Math.min(.05,t)),i=Math.exp(-("dissolve"===this.mode?2.15:3.2)*e),s=1-Math.exp(-22*e);let a=0;for(let t=0;t<this.ink.length;t++)if("dissolve"===this.mode){this.ink[t]*=i,a=Math.max(a,this.ink[t]);const e=Math.round(65535*this.ink[t]);this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e}else{this.targetX[t]*=i,this.targetY[t]*=i,this.offsetX[t]+=(this.targetX[t]-this.offsetX[t])*s,this.offsetY[t]+=(this.targetY[t]-this.offsetY[t])*s,a=Math.max(a,Math.abs(this.offsetX[t]),Math.abs(this.offsetY[t]),Math.abs(this.targetX[t]),Math.abs(this.targetY[t]));const e=Math.round(this.offsetX[t]*(this.edgeSafe?this.edge[t]:1)*32767+32768),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,d=t=>(t[l]*(1-n)+t[l+1]*n)*(1-h)+(t[c]*(1-n)+t[c+1]*n)*h;i[0]=d(this.offsetX)*(this.edgeSafe?w(t,e,this.width/this.height):1)*.08,i[1]=d(this.offsetY)*(this.edgeSafe?w(t,e,this.width/this.height):1)*.08,i[2]="dissolve"===this.mode?6*-d(this.ink):0}},y=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),d=1-Math.exp(-c/2.2),m=h*(.022+.075*i)*(.65+.95*d),f=Math.min(128,Math.max(1,Math.ceil(n/(.4*m)))),u=n/m*(.32+.22*d)/f,p=r/n,g=o/n,M=-g,x=p,v=n*(2+18*d)/f;for(let i=0;i<f;i++){const s=(i+.5)/f,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*m)),h=Math.min(this.width-2,Math.ceil(r+3*m)),l=Math.max(1,Math.floor(o-3*m)),c=Math.min(this.height-2,Math.ceil(o+3*m));for(let t=l;t<=c;t++)for(let e=n;e<=h;e++){const i=((e-r)*p+(t-o)*g)/m,s=((e-r)*M+(t-o)*x)/m,a=Math.exp(-i*i*.65-s*s*1.7),n=t*this.width+e;this.ink[n]=1-(1-this.ink[n])*Math.exp(-a*u);const h=1-s*s*.55,l=i*s*.7;this.u[n]=Math.max(-80,Math.min(80,this.u[n]+(p*h+M*l)*a*v)),this.v[n]=Math.max(-80,Math.min(80,this.v[n]+(g*h+x*l)*a*v))}}this.peak=1}read(t,e,i){const s=0|(e=Math.max(.5,Math.min(this.width-1.5,e))),a=0|(i=Math.max(.5,Math.min(this.height-1.5,i))),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,d=0|l,m=h-c,f=l-d,u=d*i+c,p=(1-m)*(1-f),g=m*(1-f),M=(1-m)*f,x=m*f;this.a[n]=(this.u[u]*p+this.u[u+1]*g+this.u[u+i]*M+this.u[u+i+1]*x)*a,this.b[n]=(this.v[u]*p+this.v[u+1]*g+this.v[u+i]*M+this.v[u+i+1]*x)*a,this.c[n]=(this.ink[u]*p+this.ink[u+1]*g+this.ink[u+i]*M+this.ink[u+i+1]*x)*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 E(t,e){const i=Math.max(0,Math.min(1,e/.38));return t+(1-2*t)*(i*i*(3-2*i))}var k=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]=w(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 y(this.columns,this.rows),this.afterimage=new b(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,d=Math.max(1,Math.floor((r-h/this.xScale)*(this.columns-1))),m=Math.min(this.columns-2,Math.ceil((r+h/this.xScale)*(this.columns-1))),f=Math.max(1,Math.floor((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=f;t<=u;t++)for(let e=d;e<=m;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,d=(this.velocity[o]+(h*s*s-8*n)*e)*i*c;this.velocity[o]=d,this.next[o]=(n+d*e)*c,t=Math.max(t,Math.abs(this.next[o]),.1*Math.abs(d))}this.heights.set(this.next),this.energy=t,this.pending=!1}if(!this.active)return void this.clear();const 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 T(t){return"videoWidth"in t?[t.videoWidth,t.videoHeight]:"naturalWidth"in t?[t.naturalWidth,t.naturalHeight]:[t.width,t.height]}var A=(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}},F=(t,e,i)=>{t.width===e&&t.height===i||(t.width=e,t.height=i)},I={blocks:" ░▒▓█",braille:" ⠁⠃⠇⡇⣇⣧⣷⣿",lines:" -═╪╬",cross:" ·+xX#",diagonal:" /╱╳",diamond:" ·◇◈◆",mixed:" .:+/◇#@"};function R(t,e={},i={}){const a=t.getContext("2d");if(!a)throw new Error("Canvas is already owned by another renderer.");const r=A(),o=A(!0),n=A(),h=A(),d=A(),m=A(),u=A(),p=A(),w=A();let b,y=l(e),S=0,R="",P=new Uint8ClampedArray(0),L=0,C=0,D=0,U=null,N="",O=new k,X=0;const _=[0,0,0],B=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 G=Math.max(.1,Math.min(8,i.pixelRatio??1));return{canvas:t,render:function(e,i=0,l=960,A=540){if(Number.isFinite(i)||(i=0),!Number.isFinite(l)||!Number.isFinite(A)||l<1||A<1)throw new Error("Render dimensions must be positive finite numbers.");const[Y,W]=T(e);if(!Y||!W)return;const q=Math.min(1,B/Math.max(l,A)),$=Math.max(2,Math.round(l*q)),j=Math.max(2,Math.round(A*q));F(t,$,j),F(r.canvas,$,j),F(n.canvas,$,j),F(h.canvas,$,j),F(d.canvas,$,j),X!==$/j&&(X=$/j,O=new k(X)),O.configure(y.hover.effect,y.hover.strength,y.hover.radius,y.hover.edgeSafe),O.step(Math.max(0,Math.min(.05,i-D))),D=i;const H="currentTime"in e?e.getVideoPlaybackQuality?.().totalVideoFrames??e.currentTime:0,V=[S,$,j,H].join(":"),J="dither"===y.style,K=f($,j,y,z,G),Q=K.cell,Z=K.rowHeight,tt=K.columns,et=K.rows;if(R!==V||U!==e||L!==tt||C!==et){U=e,R=V,L=tt,C=et,r.ctx.clearRect(0,0,$,j),r.ctx.save();const t=c(Y,W,$,j,y.crop);r.ctx.translate(t.x+t.width/2,t.y+t.height/2),r.ctx.rotate(y.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(),F(o.canvas,L,C),o.ctx.clearRect(0,0,L,C),o.ctx.drawImage(r.canvas,0,0,L,C),P=o.ctx.getImageData(0,0,L,C).data;const i=y.color;for(let t=0;t<P.length;t+=4){const e=.299*P[t]+.587*P[t+1]+.114*P[t+2];for(let s=0;s<3;s++){const a=e+(P[t+s]-e)*i.saturation;P[t+s]=((a*(1-i.grayscale)+e*i.grayscale)/255-.5)*i.contrast*255+127.5+255*i.brightness}}}n.ctx.clearRect(0,0,$,j),n.ctx.globalAlpha=1,n.ctx.globalCompositeOperation="source-over";const it=i*y.motion.speed;if(J){const t=new Uint8ClampedArray(P),e=y.motion.type;if(O.active||"none"!==e)for(let i=0;i<C;i++)for(let s=0;s<L;s++){const a=s/L,r=i/C;let o=s,n=i,h=0,l=1,c=1;if(O.active&&(O.sample(a,r,_),o-=_[0]*L,n-=_[1]*C,h=_[2]/3),"wave"===e&&(n+=Math.sin(8*a+2*it+4*r)*C*.015),"ripple"===e){const t=a-.5,e=r-.5,i=.03*Math.sin(30*Math.hypot(t,e)-3*it);o+=t*i*L,n+=e*i*C}"breathe"===e&&(l=.92+.08*Math.sin(1.5*it+3*a)),"reveal"===e&&(c=Math.max(0,Math.min(1,4*(.7*Math.sin(.7*it)+.7-a)))),"glitch"===e&&g(i,Math.floor(6*it))>.93&&(o+=8*Math.sin(5*it)),"vapor"===e&&(n+=Math.sin(6*a+it)*C*.025),"fire"===e&&(n+=Math.sin(7*a+3*it+8*r)*C*.01,l=.8+.2*Math.sin(12*r-4*it)),"hologram"===e&&(c=.72+.28*Math.sin(.65*i+5*it)),"chrome"===e&&(l=.5+Math.abs(Math.sin(8*r+it)));const d=4*(i*L+s),m=4*(Math.max(0,Math.min(C-1,Math.round(n)))*L+Math.max(0,Math.min(L-1,Math.round(o))));for(let i=0;i<3;i++){const s=P[m+i]/255;let r=(["trail","contour"].includes(y.hover.effect)?E(s,h):"dissolve"===y.hover.effect?s*Math.max(0,1+h):s)*l;"rainbow"===e&&(r*=.65+.35*Math.sin(2*it+5*a+2.094*i)),"hologram"===e&&(r*=0===i?.4:1),"fire"===e&&(r*=0===i?1.3:1===i?.7:.3),t[d+i]=255*r}t[d+3]=P[m+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(v),c=x[o],d=c?new Float32Array(3*e*3):null,m="drift"===a.motion?Math.floor(r*a.speed*3):0,f="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]){d&&(d[u]=d[u+1]=d[u+2]=0);continue}let p=0;o.startsWith("bayer")?p=M(a+m&15,s+m&15,Number(o.slice(5))):"noise"===o?p=g(a,s)-.5:"lines"===o?p=(s+m)%4/3-.5:"halftone"===o&&(p=Math.hypot(a%6-2.5,s%6-2.5)/3.54-.5);const x=128*(p*n+f+(.5-h)),v=t[r]+x+(d?.[u]??0),w=t[r+1]+x+(d?.[u+1]??0),b=t[r+2]+x+(d?.[u+2]??0);let y=0,S=0,E=0;if(l.length){let t=1/0;for(const e of l){const i=(v-e[0])**2*.299+(w-e[1])**2*.587+(b-e[2])**2*.114;i<t&&(t=i,[y,S,E]=e)}}else y=51*Math.round(v/51),S=51*Math.round(w/51),E=51*Math.round(b/51);if(t[r]=y,t[r+1]=S,t[r+2]=E,d&&c){d[u]=d[u+1]=d[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);d[l]+=(v-y)*o*n,d[l+1]+=(w-S)*o*n,d[l+2]+=(b-E)*o*n}}}}(t,L,C,y.dither,i),o.ctx.putImageData(new ImageData(t,L,C),0,0),n.ctx.imageSmoothingEnabled=!1,n.ctx.drawImage(o.canvas,0,0,$,j)}else{const t=Array.from(I[y.style]??y.charset),e=n.ctx,i="ascii"===y.style||!!I[y.style],s=Math.max(3,Math.round(.92*Z)),a=Math.ceil(Q+4),r=Math.ceil(Z+4),o=[t.join(""),s,a,r,y.ink,y.colorMode].join(":");i&&o!==N&&(N=o,F(u.canvas,a*t.length,r),u.ctx.clearRect(0,0,u.canvas.width,r),u.ctx.font=`${s}px monospace`,u.ctx.textBaseline="middle",u.ctx.textAlign="center",u.ctx.fillStyle="accent"===y.colorMode?y.ink:"#ffffff",t.forEach((t,e)=>u.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<L;o++){let n=o,h=s,l=0;O.active&&(O.sample(o/L,s/C,_),n=Math.max(0,Math.min(L-1,o-_[0]*L)),h=Math.max(0,Math.min(C-1,s-_[1]*C)),l=_[2]/3);const c=4*(Math.floor(h)*L+Math.floor(n));if(!P[c+3])continue;const d=P[c],m=P[c+1],f=P[c+2],p=(.299*d+.587*m+.114*f)/255;let M=p;["trail","contour"].includes(y.hover.effect)&&l?M=E(M,l):"dissolve"===y.hover.effect&&(M*=Math.max(0,1+l));const x=y.motion.type;let v=o*Q,w=s*Z,b=1;if("breathe"===x&&(M*=.92+.08*Math.sin(1.5*it+.03*o)),"wave"===x&&(w+=Math.sin(.12*o+2*it+.08*s)*Z*.4),"ripple"===x){const t=o/L-.5,e=s/C-.5,i=Math.hypot(t,e),a=Math.sin(30*i-3*it)*Q*.65;v+=t*a,w+=e*a}"fire"===x&&(w-=Math.sin(.16*o+3*it+.09*s)*Z*.35,M*=.85+.15*Math.sin(.3*s-4*it)),"hologram"===x&&(b=.72+.28*Math.sin(.65*s+5*it)),"reveal"===x&&(b=Math.max(0,Math.min(1,4*(.7*Math.sin(.7*it)+.7-o/L)))),"glitch"===x&&g(s,Math.floor(6*it))>.93&&(v+=Math.sin(5*it)*Q*3),"vapor"===x&&(w+=Math.sin(.04*o+it)*Z),i||"accent"!==y.colorMode||(b*=M),e.globalAlpha=b;const S=255*(M-p);let k="source"===y.colorMode?`rgb(${d+S},${m+S},${f+S})`:"gray"===y.colorMode?`rgb(${Math.round(255*M)},${Math.round(255*M)},${Math.round(255*M)})`:y.ink;if("rainbow"===x&&(k=`hsl(${(o/L*180+40*it)%360} 70% 65%)`),"fire"===x&&(k=`hsl(${15+40*M} 90% ${30+45*M}%)`),"hologram"===x&&(k=`hsl(185 65% ${40+40*M}%)`),"chrome"===x&&(k=`hsl(210 12% ${25+70*Math.abs(Math.sin(.2*s+it))}%)`),e.fillStyle=k,i){const i=Math.max(0,Math.min(t.length-1,Math.floor(M*(t.length-1))));"accent"!==y.colorMode||["rainbow","fire","hologram","chrome"].includes(x)?e.fillText(t[i],v+Q/2,w+Z/2):e.drawImage(u.canvas,i*a,0,a,r,v+(Q-a)/2,w+(Z-r)/2,a,r)}else if("dots"===y.style)e.beginPath(),e.arc(v+Q/2,w+Z/2,.48*Q*Math.sqrt(M),0,2*Math.PI),e.fill();else if("voxel"===y.style){const t=v+Q/2,i=w+Z/2;e.beginPath(),e.moveTo(t,w),e.lineTo(v+Q,w+.25*Z),e.lineTo(t,i),e.lineTo(v,w+.25*Z),e.closePath(),e.fill(),e.globalAlpha=.72*b,e.beginPath(),e.moveTo(v,w+.25*Z),e.lineTo(t,i),e.lineTo(t,w+Z),e.lineTo(v,w+.75*Z),e.closePath(),e.fill(),e.globalAlpha=.42*b,e.beginPath(),e.moveTo(t,i),e.lineTo(v+Q,w+.25*Z),e.lineTo(v+Q,w+.75*Z),e.lineTo(t,w+Z),e.closePath(),e.fill()}else{const t="pixel"===y.style?0:Math.max(.5,.06*Q);e.fillRect(v,w,Q-t,Z-t),"lego"===y.style&&(e.fillStyle="rgba(255,255,255,.2)",e.beginPath(),e.arc(v+Q/2,w+Z/2,.28*Q,0,2*Math.PI),e.fill(),e.strokeStyle="rgba(0,0,0,.25)",e.stroke()),"disco"===y.style&&(e.fillStyle=`rgba(255,255,255,${.1+.25*g(o,s)})`,e.fillRect(v,w,Q-t,.35*Z),e.fillStyle="rgba(0,0,0,.25)",e.fillRect(v,w+.65*Z,Q-t,.35*Z-t))}}}n.ctx.globalAlpha=1,(y.color.amount||y.lights.length)&&(F(p.canvas,$,j),p.ctx.clearRect(0,0,$,j),p.ctx.drawImage(n.canvas,0,0)),y.color.amount&&(n.ctx.save(),n.ctx.globalCompositeOperation=y.color.blend,n.ctx.globalAlpha=y.color.amount,n.ctx.fillStyle=y.color.tint,n.ctx.fillRect(0,0,$,j),n.ctx.restore());for(const t of y.lights){const e=t.radius*Math.max($,j),i=n.ctx.createRadialGradient(t.x*$,t.y*j,0,t.x*$,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,$,j),n.ctx.restore()}if((y.color.amount||y.lights.length)&&(n.ctx.globalCompositeOperation="destination-in",n.ctx.drawImage(p.canvas,0,0),n.ctx.globalCompositeOperation="source-over"),y.mask.enabled&&y.mask.shapes.length){const t=d.ctx;t.clearRect(0,0,$,j),t.fillStyle="#fff",t.strokeStyle="#fff",t.lineCap="round",t.lineJoin="round";for(const e of y.mask.shapes){if(t.beginPath(),"ellipse"===e.kind)t.ellipse((e.x+e.width/2)*$,(e.y+e.height/2)*j,e.width*$/2,e.height*j/2,0,0,2*Math.PI);else{if("rectangle"!==e.kind){if(t.lineWidth=(e.size??.05)*$,1===e.points?.length){t.arc(e.points[0][0]*$,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*$,i*j):t.moveTo(e*$,i*j)),t.stroke();continue}t.rect(e.x*$,e.y*j,e.width*$,e.height*j)}t.fill()}n.ctx.globalCompositeOperation=y.mask.invert?"destination-out":"destination-in",n.ctx.drawImage(d.canvas,0,0),n.ctx.globalCompositeOperation="source-over"}const st=h.ctx;st.clearRect(0,0,$,j),st.globalAlpha=y.backdrop.opacity;const at=y.backdrop;if("solid"===at.mode&&(st.fillStyle=at.color,st.fillRect(0,0,$,j)),"gradient"===at.mode){const t=st.createLinearGradient(0,0,$,j);t.addColorStop(0,at.color),t.addColorStop(1,at.color2),st.fillStyle=t,st.fillRect(0,0,$,j)}if("source"===at.mode&&st.drawImage(r.canvas,0,0),"blurred"===at.mode){const t=Math.max(1,at.blur);F(m.canvas,Math.max(2,Math.round($/t)),Math.max(2,Math.round(j/t))),m.ctx.drawImage(r.canvas,0,0,m.canvas.width,m.canvas.height),st.imageSmoothingEnabled=!0,st.drawImage(m.canvas,0,0,$,j)}st.globalAlpha=1,y.effects.characterBloom>0&&(F(w.canvas,Math.max(2,Math.round($/3)),Math.max(2,Math.round(j/3))),w.ctx.clearRect(0,0,w.canvas.width,w.canvas.height),w.ctx.drawImage(n.canvas,0,0,w.canvas.width,w.canvas.height),st.save(),st.globalAlpha=.8*y.effects.characterBloom,st.globalCompositeOperation="screen",st.filter=`blur(${1+4*y.effects.characterBloom}px)`,st.drawImage(w.canvas,0,0,$,j),st.restore()),st.drawImage(n.canvas,0,0);const rt=Object.entries(y.effects).some(([t,e])=>!["angle","focus","blurType","characterBloom"].includes(t)&&"number"==typeof e&&e>0);a.clearRect(0,0,$,j),rt?(void 0===b&&(b=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()}}}()),b?a.drawImage(b.render(h.canvas,y.effects,i,G),0,0):a.drawImage(h.canvas,0,0),t.dataset.studioFinish=b?"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){y=l(t),S++},pointer:(t,e,i)=>{O.configure(y.hover.effect,y.hover.strength,y.hover.radius,y.hover.edgeSafe),O.move(t,e,i)},leave(){O.leave()},get active(){return O.active},get settings(){return l(y)},get capabilities(){return{gpuFinish:null!==b}},invalidate(){R=""},destroy(){b?.destroy();for(const t of[r,o,n,h,d,m,u,p,w])t.canvas.width=t.canvas.height=1;U=null,P=new Uint8ClampedArray(0)}}}function P(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 L(t,e){if("string"==typeof t&&t.startsWith("blob:")){const i=await fetch(t,{signal:e}),s=await i.blob();return L(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 d=r(n,!0);if(d.length*h*l*4>128e6)throw new Error("GIF exceeds the 128 MB decoded budget. Use MP4 for long animations.");const m=document.createElement("canvas");m.width=h,m.height=l;const f=m.getContext("2d"),u=document.createElement("canvas"),p=u.getContext("2d"),g=d.reduce((t,e)=>t+Math.max(20,e.delay),0)/1e3;let M=-1,x=null;const v=t=>{const e=(t%g+g)%g*1e3;let i=0,s=0;for(;s<d.length-1&&(i+=Math.max(20,d[s].delay),!(e<i));s++);s<M&&(f.clearRect(0,0,h,l),M=-1,x=null);for(let t=M+1;t<=s;t++){const e=d[t-1];2===e?.disposalType&&f.clearRect(e.dims.left,e.dims.top,e.dims.width,e.dims.height),3===e?.disposalType&&x&&f.putImageData(x,0,0);const i=d[t];x=3===i.disposalType?f.getImageData(0,0,h,l):null,u.width=i.dims.width,u.height=i.dims.height,p.putImageData(new ImageData(new Uint8ClampedArray(i.patch),u.width,u.height),0,0),f.drawImage(u,i.dims.left,i.dims.top)}return M=s,m};return v(0),{source:m,width:h,height:l,duration:g,animated:!0,seek:async()=>{},frame:v,destroy(){m.width=u.width=1,d.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=P(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=P(o,"seeked",e);o.currentTime=i,await s},frame:()=>o,destroy:n}}catch(t){throw n(),t}}var C=t=>{if(t?.aborted)throw new DOMException("Export cancelled","AbortError")};function D(t,e,i={}){let s=l(i.settings),a=i.width??e.width,r=i.height??e.height;const o=R(t,s,i);let n=0,h=!1,c=!0,f=!1,u=!0,p=0,g=0,M=0,x=-1,v=0,w=0,b=0;const y=matchMedia("(prefers-reduced-motion: reduce)"),S=e.source instanceof HTMLVideoElement?e.source:null,E=()=>{h||n||!u||document.hidden||(n=requestAnimationFrame(A))},k=()=>!f&&!y.matches&&u&&!document.hidden,T=()=>{S&&(S.loop=!0,k()?S.play().catch(()=>{f=!0,c=!0,E()}):S.pause()),g=0,c=!0,E()};function A(t){if(n=0,h||!u||document.hidden)return;const l=k();l&&(p+=g?Math.min(.1,(t-g)/1e3):0),g=t;const m=l&&(e.animated||"none"!==s.motion.type||"none"!==s.dither.motion||s.effects.grain>0||s.effects.dust>0||s.effects.glitch>0),y=S?.getVideoPlaybackQuality?.().totalVideoFrames??-1,T="none"!==s.motion.type||"none"!==s.dither.motion||s.effects.grain>0||s.effects.dust>0||s.effects.glitch>0,A=!S||y<0||y!==x;if(c||o.active||m&&(A||T)&&t-M>=1e3/Math.max(1,Math.min(60,i.fps??60))-.5){const n=performance.now();try{e.animated&&!S&&o.invalidate();const[t,h]=d(a,r,s);o.render(e.frame(S?.currentTime??p),p,t,h);const l=performance.now()-n;i.onFrame?.(S?.currentTime??p,l),w=w?.9*w+.1*l:l,++v>20&&!1!==i.adaptive&&(b=w>13?b+1:0,b>=12&&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&&(m||o.active)&&E()}const F=e=>{if(!k())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()},P=new IntersectionObserver(([t])=>{u=t.isIntersecting,T()});P.observe(t),t.addEventListener("pointermove",F),t.addEventListener("pointerleave",I),t.addEventListener("pointercancel",I),document.addEventListener("visibilitychange",T),y.addEventListener("change",T);const L=()=>{h||(h=!0,cancelAnimationFrame(n),P.disconnect(),t.removeEventListener("pointermove",F),t.removeEventListener("pointerleave",I),t.removeEventListener("pointercancel",I),document.removeEventListener("visibilitychange",T),y.removeEventListener("change",T),i.signal?.removeEventListener("abort",L),o.destroy(),e.destroy())};if(i.signal?.addEventListener("abort",L,{once:!0}),i.signal?.aborted)throw L(),new DOMException("Cancelled","AbortError");return T(),{canvas:t,media:e,update(t){s=m(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,T()},async seek(t){p=Math.max(0,t),await e.seek(p),o.invalidate(),c=!0,E()},redraw(){o.invalidate(),c=!0,E()},get time(){return S?.currentTime??p},get paused(){return f||y.matches},get maxCells(){return o.maxCells},get capabilities(){return o.capabilities},destroy:L}}var U={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")},N=Object.keys(U);exports.BLEND_MODES=i,exports.DEFAULT_STUDIO_SETTINGS=a,exports.DITHER_ALGORITHMS=e,exports.STUDIO_CHARACTER_SETS={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:" ⠁⠃⠇⡇⣇⣧⣷⣿"}},exports.STUDIO_LOOKS=u,exports.STUDIO_PALETTES=s,exports.STUDIO_STYLES=t,exports.STUDIO_TEXT_FONTS=N,exports.createStudioRenderer=R,exports.createStudioText=async function(t,e="Standard",i="#ffffff"){if(!Object.prototype.hasOwnProperty.call(U,e))throw new Error("Unknown text font.");const{default:s}=await import("figlet/browser"),a=await U[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 d=c.getContext("2d");return d.fillStyle="#080808",d.fillRect(0,0,c.width,c.height),d.fillStyle=i,d.font=15*l+"px monospace",d.textBaseline="top",o.forEach((t,e)=>d.fillText(t,16,16+15*e*l)),{canvas:c,ascii:r}},exports.exportStudio=async function(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,d=i.time??0;if(!Number.isFinite(d)||d<0)throw new Error("Image time must be a finite non-negative number.");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 m=document.createElement("canvas"),f=R(m,l(e),{maxDimension:4096,maxCells:i.maxCells??12e3,pixelRatio:r/(i.referenceWidth??Math.min(r,960))});let u;try{if(C(a),i.onProgress?.(0),c){if(f.render(await t.frame(d,a),d,r,o),"unavailable"===m.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");C(a);const e=await new Promise((t,e)=>m.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:d}="function"==typeof s.GIFEncoder?s:s.default,u=l(),p=m.getContext("2d");for(let s=0;s<e;s++){C(a);const l=s/n;if(f.invalidate(),f.render(await t.frame(l,a),l,r,o),"unavailable"===m.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");const g=p.getImageData(0,0,r,o).data,M=c(g,256),x=d(g,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:p,WebMOutputFormat:g,BufferTarget:M,CanvasSource:x,canEncodeVideo:v}=await import("mediabunny"),w="mp4"===s?"avc":"vp9";if(!await v(w,{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 b=new l({format:"mp4"===s?new p({fastStart:"in-memory"}):new g,target:new M});m.width=r,m.height=o,u=()=>b.cancel();const y=new x(m,{codec:w,bitrate:Math.max(5e5,Math.round(r*o*n*.15))});b.addVideoTrack(y,{frameRate:n}),m.width=r,m.height=o,await b.start();for(let s=0;s<e;s++){C(a);const l=s/n;if(f.invalidate(),f.render(await t.frame(l,a),l,r,o),"unavailable"===m.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");await y.add(l,Math.min(1/n,h-l)),i.onProgress?.((s+1)/e*.98),s%4==0&&await new Promise(t=>setTimeout(t,0))}return y.close(),C(a),await b.finalize(),u=void 0,i.onProgress?.(1),new Blob([b.target.buffer],{type:"mp4"===s?"video/mp4":"video/webm"})}catch(t){throw await(u?.().catch(()=>{})),t}finally{f.destroy(),m.width=m.height=1}},exports.loadStudioMedia=L,exports.mountStudio=async function(t,e,i={}){const s=await L(e,i.signal);try{return D(t,s,i)}catch(t){throw s.destroy(),t}},exports.mountStudioMedia=D,exports.normalizeStudioSettings=l,exports.parseStudioSettings=function(t){if(t.length>1e5)throw new Error("Settings exceed 100 KB.");return l(JSON.parse(t))},exports.restyleStudio=function(t,e=Math.random){const i=u.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},exports.serializeStudioSettings=function(t){return JSON.stringify(l(t))},exports.studioCrop=c,exports.studioDimensions=d,exports.studioGrid=f,exports.studioLook=p,exports.studioSourceSize=T,exports.updateStudioSettings=m;//# sourceMappingURL=studio.cjs.map
|
package/dist/studio.d.cts
CHANGED
|
@@ -137,6 +137,17 @@ type StudioInput = {
|
|
|
137
137
|
[K in keyof StudioSettings]?: StudioSettings[K] extends readonly unknown[] ? StudioSettings[K] : StudioSettings[K] extends object ? Partial<StudioSettings[K]> : StudioSettings[K];
|
|
138
138
|
};
|
|
139
139
|
declare function updateStudioSettings(current: StudioSettings, patch: StudioInput): StudioSettings;
|
|
140
|
+
/** Effective grid and usable cell-size range at a bounded render resolution.
|
|
141
|
+
* pixelRatio preserves preview density when exporting at a larger resolution.
|
|
142
|
+
*/
|
|
143
|
+
declare function studioGrid(width: number, height: number, settings: Pick<StudioSettings, 'style' | 'cellSize' | 'dither'>, maxCells?: number, pixelRatio?: number): {
|
|
144
|
+
cell: number;
|
|
145
|
+
rowHeight: number;
|
|
146
|
+
columns: number;
|
|
147
|
+
rows: number;
|
|
148
|
+
minimum: number;
|
|
149
|
+
limited: boolean;
|
|
150
|
+
};
|
|
140
151
|
|
|
141
152
|
declare const STUDIO_LOOKS: {
|
|
142
153
|
id: string;
|
|
@@ -191,6 +202,8 @@ interface StudioExportOptions {
|
|
|
191
202
|
width: number;
|
|
192
203
|
height: number;
|
|
193
204
|
duration?: number;
|
|
205
|
+
/** Timeline position for a still image. Animations start at zero. */
|
|
206
|
+
time?: number;
|
|
194
207
|
fps?: number;
|
|
195
208
|
quality?: number;
|
|
196
209
|
signal?: AbortSignal;
|
|
@@ -319,4 +332,4 @@ declare const STUDIO_CHARACTER_SETS: {
|
|
|
319
332
|
};
|
|
320
333
|
};
|
|
321
334
|
|
|
322
|
-
export { BLEND_MODES, DEFAULT_STUDIO_SETTINGS, DITHER_ALGORITHMS, type DitherAlgorithm, type MountStudioOptions, STUDIO_CHARACTER_SETS, STUDIO_LOOKS, STUDIO_PALETTES, STUDIO_STYLES, STUDIO_TEXT_FONTS, type StudioExportFormat, type StudioExportOptions, type StudioExportSource, type StudioInput, type StudioLight, type StudioMask, type StudioMedia, type StudioSettings, type StudioSource, type StudioStyle, createStudioRenderer, createStudioText, exportStudio, loadStudioMedia, mountStudio, mountStudioMedia, normalizeStudioSettings, parseStudioSettings, restyleStudio, serializeStudioSettings, studioCrop, studioDimensions, studioLook, studioSourceSize, updateStudioSettings };
|
|
335
|
+
export { BLEND_MODES, DEFAULT_STUDIO_SETTINGS, DITHER_ALGORITHMS, type DitherAlgorithm, type MountStudioOptions, STUDIO_CHARACTER_SETS, STUDIO_LOOKS, STUDIO_PALETTES, STUDIO_STYLES, STUDIO_TEXT_FONTS, type StudioExportFormat, type StudioExportOptions, type StudioExportSource, type StudioInput, type StudioLight, type StudioMask, type StudioMedia, type StudioSettings, type StudioSource, type StudioStyle, createStudioRenderer, createStudioText, exportStudio, loadStudioMedia, mountStudio, mountStudioMedia, normalizeStudioSettings, parseStudioSettings, restyleStudio, serializeStudioSettings, studioCrop, studioDimensions, studioGrid, studioLook, studioSourceSize, updateStudioSettings };
|
package/dist/studio.d.ts
CHANGED
|
@@ -137,6 +137,17 @@ type StudioInput = {
|
|
|
137
137
|
[K in keyof StudioSettings]?: StudioSettings[K] extends readonly unknown[] ? StudioSettings[K] : StudioSettings[K] extends object ? Partial<StudioSettings[K]> : StudioSettings[K];
|
|
138
138
|
};
|
|
139
139
|
declare function updateStudioSettings(current: StudioSettings, patch: StudioInput): StudioSettings;
|
|
140
|
+
/** Effective grid and usable cell-size range at a bounded render resolution.
|
|
141
|
+
* pixelRatio preserves preview density when exporting at a larger resolution.
|
|
142
|
+
*/
|
|
143
|
+
declare function studioGrid(width: number, height: number, settings: Pick<StudioSettings, 'style' | 'cellSize' | 'dither'>, maxCells?: number, pixelRatio?: number): {
|
|
144
|
+
cell: number;
|
|
145
|
+
rowHeight: number;
|
|
146
|
+
columns: number;
|
|
147
|
+
rows: number;
|
|
148
|
+
minimum: number;
|
|
149
|
+
limited: boolean;
|
|
150
|
+
};
|
|
140
151
|
|
|
141
152
|
declare const STUDIO_LOOKS: {
|
|
142
153
|
id: string;
|
|
@@ -191,6 +202,8 @@ interface StudioExportOptions {
|
|
|
191
202
|
width: number;
|
|
192
203
|
height: number;
|
|
193
204
|
duration?: number;
|
|
205
|
+
/** Timeline position for a still image. Animations start at zero. */
|
|
206
|
+
time?: number;
|
|
194
207
|
fps?: number;
|
|
195
208
|
quality?: number;
|
|
196
209
|
signal?: AbortSignal;
|
|
@@ -319,4 +332,4 @@ declare const STUDIO_CHARACTER_SETS: {
|
|
|
319
332
|
};
|
|
320
333
|
};
|
|
321
334
|
|
|
322
|
-
export { BLEND_MODES, DEFAULT_STUDIO_SETTINGS, DITHER_ALGORITHMS, type DitherAlgorithm, type MountStudioOptions, STUDIO_CHARACTER_SETS, STUDIO_LOOKS, STUDIO_PALETTES, STUDIO_STYLES, STUDIO_TEXT_FONTS, type StudioExportFormat, type StudioExportOptions, type StudioExportSource, type StudioInput, type StudioLight, type StudioMask, type StudioMedia, type StudioSettings, type StudioSource, type StudioStyle, createStudioRenderer, createStudioText, exportStudio, loadStudioMedia, mountStudio, mountStudioMedia, normalizeStudioSettings, parseStudioSettings, restyleStudio, serializeStudioSettings, studioCrop, studioDimensions, studioLook, studioSourceSize, updateStudioSettings };
|
|
335
|
+
export { BLEND_MODES, DEFAULT_STUDIO_SETTINGS, DITHER_ALGORITHMS, type DitherAlgorithm, type MountStudioOptions, STUDIO_CHARACTER_SETS, STUDIO_LOOKS, STUDIO_PALETTES, STUDIO_STYLES, STUDIO_TEXT_FONTS, type StudioExportFormat, type StudioExportOptions, type StudioExportSource, type StudioInput, type StudioLight, type StudioMask, type StudioMedia, type StudioSettings, type StudioSource, type StudioStyle, createStudioRenderer, createStudioText, exportStudio, loadStudioMedia, mountStudio, mountStudioMedia, normalizeStudioSettings, parseStudioSettings, restyleStudio, serializeStudioSettings, studioCrop, studioDimensions, studioGrid, studioLook, studioSourceSize, updateStudioSettings };
|
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 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
|
+
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),m=a;if(void 0!==c.version&&1!==c.version)throw new Error("Unsupported studio settings version. Update asciify-engine.");const f=r(c.crop),d=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={...m.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"],m.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,m.style),cellSize:o(c.cellSize,7,3,60),charset:"string"==typeof c.charset&&c.charset.length?Array.from(c.charset).slice(0,128).join(""):m.charset,colorMode:h(c.colorMode,["accent","source","gray"],m.colorMode),ink:n(c.ink,m.ink),crop:{x:o(f.x,.5,0,1),y:o(f.y,.5,0,1),zoom:o(f.zoom,1,1,5),rotation:90*Math.round(o(f.rotation,0,-360,360)/90)},backdrop:{mode:h(d.mode,["solid","transparent","source","blurred","gradient"],m.backdrop.mode),color:n(d.color,m.backdrop.color),color2:n(d.color2,m.backdrop.color2),blur:o(d.blur,12,0,32),opacity:o(d.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,m.color.tint),amount:o(u.amount,0,0,1),blend:h(u.blend,i,m.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")):[...m.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 m(t){if(t.length>1e5)throw new Error("Settings exceed 100 KB.");return l(JSON.parse(t))}function f(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 d(t,e,i){if(Math.abs(i.crop.rotation/90)%2==1&&([t,e]=[e,t]),"original"===i.aspectRatio)return[t,e];const[s,a]=i.aspectRatio.split(":").map(Number);return t/e>s/a?[Math.round(e*s/a),e]:[t,Math.round(t*a/s)]}function 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)}function g(t,e,i,s=12e3,a=1){const r=Math.max(2,Number.isFinite(t)?t:960),o=Math.max(2,Number.isFinite(e)?e:540),n=Math.max(1,Math.floor(Number.isFinite(s)?s:12e3)),h=Math.max(.01,Number.isFinite(a)?a:1),l=["dither","pixel","mosaic","lego","voxel","disco","dots"].includes(i.style)?1:1.65;let c=Math.max(1,Math.ceil(Math.sqrt(r*o/(n*l))/h));for(;Math.ceil(r/(c*h))*Math.ceil(o/(c*h*l))>n;)c++;const m="dither"===i.style?i.dither.scale:i.cellSize,f=Math.max(c,m)*h;return{cell:f,rowHeight:f*l,columns:Math.ceil(r/f),rows:Math.ceil(o/(f*l)),minimum:c,limited:m<c}}var p=[["ascii","Signature ASCII","Brand ink and clean characters.",{}],["print","Newsprint","Fine diffusion on warm paper.",{style:"dither",dither:{algorithm:"floyd-steinberg",palette:"newsprint"}}],["handheld","Pocket camera","Four-tone ordered dither.",{style:"dither",dither:{algorithm:"bayer4",palette:"gameboy",scale:3}}],["riso","Two inks","Limited-color print texture.",{style:"dither",dither:{algorithm:"atkinson",palette:"risograph",scale:2}}],["night","Night signal","Gray characters and optical fringe.",{ink:"#888888",effects:{prism:.7,scanlines:.2,vignette:.3}}],["terminal","Phosphor","Green glyphs with a soft glow.",{ink:"#83efad",effects:{bloom:.4,scanlines:.35,crt:.2}}],["mosaic","Mosaic study","Separated color tiles.",{style:"mosaic",cellSize:14,colorMode:"source"}],["bricks","Brickwork","Colorful studded cells.",{style:"lego",cellSize:18,colorMode:"source"}],["voxel","Little volumes","Three-face isometric tiles.",{style:"voxel",cellSize:22,colorMode:"source"}],["disco","Mirror room","Faceted tiles and warm light.",{style:"disco",cellSize:18,colorMode:"source",lights:[{x:.35,y:.25,radius:.25,intensity:.45,color:"#fff2d4"}]}],["wallpaper","Wallpaper","Living ASCII over a softened source.",{backdrop:{mode:"blurred",blur:18,opacity:.55},ink:"#f2e9c9",motion:{type:"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 M(t){const e=p.find(e=>e.id===t);if(!e)throw new Error("Unknown studio look.");return l(e.settings)}function x(t,e=Math.random){const i=p.filter(e=>e.settings.style!==t.style||e.settings.ink!==t.ink),s=M(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 v=(t,e)=>{const i=43758.5453*Math.sin(127.1*t+311.7*e);return i-Math.floor(i)};function w(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 b={"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]]},y=t=>[parseInt(t.slice(1,3),16),parseInt(t.slice(3,5),16),parseInt(t.slice(5,7),16)];function k(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 E=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]=k(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 m=.035+.11*Math.max(.1,Math.min(1,i)),f=Math.min(128,Math.max(1,Math.ceil(c/(.45*m)))),d=c?h/c:1,u=c?l/c:0,g=Math.min(1,c/(m*f)*2.2);for(let i=0;i<f;i++){const h=(i+.5)/f,l=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*m/o)*(a-1))),M=Math.min(a-1,Math.ceil((l+2.5*m/o)*(a-1))),x=Math.max(0,Math.floor((c-2.5*m/n)*(r-1))),v=Math.min(r-1,Math.ceil((c+2.5*m/n)*(r-1)));for(let t=x;t<=v;t++)for(let e=p;e<=M;e++){const i=(e/(a-1)-l)*o/m,s=(t/(r-1)-c)*n/m,h=Math.exp(1.5*-(i*i+s*s)),f=t*a+e;if("dissolve"===this.mode)this.ink[f]=Math.max(this.ink[f],h);else{const t=(-i*u+s*d)*h*2.8,e="silk"===this.mode?d*t:-s*h*2.5,a="silk"===this.mode?u*t:i*h*2.5;this.targetX[f]=Math.max(-1,Math.min(1,this.targetX[f]+e*g)),this.targetY[f]=Math.max(-1,Math.min(1,this.targetY[f]+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,m=t=>(t[l]*(1-n)+t[l+1]*n)*(1-h)+(t[c]*(1-n)+t[c+1]*n)*h;i[0]=m(this.offsetX)*(this.edgeSafe?k(t,e,this.width/this.height):1)*.08,i[1]=m(this.offsetY)*(this.edgeSafe?k(t,e,this.width/this.height):1)*.08,i[2]="dissolve"===this.mode?6*-m(this.ink):0}},S=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))}},A=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),m=1-Math.exp(-c/2.2),f=h*(.022+.075*i)*(.65+.95*m),d=Math.min(128,Math.max(1,Math.ceil(n/(.4*f)))),u=n/f*(.32+.22*m)/d,g=r/n,p=o/n,M=-p,x=g,v=n*(2+18*m)/d;for(let i=0;i<d;i++){const s=(i+.5)/d,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*f)),h=Math.min(this.width-2,Math.ceil(r+3*f)),l=Math.max(1,Math.floor(o-3*f)),c=Math.min(this.height-2,Math.ceil(o+3*f));for(let t=l;t<=c;t++)for(let e=n;e<=h;e++){const i=((e-r)*g+(t-o)*p)/f,s=((e-r)*M+(t-o)*x)/f,a=Math.exp(-i*i*.65-s*s*1.7),n=t*this.width+e;this.ink[n]=1-(1-this.ink[n])*Math.exp(-a*u);const h=1-s*s*.55,l=i*s*.7;this.u[n]=Math.max(-80,Math.min(80,this.u[n]+(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,m=0|l,f=h-c,d=l-m,u=m*i+c,g=(1-f)*(1-d),p=f*(1-d),M=(1-f)*d,x=f*d;this.a[n]=(this.u[u]*g+this.u[u+1]*p+this.u[u+i]*M+this.u[u+i+1]*x)*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 F(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]=k(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 A(this.columns,this.rows),this.contour=new S(this.columns,this.rows),this.afterimage=new E(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,m=Math.max(1,Math.floor((r-h/this.xScale)*(this.columns-1))),f=Math.min(this.columns-2,Math.ceil((r+h/this.xScale)*(this.columns-1))),d=Math.max(1,Math.floor((o-h/this.yScale)*(this.rows-1))),u=Math.min(this.rows-2,Math.ceil((o+h/this.yScale)*(this.rows-1)));for(let t=d;t<=u;t++)for(let e=m;e<=f;e++){const i=(e/(this.columns-1)-r)*this.xScale,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,m=(this.velocity[o]+(h*s*s-8*n)*e)*i*c;this.velocity[o]=m,this.next[o]=(n+m*e)*c,t=Math.max(t,Math.abs(this.next[o]),.1*Math.abs(m))}this.heights.set(this.next),this.energy=t,this.pending=!1}if(!this.active)return void this.clear();const 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 I(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}},P=(t,e,i)=>{t.width===e&&t.height===i||(t.width=e,t.height=i)},C={blocks:" ░▒▓█",braille:" ⠁⠃⠇⡇⣇⣧⣷⣿",lines:" -═╪╬",cross:" ·+xX#",diagonal:" /╱╳",diamond:" ·◇◈◆",mixed:" .:+/◇#@"};function L(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(),m=R(),d=R(),u=R(),p=R();let M,x=l(e),k=0,E="",S=new Uint8ClampedArray(0),A=0,L=0,X=0,D=null,N="",U=new T,B=0;const Y=[0,0,0],O=Math.max(64,Math.min(4096,Number.isFinite(i.maxDimension)?i.maxDimension:960)),_=Math.max(256,Math.min(16e4,Number.isFinite(i.maxCells)?i.maxCells:12e3));let z=_;const W=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[_,G]=I(e);if(!_||!G)return;const q=Math.min(1,O/Math.max(l,R)),$=Math.max(2,Math.round(l*q)),j=Math.max(2,Math.round(R*q));P(t,$,j),P(r.canvas,$,j),P(n.canvas,$,j),P(h.canvas,$,j),P(c.canvas,$,j),B!==$/j&&(B=$/j,U=new T(B)),U.configure(x.hover.effect,x.hover.strength,x.hover.radius,x.hover.edgeSafe),U.step(Math.max(0,Math.min(.05,i-X))),X=i;const V="currentTime"in e?e.getVideoPlaybackQuality?.().totalVideoFrames??e.currentTime:0,H=[k,$,j,V].join(":"),J="dither"===x.style,Q=g($,j,x,z,W),K=Q.cell,Z=Q.rowHeight,tt=Q.columns,et=Q.rows;if(E!==H||D!==e||A!==tt||L!==et){D=e,E=H,A=tt,L=et,r.ctx.clearRect(0,0,$,j),r.ctx.save();const t=f(_,G,$,j,x.crop);r.ctx.translate(t.x+t.width/2,t.y+t.height/2),r.ctx.rotate(x.crop.rotation*Math.PI/180),r.ctx.drawImage(e,-_*t.scale/2,-G*t.scale/2,_*t.scale,G*t.scale),r.ctx.restore(),P(o.canvas,A,L),o.ctx.clearRect(0,0,A,L),o.ctx.drawImage(r.canvas,0,0,A,L),S=o.ctx.getImageData(0,0,A,L).data;const i=x.color;for(let t=0;t<S.length;t+=4){const e=.299*S[t]+.587*S[t+1]+.114*S[t+2];for(let s=0;s<3;s++){const a=e+(S[t+s]-e)*i.saturation;S[t+s]=((a*(1-i.grayscale)+e*i.grayscale)/255-.5)*i.contrast*255+127.5+255*i.brightness}}}n.ctx.clearRect(0,0,$,j),n.ctx.globalAlpha=1,n.ctx.globalCompositeOperation="source-over";const it=i*x.motion.speed;if(J){const t=new Uint8ClampedArray(S),e=x.motion.type;if(U.active||"none"!==e)for(let i=0;i<L;i++)for(let s=0;s<A;s++){const a=s/A,r=i/L;let o=s,n=i,h=0,l=1,c=1;if(U.active&&(U.sample(a,r,Y),o-=Y[0]*A,n-=Y[1]*L,h=Y[2]/3),"wave"===e&&(n+=Math.sin(8*a+2*it+4*r)*L*.015),"ripple"===e){const t=a-.5,e=r-.5,i=.03*Math.sin(30*Math.hypot(t,e)-3*it);o+=t*i*A,n+=e*i*L}"breathe"===e&&(l=.92+.08*Math.sin(1.5*it+3*a)),"reveal"===e&&(c=Math.max(0,Math.min(1,4*(.7*Math.sin(.7*it)+.7-a)))),"glitch"===e&&v(i,Math.floor(6*it))>.93&&(o+=8*Math.sin(5*it)),"vapor"===e&&(n+=Math.sin(6*a+it)*L*.025),"fire"===e&&(n+=Math.sin(7*a+3*it+8*r)*L*.01,l=.8+.2*Math.sin(12*r-4*it)),"hologram"===e&&(c=.72+.28*Math.sin(.65*i+5*it)),"chrome"===e&&(l=.5+Math.abs(Math.sin(8*r+it)));const m=4*(i*A+s),f=4*(Math.max(0,Math.min(L-1,Math.round(n)))*A+Math.max(0,Math.min(A-1,Math.round(o))));for(let i=0;i<3;i++){const s=S[f+i]/255;let r=(["trail","contour"].includes(x.hover.effect)?F(s,h):"dissolve"===x.hover.effect?s*Math.max(0,1+h):s)*l;"rainbow"===e&&(r*=.65+.35*Math.sin(2*it+5*a+2.094*i)),"hologram"===e&&(r*=0===i?.4:1),"fire"===e&&(r*=0===i?1.3:1===i?.7:.3),t[m+i]=255*r}t[m+3]=S[f+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(y),c=b[o],m=c?new Float32Array(3*e*3):null,f="drift"===a.motion?Math.floor(r*a.speed*3):0,d="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]){m&&(m[u]=m[u+1]=m[u+2]=0);continue}let g=0;o.startsWith("bayer")?g=w(a+f&15,s+f&15,Number(o.slice(5))):"noise"===o?g=v(a,s)-.5:"lines"===o?g=(s+f)%4/3-.5:"halftone"===o&&(g=Math.hypot(a%6-2.5,s%6-2.5)/3.54-.5);const p=128*(g*n+d+(.5-h)),M=t[r]+p+(m?.[u]??0),x=t[r+1]+p+(m?.[u+1]??0),b=t[r+2]+p+(m?.[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+(x-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(x/51),E=51*Math.round(b/51);if(t[r]=y,t[r+1]=k,t[r+2]=E,m&&c){m[u]=m[u+1]=m[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);m[l]+=(M-y)*o*n,m[l+1]+=(x-k)*o*n,m[l+2]+=(b-E)*o*n}}}}(t,A,L,x.dither,i),o.ctx.putImageData(new ImageData(t,A,L),0,0),n.ctx.imageSmoothingEnabled=!1,n.ctx.drawImage(o.canvas,0,0,$,j)}else{const t=Array.from(C[x.style]??x.charset),e=n.ctx,i="ascii"===x.style||!!C[x.style],s=Math.max(3,Math.round(.92*Z)),a=Math.ceil(K+4),r=Math.ceil(Z+4),o=[t.join(""),s,a,r,x.ink,x.colorMode].join(":");i&&o!==N&&(N=o,P(d.canvas,a*t.length,r),d.ctx.clearRect(0,0,d.canvas.width,r),d.ctx.font=`${s}px monospace`,d.ctx.textBaseline="middle",d.ctx.textAlign="center",d.ctx.fillStyle="accent"===x.colorMode?x.ink:"#ffffff",t.forEach((t,e)=>d.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<L;s++)for(let o=0;o<A;o++){let n=o,h=s,l=0;U.active&&(U.sample(o/A,s/L,Y),n=Math.max(0,Math.min(A-1,o-Y[0]*A)),h=Math.max(0,Math.min(L-1,s-Y[1]*L)),l=Y[2]/3);const c=4*(Math.floor(h)*A+Math.floor(n));if(!S[c+3])continue;const m=S[c],f=S[c+1],u=S[c+2],g=(.299*m+.587*f+.114*u)/255;let p=g;["trail","contour"].includes(x.hover.effect)&&l?p=F(p,l):"dissolve"===x.hover.effect&&(p*=Math.max(0,1+l));const M=x.motion.type;let w=o*K,b=s*Z,y=1;if("breathe"===M&&(p*=.92+.08*Math.sin(1.5*it+.03*o)),"wave"===M&&(b+=Math.sin(.12*o+2*it+.08*s)*Z*.4),"ripple"===M){const t=o/A-.5,e=s/L-.5,i=Math.hypot(t,e),a=Math.sin(30*i-3*it)*K*.65;w+=t*a,b+=e*a}"fire"===M&&(b-=Math.sin(.16*o+3*it+.09*s)*Z*.35,p*=.85+.15*Math.sin(.3*s-4*it)),"hologram"===M&&(y=.72+.28*Math.sin(.65*s+5*it)),"reveal"===M&&(y=Math.max(0,Math.min(1,4*(.7*Math.sin(.7*it)+.7-o/A)))),"glitch"===M&&v(s,Math.floor(6*it))>.93&&(w+=Math.sin(5*it)*K*3),"vapor"===M&&(b+=Math.sin(.04*o+it)*Z),i||"accent"!==x.colorMode||(y*=p),e.globalAlpha=y;const k=255*(p-g);let E="source"===x.colorMode?`rgb(${m+k},${f+k},${u+k})`:"gray"===x.colorMode?`rgb(${Math.round(255*p)},${Math.round(255*p)},${Math.round(255*p)})`:x.ink;if("rainbow"===M&&(E=`hsl(${(o/A*180+40*it)%360} 70% 65%)`),"fire"===M&&(E=`hsl(${15+40*p} 90% ${30+45*p}%)`),"hologram"===M&&(E=`hsl(185 65% ${40+40*p}%)`),"chrome"===M&&(E=`hsl(210 12% ${25+70*Math.abs(Math.sin(.2*s+it))}%)`),e.fillStyle=E,i){const i=Math.max(0,Math.min(t.length-1,Math.floor(p*(t.length-1))));"accent"!==x.colorMode||["rainbow","fire","hologram","chrome"].includes(M)?e.fillText(t[i],w+K/2,b+Z/2):e.drawImage(d.canvas,i*a,0,a,r,w+(K-a)/2,b+(Z-r)/2,a,r)}else if("dots"===x.style)e.beginPath(),e.arc(w+K/2,b+Z/2,.48*K*Math.sqrt(p),0,2*Math.PI),e.fill();else if("voxel"===x.style){const t=w+K/2,i=b+Z/2;e.beginPath(),e.moveTo(t,b),e.lineTo(w+K,b+.25*Z),e.lineTo(t,i),e.lineTo(w,b+.25*Z),e.closePath(),e.fill(),e.globalAlpha=.72*y,e.beginPath(),e.moveTo(w,b+.25*Z),e.lineTo(t,i),e.lineTo(t,b+Z),e.lineTo(w,b+.75*Z),e.closePath(),e.fill(),e.globalAlpha=.42*y,e.beginPath(),e.moveTo(t,i),e.lineTo(w+K,b+.25*Z),e.lineTo(w+K,b+.75*Z),e.lineTo(t,b+Z),e.closePath(),e.fill()}else{const t="pixel"===x.style?0:Math.max(.5,.06*K);e.fillRect(w,b,K-t,Z-t),"lego"===x.style&&(e.fillStyle="rgba(255,255,255,.2)",e.beginPath(),e.arc(w+K/2,b+Z/2,.28*K,0,2*Math.PI),e.fill(),e.strokeStyle="rgba(0,0,0,.25)",e.stroke()),"disco"===x.style&&(e.fillStyle=`rgba(255,255,255,${.1+.25*v(o,s)})`,e.fillRect(w,b,K-t,.35*Z),e.fillStyle="rgba(0,0,0,.25)",e.fillRect(w,b+.65*Z,K-t,.35*Z-t))}}}n.ctx.globalAlpha=1,(x.color.amount||x.lights.length)&&(P(u.canvas,$,j),u.ctx.clearRect(0,0,$,j),u.ctx.drawImage(n.canvas,0,0)),x.color.amount&&(n.ctx.save(),n.ctx.globalCompositeOperation=x.color.blend,n.ctx.globalAlpha=x.color.amount,n.ctx.fillStyle=x.color.tint,n.ctx.fillRect(0,0,$,j),n.ctx.restore());for(const t of x.lights){const e=t.radius*Math.max($,j),i=n.ctx.createRadialGradient(t.x*$,t.y*j,0,t.x*$,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,$,j),n.ctx.restore()}if((x.color.amount||x.lights.length)&&(n.ctx.globalCompositeOperation="destination-in",n.ctx.drawImage(u.canvas,0,0),n.ctx.globalCompositeOperation="source-over"),x.mask.enabled&&x.mask.shapes.length){const t=c.ctx;t.clearRect(0,0,$,j),t.fillStyle="#fff",t.strokeStyle="#fff",t.lineCap="round",t.lineJoin="round";for(const e of x.mask.shapes){if(t.beginPath(),"ellipse"===e.kind)t.ellipse((e.x+e.width/2)*$,(e.y+e.height/2)*j,e.width*$/2,e.height*j/2,0,0,2*Math.PI);else{if("rectangle"!==e.kind){if(t.lineWidth=(e.size??.05)*$,1===e.points?.length){t.arc(e.points[0][0]*$,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*$,i*j):t.moveTo(e*$,i*j)),t.stroke();continue}t.rect(e.x*$,e.y*j,e.width*$,e.height*j)}t.fill()}n.ctx.globalCompositeOperation=x.mask.invert?"destination-out":"destination-in",n.ctx.drawImage(c.canvas,0,0),n.ctx.globalCompositeOperation="source-over"}const st=h.ctx;st.clearRect(0,0,$,j),st.globalAlpha=x.backdrop.opacity;const at=x.backdrop;if("solid"===at.mode&&(st.fillStyle=at.color,st.fillRect(0,0,$,j)),"gradient"===at.mode){const t=st.createLinearGradient(0,0,$,j);t.addColorStop(0,at.color),t.addColorStop(1,at.color2),st.fillStyle=t,st.fillRect(0,0,$,j)}if("source"===at.mode&&st.drawImage(r.canvas,0,0),"blurred"===at.mode){const t=Math.max(1,at.blur);P(m.canvas,Math.max(2,Math.round($/t)),Math.max(2,Math.round(j/t))),m.ctx.drawImage(r.canvas,0,0,m.canvas.width,m.canvas.height),st.imageSmoothingEnabled=!0,st.drawImage(m.canvas,0,0,$,j)}st.globalAlpha=1,x.effects.characterBloom>0&&(P(p.canvas,Math.max(2,Math.round($/3)),Math.max(2,Math.round(j/3))),p.ctx.clearRect(0,0,p.canvas.width,p.canvas.height),p.ctx.drawImage(n.canvas,0,0,p.canvas.width,p.canvas.height),st.save(),st.globalAlpha=.8*x.effects.characterBloom,st.globalCompositeOperation="screen",st.filter=`blur(${1+4*x.effects.characterBloom}px)`,st.drawImage(p.canvas,0,0,$,j),st.restore()),st.drawImage(n.canvas,0,0);const rt=Object.entries(x.effects).some(([t,e])=>!["angle","focus","blurType","characterBloom"].includes(t)&&"number"==typeof e&&e>0);a.clearRect(0,0,$,j),rt?(void 0===M&&(M=function(){const t=document.createElement("canvas"),e=t.getContext("webgl",{alpha:!0,premultipliedAlpha:!1,antialias:!1,preserveDrawingBuffer:!0});if(!e)return null;const i=[],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()}}}()),M?a.drawImage(M.render(h.canvas,x.effects,i,W),0,0):a.drawImage(h.canvas,0,0),t.dataset.studioFinish=M?"gpu":"unavailable"):(a.drawImage(h.canvas,0,0),t.dataset.studioFinish="none")},setBudget(t){z=Math.max(1500,Math.min(_,Math.round(t)))},get maxCells(){return z},configure(t){x=l(t),k++},pointer:(t,e,i)=>{U.configure(x.hover.effect,x.hover.strength,x.hover.radius,x.hover.edgeSafe),U.move(t,e,i)},leave(){U.leave()},get active(){return U.active},get settings(){return l(x)},get capabilities(){return{gpuFinish:null!==M}},invalidate(){E=""},destroy(){M?.destroy();for(const t of[r,o,n,h,c,m,d,u,p])t.canvas.width=t.canvas.height=1;D=null,S=new Uint8ClampedArray(0)}}}function X(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 D(t,e){if("string"==typeof t&&t.startsWith("blob:")){const i=await fetch(t,{signal:e}),s=await i.blob();return D(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 m=r(n,!0);if(m.length*h*l*4>128e6)throw new Error("GIF exceeds the 128 MB decoded budget. Use MP4 for long animations.");const f=document.createElement("canvas");f.width=h,f.height=l;const d=f.getContext("2d"),u=document.createElement("canvas"),g=u.getContext("2d"),p=m.reduce((t,e)=>t+Math.max(20,e.delay),0)/1e3;let M=-1,x=null;const v=t=>{const e=(t%p+p)%p*1e3;let i=0,s=0;for(;s<m.length-1&&(i+=Math.max(20,m[s].delay),!(e<i));s++);s<M&&(d.clearRect(0,0,h,l),M=-1,x=null);for(let t=M+1;t<=s;t++){const e=m[t-1];2===e?.disposalType&&d.clearRect(e.dims.left,e.dims.top,e.dims.width,e.dims.height),3===e?.disposalType&&x&&d.putImageData(x,0,0);const i=m[t];x=3===i.disposalType?d.getImageData(0,0,h,l):null,u.width=i.dims.width,u.height=i.dims.height,g.putImageData(new ImageData(new Uint8ClampedArray(i.patch),u.width,u.height),0,0),d.drawImage(u,i.dims.left,i.dims.top)}return M=s,f};return v(0),{source:f,width:h,height:l,duration:p,animated:!0,seek:async()=>{},frame:v,destroy(){f.width=u.width=1,m.length=0,x=null}}}const 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=X(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=X(o,"seeked",e);o.currentTime=i,await s},frame:()=>o,destroy:n}}catch(t){throw n(),t}}var N=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,m=i.time??0;if(!Number.isFinite(m)||m<0)throw new Error("Image time must be a finite non-negative number.");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=L(f,l(e),{maxDimension:4096,maxCells:i.maxCells??12e3,pixelRatio:r/(i.referenceWidth??Math.min(r,960))});let u;try{if(N(a),i.onProgress?.(0),c){if(d.render(await t.frame(m,a),m,r,o),"unavailable"===f.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");N(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++){N(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:g,WebMOutputFormat:p,BufferTarget:M,CanvasSource:x,canEncodeVideo:v}=await import("mediabunny"),w="mp4"===s?"avc":"vp9";if(!await v(w,{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 b=new l({format:"mp4"===s?new g({fastStart:"in-memory"}):new p,target:new M});f.width=r,f.height=o,u=()=>b.cancel();const y=new x(f,{codec:w,bitrate:Math.max(5e5,Math.round(r*o*n*.15))});b.addVideoTrack(y,{frameRate:n}),f.width=r,f.height=o,await b.start();for(let s=0;s<e;s++){N(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 y.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 y.close(),N(a),await b.finalize(),u=void 0,i.onProgress?.(1),new Blob([b.target.buffer],{type:"mp4"===s?"video/mp4":"video/webm"})}catch(t){throw await(u?.().catch(()=>{})),t}finally{d.destroy(),f.width=f.height=1}}async function B(t,e,i={}){const s=await D(e,i.signal);try{return Y(t,s,i)}catch(t){throw s.destroy(),t}}function Y(t,e,i={}){let s=l(i.settings),a=i.width??e.width,r=i.height??e.height;const o=L(t,s,i);let n=0,h=!1,c=!0,m=!1,f=!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||!f||document.hidden||(n=requestAnimationFrame(F))},S=()=>!m&&!y.matches&&f&&!document.hidden,A=()=>{k&&(k.loop=!0,S()?k.play().catch(()=>{m=!0,c=!0,E()}):k.pause()),p=0,c=!0,E()};function F(t){if(n=0,h||!f||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,F=!k||y<0||y!==x;if(c||o.active||u&&(F||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]=d(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){m=!0,i.onError?.(t instanceof Error?t:new Error(String(t)))}c=!1,M=t,x=y}l&&(u||o.active)&&E()}const T=e=>{if(!S())return;const i=t.getBoundingClientRect();o.pointer((e.clientX-i.left)/i.width,(e.clientY-i.top)/i.height,e.timeStamp),E()},I=()=>{o.leave(),E()},R=new IntersectionObserver(([t])=>{f=t.isIntersecting,A()});R.observe(t),t.addEventListener("pointermove",T),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",T),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){m=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 m||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")},_=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 m=c.getContext("2d");return m.fillStyle="#080808",m.fillRect(0,0,c.width,c.height),m.fillStyle=i,m.font=15*l+"px monospace",m.textBaseline="top",o.forEach((t,e)=>m.fillText(t,16,16+15*e*l)),{canvas:c,ascii:r}}var W={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,W as STUDIO_CHARACTER_SETS,p as STUDIO_LOOKS,s as STUDIO_PALETTES,t as STUDIO_STYLES,_ as STUDIO_TEXT_FONTS,L as createStudioRenderer,z as createStudioText,U as exportStudio,D as loadStudioMedia,B as mountStudio,Y as mountStudioMedia,l as normalizeStudioSettings,m as parseStudioSettings,x as restyleStudio,c as serializeStudioSettings,f as studioCrop,d as studioDimensions,g as studioGrid,M as studioLook,I as studioSourceSize,u as updateStudioSettings};//# sourceMappingURL=studio.js.map
|
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: "2.0.
|
|
5
|
+
tested-engine: "2.0.1"
|
|
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 **2.0.
|
|
11
|
+
Use the published `asciify-engine` npm package for browser canvas rendering. Tested against **2.0.1**. 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
|
|
@@ -104,3 +104,9 @@ player.update(settings);
|
|
|
104
104
|
```
|
|
105
105
|
|
|
106
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.
|
|
107
|
+
|
|
108
|
+
## Size controls and still frames (2.0.1)
|
|
109
|
+
|
|
110
|
+
Use `studioGrid(width, height, settings, maxCells, pixelRatio)` to inspect `minimum`, `cell`, `columns`, `rows`, and `limited` at the actual preview resolution. ASCII/tile renderers use `cellSize`; Dither uses `dither.scale`. Respect the returned minimum in a size picker instead of offering a range that the performance budget silently clamps. Use the same budget and reference width for export to retain density.
|
|
111
|
+
|
|
112
|
+
For PNG/JPEG, pass `time: player.time` to `exportStudio` to save the selected frame. Default time is zero; animation exports start at zero. Snapshot the time/settings/preview size before asynchronous loading. The editor's Export tab separates Image and Animation, shows validated pixel sizes and keeps website code in an expandable section.
|
|
@@ -33,3 +33,5 @@ After updating, read the installed SKILL.md and its linked references, confirm i
|
|
|
33
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
34
|
|
|
35
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`.
|
|
36
|
+
|
|
37
|
+
2.0.1 fixes Dither size controls and publishes `studioGrid` for budget-aware size pickers. Still-image exports accept `time` for the selected frame. Existing calls default to frame zero. No preset names change in this patch.
|