asciify-engine 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -0
- package/THIRD_PARTY.md +14 -0
- package/dist/studio.cjs +1 -0
- package/dist/studio.d.cts +286 -0
- package/dist/studio.d.ts +286 -0
- package/dist/studio.js +1 -0
- package/examples/studio-composition.ts +65 -0
- package/licenses/Mediabunny-MPL-2.0.txt +373 -0
- package/package.json +21 -4
- package/skills/asciify-engine/SKILL.md +8 -4
- package/skills/asciify-engine/references/studio-workspace.md +92 -0
- package/skills/asciify-engine/references/upgrading.md +2 -0
package/README.md
CHANGED
|
@@ -490,3 +490,23 @@ MIT © [asciify.org](https://asciify.org)
|
|
|
490
490
|
## Unreleased hero finish
|
|
491
491
|
|
|
492
492
|
Version 1.3.0 adds text-shaped charcoal cutouts (`textMask`), peripheral scanline/fringe control (`edgeEffect`), fixed accent ink, and velocity-driven Trail source flow. These additions ship in **npm 1.3.0**. Upgrade older applications before using them. See the [complete API, layering example, lifecycle, and fallback limits](skills/asciify-engine/references/hero-finish.md).
|
|
493
|
+
|
|
494
|
+
## Optional Studio tools
|
|
495
|
+
|
|
496
|
+
The `asciify-engine/studio` entry adds a reusable composition pipeline: alternate render styles, palette dithering, crop and masks, source/blurred/gradient backdrops, combined optical effects, saved looks, text fonts, and PNG/JPG/GIF/MP4/WebM export. Existing ASCII defaults and `/core` and `/hover` imports stay unchanged. Fonts and video encoders load on demand.
|
|
497
|
+
|
|
498
|
+
```ts
|
|
499
|
+
import { mountStudio } from 'asciify-engine/studio';
|
|
500
|
+
|
|
501
|
+
const studio = await mountStudio(canvas, '/your-video.mp4', {
|
|
502
|
+
settings: {
|
|
503
|
+
style: 'ascii',
|
|
504
|
+
backdrop: { mode: 'blurred', opacity: 0.4 },
|
|
505
|
+
},
|
|
506
|
+
});
|
|
507
|
+
studio.update({ hover: { effect: 'water', radius: 0.35 } });
|
|
508
|
+
// On unmount:
|
|
509
|
+
studio.destroy();
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
See the [Studio API guide](skills/asciify-engine/references/studio-workspace.md) for complete settings, import/export, media ownership, browser requirements, and performance budgets.
|
package/THIRD_PARTY.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Third-party components
|
|
2
|
+
|
|
3
|
+
Asciify's own code is MIT licensed. Dependencies keep their own licenses.
|
|
4
|
+
|
|
5
|
+
| Component | Version used for this release | License | Source |
|
|
6
|
+
| --- | --- | --- | --- |
|
|
7
|
+
| gifuct-js | 2.1.2 | MIT | https://github.com/matt-way/gifuct-js |
|
|
8
|
+
| gifenc | 1.0.3 | MIT | https://github.com/mattdesl/gifenc |
|
|
9
|
+
| FIGlet.js | 1.11.4 | MIT | https://github.com/patorjk/figlet.js |
|
|
10
|
+
| Mediabunny | 1.56.0 | MPL-2.0 | https://github.com/Vanilagy/mediabunny/tree/533c857a313b15f98af24ad916eeda27204c38ce |
|
|
11
|
+
|
|
12
|
+
Mediabunny is loaded on demand for Studio video encoding. Its source is unmodified; the corresponding source release is available at https://registry.npmjs.org/mediabunny/-/mediabunny-1.56.0.tgz. The MPL-2.0 text is included in `licenses/Mediabunny-MPL-2.0.txt`. Encoding uses browser-provided WebCodecs implementations.
|
|
13
|
+
|
|
14
|
+
Font data loads individually from FIGlet.js and retains its embedded font authorship notices. The package includes only code for selecting fonts; it does not relicense the font authors' work.
|
package/dist/studio.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var t=["ascii","blocks","braille","dots","lines","cross","diagonal","diamond","mixed","pixel","mosaic","lego","voxel","disco","dither"],e=["none","bayer2","bayer4","bayer8","bayer16","floyd-steinberg","atkinson","stucki","sierra","sierra-lite","burkes","jarvis","halftone","lines","noise"],i=["source-over","multiply","screen","overlay","soft-light","hard-light","color-dodge","color-burn","hue","saturation","color","luminosity"],s={original:[],mono:["#080808","#f2f2e8"],asciify:["#080808","#625b38","#a19558","#e8b900"],gameboy:["#0f380f","#306230","#8bac0f","#9bbc0f"],cga:["#000000","#55ffff","#ff55ff","#ffffff"],pico8:["#000000","#1d2b53","#7e2553","#008751","#ab5236","#5f574f","#c2c3c7","#fff1e8","#ff004d","#ffa300","#ffec27","#00e436","#29adff","#83769c","#ff77a8","#ffccaa"],c64:["#000000","#ffffff","#880000","#aaffee","#cc44cc","#00cc55","#0000aa","#eeee77","#dd8855","#664400","#ff7777","#333333","#777777","#aaff66","#0088ff","#bbbbbb"],amber:["#100b00","#5f3b00","#c98014","#ffd17c"],ice:["#081b29","#25586e","#69a6b3","#d9ece7"],risograph:["#f4ebd0","#f2594b","#2853a5","#29232e"],sepia:["#201b17","#6b5039","#b49868","#f6e6c5"],nord:["#2e3440","#4c566a","#88c0d0","#eceff4"],dusk:["#211b35","#654271","#c3788c","#f5c9a3"],forest:["#101f1b","#355747","#87a16f","#e4e3ba"],ocean:["#071b33","#17577f","#3fa7a4","#d9efde"],newsprint:["#191919","#666666","#aaaaaa","#eee9df"],custom:["#080808","#e8b900"]},a={version:1,aspectRatio:"original",style:"ascii",cellSize:7,charset:" .:-=+*#%@",colorMode:"accent",ink:"#e8b900",crop:{x:.5,y:.5,zoom:1,rotation:0},backdrop:{mode:"solid",color:"#080808",color2:"#393323",blur:12,opacity:1},color:{brightness:0,contrast:1,saturation:1,grayscale:0,tint:"#e8b900",amount:0,blend:"source-over"},dither:{algorithm:"none",palette:"mono",colors:["#080808","#e8b900"],amount:1,scale:2,threshold:.5,motion:"none",speed:1},mask:{enabled:!1,invert:!1,shapes:[]},lights:[],effects:{bloom:0,characterBloom:0,grain:0,dust:0,scanlines:0,crt:0,prism:0,vignette:0,glitch:0,pixelate:0,blur:0,blurType:"gaussian",angle:0,focus:.5,halftone:0},motion:{type:"none",speed:1},hover:{effect:"trail",strength:.55,radius:.2,edgeSafe:!1}},o=t=>t&&"object"==typeof t&&!Array.isArray(t)?t:{},r=(t,e,i,s)=>"number"==typeof t&&Number.isFinite(t)?Math.min(s,Math.max(i,t)):e,n=(t,e)=>"string"==typeof t&&/^#[\da-f]{6}$/i.test(t)?t:e,h=(t,e,i)=>e.includes(t)?t:i;function l(l={}){const c=o(l),d=a;if(void 0!==c.version&&1!==c.version)throw new Error("Unsupported studio settings version. Update asciify-engine.");const f=o(c.crop),m=o(c.backdrop),u=o(c.color),p=o(c.dither),g=o(c.mask),M=o(c.effects),x=o(c.motion),v=o(c.hover),w={...d.effects};for(const t of["bloom","characterBloom","grain","dust","scanlines","crt","prism","vignette","glitch","pixelate","halftone"])w[t]=r(M[t],0,0,1);w.blur=r(M.blur,0,0,24),w.blurType=h(M.blurType,["gaussian","directional","radial","progressive"],d.effects.blurType),w.angle=r(M.angle,0,-180,180),w.focus=r(M.focus,.5,0,1);let b=2048;return{version:1,aspectRatio:h(c.aspectRatio,["original","16:9","9:16","1:1","4:3","3:4","21:9"],"original"),style:h(c.style,t,d.style),cellSize:r(c.cellSize,7,3,60),charset:"string"==typeof c.charset&&c.charset.length?Array.from(c.charset).slice(0,128).join(""):d.charset,colorMode:h(c.colorMode,["accent","source","gray"],d.colorMode),ink:n(c.ink,d.ink),crop:{x:r(f.x,.5,0,1),y:r(f.y,.5,0,1),zoom:r(f.zoom,1,1,5),rotation:90*Math.round(r(f.rotation,0,-360,360)/90)},backdrop:{mode:h(m.mode,["solid","transparent","source","blurred","gradient"],d.backdrop.mode),color:n(m.color,d.backdrop.color),color2:n(m.color2,d.backdrop.color2),blur:r(m.blur,12,0,32),opacity:r(m.opacity,1,0,1)},color:{brightness:r(u.brightness,0,-1,1),contrast:r(u.contrast,1,0,3),saturation:r(u.saturation,1,0,3),grayscale:r(u.grayscale,0,0,1),tint:n(u.tint,d.color.tint),amount:r(u.amount,0,0,1),blend:h(u.blend,i,d.color.blend)},dither:{algorithm:h(p.algorithm,e,"none"),palette:"string"==typeof p.palette&&Object.prototype.hasOwnProperty.call(s,p.palette)?p.palette:"mono",colors:Array.isArray(p.colors)&&p.colors.length>=2?p.colors.slice(0,32).map(t=>n(t,"#000000")):[...d.dither.colors],amount:r(p.amount,1,0,2),scale:Math.round(r(p.scale,2,1,12)),threshold:r(p.threshold,.5,0,1),motion:h(p.motion,["none","drift","shimmer"],"none"),speed:r(p.speed,1,.1,3)},mask:{enabled:!0===g.enabled,invert:!0===g.invert,shapes:Array.isArray(g.shapes)?g.shapes.slice(0,64).map(t=>{const e=o(t),i=h(e.kind,["rectangle","ellipse","brush"],"rectangle"),s="brush"===i&&Array.isArray(e.points)?e.points.slice(0,b).map(t=>Array.isArray(t)?[Math.round(1e4*r(t[0],0,0,1))/1e4,Math.round(1e4*r(t[1],0,0,1))/1e4]:[0,0]):[];return b-=s.length,{kind:i,x:r(e.x,0,0,1),y:r(e.y,0,0,1),width:r(e.width,.5,0,1),height:r(e.height,.5,0,1),size:r(e.size,.05,.005,.5),points:s}}):[]},lights:Array.isArray(c.lights)?c.lights.slice(0,4).map(t=>{const e=o(t);return{x:r(e.x,.5,0,1),y:r(e.y,.5,0,1),radius:r(e.radius,.3,.02,1),intensity:r(e.intensity,.5,0,1),color:n(e.color,"#ffffff")}}):[],effects:w,motion:{type:h(x.type,["none","breathe","wave","reveal","glitch","rainbow","hologram","fire","chrome","ripple","vapor"],"none"),speed:r(x.speed,1,.1,3)},hover:{effect:h(v.effect,["none","trail","water","contour","dissolve","silk","vortex"],"trail"),strength:r(v.strength,.55,0,1),radius:r(v.radius,.2,.1,1),edgeSafe:!0===v.edgeSafe}}}function c(t,e,i,s,a){const o=Math.abs(a.rotation/90)%2==1,r=o?e:t,n=o?t:e,h=Math.max(i/r,s/n)*a.zoom;return{width:r*h,height:n*h,x:(i-r*h)*a.x,y:(s-n*h)*a.y,scale:h,rotated:o}}function d(t,e,i){if(Math.abs(i.crop.rotation/90)%2==1&&([t,e]=[e,t]),"original"===i.aspectRatio)return[t,e];const[s,a]=i.aspectRatio.split(":").map(Number);return t/e>s/a?[Math.round(e*s/a),e]:[t,Math.round(t*a/s)]}function f(t,e){const i={...t,...e};for(const s of["crop","backdrop","color","dither","mask","effects","motion","hover"])e[s]&&Object.assign(i,{[s]:{...t[s],...e[s]}});return l(i)}var m=[["ascii","Signature ASCII","Brand ink and clean characters.",{}],["print","Newsprint","Fine diffusion on warm paper.",{style:"dither",dither:{algorithm:"floyd-steinberg",palette:"newsprint"}}],["handheld","Pocket camera","Four-tone ordered dither.",{style:"dither",dither:{algorithm:"bayer4",palette:"gameboy",scale:3}}],["riso","Two inks","Limited-color print texture.",{style:"dither",dither:{algorithm:"atkinson",palette:"risograph",scale:2}}],["night","Night signal","Gray characters and optical fringe.",{ink:"#888888",effects:{prism:.7,scanlines:.2,vignette:.3}}],["terminal","Phosphor","Green glyphs with a soft glow.",{ink:"#83efad",effects:{bloom:.4,scanlines:.35,crt:.2}}],["mosaic","Mosaic study","Separated color tiles.",{style:"mosaic",cellSize:14,colorMode:"source"}],["bricks","Brickwork","Colorful studded cells.",{style:"lego",cellSize:18,colorMode:"source"}],["voxel","Little volumes","Three-face isometric tiles.",{style:"voxel",cellSize:22,colorMode:"source"}],["disco","Mirror room","Faceted tiles and warm light.",{style:"disco",cellSize:18,colorMode:"source",lights:[{x:.35,y:.25,radius:.25,intensity:.45,color:"#fff2d4"}]}],["wallpaper","Wallpaper","Living ASCII over a softened source.",{backdrop:{mode:"blurred",blur:18,opacity:.55},ink:"#f2e9c9",motion:{type:"breathe",speed:.5}}],["blueprint","Blueprint","Linework in a cool monochrome.",{style:"lines",ink:"#9bccdf",backdrop:{mode:"solid",color:"#0a1e30"}}]].map(([t,e,i,s])=>({id:t,name:e,description:i,settings:l(s)}));function u(t){const e=m.find(e=>e.id===t);if(!e)throw new Error("Unknown studio look.");return l(e.settings)}var p=(t,e)=>{const i=43758.5453*Math.sin(127.1*t+311.7*e);return i-Math.floor(i)};function g(t,e,i){let s=0;for(let a=1;a<i;a*=2){const i=Math.floor(t/a)%2;s=4*s+[[0,2],[3,1]][Math.floor(e/a)%2][i]}return(s+.5)/(i*i)-.5}var M={"floyd-steinberg":[[1,0,7/16],[-1,1,3/16],[0,1,5/16],[1,1,1/16]],atkinson:[[1,0,.125],[2,0,.125],[-1,1,.125],[0,1,.125],[1,1,.125],[0,2,.125]],stucki:[[1,0,8/42],[2,0,4/42],[-2,1,2/42],[-1,1,4/42],[0,1,8/42],[1,1,4/42],[2,1,2/42],[-2,2,1/42],[-1,2,2/42],[0,2,4/42],[1,2,2/42],[2,2,1/42]],sierra:[[1,0,5/32],[2,0,3/32],[-2,1,2/32],[-1,1,4/32],[0,1,5/32],[1,1,4/32],[2,1,2/32],[-1,2,2/32],[0,2,3/32],[1,2,2/32]],"sierra-lite":[[1,0,.5],[-1,1,.25],[0,1,.25]],burkes:[[1,0,.25],[2,0,4/32],[-2,1,2/32],[-1,1,4/32],[0,1,.25],[1,1,4/32],[2,1,2/32]],jarvis:[[1,0,7/48],[2,0,5/48],[-2,1,3/48],[-1,1,5/48],[0,1,7/48],[1,1,5/48],[2,1,3/48],[-2,2,1/48],[-1,2,3/48],[0,2,5/48],[1,2,3/48],[2,2,1/48]]},x=t=>[parseInt(t.slice(1,3),16),parseInt(t.slice(3,5),16),parseInt(t.slice(5,7),16)];function v(t,e,i){const s=Math.min(t*Math.max(1,i),(1-t)*Math.max(1,i),e*Math.max(1,1/i),(1-e)*Math.max(1,1/i)),a=Math.max(0,Math.min(1,(s-.035)/.105));return a*a*a*(a*(6*a-15)+10)}var w=class{constructor(t,e){this.edgeSafe=!1,this.previous=null,this.peak=0,this.mode="dissolve",this.width=t,this.height=e;const i=t*e;this.pixels=new Uint8Array(4*i),this.ink=new Float32Array(i),this.targetX=new Float32Array(i),this.targetY=new Float32Array(i),this.offsetX=new Float32Array(i),this.offsetY=new Float32Array(i),this.edge=new Float32Array(i);for(let i=0;i<e;i++)for(let s=0;s<t;s++)this.edge[i*t+s]=v(s/(t-1),i/(e-1),t/e);this.clear()}get active(){return this.peak>2e-4}setMode(t){t!==this.mode&&(this.mode=t,this.clear())}clear(){for(const t of[this.ink,this.targetX,this.targetY,this.offsetX,this.offsetY,this.pixels])t.fill(0);if(this.previous=null,this.peak=0,"dissolve"!==this.mode)for(let t=0;t<this.pixels.length;t+=4)this.pixels[t]=this.pixels[t+2]=128}leave(){this.previous=null}move(t,e,i){if(!Number.isFinite(t+e+i))return;t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e));const s=this.previous;this.previous={x:t,y:e};const a=this.width,o=this.height,r=Math.max(1,a/o),n=Math.max(1,o/a),h=s?(t-s.x)*r:0,l=s?(e-s.y)*n:0,c=Math.hypot(h,l);if(!s&&"dissolve"!==this.mode)return;if(s&&c<1e-4)return;const d=.035+.11*Math.max(.1,Math.min(1,i)),f=Math.min(128,Math.max(1,Math.ceil(c/(.45*d)))),m=c?h/c:1,u=c?l/c:0,p=Math.min(1,c/(d*f)*2.2);for(let i=0;i<f;i++){const h=(i+.5)/f,l=s?s.x+(t-s.x)*h:t,c=s?s.y+(e-s.y)*h:e,g=Math.max(0,Math.floor((l-2.5*d/r)*(a-1))),M=Math.min(a-1,Math.ceil((l+2.5*d/r)*(a-1))),x=Math.max(0,Math.floor((c-2.5*d/n)*(o-1))),v=Math.min(o-1,Math.ceil((c+2.5*d/n)*(o-1)));for(let t=x;t<=v;t++)for(let e=g;e<=M;e++){const i=(e/(a-1)-l)*r/d,s=(t/(o-1)-c)*n/d,h=Math.exp(1.5*-(i*i+s*s)),f=t*a+e;if("dissolve"===this.mode)this.ink[f]=Math.max(this.ink[f],h);else{const t=(-i*u+s*m)*h*2.8,e="silk"===this.mode?m*t:-s*h*2.5,a="silk"===this.mode?u*t:i*h*2.5;this.targetX[f]=Math.max(-1,Math.min(1,this.targetX[f]+e*p)),this.targetY[f]=Math.max(-1,Math.min(1,this.targetY[f]+a*p))}}}this.peak=1}step(t){if(!this.active||!Number.isFinite(t))return;const e=Math.max(0,Math.min(.05,t)),i=Math.exp(-("dissolve"===this.mode?2.15:3.2)*e),s=1-Math.exp(-22*e);let a=0;for(let t=0;t<this.ink.length;t++)if("dissolve"===this.mode){this.ink[t]*=i,a=Math.max(a,this.ink[t]);const e=Math.round(65535*this.ink[t]);this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e}else{this.targetX[t]*=i,this.targetY[t]*=i,this.offsetX[t]+=(this.targetX[t]-this.offsetX[t])*s,this.offsetY[t]+=(this.targetY[t]-this.offsetY[t])*s,a=Math.max(a,Math.abs(this.offsetX[t]),Math.abs(this.offsetY[t]),Math.abs(this.targetX[t]),Math.abs(this.targetY[t]));const e=Math.round(this.offsetX[t]*(this.edgeSafe?this.edge[t]:1)*32767+32768),o=Math.round(this.offsetY[t]*(this.edgeSafe?this.edge[t]:1)*32767+32768);this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e,this.pixels[4*t+2]=o>>>8,this.pixels[4*t+3]=255&o}this.peak=a,this.active||this.clear()}sample(t,e,i){const s=Math.max(0,Math.min(this.width-1.001,t*(this.width-1))),a=Math.max(0,Math.min(this.height-1.001,e*(this.height-1))),o=Math.floor(s),r=Math.floor(a),n=s-o,h=a-r,l=r*this.width+o,c=l+this.width,d=t=>(t[l]*(1-n)+t[l+1]*n)*(1-h)+(t[c]*(1-n)+t[c+1]*n)*h;i[0]=d(this.offsetX)*(this.edgeSafe?v(t,e,this.width/this.height):1)*.08,i[1]=d(this.offsetY)*(this.edgeSafe?v(t,e,this.width/this.height):1)*.08,i[2]="dissolve"===this.mode?6*-d(this.ink):0}},b=class{constructor(t,e){this.rings=[],this.previous=null,this.elapsed=1,this.echoPeak=0,this.width=t,this.height=e,this.pixels=new Uint8Array(t*e*4),this.echo=new Float32Array(t*e)}get active(){return this.rings.length>0||this.echoPeak>2e-4}clear(){this.rings=[],this.previous=null,this.elapsed=1,this.pixels.fill(0),this.echo.fill(0),this.echoPeak=0}leave(){this.previous=null}move(t,e,i){const s=Math.max(1,this.width/this.height),a=Math.max(1,this.height/this.width);this.previous&&(Math.hypot((t-this.previous.x)*s,(e-this.previous.y)*a)<.065||this.elapsed<.3)||4!==this.rings.length&&(this.previous={x:t,y:e},this.elapsed=0,this.rings.push({x:t,y:e,age:0,radius:i}))}ringSample(t,e){const i=Math.max(1,this.width/this.height),s=Math.max(1,this.height/this.width);let a=0;for(const o of this.rings){const r=.015+o.age*(.15+.22*o.radius),n=.009+.014*o.radius,h=(Math.hypot((t-o.x)*i,(e-o.y)*s)-r)/n,l=Math.sin(Math.min(1,o.age/.07)*Math.PI/2)*Math.max(0,1-o.age/1.35)**2;a=Math.max(a,Math.exp(-h*h)*l)}return a}sample(t,e){const i=Math.max(0,Math.min(this.width-1,Math.round(t*(this.width-1)))),s=Math.max(0,Math.min(this.height-1,Math.round(e*(this.height-1))));return Math.max(this.ringSample(t,e),this.echo[s*this.width+i])}step(t){if(!Number.isFinite(t))return;const e=Math.max(0,Math.min(.05,t));this.elapsed+=e;for(const t of this.rings)t.age+=e;if(this.rings=this.rings.filter(t=>t.age<1.35),!this.active)return void this.pixels.fill(0);const i=Math.exp(-5.5*e);let s=0;for(let t=0;t<this.height;t++)for(let e=0;e<this.width;e++){const a=t*this.width+e;this.echo[a]=Math.max(this.ringSample(e/(this.width-1),t/(this.height-1)),this.echo[a]*i),s=Math.max(s,this.echo[a]);const o=Math.round(65535*this.echo[a]),r=4*a;this.pixels[r]=o>>>8,this.pixels[r+1]=255&o}this.echoPeak=s,this.active||(this.echo.fill(0),this.pixels.fill(0))}},y=class{constructor(t,e){this.previous=null,this.peak=0,this.width=t,this.height=e;const i=t*e;this.pixels=new Uint8Array(4*i),this.signal=new Float32Array(i),this.offsetX=new Float32Array(i),this.offsetY=new Float32Array(i),this.driftX=new Float32Array(i),this.driftY=new Float32Array(i),this.u=new Float32Array(i),this.v=new Float32Array(i),this.ink=new Float32Array(i),this.a=new Float32Array(i),this.b=new Float32Array(i),this.c=new Float32Array(i),this.pressure=new Float32Array(i),this.pressureNext=new Float32Array(i),this.divergence=new Float32Array(i),this.curl=new Float32Array(i)}get active(){return this.peak>2e-4}clear(){for(const t of[this.u,this.v,this.ink,this.a,this.b,this.c,this.pressure,this.pressureNext,this.divergence,this.curl,this.signal,this.pixels,this.offsetX,this.offsetY,this.driftX,this.driftY])t.fill(0);this.previous=null,this.peak=0}leave(){this.previous=null}move(t,e,i,s=performance.now()){if(!Number.isFinite(t+e+i+s))return;t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e)),i=Math.max(.1,Math.min(1,i));const a=this.previous;if(this.previous={x:t,y:e,time:s},!a)return;const o=(t-a.x)*(this.width-1),r=(e-a.y)*(this.height-1),n=Math.hypot(o,r);if(n<.001)return;const h=Math.min(this.width,this.height),l=s>a.time?Math.max(1/240,(s-a.time)/1e3):1/60,c=Math.min(12,n/h/l),d=1-Math.exp(-c/2.2),f=h*(.022+.075*i)*(.65+.95*d),m=Math.min(128,Math.max(1,Math.ceil(n/(.4*f)))),u=n/f*(.32+.22*d)/m,p=o/n,g=r/n,M=-g,x=p,v=n*(2+18*d)/m;for(let i=0;i<m;i++){const s=(i+.5)/m,o=(a.x+(t-a.x)*s)*(this.width-1),r=(a.y+(e-a.y)*s)*(this.height-1),n=Math.max(1,Math.floor(o-3*f)),h=Math.min(this.width-2,Math.ceil(o+3*f)),l=Math.max(1,Math.floor(r-3*f)),c=Math.min(this.height-2,Math.ceil(r+3*f));for(let t=l;t<=c;t++)for(let e=n;e<=h;e++){const i=((e-o)*p+(t-r)*g)/f,s=((e-o)*M+(t-r)*x)/f,a=Math.exp(-i*i*.65-s*s*1.7),n=t*this.width+e;this.ink[n]=1-(1-this.ink[n])*Math.exp(-a*u);const h=1-s*s*.55,l=i*s*.7;this.u[n]=Math.max(-80,Math.min(80,this.u[n]+(p*h+M*l)*a*v)),this.v[n]=Math.max(-80,Math.min(80,this.v[n]+(g*h+x*l)*a*v))}}this.peak=1}read(t,e,i){const s=0|(e=Math.max(.5,Math.min(this.width-1.5,e))),a=0|(i=Math.max(.5,Math.min(this.height-1.5,i))),o=e-s,r=i-a,n=a*this.width+s;return(t[n]*(1-o)+t[n+1]*o)*(1-r)+(t[n+this.width]*(1-o)+t[n+this.width+1]*o)*r}sample(t,e){return this.read(this.signal,t*(this.width-1),e*(this.height-1))}displacement(t,e,i){i[0]=this.read(this.offsetX,t*(this.width-1),e*(this.height-1)),i[1]=this.read(this.offsetY,t*(this.width-1),e*(this.height-1))}step(t){if(!this.active||!Number.isFinite(t))return;let e=Math.max(0,Math.min(.05,t));const i=this.width,s=this.height;for(;e>1e-7;){const t=Math.min(1/60,e);e-=t;const a=Math.exp(-1.9*t),o=Math.exp(-3.2*t);for(let e=1;e<s-1;e++)for(let r=1;r<i-1;r++){const n=e*i+r,h=Math.max(.5,Math.min(i-1.5,r-this.u[n]*t)),l=Math.max(.5,Math.min(s-1.5,e-this.v[n]*t)),c=0|h,d=0|l,f=h-c,m=l-d,u=d*i+c,p=(1-f)*(1-m),g=f*(1-m),M=(1-f)*m,x=f*m;this.a[n]=(this.u[u]*p+this.u[u+1]*g+this.u[u+i]*M+this.u[u+i+1]*x)*a,this.b[n]=(this.v[u]*p+this.v[u+1]*g+this.v[u+i]*M+this.v[u+i+1]*x)*a,this.c[n]=(this.ink[u]*p+this.ink[u+1]*g+this.ink[u+i]*M+this.ink[u+i+1]*x)*o}[this.u,this.a]=[this.a,this.u],[this.v,this.b]=[this.b,this.v],[this.ink,this.c]=[this.c,this.ink];for(let t=1;t<s-1;t++)for(let e=1;e<i-1;e++){const s=t*i+e;this.curl[s]=.5*(this.v[s+1]-this.v[s-1]-this.u[s+i]+this.u[s-i])}for(let e=1;e<s-1;e++)for(let s=1;s<i-1;s++){const a=e*i+s,o=Math.abs(this.curl[a+1])-Math.abs(this.curl[a-1]),r=Math.abs(this.curl[a+i])-Math.abs(this.curl[a-i]),n=Math.hypot(o,r)+1e-4,h=this.curl[a]*t*10,l=Math.hypot(this.u[a],this.v[a]);this.u[a]+=r/n*h,this.v[a]-=o/n*h;const c=Math.min(1,l/(Math.hypot(this.u[a],this.v[a])+1e-6));this.u[a]*=c,this.v[a]*=c,this.divergence[a]=-.5*(this.u[a+1]-this.u[a-1]+this.v[a+i]-this.v[a-i])}this.pressure.fill(0);for(let t=0;t<4;t++){for(let t=1;t<s-1;t++)for(let e=1;e<i-1;e++){const s=t*i+e;this.pressureNext[s]=.25*(this.divergence[s]+this.pressure[s-1]+this.pressure[s+1]+this.pressure[s-i]+this.pressure[s+i])}[this.pressure,this.pressureNext]=[this.pressureNext,this.pressure]}let r=0;for(let e=1;e<s-1;e++)for(let s=1;s<i-1;s++){const a=e*i+s;this.u[a]=Math.max(-80,Math.min(80,this.u[a]-.5*(this.pressure[a+1]-this.pressure[a-1]))),this.v[a]=Math.max(-80,Math.min(80,this.v[a]-.5*(this.pressure[a+i]-this.pressure[a-i]))),this.driftX[a]+=(3.6*this.u[a]-58*this.offsetX[a]-12*this.driftX[a])*t,this.driftY[a]+=(3.6*this.v[a]-58*this.offsetY[a]-12*this.driftY[a])*t,this.offsetX[a]=Math.max(-2,Math.min(2,this.offsetX[a]+this.driftX[a]*t)),this.offsetY[a]=Math.max(-2,Math.min(2,this.offsetY[a]+this.driftY[a]*t)),this.signal[a]=1-Math.exp(.06*-Math.hypot(this.u[a],this.v[a])-.16*this.ink[a]),r=Math.max(r,this.signal[a])}this.peak=r}if(this.active)for(let t=0;t<this.ink.length;t++){const e=Math.round(65535*Math.min(1,this.signal[t]));this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e,this.pixels[4*t+2]=Math.round(128+63.5*this.offsetX[t]),this.pixels[4*t+3]=Math.round(128+63.5*this.offsetY[t])}else this.clear()}};function S(t,e){const i=Math.max(0,Math.min(1,e/.38));return t+(1-2*t)*(i*i*(3-2*i))}var E=class{constructor(t=1){this.mode="water",this.amount=.55,this.radius=.2,this.lensX=.5,this.lensY=.5,this.lensStrength=0,this.previous=null,this.energy=0,this.pending=!1,this.remainder=0,t=Math.max(.25,Math.min(4,t)),this.columns=Math.round(t>=1?128:128*t),this.rows=Math.round(t>=1?128/t:128),this.xScale=Math.max(1,t),this.yScale=Math.max(1,1/t),this.heights=new Float32Array(this.columns*this.rows),this.velocity=new Float32Array(this.heights.length),this.next=new Float32Array(this.heights.length),this.normals=new Float32Array(2*this.heights.length),this.edgeMask=new Float32Array(this.heights.length);for(let e=0;e<this.rows;e++)for(let i=0;i<this.columns;i++)this.edgeMask[e*this.columns+i]=v(i/(this.columns-1),e/(this.rows-1),t);this.refraction={width:this.columns,height:this.rows,pixels:new Uint8Array(4*this.heights.length),strength:30,mode:"water",focus:[.5,.5,0,.2]},this.waterPixels=this.refraction.pixels,this.trail=new y(this.columns,this.rows),this.contour=new b(this.columns,this.rows),this.afterimage=new w(this.columns,this.rows),this.clear()}get invertsDensity(){return"trail"===this.mode}get densityTrail(){return["trail","contour","dissolve"].includes(this.mode)}get hasRefraction(){return this.active||this.lensStrength>15e-5}get active(){return["dissolve","silk","vortex"].includes(this.mode)?this.afterimage.active:"contour"===this.mode?this.contour.active:"trail"===this.mode?this.trail.active:this.pending||this.energy>15e-5}setMode(t){t!==this.mode&&(this.clear(),this.mode=t,this.refraction.mode=t,"dissolve"!==t&&"silk"!==t&&"vortex"!==t||this.afterimage.setMode(t),this.refraction.pixels="trail"===t?this.trail.pixels:"contour"===t?this.contour.pixels:["dissolve","silk","vortex"].includes(t)?this.afterimage.pixels:this.waterPixels,this.refraction.strength="water"===t?30*this.amount/.55:"silk"===t?28*this.amount:"vortex"===t?38*this.amount:0)}configure(t,e=.55,i=.2,s=!1){this.setMode(t),this.refraction.edgeSafe=s,this.afterimage.edgeSafe=s,this.amount=Number.isFinite(e)?Math.max(0,Math.min(1,e)):.55,this.radius=Number.isFinite(i)?Math.max(.1,Math.min(1,i)):.2,this.refraction.strength="water"===t?30*this.amount/.55:"silk"===t?28*this.amount:"vortex"===t?38*this.amount:0,this.refraction.focus[2]=this.densityTrail?this.amount:this.lensStrength*this.amount,this.refraction.focus[3]=this.radius}move(t,e,i){if("none"===this.mode||0===this.amount)return;if(!Number.isFinite(t+e))return;if(t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e)),["dissolve","silk","vortex"].includes(this.mode))return void this.afterimage.move(t,e,this.radius);if("contour"===this.mode)return void this.contour.move(t,e,this.radius);if("trail"===this.mode)return void this.trail.move(t,e,this.radius,i);if("water"!==this.mode)return!this.previous&&this.lensStrength<.001&&(this.lensX=t,this.lensY=e),this.previous={x:t,y:e},void(this.pending=!0);if(!this.previous)return void(this.previous={x:t,y:e});const s=this.previous;this.previous={x:t,y:e};const a=(t-s.x)*this.xScale,o=(e-s.y)*this.yScale,r=Math.hypot(a,o);if(r<1e-5)return;const n=.035+.1*this.radius,h=3*n,l=Math.min(192,Math.max(1,Math.ceil(r/(.5*n)))),c=95*Math.min(r,1)/l;for(let i=0;i<l;i++){const a=(i+.5)/l,o=s.x+(t-s.x)*a,r=s.y+(e-s.y)*a,d=Math.max(1,Math.floor((o-h/this.xScale)*(this.columns-1))),f=Math.min(this.columns-2,Math.ceil((o+h/this.xScale)*(this.columns-1))),m=Math.max(1,Math.floor((r-h/this.yScale)*(this.rows-1))),u=Math.min(this.rows-2,Math.ceil((r+h/this.yScale)*(this.rows-1)));for(let t=m;t<=u;t++)for(let e=d;e<=f;e++){const i=(e/(this.columns-1)-o)*this.xScale,s=(t/(this.rows-1)-r)*this.yScale,a=Math.exp(-(i*i+s*s)/(n*n))*c,h=t*this.columns+e;this.velocity[h]=Math.max(-12,this.velocity[h]-a)}}this.pending=!0}leave(){this.afterimage.leave(),this.contour.leave(),this.trail.leave(),this.previous=null,"water"!==this.mode&&this.lensStrength&&(this.pending=!0)}clear(){this.trail.clear(),this.contour.clear(),this.afterimage.clear(),this.heights.fill(0),this.velocity.fill(0),this.next.fill(0),this.normals.fill(0),this.refraction.focus[2]=0,this.previous=null,this.lensStrength=0,this.energy=0,this.pending=!1,this.remainder=0;for(let t=0;t<this.waterPixels.length;t+=4)this.waterPixels[t]=this.waterPixels[t+2]=128,this.waterPixels[t+1]=this.waterPixels[t+3]=0}step(t){if(!this.active||!Number.isFinite(t))return;if(["dissolve","silk","vortex"].includes(this.mode))return void this.afterimage.step(t);if("contour"===this.mode)return void this.contour.step(t);if("trail"===this.mode)return void this.trail.step(t);if("water"!==this.mode)return void this.stepLight(Math.max(0,Math.min(.05,t)));this.remainder+=Math.max(0,Math.min(.05,t));const e=1/120,i=Math.exp(-3.8*e),s=.3*Math.min(this.columns,this.rows);for(;this.remainder+1e-8>=e;){this.remainder-=e;let t=0;for(let a=1;a<this.rows-1;a++)for(let o=1;o<this.columns-1;o++){const r=a*this.columns+o,n=this.heights[r],h=this.heights[r-1]+this.heights[r+1]+this.heights[r-this.columns]+this.heights[r+this.columns]-4*n,l=Math.min(o,a,this.columns-1-o,this.rows-1-a),c=l<5?.88+.024*l:1,d=(this.velocity[r]+(h*s*s-8*n)*e)*i*c;this.velocity[r]=d,this.next[r]=(n+d*e)*c,t=Math.max(t,Math.abs(this.next[r]),.1*Math.abs(d))}this.heights.set(this.next),this.energy=t,this.pending=!1}if(!this.active)return void this.clear();const a=.18*Math.min(this.columns,this.rows);for(let t=0;t<this.rows;t++)for(let e=0;e<this.columns;e++){const i=t*this.columns+e,s=(this.heights[t*this.columns+Math.max(0,e-1)]-this.heights[t*this.columns+Math.min(this.columns-1,e+1)])*a,o=(this.heights[Math.max(0,t-1)*this.columns+e]-this.heights[Math.min(this.rows-1,t+1)*this.columns+e])*a,r=Math.tanh(s)*(this.refraction.edgeSafe?this.edgeMask[i]:1),n=Math.tanh(o)*(this.refraction.edgeSafe?this.edgeMask[i]:1);this.normals[2*i]=r,this.normals[2*i+1]=n;const h=Math.round(32767*r+32768),l=Math.round(32767*n+32768);this.refraction.pixels[4*i]=h>>>8,this.refraction.pixels[4*i+1]=255&h,this.refraction.pixels[4*i+2]=l>>>8,this.refraction.pixels[4*i+3]=255&l}}stepLight(t){const e=this.previous,i=1-Math.exp(-30*t),s=1-Math.exp(-12*t);e&&(this.lensX+=(e.x-this.lensX)*i,this.lensY+=(e.y-this.lensY)*i),this.lensStrength+=((e?1:0)-this.lensStrength)*s,this.energy=Math.max(e?Math.abs(e.x-this.lensX)+Math.abs(e.y-this.lensY):0,Math.abs((e?1:0)-this.lensStrength)),this.pending=!1,e||this.active?this.refraction.focus=[this.lensX,this.lensY,this.lensStrength*this.amount,this.radius]:this.clear()}sample(t,e,i){if(["dissolve","silk","vortex"].includes(this.mode))return this.afterimage.sample(t,e,i),i[0]*=this.amount,i[1]*=this.amount,void(i[2]*=this.amount);if("contour"===this.mode)return i[0]=i[1]=0,void(i[2]=this.contour.sample(t,e)*this.amount*3);if("trail"===this.mode)return i[0]=i[1]=0,void(i[2]=this.trail.sample(t,e)*this.amount*3);const s=Math.max(0,Math.min(this.columns-1.001,t*(this.columns-1))),a=Math.max(0,Math.min(this.rows-1.001,e*(this.rows-1))),o=Math.floor(s),r=Math.floor(a),n=s-o,h=a-r,l=2*(r*this.columns+o),c=l+2*this.columns;for(let t=0;t<2;t++)i[t]=.08*((this.normals[l+t]*(1-n)+this.normals[l+2+t]*n)*(1-h)+(this.normals[c+t]*(1-n)+this.normals[c+2+t]*n)*h);i[0]*=this.amount/.55,i[1]*=this.amount/.55,i[2]="light"===this.mode||"scan"===this.mode?function(t,e,i,s){const[a,o,r,n]=i.focus,h=(t-a)*Math.max(1,s)/n,l=(e-o)*Math.max(1,1/s)/n;return"light"===i.mode?Math.exp(-3*(h*h+l*l))*r:"scan"===i.mode?(1.3*Math.exp(-h*h*110)-.3*Math.exp(-h*h*12))*Math.exp(-l*l*1.8)*r:0}(t,e,this.refraction,this.xScale/this.yScale):0}};function k(t){return"videoWidth"in t?[t.videoWidth,t.videoHeight]:"naturalWidth"in t?[t.naturalWidth,t.naturalHeight]:[t.width,t.height]}var T=(t=!1)=>{const e=document.createElement("canvas"),i=e.getContext("2d",{willReadFrequently:t});if(!i)throw new Error("Canvas 2D is unavailable.");return{canvas:e,ctx:i}},A=(t,e,i)=>{t.width===e&&t.height===i||(t.width=e,t.height=i)},F={blocks:" ░▒▓█",braille:" ⠁⠃⠇⡇⣇⣧⣷⣿",lines:" -═╪╬",cross:" ·+xX#",diagonal:" /╱╳",diamond:" ·◇◈◆",mixed:" .:+/◇#@"};function I(t,e={},i={}){const a=t.getContext("2d");if(!a)throw new Error("Canvas is already owned by another renderer.");const o=T(),r=T(!0),n=T(),h=T(),d=T(),f=T(),m=T(),u=T(),v=T();let w,b=l(e),y=0,I="",R=new Uint8ClampedArray(0),P=0,L=0,C=0,D=null,U="",O=new E,X=0;const N=[0,0,0],B=Math.max(64,Math.min(4096,Number.isFinite(i.maxDimension)?i.maxDimension:960)),_=Math.max(256,Math.min(16e4,Number.isFinite(i.maxCells)?i.maxCells:12e3));let Y=_;const z=Math.max(.1,Math.min(8,i.pixelRatio??1));return{canvas:t,render:function(e,i=0,l=960,T=540){if(Number.isFinite(i)||(i=0),!Number.isFinite(l)||!Number.isFinite(T)||l<1||T<1)throw new Error("Render dimensions must be positive finite numbers.");const[_,G]=k(e);if(!_||!G)return;const W=Math.min(1,B/Math.max(l,T)),q=Math.max(2,Math.round(l*W)),j=Math.max(2,Math.round(T*W));A(t,q,j),A(o.canvas,q,j),A(n.canvas,q,j),A(h.canvas,q,j),A(d.canvas,q,j),X!==q/j&&(X=q/j,O=new E(X)),O.configure(b.hover.effect,b.hover.strength,b.hover.radius,b.hover.edgeSafe),O.step(Math.max(0,Math.min(.05,i-C))),C=i;const $="currentTime"in e?e.getVideoPlaybackQuality?.().totalVideoFrames??e.currentTime:0,V=[y,q,j,$].join(":"),H="dither"===b.style,J=(H?b.dither.scale:b.cellSize)*z,K=Math.max(J,Math.sqrt(q*j/Y)),Q=H||["pixel","mosaic","lego","voxel","disco","dots"].includes(b.style)?K:1.65*K,Z=Math.max(1,Math.ceil(q/K)),tt=Math.max(1,Math.ceil(j/Q));if(I!==V||D!==e||P!==Z||L!==tt){D=e,I=V,P=Z,L=tt,o.ctx.clearRect(0,0,q,j),o.ctx.save();const t=c(_,G,q,j,b.crop);o.ctx.translate(t.x+t.width/2,t.y+t.height/2),o.ctx.rotate(b.crop.rotation*Math.PI/180),o.ctx.drawImage(e,-_*t.scale/2,-G*t.scale/2,_*t.scale,G*t.scale),o.ctx.restore(),A(r.canvas,P,L),r.ctx.clearRect(0,0,P,L),r.ctx.drawImage(o.canvas,0,0,P,L),R=r.ctx.getImageData(0,0,P,L).data;const i=b.color;for(let t=0;t<R.length;t+=4){const e=.299*R[t]+.587*R[t+1]+.114*R[t+2];for(let s=0;s<3;s++){const a=e+(R[t+s]-e)*i.saturation;R[t+s]=((a*(1-i.grayscale)+e*i.grayscale)/255-.5)*i.contrast*255+127.5+255*i.brightness}}}n.ctx.clearRect(0,0,q,j),n.ctx.globalAlpha=1,n.ctx.globalCompositeOperation="source-over";const et=i*b.motion.speed;if(H){const t=new Uint8ClampedArray(R),e=b.motion.type;if(O.active||"none"!==e)for(let i=0;i<L;i++)for(let s=0;s<P;s++){const a=s/P,o=i/L;let r=s,n=i,h=0,l=1,c=1;if(O.active&&(O.sample(a,o,N),r-=N[0]*P,n-=N[1]*L,h=N[2]/3),"wave"===e&&(n+=Math.sin(8*a+2*et+4*o)*L*.015),"ripple"===e){const t=a-.5,e=o-.5,i=.03*Math.sin(30*Math.hypot(t,e)-3*et);r+=t*i*P,n+=e*i*L}"breathe"===e&&(l=.92+.08*Math.sin(1.5*et+3*a)),"reveal"===e&&(c=Math.max(0,Math.min(1,4*(.7*Math.sin(.7*et)+.7-a)))),"glitch"===e&&p(i,Math.floor(6*et))>.93&&(r+=8*Math.sin(5*et)),"vapor"===e&&(n+=Math.sin(6*a+et)*L*.025),"fire"===e&&(n+=Math.sin(7*a+3*et+8*o)*L*.01,l=.8+.2*Math.sin(12*o-4*et)),"hologram"===e&&(c=.72+.28*Math.sin(.65*i+5*et)),"chrome"===e&&(l=.5+Math.abs(Math.sin(8*o+et)));const d=4*(i*P+s),f=4*(Math.max(0,Math.min(L-1,Math.round(n)))*P+Math.max(0,Math.min(P-1,Math.round(r))));for(let i=0;i<3;i++){const s=R[f+i]/255;let o=(["trail","contour"].includes(b.hover.effect)?S(s,h):"dissolve"===b.hover.effect?s*Math.max(0,1+h):s)*l;"rainbow"===e&&(o*=.65+.35*Math.sin(2*et+5*a+2.094*i)),"hologram"===e&&(o*=0===i?.4:1),"fire"===e&&(o*=0===i?1.3:1===i?.7:.3),t[d+i]=255*o}t[d+3]=R[f+3]*c}!function(t,e,i,a,o=0){const{algorithm:r,amount:n,threshold:h}=a,l=("custom"===a.palette?a.colors:s[a.palette]??s.mono).map(x),c=M[r],d=c?new Float32Array(3*e*3):null,f="drift"===a.motion?Math.floor(o*a.speed*3):0,m="shimmer"===a.motion?.15*Math.sin(o*a.speed*2):0;for(let s=0;s<i;s++)for(let a=0;a<e;a++){const o=4*(s*e+a),u=3*(s%3*e+a);if(0===t[o+3]){d&&(d[u]=d[u+1]=d[u+2]=0);continue}let M=0;r.startsWith("bayer")?M=g(a+f&15,s+f&15,Number(r.slice(5))):"noise"===r?M=p(a,s)-.5:"lines"===r?M=(s+f)%4/3-.5:"halftone"===r&&(M=Math.hypot(a%6-2.5,s%6-2.5)/3.54-.5);const x=128*(M*n+m+(.5-h)),v=t[o]+x+(d?.[u]??0),w=t[o+1]+x+(d?.[u+1]??0),b=t[o+2]+x+(d?.[u+2]??0);let y=0,S=0,E=0;if(l.length){let t=1/0;for(const e of l){const i=(v-e[0])**2*.299+(w-e[1])**2*.587+(b-e[2])**2*.114;i<t&&(t=i,[y,S,E]=e)}}else y=51*Math.round(v/51),S=51*Math.round(w/51),E=51*Math.round(b/51);if(t[o]=y,t[o+1]=S,t[o+2]=E,d&&c){d[u]=d[u+1]=d[u+2]=0;for(const[t,o,r]of c){const h=a+t;if(h<0||h>=e||s+o>=i)continue;const l=3*((s+o)%3*e+h);d[l]+=(v-y)*r*n,d[l+1]+=(w-S)*r*n,d[l+2]+=(b-E)*r*n}}}}(t,P,L,b.dither,i),r.ctx.putImageData(new ImageData(t,P,L),0,0),n.ctx.imageSmoothingEnabled=!1,n.ctx.drawImage(r.canvas,0,0,q,j)}else{const t=Array.from(F[b.style]??b.charset),e=n.ctx,i="ascii"===b.style||!!F[b.style],s=Math.max(3,Math.round(.92*Q)),a=Math.ceil(K+4),o=Math.ceil(Q+4),r=[t.join(""),s,a,o,b.ink,b.colorMode].join(":");i&&r!==U&&(U=r,A(m.canvas,a*t.length,o),m.ctx.clearRect(0,0,m.canvas.width,o),m.ctx.font=`${s}px monospace`,m.ctx.textBaseline="middle",m.ctx.textAlign="center",m.ctx.fillStyle="accent"===b.colorMode?b.ink:"#ffffff",t.forEach((t,e)=>m.ctx.fillText(t,e*a+a/2,o/2))),e.font=`${s}px monospace`,e.textBaseline="middle",e.textAlign="center";for(let s=0;s<L;s++)for(let r=0;r<P;r++){let n=r,h=s,l=0;O.active&&(O.sample(r/P,s/L,N),n=Math.max(0,Math.min(P-1,r-N[0]*P)),h=Math.max(0,Math.min(L-1,s-N[1]*L)),l=N[2]/3);const c=4*(Math.floor(h)*P+Math.floor(n));if(!R[c+3])continue;const d=R[c],f=R[c+1],u=R[c+2],g=(.299*d+.587*f+.114*u)/255;let M=g;["trail","contour"].includes(b.hover.effect)&&l?M=S(M,l):"dissolve"===b.hover.effect&&(M*=Math.max(0,1+l));const x=b.motion.type;let v=r*K,w=s*Q,y=1;if("breathe"===x&&(M*=.92+.08*Math.sin(1.5*et+.03*r)),"wave"===x&&(w+=Math.sin(.12*r+2*et+.08*s)*Q*.4),"ripple"===x){const t=r/P-.5,e=s/L-.5,i=Math.hypot(t,e),a=Math.sin(30*i-3*et)*K*.65;v+=t*a,w+=e*a}"fire"===x&&(w-=Math.sin(.16*r+3*et+.09*s)*Q*.35,M*=.85+.15*Math.sin(.3*s-4*et)),"hologram"===x&&(y=.72+.28*Math.sin(.65*s+5*et)),"reveal"===x&&(y=Math.max(0,Math.min(1,4*(.7*Math.sin(.7*et)+.7-r/P)))),"glitch"===x&&p(s,Math.floor(6*et))>.93&&(v+=Math.sin(5*et)*K*3),"vapor"===x&&(w+=Math.sin(.04*r+et)*Q),i||"accent"!==b.colorMode||(y*=M),e.globalAlpha=y;const E=255*(M-g);let k="source"===b.colorMode?`rgb(${d+E},${f+E},${u+E})`:"gray"===b.colorMode?`rgb(${Math.round(255*M)},${Math.round(255*M)},${Math.round(255*M)})`:b.ink;if("rainbow"===x&&(k=`hsl(${(r/P*180+40*et)%360} 70% 65%)`),"fire"===x&&(k=`hsl(${15+40*M} 90% ${30+45*M}%)`),"hologram"===x&&(k=`hsl(185 65% ${40+40*M}%)`),"chrome"===x&&(k=`hsl(210 12% ${25+70*Math.abs(Math.sin(.2*s+et))}%)`),e.fillStyle=k,i){const i=Math.max(0,Math.min(t.length-1,Math.floor(M*(t.length-1))));"accent"!==b.colorMode||["rainbow","fire","hologram","chrome"].includes(x)?e.fillText(t[i],v+K/2,w+Q/2):e.drawImage(m.canvas,i*a,0,a,o,v+(K-a)/2,w+(Q-o)/2,a,o)}else if("dots"===b.style)e.beginPath(),e.arc(v+K/2,w+Q/2,.48*K*Math.sqrt(M),0,2*Math.PI),e.fill();else if("voxel"===b.style){const t=v+K/2,i=w+Q/2;e.beginPath(),e.moveTo(t,w),e.lineTo(v+K,w+.25*Q),e.lineTo(t,i),e.lineTo(v,w+.25*Q),e.closePath(),e.fill(),e.globalAlpha=.72*y,e.beginPath(),e.moveTo(v,w+.25*Q),e.lineTo(t,i),e.lineTo(t,w+Q),e.lineTo(v,w+.75*Q),e.closePath(),e.fill(),e.globalAlpha=.42*y,e.beginPath(),e.moveTo(t,i),e.lineTo(v+K,w+.25*Q),e.lineTo(v+K,w+.75*Q),e.lineTo(t,w+Q),e.closePath(),e.fill()}else{const t="pixel"===b.style?0:Math.max(.5,.06*K);e.fillRect(v,w,K-t,Q-t),"lego"===b.style&&(e.fillStyle="rgba(255,255,255,.2)",e.beginPath(),e.arc(v+K/2,w+Q/2,.28*K,0,2*Math.PI),e.fill(),e.strokeStyle="rgba(0,0,0,.25)",e.stroke()),"disco"===b.style&&(e.fillStyle=`rgba(255,255,255,${.1+.25*p(r,s)})`,e.fillRect(v,w,K-t,.35*Q),e.fillStyle="rgba(0,0,0,.25)",e.fillRect(v,w+.65*Q,K-t,.35*Q-t))}}}n.ctx.globalAlpha=1,(b.color.amount||b.lights.length)&&(A(u.canvas,q,j),u.ctx.clearRect(0,0,q,j),u.ctx.drawImage(n.canvas,0,0)),b.color.amount&&(n.ctx.save(),n.ctx.globalCompositeOperation=b.color.blend,n.ctx.globalAlpha=b.color.amount,n.ctx.fillStyle=b.color.tint,n.ctx.fillRect(0,0,q,j),n.ctx.restore());for(const t of b.lights){const e=t.radius*Math.max(q,j),i=n.ctx.createRadialGradient(t.x*q,t.y*j,0,t.x*q,t.y*j,e);i.addColorStop(0,t.color),i.addColorStop(1,"transparent"),n.ctx.save(),n.ctx.globalCompositeOperation="screen",n.ctx.globalAlpha=t.intensity,n.ctx.fillStyle=i,n.ctx.fillRect(0,0,q,j),n.ctx.restore()}if((b.color.amount||b.lights.length)&&(n.ctx.globalCompositeOperation="destination-in",n.ctx.drawImage(u.canvas,0,0),n.ctx.globalCompositeOperation="source-over"),b.mask.enabled&&b.mask.shapes.length){const t=d.ctx;t.clearRect(0,0,q,j),t.fillStyle="#fff",t.strokeStyle="#fff",t.lineCap="round",t.lineJoin="round";for(const e of b.mask.shapes){if(t.beginPath(),"ellipse"===e.kind)t.ellipse((e.x+e.width/2)*q,(e.y+e.height/2)*j,e.width*q/2,e.height*j/2,0,0,2*Math.PI);else{if("rectangle"!==e.kind){if(t.lineWidth=(e.size??.05)*q,1===e.points?.length){t.arc(e.points[0][0]*q,e.points[0][1]*j,t.lineWidth/2,0,2*Math.PI),t.fill();continue}e.points?.forEach(([e,i],s)=>s?t.lineTo(e*q,i*j):t.moveTo(e*q,i*j)),t.stroke();continue}t.rect(e.x*q,e.y*j,e.width*q,e.height*j)}t.fill()}n.ctx.globalCompositeOperation=b.mask.invert?"destination-out":"destination-in",n.ctx.drawImage(d.canvas,0,0),n.ctx.globalCompositeOperation="source-over"}const it=h.ctx;it.clearRect(0,0,q,j),it.globalAlpha=b.backdrop.opacity;const st=b.backdrop;if("solid"===st.mode&&(it.fillStyle=st.color,it.fillRect(0,0,q,j)),"gradient"===st.mode){const t=it.createLinearGradient(0,0,q,j);t.addColorStop(0,st.color),t.addColorStop(1,st.color2),it.fillStyle=t,it.fillRect(0,0,q,j)}if("source"===st.mode&&it.drawImage(o.canvas,0,0),"blurred"===st.mode){const t=Math.max(1,st.blur);A(f.canvas,Math.max(2,Math.round(q/t)),Math.max(2,Math.round(j/t))),f.ctx.drawImage(o.canvas,0,0,f.canvas.width,f.canvas.height),it.imageSmoothingEnabled=!0,it.drawImage(f.canvas,0,0,q,j)}it.globalAlpha=1,b.effects.characterBloom>0&&(A(v.canvas,Math.max(2,Math.round(q/3)),Math.max(2,Math.round(j/3))),v.ctx.clearRect(0,0,v.canvas.width,v.canvas.height),v.ctx.drawImage(n.canvas,0,0,v.canvas.width,v.canvas.height),it.save(),it.globalAlpha=.8*b.effects.characterBloom,it.globalCompositeOperation="screen",it.filter=`blur(${1+4*b.effects.characterBloom}px)`,it.drawImage(v.canvas,0,0,q,j),it.restore()),it.drawImage(n.canvas,0,0);const at=Object.entries(b.effects).some(([t,e])=>!["angle","focus","blurType","characterBloom"].includes(t)&&"number"==typeof e&&e>0);a.clearRect(0,0,q,j),at?(void 0===w&&(w=function(){const t=document.createElement("canvas"),e=t.getContext("webgl",{alpha:!0,premultipliedAlpha:!1,antialias:!1,preserveDrawingBuffer:!0});if(!e)return null;const i=[],s=(t,s)=>{const a=e.createShader(t);if(i.push(a),e.shaderSource(a,s),e.compileShader(a),!e.getShaderParameter(a,e.COMPILE_STATUS))throw new Error(e.getShaderInfoLog(a)||"Finish shader failed");return a},a=e.createProgram();if(e.attachShader(a,s(e.VERTEX_SHADER,"attribute vec2 p;varying vec2 uv;void main(){uv=(p+1.)*.5;gl_Position=vec4(p,0.,1.);}")),e.attachShader(a,s(e.FRAGMENT_SHADER,"precision mediump float;varying vec2 uv;uniform sampler2D src;uniform vec2 size;uniform float t,bloom,grain,dust,scanlines,crt,prism,vignette,glitch,pixelate,blur,blurMode,angle,focus,halftone;\n float hash(vec2 p){return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453);}\n vec4 sampleAt(vec2 p){if(min(min(p.x,p.y),min(1.-p.x,1.-p.y))<0.)return vec4(0.);return texture2D(src,vec2(p.x,1.-p.y));}\n void main(){vec2 q=uv,c=q-.5;q=c*(1.+dot(c,c)*crt*.25)+.5;\n if(glitch>0.)q.x+=(hash(vec2(floor(q.y*35.),floor(t*5.)))-.5)*.07*glitch*step(.82,hash(vec2(floor(q.y*35.),floor(t*5.)+3.)));\n if(pixelate>0.){vec2 grid=size/(1.+pixelate*20.);q=(floor(q*grid)+.5)/grid;}\n vec4 base=sampleAt(q);float edge=smoothstep(.12,.65,length(c));\n vec2 shift=vec2(prism*3.*edge/size.x,prism*edge/size.y);\n if(prism>0.)base.rgb=vec3(sampleAt(q+shift).r,base.g,sampleAt(q-shift).b);\n vec2 dir=vec2(cos(angle),sin(angle))/size;float amount=blur;\n if(blurMode>1.5&&blurMode<2.5){dir=normalize(c+vec2(.0001))/size;amount*=length(c)*2.;}\n if(blurMode>2.5)amount*=smoothstep(.05,.5,abs(q.y-focus));\n vec4 blurred=base;\n if(amount>0.){blurred=base*.2;for(int i=1;i<=4;i++){float f=float(i)*amount*.35;vec2 off=dir*f;if(blurMode<.5)off=vec2(cos(float(i)*1.57),sin(float(i)*1.57))*amount/size;blurred+=sampleAt(q+off)*.1+sampleAt(q-off)*.1;}}\n vec3 light=vec3(0.);if(bloom>0.)for(int i=0;i<4;i++){float a=float(i)*1.5708;vec3 s=sampleAt(q+vec2(cos(a),sin(a))*6./size).rgb;light+=max(vec3(0.),s-.35)*.25;}\n vec3 col=blurred.rgb+light*bloom;col*=1.-scanlines*.4*(.5+.5*cos(q.y*size.y*3.14159));\n col*=1.-vignette*smoothstep(.15,.72,length(c));\n col+=(hash(floor(q*size)+floor(t*12.))-.5)*grain*.2;\n if(dust>0.)col+=step(1.-dust*.002,hash(floor(q*size*.25)+floor(t*2.)))*.4;\n if(halftone>0.)col*=mix(1.,smoothstep(.1,.65,length(fract(q*size/6.)-.5)),halftone);\n gl_FragColor=vec4(clamp(col,0.,1.),blurred.a);}")),e.linkProgram(a),!e.getProgramParameter(a,e.LINK_STATUS))throw new Error("Finish link failed");e.useProgram(a);const o=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,o),e.bufferData(e.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,1]),e.STATIC_DRAW);const r=e.getAttribLocation(a,"p");e.enableVertexAttribArray(r),e.vertexAttribPointer(r,2,e.FLOAT,!1,0,0);const n=e.createTexture();e.bindTexture(e.TEXTURE_2D,n),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE);const h=["t","bloom","grain","dust","scanlines","crt","prism","vignette","glitch","pixelate","blur","blurMode","angle","focus","halftone"],l=Object.fromEntries(h.map(t=>[t,e.getUniformLocation(a,t)])),c=e.getUniformLocation(a,"size");return{canvas:t,render(i,s,o,r=1){t.width===i.width&&t.height===i.height||(t.width=i.width,t.height=i.height,e.viewport(0,0,t.width,t.height)),e.useProgram(a),e.bindTexture(e.TEXTURE_2D,n),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,i),e.uniform2f(c,t.width/r,t.height/r);for(const t of h)e.uniform1f(l[t],"t"===t?o:"blurMode"===t?["gaussian","directional","radial","progressive"].indexOf(s.blurType):"angle"===t?s.angle*Math.PI/180:s[t]??0);return e.drawArrays(e.TRIANGLE_STRIP,0,4),t},destroy(){e.deleteTexture(n),e.deleteBuffer(o),e.deleteProgram(a),i.forEach(t=>e.deleteShader(t)),t.width=t.height=1,e.getExtension("WEBGL_lose_context")?.loseContext()}}}()),w?a.drawImage(w.render(h.canvas,b.effects,i,z),0,0):a.drawImage(h.canvas,0,0),t.dataset.studioFinish=w?"gpu":"unavailable"):(a.drawImage(h.canvas,0,0),t.dataset.studioFinish="none")},setBudget(t){Y=Math.max(1500,Math.min(_,Math.round(t)))},get maxCells(){return Y},configure(t){b=l(t),y++},pointer:(t,e,i)=>{O.configure(b.hover.effect,b.hover.strength,b.hover.radius,b.hover.edgeSafe),O.move(t,e,i)},leave(){O.leave()},get active(){return O.active},get settings(){return l(b)},get capabilities(){return{gpuFinish:null!==w}},invalidate(){I=""},destroy(){w?.destroy();for(const t of[o,r,n,h,d,f,m,u,v])t.canvas.width=t.canvas.height=1;D=null,R=new Uint8ClampedArray(0)}}}function R(t,e,i){return new Promise((s,a)=>{const o=()=>{l(),s()},r=()=>{l(),a(new Error("Unable to load this media. Check its format and cross-origin permissions."))},n=()=>{l(),a(new DOMException("Cancelled","AbortError"))},h=setTimeout(r,2e4),l=()=>{clearTimeout(h),t.removeEventListener(e,o),t.removeEventListener("error",r),i?.removeEventListener("abort",n)};t.addEventListener(e,o,{once:!0}),t.addEventListener("error",r,{once:!0}),i?.addEventListener("abort",n,{once:!0}),i?.aborted&&n()})}async function P(t,e){if("string"==typeof t&&t.startsWith("blob:")){const i=await fetch(t,{signal:e}),s=await i.blob();return P(new File([s],"Imported media",{type:s.type}),e)}const i="string"!=typeof t,s=i?t.name:t;if(i?"image/gif"===t.type:/\.gif(?:[?#]|$)/i.test(s)){const s=await import("gifuct-js"),{parseGIF:a,decompressFrames:o}="function"==typeof s.parseGIF?s:s.default,r=i?await t.arrayBuffer():await fetch(t,{signal:e}).then(t=>{if(!t.ok)throw new Error("GIF download failed.");return t.arrayBuffer()});if(e?.aborted)throw new DOMException("Cancelled","AbortError");const n=a(r),h=n.lsd.width,l=n.lsd.height;if(h*l>4e6)throw new Error("GIF is too large. Use a smaller GIF or an MP4.");const c=n.frames.filter(t=>"image"in t).length;if(!c||c*h*l*4>128e6)throw new Error("GIF exceeds the decoded memory budget. Use MP4 for long animations.");const d=o(n,!0);if(d.length*h*l*4>128e6)throw new Error("GIF exceeds the 128 MB decoded budget. Use MP4 for long animations.");const f=document.createElement("canvas");f.width=h,f.height=l;const m=f.getContext("2d"),u=document.createElement("canvas"),p=u.getContext("2d"),g=d.reduce((t,e)=>t+Math.max(20,e.delay),0)/1e3;let M=-1,x=null;const v=t=>{const e=(t%g+g)%g*1e3;let i=0,s=0;for(;s<d.length-1&&(i+=Math.max(20,d[s].delay),!(e<i));s++);s<M&&(m.clearRect(0,0,h,l),M=-1,x=null);for(let t=M+1;t<=s;t++){const e=d[t-1];2===e?.disposalType&&m.clearRect(e.dims.left,e.dims.top,e.dims.width,e.dims.height),3===e?.disposalType&&x&&m.putImageData(x,0,0);const i=d[t];x=3===i.disposalType?m.getImageData(0,0,h,l):null,u.width=i.dims.width,u.height=i.dims.height,p.putImageData(new ImageData(new Uint8ClampedArray(i.patch),u.width,u.height),0,0),m.drawImage(u,i.dims.left,i.dims.top)}return M=s,f};return v(0),{source:f,width:h,height:l,duration:g,animated:!0,seek:async()=>{},frame:v,destroy(){f.width=u.width=1,d.length=0,x=null}}}const a=i?t.type.startsWith("video/"):/\.(mp4|webm|mov)(?:[?#]|$)/i.test(s),o=i?URL.createObjectURL(t):t,r=a?document.createElement("video"):new Image;r.crossOrigin="anonymous",r instanceof HTMLVideoElement&&(r.muted=!0,r.playsInline=!0,r.preload="auto");const n=()=>{r instanceof HTMLVideoElement?(r.pause(),r.removeAttribute("src"),r.load()):r.src="",i&&URL.revokeObjectURL(o)};try{const t=R(r,a?"loadeddata":"load",e);r.src=o,await t;const i=r instanceof HTMLVideoElement?r.videoWidth:r.naturalWidth,s=r instanceof HTMLVideoElement?r.videoHeight:r.naturalHeight;return{source:r,width:i,height:s,duration:r instanceof HTMLVideoElement?r.duration:0,animated:a,async seek(t,e){if(!(r instanceof HTMLVideoElement))return;if(!Number.isFinite(r.duration)||r.duration<=0)throw new Error("Video duration is unavailable.");const i=Math.max(0,Math.min(r.duration-.001,t%r.duration));if(Math.abs(r.currentTime-i)<.001&&r.readyState>=2)return;const s=R(r,"seeked",e);r.currentTime=i,await s},frame:()=>r,destroy:n}}catch(t){throw n(),t}}var L=t=>{if(t?.aborted)throw new DOMException("Export cancelled","AbortError")};function C(t,e,i={}){let s=l(i.settings),a=i.width??e.width,o=i.height??e.height;const r=I(t,s,i);let n=0,h=!1,c=!0,m=!1,u=!0,p=0,g=0,M=0,x=-1,v=0,w=0,b=0;const y=matchMedia("(prefers-reduced-motion: reduce)"),S=e.source instanceof HTMLVideoElement?e.source:null,E=()=>{h||n||!u||document.hidden||(n=requestAnimationFrame(A))},k=()=>!m&&!y.matches&&u&&!document.hidden,T=()=>{S&&(S.loop=!0,k()?S.play().catch(()=>{m=!0,c=!0,E()}):S.pause()),g=0,c=!0,E()};function A(t){if(n=0,h||!u||document.hidden)return;const l=k();l&&(p+=g?Math.min(.1,(t-g)/1e3):0),g=t;const f=l&&(e.animated||"none"!==s.motion.type||"none"!==s.dither.motion||s.effects.grain>0||s.effects.dust>0||s.effects.glitch>0),y=S?.getVideoPlaybackQuality?.().totalVideoFrames??-1,T="none"!==s.motion.type||"none"!==s.dither.motion||s.effects.grain>0||s.effects.dust>0||s.effects.glitch>0,A=!S||y<0||y!==x;if(c||r.active||f&&(A||T)&&t-M>=1e3/Math.max(1,Math.min(60,i.fps??60))-.5){const n=performance.now();try{e.animated&&!S&&r.invalidate();const[t,h]=d(a,o,s);r.render(e.frame(S?.currentTime??p),p,t,h);const l=performance.now()-n;i.onFrame?.(S?.currentTime??p,l),w=w?.9*w+.1*l:l,++v>20&&!1!==i.adaptive&&(b=w>13?b+1:0,b>=12&&r.maxCells>3e3&&(r.setBudget(Math.max(3e3,.8*r.maxCells)),i.onQualityChange?.(r.maxCells),b=0,w=0))}catch(t){m=!0,i.onError?.(t instanceof Error?t:new Error(String(t)))}c=!1,M=t,x=y}l&&(f||r.active)&&E()}const F=e=>{if(!k())return;const i=t.getBoundingClientRect();r.pointer((e.clientX-i.left)/i.width,(e.clientY-i.top)/i.height,e.timeStamp),E()},R=()=>{r.leave(),E()},P=new IntersectionObserver(([t])=>{u=t.isIntersecting,T()});P.observe(t),t.addEventListener("pointermove",F),t.addEventListener("pointerleave",R),t.addEventListener("pointercancel",R),document.addEventListener("visibilitychange",T),y.addEventListener("change",T);const L=()=>{h||(h=!0,cancelAnimationFrame(n),P.disconnect(),t.removeEventListener("pointermove",F),t.removeEventListener("pointerleave",R),t.removeEventListener("pointercancel",R),document.removeEventListener("visibilitychange",T),y.removeEventListener("change",T),i.signal?.removeEventListener("abort",L),r.destroy(),e.destroy())};if(i.signal?.addEventListener("abort",L,{once:!0}),i.signal?.aborted)throw L(),new DOMException("Cancelled","AbortError");return T(),{canvas:t,media:e,update(t){s=f(s,t),r.configure(s),c=!0,E()},resize(t,e){a=Math.max(2,t),o=Math.max(2,e),c=!0,E()},pause(t=!0){m=t,T()},async seek(t){p=Math.max(0,t),await e.seek(p),r.invalidate(),c=!0,E()},redraw(){r.invalidate(),c=!0,E()},get time(){return S?.currentTime??p},get paused(){return m||y.matches},get maxCells(){return r.maxCells},get capabilities(){return r.capabilities},destroy:L}}var D={Standard:()=>import("figlet/fonts/Standard"),Slant:()=>import("figlet/fonts/Slant"),Small:()=>import("figlet/fonts/Small"),Big:()=>import("figlet/fonts/Big"),Banner:()=>import("figlet/fonts/Banner"),Block:()=>import("figlet/fonts/Block"),Bubble:()=>import("figlet/fonts/Bubble"),Digital:()=>import("figlet/fonts/Digital"),Doom:()=>import("figlet/fonts/Doom"),Lean:()=>import("figlet/fonts/Lean"),Mini:()=>import("figlet/fonts/Mini"),Script:()=>import("figlet/fonts/Script"),Shadow:()=>import("figlet/fonts/Shadow"),Speed:()=>import("figlet/fonts/Speed"),Starwars:()=>import("figlet/fonts/Star Wars"),Stop:()=>import("figlet/fonts/Stop"),Straight:()=>import("figlet/fonts/Straight"),Thin:()=>import("figlet/fonts/Thin"),ThreeD:()=>import("figlet/fonts/3-D"),Univers:()=>import("figlet/fonts/Univers"),Wavy:()=>import("figlet/fonts/Wavy")},U=Object.keys(D);exports.BLEND_MODES=i,exports.DEFAULT_STUDIO_SETTINGS=a,exports.DITHER_ALGORITHMS=e,exports.STUDIO_LOOKS=m,exports.STUDIO_PALETTES=s,exports.STUDIO_STYLES=t,exports.STUDIO_TEXT_FONTS=U,exports.createStudioRenderer=I,exports.createStudioText=async function(t,e="Standard",i="#ffffff"){if(!Object.prototype.hasOwnProperty.call(D,e))throw new Error("Unknown text font.");const{default:s}=await import("figlet/browser"),a=await D[e]();s.parseFont(e,a.default),s.defaults({fetchFontIfMissing:!1});const o=s.textSync(t.slice(0,120),{font:e}),r=o.split("\n"),n=Math.max(1,...r.map(t=>t.length)),h=Math.max(1,r.length),l=Math.min(1,2048/(9*n)),c=document.createElement("canvas");c.width=Math.ceil(9*n*l+32),c.height=Math.ceil(15*h*l+32);const d=c.getContext("2d");return d.fillStyle="#080808",d.fillRect(0,0,c.width,c.height),d.fillStyle=i,d.font=15*l+"px monospace",d.textBaseline="top",r.forEach((t,e)=>d.fillText(t,16,16+15*e*l)),{canvas:c,ascii:o}},exports.exportStudio=async function(t,e,i){const{format:s,signal:a}=i,o=Math.round(i.width),r=Math.round(i.height);if(!Number.isFinite(o)||!Number.isFinite(r)||o<2||r<2||o>4096||r>4096||o*r>16777216)throw new Error("Choose export dimensions between 2 and 4096 pixels.");if(!["png","jpeg","mp4","webm","gif"].includes(s))throw new Error("Unknown export format.");if(void 0!==i.fps&&!Number.isFinite(i.fps))throw new Error("Frames per second must be finite.");const n=Math.max(1,Math.min(60,Math.round(i.fps??24))),h=i.duration??5;if(!Number.isFinite(h)||h<=0||h>60)throw new Error("Choose a duration from 0 to 60 seconds.");const c="png"===s||"jpeg"===s;if(!c&&o*r>8294400)throw new Error("Video exports support up to 3840 × 2160 pixels.");if("gif"===s&&(o*r>921600||h*n>600))throw new Error("GIF export supports up to 1280 × 720 and 600 frames. Use MP4 for larger exports.");if(void 0!==i.referenceWidth&&(!Number.isFinite(i.referenceWidth)||i.referenceWidth<1))throw new Error("Reference width must be a positive number.");if("gif"===s&&n>30)throw new Error("GIF exports support up to 30 fps. Choose MP4 or WebM for higher frame rates.");const d=document.createElement("canvas"),f=I(d,l(e),{maxDimension:4096,maxCells:i.maxCells??12e3,pixelRatio:o/(i.referenceWidth??Math.min(o,960))});let m;try{if(L(a),i.onProgress?.(0),c){if(f.render(await t.frame(0,a),0,o,r),"unavailable"===d.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");L(a);const e=await new Promise((t,e)=>d.toBlob(i=>i?t(i):e(new Error("Image export failed.")),"png"===s?"image/png":"image/jpeg",i.quality??.92));return i.onProgress?.(1),e}const e=Math.ceil(h*n);if("gif"===s){const s=await import("gifenc"),{GIFEncoder:l,quantize:c,applyPalette:m}="function"==typeof s.GIFEncoder?s:s.default,u=l(),p=d.getContext("2d");for(let s=0;s<e;s++){L(a);const l=s/n;if(f.invalidate(),f.render(await t.frame(l,a),l,o,r),"unavailable"===d.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");const g=p.getImageData(0,0,o,r).data,M=c(g,256),x=m(g,M);u.writeFrame(x,o,r,{palette:M,delay:10*(Math.round(100*Math.min((s+1)/n,h))-Math.round(100*s/n)),repeat:0}),i.onProgress?.((s+1)/e*.98),await new Promise(t=>setTimeout(t,0))}return u.finish(),i.onProgress?.(1),new Blob([new Uint8Array(u.bytes())],{type:"image/gif"})}const{Output:l,Mp4OutputFormat:u,WebMOutputFormat:p,BufferTarget:g,CanvasSource:M,canEncodeVideo:x}=await import("mediabunny"),v="mp4"===s?"avc":"vp9";if(!await x(v,{width:o,height:r}))throw new Error(`${s.toUpperCase()} encoding is unavailable in this browser. Try another format or a current browser with WebCodecs.`);const w=new l({format:"mp4"===s?new u({fastStart:"in-memory"}):new p,target:new g});d.width=o,d.height=r,m=()=>w.cancel();const b=new M(d,{codec:v,bitrate:Math.max(5e5,Math.round(o*r*n*.15))});w.addVideoTrack(b,{frameRate:n}),d.width=o,d.height=r,await w.start();for(let s=0;s<e;s++){L(a);const l=s/n;if(f.invalidate(),f.render(await t.frame(l,a),l,o,r),"unavailable"===d.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");await b.add(l,Math.min(1/n,h-l)),i.onProgress?.((s+1)/e*.98),s%4==0&&await new Promise(t=>setTimeout(t,0))}return b.close(),L(a),await w.finalize(),m=void 0,i.onProgress?.(1),new Blob([w.target.buffer],{type:"mp4"===s?"video/mp4":"video/webm"})}catch(t){throw await(m?.().catch(()=>{})),t}finally{f.destroy(),d.width=d.height=1}},exports.loadStudioMedia=P,exports.mountStudio=async function(t,e,i={}){const s=await P(e,i.signal);try{return C(t,s,i)}catch(t){throw s.destroy(),t}},exports.mountStudioMedia=C,exports.normalizeStudioSettings=l,exports.parseStudioSettings=function(t){if(t.length>1e5)throw new Error("Settings exceed 100 KB.");return l(JSON.parse(t))},exports.restyleStudio=function(t,e=Math.random){const i=m.filter(e=>e.settings.style!==t.style||e.settings.ink!==t.ink),s=u(i[Math.min(i.length-1,Math.max(0,Math.floor(e()*i.length)))].id);return s.aspectRatio=t.aspectRatio,s.crop={...t.crop},s.mask=l(t).mask,s},exports.serializeStudioSettings=function(t){return JSON.stringify(l(t))},exports.studioCrop=c,exports.studioDimensions=d,exports.studioLook=u,exports.studioSourceSize=k,exports.updateStudioSettings=f;//# sourceMappingURL=studio.cjs.map
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import * as figlet_fonts_Wavy from 'figlet/fonts/Wavy';
|
|
2
|
+
import * as figlet_fonts_Univers from 'figlet/fonts/Univers';
|
|
3
|
+
import * as figlet_fonts_3_D from 'figlet/fonts/3-D';
|
|
4
|
+
import * as figlet_fonts_Thin from 'figlet/fonts/Thin';
|
|
5
|
+
import * as figlet_fonts_Straight from 'figlet/fonts/Straight';
|
|
6
|
+
import * as figlet_fonts_Stop from 'figlet/fonts/Stop';
|
|
7
|
+
import * as figlet_fonts_Star_Wars from 'figlet/fonts/Star Wars';
|
|
8
|
+
import * as figlet_fonts_Speed from 'figlet/fonts/Speed';
|
|
9
|
+
import * as figlet_fonts_Shadow from 'figlet/fonts/Shadow';
|
|
10
|
+
import * as figlet_fonts_Script from 'figlet/fonts/Script';
|
|
11
|
+
import * as figlet_fonts_Mini from 'figlet/fonts/Mini';
|
|
12
|
+
import * as figlet_fonts_Lean from 'figlet/fonts/Lean';
|
|
13
|
+
import * as figlet_fonts_Doom from 'figlet/fonts/Doom';
|
|
14
|
+
import * as figlet_fonts_Digital from 'figlet/fonts/Digital';
|
|
15
|
+
import * as figlet_fonts_Bubble from 'figlet/fonts/Bubble';
|
|
16
|
+
import * as figlet_fonts_Block from 'figlet/fonts/Block';
|
|
17
|
+
import * as figlet_fonts_Banner from 'figlet/fonts/Banner';
|
|
18
|
+
import * as figlet_fonts_Big from 'figlet/fonts/Big';
|
|
19
|
+
import * as figlet_fonts_Small from 'figlet/fonts/Small';
|
|
20
|
+
import * as figlet_fonts_Slant from 'figlet/fonts/Slant';
|
|
21
|
+
import * as figlet_fonts_Standard from 'figlet/fonts/Standard';
|
|
22
|
+
|
|
23
|
+
/** Serializable, media-independent editing state. No DOM work at import time. */
|
|
24
|
+
declare const STUDIO_STYLES: readonly ["ascii", "blocks", "braille", "dots", "lines", "cross", "diagonal", "diamond", "mixed", "pixel", "mosaic", "lego", "voxel", "disco", "dither"];
|
|
25
|
+
type StudioStyle = (typeof STUDIO_STYLES)[number];
|
|
26
|
+
declare const DITHER_ALGORITHMS: readonly ["none", "bayer2", "bayer4", "bayer8", "bayer16", "floyd-steinberg", "atkinson", "stucki", "sierra", "sierra-lite", "burkes", "jarvis", "halftone", "lines", "noise"];
|
|
27
|
+
type DitherAlgorithm = (typeof DITHER_ALGORITHMS)[number];
|
|
28
|
+
declare const BLEND_MODES: readonly ["source-over", "multiply", "screen", "overlay", "soft-light", "hard-light", "color-dodge", "color-burn", "hue", "saturation", "color", "luminosity"];
|
|
29
|
+
declare const STUDIO_PALETTES: Record<string, readonly string[]>;
|
|
30
|
+
interface StudioMask {
|
|
31
|
+
kind: "rectangle" | "ellipse" | "brush";
|
|
32
|
+
x: number;
|
|
33
|
+
y: number;
|
|
34
|
+
width: number;
|
|
35
|
+
height: number;
|
|
36
|
+
points?: [number, number][];
|
|
37
|
+
size?: number;
|
|
38
|
+
}
|
|
39
|
+
interface StudioLight {
|
|
40
|
+
x: number;
|
|
41
|
+
y: number;
|
|
42
|
+
radius: number;
|
|
43
|
+
intensity: number;
|
|
44
|
+
color: string;
|
|
45
|
+
}
|
|
46
|
+
interface StudioSettings {
|
|
47
|
+
version: 1;
|
|
48
|
+
aspectRatio: "original" | "16:9" | "9:16" | "1:1" | "4:3" | "3:4" | "21:9";
|
|
49
|
+
style: StudioStyle;
|
|
50
|
+
cellSize: number;
|
|
51
|
+
charset: string;
|
|
52
|
+
colorMode: "accent" | "source" | "gray";
|
|
53
|
+
ink: string;
|
|
54
|
+
crop: {
|
|
55
|
+
x: number;
|
|
56
|
+
y: number;
|
|
57
|
+
zoom: number;
|
|
58
|
+
rotation: number;
|
|
59
|
+
};
|
|
60
|
+
backdrop: {
|
|
61
|
+
mode: "solid" | "transparent" | "source" | "blurred" | "gradient";
|
|
62
|
+
color: string;
|
|
63
|
+
color2: string;
|
|
64
|
+
blur: number;
|
|
65
|
+
opacity: number;
|
|
66
|
+
};
|
|
67
|
+
color: {
|
|
68
|
+
brightness: number;
|
|
69
|
+
contrast: number;
|
|
70
|
+
saturation: number;
|
|
71
|
+
grayscale: number;
|
|
72
|
+
tint: string;
|
|
73
|
+
amount: number;
|
|
74
|
+
blend: (typeof BLEND_MODES)[number];
|
|
75
|
+
};
|
|
76
|
+
dither: {
|
|
77
|
+
algorithm: DitherAlgorithm;
|
|
78
|
+
palette: string;
|
|
79
|
+
colors: string[];
|
|
80
|
+
amount: number;
|
|
81
|
+
scale: number;
|
|
82
|
+
threshold: number;
|
|
83
|
+
motion: "none" | "drift" | "shimmer";
|
|
84
|
+
speed: number;
|
|
85
|
+
};
|
|
86
|
+
mask: {
|
|
87
|
+
enabled: boolean;
|
|
88
|
+
invert: boolean;
|
|
89
|
+
shapes: StudioMask[];
|
|
90
|
+
};
|
|
91
|
+
lights: StudioLight[];
|
|
92
|
+
effects: {
|
|
93
|
+
bloom: number;
|
|
94
|
+
characterBloom: number;
|
|
95
|
+
grain: number;
|
|
96
|
+
dust: number;
|
|
97
|
+
scanlines: number;
|
|
98
|
+
crt: number;
|
|
99
|
+
prism: number;
|
|
100
|
+
vignette: number;
|
|
101
|
+
glitch: number;
|
|
102
|
+
pixelate: number;
|
|
103
|
+
blur: number;
|
|
104
|
+
blurType: "gaussian" | "directional" | "radial" | "progressive";
|
|
105
|
+
angle: number;
|
|
106
|
+
focus: number;
|
|
107
|
+
halftone: number;
|
|
108
|
+
};
|
|
109
|
+
motion: {
|
|
110
|
+
type: "none" | "breathe" | "wave" | "reveal" | "glitch" | "rainbow" | "hologram" | "fire" | "chrome" | "ripple" | "vapor";
|
|
111
|
+
speed: number;
|
|
112
|
+
};
|
|
113
|
+
hover: {
|
|
114
|
+
effect: "none" | "trail" | "water" | "contour" | "dissolve" | "silk" | "vortex";
|
|
115
|
+
strength: number;
|
|
116
|
+
radius: number;
|
|
117
|
+
edgeSafe: boolean;
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
declare const DEFAULT_STUDIO_SETTINGS: StudioSettings;
|
|
121
|
+
/** Whitelist external settings; reject future versions instead of misinterpreting them. */
|
|
122
|
+
declare function normalizeStudioSettings(input?: unknown): StudioSettings;
|
|
123
|
+
declare function serializeStudioSettings(settings: StudioSettings): string;
|
|
124
|
+
declare function parseStudioSettings(json: string): StudioSettings;
|
|
125
|
+
declare function studioCrop(sw: number, sh: number, w: number, h: number, c: StudioSettings["crop"]): {
|
|
126
|
+
width: number;
|
|
127
|
+
height: number;
|
|
128
|
+
x: number;
|
|
129
|
+
y: number;
|
|
130
|
+
scale: number;
|
|
131
|
+
rotated: boolean;
|
|
132
|
+
};
|
|
133
|
+
/** Dimensions for the saved canvas ratio, including source rotation. */
|
|
134
|
+
declare function studioDimensions(width: number, height: number, settings: StudioSettings): [number, number];
|
|
135
|
+
/** Partial configuration for mounting and incremental updates. Arrays replace previous arrays. */
|
|
136
|
+
type StudioInput = {
|
|
137
|
+
[K in keyof StudioSettings]?: StudioSettings[K] extends readonly unknown[] ? StudioSettings[K] : StudioSettings[K] extends object ? Partial<StudioSettings[K]> : StudioSettings[K];
|
|
138
|
+
};
|
|
139
|
+
declare function updateStudioSettings(current: StudioSettings, patch: StudioInput): StudioSettings;
|
|
140
|
+
|
|
141
|
+
declare const STUDIO_LOOKS: {
|
|
142
|
+
id: string;
|
|
143
|
+
name: string;
|
|
144
|
+
description: string;
|
|
145
|
+
settings: StudioSettings;
|
|
146
|
+
}[];
|
|
147
|
+
/** Return independent state; applying or editing a look never mutates its preset. */
|
|
148
|
+
declare function studioLook(id: string): StudioSettings;
|
|
149
|
+
declare function restyleStudio(current: StudioSettings, random?: () => number): StudioSettings;
|
|
150
|
+
|
|
151
|
+
type StudioSource = HTMLImageElement | HTMLVideoElement | HTMLCanvasElement | ImageBitmap;
|
|
152
|
+
declare function studioSourceSize(s: StudioSource): [number, number];
|
|
153
|
+
/** Reusable bounded renderer. Call configure only when settings change; render owns no RAF. */
|
|
154
|
+
declare function createStudioRenderer(canvas: HTMLCanvasElement, settings?: unknown, limits?: {
|
|
155
|
+
maxDimension?: number;
|
|
156
|
+
maxCells?: number;
|
|
157
|
+
pixelRatio?: number;
|
|
158
|
+
}): {
|
|
159
|
+
canvas: HTMLCanvasElement;
|
|
160
|
+
render: (source: StudioSource, time?: number, requestedWidth?: number, requestedHeight?: number) => void;
|
|
161
|
+
setBudget(cells: number): void;
|
|
162
|
+
readonly maxCells: number;
|
|
163
|
+
configure(input: unknown): void;
|
|
164
|
+
pointer: (x: number, y: number, time: number) => void;
|
|
165
|
+
leave(): void;
|
|
166
|
+
readonly active: boolean;
|
|
167
|
+
readonly settings: StudioSettings;
|
|
168
|
+
readonly capabilities: {
|
|
169
|
+
gpuFinish: boolean;
|
|
170
|
+
};
|
|
171
|
+
invalidate(): void;
|
|
172
|
+
destroy(): void;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
interface StudioMedia {
|
|
176
|
+
source: StudioSource;
|
|
177
|
+
width: number;
|
|
178
|
+
height: number;
|
|
179
|
+
duration: number;
|
|
180
|
+
animated: boolean;
|
|
181
|
+
seek(time: number, signal?: AbortSignal): Promise<void>;
|
|
182
|
+
frame(time: number): StudioSource;
|
|
183
|
+
destroy(): void;
|
|
184
|
+
}
|
|
185
|
+
/** Local File or permitted CORS URL. Caller owns destroy; URLs created here are revoked. */
|
|
186
|
+
declare function loadStudioMedia(input: File | string, signal?: AbortSignal): Promise<StudioMedia>;
|
|
187
|
+
|
|
188
|
+
type StudioExportFormat = "png" | "jpeg" | "mp4" | "webm" | "gif";
|
|
189
|
+
interface StudioExportOptions {
|
|
190
|
+
format: StudioExportFormat;
|
|
191
|
+
width: number;
|
|
192
|
+
height: number;
|
|
193
|
+
duration?: number;
|
|
194
|
+
fps?: number;
|
|
195
|
+
quality?: number;
|
|
196
|
+
signal?: AbortSignal;
|
|
197
|
+
onProgress?: (progress: number) => void;
|
|
198
|
+
maxCells?: number;
|
|
199
|
+
/** Preview canvas width, for identical cell density when upscaling. */
|
|
200
|
+
referenceWidth?: number;
|
|
201
|
+
}
|
|
202
|
+
interface StudioExportSource {
|
|
203
|
+
frame(time: number, signal?: AbortSignal): StudioSource | Promise<StudioSource>;
|
|
204
|
+
}
|
|
205
|
+
/** A separate renderer preserves preview state. The source callback must also be independent for video exports. */
|
|
206
|
+
declare function exportStudio(source: StudioExportSource, settings: StudioSettings, options: StudioExportOptions): Promise<Blob>;
|
|
207
|
+
|
|
208
|
+
interface MountStudioOptions {
|
|
209
|
+
settings?: StudioInput;
|
|
210
|
+
width?: number;
|
|
211
|
+
height?: number;
|
|
212
|
+
fps?: number;
|
|
213
|
+
maxDimension?: number;
|
|
214
|
+
maxCells?: number;
|
|
215
|
+
adaptive?: boolean;
|
|
216
|
+
onQualityChange?: (maxCells: number) => void;
|
|
217
|
+
signal?: AbortSignal;
|
|
218
|
+
onError?: (error: Error) => void;
|
|
219
|
+
onFrame?: (time: number, costMs: number) => void;
|
|
220
|
+
}
|
|
221
|
+
/** Mount one source, update serializable settings, and destroy on unmount. */
|
|
222
|
+
declare function mountStudio(canvas: HTMLCanvasElement, source: File | string, options?: MountStudioOptions): Promise<{
|
|
223
|
+
canvas: HTMLCanvasElement;
|
|
224
|
+
media: StudioMedia;
|
|
225
|
+
update(next: StudioInput): void;
|
|
226
|
+
resize(w: number, h: number): void;
|
|
227
|
+
pause(value?: boolean): void;
|
|
228
|
+
seek(seconds: number): Promise<void>;
|
|
229
|
+
redraw(): void;
|
|
230
|
+
readonly time: number;
|
|
231
|
+
readonly paused: boolean;
|
|
232
|
+
readonly maxCells: number;
|
|
233
|
+
readonly capabilities: {
|
|
234
|
+
gpuFinish: boolean;
|
|
235
|
+
};
|
|
236
|
+
destroy: () => void;
|
|
237
|
+
}>;
|
|
238
|
+
/** Takes ownership of media. Use a second media instance for export. */
|
|
239
|
+
declare function mountStudioMedia(canvas: HTMLCanvasElement, media: StudioMedia, options?: MountStudioOptions): {
|
|
240
|
+
canvas: HTMLCanvasElement;
|
|
241
|
+
media: StudioMedia;
|
|
242
|
+
update(next: StudioInput): void;
|
|
243
|
+
resize(w: number, h: number): void;
|
|
244
|
+
pause(value?: boolean): void;
|
|
245
|
+
seek(seconds: number): Promise<void>;
|
|
246
|
+
redraw(): void;
|
|
247
|
+
readonly time: number;
|
|
248
|
+
readonly paused: boolean;
|
|
249
|
+
readonly maxCells: number;
|
|
250
|
+
readonly capabilities: {
|
|
251
|
+
gpuFinish: boolean;
|
|
252
|
+
};
|
|
253
|
+
destroy: () => void;
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
/** Fonts are loaded individually only when selected; none enter the core renderer. */
|
|
257
|
+
declare const loaders: {
|
|
258
|
+
Standard: () => Promise<typeof figlet_fonts_Standard>;
|
|
259
|
+
Slant: () => Promise<typeof figlet_fonts_Slant>;
|
|
260
|
+
Small: () => Promise<typeof figlet_fonts_Small>;
|
|
261
|
+
Big: () => Promise<typeof figlet_fonts_Big>;
|
|
262
|
+
Banner: () => Promise<typeof figlet_fonts_Banner>;
|
|
263
|
+
Block: () => Promise<typeof figlet_fonts_Block>;
|
|
264
|
+
Bubble: () => Promise<typeof figlet_fonts_Bubble>;
|
|
265
|
+
Digital: () => Promise<typeof figlet_fonts_Digital>;
|
|
266
|
+
Doom: () => Promise<typeof figlet_fonts_Doom>;
|
|
267
|
+
Lean: () => Promise<typeof figlet_fonts_Lean>;
|
|
268
|
+
Mini: () => Promise<typeof figlet_fonts_Mini>;
|
|
269
|
+
Script: () => Promise<typeof figlet_fonts_Script>;
|
|
270
|
+
Shadow: () => Promise<typeof figlet_fonts_Shadow>;
|
|
271
|
+
Speed: () => Promise<typeof figlet_fonts_Speed>;
|
|
272
|
+
Starwars: () => Promise<typeof figlet_fonts_Star_Wars>;
|
|
273
|
+
Stop: () => Promise<typeof figlet_fonts_Stop>;
|
|
274
|
+
Straight: () => Promise<typeof figlet_fonts_Straight>;
|
|
275
|
+
Thin: () => Promise<typeof figlet_fonts_Thin>;
|
|
276
|
+
ThreeD: () => Promise<typeof figlet_fonts_3_D>;
|
|
277
|
+
Univers: () => Promise<typeof figlet_fonts_Univers>;
|
|
278
|
+
Wavy: () => Promise<typeof figlet_fonts_Wavy>;
|
|
279
|
+
};
|
|
280
|
+
declare const STUDIO_TEXT_FONTS: (keyof typeof loaders)[];
|
|
281
|
+
declare function createStudioText(text: string, font?: keyof typeof loaders, ink?: string): Promise<{
|
|
282
|
+
canvas: HTMLCanvasElement;
|
|
283
|
+
ascii: string;
|
|
284
|
+
}>;
|
|
285
|
+
|
|
286
|
+
export { BLEND_MODES, DEFAULT_STUDIO_SETTINGS, DITHER_ALGORITHMS, type DitherAlgorithm, type MountStudioOptions, 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 };
|