asciify-engine 4.4.0 → 4.6.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 +21 -1
- package/dist/core.d.cts +1 -1
- package/dist/core.d.ts +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/{model-BOcK8oM-.d.cts → model-BR3qK_NW.d.cts} +23 -2
- package/dist/{model-BhR1zliO.d.ts → model-Tyu-NpVf.d.ts} +23 -2
- package/dist/studio.cjs +1 -1
- package/dist/studio.d.cts +6 -2
- package/dist/studio.d.ts +6 -2
- package/dist/studio.js +1 -1
- package/examples/studio-composition.ts +1 -1
- package/package.json +1 -1
- package/skills/asciify-engine/SKILL.md +6 -2
- package/skills/asciify-engine/references/studio-workspace.md +55 -1
- package/skills/asciify-engine/references/upgrading.md +7 -0
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<a href="https://www.buymeacoffee.com/asciify"><img src="https://img.shields.io/badge/buy_me_a_coffee-%E2%98%95-d4ff00?labelColor=0a0a0a&style=flat-square" alt="Buy Me A Coffee" /></a>
|
|
8
8
|
</p>
|
|
9
9
|
|
|
10
|
-
A framework-agnostic ASCII art rendering engine for the browser. Convert images, animated GIFs, and video into character-based art rendered onto an HTML canvas — with full color support, interactive hover effects, living-image motion,
|
|
10
|
+
A framework-agnostic ASCII art rendering engine for the browser. Convert images, animated GIFs, and video into character-based art rendered onto an HTML canvas — with full color support, interactive hover effects, living-image motion, 18 Studio render styles, and export.
|
|
11
11
|
|
|
12
12
|
### Media first, optional backgrounds
|
|
13
13
|
|
|
@@ -560,3 +560,23 @@ player.update({
|
|
|
560
560
|
```
|
|
561
561
|
|
|
562
562
|
All motion choices repeat every `12 / speed` seconds. Still exports preserve the selected preview phase; animated exports include motion without pointer events. Grain, dust, glitch, animated dither and source video have separate timing. No external AI service is used. See [effect integration](skills/asciify-engine/references/studio-effects.md).
|
|
563
|
+
|
|
564
|
+
### Tonal detail and blue-noise dithering (4.5)
|
|
565
|
+
|
|
566
|
+
Studio adds `dither.algorithm: 'blue-noise'`: a stable precomputed dispersed pattern with no runtime generation or asset download. `noise` remains white noise. Choose the algorithm from `DITHER_ALGORITHMS`; drift and shimmer remain independently controlled.
|
|
567
|
+
|
|
568
|
+
Recover usable shadow/highlight separation before conversion with `color.gamma`, `shadows`, `highlights`, `blackPoint` and `whitePoint`. All 18 styles share these controls and retain neutral defaults. They are a bounded monotone tonal curve, not arbitrary per-channel curve editing. See [exact ranges, sampling budgets and a live-project example](skills/asciify-engine/references/studio-workspace.md#tonal-detail-and-blue-noise-45).
|
|
569
|
+
|
|
570
|
+
### Channel curves and source noise reduction (4.6)
|
|
571
|
+
|
|
572
|
+
Studio adds editable RGB, red, green and blue curves, with up to 16 control points each, plus optional edge-preserving source noise reduction. They apply before every render style and travel with saved settings and exports. Defaults preserve existing output. Curves use small cached lookups; still images reuse filtered pixels while hover/motion run. Dense video filtering is an explicit CPU tradeoff.
|
|
573
|
+
|
|
574
|
+
```ts
|
|
575
|
+
player.update({color:{
|
|
576
|
+
denoise:.25,
|
|
577
|
+
curves:{rgb:[[0,0],[.25,.2],[.75,.8],[1,1]]},
|
|
578
|
+
}});
|
|
579
|
+
const settings = player.settings; // detached snapshot for save/export
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
See [settings, normalization, processing order and performance guidance](skills/asciify-engine/references/studio-workspace.md#channel-curves-and-source-noise-46). Curves are local source controls, not another art-style alias or AI restoration.
|
package/dist/core.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as AsciiOptions, A as AsciiFrame, b as ArtStyle, H as HoverEffect } from './types-D38BMBRB.cjs';
|
|
2
2
|
export { c as AnimationStyle, d as AsciiCell, e as AsciiResult, C as ColorMode, D as DEFAULT_OPTIONS, f as HOVER_PRESETS, g as HoverPreset, h as HoverShape, P as PALETTE_THEMES, i as PaletteTheme, R as RenderMode, S as SourceType } from './types-D38BMBRB.cjs';
|
|
3
|
-
export { C as CHARACTER_SETS,
|
|
3
|
+
export { C as CHARACTER_SETS, g as STUDIO_STYLES, m as StudioStyle } from './model-BR3qK_NW.cjs';
|
|
4
4
|
import './hover-catalog-BeIkNwhH.cjs';
|
|
5
5
|
|
|
6
6
|
/**
|
package/dist/core.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as AsciiOptions, A as AsciiFrame, b as ArtStyle, H as HoverEffect } from './types-C05AfrjT.js';
|
|
2
2
|
export { c as AnimationStyle, d as AsciiCell, e as AsciiResult, C as ColorMode, D as DEFAULT_OPTIONS, f as HOVER_PRESETS, g as HoverPreset, h as HoverShape, P as PALETTE_THEMES, i as PaletteTheme, R as RenderMode, S as SourceType } from './types-C05AfrjT.js';
|
|
3
|
-
export { C as CHARACTER_SETS,
|
|
3
|
+
export { C as CHARACTER_SETS, g as STUDIO_STYLES, m as StudioStyle } from './model-Tyu-NpVf.js';
|
|
4
4
|
import './hover-catalog-BeIkNwhH.js';
|
|
5
5
|
|
|
6
6
|
/**
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { c as AnimationStyle, b as ArtStyle, d as AsciiCell, A as AsciiFrame, a as AsciiOptions, e as AsciiResult, C as ColorMode, D as DEFAULT_OPTIONS, f as HOVER_PRESETS, H as HoverEffect, g as HoverPreset, h as HoverShape, P as PALETTE_THEMES, i as PaletteTheme, R as RenderMode, S as SourceType } from './types-D38BMBRB.cjs';
|
|
2
2
|
export { AsciiTextFrame, AsciifyLiveVideoOptions, AsciifySimpleOptions, AsciifyVideoOptions, BigTextOptions, CanvasBleed, CanvasObjectFit, CanvasRenderSizeInput, SnapshotOptions, TextBackgroundOptions, VideoScrollScrubOptions, WebcamOptions, asciiText, asciiTextAnsi, asciify, asciifyGif, asciifyLiveVideo, asciifyText, asciifyVideo, asciifyWebcam, buildTextFrame, captureSnapshot, clearAsciifyCaches, computeCanvasRenderSize, createVideoScrollScrub, gifToAsciiFrames, gifToAsciiTextFrames, imageToAsciiFrame, imageToAsciiTextFrame, renderFrameToCanvas, renderTextBackground, renderTextFrameToCanvas, renderTextToCanvas, snapshotAndDownload, videoToAsciiFrames, videoToAsciiTextFrames } from './core.cjs';
|
|
3
|
-
export { C as CHARACTER_SETS,
|
|
3
|
+
export { C as CHARACTER_SETS, g as STUDIO_STYLES, m as StudioStyle } from './model-BR3qK_NW.cjs';
|
|
4
4
|
import './hover-catalog-BeIkNwhH.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { c as AnimationStyle, b as ArtStyle, d as AsciiCell, A as AsciiFrame, a as AsciiOptions, e as AsciiResult, C as ColorMode, D as DEFAULT_OPTIONS, f as HOVER_PRESETS, H as HoverEffect, g as HoverPreset, h as HoverShape, P as PALETTE_THEMES, i as PaletteTheme, R as RenderMode, S as SourceType } from './types-C05AfrjT.js';
|
|
2
2
|
export { AsciiTextFrame, AsciifyLiveVideoOptions, AsciifySimpleOptions, AsciifyVideoOptions, BigTextOptions, CanvasBleed, CanvasObjectFit, CanvasRenderSizeInput, SnapshotOptions, TextBackgroundOptions, VideoScrollScrubOptions, WebcamOptions, asciiText, asciiTextAnsi, asciify, asciifyGif, asciifyLiveVideo, asciifyText, asciifyVideo, asciifyWebcam, buildTextFrame, captureSnapshot, clearAsciifyCaches, computeCanvasRenderSize, createVideoScrollScrub, gifToAsciiFrames, gifToAsciiTextFrames, imageToAsciiFrame, imageToAsciiTextFrame, renderFrameToCanvas, renderTextBackground, renderTextFrameToCanvas, renderTextToCanvas, snapshotAndDownload, videoToAsciiFrames, videoToAsciiTextFrames } from './core.js';
|
|
3
|
-
export { C as CHARACTER_SETS,
|
|
3
|
+
export { C as CHARACTER_SETS, g as STUDIO_STYLES, m as StudioStyle } from './model-Tyu-NpVf.js';
|
|
4
4
|
import './hover-catalog-BeIkNwhH.js';
|
|
@@ -70,10 +70,24 @@ declare const STUDIO_CHARACTER_SETS: {
|
|
|
70
70
|
};
|
|
71
71
|
};
|
|
72
72
|
|
|
73
|
+
/** Input/output coordinates use 0–1. Curves have at most 16 points, including endpoints. */
|
|
74
|
+
type StudioCurvePoint = [number, number];
|
|
75
|
+
declare const STUDIO_CURVE_CHANNELS: readonly ["rgb", "red", "green", "blue"];
|
|
76
|
+
type StudioCurveChannel = typeof STUDIO_CURVE_CHANNELS[number];
|
|
77
|
+
type StudioCurves = Record<StudioCurveChannel, StudioCurvePoint[]>;
|
|
78
|
+
/** Accept saved settings safely. Repeated inputs keep the last valid point. */
|
|
79
|
+
declare function normalizeStudioCurve(input: unknown): StudioCurvePoint[];
|
|
80
|
+
declare function normalizeStudioCurves(input: unknown): StudioCurves;
|
|
81
|
+
/** Shape-preserving cubic interpolation: no overshoot between control points.
|
|
82
|
+
* The same 256 samples drive the editor graph and the pre-conversion transform.
|
|
83
|
+
* Build on settings changes, never inside the per-pixel loop.
|
|
84
|
+
*/
|
|
85
|
+
declare function createStudioCurveLookup(input: unknown): Uint8Array;
|
|
86
|
+
|
|
73
87
|
/** Serializable, media-independent editing state. No DOM work at import time. */
|
|
74
88
|
declare const STUDIO_STYLES: readonly ["ascii", "blocks", "braille", "dots", "lines", "cross", "diagonal", "diamond", "mixed", "pixel", "mosaic", "lego", "voxel", "disco", "dither", "hex", "led", "cmyk"];
|
|
75
89
|
type StudioStyle = (typeof STUDIO_STYLES)[number];
|
|
76
|
-
declare const DITHER_ALGORITHMS: readonly ["none", "bayer2", "bayer4", "bayer8", "bayer16", "floyd-steinberg", "atkinson", "stucki", "sierra", "sierra-lite", "burkes", "jarvis", "halftone", "lines", "noise", "vertical-lines", "diagonal-lines", "radial"];
|
|
90
|
+
declare const DITHER_ALGORITHMS: readonly ["none", "bayer2", "bayer4", "bayer8", "bayer16", "floyd-steinberg", "atkinson", "stucki", "sierra", "sierra-lite", "burkes", "jarvis", "halftone", "lines", "noise", "vertical-lines", "diagonal-lines", "radial", "blue-noise"];
|
|
77
91
|
type DitherAlgorithm = (typeof DITHER_ALGORITHMS)[number];
|
|
78
92
|
declare const BLEND_MODES: readonly ["source-over", "multiply", "screen", "overlay", "soft-light", "hard-light", "color-dodge", "color-burn", "hue", "saturation", "color", "luminosity"];
|
|
79
93
|
declare const STUDIO_PALETTES: Record<string, readonly string[]>;
|
|
@@ -122,6 +136,13 @@ interface StudioSettings {
|
|
|
122
136
|
tint: string;
|
|
123
137
|
amount: number;
|
|
124
138
|
blend: (typeof BLEND_MODES)[number];
|
|
139
|
+
blackPoint?: number;
|
|
140
|
+
whitePoint?: number;
|
|
141
|
+
gamma?: number;
|
|
142
|
+
shadows?: number;
|
|
143
|
+
highlights?: number;
|
|
144
|
+
curves?: Partial<StudioCurves>;
|
|
145
|
+
denoise?: number;
|
|
125
146
|
};
|
|
126
147
|
dither: {
|
|
127
148
|
algorithm: DitherAlgorithm;
|
|
@@ -204,4 +225,4 @@ declare function studioGrid(width: number, height: number, settings: Pick<Studio
|
|
|
204
225
|
limited: boolean;
|
|
205
226
|
};
|
|
206
227
|
|
|
207
|
-
export { BLEND_MODES as B, CHARACTER_SETS as C, DEFAULT_STUDIO_SETTINGS as D, type StudioSettings as S, type StudioInput as a, DITHER_ALGORITHMS as b, type DitherAlgorithm as c, STUDIO_CHARACTER_SETS as d,
|
|
228
|
+
export { BLEND_MODES as B, CHARACTER_SETS as C, DEFAULT_STUDIO_SETTINGS as D, type StudioSettings as S, type StudioInput as a, DITHER_ALGORITHMS as b, type DitherAlgorithm as c, STUDIO_CHARACTER_SETS as d, STUDIO_CURVE_CHANNELS as e, STUDIO_PALETTES as f, STUDIO_STYLES as g, type StudioCurveChannel as h, type StudioCurvePoint as i, type StudioCurves as j, type StudioLight as k, type StudioMask as l, type StudioStyle as m, createStudioCurveLookup as n, normalizeStudioCurve as o, normalizeStudioCurves as p, normalizeStudioSettings as q, parseStudioSettings as r, serializeStudioSettings as s, studioCrop as t, studioDimensions as u, studioGrid as v, updateStudioSettings as w };
|
|
@@ -70,10 +70,24 @@ declare const STUDIO_CHARACTER_SETS: {
|
|
|
70
70
|
};
|
|
71
71
|
};
|
|
72
72
|
|
|
73
|
+
/** Input/output coordinates use 0–1. Curves have at most 16 points, including endpoints. */
|
|
74
|
+
type StudioCurvePoint = [number, number];
|
|
75
|
+
declare const STUDIO_CURVE_CHANNELS: readonly ["rgb", "red", "green", "blue"];
|
|
76
|
+
type StudioCurveChannel = typeof STUDIO_CURVE_CHANNELS[number];
|
|
77
|
+
type StudioCurves = Record<StudioCurveChannel, StudioCurvePoint[]>;
|
|
78
|
+
/** Accept saved settings safely. Repeated inputs keep the last valid point. */
|
|
79
|
+
declare function normalizeStudioCurve(input: unknown): StudioCurvePoint[];
|
|
80
|
+
declare function normalizeStudioCurves(input: unknown): StudioCurves;
|
|
81
|
+
/** Shape-preserving cubic interpolation: no overshoot between control points.
|
|
82
|
+
* The same 256 samples drive the editor graph and the pre-conversion transform.
|
|
83
|
+
* Build on settings changes, never inside the per-pixel loop.
|
|
84
|
+
*/
|
|
85
|
+
declare function createStudioCurveLookup(input: unknown): Uint8Array;
|
|
86
|
+
|
|
73
87
|
/** Serializable, media-independent editing state. No DOM work at import time. */
|
|
74
88
|
declare const STUDIO_STYLES: readonly ["ascii", "blocks", "braille", "dots", "lines", "cross", "diagonal", "diamond", "mixed", "pixel", "mosaic", "lego", "voxel", "disco", "dither", "hex", "led", "cmyk"];
|
|
75
89
|
type StudioStyle = (typeof STUDIO_STYLES)[number];
|
|
76
|
-
declare const DITHER_ALGORITHMS: readonly ["none", "bayer2", "bayer4", "bayer8", "bayer16", "floyd-steinberg", "atkinson", "stucki", "sierra", "sierra-lite", "burkes", "jarvis", "halftone", "lines", "noise", "vertical-lines", "diagonal-lines", "radial"];
|
|
90
|
+
declare const DITHER_ALGORITHMS: readonly ["none", "bayer2", "bayer4", "bayer8", "bayer16", "floyd-steinberg", "atkinson", "stucki", "sierra", "sierra-lite", "burkes", "jarvis", "halftone", "lines", "noise", "vertical-lines", "diagonal-lines", "radial", "blue-noise"];
|
|
77
91
|
type DitherAlgorithm = (typeof DITHER_ALGORITHMS)[number];
|
|
78
92
|
declare const BLEND_MODES: readonly ["source-over", "multiply", "screen", "overlay", "soft-light", "hard-light", "color-dodge", "color-burn", "hue", "saturation", "color", "luminosity"];
|
|
79
93
|
declare const STUDIO_PALETTES: Record<string, readonly string[]>;
|
|
@@ -122,6 +136,13 @@ interface StudioSettings {
|
|
|
122
136
|
tint: string;
|
|
123
137
|
amount: number;
|
|
124
138
|
blend: (typeof BLEND_MODES)[number];
|
|
139
|
+
blackPoint?: number;
|
|
140
|
+
whitePoint?: number;
|
|
141
|
+
gamma?: number;
|
|
142
|
+
shadows?: number;
|
|
143
|
+
highlights?: number;
|
|
144
|
+
curves?: Partial<StudioCurves>;
|
|
145
|
+
denoise?: number;
|
|
125
146
|
};
|
|
126
147
|
dither: {
|
|
127
148
|
algorithm: DitherAlgorithm;
|
|
@@ -204,4 +225,4 @@ declare function studioGrid(width: number, height: number, settings: Pick<Studio
|
|
|
204
225
|
limited: boolean;
|
|
205
226
|
};
|
|
206
227
|
|
|
207
|
-
export { BLEND_MODES as B, CHARACTER_SETS as C, DEFAULT_STUDIO_SETTINGS as D, type StudioSettings as S, type StudioInput as a, DITHER_ALGORITHMS as b, type DitherAlgorithm as c, STUDIO_CHARACTER_SETS as d,
|
|
228
|
+
export { BLEND_MODES as B, CHARACTER_SETS as C, DEFAULT_STUDIO_SETTINGS as D, type StudioSettings as S, type StudioInput as a, DITHER_ALGORITHMS as b, type DitherAlgorithm as c, STUDIO_CHARACTER_SETS as d, STUDIO_CURVE_CHANNELS as e, STUDIO_PALETTES as f, STUDIO_STYLES as g, type StudioCurveChannel as h, type StudioCurvePoint as i, type StudioCurves as j, type StudioLight as k, type StudioMask as l, type StudioStyle as m, createStudioCurveLookup as n, normalizeStudioCurve as o, normalizeStudioCurves as p, normalizeStudioSettings as q, parseStudioSettings as r, serializeStudioSettings as s, studioCrop as t, studioDimensions as u, studioGrid as v, updateStudioSettings as w };
|
package/dist/studio.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var t=[{value:"none",label:"Off",group:"Still",description:"Keep the artwork still under the pointer."},{value:"trail",label:"Trail",group:"Change characters",description:"A fluid wake changes character density and settles behind your cursor."},{value:"dissolve",label:"Dissolve",group:"Change characters",description:"Erase a soft path through the characters; the image gradually reforms."},{value:"contour",label:"Contour",group:"Change characters",description:"Fine tonal rings trace your path without moving the grid."},{value:"etch",label:"Emboss",group:"Change characters",description:"Press a light-and-shadow impression into the characters; the grid stays fixed."},{value:"water",label:"Water",group:"Move the image",description:"Soft ripples refract the image and settle after your stroke."},{value:"silk",label:"Silk",group:"Move the image",description:"Directional folds follow the movement of your hand."},{value:"vortex",label:"Vortex",group:"Move the image",description:"A swirling wake curls through the image."},{value:"magnetic",label:"Magnetic Pull",group:"Move the image",description:"The image gathers toward your stroke, then relaxes."},{value:"scatter",label:"Scatter",group:"Move the image",description:"A textured outward scatter settles behind your cursor."},{value:"elastic",label:"Elastic",group:"Move the image",description:"Push the image with your stroke; it recoils and springs back into place."},{value:"rake",label:"Rake",group:"Move the image",description:"Comb the image into alternating ribbons that glide back into alignment."}],e=[{value:"none",mode:"none",group:"Still",label:"Off",description:"Keep the image still. Hover stays available."},{value:"caustics",mode:"caustics",group:"Light and texture",label:"Caustics",description:"Soft ribbons of light travel across a stationary character grid."},{value:"current",mode:"current",group:"Flow and depth",label:"Slow Current",description:"A gentle flow through the image, with steady edges."},{value:"reform",mode:"reform",group:"Rebuild",label:"Reveal & Reform",description:"Disperse, gather, then hold the complete image."},{value:"sheen",mode:"sheen",group:"Light and texture",label:"Sheen",description:"A broad diagonal light sweep; characters stay anchored."},{value:"tidal",mode:"tidal",group:"Flow and depth",label:"Tidal Rings",description:"Concentric currents travel outward, with protected edges."},{value:"grain",mode:"grain",group:"Light and texture",label:"Living Grain",description:"Slow, individually phased tonal changes on a stationary grid."},{value:"parallax",mode:"parallax",group:"Flow and depth",label:"Parallax",description:"A shallow, continuous drift through the image, with the edges held in place."},{value:"weave",mode:"weave",group:"Flow and depth",label:"Woven Flow",description:"Interlaced bands move in opposing directions, like a flexible printed fabric."},{value:"print",mode:"print",group:"Rebuild",label:"Print Shift",description:"Staggered rows lift, soften and register back into the image."},{value:"trace",mode:"trace",group:"Light and texture",label:"Contour Light",description:"Light follows the source image’s tonal contours; every character stays anchored."}],i=t=>Math.max(0,Math.min(1,t)),a=(t,e,a)=>{const s=i((a-t)/(e-t));return s*s*(3-2*s)},s=(t,e)=>{const i=(.06711056*t+.00583715*e)%1*52.9829189;return i-Math.floor(i)},r=class{constructor(){this.last=null,this.mode="none",this.phase=0}update(t,e,i=1){return Number.isFinite(t)?((e!==this.mode||null!==this.last&&t<this.last)&&(this.mode=e,this.phase=0,this.last=t),null!==this.last&&(this.phase+=Math.max(0,t-this.last)*Math.max(.1,Math.min(3,Number.isFinite(i)?i:1))),this.last=t,this.phase):this.phase}};function o(t,e,r,o,n,h=.5){if(n[0]=n[1]=n[2]=0,n[3]=1,"none"===t)return n;const l=o*Math.PI/6,c=a(0,.12,Math.min(e,1-e,r,1-r));if("caustics"===t){const t=Math.sin(9*e+5*r+l)+Math.sin(8*r-3*e-l),i=Math.pow(Math.max(0,1-.72*Math.abs(t)),3);n[2]=(.22*i-.045)*c}else if("current"===t)n[0]=Math.sin(9*r+l)*Math.cos(7*e-l)*10*c,n[1]=Math.cos(8*e+l)*Math.sin(6*r-l)*7*c;else if("sheen"===t)n[2]=.2*Math.pow(.5+.5*Math.cos(5*e+3*r-l),8)-.025;else if("tidal"===t){const t=e-.5,i=r-.5,a=Math.hypot(t,i),s=Math.sin(22*a-l)*c;n[0]=t*s*9,n[1]=i*s*9,n[2]=.035*s}else if("grain"===t){const t=s(Math.floor(160*e),Math.floor(100*r))*Math.PI*2;n[2]=.07*Math.sin(l+t)}else if("parallax"===t){const t=.45+.55*Math.max(0,1-1.4*Math.hypot(e-.5,r-.5));n[0]=12*Math.sin(l)*t*c,n[1]=6*(Math.cos(l)-1)*t*c}else if("weave"===t)n[0]=Math.sin(r*Math.PI*6+l)*Math.sin(l)*8*c,n[1]=Math.sin(e*Math.PI*6-l)*Math.sin(l)*6*c;else if("print"===t){const t=Math.floor(24*r),e=((o+3*s(t,3))%12+12)%12,i=a(1,2.5,e)*(1-a(3.5,5,e));n[0]=Math.sin(2.4*t)*i*9*c,n[1]=5*-i*c,n[2]=.22*-i,n[3]=1-.45*i}else if("trace"===t){const t=.5+.5*Math.cos(l);n[2]=.22*Math.pow(Math.max(0,1-Math.abs(i(h)-t)/.16),3)-.015}else if("reform"===t){const t=(o%12+12)%12,i=s(Math.floor(160*e),Math.floor(100*r)),h=.65*e+.2*r+.15*i+.08*Math.sin(8*e-5*r),d=a(1.8+1.2*h,3.8+1.2*h,t)*(1-a(5+1.7*h,7.2+1.7*h,t));n[0]=Math.sin(9*r+l)*d*(1-d)*24*c,n[1]=-d*(1-d)*(8+12*i)*c,n[2]=.45*-d,n[3]=1-.9*d}return n}function n(t,e){const a=Math.max(0,Math.min(2,Number.isFinite(e)?e:1));return t[0]*=a,t[1]*=a,t[2]*=a,t[3]=i(1+(t[3]-1)*a),t}var h=["ascii","blocks","braille","dots","lines","cross","diagonal","diamond","mixed","pixel","mosaic","lego","voxel","disco","dither","hex","led","cmyk"],l=["none","bayer2","bayer4","bayer8","bayer16","floyd-steinberg","atkinson","stucki","sierra","sierra-lite","burkes","jarvis","halftone","lines","noise","vertical-lines","diagonal-lines","radial"],c=["source-over","multiply","screen","overlay","soft-light","hard-light","color-dodge","color-burn","hue","saturation","color","luminosity"],d={original:[],gray4:["#000000","#555555","#aaaaaa","#ffffff"],gray8:["#000000","#242424","#494949","#6d6d6d","#929292","#b6b6b6","#dbdbdb","#ffffff"],rgb8:["#000000","#ff0000","#00ff00","#0000ff","#ffff00","#ff00ff","#00ffff","#ffffff"],cyberpunk:["#08081a","#3c1670","#ed299a","#29dfef","#fff7bf"],pastel:["#393448","#a5b4d4","#9ed9c6","#e7aac1","#f5e8be"],mono:["#080808","#f2f2e8"],asciify:["#080808","#625b38","#a19558","#e8b900"],gameboy:["#0f380f","#306230","#8bac0f","#9bbc0f"],cga:["#000000","#55ffff","#ff55ff","#ffffff"],pico8:["#000000","#1d2b53","#7e2553","#008751","#ab5236","#5f574f","#c2c3c7","#fff1e8","#ff004d","#ffa300","#ffec27","#00e436","#29adff","#83769c","#ff77a8","#ffccaa"],c64:["#000000","#ffffff","#880000","#aaffee","#cc44cc","#00cc55","#0000aa","#eeee77","#dd8855","#664400","#ff7777","#333333","#777777","#aaff66","#0088ff","#bbbbbb"],amber:["#100b00","#5f3b00","#c98014","#ffd17c"],ice:["#081b29","#25586e","#69a6b3","#d9ece7"],risograph:["#f4ebd0","#f2594b","#2853a5","#29232e"],sepia:["#201b17","#6b5039","#b49868","#f6e6c5"],nord:["#2e3440","#4c566a","#88c0d0","#eceff4"],dusk:["#211b35","#654271","#c3788c","#f5c9a3"],forest:["#101f1b","#355747","#87a16f","#e4e3ba"],ocean:["#071b33","#17577f","#3fa7a4","#d9efde"],newsprint:["#191919","#666666","#aaaaaa","#eee9df"],custom:["#080808","#e8b900"]},m={version:1,aspectRatio:"original",style:"ascii",cellSize:6,charset:" .:-=+*#%@",colorMode:"accent",ink:"#e8b900",crop:{x:.5,y:.5,zoom:1,rotation:0},backdrop:{mode:"solid",color:"#080808",color2:"#393323",blur:12,opacity:1},color:{brightness:0,contrast:1,saturation:1,grayscale:0,tint:"#e8b900",amount:0,blend:"source-over"},dither:{algorithm:"none",palette:"mono",colors:["#080808","#e8b900"],amount:1,scale:2,threshold:.5,motion:"none",speed:1,direction:45,colorSpace:"rgb"},mask:{enabled:!1,invert:!1,shapes:[]},lights:[],effects:{bloom:0,characterBloom:0,grain:0,dust:0,scanlines:0,crt:0,prism:0,rgbSplit:0,sharpen:0,vignette:0,glitch:0,pixelate:0,blur:0,blurType:"gaussian",angle:0,focus:.5,halftone:0},motion:{type:"none",speed:1,amount:1},hover:{effect:"trail",strength:.55,radius:.2,edgeSafe:!1}},f=t=>t&&"object"==typeof t&&!Array.isArray(t)?t:{},u=(t,e,i,a)=>"number"==typeof t&&Number.isFinite(t)?Math.min(a,Math.max(i,t)):e,g=(t,e)=>"string"==typeof t&&/^#[\da-f]{6}$/i.test(t)?t:e,p=(t,e,i)=>e.includes(t)?t:i;function M(i={}){const a=f(i),s=m;if(void 0!==a.version&&1!==a.version)throw new Error("Unsupported studio settings version. Update asciify-engine.");const r=f(a.crop),o=f(a.backdrop),n=f(a.color),M=f(a.dither),x=f(a.mask),v=f(a.effects),b=f(a.motion),w=f(a.hover),y={...s.effects};for(const t of["bloom","characterBloom","grain","dust","scanlines","crt","prism","rgbSplit","sharpen","vignette","glitch","pixelate","halftone"])y[t]=u(v[t],0,0,1);y.blur=u(v.blur,0,0,24),y.blurType=p(v.blurType,["gaussian","directional","radial","progressive"],s.effects.blurType),y.angle=u(v.angle,0,-180,180),y.focus=u(v.focus,.5,0,1);let S=2048;return{version:1,aspectRatio:p(a.aspectRatio,["original","16:9","9:16","1:1","4:3","3:4","21:9"],"original"),style:p(a.style,h,s.style),cellSize:u(a.cellSize,s.cellSize,["pixel","mosaic","lego","voxel","disco","dots","hex","led","cmyk"].includes(String(a.style))?1:3,60),charset:"string"==typeof a.charset&&a.charset.length?Array.from(a.charset).slice(0,128).join(""):s.charset,colorMode:p(a.colorMode,["accent","source","gray"],s.colorMode),ink:g(a.ink,s.ink),crop:{x:u(r.x,.5,0,1),y:u(r.y,.5,0,1),zoom:u(r.zoom,1,1,5),rotation:90*Math.round(u(r.rotation,0,-360,360)/90)},backdrop:{mode:p(o.mode,["solid","transparent","source","blurred","gradient"],s.backdrop.mode),color:g(o.color,s.backdrop.color),color2:g(o.color2,s.backdrop.color2),blur:u(o.blur,12,0,32),opacity:u(o.opacity,1,0,1)},color:{brightness:u(n.brightness,0,-1,1),contrast:u(n.contrast,1,0,3),saturation:u(n.saturation,1,0,3),grayscale:u(n.grayscale,0,0,1),tint:g(n.tint,s.color.tint),amount:u(n.amount,0,0,1),blend:p(n.blend,c,s.color.blend)},dither:{algorithm:p(M.algorithm,l,"none"),palette:"string"==typeof M.palette&&Object.prototype.hasOwnProperty.call(d,M.palette)?M.palette:"mono",colors:Array.isArray(M.colors)&&M.colors.length>=2?M.colors.slice(0,32).map(t=>g(t,"#000000")):[...s.dither.colors],amount:u(M.amount,1,0,2),scale:Math.round(u(M.scale,2,1,12)),threshold:u(M.threshold,.5,0,1),motion:p(M.motion,["none","drift","shimmer"],"none"),speed:u(M.speed,1,.1,3),direction:u(M.direction,45,-180,180),colorSpace:p(M.colorSpace,["rgb","luminance"],"rgb")},mask:{enabled:!0===x.enabled,invert:!0===x.invert,shapes:Array.isArray(x.shapes)?x.shapes.slice(0,64).map(t=>{const e=f(t),i=p(e.kind,["rectangle","ellipse","brush"],"rectangle"),a="brush"===i&&Array.isArray(e.points)?e.points.slice(0,S).map(t=>Array.isArray(t)?[Math.round(1e4*u(t[0],0,0,1))/1e4,Math.round(1e4*u(t[1],0,0,1))/1e4]:[0,0]):[];return S-=a.length,{kind:i,x:u(e.x,0,0,1),y:u(e.y,0,0,1),width:u(e.width,.5,0,1),height:u(e.height,.5,0,1),size:u(e.size,.05,.005,.5),points:a}}):[]},lights:Array.isArray(a.lights)?a.lights.slice(0,4).map(t=>{const e=f(t);return{x:u(e.x,.5,0,1),y:u(e.y,.5,0,1),radius:u(e.radius,.3,.02,1),intensity:u(e.intensity,.5,0,1),color:g(e.color,"#ffffff")}}):[],effects:y,motion:{type:p(b.type,e.map(t=>t.mode),"none"),speed:u(b.speed,1,.1,3),amount:u(b.amount,1,0,2)},hover:{effect:p(w.effect,t.map(t=>t.value),"trail"),strength:u(w.strength,.55,0,1),radius:u(w.radius,.2,.1,1),edgeSafe:!0===w.edgeSafe}}}function x(t,e,i,a,s){const r=Math.abs(s.rotation/90)%2==1,o=r?e:t,n=r?t:e,h=Math.max(i/o,a/n)*s.zoom;return{width:o*h,height:n*h,x:(i-o*h)*s.x,y:(a-n*h)*s.y,scale:h,rotated:r}}function v(t,e,i){if(Math.abs(i.crop.rotation/90)%2==1&&([t,e]=[e,t]),"original"===i.aspectRatio)return[t,e];const[a,s]=i.aspectRatio.split(":").map(Number);return t/e>a/s?[Math.round(e*a/s),e]:[t,Math.round(t*s/a)]}function b(t,e){const i={...t,...e};for(const a of["crop","backdrop","color","dither","mask","effects","motion","hover"])e[a]&&Object.assign(i,{[a]:{...t[a],...e[a]}});return M(i)}function w(t,e,i,a=12e3,s=1){const r=Math.max(2,Number.isFinite(t)?t:960),o=Math.max(2,Number.isFinite(e)?e:540),n=Math.max(1,Math.floor(Number.isFinite(a)?a:12e3)),h=Math.max(.01,Number.isFinite(s)?s:1),l=["dither","pixel","mosaic","lego","voxel","disco","dots","hex","led","cmyk"].includes(i.style)?1:1.65;let c=Math.max(1,Math.ceil(Math.sqrt(r*o/(n*l))/h));for(;Math.ceil(r/(c*h))*Math.ceil(o/(c*h*l))>n;)c++;const 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 y=[["ascii","Signature ASCII","Brand ink and clean characters.",{}],["print","Newsprint","Fine diffusion on warm paper.",{style:"dither",dither:{algorithm:"floyd-steinberg",palette:"newsprint"}}],["handheld","Pocket camera","Four-tone ordered dither.",{style:"dither",dither:{algorithm:"bayer4",palette:"gameboy",scale:3}}],["riso","Two inks","Limited-color print texture.",{style:"dither",dither:{algorithm:"atkinson",palette:"risograph",scale:2}}],["night","Night signal","Gray characters and optical fringe.",{ink:"#888888",effects:{prism:.7,scanlines:.2,vignette:.3}}],["terminal","Phosphor","Green glyphs with a soft glow.",{ink:"#83efad",effects:{bloom:.4,scanlines:.35,crt:.2}}],["mosaic","Mosaic study","Separated color tiles.",{style:"mosaic",cellSize:14,colorMode:"source"}],["bricks","Brickwork","Colorful studded cells.",{style:"lego",cellSize:18,colorMode:"source"}],["voxel","Little volumes","Three-face isometric tiles.",{style:"voxel",cellSize:22,colorMode:"source"}],["disco","Mirror room","Faceted tiles and warm light.",{style:"disco",cellSize:18,colorMode:"source",lights:[{x:.35,y:.25,radius:.25,intensity:.45,color:"#fff2d4"}]}],["wallpaper","Wallpaper","Living ASCII over a softened source.",{backdrop:{mode:"blurred",blur:18,opacity:.55},ink:"#f2e9c9",motion:{type:"caustics",speed:.5}}],["blueprint","Blueprint","Linework in a cool monochrome.",{style:"lines",ink:"#9bccdf",backdrop:{mode:"solid",color:"#0a1e30"}}]].map(([t,e,i,a])=>({id:t,name:e,description:i,settings:M(a)}));function S(t){const e=y.find(e=>e.id===t);if(!e)throw new Error("Unknown studio look.");return M(e.settings)}function k(t,e,i,a,s,r){a=Math.max(0,Math.min(e-1,a)),s=Math.max(0,Math.min(i-1,s));const o=Math.floor(a),n=Math.floor(s),h=a-o,l=s-n,c=4*(n*e+o);if(0===h&&0===l){for(let e=0;e<4;e++)r[e]=t[c+e];return}const d=4*(n*e+Math.min(e-1,o+1)),m=4*(Math.min(i-1,n+1)*e+o),f=4*(Math.min(i-1,n+1)*e+Math.min(e-1,o+1)),u=(1-h)*(1-l)*t[c+3],g=h*(1-l)*t[d+3],p=(1-h)*l*t[m+3],M=h*l*t[f+3],x=u+g+p+M;for(let e=0;e<3;e++)r[e]=x?(t[c+e]*u+t[d+e]*g+t[m+e]*p+t[f+e]*M)/x:0;r[3]=x}var E=new Set(["none","floyd-steinberg","atkinson","stucki","sierra","sierra-lite","burkes","jarvis"]);function A(t){return"dither"===t.style&&("shimmer"===t.dither.motion||"drift"===t.dither.motion&&t.dither.amount>0&&!E.has(t.dither.algorithm))}function T(t){return"none"!==t.motion.type&&(t.motion.amount??1)>0}var F=(t,e)=>{const i=43758.5453*Math.sin(127.1*t+311.7*e);return i-Math.floor(i)};var I=new Map([2,4,8,16].map(t=>[t,Float64Array.from({length:t*t},(e,i)=>function(t,e,i){let a=0;for(let s=1;s<i;s*=2){const i=(Math.floor(t/s)%2+2)%2;a=4*a+[[0,2],[3,1]][(Math.floor(e/s)%2+2)%2][i]}return(a+.5)/(i*i)-.5}(i%t,Math.floor(i/t),t))])),P={"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]]},R=t=>[parseInt(t.slice(1,3),16),parseInt(t.slice(3,5),16),parseInt(t.slice(5,7),16)];function C(t,e,i){const a=Math.min(t*Math.max(1,i),(1-t)*Math.max(1,i),e*Math.max(1,1/i),(1-e)*Math.max(1,1/i)),s=Math.max(0,Math.min(1,(a-.035)/.105));return s*s*s*(s*(6*s-15)+10)}var L=t=>["dissolve","silk","vortex","magnetic","scatter","etch","elastic","rake"].includes(t),D=class{constructor(t,e){this.edgeSafe=!1,this.previous=null,this.peak=0,this.scatterDirections=null,this.springX=null,this.springY=null,this.mode="dissolve",this.width=t,this.height=e;const i=t*e;this.pixels=new Uint8Array(4*i),this.ink=new Float32Array(i),this.targetX=new Float32Array(i),this.targetY=new Float32Array(i),this.offsetX=new Float32Array(i),this.offsetY=new Float32Array(i),this.edge=new Float32Array(i);for(let i=0;i<e;i++)for(let a=0;a<t;a++)this.edge[i*t+a]=C(a/(t-1),i/(e-1),t/e);this.clear()}get active(){return this.peak>2e-4}setMode(t){if("elastic"!==t||this.springX||(this.springX=new Float32Array(this.ink.length),this.springY=new Float32Array(this.ink.length)),"scatter"===t&&!this.scatterDirections){const t=this.scatterDirections=new Float64Array(this.width*this.height*2);for(let e=0;e<this.height;e++)for(let i=0;i<this.width;i++){const a=43758.5453*Math.sin(127.1*i+311.7*e),s=(a-Math.floor(a))*Math.PI*2,r=2*(e*this.width+i);t[r]=.7*Math.cos(s),t[r+1]=.7*Math.sin(s)}}t!==this.mode&&(this.mode=t,this.clear())}clear(){for(const t of[this.ink,this.targetX,this.targetY,this.offsetX,this.offsetY,this.pixels])t.fill(0);if(this.previous=null,this.peak=0,this.springX?.fill(0),this.springY?.fill(0),"dissolve"!==this.mode)for(let t=0;t<this.pixels.length;t+=4)this.pixels[t]=this.pixels[t+2]=128}leave(){this.previous=null}move(t,e,i){if(!Number.isFinite(t+e+i))return;t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e));const a=this.previous;this.previous={x:t,y:e};const s=this.width,r=this.height,o=Math.max(1,s/r),n=Math.max(1,r/s),h=a?(t-a.x)*o:0,l=a?(e-a.y)*n:0,c=Math.hypot(h,l);if(!a&&"dissolve"!==this.mode&&"etch"!==this.mode)return;if(a&&c<1e-4)return;const d=.035+.11*Math.max(.1,Math.min(1,i)),m=Math.min(128,Math.max(1,Math.ceil(c/(.45*d)))),f=c?h/c:1,u=c?l/c:0,g=Math.min(1,c/(d*m)*2.2);for(let i=0;i<m;i++){const h=(i+.5)/m,l=a?a.x+(t-a.x)*h:t,c=a?a.y+(e-a.y)*h:e,p=Math.max(0,Math.floor((l-2.5*d/o)*(s-1))),M=Math.min(s-1,Math.ceil((l+2.5*d/o)*(s-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=p;e<=M;e++){const i=(e/(s-1)-l)*o/d,a=(t/(r-1)-c)*n/d,h=Math.exp(1.5*-(i*i+a*a)),m=t*s+e;if("dissolve"===this.mode||"etch"===this.mode)this.ink[m]=Math.max(this.ink[m],h);else if("elastic"===this.mode)this.springX[m]=Math.max(-24,Math.min(24,this.springX[m]+f*h*g*8)),this.springY[m]=Math.max(-24,Math.min(24,this.springY[m]+u*h*g*8));else{const s=(-i*u+a*f)*h*2.8,r="rake"===this.mode?f*Math.sin(t*Math.PI/3)*h*2:"magnetic"===this.mode?-i*h*2.5:"scatter"===this.mode?(i+this.scatterDirections[2*m])*h*2:"silk"===this.mode?f*s:-a*h*2.5,o="rake"===this.mode?u*Math.sin(e*Math.PI/3)*h*2:"magnetic"===this.mode?-a*h*2.5:"scatter"===this.mode?(a+this.scatterDirections[2*m+1])*h*2:"silk"===this.mode?u*s:i*h*2.5;this.targetX[m]=Math.max(-1,Math.min(1,this.targetX[m]+r*g)),this.targetY[m]=Math.max(-1,Math.min(1,this.targetY[m]+o*g))}}}this.peak=1}step(t){if(!this.active||!Number.isFinite(t))return;const e=Math.max(0,Math.min(.05,t)),i=Math.exp(-("dissolve"===this.mode?2.15:3.2)*e),a=1-Math.exp(-22*e);let s=0;const r=Math.sqrt(336),o=Math.exp(-8*e),n=Math.cos(r*e),h=Math.sin(r*e)/r;for(let t=0;t<this.ink.length;t++)if("etch"===this.mode)this.ink[t]*=i,s=Math.max(s,this.ink[t]);else if("dissolve"===this.mode){this.ink[t]*=i,s=Math.max(s,this.ink[t]);const e=Math.round(65535*this.ink[t]);this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e}else{if("elastic"===this.mode){const e=this.offsetX[t],i=this.offsetY[t],a=this.springX[t],r=this.springY[t];this.offsetX[t]=Math.max(-1,Math.min(1,o*(e*n+(a+8*e)*h))),this.offsetY[t]=Math.max(-1,Math.min(1,o*(i*n+(r+8*i)*h))),this.springX[t]=o*(a*n-(8*a+400*e)*h),this.springY[t]=o*(r*n-(8*r+400*i)*h),s=Math.max(s,.05*Math.abs(this.springX[t]),.05*Math.abs(this.springY[t]))}else this.targetX[t]*=i,this.targetY[t]*=i,this.offsetX[t]+=(this.targetX[t]-this.offsetX[t])*a,this.offsetY[t]+=(this.targetY[t]-this.offsetY[t])*a;s=Math.max(s,Math.abs(this.offsetX[t]),Math.abs(this.offsetY[t]),Math.abs(this.targetX[t]),Math.abs(this.targetY[t]));const e=Math.round(this.offsetX[t]*(this.edgeSafe?this.edge[t]:1)*32767+32768),r=Math.round(this.offsetY[t]*(this.edgeSafe?this.edge[t]:1)*32767+32768);this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e,this.pixels[4*t+2]=r>>>8,this.pixels[4*t+3]=255&r}if("etch"===this.mode)for(let t=0;t<this.height;t++)for(let e=0;e<this.width;e++){const i=t*this.width+e,a=3*(this.ink[t*this.width+Math.max(0,e-1)]-this.ink[t*this.width+Math.min(this.width-1,e+1)]+this.ink[Math.max(0,t-1)*this.width+e]-this.ink[Math.min(this.height-1,t+1)*this.width+e]);this.offsetX[i]=Math.max(-1,Math.min(1,a))*(this.edgeSafe?this.edge[i]:1);const s=Math.round(32767*this.offsetX[i]+32768);this.pixels[4*i]=s>>>8,this.pixels[4*i+1]=255&s}this.peak=s,this.active||this.clear()}sample(t,e,i){const a=Math.max(0,Math.min(this.width-1.001,t*(this.width-1))),s=Math.max(0,Math.min(this.height-1.001,e*(this.height-1))),r=Math.floor(a),o=Math.floor(s),n=a-r,h=s-o,l=o*this.width+r,c=l+this.width,d=t=>(t[l]*(1-n)+t[l+1]*n)*(1-h)+(t[c]*(1-n)+t[c+1]*n)*h;if("etch"===this.mode)return i[0]=i[1]=0,void(i[2]=3*d(this.offsetX));i[0]=d(this.offsetX)*(this.edgeSafe?C(t,e,this.width/this.height):1)*.08,i[1]=d(this.offsetY)*(this.edgeSafe?C(t,e,this.width/this.height):1)*.08,i[2]="dissolve"===this.mode?6*-d(this.ink):0}},X=class{constructor(t,e){this.rings=[],this.previous=null,this.elapsed=1,this.echoPeak=0,this.width=t,this.height=e,this.pixels=new Uint8Array(t*e*4),this.echo=new Float32Array(t*e)}get active(){return this.rings.length>0||this.echoPeak>2e-4}clear(){this.rings=[],this.previous=null,this.elapsed=1,this.pixels.fill(0),this.echo.fill(0),this.echoPeak=0}leave(){this.previous=null}move(t,e,i){const a=Math.max(1,this.width/this.height),s=Math.max(1,this.height/this.width);this.previous&&(Math.hypot((t-this.previous.x)*a,(e-this.previous.y)*s)<.065||this.elapsed<.3)||4!==this.rings.length&&(this.previous={x:t,y:e},this.elapsed=0,this.rings.push({x:t,y:e,age:0,radius:i}))}ringSample(t,e){const i=Math.max(1,this.width/this.height),a=Math.max(1,this.height/this.width);let s=0;for(const r of this.rings){const o=.015+r.age*(.15+.22*r.radius),n=.009+.014*r.radius,h=(Math.hypot((t-r.x)*i,(e-r.y)*a)-o)/n,l=Math.sin(Math.min(1,r.age/.07)*Math.PI/2)*Math.max(0,1-r.age/1.35)**2;s=Math.max(s,Math.exp(-h*h)*l)}return s}sample(t,e){const i=Math.max(0,Math.min(this.width-1,Math.round(t*(this.width-1)))),a=Math.max(0,Math.min(this.height-1,Math.round(e*(this.height-1))));return Math.max(this.ringSample(t,e),this.echo[a*this.width+i])}step(t){if(!Number.isFinite(t))return;const e=Math.max(0,Math.min(.05,t));this.elapsed+=e;for(const t of this.rings)t.age+=e;if(this.rings=this.rings.filter(t=>t.age<1.35),!this.active)return void this.pixels.fill(0);const i=Math.exp(-5.5*e);let a=0;for(let t=0;t<this.height;t++)for(let e=0;e<this.width;e++){const s=t*this.width+e;this.echo[s]=Math.max(this.ringSample(e/(this.width-1),t/(this.height-1)),this.echo[s]*i),a=Math.max(a,this.echo[s]);const r=Math.round(65535*this.echo[s]),o=4*s;this.pixels[o]=r>>>8,this.pixels[o+1]=255&r}this.echoPeak=a,this.active||(this.echo.fill(0),this.pixels.fill(0))}},O=class{constructor(t,e){this.previous=null,this.peak=0,this.width=t,this.height=e;const i=t*e;this.pixels=new Uint8Array(4*i),this.signal=new Float32Array(i),this.offsetX=new Float32Array(i),this.offsetY=new Float32Array(i),this.driftX=new Float32Array(i),this.driftY=new Float32Array(i),this.u=new Float32Array(i),this.v=new Float32Array(i),this.ink=new Float32Array(i),this.a=new Float32Array(i),this.b=new Float32Array(i),this.c=new Float32Array(i),this.pressure=new Float32Array(i),this.pressureNext=new Float32Array(i),this.divergence=new Float32Array(i),this.curl=new Float32Array(i)}get active(){return this.peak>2e-4}clear(){for(const t of[this.u,this.v,this.ink,this.a,this.b,this.c,this.pressure,this.pressureNext,this.divergence,this.curl,this.signal,this.pixels,this.offsetX,this.offsetY,this.driftX,this.driftY])t.fill(0);this.previous=null,this.peak=0}leave(){this.previous=null}move(t,e,i,a=performance.now()){if(!Number.isFinite(t+e+i+a))return;t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e)),i=Math.max(.1,Math.min(1,i));const s=this.previous;if(this.previous={x:t,y:e,time:a},!s)return;const r=(t-s.x)*(this.width-1),o=(e-s.y)*(this.height-1),n=Math.hypot(r,o);if(n<.001)return;const h=Math.min(this.width,this.height),l=a>s.time?Math.max(1/240,(a-s.time)/1e3):1/60,c=Math.min(12,n/h/l),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,g=r/n,p=o/n,M=-p,x=g,v=n*(2+18*d)/f;for(let i=0;i<f;i++){const a=(i+.5)/f,r=(s.x+(t-s.x)*a)*(this.width-1),o=(s.y+(e-s.y)*a)*(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)*g+(t-o)*p)/m,a=((e-r)*M+(t-o)*x)/m,s=Math.exp(-i*i*.65-a*a*1.7),n=t*this.width+e;this.ink[n]=1-(1-this.ink[n])*Math.exp(-s*u);const h=1-a*a*.55,l=i*a*.7;this.u[n]=Math.max(-80,Math.min(80,this.u[n]+(g*h+M*l)*s*v)),this.v[n]=Math.max(-80,Math.min(80,this.v[n]+(p*h+x*l)*s*v))}}this.peak=1}read(t,e,i){const a=0|(e=Math.max(.5,Math.min(this.width-1.5,e))),s=0|(i=Math.max(.5,Math.min(this.height-1.5,i))),r=e-a,o=i-s,n=s*this.width+a;return(t[n]*(1-r)+t[n+1]*r)*(1-o)+(t[n+this.width]*(1-r)+t[n+this.width+1]*r)*o}sample(t,e){return this.read(this.signal,t*(this.width-1),e*(this.height-1))}displacement(t,e,i){i[0]=this.read(this.offsetX,t*(this.width-1),e*(this.height-1)),i[1]=this.read(this.offsetY,t*(this.width-1),e*(this.height-1))}step(t){if(!this.active||!Number.isFinite(t))return;let e=Math.max(0,Math.min(.05,t));const i=this.width,a=this.height;for(;e>1e-7;){const t=Math.min(1/60,e);e-=t;const s=Math.exp(-1.9*t),r=Math.exp(-3.2*t);for(let e=1;e<a-1;e++)for(let o=1;o<i-1;o++){const n=e*i+o,h=Math.max(.5,Math.min(i-1.5,o-this.u[n]*t)),l=Math.max(.5,Math.min(a-1.5,e-this.v[n]*t)),c=0|h,d=0|l,m=h-c,f=l-d,u=d*i+c,g=(1-m)*(1-f),p=m*(1-f),M=(1-m)*f,x=m*f;this.a[n]=(this.u[u]*g+this.u[u+1]*p+this.u[u+i]*M+this.u[u+i+1]*x)*s,this.b[n]=(this.v[u]*g+this.v[u+1]*p+this.v[u+i]*M+this.v[u+i+1]*x)*s,this.c[n]=(this.ink[u]*g+this.ink[u+1]*p+this.ink[u+i]*M+this.ink[u+i+1]*x)*r}[this.u,this.a]=[this.a,this.u],[this.v,this.b]=[this.b,this.v],[this.ink,this.c]=[this.c,this.ink];for(let t=1;t<a-1;t++)for(let e=1;e<i-1;e++){const a=t*i+e;this.curl[a]=.5*(this.v[a+1]-this.v[a-1]-this.u[a+i]+this.u[a-i])}for(let e=1;e<a-1;e++)for(let a=1;a<i-1;a++){const s=e*i+a,r=Math.abs(this.curl[s+1])-Math.abs(this.curl[s-1]),o=Math.abs(this.curl[s+i])-Math.abs(this.curl[s-i]),n=Math.hypot(r,o)+1e-4,h=this.curl[s]*t*10,l=Math.hypot(this.u[s],this.v[s]);this.u[s]+=o/n*h,this.v[s]-=r/n*h;const c=Math.min(1,l/(Math.hypot(this.u[s],this.v[s])+1e-6));this.u[s]*=c,this.v[s]*=c,this.divergence[s]=-.5*(this.u[s+1]-this.u[s-1]+this.v[s+i]-this.v[s-i])}this.pressure.fill(0);for(let t=0;t<4;t++){for(let t=1;t<a-1;t++)for(let e=1;e<i-1;e++){const a=t*i+e;this.pressureNext[a]=.25*(this.divergence[a]+this.pressure[a-1]+this.pressure[a+1]+this.pressure[a-i]+this.pressure[a+i])}[this.pressure,this.pressureNext]=[this.pressureNext,this.pressure]}let o=0;for(let e=1;e<a-1;e++)for(let a=1;a<i-1;a++){const s=e*i+a;this.u[s]=Math.max(-80,Math.min(80,this.u[s]-.5*(this.pressure[s+1]-this.pressure[s-1]))),this.v[s]=Math.max(-80,Math.min(80,this.v[s]-.5*(this.pressure[s+i]-this.pressure[s-i]))),this.driftX[s]+=(3.6*this.u[s]-58*this.offsetX[s]-12*this.driftX[s])*t,this.driftY[s]+=(3.6*this.v[s]-58*this.offsetY[s]-12*this.driftY[s])*t,this.offsetX[s]=Math.max(-2,Math.min(2,this.offsetX[s]+this.driftX[s]*t)),this.offsetY[s]=Math.max(-2,Math.min(2,this.offsetY[s]+this.driftY[s]*t)),this.signal[s]=1-Math.exp(.06*-Math.hypot(this.u[s],this.v[s])-.16*this.ink[s]),o=Math.max(o,this.signal[s])}this.peak=o}if(this.active)for(let t=0;t<this.ink.length;t++){const e=Math.round(65535*Math.min(1,this.signal[t]));this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e,this.pixels[4*t+2]=Math.round(128+63.5*this.offsetX[t]),this.pixels[4*t+3]=Math.round(128+63.5*this.offsetY[t])}else this.clear()}};function N(t,e){const i=Math.max(0,Math.min(1,e/.38));return t+(1-2*t)*(i*i*(3-2*i))}var U=(t,e)=>"water"===t?30*e/.55:"silk"===t?28*e:"vortex"===t?38*e:["magnetic","scatter","elastic","rake"].includes(t)?32*e:0,Y=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]=C(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 O(this.columns,this.rows),this.contour=new X(this.columns,this.rows),this.afterimage=new D(this.columns,this.rows),this.clear()}get invertsDensity(){return"trail"===this.mode}get densityTrail(){return["trail","contour","dissolve","etch"].includes(this.mode)}get hasRefraction(){return this.active||this.lensStrength>15e-5}get active(){return L(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,L(t)&&this.afterimage.setMode(t),this.refraction.pixels="trail"===t?this.trail.pixels:"contour"===t?this.contour.pixels:L(t)?this.afterimage.pixels:this.waterPixels,this.refraction.strength=U(t,this.amount))}configure(t,e=.55,i=.2,a=!1){this.setMode(t),this.refraction.edgeSafe=a,this.afterimage.edgeSafe=a,this.amount=Number.isFinite(e)?Math.max(0,Math.min(1,e)):.55,this.radius=Number.isFinite(i)?Math.max(.1,Math.min(1,i)):.2,this.refraction.strength=U(t,this.amount),this.refraction.focus[2]=this.densityTrail?this.amount:this.lensStrength*this.amount,this.refraction.focus[3]=this.radius}move(t,e,i){if("none"===this.mode||0===this.amount)return;if(!Number.isFinite(t+e))return;if(t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e)),L(this.mode))return void this.afterimage.move(t,e,this.radius);if("contour"===this.mode)return void this.contour.move(t,e,this.radius);if("trail"===this.mode)return void this.trail.move(t,e,this.radius,i);if("water"!==this.mode)return!this.previous&&this.lensStrength<.001&&(this.lensX=t,this.lensY=e),this.previous={x:t,y:e},void(this.pending=!0);if(!this.previous)return void(this.previous={x:t,y:e});const a=this.previous;this.previous={x:t,y:e};const s=(t-a.x)*this.xScale,r=(e-a.y)*this.yScale,o=Math.hypot(s,r);if(o<1e-5)return;const n=.035+.1*this.radius,h=3*n,l=Math.min(192,Math.max(1,Math.ceil(o/(.5*n)))),c=95*Math.min(o,1)/l;for(let i=0;i<l;i++){const s=(i+.5)/l,r=a.x+(t-a.x)*s,o=a.y+(e-a.y)*s,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,a=(t/(this.rows-1)-o)*this.yScale,s=Math.exp(-(i*i+a*a)/(n*n))*c,h=t*this.columns+e;this.velocity[h]=Math.max(-12,this.velocity[h]-s)}}this.pending=!0}leave(){this.afterimage.leave(),this.contour.leave(),this.trail.leave(),this.previous=null,"water"!==this.mode&&this.lensStrength&&(this.pending=!0)}clear(){this.trail.clear(),this.contour.clear(),this.afterimage.clear(),this.heights.fill(0),this.velocity.fill(0),this.next.fill(0),this.normals.fill(0),this.refraction.focus[2]=0,this.previous=null,this.lensStrength=0,this.energy=0,this.pending=!1,this.remainder=0;for(let t=0;t<this.waterPixels.length;t+=4)this.waterPixels[t]=this.waterPixels[t+2]=128,this.waterPixels[t+1]=this.waterPixels[t+3]=0}step(t){if(!this.active||!Number.isFinite(t))return;if(L(this.mode))return void this.afterimage.step(t);if("contour"===this.mode)return void this.contour.step(t);if("trail"===this.mode)return void this.trail.step(t);if("water"!==this.mode)return void this.stepLight(Math.max(0,Math.min(.05,t)));this.remainder+=Math.max(0,Math.min(.05,t));const e=1/120,i=Math.exp(-3.8*e),a=.3*Math.min(this.columns,this.rows);for(;this.remainder+1e-8>=e;){this.remainder-=e;let t=0;for(let s=1;s<this.rows-1;s++)for(let r=1;r<this.columns-1;r++){const o=s*this.columns+r,n=this.heights[o],h=this.heights[o-1]+this.heights[o+1]+this.heights[o-this.columns]+this.heights[o+this.columns]-4*n,l=Math.min(r,s,this.columns-1-r,this.rows-1-s),c=l<5?.88+.024*l:1,d=(this.velocity[o]+(h*a*a-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 s=.18*Math.min(this.columns,this.rows);for(let t=0;t<this.rows;t++)for(let e=0;e<this.columns;e++){const i=t*this.columns+e,a=(this.heights[t*this.columns+Math.max(0,e-1)]-this.heights[t*this.columns+Math.min(this.columns-1,e+1)])*s,r=(this.heights[Math.max(0,t-1)*this.columns+e]-this.heights[Math.min(this.rows-1,t+1)*this.columns+e])*s,o=Math.tanh(a)*(this.refraction.edgeSafe?this.edgeMask[i]:1),n=Math.tanh(r)*(this.refraction.edgeSafe?this.edgeMask[i]:1);this.normals[2*i]=o,this.normals[2*i+1]=n;const h=Math.round(32767*o+32768),l=Math.round(32767*n+32768);this.refraction.pixels[4*i]=h>>>8,this.refraction.pixels[4*i+1]=255&h,this.refraction.pixels[4*i+2]=l>>>8,this.refraction.pixels[4*i+3]=255&l}}stepLight(t){const e=this.previous,i=1-Math.exp(-30*t),a=1-Math.exp(-12*t);e&&(this.lensX+=(e.x-this.lensX)*i,this.lensY+=(e.y-this.lensY)*i),this.lensStrength+=((e?1:0)-this.lensStrength)*a,this.energy=Math.max(e?Math.abs(e.x-this.lensX)+Math.abs(e.y-this.lensY):0,Math.abs((e?1:0)-this.lensStrength)),this.pending=!1,e||this.active?this.refraction.focus=[this.lensX,this.lensY,this.lensStrength*this.amount,this.radius]:this.clear()}sample(t,e,i){if(L(this.mode))return this.afterimage.sample(t,e,i),i[0]*=this.amount,i[1]*=this.amount,void(i[2]*=this.amount);if("contour"===this.mode)return i[0]=i[1]=0,void(i[2]=this.contour.sample(t,e)*this.amount*3);if("trail"===this.mode)return i[0]=i[1]=0,void(i[2]=this.trail.sample(t,e)*this.amount*3);const a=Math.max(0,Math.min(this.columns-1.001,t*(this.columns-1))),s=Math.max(0,Math.min(this.rows-1.001,e*(this.rows-1))),r=Math.floor(a),o=Math.floor(s),n=a-r,h=s-o,l=2*(o*this.columns+r),c=l+2*this.columns;for(let t=0;t<2;t++)i[t]=.08*((this.normals[l+t]*(1-n)+this.normals[l+2+t]*n)*(1-h)+(this.normals[c+t]*(1-n)+this.normals[c+2+t]*n)*h);i[0]*=this.amount/.55,i[1]*=this.amount/.55,i[2]="light"===this.mode||"scan"===this.mode?function(t,e,i,a){const[s,r,o,n]=i.focus,h=(t-s)*Math.max(1,a)/n,l=(e-r)*Math.max(1,1/a)/n;return"light"===i.mode?Math.exp(-3*(h*h+l*l))*o:"scan"===i.mode?(1.3*Math.exp(-h*h*110)-.3*Math.exp(-h*h*12))*Math.exp(-l*l*1.8)*o:0}(t,e,this.refraction,this.xScale/this.yScale):0}};function _(t){return"videoWidth"in t?[t.videoWidth,t.videoHeight]:"naturalWidth"in t?[t.naturalWidth,t.naturalHeight]:[t.width,t.height]}var B=(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}},z=(t,e,i)=>{t.width===e&&t.height===i||(t.width=e,t.height=i)},W={blocks:" ░▒▓█",braille:" ⠁⠃⠇⡇⣇⣧⣷⣿",lines:" -═╪╬",cross:" ·+xX#",diagonal:" /╱╳",diamond:" ·◇◈◆",mixed:" .:+/◇#@"};function G(t,e={},i={}){const a=t.getContext("2d");if(!a)throw new Error("Canvas is already owned by another renderer.");const s=B(),r=B(!0),h=B(),l=B(),c=B(),m=B(),f=B(),u=B(),g=B(),p=B();let v,b=0,y=M(e),S=0,E="",C="",L="",D=new Uint8ClampedArray(0),X=new Uint8ClampedArray(0),O=0,U=0,G=0,q=null,j="",H=new Y,V=0;const $=[0,0,0],K=[0,0,0,1],Q=[0,0,0,0],J=Math.max(64,Math.min(4096,Number.isFinite(i.maxDimension)?i.maxDimension:960)),Z=Math.max(256,Math.min(1048576,Number.isFinite(i.maxCells)?i.maxCells:12e3));let tt=Z,et=Math.max(.1,Math.min(8,i.pixelRatio??1));return{canvas:t,render:function(e,i=0,M=960,B=540,Z=i*y.motion.speed){if(Number.isFinite(i)||(i=0),!Number.isFinite(M)||!Number.isFinite(B)||M<1||B<1)throw new Error("Render dimensions must be positive finite numbers.");const[it,at]=_(e);if(!it||!at)return;const st=Math.min(1,J/Math.max(M,B)),rt=Math.max(2,Math.round(M*st)),ot=Math.max(2,Math.round(B*st));z(t,rt,ot),z(s.canvas,rt,ot),z(h.canvas,rt,ot),z(l.canvas,rt,ot),z(c.canvas,rt,ot),V!==rt/ot&&(V=rt/ot,H=new Y(V)),H.configure(y.hover.effect,y.hover.strength,y.hover.radius,y.hover.edgeSafe),H.step(Math.max(0,Math.min(.05,i-G))),G=i;const nt="currentTime"in e?e.getVideoPlaybackQuality?.().totalVideoFrames??e.currentTime:0,ht=[S,rt,ot,nt].join(":"),lt="dither"===y.style,ct=w(rt,ot,y,tt,et),dt=ct.cell,mt=ct.rowHeight,ft=ct.columns,ut=ct.rows;if(E!==ht||q!==e||O!==ft||U!==ut){q=e,E=ht,C="",L="",O=ft,U=ut,s.ctx.clearRect(0,0,rt,ot),s.ctx.save();const t=x(it,at,rt,ot,y.crop);s.ctx.translate(t.x+t.width/2,t.y+t.height/2),s.ctx.rotate(y.crop.rotation*Math.PI/180),s.ctx.drawImage(e,-it*t.scale/2,-at*t.scale/2,it*t.scale,at*t.scale),s.ctx.restore(),z(r.canvas,O,U),r.ctx.clearRect(0,0,O,U),r.ctx.drawImage(s.canvas,0,0,O,U),D=r.ctx.getImageData(0,0,O,U).data;const i=y.color;for(let t=0;t<D.length;t+=4){const e=.299*D[t]+.587*D[t+1]+.114*D[t+2];for(let a=0;a<3;a++){const s=e+(D[t+a]-e)*i.saturation;D[t+a]=((s*(1-i.grayscale)+e*i.grayscale)/255-.5)*i.contrast*255+127.5+255*i.brightness}}}const gt=T(y),pt=A(y),Mt=!H.active&&!gt&&!pt,xt=[ht,O,U,dt,mt,et].join(":");if(!Mt||L!==xt){h.ctx.clearRect(0,0,rt,ot),h.ctx.globalAlpha=1,h.ctx.globalCompositeOperation="source-over";const t=Z,e=gt?y.motion.type:"none",a=["none","caustics","sheen","grain","trace"].includes(e);if(lt){const a=Mt;if(!a||C!==ht){X.length!==D.length&&(X=new Uint8ClampedArray(D.length));const s=X;if(s.set(D),H.active||"none"!==e)for(let i=0;i<U;i++)for(let a=0;a<O;a++){const r=a/O,h=i/U;let l=a,c=i,d=0,m=1,f=1;H.active&&(H.sample(r,h,$),l-=$[0]*O,c-=$[1]*U,d=$[2]/3);const u=4*(i*O+a);o(e,r,h,t,K,(.299*D[u]+.587*D[u+1]+.114*D[u+2])/255),n(K,y.motion.amount??1),l-=K[0]/960*O,c-=K[1]/960*U,m=1+K[2],f=K[3],l=Math.max(0,Math.min(O-1,l)),c=Math.max(0,Math.min(U-1,c));const g=Math.floor(l),p=Math.floor(c),M=l-g,x=c-p,v=4*(i*O+a),b=4*(p*O+g),w=4*(p*O+Math.min(O-1,g+1)),S=4*(Math.min(U-1,p+1)*O+g),k=4*(Math.min(U-1,p+1)*O+Math.min(O-1,g+1));for(let t=0;t<3;t++){const e=((D[b+t]*(1-M)+D[w+t]*M)*(1-x)+(D[S+t]*(1-M)+D[k+t]*M)*x)/255;let i=(["trail","contour"].includes(y.hover.effect)?N(e,d):"etch"===y.hover.effect?Math.max(0,Math.min(1,e+.35*d)):"dissolve"===y.hover.effect?e*Math.max(0,1+d):e)*m;s[v+t]=255*i}s[v+3]=D[b+3]*f}!function(t,e,i,a,s=0){const{algorithm:r,amount:o,threshold:n}=a,h=r.startsWith("bayer")?Number(r.slice(5)):0,l=I.get(h),c=h-1,m="luminance"===a.colorSpace,f=("custom"===a.palette?a.colors:d[a.palette]??d.mono).map(R),u=P[r],g=u?new Float32Array(3*e*3):null,p="drift"===a.motion?s*a.speed*3:0,M=(a.direction??45)*Math.PI/180,x=Math.round(Math.cos(M)*p),v=Math.round(Math.sin(M)*p),b=(t,e)=>(t%e+e)%e,w=f.map(t=>.299*t[0]+.587*t[1]+.114*t[2]),y="shimmer"===a.motion?.15*Math.sin(s*a.speed*2):0;for(let a=0;a<i;a++)for(let s=0;s<e;s++){const d=4*(a*e+s),M=3*(a%3*e+s);if(0===t[d+3]){g&&(g[M]=g[M+1]=g[M+2]=0);continue}let S=0;l?S=l[(a-v&c)*h+(s-x&c)]:"noise"===r?S=F(s-x,a-v)-.5:"lines"===r?S=b(a-v,4)/3-.5:"vertical-lines"===r?S=b(s-x,4)/3-.5:"diagonal-lines"===r?S=b(s-x+a-v,4)/3-.5:"radial"===r?S=b(Math.hypot(s-e/2,a-i/2)-p,6)/6-.5:"halftone"===r&&(S=Math.hypot(b(s-x,6)-2.5,b(a-v,6)-2.5)/3.54-.5);const k=128*(S*o+y+(.5-n)),E=t[d]+k+(g?.[M]??0),A=t[d+1]+k+(g?.[M+1]??0),T=t[d+2]+k+(g?.[M+2]??0);let I=0,P=0,R=0;if(f.length){let t=1/0;const e=.299*E+.587*A+.114*T;for(let i=0;i<f.length;i++){const a=f[i],s=m?(e-w[i])**2:(E-a[0])**2*.299+(A-a[1])**2*.587+(T-a[2])**2*.114;s<t&&(t=s,[I,P,R]=a)}}else I=51*Math.round(E/51),P=51*Math.round(A/51),R=51*Math.round(T/51);if(t[d]=I,t[d+1]=P,t[d+2]=R,g&&u){g[M]=g[M+1]=g[M+2]=0;for(const[t,r,n]of u){const h=s+t;if(h<0||h>=e||a+r>=i)continue;const l=3*((a+r)%3*e+h);g[l]+=(E-I)*n*o,g[l+1]+=(A-P)*n*o,g[l+2]+=(T-R)*n*o}}}}(s,O,U,y.dither,i),r.ctx.putImageData(new ImageData(s,O,U),0,0),C=a?ht:""}h.ctx.imageSmoothingEnabled=!1,h.ctx.drawImage(r.canvas,0,0,rt,ot)}else{const i=Array.from(W[y.style]??y.charset),s=h.ctx,r=R(y.ink),l="ascii"===y.style||!!W[y.style],c=Math.max(3,Math.round(.92*mt)),d=Math.ceil(dt+4),m=Math.ceil(mt+4),u=[i.join(""),c,d,m,y.ink,y.colorMode].join(":");if(l&&u!==j&&(j=u,z(f.canvas,d*i.length,m),f.ctx.clearRect(0,0,f.canvas.width,m),f.ctx.font=`${c}px monospace`,f.ctx.textBaseline="middle",f.ctx.textAlign="center",f.ctx.fillStyle="accent"===y.colorMode?y.ink:"#ffffff",i.forEach((t,e)=>f.ctx.fillText(t,e*d+d/2,m/2))),"lego"===y.style&&b!==dt){b=dt,z(p.canvas,Math.ceil(dt),Math.ceil(mt));const t=p.ctx;t.clearRect(0,0,p.canvas.width,p.canvas.height),t.fillStyle="rgba(255,255,255,.2)",t.strokeStyle="rgba(0,0,0,.25)",t.lineWidth=Math.max(.5,.6*et),t.beginPath(),t.arc(dt/2,mt/2,.28*dt,0,2*Math.PI),t.fill(),t.stroke()}s.font=`${c}px monospace`,s.textBaseline="middle",s.textAlign="center";for(let h=0;h<U;h++)for(let c=0;c<O;c++){let u=c,g=h,M=0;if(H.active&&(H.sample(c/O,h/U,$),u=Math.max(0,Math.min(O-1,c-$[0]*O)),g=Math.max(0,Math.min(U-1,h-$[1]*U)),M=$[2]/3),k(D,O,U,u,g,Q),!Q[3])continue;const x=Q[0],v=Q[1],b=Q[2],w=(.299*x+.587*v+.114*b)/255;let S=w;["trail","contour"].includes(y.hover.effect)&&M?S=N(S,M):"etch"===y.hover.effect?S=Math.max(0,Math.min(1,S+.35*M)):"dissolve"===y.hover.effect&&(S*=Math.max(0,1+M));let E=c*dt,A=h*mt,T=1;o(e,c/O,h/U,t,K,w),n(K,y.motion.amount??1),E+=K[0]*rt/960,A+=K[1]*ot/960,S=Math.max(0,Math.min(1,S+K[2])),T=K[3]*Q[3]/255,l||"accent"!==y.colorMode||"cmyk"===y.style||(T*=S),s.globalAlpha=T;const I=255*(S-w),P="source"===y.colorMode?`rgb(${x+I},${v+I},${b+I})`:"gray"===y.colorMode?`rgb(${Math.round(255*S)},${Math.round(255*S)},${Math.round(255*S)})`:y.ink;if(s.fillStyle=P,l){const t=Math.max(0,Math.min(i.length-1,Math.round(S*(i.length-1))));"accent"===y.colorMode?s.drawImage(f.canvas,t*d,0,d,m,a?Math.round(E+(dt-d)/2):E+(dt-d)/2,a?Math.round(A+(mt-m)/2):A+(mt-m)/2,d,m):s.fillText(i[t],E+dt/2,A+mt/2)}else if("dots"===y.style)s.beginPath(),s.arc(E+dt/2,A+mt/2,.48*dt*Math.sqrt(S),0,2*Math.PI),s.fill();else if("led"===y.style)s.beginPath(),s.arc(E+dt/2,A+mt/2,.39*dt,0,2*Math.PI),s.fill(),s.globalAlpha=.35*T,s.fillStyle="#ffffff",s.beginPath(),s.arc(E+.43*dt,A+.4*mt,.11*dt,0,2*Math.PI),s.fill();else if("hex"===y.style){const t=E+dt/2,e=A+mt/2;s.beginPath();for(let i=0;i<6;i++){const a=Math.PI/3*i,r=t+Math.cos(a)*dt*.49,o=e+Math.sin(a)*mt*.49;0===i?s.moveTo(r,o):s.lineTo(r,o)}s.closePath(),s.fill()}else if("cmyk"===y.style){s.fillStyle="#ffffff",s.fillRect(E,A,dt,mt);const t=(t,e)=>Math.max(0,Math.min(255,"source"===y.colorMode?t+I:"gray"===y.colorMode?255*S:e*S)),e=t(x,r[0]),i=t(v,r[1]),a=t(b,r[2]),o=1-Math.max(e,i,a)/255,n=Math.max(.001,1-o),h=[["#00ffff",(1-e/255-o)/n,.36,.36],["#ff00ff",(1-i/255-o)/n,.64,.36],["#ffff00",(1-a/255-o)/n,.5,.66],["#000000",o,.5,.5]];s.globalCompositeOperation="multiply";for(const[t,e,i,a]of h)s.fillStyle=t,s.beginPath(),s.arc(E+dt*i,A+mt*a,.48*dt*Math.sqrt(Math.max(0,e)),0,2*Math.PI),s.fill();s.globalCompositeOperation="source-over"}else if("voxel"===y.style){const t=E+dt/2,e=A+mt/2;s.beginPath(),s.moveTo(t,A),s.lineTo(E+dt,A+.25*mt),s.lineTo(t,e),s.lineTo(E,A+.25*mt),s.closePath(),s.fill(),s.globalAlpha=.72*T,s.beginPath(),s.moveTo(E,A+.25*mt),s.lineTo(t,e),s.lineTo(t,A+mt),s.lineTo(E,A+.75*mt),s.closePath(),s.fill(),s.globalAlpha=.42*T,s.beginPath(),s.moveTo(t,e),s.lineTo(E+dt,A+.25*mt),s.lineTo(E+dt,A+.75*mt),s.lineTo(t,A+mt),s.closePath(),s.fill()}else{const t="pixel"===y.style?0:Math.max(.5,.06*dt);s.fillRect(E,A,dt-t,mt-t),"lego"===y.style&&s.drawImage(p.canvas,E,A),"disco"===y.style&&(s.fillStyle=`rgba(255,255,255,${.1+.25*F(c,h)})`,s.fillRect(E,A,dt-t,.35*mt),s.fillStyle="rgba(0,0,0,.25)",s.fillRect(E,A+.65*mt,dt-t,.35*mt-t))}}}h.ctx.globalAlpha=1,(y.color.amount||y.lights.length)&&(z(u.canvas,rt,ot),u.ctx.clearRect(0,0,rt,ot),u.ctx.drawImage(h.canvas,0,0)),y.color.amount&&(h.ctx.save(),h.ctx.globalCompositeOperation=y.color.blend,h.ctx.globalAlpha=y.color.amount,h.ctx.fillStyle=y.color.tint,h.ctx.fillRect(0,0,rt,ot),h.ctx.restore());for(const t of y.lights){const e=t.radius*Math.max(rt,ot),i=h.ctx.createRadialGradient(t.x*rt,t.y*ot,0,t.x*rt,t.y*ot,e);i.addColorStop(0,t.color),i.addColorStop(1,"transparent"),h.ctx.save(),h.ctx.globalCompositeOperation="screen",h.ctx.globalAlpha=t.intensity,h.ctx.fillStyle=i,h.ctx.fillRect(0,0,rt,ot),h.ctx.restore()}if((y.color.amount||y.lights.length)&&(h.ctx.globalCompositeOperation="destination-in",h.ctx.drawImage(u.canvas,0,0),h.ctx.globalCompositeOperation="source-over"),y.mask.enabled&&y.mask.shapes.length){const t=c.ctx;t.clearRect(0,0,rt,ot),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)*rt,(e.y+e.height/2)*ot,e.width*rt/2,e.height*ot/2,0,0,2*Math.PI);else{if("rectangle"!==e.kind){if(t.lineWidth=(e.size??.05)*rt,1===e.points?.length){t.arc(e.points[0][0]*rt,e.points[0][1]*ot,t.lineWidth/2,0,2*Math.PI),t.fill();continue}e.points?.forEach(([e,i],a)=>a?t.lineTo(e*rt,i*ot):t.moveTo(e*rt,i*ot)),t.stroke();continue}t.rect(e.x*rt,e.y*ot,e.width*rt,e.height*ot)}t.fill()}h.ctx.globalCompositeOperation=y.mask.invert?"destination-out":"destination-in",h.ctx.drawImage(c.canvas,0,0),h.ctx.globalCompositeOperation="source-over"}const M=l.ctx;M.clearRect(0,0,rt,ot),M.globalAlpha=y.backdrop.opacity;const x=y.backdrop;if("solid"===x.mode&&(M.fillStyle=x.color,M.fillRect(0,0,rt,ot)),"gradient"===x.mode){const t=M.createLinearGradient(0,0,rt,ot);t.addColorStop(0,x.color),t.addColorStop(1,x.color2),M.fillStyle=t,M.fillRect(0,0,rt,ot)}if("source"===x.mode&&M.drawImage(s.canvas,0,0),"blurred"===x.mode){const t=Math.max(1,x.blur);z(m.canvas,Math.max(2,Math.round(rt/t)),Math.max(2,Math.round(ot/t))),m.ctx.drawImage(s.canvas,0,0,m.canvas.width,m.canvas.height),M.imageSmoothingEnabled=!0,M.drawImage(m.canvas,0,0,rt,ot)}M.globalAlpha=1,y.effects.characterBloom>0&&(z(g.canvas,Math.max(2,Math.round(rt/3)),Math.max(2,Math.round(ot/3))),g.ctx.clearRect(0,0,g.canvas.width,g.canvas.height),g.ctx.drawImage(h.canvas,0,0,g.canvas.width,g.canvas.height),M.save(),M.globalAlpha=.8*y.effects.characterBloom,M.globalCompositeOperation="screen",M.filter=`blur(${1+4*y.effects.characterBloom}px)`,M.drawImage(g.canvas,0,0,rt,ot),M.restore()),M.drawImage(h.canvas,0,0),L=Mt?xt:""}const vt=Object.entries(y.effects).some(([t,e])=>!["angle","focus","blurType","characterBloom"].includes(t)&&"number"==typeof e&&e>0);a.clearRect(0,0,rt,ot),vt?(void 0===v&&(v=function(){const t=document.createElement("canvas"),e=t.getContext("webgl",{alpha:!0,premultipliedAlpha:!1,antialias:!1,preserveDrawingBuffer:!0});if(!e)return null;const i=[],a=(t,a)=>{const s=e.createShader(t);if(i.push(s),e.shaderSource(s,a),e.compileShader(s),!e.getShaderParameter(s,e.COMPILE_STATUS))throw new Error(e.getShaderInfoLog(s)||"Finish shader failed");return s},s=e.createProgram();if(e.attachShader(s,a(e.VERTEX_SHADER,"attribute vec2 p;varying vec2 uv;void main(){uv=(p+1.)*.5;gl_Position=vec4(p,0.,1.);}")),e.attachShader(s,a(e.FRAGMENT_SHADER,"precision mediump float;varying vec2 uv;uniform sampler2D src;uniform vec2 size;uniform float t,bloom,grain,dust,scanlines,crt,prism,vignette,glitch,pixelate,blur,blurMode,angle,focus,halftone,rgbSplit,sharpen;\n float hash(vec2 p){return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453);}\n vec4 sampleAt(vec2 p){if(min(min(p.x,p.y),min(1.-p.x,1.-p.y))<0.)return vec4(0.);return texture2D(src,vec2(p.x,1.-p.y));}\n void main(){vec2 q=uv,c=q-.5;q=c*(1.+dot(c,c)*crt*.25)+.5;\n if(glitch>0.)q.x+=(hash(vec2(floor(q.y*35.),floor(t*5.)))-.5)*.07*glitch*step(.82,hash(vec2(floor(q.y*35.),floor(t*5.)+3.)));\n if(pixelate>0.){vec2 grid=size/(1.+pixelate*20.);q=(floor(q*grid)+.5)/grid;}\n vec4 base=sampleAt(q);float edge=smoothstep(.12,.65,length(c));\n vec2 shift=vec2((prism*3.*edge+rgbSplit*8.)/size.x,prism*edge/size.y);\n if(prism>0.||rgbSplit>0.)base.rgb=vec3(sampleAt(q+shift).r,base.g,sampleAt(q-shift).b);\n vec2 dir=vec2(cos(angle),sin(angle))/size;float amount=blur;\n if(blurMode>1.5&&blurMode<2.5){dir=normalize(c+vec2(.0001))/size;amount*=length(c)*2.;}\n if(blurMode>2.5)amount*=smoothstep(.05,.5,abs(q.y-focus));\n vec4 blurred=base;\n if(amount>0.){blurred=base*.2;for(int i=1;i<=4;i++){float f=float(i)*amount*.35;vec2 off=dir*f;if(blurMode<.5)off=vec2(cos(float(i)*1.57),sin(float(i)*1.57))*amount/size;blurred+=sampleAt(q+off)*.1+sampleAt(q-off)*.1;}}\n vec3 light=vec3(0.);if(bloom>0.)for(int i=0;i<4;i++){float a=float(i)*1.5708;vec3 s=sampleAt(q+vec2(cos(a),sin(a))*6./size).rgb;light+=max(vec3(0.),s-.35)*.25;}\n vec3 col=blurred.rgb+light*bloom;\n if(sharpen>0.){vec2 px=1./size;vec3 near=sampleAt(q+vec2(px.x,0.)).rgb+sampleAt(q-vec2(px.x,0.)).rgb+sampleAt(q+vec2(0.,px.y)).rgb+sampleAt(q-vec2(0.,px.y)).rgb;col+=(base.rgb*4.-near)*sharpen*.5;}\ncol*=1.-scanlines*.4*(.5+.5*cos(q.y*size.y*3.14159));\n col*=1.-vignette*smoothstep(.15,.72,length(c));\n col+=(hash(floor(q*size)+floor(t*12.))-.5)*grain*.2;\n if(dust>0.)col+=step(1.-dust*.002,hash(floor(q*size*.25)+floor(t*2.)))*.4;\n if(halftone>0.)col*=mix(1.,smoothstep(.1,.65,length(fract(q*size/6.)-.5)),halftone);\n gl_FragColor=vec4(clamp(col,0.,1.),blurred.a);}")),e.linkProgram(s),!e.getProgramParameter(s,e.LINK_STATUS))throw new Error("Finish link failed");e.useProgram(s);const r=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,r),e.bufferData(e.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,1]),e.STATIC_DRAW);const o=e.getAttribLocation(s,"p");e.enableVertexAttribArray(o),e.vertexAttribPointer(o,2,e.FLOAT,!1,0,0);const n=e.createTexture();e.bindTexture(e.TEXTURE_2D,n),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE);const h=["t","bloom","grain","dust","scanlines","crt","prism","rgbSplit","sharpen","vignette","glitch","pixelate","blur","blurMode","angle","focus","halftone"],l=Object.fromEntries(h.map(t=>[t,e.getUniformLocation(s,t)])),c=e.getUniformLocation(s,"size");return{canvas:t,render(i,a,r,o=1){t.width===i.width&&t.height===i.height||(t.width=i.width,t.height=i.height,e.viewport(0,0,t.width,t.height)),e.useProgram(s),e.bindTexture(e.TEXTURE_2D,n),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,i),e.uniform2f(c,t.width/o,t.height/o);for(const t of h)e.uniform1f(l[t],"t"===t?r:"blurMode"===t?["gaussian","directional","radial","progressive"].indexOf(a.blurType):"angle"===t?a.angle*Math.PI/180:a[t]??0);return e.drawArrays(e.TRIANGLE_STRIP,0,4),t},destroy(){e.deleteTexture(n),e.deleteBuffer(r),e.deleteProgram(s),i.forEach(t=>e.deleteShader(t)),t.width=t.height=1,e.getExtension("WEBGL_lose_context")?.loseContext()}}}()),v?a.drawImage(v.render(l.canvas,y.effects,i,et),0,0):a.drawImage(l.canvas,0,0),t.dataset.studioFinish=v?"gpu":"unavailable"):(a.drawImage(l.canvas,0,0),t.dataset.studioFinish="none")},setPixelRatio(t){et=Math.max(.1,Math.min(8,Number.isFinite(t)?t:1))},get pixelRatio(){return et},setBudget(t){tt=Math.max(256,Math.min(Z,Number.isFinite(t)?Math.round(t):Z))},get maxCells(){return tt},configure(t){y=M(t),S++},pointer:(t,e,i)=>{H.configure(y.hover.effect,y.hover.strength,y.hover.radius,y.hover.edgeSafe),H.move(t,e,i)},leave(){H.leave()},get active(){return H.active},get settings(){return M(y)},get capabilities(){return{gpuFinish:null!==v}},invalidate(){E=""},destroy(){v?.destroy();for(const t of[s,r,h,l,c,m,f,u,g,p])t.canvas.width=t.canvas.height=1;q=null,D=new Uint8ClampedArray(0)}}}function q(t,e,i){return new Promise((a,s)=>{const r=()=>{l(),a()},o=()=>{l(),s(new Error("Unable to load this media. Check its format and cross-origin permissions."))},n=()=>{l(),s(new DOMException("Cancelled","AbortError"))},h=setTimeout(o,2e4),l=()=>{clearTimeout(h),t.removeEventListener(e,r),t.removeEventListener("error",o),i?.removeEventListener("abort",n)};t.addEventListener(e,r,{once:!0}),t.addEventListener("error",o,{once:!0}),i?.addEventListener("abort",n,{once:!0}),i?.aborted&&n()})}async function j(t,e){if("string"==typeof t&&t.startsWith("blob:")){const i=await fetch(t,{signal:e}),a=await i.blob();return j(new File([a],"Imported media",{type:a.type}),e)}const i="string"!=typeof t,a=i?t.name:t;if(i?"image/gif"===t.type:/\.gif(?:[?#]|$)/i.test(a)){const a=await import("gifuct-js"),{parseGIF:s,decompressFrames:r}="function"==typeof a.parseGIF?a:a.default,o=i?await t.arrayBuffer():await fetch(t,{signal:e}).then(t=>{if(!t.ok)throw new Error("GIF download failed.");return t.arrayBuffer()});if(e?.aborted)throw new DOMException("Cancelled","AbortError");const n=s(o),h=n.lsd.width,l=n.lsd.height;if(h*l>4e6)throw new Error("GIF is too large. Use a smaller GIF or an MP4.");const c=n.frames.filter(t=>"image"in t).length;if(!c||c*h*l*4>128e6)throw new Error("GIF exceeds the decoded memory budget. Use MP4 for long animations.");const 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"),g=u.getContext("2d"),p=d.reduce((t,e)=>t+Math.max(20,e.delay),0)/1e3;let M=-1,x=null;const v=t=>{const e=(t%p+p)%p*1e3;let i=0,a=0;for(;a<d.length-1&&(i+=Math.max(20,d[a].delay),!(e<i));a++);a<M&&(f.clearRect(0,0,h,l),M=-1,x=null);for(let t=M+1;t<=a;t++){const e=d[t-1];2===e?.disposalType&&f.clearRect(e.dims.left,e.dims.top,e.dims.width,e.dims.height),3===e?.disposalType&&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,g.putImageData(new ImageData(new Uint8ClampedArray(i.patch),u.width,u.height),0,0),f.drawImage(u,i.dims.left,i.dims.top)}return M=a,m};return v(0),{source:m,width:h,height:l,duration:p,animated:!0,seek:async()=>{},frame:v,destroy(){m.width=u.width=1,d.length=0,x=null}}}const s=i?t.type.startsWith("video/"):/\.(mp4|webm|mov)(?:[?#]|$)/i.test(a),r=i?URL.createObjectURL(t):t,o=s?document.createElement("video"):new Image;o.crossOrigin="anonymous",o instanceof HTMLVideoElement&&(o.muted=!0,o.playsInline=!0,o.preload="auto");const n=()=>{o instanceof HTMLVideoElement?(o.pause(),o.removeAttribute("src"),o.load()):o.src="",i&&URL.revokeObjectURL(r)};try{const t=q(o,s?"loadeddata":"load",e);o.src=r,await t;const i=o instanceof HTMLVideoElement?o.videoWidth:o.naturalWidth,a=o instanceof HTMLVideoElement?o.videoHeight:o.naturalHeight;return{source:o,width:i,height:a,duration:o instanceof HTMLVideoElement?o.duration:0,animated:s,async seek(t,e){if(!(o instanceof HTMLVideoElement))return;if(!Number.isFinite(o.duration)||o.duration<=0)throw new Error("Video duration is unavailable.");const i=Math.max(0,Math.min(o.duration-.001,t%o.duration));if(Math.abs(o.currentTime-i)<.001&&o.readyState>=2)return;const a=q(o,"seeked",e);o.currentTime=i,await a},frame:()=>o,destroy:n}}catch(t){throw n(),t}}var H=t=>{if(t?.aborted)throw new DOMException("Export cancelled","AbortError")};function V(t,e,i={}){let a=M(i.settings),s=i.width??e.width,o=i.height??e.height;const n=G(t,a,i),h=new r;let l=0,c=!1,d=!0,m=!1,f=!0,u=0,g=0,p=0,x=0,w=-1,y=!1!==i.adaptive,S=0,k=0,E=0;const F=matchMedia("(prefers-reduced-motion: reduce)"),I=e.source instanceof HTMLVideoElement?e.source:null,P=()=>{c||l||!f||document.hidden||(l=requestAnimationFrame(L))},R=()=>!m&&!F.matches&&f&&!document.hidden,C=()=>{I&&(I.loop=!0,R()?I.play().catch(()=>{m=!0,d=!0,P()}):I.pause()),p=0,d=!0,P()};function L(t){if(l=0,c||!f||document.hidden)return;const r=R();r&&(u+=p?Math.min(.1,(t-p)/1e3):0),p=t;const M=function(t){return T(t)||A(t)||t.effects.grain>0||t.effects.dust>0||t.effects.glitch>0}(a),b=r&&(e.animated||M),F=I?.getVideoPlaybackQuality?.().totalVideoFrames??-1,C=!I||F<0||F!==w;if(d||n.active||b&&(C||M)&&t-x>=1e3/Math.max(1,Math.min(60,i.fps??60))-.5){const r=performance.now();try{e.animated&&!I&&n.invalidate();const[t,l]=v(s,o,a);g=h.update(u,a.motion.type,a.motion.speed),n.render(e.frame(I?.currentTime??u),u,t,l,g);const c=performance.now()-r;i.onFrame?.(I?.currentTime??u,c),k=k?.9*k+.1*c:c,++S>20&&y&&(b||n.active)&&(E=k>13?E+1:0,E>=12&&n.maxCells>3e3&&(n.setBudget(Math.max(3e3,.8*n.maxCells)),i.onQualityChange?.(n.maxCells),E=0,k=0))}catch(t){m=!0,i.onError?.(t instanceof Error?t:new Error(String(t)))}d=!1,x=t,w=F}r&&(b||n.active)&&P()}const D=e=>{if(!R())return;const i=t.getBoundingClientRect();n.pointer((e.clientX-i.left)/i.width,(e.clientY-i.top)/i.height,e.timeStamp),P()},X=()=>{n.leave(),P()},O=new IntersectionObserver(([t])=>{f=t.isIntersecting,C()});O.observe(t),t.addEventListener("pointermove",D),t.addEventListener("pointerleave",X),t.addEventListener("pointercancel",X),document.addEventListener("visibilitychange",C),F.addEventListener("change",C);const N=()=>{c||(c=!0,cancelAnimationFrame(l),O.disconnect(),t.removeEventListener("pointermove",D),t.removeEventListener("pointerleave",X),t.removeEventListener("pointercancel",X),document.removeEventListener("visibilitychange",C),F.removeEventListener("change",C),i.signal?.removeEventListener("abort",N),n.destroy(),e.destroy())};if(i.signal?.addEventListener("abort",N,{once:!0}),i.signal?.aborted)throw N(),new DOMException("Cancelled","AbortError");return C(),{canvas:t,media:e,update(t){a=b(a,t),n.configure(a),d=!0,P()},resize(t,e,i){void 0!==i&&n.setPixelRatio(i),s=Math.max(2,t),o=Math.max(2,e),d=!0,P()},pause(t=!0){m=t,C()},async seek(t){u=Math.max(0,t),await e.seek(u),n.invalidate(),d=!0,P()},redraw(){n.invalidate(),d=!0,P()},get time(){return I?.currentTime??u},get motionTime(){return g},get paused(){return m||F.matches},setAdaptive(t){y=t,S=E=k=0},setBudget(t){n.setBudget(t),i.onQualityChange?.(n.maxCells),d=!0,P()},get pixelRatio(){return n.pixelRatio},get maxCells(){return n.maxCells},get capabilities(){return n.capabilities},destroy:N}}var $={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")},K=Object.keys($);var Q={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:" ⠁⠃⠇⡇⣇⣧⣷⣿"}},J=Q;exports.BLEND_MODES=c,exports.CHARACTER_SETS=Q,exports.DEFAULT_STUDIO_SETTINGS=m,exports.DITHER_ALGORITHMS=l,exports.STUDIO_CHARACTER_SETS=J,exports.STUDIO_HOVERS=t,exports.STUDIO_LOOKS=y,exports.STUDIO_MOTIONS=e,exports.STUDIO_PALETTES=d,exports.STUDIO_STYLES=h,exports.STUDIO_TEXT_FONTS=K,exports.createStudioRenderer=G,exports.createStudioText=async function(t,e="Standard",i="#ffffff"){if(!Object.prototype.hasOwnProperty.call($,e))throw new Error("Unknown text font.");const{default:a}=await import("figlet/browser"),s=await $[e]();a.parseFont(e,s.default),a.defaults({fetchFontIfMissing:!1});const r=a.textSync(t.slice(0,120),{font:e}),o=r.split("\n"),n=Math.max(1,...o.map(t=>t.length)),h=Math.max(1,o.length),l=Math.min(1,2048/(9*n)),c=document.createElement("canvas");c.width=Math.ceil(9*n*l+32),c.height=Math.ceil(15*h*l+32);const 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:a,signal:s}=i,r=Math.round(i.width),o=Math.round(i.height);if(!Number.isFinite(r)||!Number.isFinite(o)||r<2||o<2||r>4096||o>4096||r*o>16777216)throw new Error("Choose export dimensions between 2 and 4096 pixels.");if(!["png","jpeg","mp4","webm","gif"].includes(a))throw new Error("Unknown export format.");if(void 0!==i.fps&&!Number.isFinite(i.fps))throw new Error("Frames per second must be finite.");const n=Math.max(1,Math.min(60,Math.round(i.fps??24))),h=i.duration??5;if(!Number.isFinite(h)||h<=0||h>60)throw new Error("Choose a duration from 0 to 60 seconds.");const l="png"===a||"jpeg"===a,c=i.time??0;if(!Number.isFinite(c)||c<0)throw new Error("Image time must be a finite non-negative number.");if(void 0!==i.motionTime&&(!Number.isFinite(i.motionTime)||i.motionTime<0))throw new Error("Motion time must be a finite non-negative number.");if(!l&&r*o>8294400)throw new Error("Video exports support up to 3840 × 2160 pixels.");if("gif"===a&&(r*o>921600||h*n>600))throw new Error("GIF export supports up to 1280 × 720 and 600 frames. Use MP4 for larger exports.");if(void 0!==i.referenceWidth&&(!Number.isFinite(i.referenceWidth)||i.referenceWidth<1))throw new Error("Reference width must be a positive number.");if("gif"===a&&n>30)throw new Error("GIF exports support up to 30 fps. Choose MP4 or WebM for higher frame rates.");const d=document.createElement("canvas"),m=G(d,M(e),{maxDimension:4096,maxCells:i.maxCells??12e3,pixelRatio:r/(i.referenceWidth??Math.min(r,960))});let f;try{if(H(s),i.onProgress?.(0),l){if(m.render(await t.frame(c,s),c,r,o,i.motionTime),"unavailable"===d.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");H(s);const e=await new Promise((t,e)=>d.toBlob(i=>i?t(i):e(new Error("Image export failed.")),"png"===a?"image/png":"image/jpeg",i.quality??.92));return i.onProgress?.(1),e}const e=Math.ceil(h*n);if("gif"===a){const a=await import("gifenc"),{GIFEncoder:l,quantize:c,applyPalette:f}="function"==typeof a.GIFEncoder?a:a.default,u=l(),g=d.getContext("2d");for(let a=0;a<e;a++){H(s);const l=a/n;if(m.invalidate(),m.render(await t.frame(l,s),l,r,o),"unavailable"===d.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=f(p,M);u.writeFrame(x,r,o,{palette:M,delay:10*(Math.round(100*Math.min((a+1)/n,h))-Math.round(100*a/n)),repeat:0}),i.onProgress?.((a+1)/e*.98),await new Promise(t=>setTimeout(t,0))}return u.finish(),i.onProgress?.(1),new Blob([new Uint8Array(u.bytes())],{type:"image/gif"})}const{Output:u,Mp4OutputFormat:g,WebMOutputFormat:p,BufferTarget:M,CanvasSource:x,canEncodeVideo:v}=await import("mediabunny"),b="mp4"===a?"avc":"vp9";if(!await v(b,{width:r,height:o}))throw new Error(`${a.toUpperCase()} encoding is unavailable in this browser. Try another format or a current browser with WebCodecs.`);const w=new u({format:"mp4"===a?new g({fastStart:"in-memory"}):new p,target:new M});d.width=r,d.height=o,f=()=>w.cancel();const y=new x(d,{codec:b,bitrate:Math.max(5e5,Math.round(r*o*n*.15))});w.addVideoTrack(y,{frameRate:n}),d.width=r,d.height=o,await w.start();for(let a=0;a<e;a++){H(s);const l=a/n;if(m.invalidate(),m.render(await t.frame(l,s),l,r,o),"unavailable"===d.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");await y.add(l,Math.min(1/n,h-l)),i.onProgress?.((a+1)/e*.98),a%4==0&&await new Promise(t=>setTimeout(t,0))}return y.close(),H(s),await w.finalize(),f=void 0,i.onProgress?.(1),new Blob([w.target.buffer],{type:"mp4"===a?"video/mp4":"video/webm"})}catch(t){throw await(f?.().catch(()=>{})),t}finally{m.destroy(),d.width=d.height=1}},exports.loadStudioMedia=j,exports.mountStudio=async function(t,e,i={}){const a=await j(e,i.signal);try{return V(t,a,i)}catch(t){throw a.destroy(),t}},exports.mountStudioMedia=V,exports.normalizeStudioSettings=M,exports.parseStudioSettings=function(t){if(t.length>1e5)throw new Error("Settings exceed 100 KB.");return M(JSON.parse(t))},exports.restyleStudio=function(t,e=Math.random){const i=y.filter(e=>e.settings.style!==t.style||e.settings.ink!==t.ink),a=S(i[Math.min(i.length-1,Math.max(0,Math.floor(e()*i.length)))].id);return a.aspectRatio=t.aspectRatio,a.crop={...t.crop},a.mask=M(t).mask,a},exports.serializeStudioSettings=function(t){return JSON.stringify(M(t))},exports.studioCrop=x,exports.studioDimensions=v,exports.studioGrid=w,exports.studioLook=S,exports.studioSourceSize=_,exports.updateStudioSettings=b;//# sourceMappingURL=studio.cjs.map
|
|
1
|
+
"use strict";var t=[{value:"none",label:"Off",group:"Still",description:"Keep the artwork still under the pointer."},{value:"trail",label:"Trail",group:"Change characters",description:"A fluid wake changes character density and settles behind your cursor."},{value:"dissolve",label:"Dissolve",group:"Change characters",description:"Erase a soft path through the characters; the image gradually reforms."},{value:"contour",label:"Contour",group:"Change characters",description:"Fine tonal rings trace your path without moving the grid."},{value:"etch",label:"Emboss",group:"Change characters",description:"Press a light-and-shadow impression into the characters; the grid stays fixed."},{value:"water",label:"Water",group:"Move the image",description:"Soft ripples refract the image and settle after your stroke."},{value:"silk",label:"Silk",group:"Move the image",description:"Directional folds follow the movement of your hand."},{value:"vortex",label:"Vortex",group:"Move the image",description:"A swirling wake curls through the image."},{value:"magnetic",label:"Magnetic Pull",group:"Move the image",description:"The image gathers toward your stroke, then relaxes."},{value:"scatter",label:"Scatter",group:"Move the image",description:"A textured outward scatter settles behind your cursor."},{value:"elastic",label:"Elastic",group:"Move the image",description:"Push the image with your stroke; it recoils and springs back into place."},{value:"rake",label:"Rake",group:"Move the image",description:"Comb the image into alternating ribbons that glide back into alignment."}],e=[{value:"none",mode:"none",group:"Still",label:"Off",description:"Keep the image still. Hover stays available."},{value:"caustics",mode:"caustics",group:"Light and texture",label:"Caustics",description:"Soft ribbons of light travel across a stationary character grid."},{value:"current",mode:"current",group:"Flow and depth",label:"Slow Current",description:"A gentle flow through the image, with steady edges."},{value:"reform",mode:"reform",group:"Rebuild",label:"Reveal & Reform",description:"Disperse, gather, then hold the complete image."},{value:"sheen",mode:"sheen",group:"Light and texture",label:"Sheen",description:"A broad diagonal light sweep; characters stay anchored."},{value:"tidal",mode:"tidal",group:"Flow and depth",label:"Tidal Rings",description:"Concentric currents travel outward, with protected edges."},{value:"grain",mode:"grain",group:"Light and texture",label:"Living Grain",description:"Slow, individually phased tonal changes on a stationary grid."},{value:"parallax",mode:"parallax",group:"Flow and depth",label:"Parallax",description:"A shallow, continuous drift through the image, with the edges held in place."},{value:"weave",mode:"weave",group:"Flow and depth",label:"Woven Flow",description:"Interlaced bands move in opposing directions, like a flexible printed fabric."},{value:"print",mode:"print",group:"Rebuild",label:"Print Shift",description:"Staggered rows lift, soften and register back into the image."},{value:"trace",mode:"trace",group:"Light and texture",label:"Contour Light",description:"Light follows the source image’s tonal contours; every character stays anchored."}],i=t=>Math.max(0,Math.min(1,t)),a=(t,e,a)=>{const s=i((a-t)/(e-t));return s*s*(3-2*s)},s=(t,e)=>{const i=(.06711056*t+.00583715*e)%1*52.9829189;return i-Math.floor(i)},r=class{constructor(){this.last=null,this.mode="none",this.phase=0}update(t,e,i=1){return Number.isFinite(t)?((e!==this.mode||null!==this.last&&t<this.last)&&(this.mode=e,this.phase=0,this.last=t),null!==this.last&&(this.phase+=Math.max(0,t-this.last)*Math.max(.1,Math.min(3,Number.isFinite(i)?i:1))),this.last=t,this.phase):this.phase}};function o(t,e,r,o,n,h=.5){if(n[0]=n[1]=n[2]=0,n[3]=1,"none"===t)return n;const l=o*Math.PI/6,c=a(0,.12,Math.min(e,1-e,r,1-r));if("caustics"===t){const t=Math.sin(9*e+5*r+l)+Math.sin(8*r-3*e-l),i=Math.pow(Math.max(0,1-.72*Math.abs(t)),3);n[2]=(.22*i-.045)*c}else if("current"===t)n[0]=Math.sin(9*r+l)*Math.cos(7*e-l)*10*c,n[1]=Math.cos(8*e+l)*Math.sin(6*r-l)*7*c;else if("sheen"===t)n[2]=.2*Math.pow(.5+.5*Math.cos(5*e+3*r-l),8)-.025;else if("tidal"===t){const t=e-.5,i=r-.5,a=Math.hypot(t,i),s=Math.sin(22*a-l)*c;n[0]=t*s*9,n[1]=i*s*9,n[2]=.035*s}else if("grain"===t){const t=s(Math.floor(160*e),Math.floor(100*r))*Math.PI*2;n[2]=.07*Math.sin(l+t)}else if("parallax"===t){const t=.45+.55*Math.max(0,1-1.4*Math.hypot(e-.5,r-.5));n[0]=12*Math.sin(l)*t*c,n[1]=6*(Math.cos(l)-1)*t*c}else if("weave"===t)n[0]=Math.sin(r*Math.PI*6+l)*Math.sin(l)*8*c,n[1]=Math.sin(e*Math.PI*6-l)*Math.sin(l)*6*c;else if("print"===t){const t=Math.floor(24*r),e=((o+3*s(t,3))%12+12)%12,i=a(1,2.5,e)*(1-a(3.5,5,e));n[0]=Math.sin(2.4*t)*i*9*c,n[1]=5*-i*c,n[2]=.22*-i,n[3]=1-.45*i}else if("trace"===t){const t=.5+.5*Math.cos(l);n[2]=.22*Math.pow(Math.max(0,1-Math.abs(i(h)-t)/.16),3)-.015}else if("reform"===t){const t=(o%12+12)%12,i=s(Math.floor(160*e),Math.floor(100*r)),h=.65*e+.2*r+.15*i+.08*Math.sin(8*e-5*r),m=a(1.8+1.2*h,3.8+1.2*h,t)*(1-a(5+1.7*h,7.2+1.7*h,t));n[0]=Math.sin(9*r+l)*m*(1-m)*24*c,n[1]=-m*(1-m)*(8+12*i)*c,n[2]=.45*-m,n[3]=1-.9*m}return n}function n(t,e){const a=Math.max(0,Math.min(2,Number.isFinite(e)?e:1));return t[0]*=a,t[1]*=a,t[2]*=a,t[3]=i(1+(t[3]-1)*a),t}var h=["rgb","red","green","blue"],l=t=>Math.max(0,Math.min(1,t));function c(t){const e=new Map([[0,0],[1,1]]);if(Array.isArray(t))for(const i of t.slice(0,64)){if(!Array.isArray(i)||i.length<2||"number"!=typeof i[0]||!Number.isFinite(i[0])||"number"!=typeof i[1]||!Number.isFinite(i[1]))continue;const t=Math.round(255*l(i[0]))/255;!e.has(t)&&e.size>=16||e.set(t,l(i[1]))}return[...e].sort((t,e)=>t[0]-e[0])}function m(t){const e=t&&"object"==typeof t?t:{};return Object.fromEntries(h.map(t=>[t,c(e[t])]))}function f(t){const e=c(t),i=e.length,a=e.slice(1).map((t,i)=>t[0]-e[i][0]),s=e.slice(1).map((t,i)=>(t[1]-e[i][1])/a[i]),r=new Float64Array(i);r[0]=s[0],r[i-1]=s[i-2];for(let t=1;t<i-1;t++){const e=s[t-1],i=s[t];if(e*i<=0)continue;const o=2*a[t]+a[t-1],n=a[t]+2*a[t-1];r[t]=(o+n)/(o/e+n/i)}const o=new Uint8Array(256);let n=0;for(let t=0;t<256;t++){const s=t/255;for(;n<i-2&&s>e[n+1][0];)n++;const h=a[n],c=(s-e[n][0])/h,m=c*c,f=m*c,d=(2*f-3*m+1)*e[n][1]+(f-2*m+c)*h*r[n]+(-2*f+3*m)*e[n+1][1]+(f-m)*h*r[n+1];o[t]=Math.round(255*l(d))}return o}var d=["ascii","blocks","braille","dots","lines","cross","diagonal","diamond","mixed","pixel","mosaic","lego","voxel","disco","dither","hex","led","cmyk"],u=["none","bayer2","bayer4","bayer8","bayer16","floyd-steinberg","atkinson","stucki","sierra","sierra-lite","burkes","jarvis","halftone","lines","noise","vertical-lines","diagonal-lines","radial","blue-noise"],g=["source-over","multiply","screen","overlay","soft-light","hard-light","color-dodge","color-burn","hue","saturation","color","luminosity"],p={original:[],gray4:["#000000","#555555","#aaaaaa","#ffffff"],gray8:["#000000","#242424","#494949","#6d6d6d","#929292","#b6b6b6","#dbdbdb","#ffffff"],rgb8:["#000000","#ff0000","#00ff00","#0000ff","#ffff00","#ff00ff","#00ffff","#ffffff"],cyberpunk:["#08081a","#3c1670","#ed299a","#29dfef","#fff7bf"],pastel:["#393448","#a5b4d4","#9ed9c6","#e7aac1","#f5e8be"],mono:["#080808","#f2f2e8"],asciify:["#080808","#625b38","#a19558","#e8b900"],gameboy:["#0f380f","#306230","#8bac0f","#9bbc0f"],cga:["#000000","#55ffff","#ff55ff","#ffffff"],pico8:["#000000","#1d2b53","#7e2553","#008751","#ab5236","#5f574f","#c2c3c7","#fff1e8","#ff004d","#ffa300","#ffec27","#00e436","#29adff","#83769c","#ff77a8","#ffccaa"],c64:["#000000","#ffffff","#880000","#aaffee","#cc44cc","#00cc55","#0000aa","#eeee77","#dd8855","#664400","#ff7777","#333333","#777777","#aaff66","#0088ff","#bbbbbb"],amber:["#100b00","#5f3b00","#c98014","#ffd17c"],ice:["#081b29","#25586e","#69a6b3","#d9ece7"],risograph:["#f4ebd0","#f2594b","#2853a5","#29232e"],sepia:["#201b17","#6b5039","#b49868","#f6e6c5"],nord:["#2e3440","#4c566a","#88c0d0","#eceff4"],dusk:["#211b35","#654271","#c3788c","#f5c9a3"],forest:["#101f1b","#355747","#87a16f","#e4e3ba"],ocean:["#071b33","#17577f","#3fa7a4","#d9efde"],newsprint:["#191919","#666666","#aaaaaa","#eee9df"],custom:["#080808","#e8b900"]},M={version:1,aspectRatio:"original",style:"ascii",cellSize:6,charset:" .:-=+*#%@",colorMode:"accent",ink:"#e8b900",crop:{x:.5,y:.5,zoom:1,rotation:0},backdrop:{mode:"solid",color:"#080808",color2:"#393323",blur:12,opacity:1},color:{brightness:0,contrast:1,saturation:1,grayscale:0,tint:"#e8b900",amount:0,blend:"source-over",blackPoint:0,whitePoint:1,gamma:1,shadows:0,highlights:0,curves:{rgb:[[0,0],[1,1]],red:[[0,0],[1,1]],green:[[0,0],[1,1]],blue:[[0,0],[1,1]]},denoise:0},dither:{algorithm:"none",palette:"mono",colors:["#080808","#e8b900"],amount:1,scale:2,threshold:.5,motion:"none",speed:1,direction:45,colorSpace:"rgb"},mask:{enabled:!1,invert:!1,shapes:[]},lights:[],effects:{bloom:0,characterBloom:0,grain:0,dust:0,scanlines:0,crt:0,prism:0,rgbSplit:0,sharpen:0,vignette:0,glitch:0,pixelate:0,blur:0,blurType:"gaussian",angle:0,focus:.5,halftone:0},motion:{type:"none",speed:1,amount:1},hover:{effect:"trail",strength:.55,radius:.2,edgeSafe:!1}},x=t=>t&&"object"==typeof t&&!Array.isArray(t)?t:{},v=(t,e,i,a)=>"number"==typeof t&&Number.isFinite(t)?Math.min(a,Math.max(i,t)):e,b=(t,e)=>"string"==typeof t&&/^#[\da-f]{6}$/i.test(t)?t:e,w=(t,e,i)=>e.includes(t)?t:i;function y(i={}){const a=x(i),s=M;if(void 0!==a.version&&1!==a.version)throw new Error("Unsupported studio settings version. Update asciify-engine.");const r=x(a.crop),o=x(a.backdrop),n=x(a.color),h=x(a.dither),l=x(a.mask),c=x(a.effects),f=x(a.motion),y=x(a.hover),S={...s.effects};for(const t of["bloom","characterBloom","grain","dust","scanlines","crt","prism","rgbSplit","sharpen","vignette","glitch","pixelate","halftone"])S[t]=v(c[t],0,0,1);S.blur=v(c.blur,0,0,24),S.blurType=w(c.blurType,["gaussian","directional","radial","progressive"],s.effects.blurType),S.angle=v(c.angle,0,-180,180),S.focus=v(c.focus,.5,0,1);let k=2048;return{version:1,aspectRatio:w(a.aspectRatio,["original","16:9","9:16","1:1","4:3","3:4","21:9"],"original"),style:w(a.style,d,s.style),cellSize:v(a.cellSize,s.cellSize,["pixel","mosaic","lego","voxel","disco","dots","hex","led","cmyk"].includes(String(a.style))?1:3,60),charset:"string"==typeof a.charset&&a.charset.length?Array.from(a.charset).slice(0,128).join(""):s.charset,colorMode:w(a.colorMode,["accent","source","gray"],s.colorMode),ink:b(a.ink,s.ink),crop:{x:v(r.x,.5,0,1),y:v(r.y,.5,0,1),zoom:v(r.zoom,1,1,5),rotation:90*Math.round(v(r.rotation,0,-360,360)/90)},backdrop:{mode:w(o.mode,["solid","transparent","source","blurred","gradient"],s.backdrop.mode),color:b(o.color,s.backdrop.color),color2:b(o.color2,s.backdrop.color2),blur:v(o.blur,12,0,32),opacity:v(o.opacity,1,0,1)},color:{brightness:v(n.brightness,0,-1,1),contrast:v(n.contrast,1,0,3),saturation:v(n.saturation,1,0,3),grayscale:v(n.grayscale,0,0,1),tint:b(n.tint,s.color.tint),amount:v(n.amount,0,0,1),blend:w(n.blend,g,s.color.blend),blackPoint:v(n.blackPoint,0,0,.99),whitePoint:Math.max(v(n.blackPoint,0,0,.99)+1/255,v(n.whitePoint,1,1/255,1)),gamma:v(n.gamma,1,.25,4),shadows:v(n.shadows,0,-1,1),highlights:v(n.highlights,0,-1,1),curves:m(n.curves),denoise:v(n.denoise,0,0,1)},dither:{algorithm:w(h.algorithm,u,"none"),palette:"string"==typeof h.palette&&Object.prototype.hasOwnProperty.call(p,h.palette)?h.palette:"mono",colors:Array.isArray(h.colors)&&h.colors.length>=2?h.colors.slice(0,32).map(t=>b(t,"#000000")):[...s.dither.colors],amount:v(h.amount,1,0,2),scale:Math.round(v(h.scale,2,1,12)),threshold:v(h.threshold,.5,0,1),motion:w(h.motion,["none","drift","shimmer"],"none"),speed:v(h.speed,1,.1,3),direction:v(h.direction,45,-180,180),colorSpace:w(h.colorSpace,["rgb","luminance"],"rgb")},mask:{enabled:!0===l.enabled,invert:!0===l.invert,shapes:Array.isArray(l.shapes)?l.shapes.slice(0,64).map(t=>{const e=x(t),i=w(e.kind,["rectangle","ellipse","brush"],"rectangle"),a="brush"===i&&Array.isArray(e.points)?e.points.slice(0,k).map(t=>Array.isArray(t)?[Math.round(1e4*v(t[0],0,0,1))/1e4,Math.round(1e4*v(t[1],0,0,1))/1e4]:[0,0]):[];return k-=a.length,{kind:i,x:v(e.x,0,0,1),y:v(e.y,0,0,1),width:v(e.width,.5,0,1),height:v(e.height,.5,0,1),size:v(e.size,.05,.005,.5),points:a}}):[]},lights:Array.isArray(a.lights)?a.lights.slice(0,4).map(t=>{const e=x(t);return{x:v(e.x,.5,0,1),y:v(e.y,.5,0,1),radius:v(e.radius,.3,.02,1),intensity:v(e.intensity,.5,0,1),color:b(e.color,"#ffffff")}}):[],effects:S,motion:{type:w(f.type,e.map(t=>t.mode),"none"),speed:v(f.speed,1,.1,3),amount:v(f.amount,1,0,2)},hover:{effect:w(y.effect,t.map(t=>t.value),"trail"),strength:v(y.strength,.55,0,1),radius:v(y.radius,.2,.1,1),edgeSafe:!0===y.edgeSafe}}}function S(t,e,i,a,s){const r=Math.abs(s.rotation/90)%2==1,o=r?e:t,n=r?t:e,h=Math.max(i/o,a/n)*s.zoom;return{width:o*h,height:n*h,x:(i-o*h)*s.x,y:(a-n*h)*s.y,scale:h,rotated:r}}function k(t,e,i){if(Math.abs(i.crop.rotation/90)%2==1&&([t,e]=[e,t]),"original"===i.aspectRatio)return[t,e];const[a,s]=i.aspectRatio.split(":").map(Number);return t/e>a/s?[Math.round(e*a/s),e]:[t,Math.round(t*s/a)]}function A(t,e){const i={...t,...e};for(const a of["crop","backdrop","color","dither","mask","effects","motion","hover"])e[a]&&Object.assign(i,{[a]:{...t[a],...e[a]}});return e.color?.curves&&(i.color.curves={...t.color.curves,...e.color.curves}),y(i)}function E(t,e,i,a=12e3,s=1){const r=Math.max(2,Number.isFinite(t)?t:960),o=Math.max(2,Number.isFinite(e)?e:540),n=Math.max(1,Math.floor(Number.isFinite(a)?a:12e3)),h=Math.max(.01,Number.isFinite(s)?s:1),l=["dither","pixel","mosaic","lego","voxel","disco","dots","hex","led","cmyk"].includes(i.style)?1:1.65;let c=Math.max(1,Math.ceil(Math.sqrt(r*o/(n*l))/h));for(;Math.ceil(r/(c*h))*Math.ceil(o/(c*h*l))>n;)c++;const m="dither"===i.style?i.dither.scale:i.cellSize,f=Math.max(c,m)*h;return{cell:f,rowHeight:f*l,columns:Math.ceil(r/f),rows:Math.ceil(o/(f*l)),minimum:c,limited:m<c}}var T=[["ascii","Signature ASCII","Brand ink and clean characters.",{}],["print","Newsprint","Fine diffusion on warm paper.",{style:"dither",dither:{algorithm:"floyd-steinberg",palette:"newsprint"}}],["handheld","Pocket camera","Four-tone ordered dither.",{style:"dither",dither:{algorithm:"bayer4",palette:"gameboy",scale:3}}],["riso","Two inks","Limited-color print texture.",{style:"dither",dither:{algorithm:"atkinson",palette:"risograph",scale:2}}],["night","Night signal","Gray characters and optical fringe.",{ink:"#888888",effects:{prism:.7,scanlines:.2,vignette:.3}}],["terminal","Phosphor","Green glyphs with a soft glow.",{ink:"#83efad",effects:{bloom:.4,scanlines:.35,crt:.2}}],["mosaic","Mosaic study","Separated color tiles.",{style:"mosaic",cellSize:14,colorMode:"source"}],["bricks","Brickwork","Colorful studded cells.",{style:"lego",cellSize:18,colorMode:"source"}],["voxel","Little volumes","Three-face isometric tiles.",{style:"voxel",cellSize:22,colorMode:"source"}],["disco","Mirror room","Faceted tiles and warm light.",{style:"disco",cellSize:18,colorMode:"source",lights:[{x:.35,y:.25,radius:.25,intensity:.45,color:"#fff2d4"}]}],["wallpaper","Wallpaper","Living ASCII over a softened source.",{backdrop:{mode:"blurred",blur:18,opacity:.55},ink:"#f2e9c9",motion:{type:"caustics",speed:.5}}],["blueprint","Blueprint","Linework in a cool monochrome.",{style:"lines",ink:"#9bccdf",backdrop:{mode:"solid",color:"#0a1e30"}}]].map(([t,e,i,a])=>({id:t,name:e,description:i,settings:y(a)}));function F(t){const e=T.find(e=>e.id===t);if(!e)throw new Error("Unknown studio look.");return y(e.settings)}function I(t,e,i,a,s,r){a=Math.max(0,Math.min(e-1,a)),s=Math.max(0,Math.min(i-1,s));const o=Math.floor(a),n=Math.floor(s),h=a-o,l=s-n,c=4*(n*e+o);if(0===h&&0===l){for(let e=0;e<4;e++)r[e]=t[c+e];return}const m=4*(n*e+Math.min(e-1,o+1)),f=4*(Math.min(i-1,n+1)*e+o),d=4*(Math.min(i-1,n+1)*e+Math.min(e-1,o+1)),u=(1-h)*(1-l)*t[c+3],g=h*(1-l)*t[m+3],p=(1-h)*l*t[f+3],M=h*l*t[d+3],x=u+g+p+M;for(let e=0;e<3;e++)r[e]=x?(t[c+e]*u+t[m+e]*g+t[f+e]*p+t[d+e]*M)/x:0;r[3]=x}function P(t){const e=function(t){const e=t.blackPoint??0,i=t.whitePoint??1,a=t.gamma??1,s=t.shadows??0,r=t.highlights??0;if(0===e&&1===i&&1===a&&0===s&&0===r)return null;const o=[0,.25+.2*s,.5,.75+.2*r,1],n=o.slice(1).map((t,e)=>4*(t-o[e])),h=[n[0],...n.slice(1).map((t,e)=>2*t*n[e]/(t+n[e])),n[3]],l=new Uint8Array(256);for(let t=0;t<256;t++){const s=Math.pow(Math.max(0,Math.min(1,(t/255-e)/(i-e))),1/a),r=Math.min(3,Math.floor(4*s)),n=4*s-r,c=n*n,m=c*n,f=(2*m-3*c+1)*o[r]+(m-2*c+n)*h[r]/4+(-2*m+3*c)*o[r+1]+(m-c)*h[r+1]/4;l[t]=Math.round(255*Math.max(0,Math.min(1,f)))}return l}(t),i=t.curves;if(!e&&(!i||Object.values(i).every(t=>t.every(([t,e])=>t===e))))return null;const a=f(i?.rgb),s=[i?.red,i?.green,i?.blue].map(f),r=new Uint8Array(768);for(let t=0;t<256;t++)for(let i=0;i<3;i++)r[256*i+t]=s[i][a[e?e[t]:t]];return r}var R=class{constructor(t=0){this.amount=0,this.weights=new Float32Array(256),this.source=new Uint8ClampedArray(0),this.configure(t)}configure(t=0){const e=Math.max(0,Math.min(1,Number.isFinite(t)?t:0));if(e===this.amount)return;if(this.amount=e,0===e)return void(this.source=new Uint8ClampedArray(0));const i=8+24*e;for(let t=0;t<256;t++)this.weights[t]=Math.exp(-t*t/(2*i*i))}apply(t,e,i){if(!this.amount)return;if(!Number.isInteger(e)||!Number.isInteger(i)||e<1||i<1||e*i*4!==t.length)throw new Error("Denoise dimensions do not match the source.");this.source.length!==t.length&&(this.source=new Uint8ClampedArray(t.length));const a=this.source;a.set(t);for(let s=0;s<i;s++)for(let r=0;r<e;r++){const o=4*(s*e+r);if(!a[o+3])continue;const n=a[o],h=a[o+1],l=a[o+2];let c=0,m=0,f=0,d=0;for(let t=-1;t<=1;t++){const o=s+t;if(!(o<0||o>=i))for(let i=-1;i<=1;i++){const s=r+i;if(s<0||s>=e)continue;const u=4*(o*e+s);if(!a[u+3])continue;const g=Math.max(Math.abs(a[u]-n),Math.abs(a[u+1]-h),Math.abs(a[u+2]-l)),p=this.weights[g]*(0===i?1:.6)*(0===t?1:.6)*a[u+3];c+=a[u]*p,m+=a[u+1]*p,f+=a[u+2]*p,d+=p}}t[o]=n+(c/d-n)*this.amount,t[o+1]=h+(m/d-h)*this.amount,t[o+2]=l+(f/d-l)*this.amount}}},C=new Set(["none","floyd-steinberg","atkinson","stucki","sierra","sierra-lite","burkes","jarvis"]);function L(t){return"dither"===t.style&&("shimmer"===t.dither.motion||"drift"===t.dither.motion&&t.dither.amount>0&&!C.has(t.dither.algorithm))}function D(t){return"none"!==t.motion.type&&(t.motion.amount??1)>0}var N="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",U="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",O=new Uint16Array(4096);for(let t=0;t<O.length;t++)O[t]=N.indexOf(U[2*t])<<6|N.indexOf(U[2*t+1]);var X=(t,e)=>{const i=43758.5453*Math.sin(127.1*t+311.7*e);return i-Math.floor(i)};var Y=new Map([2,4,8,16].map(t=>[t,Float64Array.from({length:t*t},(e,i)=>function(t,e,i){let a=0;for(let s=1;s<i;s*=2){const i=(Math.floor(t/s)%2+2)%2;a=4*a+[[0,2],[3,1]][(Math.floor(e/s)%2+2)%2][i]}return(a+.5)/(i*i)-.5}(i%t,Math.floor(i/t),t))])),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]]},z=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 a=Math.min(t*Math.max(1,i),(1-t)*Math.max(1,i),e*Math.max(1,1/i),(1-e)*Math.max(1,1/i)),s=Math.max(0,Math.min(1,(a-.035)/.105));return s*s*s*(s*(6*s-15)+10)}var G=t=>["dissolve","silk","vortex","magnetic","scatter","etch","elastic","rake"].includes(t),q=class{constructor(t,e){this.edgeSafe=!1,this.previous=null,this.peak=0,this.scatterDirections=null,this.springX=null,this.springY=null,this.mode="dissolve",this.width=t,this.height=e;const i=t*e;this.pixels=new Uint8Array(4*i),this.ink=new Float32Array(i),this.targetX=new Float32Array(i),this.targetY=new Float32Array(i),this.offsetX=new Float32Array(i),this.offsetY=new Float32Array(i),this.edge=new Float32Array(i);for(let i=0;i<e;i++)for(let a=0;a<t;a++)this.edge[i*t+a]=W(a/(t-1),i/(e-1),t/e);this.clear()}get active(){return this.peak>2e-4}setMode(t){if("elastic"!==t||this.springX||(this.springX=new Float32Array(this.ink.length),this.springY=new Float32Array(this.ink.length)),"scatter"===t&&!this.scatterDirections){const t=this.scatterDirections=new Float64Array(this.width*this.height*2);for(let e=0;e<this.height;e++)for(let i=0;i<this.width;i++){const a=43758.5453*Math.sin(127.1*i+311.7*e),s=(a-Math.floor(a))*Math.PI*2,r=2*(e*this.width+i);t[r]=.7*Math.cos(s),t[r+1]=.7*Math.sin(s)}}t!==this.mode&&(this.mode=t,this.clear())}clear(){for(const t of[this.ink,this.targetX,this.targetY,this.offsetX,this.offsetY,this.pixels])t.fill(0);if(this.previous=null,this.peak=0,this.springX?.fill(0),this.springY?.fill(0),"dissolve"!==this.mode)for(let t=0;t<this.pixels.length;t+=4)this.pixels[t]=this.pixels[t+2]=128}leave(){this.previous=null}move(t,e,i){if(!Number.isFinite(t+e+i))return;t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e));const a=this.previous;this.previous={x:t,y:e};const s=this.width,r=this.height,o=Math.max(1,s/r),n=Math.max(1,r/s),h=a?(t-a.x)*o:0,l=a?(e-a.y)*n:0,c=Math.hypot(h,l);if(!a&&"dissolve"!==this.mode&&"etch"!==this.mode)return;if(a&&c<1e-4)return;const m=.035+.11*Math.max(.1,Math.min(1,i)),f=Math.min(128,Math.max(1,Math.ceil(c/(.45*m)))),d=c?h/c:1,u=c?l/c:0,g=Math.min(1,c/(m*f)*2.2);for(let i=0;i<f;i++){const h=(i+.5)/f,l=a?a.x+(t-a.x)*h:t,c=a?a.y+(e-a.y)*h:e,p=Math.max(0,Math.floor((l-2.5*m/o)*(s-1))),M=Math.min(s-1,Math.ceil((l+2.5*m/o)*(s-1))),x=Math.max(0,Math.floor((c-2.5*m/n)*(r-1))),v=Math.min(r-1,Math.ceil((c+2.5*m/n)*(r-1)));for(let t=x;t<=v;t++)for(let e=p;e<=M;e++){const i=(e/(s-1)-l)*o/m,a=(t/(r-1)-c)*n/m,h=Math.exp(1.5*-(i*i+a*a)),f=t*s+e;if("dissolve"===this.mode||"etch"===this.mode)this.ink[f]=Math.max(this.ink[f],h);else if("elastic"===this.mode)this.springX[f]=Math.max(-24,Math.min(24,this.springX[f]+d*h*g*8)),this.springY[f]=Math.max(-24,Math.min(24,this.springY[f]+u*h*g*8));else{const s=(-i*u+a*d)*h*2.8,r="rake"===this.mode?d*Math.sin(t*Math.PI/3)*h*2:"magnetic"===this.mode?-i*h*2.5:"scatter"===this.mode?(i+this.scatterDirections[2*f])*h*2:"silk"===this.mode?d*s:-a*h*2.5,o="rake"===this.mode?u*Math.sin(e*Math.PI/3)*h*2:"magnetic"===this.mode?-a*h*2.5:"scatter"===this.mode?(a+this.scatterDirections[2*f+1])*h*2:"silk"===this.mode?u*s:i*h*2.5;this.targetX[f]=Math.max(-1,Math.min(1,this.targetX[f]+r*g)),this.targetY[f]=Math.max(-1,Math.min(1,this.targetY[f]+o*g))}}}this.peak=1}step(t){if(!this.active||!Number.isFinite(t))return;const e=Math.max(0,Math.min(.05,t)),i=Math.exp(-("dissolve"===this.mode?2.15:3.2)*e),a=1-Math.exp(-22*e);let s=0;const r=Math.sqrt(336),o=Math.exp(-8*e),n=Math.cos(r*e),h=Math.sin(r*e)/r;for(let t=0;t<this.ink.length;t++)if("etch"===this.mode)this.ink[t]*=i,s=Math.max(s,this.ink[t]);else if("dissolve"===this.mode){this.ink[t]*=i,s=Math.max(s,this.ink[t]);const e=Math.round(65535*this.ink[t]);this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e}else{if("elastic"===this.mode){const e=this.offsetX[t],i=this.offsetY[t],a=this.springX[t],r=this.springY[t];this.offsetX[t]=Math.max(-1,Math.min(1,o*(e*n+(a+8*e)*h))),this.offsetY[t]=Math.max(-1,Math.min(1,o*(i*n+(r+8*i)*h))),this.springX[t]=o*(a*n-(8*a+400*e)*h),this.springY[t]=o*(r*n-(8*r+400*i)*h),s=Math.max(s,.05*Math.abs(this.springX[t]),.05*Math.abs(this.springY[t]))}else this.targetX[t]*=i,this.targetY[t]*=i,this.offsetX[t]+=(this.targetX[t]-this.offsetX[t])*a,this.offsetY[t]+=(this.targetY[t]-this.offsetY[t])*a;s=Math.max(s,Math.abs(this.offsetX[t]),Math.abs(this.offsetY[t]),Math.abs(this.targetX[t]),Math.abs(this.targetY[t]));const e=Math.round(this.offsetX[t]*(this.edgeSafe?this.edge[t]:1)*32767+32768),r=Math.round(this.offsetY[t]*(this.edgeSafe?this.edge[t]:1)*32767+32768);this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e,this.pixels[4*t+2]=r>>>8,this.pixels[4*t+3]=255&r}if("etch"===this.mode)for(let t=0;t<this.height;t++)for(let e=0;e<this.width;e++){const i=t*this.width+e,a=3*(this.ink[t*this.width+Math.max(0,e-1)]-this.ink[t*this.width+Math.min(this.width-1,e+1)]+this.ink[Math.max(0,t-1)*this.width+e]-this.ink[Math.min(this.height-1,t+1)*this.width+e]);this.offsetX[i]=Math.max(-1,Math.min(1,a))*(this.edgeSafe?this.edge[i]:1);const s=Math.round(32767*this.offsetX[i]+32768);this.pixels[4*i]=s>>>8,this.pixels[4*i+1]=255&s}this.peak=s,this.active||this.clear()}sample(t,e,i){const a=Math.max(0,Math.min(this.width-1.001,t*(this.width-1))),s=Math.max(0,Math.min(this.height-1.001,e*(this.height-1))),r=Math.floor(a),o=Math.floor(s),n=a-r,h=s-o,l=o*this.width+r,c=l+this.width,m=t=>(t[l]*(1-n)+t[l+1]*n)*(1-h)+(t[c]*(1-n)+t[c+1]*n)*h;if("etch"===this.mode)return i[0]=i[1]=0,void(i[2]=3*m(this.offsetX));i[0]=m(this.offsetX)*(this.edgeSafe?W(t,e,this.width/this.height):1)*.08,i[1]=m(this.offsetY)*(this.edgeSafe?W(t,e,this.width/this.height):1)*.08,i[2]="dissolve"===this.mode?6*-m(this.ink):0}},j=class{constructor(t,e){this.rings=[],this.previous=null,this.elapsed=1,this.echoPeak=0,this.width=t,this.height=e,this.pixels=new Uint8Array(t*e*4),this.echo=new Float32Array(t*e)}get active(){return this.rings.length>0||this.echoPeak>2e-4}clear(){this.rings=[],this.previous=null,this.elapsed=1,this.pixels.fill(0),this.echo.fill(0),this.echoPeak=0}leave(){this.previous=null}move(t,e,i){const a=Math.max(1,this.width/this.height),s=Math.max(1,this.height/this.width);this.previous&&(Math.hypot((t-this.previous.x)*a,(e-this.previous.y)*s)<.065||this.elapsed<.3)||4!==this.rings.length&&(this.previous={x:t,y:e},this.elapsed=0,this.rings.push({x:t,y:e,age:0,radius:i}))}ringSample(t,e){const i=Math.max(1,this.width/this.height),a=Math.max(1,this.height/this.width);let s=0;for(const r of this.rings){const o=.015+r.age*(.15+.22*r.radius),n=.009+.014*r.radius,h=(Math.hypot((t-r.x)*i,(e-r.y)*a)-o)/n,l=Math.sin(Math.min(1,r.age/.07)*Math.PI/2)*Math.max(0,1-r.age/1.35)**2;s=Math.max(s,Math.exp(-h*h)*l)}return s}sample(t,e){const i=Math.max(0,Math.min(this.width-1,Math.round(t*(this.width-1)))),a=Math.max(0,Math.min(this.height-1,Math.round(e*(this.height-1))));return Math.max(this.ringSample(t,e),this.echo[a*this.width+i])}step(t){if(!Number.isFinite(t))return;const e=Math.max(0,Math.min(.05,t));this.elapsed+=e;for(const t of this.rings)t.age+=e;if(this.rings=this.rings.filter(t=>t.age<1.35),!this.active)return void this.pixels.fill(0);const i=Math.exp(-5.5*e);let a=0;for(let t=0;t<this.height;t++)for(let e=0;e<this.width;e++){const s=t*this.width+e;this.echo[s]=Math.max(this.ringSample(e/(this.width-1),t/(this.height-1)),this.echo[s]*i),a=Math.max(a,this.echo[s]);const r=Math.round(65535*this.echo[s]),o=4*s;this.pixels[o]=r>>>8,this.pixels[o+1]=255&r}this.echoPeak=a,this.active||(this.echo.fill(0),this.pixels.fill(0))}},H=class{constructor(t,e){this.previous=null,this.peak=0,this.width=t,this.height=e;const i=t*e;this.pixels=new Uint8Array(4*i),this.signal=new Float32Array(i),this.offsetX=new Float32Array(i),this.offsetY=new Float32Array(i),this.driftX=new Float32Array(i),this.driftY=new Float32Array(i),this.u=new Float32Array(i),this.v=new Float32Array(i),this.ink=new Float32Array(i),this.a=new Float32Array(i),this.b=new Float32Array(i),this.c=new Float32Array(i),this.pressure=new Float32Array(i),this.pressureNext=new Float32Array(i),this.divergence=new Float32Array(i),this.curl=new Float32Array(i)}get active(){return this.peak>2e-4}clear(){for(const t of[this.u,this.v,this.ink,this.a,this.b,this.c,this.pressure,this.pressureNext,this.divergence,this.curl,this.signal,this.pixels,this.offsetX,this.offsetY,this.driftX,this.driftY])t.fill(0);this.previous=null,this.peak=0}leave(){this.previous=null}move(t,e,i,a=performance.now()){if(!Number.isFinite(t+e+i+a))return;t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e)),i=Math.max(.1,Math.min(1,i));const s=this.previous;if(this.previous={x:t,y:e,time:a},!s)return;const r=(t-s.x)*(this.width-1),o=(e-s.y)*(this.height-1),n=Math.hypot(r,o);if(n<.001)return;const h=Math.min(this.width,this.height),l=a>s.time?Math.max(1/240,(a-s.time)/1e3):1/60,c=Math.min(12,n/h/l),m=1-Math.exp(-c/2.2),f=h*(.022+.075*i)*(.65+.95*m),d=Math.min(128,Math.max(1,Math.ceil(n/(.4*f)))),u=n/f*(.32+.22*m)/d,g=r/n,p=o/n,M=-p,x=g,v=n*(2+18*m)/d;for(let i=0;i<d;i++){const a=(i+.5)/d,r=(s.x+(t-s.x)*a)*(this.width-1),o=(s.y+(e-s.y)*a)*(this.height-1),n=Math.max(1,Math.floor(r-3*f)),h=Math.min(this.width-2,Math.ceil(r+3*f)),l=Math.max(1,Math.floor(o-3*f)),c=Math.min(this.height-2,Math.ceil(o+3*f));for(let t=l;t<=c;t++)for(let e=n;e<=h;e++){const i=((e-r)*g+(t-o)*p)/f,a=((e-r)*M+(t-o)*x)/f,s=Math.exp(-i*i*.65-a*a*1.7),n=t*this.width+e;this.ink[n]=1-(1-this.ink[n])*Math.exp(-s*u);const h=1-a*a*.55,l=i*a*.7;this.u[n]=Math.max(-80,Math.min(80,this.u[n]+(g*h+M*l)*s*v)),this.v[n]=Math.max(-80,Math.min(80,this.v[n]+(p*h+x*l)*s*v))}}this.peak=1}read(t,e,i){const a=0|(e=Math.max(.5,Math.min(this.width-1.5,e))),s=0|(i=Math.max(.5,Math.min(this.height-1.5,i))),r=e-a,o=i-s,n=s*this.width+a;return(t[n]*(1-r)+t[n+1]*r)*(1-o)+(t[n+this.width]*(1-r)+t[n+this.width+1]*r)*o}sample(t,e){return this.read(this.signal,t*(this.width-1),e*(this.height-1))}displacement(t,e,i){i[0]=this.read(this.offsetX,t*(this.width-1),e*(this.height-1)),i[1]=this.read(this.offsetY,t*(this.width-1),e*(this.height-1))}step(t){if(!this.active||!Number.isFinite(t))return;let e=Math.max(0,Math.min(.05,t));const i=this.width,a=this.height;for(;e>1e-7;){const t=Math.min(1/60,e);e-=t;const s=Math.exp(-1.9*t),r=Math.exp(-3.2*t);for(let e=1;e<a-1;e++)for(let o=1;o<i-1;o++){const n=e*i+o,h=Math.max(.5,Math.min(i-1.5,o-this.u[n]*t)),l=Math.max(.5,Math.min(a-1.5,e-this.v[n]*t)),c=0|h,m=0|l,f=h-c,d=l-m,u=m*i+c,g=(1-f)*(1-d),p=f*(1-d),M=(1-f)*d,x=f*d;this.a[n]=(this.u[u]*g+this.u[u+1]*p+this.u[u+i]*M+this.u[u+i+1]*x)*s,this.b[n]=(this.v[u]*g+this.v[u+1]*p+this.v[u+i]*M+this.v[u+i+1]*x)*s,this.c[n]=(this.ink[u]*g+this.ink[u+1]*p+this.ink[u+i]*M+this.ink[u+i+1]*x)*r}[this.u,this.a]=[this.a,this.u],[this.v,this.b]=[this.b,this.v],[this.ink,this.c]=[this.c,this.ink];for(let t=1;t<a-1;t++)for(let e=1;e<i-1;e++){const a=t*i+e;this.curl[a]=.5*(this.v[a+1]-this.v[a-1]-this.u[a+i]+this.u[a-i])}for(let e=1;e<a-1;e++)for(let a=1;a<i-1;a++){const s=e*i+a,r=Math.abs(this.curl[s+1])-Math.abs(this.curl[s-1]),o=Math.abs(this.curl[s+i])-Math.abs(this.curl[s-i]),n=Math.hypot(r,o)+1e-4,h=this.curl[s]*t*10,l=Math.hypot(this.u[s],this.v[s]);this.u[s]+=o/n*h,this.v[s]-=r/n*h;const c=Math.min(1,l/(Math.hypot(this.u[s],this.v[s])+1e-6));this.u[s]*=c,this.v[s]*=c,this.divergence[s]=-.5*(this.u[s+1]-this.u[s-1]+this.v[s+i]-this.v[s-i])}this.pressure.fill(0);for(let t=0;t<4;t++){for(let t=1;t<a-1;t++)for(let e=1;e<i-1;e++){const a=t*i+e;this.pressureNext[a]=.25*(this.divergence[a]+this.pressure[a-1]+this.pressure[a+1]+this.pressure[a-i]+this.pressure[a+i])}[this.pressure,this.pressureNext]=[this.pressureNext,this.pressure]}let o=0;for(let e=1;e<a-1;e++)for(let a=1;a<i-1;a++){const s=e*i+a;this.u[s]=Math.max(-80,Math.min(80,this.u[s]-.5*(this.pressure[s+1]-this.pressure[s-1]))),this.v[s]=Math.max(-80,Math.min(80,this.v[s]-.5*(this.pressure[s+i]-this.pressure[s-i]))),this.driftX[s]+=(3.6*this.u[s]-58*this.offsetX[s]-12*this.driftX[s])*t,this.driftY[s]+=(3.6*this.v[s]-58*this.offsetY[s]-12*this.driftY[s])*t,this.offsetX[s]=Math.max(-2,Math.min(2,this.offsetX[s]+this.driftX[s]*t)),this.offsetY[s]=Math.max(-2,Math.min(2,this.offsetY[s]+this.driftY[s]*t)),this.signal[s]=1-Math.exp(.06*-Math.hypot(this.u[s],this.v[s])-.16*this.ink[s]),o=Math.max(o,this.signal[s])}this.peak=o}if(this.active)for(let t=0;t<this.ink.length;t++){const e=Math.round(65535*Math.min(1,this.signal[t]));this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e,this.pixels[4*t+2]=Math.round(128+63.5*this.offsetX[t]),this.pixels[4*t+3]=Math.round(128+63.5*this.offsetY[t])}else this.clear()}};function V(t,e){const i=Math.max(0,Math.min(1,e/.38));return t+(1-2*t)*(i*i*(3-2*i))}var K=(t,e)=>"water"===t?30*e/.55:"silk"===t?28*e:"vortex"===t?38*e:["magnetic","scatter","elastic","rake"].includes(t)?32*e:0,Q=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 H(this.columns,this.rows),this.contour=new j(this.columns,this.rows),this.afterimage=new q(this.columns,this.rows),this.clear()}get invertsDensity(){return"trail"===this.mode}get densityTrail(){return["trail","contour","dissolve","etch"].includes(this.mode)}get hasRefraction(){return this.active||this.lensStrength>15e-5}get active(){return G(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,G(t)&&this.afterimage.setMode(t),this.refraction.pixels="trail"===t?this.trail.pixels:"contour"===t?this.contour.pixels:G(t)?this.afterimage.pixels:this.waterPixels,this.refraction.strength=K(t,this.amount))}configure(t,e=.55,i=.2,a=!1){this.setMode(t),this.refraction.edgeSafe=a,this.afterimage.edgeSafe=a,this.amount=Number.isFinite(e)?Math.max(0,Math.min(1,e)):.55,this.radius=Number.isFinite(i)?Math.max(.1,Math.min(1,i)):.2,this.refraction.strength=K(t,this.amount),this.refraction.focus[2]=this.densityTrail?this.amount:this.lensStrength*this.amount,this.refraction.focus[3]=this.radius}move(t,e,i){if("none"===this.mode||0===this.amount)return;if(!Number.isFinite(t+e))return;if(t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e)),G(this.mode))return void this.afterimage.move(t,e,this.radius);if("contour"===this.mode)return void this.contour.move(t,e,this.radius);if("trail"===this.mode)return void this.trail.move(t,e,this.radius,i);if("water"!==this.mode)return!this.previous&&this.lensStrength<.001&&(this.lensX=t,this.lensY=e),this.previous={x:t,y:e},void(this.pending=!0);if(!this.previous)return void(this.previous={x:t,y:e});const a=this.previous;this.previous={x:t,y:e};const s=(t-a.x)*this.xScale,r=(e-a.y)*this.yScale,o=Math.hypot(s,r);if(o<1e-5)return;const n=.035+.1*this.radius,h=3*n,l=Math.min(192,Math.max(1,Math.ceil(o/(.5*n)))),c=95*Math.min(o,1)/l;for(let i=0;i<l;i++){const s=(i+.5)/l,r=a.x+(t-a.x)*s,o=a.y+(e-a.y)*s,m=Math.max(1,Math.floor((r-h/this.xScale)*(this.columns-1))),f=Math.min(this.columns-2,Math.ceil((r+h/this.xScale)*(this.columns-1))),d=Math.max(1,Math.floor((o-h/this.yScale)*(this.rows-1))),u=Math.min(this.rows-2,Math.ceil((o+h/this.yScale)*(this.rows-1)));for(let t=d;t<=u;t++)for(let e=m;e<=f;e++){const i=(e/(this.columns-1)-r)*this.xScale,a=(t/(this.rows-1)-o)*this.yScale,s=Math.exp(-(i*i+a*a)/(n*n))*c,h=t*this.columns+e;this.velocity[h]=Math.max(-12,this.velocity[h]-s)}}this.pending=!0}leave(){this.afterimage.leave(),this.contour.leave(),this.trail.leave(),this.previous=null,"water"!==this.mode&&this.lensStrength&&(this.pending=!0)}clear(){this.trail.clear(),this.contour.clear(),this.afterimage.clear(),this.heights.fill(0),this.velocity.fill(0),this.next.fill(0),this.normals.fill(0),this.refraction.focus[2]=0,this.previous=null,this.lensStrength=0,this.energy=0,this.pending=!1,this.remainder=0;for(let t=0;t<this.waterPixels.length;t+=4)this.waterPixels[t]=this.waterPixels[t+2]=128,this.waterPixels[t+1]=this.waterPixels[t+3]=0}step(t){if(!this.active||!Number.isFinite(t))return;if(G(this.mode))return void this.afterimage.step(t);if("contour"===this.mode)return void this.contour.step(t);if("trail"===this.mode)return void this.trail.step(t);if("water"!==this.mode)return void this.stepLight(Math.max(0,Math.min(.05,t)));this.remainder+=Math.max(0,Math.min(.05,t));const e=1/120,i=Math.exp(-3.8*e),a=.3*Math.min(this.columns,this.rows);for(;this.remainder+1e-8>=e;){this.remainder-=e;let t=0;for(let s=1;s<this.rows-1;s++)for(let r=1;r<this.columns-1;r++){const o=s*this.columns+r,n=this.heights[o],h=this.heights[o-1]+this.heights[o+1]+this.heights[o-this.columns]+this.heights[o+this.columns]-4*n,l=Math.min(r,s,this.columns-1-r,this.rows-1-s),c=l<5?.88+.024*l:1,m=(this.velocity[o]+(h*a*a-8*n)*e)*i*c;this.velocity[o]=m,this.next[o]=(n+m*e)*c,t=Math.max(t,Math.abs(this.next[o]),.1*Math.abs(m))}this.heights.set(this.next),this.energy=t,this.pending=!1}if(!this.active)return void this.clear();const s=.18*Math.min(this.columns,this.rows);for(let t=0;t<this.rows;t++)for(let e=0;e<this.columns;e++){const i=t*this.columns+e,a=(this.heights[t*this.columns+Math.max(0,e-1)]-this.heights[t*this.columns+Math.min(this.columns-1,e+1)])*s,r=(this.heights[Math.max(0,t-1)*this.columns+e]-this.heights[Math.min(this.rows-1,t+1)*this.columns+e])*s,o=Math.tanh(a)*(this.refraction.edgeSafe?this.edgeMask[i]:1),n=Math.tanh(r)*(this.refraction.edgeSafe?this.edgeMask[i]:1);this.normals[2*i]=o,this.normals[2*i+1]=n;const h=Math.round(32767*o+32768),l=Math.round(32767*n+32768);this.refraction.pixels[4*i]=h>>>8,this.refraction.pixels[4*i+1]=255&h,this.refraction.pixels[4*i+2]=l>>>8,this.refraction.pixels[4*i+3]=255&l}}stepLight(t){const e=this.previous,i=1-Math.exp(-30*t),a=1-Math.exp(-12*t);e&&(this.lensX+=(e.x-this.lensX)*i,this.lensY+=(e.y-this.lensY)*i),this.lensStrength+=((e?1:0)-this.lensStrength)*a,this.energy=Math.max(e?Math.abs(e.x-this.lensX)+Math.abs(e.y-this.lensY):0,Math.abs((e?1:0)-this.lensStrength)),this.pending=!1,e||this.active?this.refraction.focus=[this.lensX,this.lensY,this.lensStrength*this.amount,this.radius]:this.clear()}sample(t,e,i){if(G(this.mode))return this.afterimage.sample(t,e,i),i[0]*=this.amount,i[1]*=this.amount,void(i[2]*=this.amount);if("contour"===this.mode)return i[0]=i[1]=0,void(i[2]=this.contour.sample(t,e)*this.amount*3);if("trail"===this.mode)return i[0]=i[1]=0,void(i[2]=this.trail.sample(t,e)*this.amount*3);const a=Math.max(0,Math.min(this.columns-1.001,t*(this.columns-1))),s=Math.max(0,Math.min(this.rows-1.001,e*(this.rows-1))),r=Math.floor(a),o=Math.floor(s),n=a-r,h=s-o,l=2*(o*this.columns+r),c=l+2*this.columns;for(let t=0;t<2;t++)i[t]=.08*((this.normals[l+t]*(1-n)+this.normals[l+2+t]*n)*(1-h)+(this.normals[c+t]*(1-n)+this.normals[c+2+t]*n)*h);i[0]*=this.amount/.55,i[1]*=this.amount/.55,i[2]="light"===this.mode||"scan"===this.mode?function(t,e,i,a){const[s,r,o,n]=i.focus,h=(t-s)*Math.max(1,a)/n,l=(e-r)*Math.max(1,1/a)/n;return"light"===i.mode?Math.exp(-3*(h*h+l*l))*o:"scan"===i.mode?(1.3*Math.exp(-h*h*110)-.3*Math.exp(-h*h*12))*Math.exp(-l*l*1.8)*o:0}(t,e,this.refraction,this.xScale/this.yScale):0}};function J(t){return"videoWidth"in t?[t.videoWidth,t.videoHeight]:"naturalWidth"in t?[t.naturalWidth,t.naturalHeight]:[t.width,t.height]}var Z=(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}},_=(t,e,i)=>{t.width===e&&t.height===i||(t.width=e,t.height=i)},$={blocks:" ░▒▓█",braille:" ⠁⠃⠇⡇⣇⣧⣷⣿",lines:" -═╪╬",cross:" ·+xX#",diagonal:" /╱╳",diamond:" ·◇◈◆",mixed:" .:+/◇#@"};function tt(t,e={},i={}){const a=t.getContext("2d");if(!a)throw new Error("Canvas is already owned by another renderer.");const s=Z(),r=Z(!0),h=Z(),l=Z(),c=Z(),m=Z(),f=Z(),d=Z(),u=Z(),g=Z();let M,x=0,v=y(e),b=0,w="",k="",A="",T=new Uint8ClampedArray(0),F=new Uint8ClampedArray(0),C=0,N=0,U=0,W=null,G="",q=new Q,j=0;const H=[0,0,0],K=[0,0,0,1],tt=[0,0,0,0];let et=P(v.color);const it=new R(v.color.denoise),at=Math.max(64,Math.min(4096,Number.isFinite(i.maxDimension)?i.maxDimension:960)),st=Math.max(256,Math.min(1048576,Number.isFinite(i.maxCells)?i.maxCells:12e3));let rt=st,ot=Math.max(.1,Math.min(8,i.pixelRatio??1));return{canvas:t,render:function(e,i=0,y=960,P=540,R=i*v.motion.speed){if(Number.isFinite(i)||(i=0),!Number.isFinite(y)||!Number.isFinite(P)||y<1||P<1)throw new Error("Render dimensions must be positive finite numbers.");const[Z,st]=J(e);if(!Z||!st)return;const nt=Math.min(1,at/Math.max(y,P)),ht=Math.max(2,Math.round(y*nt)),lt=Math.max(2,Math.round(P*nt));_(t,ht,lt),_(s.canvas,ht,lt),_(h.canvas,ht,lt),_(l.canvas,ht,lt),_(c.canvas,ht,lt),j!==ht/lt&&(j=ht/lt,q=new Q(j)),q.configure(v.hover.effect,v.hover.strength,v.hover.radius,v.hover.edgeSafe),q.step(Math.max(0,Math.min(.05,i-U))),U=i;const ct="currentTime"in e?e.getVideoPlaybackQuality?.().totalVideoFrames??e.currentTime:0,mt=[b,ht,lt,ct].join(":"),ft="dither"===v.style,dt=E(ht,lt,v,rt,ot),ut=dt.cell,gt=dt.rowHeight,pt=dt.columns,Mt=dt.rows;if(w!==mt||W!==e||C!==pt||N!==Mt){W=e,w=mt,k="",A="",C=pt,N=Mt,s.ctx.clearRect(0,0,ht,lt),s.ctx.save();const t=S(Z,st,ht,lt,v.crop);s.ctx.translate(t.x+t.width/2,t.y+t.height/2),s.ctx.rotate(v.crop.rotation*Math.PI/180),s.ctx.drawImage(e,-Z*t.scale/2,-st*t.scale/2,Z*t.scale,st*t.scale),s.ctx.restore(),_(r.canvas,C,N),r.ctx.clearRect(0,0,C,N),r.ctx.drawImage(s.canvas,0,0,C,N),T=r.ctx.getImageData(0,0,C,N).data,it.apply(T,C,N);const i=v.color;for(let t=0;t<T.length;t+=4){const e=.299*T[t]+.587*T[t+1]+.114*T[t+2];for(let a=0;a<3;a++){const s=e+(T[t+a]-e)*i.saturation;T[t+a]=((s*(1-i.grayscale)+e*i.grayscale)/255-.5)*i.contrast*255+127.5+255*i.brightness}}et&&function(t,e){for(let i=0;i<t.length;i+=4)t[i+3]&&(t[i]=e[t[i]],t[i+1]=e[256+t[i+1]],t[i+2]=e[512+t[i+2]])}(T,et)}const xt=D(v),vt=L(v),bt=!q.active&&!xt&&!vt,wt=[mt,C,N,ut,gt,ot].join(":");if(!bt||A!==wt){h.ctx.clearRect(0,0,ht,lt),h.ctx.globalAlpha=1,h.ctx.globalCompositeOperation="source-over";const t=R,e=xt?v.motion.type:"none",a=["none","caustics","sheen","grain","trace"].includes(e);if(ft){const a=bt;if(!a||k!==mt){F.length!==T.length&&(F=new Uint8ClampedArray(T.length));const s=F;if(s.set(T),q.active||"none"!==e)for(let i=0;i<N;i++)for(let a=0;a<C;a++){const r=a/C,h=i/N;let l=a,c=i,m=0,f=1,d=1;q.active&&(q.sample(r,h,H),l-=H[0]*C,c-=H[1]*N,m=H[2]/3);const u=4*(i*C+a);o(e,r,h,t,K,(.299*T[u]+.587*T[u+1]+.114*T[u+2])/255),n(K,v.motion.amount??1),l-=K[0]/960*C,c-=K[1]/960*N,f=1+K[2],d=K[3],l=Math.max(0,Math.min(C-1,l)),c=Math.max(0,Math.min(N-1,c));const g=Math.floor(l),p=Math.floor(c),M=l-g,x=c-p,b=4*(i*C+a),w=4*(p*C+g),y=4*(p*C+Math.min(C-1,g+1)),S=4*(Math.min(N-1,p+1)*C+g),k=4*(Math.min(N-1,p+1)*C+Math.min(C-1,g+1));for(let t=0;t<3;t++){const e=((T[w+t]*(1-M)+T[y+t]*M)*(1-x)+(T[S+t]*(1-M)+T[k+t]*M)*x)/255;let i=(["trail","contour"].includes(v.hover.effect)?V(e,m):"etch"===v.hover.effect?Math.max(0,Math.min(1,e+.35*m)):"dissolve"===v.hover.effect?e*Math.max(0,1+m):e)*f;s[b+t]=255*i}s[b+3]=T[w+3]*d}!function(t,e,i,a,s=0){const{algorithm:r,amount:o,threshold:n}=a,h="blue-noise"===r,l=r.startsWith("bayer")?Number(r.slice(5)):0,c=Y.get(l),m=l-1,f="luminance"===a.colorSpace,d=("custom"===a.palette?a.colors:p[a.palette]??p.mono).map(z),u=B[r],g=u?new Float32Array(3*e*3):null,M="drift"===a.motion?s*a.speed*3:0,x=(a.direction??45)*Math.PI/180,v=Math.round(Math.cos(x)*M),b=Math.round(Math.sin(x)*M),w=(t,e)=>(t%e+e)%e,y=d.map(t=>.299*t[0]+.587*t[1]+.114*t[2]),S="shimmer"===a.motion?.15*Math.sin(s*a.speed*2):0;for(let a=0;a<i;a++)for(let s=0;s<e;s++){const p=4*(a*e+s),x=3*(a%3*e+s);if(0===t[p+3]){g&&(g[x]=g[x+1]=g[x+2]=0);continue}let k=0;const A=h?(O[64*(a-b&63)+(s-v&63)]+.5)/O.length:0;c?k=c[(a-b&m)*l+(s-v&m)]:"noise"===r?k=X(s-v,a-b)-.5:"lines"===r?k=w(a-b,4)/3-.5:"vertical-lines"===r?k=w(s-v,4)/3-.5:"diagonal-lines"===r?k=w(s-v+a-b,4)/3-.5:"radial"===r?k=w(Math.hypot(s-e/2,a-i/2)-M,6)/6-.5:"halftone"===r&&(k=Math.hypot(w(s-v,6)-2.5,w(a-b,6)-2.5)/3.54-.5);const E=128*(k*o+S+(.5-n)),T=t[p]+E+(g?.[x]??0),F=t[p+1]+E+(g?.[x+1]??0),I=t[p+2]+E+(g?.[x+2]??0);let P=0,R=0,C=0;if(d.length){let t=1/0,e=1/0,i=0,a=0;const s=.299*T+.587*F+.114*I;for(let r=0;r<d.length;r++){const o=d[r],n=f?(s-y[r])**2:(T-o[0])**2*.299+(F-o[1])**2*.587+(I-o[2])**2*.114;n<t?(h&&(e=t,a=i,i=r),t=n,[P,R,C]=o):h&&n<e&&(e=n,a=r)}if(h&&o>0&&Number.isFinite(e)){const t=d[a],e=t[0]-P,r=t[1]-R,n=t[2]-C,h=y[a]-y[i],l=f?h*h:e*e*.299+r*r*.587+n*n*.114,c=f?(s-y[i])*h:(T-P)*e*.299+(F-R)*r*.587+(I-C)*n*.114;A<(l?Math.max(0,Math.min(1,c/l*o)):0)&&([P,R,C]=t)}}else if(h){const t=Math.max(0,Math.min(1,.5+(A-.5)*o));P=51*Math.floor(T/51+1-t),R=51*Math.floor(F/51+1-t),C=51*Math.floor(I/51+1-t)}else P=51*Math.round(T/51),R=51*Math.round(F/51),C=51*Math.round(I/51);if(t[p]=P,t[p+1]=R,t[p+2]=C,g&&u){g[x]=g[x+1]=g[x+2]=0;for(const[t,r,n]of u){const h=s+t;if(h<0||h>=e||a+r>=i)continue;const l=3*((a+r)%3*e+h);g[l]+=(T-P)*n*o,g[l+1]+=(F-R)*n*o,g[l+2]+=(I-C)*n*o}}}}(s,C,N,v.dither,i),r.ctx.putImageData(new ImageData(s,C,N),0,0),k=a?mt:""}h.ctx.imageSmoothingEnabled=!1,h.ctx.drawImage(r.canvas,0,0,ht,lt)}else{const i=Array.from($[v.style]??v.charset),s=h.ctx,r=z(v.ink),l="ascii"===v.style||!!$[v.style],c=Math.max(3,Math.round(.92*gt)),m=Math.ceil(ut+4),d=Math.ceil(gt+4),u=[i.join(""),c,m,d,v.ink,v.colorMode].join(":");if(l&&u!==G&&(G=u,_(f.canvas,m*i.length,d),f.ctx.clearRect(0,0,f.canvas.width,d),f.ctx.font=`${c}px monospace`,f.ctx.textBaseline="middle",f.ctx.textAlign="center",f.ctx.fillStyle="accent"===v.colorMode?v.ink:"#ffffff",i.forEach((t,e)=>f.ctx.fillText(t,e*m+m/2,d/2))),"lego"===v.style&&x!==ut){x=ut,_(g.canvas,Math.ceil(ut),Math.ceil(gt));const t=g.ctx;t.clearRect(0,0,g.canvas.width,g.canvas.height),t.fillStyle="rgba(255,255,255,.2)",t.strokeStyle="rgba(0,0,0,.25)",t.lineWidth=Math.max(.5,.6*ot),t.beginPath(),t.arc(ut/2,gt/2,.28*ut,0,2*Math.PI),t.fill(),t.stroke()}s.font=`${c}px monospace`,s.textBaseline="middle",s.textAlign="center";for(let h=0;h<N;h++)for(let c=0;c<C;c++){let u=c,p=h,M=0;if(q.active&&(q.sample(c/C,h/N,H),u=Math.max(0,Math.min(C-1,c-H[0]*C)),p=Math.max(0,Math.min(N-1,h-H[1]*N)),M=H[2]/3),I(T,C,N,u,p,tt),!tt[3])continue;const x=tt[0],b=tt[1],w=tt[2],y=(.299*x+.587*b+.114*w)/255;let S=y;["trail","contour"].includes(v.hover.effect)&&M?S=V(S,M):"etch"===v.hover.effect?S=Math.max(0,Math.min(1,S+.35*M)):"dissolve"===v.hover.effect&&(S*=Math.max(0,1+M));let k=c*ut,A=h*gt,E=1;o(e,c/C,h/N,t,K,y),n(K,v.motion.amount??1),k+=K[0]*ht/960,A+=K[1]*lt/960,S=Math.max(0,Math.min(1,S+K[2])),E=K[3]*tt[3]/255,l||"accent"!==v.colorMode||"cmyk"===v.style||(E*=S),s.globalAlpha=E;const F=255*(S-y),P="source"===v.colorMode?`rgb(${x+F},${b+F},${w+F})`:"gray"===v.colorMode?`rgb(${Math.round(255*S)},${Math.round(255*S)},${Math.round(255*S)})`:v.ink;if(s.fillStyle=P,l){const t=Math.max(0,Math.min(i.length-1,Math.round(S*(i.length-1))));"accent"===v.colorMode?s.drawImage(f.canvas,t*m,0,m,d,a?Math.round(k+(ut-m)/2):k+(ut-m)/2,a?Math.round(A+(gt-d)/2):A+(gt-d)/2,m,d):s.fillText(i[t],k+ut/2,A+gt/2)}else if("dots"===v.style)s.beginPath(),s.arc(k+ut/2,A+gt/2,.48*ut*Math.sqrt(S),0,2*Math.PI),s.fill();else if("led"===v.style)s.beginPath(),s.arc(k+ut/2,A+gt/2,.39*ut,0,2*Math.PI),s.fill(),s.globalAlpha=.35*E,s.fillStyle="#ffffff",s.beginPath(),s.arc(k+.43*ut,A+.4*gt,.11*ut,0,2*Math.PI),s.fill();else if("hex"===v.style){const t=k+ut/2,e=A+gt/2;s.beginPath();for(let i=0;i<6;i++){const a=Math.PI/3*i,r=t+Math.cos(a)*ut*.49,o=e+Math.sin(a)*gt*.49;0===i?s.moveTo(r,o):s.lineTo(r,o)}s.closePath(),s.fill()}else if("cmyk"===v.style){s.fillStyle="#ffffff",s.fillRect(k,A,ut,gt);const t=(t,e)=>Math.max(0,Math.min(255,"source"===v.colorMode?t+F:"gray"===v.colorMode?255*S:e*S)),e=t(x,r[0]),i=t(b,r[1]),a=t(w,r[2]),o=1-Math.max(e,i,a)/255,n=Math.max(.001,1-o),h=[["#00ffff",(1-e/255-o)/n,.36,.36],["#ff00ff",(1-i/255-o)/n,.64,.36],["#ffff00",(1-a/255-o)/n,.5,.66],["#000000",o,.5,.5]];s.globalCompositeOperation="multiply";for(const[t,e,i,a]of h)s.fillStyle=t,s.beginPath(),s.arc(k+ut*i,A+gt*a,.48*ut*Math.sqrt(Math.max(0,e)),0,2*Math.PI),s.fill();s.globalCompositeOperation="source-over"}else if("voxel"===v.style){const t=k+ut/2,e=A+gt/2;s.beginPath(),s.moveTo(t,A),s.lineTo(k+ut,A+.25*gt),s.lineTo(t,e),s.lineTo(k,A+.25*gt),s.closePath(),s.fill(),s.globalAlpha=.72*E,s.beginPath(),s.moveTo(k,A+.25*gt),s.lineTo(t,e),s.lineTo(t,A+gt),s.lineTo(k,A+.75*gt),s.closePath(),s.fill(),s.globalAlpha=.42*E,s.beginPath(),s.moveTo(t,e),s.lineTo(k+ut,A+.25*gt),s.lineTo(k+ut,A+.75*gt),s.lineTo(t,A+gt),s.closePath(),s.fill()}else{const t="pixel"===v.style?0:Math.max(.5,.06*ut);s.fillRect(k,A,ut-t,gt-t),"lego"===v.style&&s.drawImage(g.canvas,k,A),"disco"===v.style&&(s.fillStyle=`rgba(255,255,255,${.1+.25*X(c,h)})`,s.fillRect(k,A,ut-t,.35*gt),s.fillStyle="rgba(0,0,0,.25)",s.fillRect(k,A+.65*gt,ut-t,.35*gt-t))}}}h.ctx.globalAlpha=1,(v.color.amount||v.lights.length)&&(_(d.canvas,ht,lt),d.ctx.clearRect(0,0,ht,lt),d.ctx.drawImage(h.canvas,0,0)),v.color.amount&&(h.ctx.save(),h.ctx.globalCompositeOperation=v.color.blend,h.ctx.globalAlpha=v.color.amount,h.ctx.fillStyle=v.color.tint,h.ctx.fillRect(0,0,ht,lt),h.ctx.restore());for(const t of v.lights){const e=t.radius*Math.max(ht,lt),i=h.ctx.createRadialGradient(t.x*ht,t.y*lt,0,t.x*ht,t.y*lt,e);i.addColorStop(0,t.color),i.addColorStop(1,"transparent"),h.ctx.save(),h.ctx.globalCompositeOperation="screen",h.ctx.globalAlpha=t.intensity,h.ctx.fillStyle=i,h.ctx.fillRect(0,0,ht,lt),h.ctx.restore()}if((v.color.amount||v.lights.length)&&(h.ctx.globalCompositeOperation="destination-in",h.ctx.drawImage(d.canvas,0,0),h.ctx.globalCompositeOperation="source-over"),v.mask.enabled&&v.mask.shapes.length){const t=c.ctx;t.clearRect(0,0,ht,lt),t.fillStyle="#fff",t.strokeStyle="#fff",t.lineCap="round",t.lineJoin="round";for(const e of v.mask.shapes){if(t.beginPath(),"ellipse"===e.kind)t.ellipse((e.x+e.width/2)*ht,(e.y+e.height/2)*lt,e.width*ht/2,e.height*lt/2,0,0,2*Math.PI);else{if("rectangle"!==e.kind){if(t.lineWidth=(e.size??.05)*ht,1===e.points?.length){t.arc(e.points[0][0]*ht,e.points[0][1]*lt,t.lineWidth/2,0,2*Math.PI),t.fill();continue}e.points?.forEach(([e,i],a)=>a?t.lineTo(e*ht,i*lt):t.moveTo(e*ht,i*lt)),t.stroke();continue}t.rect(e.x*ht,e.y*lt,e.width*ht,e.height*lt)}t.fill()}h.ctx.globalCompositeOperation=v.mask.invert?"destination-out":"destination-in",h.ctx.drawImage(c.canvas,0,0),h.ctx.globalCompositeOperation="source-over"}const M=l.ctx;M.clearRect(0,0,ht,lt),M.globalAlpha=v.backdrop.opacity;const b=v.backdrop;if("solid"===b.mode&&(M.fillStyle=b.color,M.fillRect(0,0,ht,lt)),"gradient"===b.mode){const t=M.createLinearGradient(0,0,ht,lt);t.addColorStop(0,b.color),t.addColorStop(1,b.color2),M.fillStyle=t,M.fillRect(0,0,ht,lt)}if("source"===b.mode&&M.drawImage(s.canvas,0,0),"blurred"===b.mode){const t=Math.max(1,b.blur);_(m.canvas,Math.max(2,Math.round(ht/t)),Math.max(2,Math.round(lt/t))),m.ctx.drawImage(s.canvas,0,0,m.canvas.width,m.canvas.height),M.imageSmoothingEnabled=!0,M.drawImage(m.canvas,0,0,ht,lt)}M.globalAlpha=1,v.effects.characterBloom>0&&(_(u.canvas,Math.max(2,Math.round(ht/3)),Math.max(2,Math.round(lt/3))),u.ctx.clearRect(0,0,u.canvas.width,u.canvas.height),u.ctx.drawImage(h.canvas,0,0,u.canvas.width,u.canvas.height),M.save(),M.globalAlpha=.8*v.effects.characterBloom,M.globalCompositeOperation="screen",M.filter=`blur(${1+4*v.effects.characterBloom}px)`,M.drawImage(u.canvas,0,0,ht,lt),M.restore()),M.drawImage(h.canvas,0,0),A=bt?wt:""}const yt=Object.entries(v.effects).some(([t,e])=>!["angle","focus","blurType","characterBloom"].includes(t)&&"number"==typeof e&&e>0);a.clearRect(0,0,ht,lt),yt?(void 0===M&&(M=function(){const t=document.createElement("canvas"),e=t.getContext("webgl",{alpha:!0,premultipliedAlpha:!1,antialias:!1,preserveDrawingBuffer:!0});if(!e)return null;const i=[],a=(t,a)=>{const s=e.createShader(t);if(i.push(s),e.shaderSource(s,a),e.compileShader(s),!e.getShaderParameter(s,e.COMPILE_STATUS))throw new Error(e.getShaderInfoLog(s)||"Finish shader failed");return s},s=e.createProgram();if(e.attachShader(s,a(e.VERTEX_SHADER,"attribute vec2 p;varying vec2 uv;void main(){uv=(p+1.)*.5;gl_Position=vec4(p,0.,1.);}")),e.attachShader(s,a(e.FRAGMENT_SHADER,"precision mediump float;varying vec2 uv;uniform sampler2D src;uniform vec2 size;uniform float t,bloom,grain,dust,scanlines,crt,prism,vignette,glitch,pixelate,blur,blurMode,angle,focus,halftone,rgbSplit,sharpen;\n float hash(vec2 p){return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453);}\n vec4 sampleAt(vec2 p){if(min(min(p.x,p.y),min(1.-p.x,1.-p.y))<0.)return vec4(0.);return texture2D(src,vec2(p.x,1.-p.y));}\n void main(){vec2 q=uv,c=q-.5;q=c*(1.+dot(c,c)*crt*.25)+.5;\n if(glitch>0.)q.x+=(hash(vec2(floor(q.y*35.),floor(t*5.)))-.5)*.07*glitch*step(.82,hash(vec2(floor(q.y*35.),floor(t*5.)+3.)));\n if(pixelate>0.){vec2 grid=size/(1.+pixelate*20.);q=(floor(q*grid)+.5)/grid;}\n vec4 base=sampleAt(q);float edge=smoothstep(.12,.65,length(c));\n vec2 shift=vec2((prism*3.*edge+rgbSplit*8.)/size.x,prism*edge/size.y);\n if(prism>0.||rgbSplit>0.)base.rgb=vec3(sampleAt(q+shift).r,base.g,sampleAt(q-shift).b);\n vec2 dir=vec2(cos(angle),sin(angle))/size;float amount=blur;\n if(blurMode>1.5&&blurMode<2.5){dir=normalize(c+vec2(.0001))/size;amount*=length(c)*2.;}\n if(blurMode>2.5)amount*=smoothstep(.05,.5,abs(q.y-focus));\n vec4 blurred=base;\n if(amount>0.){blurred=base*.2;for(int i=1;i<=4;i++){float f=float(i)*amount*.35;vec2 off=dir*f;if(blurMode<.5)off=vec2(cos(float(i)*1.57),sin(float(i)*1.57))*amount/size;blurred+=sampleAt(q+off)*.1+sampleAt(q-off)*.1;}}\n vec3 light=vec3(0.);if(bloom>0.)for(int i=0;i<4;i++){float a=float(i)*1.5708;vec3 s=sampleAt(q+vec2(cos(a),sin(a))*6./size).rgb;light+=max(vec3(0.),s-.35)*.25;}\n vec3 col=blurred.rgb+light*bloom;\n if(sharpen>0.){vec2 px=1./size;vec3 near=sampleAt(q+vec2(px.x,0.)).rgb+sampleAt(q-vec2(px.x,0.)).rgb+sampleAt(q+vec2(0.,px.y)).rgb+sampleAt(q-vec2(0.,px.y)).rgb;col+=(base.rgb*4.-near)*sharpen*.5;}\ncol*=1.-scanlines*.4*(.5+.5*cos(q.y*size.y*3.14159));\n col*=1.-vignette*smoothstep(.15,.72,length(c));\n col+=(hash(floor(q*size)+floor(t*12.))-.5)*grain*.2;\n if(dust>0.)col+=step(1.-dust*.002,hash(floor(q*size*.25)+floor(t*2.)))*.4;\n if(halftone>0.)col*=mix(1.,smoothstep(.1,.65,length(fract(q*size/6.)-.5)),halftone);\n gl_FragColor=vec4(clamp(col,0.,1.),blurred.a);}")),e.linkProgram(s),!e.getProgramParameter(s,e.LINK_STATUS))throw new Error("Finish link failed");e.useProgram(s);const r=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,r),e.bufferData(e.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,1]),e.STATIC_DRAW);const o=e.getAttribLocation(s,"p");e.enableVertexAttribArray(o),e.vertexAttribPointer(o,2,e.FLOAT,!1,0,0);const n=e.createTexture();e.bindTexture(e.TEXTURE_2D,n),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE);const h=["t","bloom","grain","dust","scanlines","crt","prism","rgbSplit","sharpen","vignette","glitch","pixelate","blur","blurMode","angle","focus","halftone"],l=Object.fromEntries(h.map(t=>[t,e.getUniformLocation(s,t)])),c=e.getUniformLocation(s,"size");return{canvas:t,render(i,a,r,o=1){t.width===i.width&&t.height===i.height||(t.width=i.width,t.height=i.height,e.viewport(0,0,t.width,t.height)),e.useProgram(s),e.bindTexture(e.TEXTURE_2D,n),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,i),e.uniform2f(c,t.width/o,t.height/o);for(const t of h)e.uniform1f(l[t],"t"===t?r:"blurMode"===t?["gaussian","directional","radial","progressive"].indexOf(a.blurType):"angle"===t?a.angle*Math.PI/180:a[t]??0);return e.drawArrays(e.TRIANGLE_STRIP,0,4),t},destroy(){e.deleteTexture(n),e.deleteBuffer(r),e.deleteProgram(s),i.forEach(t=>e.deleteShader(t)),t.width=t.height=1,e.getExtension("WEBGL_lose_context")?.loseContext()}}}()),M?a.drawImage(M.render(l.canvas,v.effects,i,ot),0,0):a.drawImage(l.canvas,0,0),t.dataset.studioFinish=M?"gpu":"unavailable"):(a.drawImage(l.canvas,0,0),t.dataset.studioFinish="none")},setPixelRatio(t){ot=Math.max(.1,Math.min(8,Number.isFinite(t)?t:1))},get pixelRatio(){return ot},setBudget(t){rt=Math.max(256,Math.min(st,Number.isFinite(t)?Math.round(t):st))},get maxCells(){return rt},configure(t){v=y(t),et=P(v.color),it.configure(v.color.denoise),b++},pointer:(t,e,i)=>{q.configure(v.hover.effect,v.hover.strength,v.hover.radius,v.hover.edgeSafe),q.move(t,e,i)},leave(){q.leave()},get active(){return q.active},get settings(){return y(v)},get capabilities(){return{gpuFinish:null!==M}},invalidate(){w=""},destroy(){M?.destroy();for(const t of[s,r,h,l,c,m,f,d,u,g])t.canvas.width=t.canvas.height=1;W=null,T=new Uint8ClampedArray(0)}}}function et(t,e,i){return new Promise((a,s)=>{const r=()=>{l(),a()},o=()=>{l(),s(new Error("Unable to load this media. Check its format and cross-origin permissions."))},n=()=>{l(),s(new DOMException("Cancelled","AbortError"))},h=setTimeout(o,2e4),l=()=>{clearTimeout(h),t.removeEventListener(e,r),t.removeEventListener("error",o),i?.removeEventListener("abort",n)};t.addEventListener(e,r,{once:!0}),t.addEventListener("error",o,{once:!0}),i?.addEventListener("abort",n,{once:!0}),i?.aborted&&n()})}async function it(t,e){if("string"==typeof t&&t.startsWith("blob:")){const i=await fetch(t,{signal:e}),a=await i.blob();return it(new File([a],"Imported media",{type:a.type}),e)}const i="string"!=typeof t,a=i?t.name:t;if(i?"image/gif"===t.type:/\.gif(?:[?#]|$)/i.test(a)){const a=await import("gifuct-js"),{parseGIF:s,decompressFrames:r}="function"==typeof a.parseGIF?a:a.default,o=i?await t.arrayBuffer():await fetch(t,{signal:e}).then(t=>{if(!t.ok)throw new Error("GIF download failed.");return t.arrayBuffer()});if(e?.aborted)throw new DOMException("Cancelled","AbortError");const n=s(o),h=n.lsd.width,l=n.lsd.height;if(h*l>4e6)throw new Error("GIF is too large. Use a smaller GIF or an MP4.");const c=n.frames.filter(t=>"image"in t).length;if(!c||c*h*l*4>128e6)throw new Error("GIF exceeds the decoded memory budget. Use MP4 for long animations.");const m=r(n,!0);if(m.length*h*l*4>128e6)throw new Error("GIF exceeds the 128 MB decoded budget. Use MP4 for long animations.");const f=document.createElement("canvas");f.width=h,f.height=l;const d=f.getContext("2d"),u=document.createElement("canvas"),g=u.getContext("2d"),p=m.reduce((t,e)=>t+Math.max(20,e.delay),0)/1e3;let M=-1,x=null;const v=t=>{const e=(t%p+p)%p*1e3;let i=0,a=0;for(;a<m.length-1&&(i+=Math.max(20,m[a].delay),!(e<i));a++);a<M&&(d.clearRect(0,0,h,l),M=-1,x=null);for(let t=M+1;t<=a;t++){const e=m[t-1];2===e?.disposalType&&d.clearRect(e.dims.left,e.dims.top,e.dims.width,e.dims.height),3===e?.disposalType&&x&&d.putImageData(x,0,0);const i=m[t];x=3===i.disposalType?d.getImageData(0,0,h,l):null,u.width=i.dims.width,u.height=i.dims.height,g.putImageData(new ImageData(new Uint8ClampedArray(i.patch),u.width,u.height),0,0),d.drawImage(u,i.dims.left,i.dims.top)}return M=a,f};return v(0),{source:f,width:h,height:l,duration:p,animated:!0,seek:async()=>{},frame:v,destroy(){f.width=u.width=1,m.length=0,x=null}}}const s=i?t.type.startsWith("video/"):/\.(mp4|webm|mov)(?:[?#]|$)/i.test(a),r=i?URL.createObjectURL(t):t,o=s?document.createElement("video"):new Image;o.crossOrigin="anonymous",o instanceof HTMLVideoElement&&(o.muted=!0,o.playsInline=!0,o.preload="auto");const n=()=>{o instanceof HTMLVideoElement?(o.pause(),o.removeAttribute("src"),o.load()):o.src="",i&&URL.revokeObjectURL(r)};try{const t=et(o,s?"loadeddata":"load",e);o.src=r,await t;const i=o instanceof HTMLVideoElement?o.videoWidth:o.naturalWidth,a=o instanceof HTMLVideoElement?o.videoHeight:o.naturalHeight;return{source:o,width:i,height:a,duration:o instanceof HTMLVideoElement?o.duration:0,animated:s,async seek(t,e){if(!(o instanceof HTMLVideoElement))return;if(!Number.isFinite(o.duration)||o.duration<=0)throw new Error("Video duration is unavailable.");const i=Math.max(0,Math.min(o.duration-.001,t%o.duration));if(Math.abs(o.currentTime-i)<.001&&o.readyState>=2)return;const a=et(o,"seeked",e);o.currentTime=i,await a},frame:()=>o,destroy:n}}catch(t){throw n(),t}}var at=t=>{if(t?.aborted)throw new DOMException("Export cancelled","AbortError")};function st(t,e,i={}){let a=y(i.settings),s=i.width??e.width,o=i.height??e.height;const n=tt(t,a,i),h=new r;let l=0,c=!1,m=!0,f=!1,d=!0,u=0,g=0,p=0,M=0,x=-1,v=!1!==i.adaptive,b=0,w=0,S=0;const E=matchMedia("(prefers-reduced-motion: reduce)"),T=e.source instanceof HTMLVideoElement?e.source:null,F=()=>{c||l||!d||document.hidden||(l=requestAnimationFrame(R))},I=()=>!f&&!E.matches&&d&&!document.hidden,P=()=>{T&&(T.loop=!0,I()?T.play().catch(()=>{f=!0,m=!0,F()}):T.pause()),p=0,m=!0,F()};function R(t){if(l=0,c||!d||document.hidden)return;const r=I();r&&(u+=p?Math.min(.1,(t-p)/1e3):0),p=t;const y=function(t){return D(t)||L(t)||t.effects.grain>0||t.effects.dust>0||t.effects.glitch>0}(a),A=r&&(e.animated||y),E=T?.getVideoPlaybackQuality?.().totalVideoFrames??-1,P=!T||E<0||E!==x;if(m||n.active||A&&(P||y)&&t-M>=1e3/Math.max(1,Math.min(60,i.fps??60))-.5){const r=performance.now();try{e.animated&&!T&&n.invalidate();const[t,l]=k(s,o,a);g=h.update(u,a.motion.type,a.motion.speed),n.render(e.frame(T?.currentTime??u),u,t,l,g);const c=performance.now()-r;i.onFrame?.(T?.currentTime??u,c),w=w?.9*w+.1*c:c,++b>20&&v&&(A||n.active)&&(S=w>13?S+1:0,S>=12&&n.maxCells>3e3&&(n.setBudget(Math.max(3e3,.8*n.maxCells)),i.onQualityChange?.(n.maxCells),S=0,w=0))}catch(t){f=!0,i.onError?.(t instanceof Error?t:new Error(String(t)))}m=!1,M=t,x=E}r&&(A||n.active)&&F()}const C=e=>{if(!I())return;const i=t.getBoundingClientRect();n.pointer((e.clientX-i.left)/i.width,(e.clientY-i.top)/i.height,e.timeStamp),F()},N=()=>{n.leave(),F()},U=new IntersectionObserver(([t])=>{d=t.isIntersecting,P()});U.observe(t),t.addEventListener("pointermove",C),t.addEventListener("pointerleave",N),t.addEventListener("pointercancel",N),document.addEventListener("visibilitychange",P),E.addEventListener("change",P);const O=()=>{c||(c=!0,cancelAnimationFrame(l),U.disconnect(),t.removeEventListener("pointermove",C),t.removeEventListener("pointerleave",N),t.removeEventListener("pointercancel",N),document.removeEventListener("visibilitychange",P),E.removeEventListener("change",P),i.signal?.removeEventListener("abort",O),n.destroy(),e.destroy())};if(i.signal?.addEventListener("abort",O,{once:!0}),i.signal?.aborted)throw O(),new DOMException("Cancelled","AbortError");return P(),{canvas:t,media:e,update(t){a=A(a,t),n.configure(a),m=!0,F()},resize(t,e,i){void 0!==i&&n.setPixelRatio(i),s=Math.max(2,t),o=Math.max(2,e),m=!0,F()},pause(t=!0){f=t,P()},async seek(t){u=Math.max(0,t),await e.seek(u),n.invalidate(),m=!0,F()},redraw(){n.invalidate(),m=!0,F()},get time(){return T?.currentTime??u},get settings(){return y(a)},get motionTime(){return g},get paused(){return f||E.matches},setAdaptive(t){v=t,b=S=w=0},setBudget(t){n.setBudget(t),i.onQualityChange?.(n.maxCells),m=!0,F()},get pixelRatio(){return n.pixelRatio},get maxCells(){return n.maxCells},get capabilities(){return n.capabilities},destroy:O}}var rt={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")},ot=Object.keys(rt);var nt={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:" ⠁⠃⠇⡇⣇⣧⣷⣿"}},ht=nt;exports.BLEND_MODES=g,exports.CHARACTER_SETS=nt,exports.DEFAULT_STUDIO_SETTINGS=M,exports.DITHER_ALGORITHMS=u,exports.STUDIO_CHARACTER_SETS=ht,exports.STUDIO_CURVE_CHANNELS=h,exports.STUDIO_HOVERS=t,exports.STUDIO_LOOKS=T,exports.STUDIO_MOTIONS=e,exports.STUDIO_PALETTES=p,exports.STUDIO_STYLES=d,exports.STUDIO_TEXT_FONTS=ot,exports.createStudioCurveLookup=f,exports.createStudioRenderer=tt,exports.createStudioText=async function(t,e="Standard",i="#ffffff"){if(!Object.prototype.hasOwnProperty.call(rt,e))throw new Error("Unknown text font.");const{default:a}=await import("figlet/browser"),s=await rt[e]();a.parseFont(e,s.default),a.defaults({fetchFontIfMissing:!1});const r=a.textSync(t.slice(0,120),{font:e}),o=r.split("\n"),n=Math.max(1,...o.map(t=>t.length)),h=Math.max(1,o.length),l=Math.min(1,2048/(9*n)),c=document.createElement("canvas");c.width=Math.ceil(9*n*l+32),c.height=Math.ceil(15*h*l+32);const m=c.getContext("2d");return m.fillStyle="#080808",m.fillRect(0,0,c.width,c.height),m.fillStyle=i,m.font=15*l+"px monospace",m.textBaseline="top",o.forEach((t,e)=>m.fillText(t,16,16+15*e*l)),{canvas:c,ascii:r}},exports.exportStudio=async function(t,e,i){const{format:a,signal:s}=i,r=Math.round(i.width),o=Math.round(i.height);if(!Number.isFinite(r)||!Number.isFinite(o)||r<2||o<2||r>4096||o>4096||r*o>16777216)throw new Error("Choose export dimensions between 2 and 4096 pixels.");if(!["png","jpeg","mp4","webm","gif"].includes(a))throw new Error("Unknown export format.");if(void 0!==i.fps&&!Number.isFinite(i.fps))throw new Error("Frames per second must be finite.");const n=Math.max(1,Math.min(60,Math.round(i.fps??24))),h=i.duration??5;if(!Number.isFinite(h)||h<=0||h>60)throw new Error("Choose a duration from 0 to 60 seconds.");const l="png"===a||"jpeg"===a,c=i.time??0;if(!Number.isFinite(c)||c<0)throw new Error("Image time must be a finite non-negative number.");if(void 0!==i.motionTime&&(!Number.isFinite(i.motionTime)||i.motionTime<0))throw new Error("Motion time must be a finite non-negative number.");if(!l&&r*o>8294400)throw new Error("Video exports support up to 3840 × 2160 pixels.");if("gif"===a&&(r*o>921600||h*n>600))throw new Error("GIF export supports up to 1280 × 720 and 600 frames. Use MP4 for larger exports.");if(void 0!==i.referenceWidth&&(!Number.isFinite(i.referenceWidth)||i.referenceWidth<1))throw new Error("Reference width must be a positive number.");if("gif"===a&&n>30)throw new Error("GIF exports support up to 30 fps. Choose MP4 or WebM for higher frame rates.");const m=document.createElement("canvas"),f=tt(m,y(e),{maxDimension:4096,maxCells:i.maxCells??12e3,pixelRatio:r/(i.referenceWidth??Math.min(r,960))});let d;try{if(at(s),i.onProgress?.(0),l){if(f.render(await t.frame(c,s),c,r,o,i.motionTime),"unavailable"===m.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");at(s);const e=await new Promise((t,e)=>m.toBlob(i=>i?t(i):e(new Error("Image export failed.")),"png"===a?"image/png":"image/jpeg",i.quality??.92));return i.onProgress?.(1),e}const e=Math.ceil(h*n);if("gif"===a){const a=await import("gifenc"),{GIFEncoder:l,quantize:c,applyPalette:d}="function"==typeof a.GIFEncoder?a:a.default,u=l(),g=m.getContext("2d");for(let a=0;a<e;a++){at(s);const l=a/n;if(f.invalidate(),f.render(await t.frame(l,s),l,r,o),"unavailable"===m.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");const p=g.getImageData(0,0,r,o).data,M=c(p,256),x=d(p,M);u.writeFrame(x,r,o,{palette:M,delay:10*(Math.round(100*Math.min((a+1)/n,h))-Math.round(100*a/n)),repeat:0}),i.onProgress?.((a+1)/e*.98),await new Promise(t=>setTimeout(t,0))}return u.finish(),i.onProgress?.(1),new Blob([new Uint8Array(u.bytes())],{type:"image/gif"})}const{Output:u,Mp4OutputFormat:g,WebMOutputFormat:p,BufferTarget:M,CanvasSource:x,canEncodeVideo:v}=await import("mediabunny"),b="mp4"===a?"avc":"vp9";if(!await v(b,{width:r,height:o}))throw new Error(`${a.toUpperCase()} encoding is unavailable in this browser. Try another format or a current browser with WebCodecs.`);const w=new u({format:"mp4"===a?new g({fastStart:"in-memory"}):new p,target:new M});m.width=r,m.height=o,d=()=>w.cancel();const y=new x(m,{codec:b,bitrate:Math.max(5e5,Math.round(r*o*n*.15))});w.addVideoTrack(y,{frameRate:n}),m.width=r,m.height=o,await w.start();for(let a=0;a<e;a++){at(s);const l=a/n;if(f.invalidate(),f.render(await t.frame(l,s),l,r,o),"unavailable"===m.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");await y.add(l,Math.min(1/n,h-l)),i.onProgress?.((a+1)/e*.98),a%4==0&&await new Promise(t=>setTimeout(t,0))}return y.close(),at(s),await w.finalize(),d=void 0,i.onProgress?.(1),new Blob([w.target.buffer],{type:"mp4"===a?"video/mp4":"video/webm"})}catch(t){throw await(d?.().catch(()=>{})),t}finally{f.destroy(),m.width=m.height=1}},exports.loadStudioMedia=it,exports.mountStudio=async function(t,e,i={}){const a=await it(e,i.signal);try{return st(t,a,i)}catch(t){throw a.destroy(),t}},exports.mountStudioMedia=st,exports.normalizeStudioCurve=c,exports.normalizeStudioCurves=m,exports.normalizeStudioSettings=y,exports.parseStudioSettings=function(t){if(t.length>1e5)throw new Error("Settings exceed 100 KB.");return y(JSON.parse(t))},exports.restyleStudio=function(t,e=Math.random){const i=T.filter(e=>e.settings.style!==t.style||e.settings.ink!==t.ink),a=F(i[Math.min(i.length-1,Math.max(0,Math.floor(e()*i.length)))].id);return a.aspectRatio=t.aspectRatio,a.crop={...t.crop},a.mask=y(t).mask,a},exports.serializeStudioSettings=function(t){return JSON.stringify(y(t))},exports.studioCrop=S,exports.studioDimensions=k,exports.studioGrid=E,exports.studioLook=F,exports.studioSourceSize=J,exports.updateStudioSettings=A;//# sourceMappingURL=studio.cjs.map
|
package/dist/studio.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as StudioSettings, a as StudioInput } from './model-
|
|
2
|
-
export { B as BLEND_MODES, C as CHARACTER_SETS, D as DEFAULT_STUDIO_SETTINGS, b as DITHER_ALGORITHMS, c as DitherAlgorithm, d as STUDIO_CHARACTER_SETS, e as
|
|
1
|
+
import { S as StudioSettings, a as StudioInput } from './model-BR3qK_NW.cjs';
|
|
2
|
+
export { B as BLEND_MODES, C as CHARACTER_SETS, D as DEFAULT_STUDIO_SETTINGS, b as DITHER_ALGORITHMS, c as DitherAlgorithm, d as STUDIO_CHARACTER_SETS, e as STUDIO_CURVE_CHANNELS, f as STUDIO_PALETTES, g as STUDIO_STYLES, h as StudioCurveChannel, i as StudioCurvePoint, j as StudioCurves, k as StudioLight, l as StudioMask, m as StudioStyle, n as createStudioCurveLookup, o as normalizeStudioCurve, p as normalizeStudioCurves, q as normalizeStudioSettings, r as parseStudioSettings, s as serializeStudioSettings, t as studioCrop, u as studioDimensions, v as studioGrid, w as updateStudioSettings } from './model-BR3qK_NW.cjs';
|
|
3
3
|
import * as figlet_fonts_Wavy from 'figlet/fonts/Wavy';
|
|
4
4
|
import * as figlet_fonts_Univers from 'figlet/fonts/Univers';
|
|
5
5
|
import * as figlet_fonts_3_D from 'figlet/fonts/3-D';
|
|
@@ -120,6 +120,8 @@ declare function mountStudio(canvas: HTMLCanvasElement, source: File | string, o
|
|
|
120
120
|
seek(seconds: number): Promise<void>;
|
|
121
121
|
redraw(): void;
|
|
122
122
|
readonly time: number;
|
|
123
|
+
/** Independent serializable snapshot; edits must go through update(). */
|
|
124
|
+
readonly settings: StudioSettings;
|
|
123
125
|
/** Ambient phase of the last displayed frame, preserved across speed edits. */
|
|
124
126
|
readonly motionTime: number;
|
|
125
127
|
readonly paused: boolean;
|
|
@@ -142,6 +144,8 @@ declare function mountStudioMedia(canvas: HTMLCanvasElement, media: StudioMedia,
|
|
|
142
144
|
seek(seconds: number): Promise<void>;
|
|
143
145
|
redraw(): void;
|
|
144
146
|
readonly time: number;
|
|
147
|
+
/** Independent serializable snapshot; edits must go through update(). */
|
|
148
|
+
readonly settings: StudioSettings;
|
|
145
149
|
/** Ambient phase of the last displayed frame, preserved across speed edits. */
|
|
146
150
|
readonly motionTime: number;
|
|
147
151
|
readonly paused: boolean;
|
package/dist/studio.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as StudioSettings, a as StudioInput } from './model-
|
|
2
|
-
export { B as BLEND_MODES, C as CHARACTER_SETS, D as DEFAULT_STUDIO_SETTINGS, b as DITHER_ALGORITHMS, c as DitherAlgorithm, d as STUDIO_CHARACTER_SETS, e as
|
|
1
|
+
import { S as StudioSettings, a as StudioInput } from './model-Tyu-NpVf.js';
|
|
2
|
+
export { B as BLEND_MODES, C as CHARACTER_SETS, D as DEFAULT_STUDIO_SETTINGS, b as DITHER_ALGORITHMS, c as DitherAlgorithm, d as STUDIO_CHARACTER_SETS, e as STUDIO_CURVE_CHANNELS, f as STUDIO_PALETTES, g as STUDIO_STYLES, h as StudioCurveChannel, i as StudioCurvePoint, j as StudioCurves, k as StudioLight, l as StudioMask, m as StudioStyle, n as createStudioCurveLookup, o as normalizeStudioCurve, p as normalizeStudioCurves, q as normalizeStudioSettings, r as parseStudioSettings, s as serializeStudioSettings, t as studioCrop, u as studioDimensions, v as studioGrid, w as updateStudioSettings } from './model-Tyu-NpVf.js';
|
|
3
3
|
import * as figlet_fonts_Wavy from 'figlet/fonts/Wavy';
|
|
4
4
|
import * as figlet_fonts_Univers from 'figlet/fonts/Univers';
|
|
5
5
|
import * as figlet_fonts_3_D from 'figlet/fonts/3-D';
|
|
@@ -120,6 +120,8 @@ declare function mountStudio(canvas: HTMLCanvasElement, source: File | string, o
|
|
|
120
120
|
seek(seconds: number): Promise<void>;
|
|
121
121
|
redraw(): void;
|
|
122
122
|
readonly time: number;
|
|
123
|
+
/** Independent serializable snapshot; edits must go through update(). */
|
|
124
|
+
readonly settings: StudioSettings;
|
|
123
125
|
/** Ambient phase of the last displayed frame, preserved across speed edits. */
|
|
124
126
|
readonly motionTime: number;
|
|
125
127
|
readonly paused: boolean;
|
|
@@ -142,6 +144,8 @@ declare function mountStudioMedia(canvas: HTMLCanvasElement, media: StudioMedia,
|
|
|
142
144
|
seek(seconds: number): Promise<void>;
|
|
143
145
|
redraw(): void;
|
|
144
146
|
readonly time: number;
|
|
147
|
+
/** Independent serializable snapshot; edits must go through update(). */
|
|
148
|
+
readonly settings: StudioSettings;
|
|
145
149
|
/** Ambient phase of the last displayed frame, preserved across speed edits. */
|
|
146
150
|
readonly motionTime: number;
|
|
147
151
|
readonly paused: boolean;
|
package/dist/studio.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var t=[{value:"none",label:"Off",group:"Still",description:"Keep the artwork still under the pointer."},{value:"trail",label:"Trail",group:"Change characters",description:"A fluid wake changes character density and settles behind your cursor."},{value:"dissolve",label:"Dissolve",group:"Change characters",description:"Erase a soft path through the characters; the image gradually reforms."},{value:"contour",label:"Contour",group:"Change characters",description:"Fine tonal rings trace your path without moving the grid."},{value:"etch",label:"Emboss",group:"Change characters",description:"Press a light-and-shadow impression into the characters; the grid stays fixed."},{value:"water",label:"Water",group:"Move the image",description:"Soft ripples refract the image and settle after your stroke."},{value:"silk",label:"Silk",group:"Move the image",description:"Directional folds follow the movement of your hand."},{value:"vortex",label:"Vortex",group:"Move the image",description:"A swirling wake curls through the image."},{value:"magnetic",label:"Magnetic Pull",group:"Move the image",description:"The image gathers toward your stroke, then relaxes."},{value:"scatter",label:"Scatter",group:"Move the image",description:"A textured outward scatter settles behind your cursor."},{value:"elastic",label:"Elastic",group:"Move the image",description:"Push the image with your stroke; it recoils and springs back into place."},{value:"rake",label:"Rake",group:"Move the image",description:"Comb the image into alternating ribbons that glide back into alignment."}],e=[{value:"none",mode:"none",group:"Still",label:"Off",description:"Keep the image still. Hover stays available."},{value:"caustics",mode:"caustics",group:"Light and texture",label:"Caustics",description:"Soft ribbons of light travel across a stationary character grid."},{value:"current",mode:"current",group:"Flow and depth",label:"Slow Current",description:"A gentle flow through the image, with steady edges."},{value:"reform",mode:"reform",group:"Rebuild",label:"Reveal & Reform",description:"Disperse, gather, then hold the complete image."},{value:"sheen",mode:"sheen",group:"Light and texture",label:"Sheen",description:"A broad diagonal light sweep; characters stay anchored."},{value:"tidal",mode:"tidal",group:"Flow and depth",label:"Tidal Rings",description:"Concentric currents travel outward, with protected edges."},{value:"grain",mode:"grain",group:"Light and texture",label:"Living Grain",description:"Slow, individually phased tonal changes on a stationary grid."},{value:"parallax",mode:"parallax",group:"Flow and depth",label:"Parallax",description:"A shallow, continuous drift through the image, with the edges held in place."},{value:"weave",mode:"weave",group:"Flow and depth",label:"Woven Flow",description:"Interlaced bands move in opposing directions, like a flexible printed fabric."},{value:"print",mode:"print",group:"Rebuild",label:"Print Shift",description:"Staggered rows lift, soften and register back into the image."},{value:"trace",mode:"trace",group:"Light and texture",label:"Contour Light",description:"Light follows the source image’s tonal contours; every character stays anchored."}],i=t=>Math.max(0,Math.min(1,t)),a=(t,e,a)=>{const s=i((a-t)/(e-t));return s*s*(3-2*s)},s=(t,e)=>{const i=(.06711056*t+.00583715*e)%1*52.9829189;return i-Math.floor(i)},r=class{constructor(){this.last=null,this.mode="none",this.phase=0}update(t,e,i=1){return Number.isFinite(t)?((e!==this.mode||null!==this.last&&t<this.last)&&(this.mode=e,this.phase=0,this.last=t),null!==this.last&&(this.phase+=Math.max(0,t-this.last)*Math.max(.1,Math.min(3,Number.isFinite(i)?i:1))),this.last=t,this.phase):this.phase}};function o(t,e,r,o,n,h=.5){if(n[0]=n[1]=n[2]=0,n[3]=1,"none"===t)return n;const l=o*Math.PI/6,c=a(0,.12,Math.min(e,1-e,r,1-r));if("caustics"===t){const t=Math.sin(9*e+5*r+l)+Math.sin(8*r-3*e-l),i=Math.pow(Math.max(0,1-.72*Math.abs(t)),3);n[2]=(.22*i-.045)*c}else if("current"===t)n[0]=Math.sin(9*r+l)*Math.cos(7*e-l)*10*c,n[1]=Math.cos(8*e+l)*Math.sin(6*r-l)*7*c;else if("sheen"===t)n[2]=.2*Math.pow(.5+.5*Math.cos(5*e+3*r-l),8)-.025;else if("tidal"===t){const t=e-.5,i=r-.5,a=Math.hypot(t,i),s=Math.sin(22*a-l)*c;n[0]=t*s*9,n[1]=i*s*9,n[2]=.035*s}else if("grain"===t){const t=s(Math.floor(160*e),Math.floor(100*r))*Math.PI*2;n[2]=.07*Math.sin(l+t)}else if("parallax"===t){const t=.45+.55*Math.max(0,1-1.4*Math.hypot(e-.5,r-.5));n[0]=12*Math.sin(l)*t*c,n[1]=6*(Math.cos(l)-1)*t*c}else if("weave"===t)n[0]=Math.sin(r*Math.PI*6+l)*Math.sin(l)*8*c,n[1]=Math.sin(e*Math.PI*6-l)*Math.sin(l)*6*c;else if("print"===t){const t=Math.floor(24*r),e=((o+3*s(t,3))%12+12)%12,i=a(1,2.5,e)*(1-a(3.5,5,e));n[0]=Math.sin(2.4*t)*i*9*c,n[1]=5*-i*c,n[2]=.22*-i,n[3]=1-.45*i}else if("trace"===t){const t=.5+.5*Math.cos(l);n[2]=.22*Math.pow(Math.max(0,1-Math.abs(i(h)-t)/.16),3)-.015}else if("reform"===t){const t=(o%12+12)%12,i=s(Math.floor(160*e),Math.floor(100*r)),h=.65*e+.2*r+.15*i+.08*Math.sin(8*e-5*r),m=a(1.8+1.2*h,3.8+1.2*h,t)*(1-a(5+1.7*h,7.2+1.7*h,t));n[0]=Math.sin(9*r+l)*m*(1-m)*24*c,n[1]=-m*(1-m)*(8+12*i)*c,n[2]=.45*-m,n[3]=1-.9*m}return n}function n(t,e){const a=Math.max(0,Math.min(2,Number.isFinite(e)?e:1));return t[0]*=a,t[1]*=a,t[2]*=a,t[3]=i(1+(t[3]-1)*a),t}var h=["ascii","blocks","braille","dots","lines","cross","diagonal","diamond","mixed","pixel","mosaic","lego","voxel","disco","dither","hex","led","cmyk"],l=["none","bayer2","bayer4","bayer8","bayer16","floyd-steinberg","atkinson","stucki","sierra","sierra-lite","burkes","jarvis","halftone","lines","noise","vertical-lines","diagonal-lines","radial"],c=["source-over","multiply","screen","overlay","soft-light","hard-light","color-dodge","color-burn","hue","saturation","color","luminosity"],m={original:[],gray4:["#000000","#555555","#aaaaaa","#ffffff"],gray8:["#000000","#242424","#494949","#6d6d6d","#929292","#b6b6b6","#dbdbdb","#ffffff"],rgb8:["#000000","#ff0000","#00ff00","#0000ff","#ffff00","#ff00ff","#00ffff","#ffffff"],cyberpunk:["#08081a","#3c1670","#ed299a","#29dfef","#fff7bf"],pastel:["#393448","#a5b4d4","#9ed9c6","#e7aac1","#f5e8be"],mono:["#080808","#f2f2e8"],asciify:["#080808","#625b38","#a19558","#e8b900"],gameboy:["#0f380f","#306230","#8bac0f","#9bbc0f"],cga:["#000000","#55ffff","#ff55ff","#ffffff"],pico8:["#000000","#1d2b53","#7e2553","#008751","#ab5236","#5f574f","#c2c3c7","#fff1e8","#ff004d","#ffa300","#ffec27","#00e436","#29adff","#83769c","#ff77a8","#ffccaa"],c64:["#000000","#ffffff","#880000","#aaffee","#cc44cc","#00cc55","#0000aa","#eeee77","#dd8855","#664400","#ff7777","#333333","#777777","#aaff66","#0088ff","#bbbbbb"],amber:["#100b00","#5f3b00","#c98014","#ffd17c"],ice:["#081b29","#25586e","#69a6b3","#d9ece7"],risograph:["#f4ebd0","#f2594b","#2853a5","#29232e"],sepia:["#201b17","#6b5039","#b49868","#f6e6c5"],nord:["#2e3440","#4c566a","#88c0d0","#eceff4"],dusk:["#211b35","#654271","#c3788c","#f5c9a3"],forest:["#101f1b","#355747","#87a16f","#e4e3ba"],ocean:["#071b33","#17577f","#3fa7a4","#d9efde"],newsprint:["#191919","#666666","#aaaaaa","#eee9df"],custom:["#080808","#e8b900"]},f={version:1,aspectRatio:"original",style:"ascii",cellSize:6,charset:" .:-=+*#%@",colorMode:"accent",ink:"#e8b900",crop:{x:.5,y:.5,zoom:1,rotation:0},backdrop:{mode:"solid",color:"#080808",color2:"#393323",blur:12,opacity:1},color:{brightness:0,contrast:1,saturation:1,grayscale:0,tint:"#e8b900",amount:0,blend:"source-over"},dither:{algorithm:"none",palette:"mono",colors:["#080808","#e8b900"],amount:1,scale:2,threshold:.5,motion:"none",speed:1,direction:45,colorSpace:"rgb"},mask:{enabled:!1,invert:!1,shapes:[]},lights:[],effects:{bloom:0,characterBloom:0,grain:0,dust:0,scanlines:0,crt:0,prism:0,rgbSplit:0,sharpen:0,vignette:0,glitch:0,pixelate:0,blur:0,blurType:"gaussian",angle:0,focus:.5,halftone:0},motion:{type:"none",speed:1,amount:1},hover:{effect:"trail",strength:.55,radius:.2,edgeSafe:!1}},d=t=>t&&"object"==typeof t&&!Array.isArray(t)?t:{},u=(t,e,i,a)=>"number"==typeof t&&Number.isFinite(t)?Math.min(a,Math.max(i,t)):e,g=(t,e)=>"string"==typeof t&&/^#[\da-f]{6}$/i.test(t)?t:e,p=(t,e,i)=>e.includes(t)?t:i;function M(i={}){const a=d(i),s=f;if(void 0!==a.version&&1!==a.version)throw new Error("Unsupported studio settings version. Update asciify-engine.");const r=d(a.crop),o=d(a.backdrop),n=d(a.color),M=d(a.dither),x=d(a.mask),v=d(a.effects),b=d(a.motion),w=d(a.hover),y={...s.effects};for(const t of["bloom","characterBloom","grain","dust","scanlines","crt","prism","rgbSplit","sharpen","vignette","glitch","pixelate","halftone"])y[t]=u(v[t],0,0,1);y.blur=u(v.blur,0,0,24),y.blurType=p(v.blurType,["gaussian","directional","radial","progressive"],s.effects.blurType),y.angle=u(v.angle,0,-180,180),y.focus=u(v.focus,.5,0,1);let k=2048;return{version:1,aspectRatio:p(a.aspectRatio,["original","16:9","9:16","1:1","4:3","3:4","21:9"],"original"),style:p(a.style,h,s.style),cellSize:u(a.cellSize,s.cellSize,["pixel","mosaic","lego","voxel","disco","dots","hex","led","cmyk"].includes(String(a.style))?1:3,60),charset:"string"==typeof a.charset&&a.charset.length?Array.from(a.charset).slice(0,128).join(""):s.charset,colorMode:p(a.colorMode,["accent","source","gray"],s.colorMode),ink:g(a.ink,s.ink),crop:{x:u(r.x,.5,0,1),y:u(r.y,.5,0,1),zoom:u(r.zoom,1,1,5),rotation:90*Math.round(u(r.rotation,0,-360,360)/90)},backdrop:{mode:p(o.mode,["solid","transparent","source","blurred","gradient"],s.backdrop.mode),color:g(o.color,s.backdrop.color),color2:g(o.color2,s.backdrop.color2),blur:u(o.blur,12,0,32),opacity:u(o.opacity,1,0,1)},color:{brightness:u(n.brightness,0,-1,1),contrast:u(n.contrast,1,0,3),saturation:u(n.saturation,1,0,3),grayscale:u(n.grayscale,0,0,1),tint:g(n.tint,s.color.tint),amount:u(n.amount,0,0,1),blend:p(n.blend,c,s.color.blend)},dither:{algorithm:p(M.algorithm,l,"none"),palette:"string"==typeof M.palette&&Object.prototype.hasOwnProperty.call(m,M.palette)?M.palette:"mono",colors:Array.isArray(M.colors)&&M.colors.length>=2?M.colors.slice(0,32).map(t=>g(t,"#000000")):[...s.dither.colors],amount:u(M.amount,1,0,2),scale:Math.round(u(M.scale,2,1,12)),threshold:u(M.threshold,.5,0,1),motion:p(M.motion,["none","drift","shimmer"],"none"),speed:u(M.speed,1,.1,3),direction:u(M.direction,45,-180,180),colorSpace:p(M.colorSpace,["rgb","luminance"],"rgb")},mask:{enabled:!0===x.enabled,invert:!0===x.invert,shapes:Array.isArray(x.shapes)?x.shapes.slice(0,64).map(t=>{const e=d(t),i=p(e.kind,["rectangle","ellipse","brush"],"rectangle"),a="brush"===i&&Array.isArray(e.points)?e.points.slice(0,k).map(t=>Array.isArray(t)?[Math.round(1e4*u(t[0],0,0,1))/1e4,Math.round(1e4*u(t[1],0,0,1))/1e4]:[0,0]):[];return k-=a.length,{kind:i,x:u(e.x,0,0,1),y:u(e.y,0,0,1),width:u(e.width,.5,0,1),height:u(e.height,.5,0,1),size:u(e.size,.05,.005,.5),points:a}}):[]},lights:Array.isArray(a.lights)?a.lights.slice(0,4).map(t=>{const e=d(t);return{x:u(e.x,.5,0,1),y:u(e.y,.5,0,1),radius:u(e.radius,.3,.02,1),intensity:u(e.intensity,.5,0,1),color:g(e.color,"#ffffff")}}):[],effects:y,motion:{type:p(b.type,e.map(t=>t.mode),"none"),speed:u(b.speed,1,.1,3),amount:u(b.amount,1,0,2)},hover:{effect:p(w.effect,t.map(t=>t.value),"trail"),strength:u(w.strength,.55,0,1),radius:u(w.radius,.2,.1,1),edgeSafe:!0===w.edgeSafe}}}function x(t){return JSON.stringify(M(t))}function v(t){if(t.length>1e5)throw new Error("Settings exceed 100 KB.");return M(JSON.parse(t))}function b(t,e,i,a,s){const r=Math.abs(s.rotation/90)%2==1,o=r?e:t,n=r?t:e,h=Math.max(i/o,a/n)*s.zoom;return{width:o*h,height:n*h,x:(i-o*h)*s.x,y:(a-n*h)*s.y,scale:h,rotated:r}}function w(t,e,i){if(Math.abs(i.crop.rotation/90)%2==1&&([t,e]=[e,t]),"original"===i.aspectRatio)return[t,e];const[a,s]=i.aspectRatio.split(":").map(Number);return t/e>a/s?[Math.round(e*a/s),e]:[t,Math.round(t*s/a)]}function y(t,e){const i={...t,...e};for(const a of["crop","backdrop","color","dither","mask","effects","motion","hover"])e[a]&&Object.assign(i,{[a]:{...t[a],...e[a]}});return M(i)}function k(t,e,i,a=12e3,s=1){const r=Math.max(2,Number.isFinite(t)?t:960),o=Math.max(2,Number.isFinite(e)?e:540),n=Math.max(1,Math.floor(Number.isFinite(a)?a:12e3)),h=Math.max(.01,Number.isFinite(s)?s:1),l=["dither","pixel","mosaic","lego","voxel","disco","dots","hex","led","cmyk"].includes(i.style)?1:1.65;let c=Math.max(1,Math.ceil(Math.sqrt(r*o/(n*l))/h));for(;Math.ceil(r/(c*h))*Math.ceil(o/(c*h*l))>n;)c++;const m="dither"===i.style?i.dither.scale:i.cellSize,f=Math.max(c,m)*h;return{cell:f,rowHeight:f*l,columns:Math.ceil(r/f),rows:Math.ceil(o/(f*l)),minimum:c,limited:m<c}}var S=[["ascii","Signature ASCII","Brand ink and clean characters.",{}],["print","Newsprint","Fine diffusion on warm paper.",{style:"dither",dither:{algorithm:"floyd-steinberg",palette:"newsprint"}}],["handheld","Pocket camera","Four-tone ordered dither.",{style:"dither",dither:{algorithm:"bayer4",palette:"gameboy",scale:3}}],["riso","Two inks","Limited-color print texture.",{style:"dither",dither:{algorithm:"atkinson",palette:"risograph",scale:2}}],["night","Night signal","Gray characters and optical fringe.",{ink:"#888888",effects:{prism:.7,scanlines:.2,vignette:.3}}],["terminal","Phosphor","Green glyphs with a soft glow.",{ink:"#83efad",effects:{bloom:.4,scanlines:.35,crt:.2}}],["mosaic","Mosaic study","Separated color tiles.",{style:"mosaic",cellSize:14,colorMode:"source"}],["bricks","Brickwork","Colorful studded cells.",{style:"lego",cellSize:18,colorMode:"source"}],["voxel","Little volumes","Three-face isometric tiles.",{style:"voxel",cellSize:22,colorMode:"source"}],["disco","Mirror room","Faceted tiles and warm light.",{style:"disco",cellSize:18,colorMode:"source",lights:[{x:.35,y:.25,radius:.25,intensity:.45,color:"#fff2d4"}]}],["wallpaper","Wallpaper","Living ASCII over a softened source.",{backdrop:{mode:"blurred",blur:18,opacity:.55},ink:"#f2e9c9",motion:{type:"caustics",speed:.5}}],["blueprint","Blueprint","Linework in a cool monochrome.",{style:"lines",ink:"#9bccdf",backdrop:{mode:"solid",color:"#0a1e30"}}]].map(([t,e,i,a])=>({id:t,name:e,description:i,settings:M(a)}));function E(t){const e=S.find(e=>e.id===t);if(!e)throw new Error("Unknown studio look.");return M(e.settings)}function A(t,e=Math.random){const i=S.filter(e=>e.settings.style!==t.style||e.settings.ink!==t.ink),a=E(i[Math.min(i.length-1,Math.max(0,Math.floor(e()*i.length)))].id);return a.aspectRatio=t.aspectRatio,a.crop={...t.crop},a.mask=M(t).mask,a}function F(t,e,i,a,s,r){a=Math.max(0,Math.min(e-1,a)),s=Math.max(0,Math.min(i-1,s));const o=Math.floor(a),n=Math.floor(s),h=a-o,l=s-n,c=4*(n*e+o);if(0===h&&0===l){for(let e=0;e<4;e++)r[e]=t[c+e];return}const m=4*(n*e+Math.min(e-1,o+1)),f=4*(Math.min(i-1,n+1)*e+o),d=4*(Math.min(i-1,n+1)*e+Math.min(e-1,o+1)),u=(1-h)*(1-l)*t[c+3],g=h*(1-l)*t[m+3],p=(1-h)*l*t[f+3],M=h*l*t[d+3],x=u+g+p+M;for(let e=0;e<3;e++)r[e]=x?(t[c+e]*u+t[m+e]*g+t[f+e]*p+t[d+e]*M)/x:0;r[3]=x}var T=new Set(["none","floyd-steinberg","atkinson","stucki","sierra","sierra-lite","burkes","jarvis"]);function P(t){return"dither"===t.style&&("shimmer"===t.dither.motion||"drift"===t.dither.motion&&t.dither.amount>0&&!T.has(t.dither.algorithm))}function I(t){return"none"!==t.motion.type&&(t.motion.amount??1)>0}var R=(t,e)=>{const i=43758.5453*Math.sin(127.1*t+311.7*e);return i-Math.floor(i)};var C=new Map([2,4,8,16].map(t=>[t,Float64Array.from({length:t*t},(e,i)=>function(t,e,i){let a=0;for(let s=1;s<i;s*=2){const i=(Math.floor(t/s)%2+2)%2;a=4*a+[[0,2],[3,1]][(Math.floor(e/s)%2+2)%2][i]}return(a+.5)/(i*i)-.5}(i%t,Math.floor(i/t),t))])),L={"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 D(t,e,i){const a=Math.min(t*Math.max(1,i),(1-t)*Math.max(1,i),e*Math.max(1,1/i),(1-e)*Math.max(1,1/i)),s=Math.max(0,Math.min(1,(a-.035)/.105));return s*s*s*(s*(6*s-15)+10)}var N=t=>["dissolve","silk","vortex","magnetic","scatter","etch","elastic","rake"].includes(t),Y=class{constructor(t,e){this.edgeSafe=!1,this.previous=null,this.peak=0,this.scatterDirections=null,this.springX=null,this.springY=null,this.mode="dissolve",this.width=t,this.height=e;const i=t*e;this.pixels=new Uint8Array(4*i),this.ink=new Float32Array(i),this.targetX=new Float32Array(i),this.targetY=new Float32Array(i),this.offsetX=new Float32Array(i),this.offsetY=new Float32Array(i),this.edge=new Float32Array(i);for(let i=0;i<e;i++)for(let a=0;a<t;a++)this.edge[i*t+a]=D(a/(t-1),i/(e-1),t/e);this.clear()}get active(){return this.peak>2e-4}setMode(t){if("elastic"!==t||this.springX||(this.springX=new Float32Array(this.ink.length),this.springY=new Float32Array(this.ink.length)),"scatter"===t&&!this.scatterDirections){const t=this.scatterDirections=new Float64Array(this.width*this.height*2);for(let e=0;e<this.height;e++)for(let i=0;i<this.width;i++){const a=43758.5453*Math.sin(127.1*i+311.7*e),s=(a-Math.floor(a))*Math.PI*2,r=2*(e*this.width+i);t[r]=.7*Math.cos(s),t[r+1]=.7*Math.sin(s)}}t!==this.mode&&(this.mode=t,this.clear())}clear(){for(const t of[this.ink,this.targetX,this.targetY,this.offsetX,this.offsetY,this.pixels])t.fill(0);if(this.previous=null,this.peak=0,this.springX?.fill(0),this.springY?.fill(0),"dissolve"!==this.mode)for(let t=0;t<this.pixels.length;t+=4)this.pixels[t]=this.pixels[t+2]=128}leave(){this.previous=null}move(t,e,i){if(!Number.isFinite(t+e+i))return;t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e));const a=this.previous;this.previous={x:t,y:e};const s=this.width,r=this.height,o=Math.max(1,s/r),n=Math.max(1,r/s),h=a?(t-a.x)*o:0,l=a?(e-a.y)*n:0,c=Math.hypot(h,l);if(!a&&"dissolve"!==this.mode&&"etch"!==this.mode)return;if(a&&c<1e-4)return;const m=.035+.11*Math.max(.1,Math.min(1,i)),f=Math.min(128,Math.max(1,Math.ceil(c/(.45*m)))),d=c?h/c:1,u=c?l/c:0,g=Math.min(1,c/(m*f)*2.2);for(let i=0;i<f;i++){const h=(i+.5)/f,l=a?a.x+(t-a.x)*h:t,c=a?a.y+(e-a.y)*h:e,p=Math.max(0,Math.floor((l-2.5*m/o)*(s-1))),M=Math.min(s-1,Math.ceil((l+2.5*m/o)*(s-1))),x=Math.max(0,Math.floor((c-2.5*m/n)*(r-1))),v=Math.min(r-1,Math.ceil((c+2.5*m/n)*(r-1)));for(let t=x;t<=v;t++)for(let e=p;e<=M;e++){const i=(e/(s-1)-l)*o/m,a=(t/(r-1)-c)*n/m,h=Math.exp(1.5*-(i*i+a*a)),f=t*s+e;if("dissolve"===this.mode||"etch"===this.mode)this.ink[f]=Math.max(this.ink[f],h);else if("elastic"===this.mode)this.springX[f]=Math.max(-24,Math.min(24,this.springX[f]+d*h*g*8)),this.springY[f]=Math.max(-24,Math.min(24,this.springY[f]+u*h*g*8));else{const s=(-i*u+a*d)*h*2.8,r="rake"===this.mode?d*Math.sin(t*Math.PI/3)*h*2:"magnetic"===this.mode?-i*h*2.5:"scatter"===this.mode?(i+this.scatterDirections[2*f])*h*2:"silk"===this.mode?d*s:-a*h*2.5,o="rake"===this.mode?u*Math.sin(e*Math.PI/3)*h*2:"magnetic"===this.mode?-a*h*2.5:"scatter"===this.mode?(a+this.scatterDirections[2*f+1])*h*2:"silk"===this.mode?u*s:i*h*2.5;this.targetX[f]=Math.max(-1,Math.min(1,this.targetX[f]+r*g)),this.targetY[f]=Math.max(-1,Math.min(1,this.targetY[f]+o*g))}}}this.peak=1}step(t){if(!this.active||!Number.isFinite(t))return;const e=Math.max(0,Math.min(.05,t)),i=Math.exp(-("dissolve"===this.mode?2.15:3.2)*e),a=1-Math.exp(-22*e);let s=0;const r=Math.sqrt(336),o=Math.exp(-8*e),n=Math.cos(r*e),h=Math.sin(r*e)/r;for(let t=0;t<this.ink.length;t++)if("etch"===this.mode)this.ink[t]*=i,s=Math.max(s,this.ink[t]);else if("dissolve"===this.mode){this.ink[t]*=i,s=Math.max(s,this.ink[t]);const e=Math.round(65535*this.ink[t]);this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e}else{if("elastic"===this.mode){const e=this.offsetX[t],i=this.offsetY[t],a=this.springX[t],r=this.springY[t];this.offsetX[t]=Math.max(-1,Math.min(1,o*(e*n+(a+8*e)*h))),this.offsetY[t]=Math.max(-1,Math.min(1,o*(i*n+(r+8*i)*h))),this.springX[t]=o*(a*n-(8*a+400*e)*h),this.springY[t]=o*(r*n-(8*r+400*i)*h),s=Math.max(s,.05*Math.abs(this.springX[t]),.05*Math.abs(this.springY[t]))}else this.targetX[t]*=i,this.targetY[t]*=i,this.offsetX[t]+=(this.targetX[t]-this.offsetX[t])*a,this.offsetY[t]+=(this.targetY[t]-this.offsetY[t])*a;s=Math.max(s,Math.abs(this.offsetX[t]),Math.abs(this.offsetY[t]),Math.abs(this.targetX[t]),Math.abs(this.targetY[t]));const e=Math.round(this.offsetX[t]*(this.edgeSafe?this.edge[t]:1)*32767+32768),r=Math.round(this.offsetY[t]*(this.edgeSafe?this.edge[t]:1)*32767+32768);this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e,this.pixels[4*t+2]=r>>>8,this.pixels[4*t+3]=255&r}if("etch"===this.mode)for(let t=0;t<this.height;t++)for(let e=0;e<this.width;e++){const i=t*this.width+e,a=3*(this.ink[t*this.width+Math.max(0,e-1)]-this.ink[t*this.width+Math.min(this.width-1,e+1)]+this.ink[Math.max(0,t-1)*this.width+e]-this.ink[Math.min(this.height-1,t+1)*this.width+e]);this.offsetX[i]=Math.max(-1,Math.min(1,a))*(this.edgeSafe?this.edge[i]:1);const s=Math.round(32767*this.offsetX[i]+32768);this.pixels[4*i]=s>>>8,this.pixels[4*i+1]=255&s}this.peak=s,this.active||this.clear()}sample(t,e,i){const a=Math.max(0,Math.min(this.width-1.001,t*(this.width-1))),s=Math.max(0,Math.min(this.height-1.001,e*(this.height-1))),r=Math.floor(a),o=Math.floor(s),n=a-r,h=s-o,l=o*this.width+r,c=l+this.width,m=t=>(t[l]*(1-n)+t[l+1]*n)*(1-h)+(t[c]*(1-n)+t[c+1]*n)*h;if("etch"===this.mode)return i[0]=i[1]=0,void(i[2]=3*m(this.offsetX));i[0]=m(this.offsetX)*(this.edgeSafe?D(t,e,this.width/this.height):1)*.08,i[1]=m(this.offsetY)*(this.edgeSafe?D(t,e,this.width/this.height):1)*.08,i[2]="dissolve"===this.mode?6*-m(this.ink):0}},U=class{constructor(t,e){this.rings=[],this.previous=null,this.elapsed=1,this.echoPeak=0,this.width=t,this.height=e,this.pixels=new Uint8Array(t*e*4),this.echo=new Float32Array(t*e)}get active(){return this.rings.length>0||this.echoPeak>2e-4}clear(){this.rings=[],this.previous=null,this.elapsed=1,this.pixels.fill(0),this.echo.fill(0),this.echoPeak=0}leave(){this.previous=null}move(t,e,i){const a=Math.max(1,this.width/this.height),s=Math.max(1,this.height/this.width);this.previous&&(Math.hypot((t-this.previous.x)*a,(e-this.previous.y)*s)<.065||this.elapsed<.3)||4!==this.rings.length&&(this.previous={x:t,y:e},this.elapsed=0,this.rings.push({x:t,y:e,age:0,radius:i}))}ringSample(t,e){const i=Math.max(1,this.width/this.height),a=Math.max(1,this.height/this.width);let s=0;for(const r of this.rings){const o=.015+r.age*(.15+.22*r.radius),n=.009+.014*r.radius,h=(Math.hypot((t-r.x)*i,(e-r.y)*a)-o)/n,l=Math.sin(Math.min(1,r.age/.07)*Math.PI/2)*Math.max(0,1-r.age/1.35)**2;s=Math.max(s,Math.exp(-h*h)*l)}return s}sample(t,e){const i=Math.max(0,Math.min(this.width-1,Math.round(t*(this.width-1)))),a=Math.max(0,Math.min(this.height-1,Math.round(e*(this.height-1))));return Math.max(this.ringSample(t,e),this.echo[a*this.width+i])}step(t){if(!Number.isFinite(t))return;const e=Math.max(0,Math.min(.05,t));this.elapsed+=e;for(const t of this.rings)t.age+=e;if(this.rings=this.rings.filter(t=>t.age<1.35),!this.active)return void this.pixels.fill(0);const i=Math.exp(-5.5*e);let a=0;for(let t=0;t<this.height;t++)for(let e=0;e<this.width;e++){const s=t*this.width+e;this.echo[s]=Math.max(this.ringSample(e/(this.width-1),t/(this.height-1)),this.echo[s]*i),a=Math.max(a,this.echo[s]);const r=Math.round(65535*this.echo[s]),o=4*s;this.pixels[o]=r>>>8,this.pixels[o+1]=255&r}this.echoPeak=a,this.active||(this.echo.fill(0),this.pixels.fill(0))}},O=class{constructor(t,e){this.previous=null,this.peak=0,this.width=t,this.height=e;const i=t*e;this.pixels=new Uint8Array(4*i),this.signal=new Float32Array(i),this.offsetX=new Float32Array(i),this.offsetY=new Float32Array(i),this.driftX=new Float32Array(i),this.driftY=new Float32Array(i),this.u=new Float32Array(i),this.v=new Float32Array(i),this.ink=new Float32Array(i),this.a=new Float32Array(i),this.b=new Float32Array(i),this.c=new Float32Array(i),this.pressure=new Float32Array(i),this.pressureNext=new Float32Array(i),this.divergence=new Float32Array(i),this.curl=new Float32Array(i)}get active(){return this.peak>2e-4}clear(){for(const t of[this.u,this.v,this.ink,this.a,this.b,this.c,this.pressure,this.pressureNext,this.divergence,this.curl,this.signal,this.pixels,this.offsetX,this.offsetY,this.driftX,this.driftY])t.fill(0);this.previous=null,this.peak=0}leave(){this.previous=null}move(t,e,i,a=performance.now()){if(!Number.isFinite(t+e+i+a))return;t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e)),i=Math.max(.1,Math.min(1,i));const s=this.previous;if(this.previous={x:t,y:e,time:a},!s)return;const r=(t-s.x)*(this.width-1),o=(e-s.y)*(this.height-1),n=Math.hypot(r,o);if(n<.001)return;const h=Math.min(this.width,this.height),l=a>s.time?Math.max(1/240,(a-s.time)/1e3):1/60,c=Math.min(12,n/h/l),m=1-Math.exp(-c/2.2),f=h*(.022+.075*i)*(.65+.95*m),d=Math.min(128,Math.max(1,Math.ceil(n/(.4*f)))),u=n/f*(.32+.22*m)/d,g=r/n,p=o/n,M=-p,x=g,v=n*(2+18*m)/d;for(let i=0;i<d;i++){const a=(i+.5)/d,r=(s.x+(t-s.x)*a)*(this.width-1),o=(s.y+(e-s.y)*a)*(this.height-1),n=Math.max(1,Math.floor(r-3*f)),h=Math.min(this.width-2,Math.ceil(r+3*f)),l=Math.max(1,Math.floor(o-3*f)),c=Math.min(this.height-2,Math.ceil(o+3*f));for(let t=l;t<=c;t++)for(let e=n;e<=h;e++){const i=((e-r)*g+(t-o)*p)/f,a=((e-r)*M+(t-o)*x)/f,s=Math.exp(-i*i*.65-a*a*1.7),n=t*this.width+e;this.ink[n]=1-(1-this.ink[n])*Math.exp(-s*u);const h=1-a*a*.55,l=i*a*.7;this.u[n]=Math.max(-80,Math.min(80,this.u[n]+(g*h+M*l)*s*v)),this.v[n]=Math.max(-80,Math.min(80,this.v[n]+(p*h+x*l)*s*v))}}this.peak=1}read(t,e,i){const a=0|(e=Math.max(.5,Math.min(this.width-1.5,e))),s=0|(i=Math.max(.5,Math.min(this.height-1.5,i))),r=e-a,o=i-s,n=s*this.width+a;return(t[n]*(1-r)+t[n+1]*r)*(1-o)+(t[n+this.width]*(1-r)+t[n+this.width+1]*r)*o}sample(t,e){return this.read(this.signal,t*(this.width-1),e*(this.height-1))}displacement(t,e,i){i[0]=this.read(this.offsetX,t*(this.width-1),e*(this.height-1)),i[1]=this.read(this.offsetY,t*(this.width-1),e*(this.height-1))}step(t){if(!this.active||!Number.isFinite(t))return;let e=Math.max(0,Math.min(.05,t));const i=this.width,a=this.height;for(;e>1e-7;){const t=Math.min(1/60,e);e-=t;const s=Math.exp(-1.9*t),r=Math.exp(-3.2*t);for(let e=1;e<a-1;e++)for(let o=1;o<i-1;o++){const n=e*i+o,h=Math.max(.5,Math.min(i-1.5,o-this.u[n]*t)),l=Math.max(.5,Math.min(a-1.5,e-this.v[n]*t)),c=0|h,m=0|l,f=h-c,d=l-m,u=m*i+c,g=(1-f)*(1-d),p=f*(1-d),M=(1-f)*d,x=f*d;this.a[n]=(this.u[u]*g+this.u[u+1]*p+this.u[u+i]*M+this.u[u+i+1]*x)*s,this.b[n]=(this.v[u]*g+this.v[u+1]*p+this.v[u+i]*M+this.v[u+i+1]*x)*s,this.c[n]=(this.ink[u]*g+this.ink[u+1]*p+this.ink[u+i]*M+this.ink[u+i+1]*x)*r}[this.u,this.a]=[this.a,this.u],[this.v,this.b]=[this.b,this.v],[this.ink,this.c]=[this.c,this.ink];for(let t=1;t<a-1;t++)for(let e=1;e<i-1;e++){const a=t*i+e;this.curl[a]=.5*(this.v[a+1]-this.v[a-1]-this.u[a+i]+this.u[a-i])}for(let e=1;e<a-1;e++)for(let a=1;a<i-1;a++){const s=e*i+a,r=Math.abs(this.curl[s+1])-Math.abs(this.curl[s-1]),o=Math.abs(this.curl[s+i])-Math.abs(this.curl[s-i]),n=Math.hypot(r,o)+1e-4,h=this.curl[s]*t*10,l=Math.hypot(this.u[s],this.v[s]);this.u[s]+=o/n*h,this.v[s]-=r/n*h;const c=Math.min(1,l/(Math.hypot(this.u[s],this.v[s])+1e-6));this.u[s]*=c,this.v[s]*=c,this.divergence[s]=-.5*(this.u[s+1]-this.u[s-1]+this.v[s+i]-this.v[s-i])}this.pressure.fill(0);for(let t=0;t<4;t++){for(let t=1;t<a-1;t++)for(let e=1;e<i-1;e++){const a=t*i+e;this.pressureNext[a]=.25*(this.divergence[a]+this.pressure[a-1]+this.pressure[a+1]+this.pressure[a-i]+this.pressure[a+i])}[this.pressure,this.pressureNext]=[this.pressureNext,this.pressure]}let o=0;for(let e=1;e<a-1;e++)for(let a=1;a<i-1;a++){const s=e*i+a;this.u[s]=Math.max(-80,Math.min(80,this.u[s]-.5*(this.pressure[s+1]-this.pressure[s-1]))),this.v[s]=Math.max(-80,Math.min(80,this.v[s]-.5*(this.pressure[s+i]-this.pressure[s-i]))),this.driftX[s]+=(3.6*this.u[s]-58*this.offsetX[s]-12*this.driftX[s])*t,this.driftY[s]+=(3.6*this.v[s]-58*this.offsetY[s]-12*this.driftY[s])*t,this.offsetX[s]=Math.max(-2,Math.min(2,this.offsetX[s]+this.driftX[s]*t)),this.offsetY[s]=Math.max(-2,Math.min(2,this.offsetY[s]+this.driftY[s]*t)),this.signal[s]=1-Math.exp(.06*-Math.hypot(this.u[s],this.v[s])-.16*this.ink[s]),o=Math.max(o,this.signal[s])}this.peak=o}if(this.active)for(let t=0;t<this.ink.length;t++){const e=Math.round(65535*Math.min(1,this.signal[t]));this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e,this.pixels[4*t+2]=Math.round(128+63.5*this.offsetX[t]),this.pixels[4*t+3]=Math.round(128+63.5*this.offsetY[t])}else this.clear()}};function B(t,e){const i=Math.max(0,Math.min(1,e/.38));return t+(1-2*t)*(i*i*(3-2*i))}var _=(t,e)=>"water"===t?30*e/.55:"silk"===t?28*e:"vortex"===t?38*e:["magnetic","scatter","elastic","rake"].includes(t)?32*e:0,z=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]=D(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 O(this.columns,this.rows),this.contour=new U(this.columns,this.rows),this.afterimage=new Y(this.columns,this.rows),this.clear()}get invertsDensity(){return"trail"===this.mode}get densityTrail(){return["trail","contour","dissolve","etch"].includes(this.mode)}get hasRefraction(){return this.active||this.lensStrength>15e-5}get active(){return N(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,N(t)&&this.afterimage.setMode(t),this.refraction.pixels="trail"===t?this.trail.pixels:"contour"===t?this.contour.pixels:N(t)?this.afterimage.pixels:this.waterPixels,this.refraction.strength=_(t,this.amount))}configure(t,e=.55,i=.2,a=!1){this.setMode(t),this.refraction.edgeSafe=a,this.afterimage.edgeSafe=a,this.amount=Number.isFinite(e)?Math.max(0,Math.min(1,e)):.55,this.radius=Number.isFinite(i)?Math.max(.1,Math.min(1,i)):.2,this.refraction.strength=_(t,this.amount),this.refraction.focus[2]=this.densityTrail?this.amount:this.lensStrength*this.amount,this.refraction.focus[3]=this.radius}move(t,e,i){if("none"===this.mode||0===this.amount)return;if(!Number.isFinite(t+e))return;if(t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e)),N(this.mode))return void this.afterimage.move(t,e,this.radius);if("contour"===this.mode)return void this.contour.move(t,e,this.radius);if("trail"===this.mode)return void this.trail.move(t,e,this.radius,i);if("water"!==this.mode)return!this.previous&&this.lensStrength<.001&&(this.lensX=t,this.lensY=e),this.previous={x:t,y:e},void(this.pending=!0);if(!this.previous)return void(this.previous={x:t,y:e});const a=this.previous;this.previous={x:t,y:e};const s=(t-a.x)*this.xScale,r=(e-a.y)*this.yScale,o=Math.hypot(s,r);if(o<1e-5)return;const n=.035+.1*this.radius,h=3*n,l=Math.min(192,Math.max(1,Math.ceil(o/(.5*n)))),c=95*Math.min(o,1)/l;for(let i=0;i<l;i++){const s=(i+.5)/l,r=a.x+(t-a.x)*s,o=a.y+(e-a.y)*s,m=Math.max(1,Math.floor((r-h/this.xScale)*(this.columns-1))),f=Math.min(this.columns-2,Math.ceil((r+h/this.xScale)*(this.columns-1))),d=Math.max(1,Math.floor((o-h/this.yScale)*(this.rows-1))),u=Math.min(this.rows-2,Math.ceil((o+h/this.yScale)*(this.rows-1)));for(let t=d;t<=u;t++)for(let e=m;e<=f;e++){const i=(e/(this.columns-1)-r)*this.xScale,a=(t/(this.rows-1)-o)*this.yScale,s=Math.exp(-(i*i+a*a)/(n*n))*c,h=t*this.columns+e;this.velocity[h]=Math.max(-12,this.velocity[h]-s)}}this.pending=!0}leave(){this.afterimage.leave(),this.contour.leave(),this.trail.leave(),this.previous=null,"water"!==this.mode&&this.lensStrength&&(this.pending=!0)}clear(){this.trail.clear(),this.contour.clear(),this.afterimage.clear(),this.heights.fill(0),this.velocity.fill(0),this.next.fill(0),this.normals.fill(0),this.refraction.focus[2]=0,this.previous=null,this.lensStrength=0,this.energy=0,this.pending=!1,this.remainder=0;for(let t=0;t<this.waterPixels.length;t+=4)this.waterPixels[t]=this.waterPixels[t+2]=128,this.waterPixels[t+1]=this.waterPixels[t+3]=0}step(t){if(!this.active||!Number.isFinite(t))return;if(N(this.mode))return void this.afterimage.step(t);if("contour"===this.mode)return void this.contour.step(t);if("trail"===this.mode)return void this.trail.step(t);if("water"!==this.mode)return void this.stepLight(Math.max(0,Math.min(.05,t)));this.remainder+=Math.max(0,Math.min(.05,t));const e=1/120,i=Math.exp(-3.8*e),a=.3*Math.min(this.columns,this.rows);for(;this.remainder+1e-8>=e;){this.remainder-=e;let t=0;for(let s=1;s<this.rows-1;s++)for(let r=1;r<this.columns-1;r++){const o=s*this.columns+r,n=this.heights[o],h=this.heights[o-1]+this.heights[o+1]+this.heights[o-this.columns]+this.heights[o+this.columns]-4*n,l=Math.min(r,s,this.columns-1-r,this.rows-1-s),c=l<5?.88+.024*l:1,m=(this.velocity[o]+(h*a*a-8*n)*e)*i*c;this.velocity[o]=m,this.next[o]=(n+m*e)*c,t=Math.max(t,Math.abs(this.next[o]),.1*Math.abs(m))}this.heights.set(this.next),this.energy=t,this.pending=!1}if(!this.active)return void this.clear();const s=.18*Math.min(this.columns,this.rows);for(let t=0;t<this.rows;t++)for(let e=0;e<this.columns;e++){const i=t*this.columns+e,a=(this.heights[t*this.columns+Math.max(0,e-1)]-this.heights[t*this.columns+Math.min(this.columns-1,e+1)])*s,r=(this.heights[Math.max(0,t-1)*this.columns+e]-this.heights[Math.min(this.rows-1,t+1)*this.columns+e])*s,o=Math.tanh(a)*(this.refraction.edgeSafe?this.edgeMask[i]:1),n=Math.tanh(r)*(this.refraction.edgeSafe?this.edgeMask[i]:1);this.normals[2*i]=o,this.normals[2*i+1]=n;const h=Math.round(32767*o+32768),l=Math.round(32767*n+32768);this.refraction.pixels[4*i]=h>>>8,this.refraction.pixels[4*i+1]=255&h,this.refraction.pixels[4*i+2]=l>>>8,this.refraction.pixels[4*i+3]=255&l}}stepLight(t){const e=this.previous,i=1-Math.exp(-30*t),a=1-Math.exp(-12*t);e&&(this.lensX+=(e.x-this.lensX)*i,this.lensY+=(e.y-this.lensY)*i),this.lensStrength+=((e?1:0)-this.lensStrength)*a,this.energy=Math.max(e?Math.abs(e.x-this.lensX)+Math.abs(e.y-this.lensY):0,Math.abs((e?1:0)-this.lensStrength)),this.pending=!1,e||this.active?this.refraction.focus=[this.lensX,this.lensY,this.lensStrength*this.amount,this.radius]:this.clear()}sample(t,e,i){if(N(this.mode))return this.afterimage.sample(t,e,i),i[0]*=this.amount,i[1]*=this.amount,void(i[2]*=this.amount);if("contour"===this.mode)return i[0]=i[1]=0,void(i[2]=this.contour.sample(t,e)*this.amount*3);if("trail"===this.mode)return i[0]=i[1]=0,void(i[2]=this.trail.sample(t,e)*this.amount*3);const a=Math.max(0,Math.min(this.columns-1.001,t*(this.columns-1))),s=Math.max(0,Math.min(this.rows-1.001,e*(this.rows-1))),r=Math.floor(a),o=Math.floor(s),n=a-r,h=s-o,l=2*(o*this.columns+r),c=l+2*this.columns;for(let t=0;t<2;t++)i[t]=.08*((this.normals[l+t]*(1-n)+this.normals[l+2+t]*n)*(1-h)+(this.normals[c+t]*(1-n)+this.normals[c+2+t]*n)*h);i[0]*=this.amount/.55,i[1]*=this.amount/.55,i[2]="light"===this.mode||"scan"===this.mode?function(t,e,i,a){const[s,r,o,n]=i.focus,h=(t-s)*Math.max(1,a)/n,l=(e-r)*Math.max(1,1/a)/n;return"light"===i.mode?Math.exp(-3*(h*h+l*l))*o:"scan"===i.mode?(1.3*Math.exp(-h*h*110)-.3*Math.exp(-h*h*12))*Math.exp(-l*l*1.8)*o:0}(t,e,this.refraction,this.xScale/this.yScale):0}};function W(t){return"videoWidth"in t?[t.videoWidth,t.videoHeight]:"naturalWidth"in t?[t.naturalWidth,t.naturalHeight]:[t.width,t.height]}var q=(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}},G=(t,e,i)=>{t.width===e&&t.height===i||(t.width=e,t.height=i)},j={blocks:" ░▒▓█",braille:" ⠁⠃⠇⡇⣇⣧⣷⣿",lines:" -═╪╬",cross:" ·+xX#",diagonal:" /╱╳",diamond:" ·◇◈◆",mixed:" .:+/◇#@"};function V(t,e={},i={}){const a=t.getContext("2d");if(!a)throw new Error("Canvas is already owned by another renderer.");const s=q(),r=q(!0),h=q(),l=q(),c=q(),f=q(),d=q(),u=q(),g=q(),p=q();let x,v=0,w=M(e),y=0,S="",E="",A="",T=new Uint8ClampedArray(0),D=new Uint8ClampedArray(0),N=0,Y=0,U=0,O=null,_="",V=new z,H=0;const $=[0,0,0],K=[0,0,0,1],Q=[0,0,0,0],J=Math.max(64,Math.min(4096,Number.isFinite(i.maxDimension)?i.maxDimension:960)),Z=Math.max(256,Math.min(1048576,Number.isFinite(i.maxCells)?i.maxCells:12e3));let tt=Z,et=Math.max(.1,Math.min(8,i.pixelRatio??1));return{canvas:t,render:function(e,i=0,M=960,q=540,Z=i*w.motion.speed){if(Number.isFinite(i)||(i=0),!Number.isFinite(M)||!Number.isFinite(q)||M<1||q<1)throw new Error("Render dimensions must be positive finite numbers.");const[it,at]=W(e);if(!it||!at)return;const st=Math.min(1,J/Math.max(M,q)),rt=Math.max(2,Math.round(M*st)),ot=Math.max(2,Math.round(q*st));G(t,rt,ot),G(s.canvas,rt,ot),G(h.canvas,rt,ot),G(l.canvas,rt,ot),G(c.canvas,rt,ot),H!==rt/ot&&(H=rt/ot,V=new z(H)),V.configure(w.hover.effect,w.hover.strength,w.hover.radius,w.hover.edgeSafe),V.step(Math.max(0,Math.min(.05,i-U))),U=i;const nt="currentTime"in e?e.getVideoPlaybackQuality?.().totalVideoFrames??e.currentTime:0,ht=[y,rt,ot,nt].join(":"),lt="dither"===w.style,ct=k(rt,ot,w,tt,et),mt=ct.cell,ft=ct.rowHeight,dt=ct.columns,ut=ct.rows;if(S!==ht||O!==e||N!==dt||Y!==ut){O=e,S=ht,E="",A="",N=dt,Y=ut,s.ctx.clearRect(0,0,rt,ot),s.ctx.save();const t=b(it,at,rt,ot,w.crop);s.ctx.translate(t.x+t.width/2,t.y+t.height/2),s.ctx.rotate(w.crop.rotation*Math.PI/180),s.ctx.drawImage(e,-it*t.scale/2,-at*t.scale/2,it*t.scale,at*t.scale),s.ctx.restore(),G(r.canvas,N,Y),r.ctx.clearRect(0,0,N,Y),r.ctx.drawImage(s.canvas,0,0,N,Y),T=r.ctx.getImageData(0,0,N,Y).data;const i=w.color;for(let t=0;t<T.length;t+=4){const e=.299*T[t]+.587*T[t+1]+.114*T[t+2];for(let a=0;a<3;a++){const s=e+(T[t+a]-e)*i.saturation;T[t+a]=((s*(1-i.grayscale)+e*i.grayscale)/255-.5)*i.contrast*255+127.5+255*i.brightness}}}const gt=I(w),pt=P(w),Mt=!V.active&&!gt&&!pt,xt=[ht,N,Y,mt,ft,et].join(":");if(!Mt||A!==xt){h.ctx.clearRect(0,0,rt,ot),h.ctx.globalAlpha=1,h.ctx.globalCompositeOperation="source-over";const t=Z,e=gt?w.motion.type:"none",a=["none","caustics","sheen","grain","trace"].includes(e);if(lt){const a=Mt;if(!a||E!==ht){D.length!==T.length&&(D=new Uint8ClampedArray(T.length));const s=D;if(s.set(T),V.active||"none"!==e)for(let i=0;i<Y;i++)for(let a=0;a<N;a++){const r=a/N,h=i/Y;let l=a,c=i,m=0,f=1,d=1;V.active&&(V.sample(r,h,$),l-=$[0]*N,c-=$[1]*Y,m=$[2]/3);const u=4*(i*N+a);o(e,r,h,t,K,(.299*T[u]+.587*T[u+1]+.114*T[u+2])/255),n(K,w.motion.amount??1),l-=K[0]/960*N,c-=K[1]/960*Y,f=1+K[2],d=K[3],l=Math.max(0,Math.min(N-1,l)),c=Math.max(0,Math.min(Y-1,c));const g=Math.floor(l),p=Math.floor(c),M=l-g,x=c-p,v=4*(i*N+a),b=4*(p*N+g),y=4*(p*N+Math.min(N-1,g+1)),k=4*(Math.min(Y-1,p+1)*N+g),S=4*(Math.min(Y-1,p+1)*N+Math.min(N-1,g+1));for(let t=0;t<3;t++){const e=((T[b+t]*(1-M)+T[y+t]*M)*(1-x)+(T[k+t]*(1-M)+T[S+t]*M)*x)/255;let i=(["trail","contour"].includes(w.hover.effect)?B(e,m):"etch"===w.hover.effect?Math.max(0,Math.min(1,e+.35*m)):"dissolve"===w.hover.effect?e*Math.max(0,1+m):e)*f;s[v+t]=255*i}s[v+3]=T[b+3]*d}!function(t,e,i,a,s=0){const{algorithm:r,amount:o,threshold:n}=a,h=r.startsWith("bayer")?Number(r.slice(5)):0,l=C.get(h),c=h-1,f="luminance"===a.colorSpace,d=("custom"===a.palette?a.colors:m[a.palette]??m.mono).map(X),u=L[r],g=u?new Float32Array(3*e*3):null,p="drift"===a.motion?s*a.speed*3:0,M=(a.direction??45)*Math.PI/180,x=Math.round(Math.cos(M)*p),v=Math.round(Math.sin(M)*p),b=(t,e)=>(t%e+e)%e,w=d.map(t=>.299*t[0]+.587*t[1]+.114*t[2]),y="shimmer"===a.motion?.15*Math.sin(s*a.speed*2):0;for(let a=0;a<i;a++)for(let s=0;s<e;s++){const m=4*(a*e+s),M=3*(a%3*e+s);if(0===t[m+3]){g&&(g[M]=g[M+1]=g[M+2]=0);continue}let k=0;l?k=l[(a-v&c)*h+(s-x&c)]:"noise"===r?k=R(s-x,a-v)-.5:"lines"===r?k=b(a-v,4)/3-.5:"vertical-lines"===r?k=b(s-x,4)/3-.5:"diagonal-lines"===r?k=b(s-x+a-v,4)/3-.5:"radial"===r?k=b(Math.hypot(s-e/2,a-i/2)-p,6)/6-.5:"halftone"===r&&(k=Math.hypot(b(s-x,6)-2.5,b(a-v,6)-2.5)/3.54-.5);const S=128*(k*o+y+(.5-n)),E=t[m]+S+(g?.[M]??0),A=t[m+1]+S+(g?.[M+1]??0),F=t[m+2]+S+(g?.[M+2]??0);let T=0,P=0,I=0;if(d.length){let t=1/0;const e=.299*E+.587*A+.114*F;for(let i=0;i<d.length;i++){const a=d[i],s=f?(e-w[i])**2:(E-a[0])**2*.299+(A-a[1])**2*.587+(F-a[2])**2*.114;s<t&&(t=s,[T,P,I]=a)}}else T=51*Math.round(E/51),P=51*Math.round(A/51),I=51*Math.round(F/51);if(t[m]=T,t[m+1]=P,t[m+2]=I,g&&u){g[M]=g[M+1]=g[M+2]=0;for(const[t,r,n]of u){const h=s+t;if(h<0||h>=e||a+r>=i)continue;const l=3*((a+r)%3*e+h);g[l]+=(E-T)*n*o,g[l+1]+=(A-P)*n*o,g[l+2]+=(F-I)*n*o}}}}(s,N,Y,w.dither,i),r.ctx.putImageData(new ImageData(s,N,Y),0,0),E=a?ht:""}h.ctx.imageSmoothingEnabled=!1,h.ctx.drawImage(r.canvas,0,0,rt,ot)}else{const i=Array.from(j[w.style]??w.charset),s=h.ctx,r=X(w.ink),l="ascii"===w.style||!!j[w.style],c=Math.max(3,Math.round(.92*ft)),m=Math.ceil(mt+4),f=Math.ceil(ft+4),u=[i.join(""),c,m,f,w.ink,w.colorMode].join(":");if(l&&u!==_&&(_=u,G(d.canvas,m*i.length,f),d.ctx.clearRect(0,0,d.canvas.width,f),d.ctx.font=`${c}px monospace`,d.ctx.textBaseline="middle",d.ctx.textAlign="center",d.ctx.fillStyle="accent"===w.colorMode?w.ink:"#ffffff",i.forEach((t,e)=>d.ctx.fillText(t,e*m+m/2,f/2))),"lego"===w.style&&v!==mt){v=mt,G(p.canvas,Math.ceil(mt),Math.ceil(ft));const t=p.ctx;t.clearRect(0,0,p.canvas.width,p.canvas.height),t.fillStyle="rgba(255,255,255,.2)",t.strokeStyle="rgba(0,0,0,.25)",t.lineWidth=Math.max(.5,.6*et),t.beginPath(),t.arc(mt/2,ft/2,.28*mt,0,2*Math.PI),t.fill(),t.stroke()}s.font=`${c}px monospace`,s.textBaseline="middle",s.textAlign="center";for(let h=0;h<Y;h++)for(let c=0;c<N;c++){let u=c,g=h,M=0;if(V.active&&(V.sample(c/N,h/Y,$),u=Math.max(0,Math.min(N-1,c-$[0]*N)),g=Math.max(0,Math.min(Y-1,h-$[1]*Y)),M=$[2]/3),F(T,N,Y,u,g,Q),!Q[3])continue;const x=Q[0],v=Q[1],b=Q[2],y=(.299*x+.587*v+.114*b)/255;let k=y;["trail","contour"].includes(w.hover.effect)&&M?k=B(k,M):"etch"===w.hover.effect?k=Math.max(0,Math.min(1,k+.35*M)):"dissolve"===w.hover.effect&&(k*=Math.max(0,1+M));let S=c*mt,E=h*ft,A=1;o(e,c/N,h/Y,t,K,y),n(K,w.motion.amount??1),S+=K[0]*rt/960,E+=K[1]*ot/960,k=Math.max(0,Math.min(1,k+K[2])),A=K[3]*Q[3]/255,l||"accent"!==w.colorMode||"cmyk"===w.style||(A*=k),s.globalAlpha=A;const P=255*(k-y),I="source"===w.colorMode?`rgb(${x+P},${v+P},${b+P})`:"gray"===w.colorMode?`rgb(${Math.round(255*k)},${Math.round(255*k)},${Math.round(255*k)})`:w.ink;if(s.fillStyle=I,l){const t=Math.max(0,Math.min(i.length-1,Math.round(k*(i.length-1))));"accent"===w.colorMode?s.drawImage(d.canvas,t*m,0,m,f,a?Math.round(S+(mt-m)/2):S+(mt-m)/2,a?Math.round(E+(ft-f)/2):E+(ft-f)/2,m,f):s.fillText(i[t],S+mt/2,E+ft/2)}else if("dots"===w.style)s.beginPath(),s.arc(S+mt/2,E+ft/2,.48*mt*Math.sqrt(k),0,2*Math.PI),s.fill();else if("led"===w.style)s.beginPath(),s.arc(S+mt/2,E+ft/2,.39*mt,0,2*Math.PI),s.fill(),s.globalAlpha=.35*A,s.fillStyle="#ffffff",s.beginPath(),s.arc(S+.43*mt,E+.4*ft,.11*mt,0,2*Math.PI),s.fill();else if("hex"===w.style){const t=S+mt/2,e=E+ft/2;s.beginPath();for(let i=0;i<6;i++){const a=Math.PI/3*i,r=t+Math.cos(a)*mt*.49,o=e+Math.sin(a)*ft*.49;0===i?s.moveTo(r,o):s.lineTo(r,o)}s.closePath(),s.fill()}else if("cmyk"===w.style){s.fillStyle="#ffffff",s.fillRect(S,E,mt,ft);const t=(t,e)=>Math.max(0,Math.min(255,"source"===w.colorMode?t+P:"gray"===w.colorMode?255*k:e*k)),e=t(x,r[0]),i=t(v,r[1]),a=t(b,r[2]),o=1-Math.max(e,i,a)/255,n=Math.max(.001,1-o),h=[["#00ffff",(1-e/255-o)/n,.36,.36],["#ff00ff",(1-i/255-o)/n,.64,.36],["#ffff00",(1-a/255-o)/n,.5,.66],["#000000",o,.5,.5]];s.globalCompositeOperation="multiply";for(const[t,e,i,a]of h)s.fillStyle=t,s.beginPath(),s.arc(S+mt*i,E+ft*a,.48*mt*Math.sqrt(Math.max(0,e)),0,2*Math.PI),s.fill();s.globalCompositeOperation="source-over"}else if("voxel"===w.style){const t=S+mt/2,e=E+ft/2;s.beginPath(),s.moveTo(t,E),s.lineTo(S+mt,E+.25*ft),s.lineTo(t,e),s.lineTo(S,E+.25*ft),s.closePath(),s.fill(),s.globalAlpha=.72*A,s.beginPath(),s.moveTo(S,E+.25*ft),s.lineTo(t,e),s.lineTo(t,E+ft),s.lineTo(S,E+.75*ft),s.closePath(),s.fill(),s.globalAlpha=.42*A,s.beginPath(),s.moveTo(t,e),s.lineTo(S+mt,E+.25*ft),s.lineTo(S+mt,E+.75*ft),s.lineTo(t,E+ft),s.closePath(),s.fill()}else{const t="pixel"===w.style?0:Math.max(.5,.06*mt);s.fillRect(S,E,mt-t,ft-t),"lego"===w.style&&s.drawImage(p.canvas,S,E),"disco"===w.style&&(s.fillStyle=`rgba(255,255,255,${.1+.25*R(c,h)})`,s.fillRect(S,E,mt-t,.35*ft),s.fillStyle="rgba(0,0,0,.25)",s.fillRect(S,E+.65*ft,mt-t,.35*ft-t))}}}h.ctx.globalAlpha=1,(w.color.amount||w.lights.length)&&(G(u.canvas,rt,ot),u.ctx.clearRect(0,0,rt,ot),u.ctx.drawImage(h.canvas,0,0)),w.color.amount&&(h.ctx.save(),h.ctx.globalCompositeOperation=w.color.blend,h.ctx.globalAlpha=w.color.amount,h.ctx.fillStyle=w.color.tint,h.ctx.fillRect(0,0,rt,ot),h.ctx.restore());for(const t of w.lights){const e=t.radius*Math.max(rt,ot),i=h.ctx.createRadialGradient(t.x*rt,t.y*ot,0,t.x*rt,t.y*ot,e);i.addColorStop(0,t.color),i.addColorStop(1,"transparent"),h.ctx.save(),h.ctx.globalCompositeOperation="screen",h.ctx.globalAlpha=t.intensity,h.ctx.fillStyle=i,h.ctx.fillRect(0,0,rt,ot),h.ctx.restore()}if((w.color.amount||w.lights.length)&&(h.ctx.globalCompositeOperation="destination-in",h.ctx.drawImage(u.canvas,0,0),h.ctx.globalCompositeOperation="source-over"),w.mask.enabled&&w.mask.shapes.length){const t=c.ctx;t.clearRect(0,0,rt,ot),t.fillStyle="#fff",t.strokeStyle="#fff",t.lineCap="round",t.lineJoin="round";for(const e of w.mask.shapes){if(t.beginPath(),"ellipse"===e.kind)t.ellipse((e.x+e.width/2)*rt,(e.y+e.height/2)*ot,e.width*rt/2,e.height*ot/2,0,0,2*Math.PI);else{if("rectangle"!==e.kind){if(t.lineWidth=(e.size??.05)*rt,1===e.points?.length){t.arc(e.points[0][0]*rt,e.points[0][1]*ot,t.lineWidth/2,0,2*Math.PI),t.fill();continue}e.points?.forEach(([e,i],a)=>a?t.lineTo(e*rt,i*ot):t.moveTo(e*rt,i*ot)),t.stroke();continue}t.rect(e.x*rt,e.y*ot,e.width*rt,e.height*ot)}t.fill()}h.ctx.globalCompositeOperation=w.mask.invert?"destination-out":"destination-in",h.ctx.drawImage(c.canvas,0,0),h.ctx.globalCompositeOperation="source-over"}const M=l.ctx;M.clearRect(0,0,rt,ot),M.globalAlpha=w.backdrop.opacity;const x=w.backdrop;if("solid"===x.mode&&(M.fillStyle=x.color,M.fillRect(0,0,rt,ot)),"gradient"===x.mode){const t=M.createLinearGradient(0,0,rt,ot);t.addColorStop(0,x.color),t.addColorStop(1,x.color2),M.fillStyle=t,M.fillRect(0,0,rt,ot)}if("source"===x.mode&&M.drawImage(s.canvas,0,0),"blurred"===x.mode){const t=Math.max(1,x.blur);G(f.canvas,Math.max(2,Math.round(rt/t)),Math.max(2,Math.round(ot/t))),f.ctx.drawImage(s.canvas,0,0,f.canvas.width,f.canvas.height),M.imageSmoothingEnabled=!0,M.drawImage(f.canvas,0,0,rt,ot)}M.globalAlpha=1,w.effects.characterBloom>0&&(G(g.canvas,Math.max(2,Math.round(rt/3)),Math.max(2,Math.round(ot/3))),g.ctx.clearRect(0,0,g.canvas.width,g.canvas.height),g.ctx.drawImage(h.canvas,0,0,g.canvas.width,g.canvas.height),M.save(),M.globalAlpha=.8*w.effects.characterBloom,M.globalCompositeOperation="screen",M.filter=`blur(${1+4*w.effects.characterBloom}px)`,M.drawImage(g.canvas,0,0,rt,ot),M.restore()),M.drawImage(h.canvas,0,0),A=Mt?xt:""}const vt=Object.entries(w.effects).some(([t,e])=>!["angle","focus","blurType","characterBloom"].includes(t)&&"number"==typeof e&&e>0);a.clearRect(0,0,rt,ot),vt?(void 0===x&&(x=function(){const t=document.createElement("canvas"),e=t.getContext("webgl",{alpha:!0,premultipliedAlpha:!1,antialias:!1,preserveDrawingBuffer:!0});if(!e)return null;const i=[],a=(t,a)=>{const s=e.createShader(t);if(i.push(s),e.shaderSource(s,a),e.compileShader(s),!e.getShaderParameter(s,e.COMPILE_STATUS))throw new Error(e.getShaderInfoLog(s)||"Finish shader failed");return s},s=e.createProgram();if(e.attachShader(s,a(e.VERTEX_SHADER,"attribute vec2 p;varying vec2 uv;void main(){uv=(p+1.)*.5;gl_Position=vec4(p,0.,1.);}")),e.attachShader(s,a(e.FRAGMENT_SHADER,"precision mediump float;varying vec2 uv;uniform sampler2D src;uniform vec2 size;uniform float t,bloom,grain,dust,scanlines,crt,prism,vignette,glitch,pixelate,blur,blurMode,angle,focus,halftone,rgbSplit,sharpen;\n float hash(vec2 p){return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453);}\n vec4 sampleAt(vec2 p){if(min(min(p.x,p.y),min(1.-p.x,1.-p.y))<0.)return vec4(0.);return texture2D(src,vec2(p.x,1.-p.y));}\n void main(){vec2 q=uv,c=q-.5;q=c*(1.+dot(c,c)*crt*.25)+.5;\n if(glitch>0.)q.x+=(hash(vec2(floor(q.y*35.),floor(t*5.)))-.5)*.07*glitch*step(.82,hash(vec2(floor(q.y*35.),floor(t*5.)+3.)));\n if(pixelate>0.){vec2 grid=size/(1.+pixelate*20.);q=(floor(q*grid)+.5)/grid;}\n vec4 base=sampleAt(q);float edge=smoothstep(.12,.65,length(c));\n vec2 shift=vec2((prism*3.*edge+rgbSplit*8.)/size.x,prism*edge/size.y);\n if(prism>0.||rgbSplit>0.)base.rgb=vec3(sampleAt(q+shift).r,base.g,sampleAt(q-shift).b);\n vec2 dir=vec2(cos(angle),sin(angle))/size;float amount=blur;\n if(blurMode>1.5&&blurMode<2.5){dir=normalize(c+vec2(.0001))/size;amount*=length(c)*2.;}\n if(blurMode>2.5)amount*=smoothstep(.05,.5,abs(q.y-focus));\n vec4 blurred=base;\n if(amount>0.){blurred=base*.2;for(int i=1;i<=4;i++){float f=float(i)*amount*.35;vec2 off=dir*f;if(blurMode<.5)off=vec2(cos(float(i)*1.57),sin(float(i)*1.57))*amount/size;blurred+=sampleAt(q+off)*.1+sampleAt(q-off)*.1;}}\n vec3 light=vec3(0.);if(bloom>0.)for(int i=0;i<4;i++){float a=float(i)*1.5708;vec3 s=sampleAt(q+vec2(cos(a),sin(a))*6./size).rgb;light+=max(vec3(0.),s-.35)*.25;}\n vec3 col=blurred.rgb+light*bloom;\n if(sharpen>0.){vec2 px=1./size;vec3 near=sampleAt(q+vec2(px.x,0.)).rgb+sampleAt(q-vec2(px.x,0.)).rgb+sampleAt(q+vec2(0.,px.y)).rgb+sampleAt(q-vec2(0.,px.y)).rgb;col+=(base.rgb*4.-near)*sharpen*.5;}\ncol*=1.-scanlines*.4*(.5+.5*cos(q.y*size.y*3.14159));\n col*=1.-vignette*smoothstep(.15,.72,length(c));\n col+=(hash(floor(q*size)+floor(t*12.))-.5)*grain*.2;\n if(dust>0.)col+=step(1.-dust*.002,hash(floor(q*size*.25)+floor(t*2.)))*.4;\n if(halftone>0.)col*=mix(1.,smoothstep(.1,.65,length(fract(q*size/6.)-.5)),halftone);\n gl_FragColor=vec4(clamp(col,0.,1.),blurred.a);}")),e.linkProgram(s),!e.getProgramParameter(s,e.LINK_STATUS))throw new Error("Finish link failed");e.useProgram(s);const r=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,r),e.bufferData(e.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,1]),e.STATIC_DRAW);const o=e.getAttribLocation(s,"p");e.enableVertexAttribArray(o),e.vertexAttribPointer(o,2,e.FLOAT,!1,0,0);const n=e.createTexture();e.bindTexture(e.TEXTURE_2D,n),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE);const h=["t","bloom","grain","dust","scanlines","crt","prism","rgbSplit","sharpen","vignette","glitch","pixelate","blur","blurMode","angle","focus","halftone"],l=Object.fromEntries(h.map(t=>[t,e.getUniformLocation(s,t)])),c=e.getUniformLocation(s,"size");return{canvas:t,render(i,a,r,o=1){t.width===i.width&&t.height===i.height||(t.width=i.width,t.height=i.height,e.viewport(0,0,t.width,t.height)),e.useProgram(s),e.bindTexture(e.TEXTURE_2D,n),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,i),e.uniform2f(c,t.width/o,t.height/o);for(const t of h)e.uniform1f(l[t],"t"===t?r:"blurMode"===t?["gaussian","directional","radial","progressive"].indexOf(a.blurType):"angle"===t?a.angle*Math.PI/180:a[t]??0);return e.drawArrays(e.TRIANGLE_STRIP,0,4),t},destroy(){e.deleteTexture(n),e.deleteBuffer(r),e.deleteProgram(s),i.forEach(t=>e.deleteShader(t)),t.width=t.height=1,e.getExtension("WEBGL_lose_context")?.loseContext()}}}()),x?a.drawImage(x.render(l.canvas,w.effects,i,et),0,0):a.drawImage(l.canvas,0,0),t.dataset.studioFinish=x?"gpu":"unavailable"):(a.drawImage(l.canvas,0,0),t.dataset.studioFinish="none")},setPixelRatio(t){et=Math.max(.1,Math.min(8,Number.isFinite(t)?t:1))},get pixelRatio(){return et},setBudget(t){tt=Math.max(256,Math.min(Z,Number.isFinite(t)?Math.round(t):Z))},get maxCells(){return tt},configure(t){w=M(t),y++},pointer:(t,e,i)=>{V.configure(w.hover.effect,w.hover.strength,w.hover.radius,w.hover.edgeSafe),V.move(t,e,i)},leave(){V.leave()},get active(){return V.active},get settings(){return M(w)},get capabilities(){return{gpuFinish:null!==x}},invalidate(){S=""},destroy(){x?.destroy();for(const t of[s,r,h,l,c,f,d,u,g,p])t.canvas.width=t.canvas.height=1;O=null,T=new Uint8ClampedArray(0)}}}function H(t,e,i){return new Promise((a,s)=>{const r=()=>{l(),a()},o=()=>{l(),s(new Error("Unable to load this media. Check its format and cross-origin permissions."))},n=()=>{l(),s(new DOMException("Cancelled","AbortError"))},h=setTimeout(o,2e4),l=()=>{clearTimeout(h),t.removeEventListener(e,r),t.removeEventListener("error",o),i?.removeEventListener("abort",n)};t.addEventListener(e,r,{once:!0}),t.addEventListener("error",o,{once:!0}),i?.addEventListener("abort",n,{once:!0}),i?.aborted&&n()})}async function $(t,e){if("string"==typeof t&&t.startsWith("blob:")){const i=await fetch(t,{signal:e}),a=await i.blob();return $(new File([a],"Imported media",{type:a.type}),e)}const i="string"!=typeof t,a=i?t.name:t;if(i?"image/gif"===t.type:/\.gif(?:[?#]|$)/i.test(a)){const a=await import("gifuct-js"),{parseGIF:s,decompressFrames:r}="function"==typeof a.parseGIF?a:a.default,o=i?await t.arrayBuffer():await fetch(t,{signal:e}).then(t=>{if(!t.ok)throw new Error("GIF download failed.");return t.arrayBuffer()});if(e?.aborted)throw new DOMException("Cancelled","AbortError");const n=s(o),h=n.lsd.width,l=n.lsd.height;if(h*l>4e6)throw new Error("GIF is too large. Use a smaller GIF or an MP4.");const c=n.frames.filter(t=>"image"in t).length;if(!c||c*h*l*4>128e6)throw new Error("GIF exceeds the decoded memory budget. Use MP4 for long animations.");const m=r(n,!0);if(m.length*h*l*4>128e6)throw new Error("GIF exceeds the 128 MB decoded budget. Use MP4 for long animations.");const f=document.createElement("canvas");f.width=h,f.height=l;const d=f.getContext("2d"),u=document.createElement("canvas"),g=u.getContext("2d"),p=m.reduce((t,e)=>t+Math.max(20,e.delay),0)/1e3;let M=-1,x=null;const v=t=>{const e=(t%p+p)%p*1e3;let i=0,a=0;for(;a<m.length-1&&(i+=Math.max(20,m[a].delay),!(e<i));a++);a<M&&(d.clearRect(0,0,h,l),M=-1,x=null);for(let t=M+1;t<=a;t++){const e=m[t-1];2===e?.disposalType&&d.clearRect(e.dims.left,e.dims.top,e.dims.width,e.dims.height),3===e?.disposalType&&x&&d.putImageData(x,0,0);const i=m[t];x=3===i.disposalType?d.getImageData(0,0,h,l):null,u.width=i.dims.width,u.height=i.dims.height,g.putImageData(new ImageData(new Uint8ClampedArray(i.patch),u.width,u.height),0,0),d.drawImage(u,i.dims.left,i.dims.top)}return M=a,f};return v(0),{source:f,width:h,height:l,duration:p,animated:!0,seek:async()=>{},frame:v,destroy(){f.width=u.width=1,m.length=0,x=null}}}const s=i?t.type.startsWith("video/"):/\.(mp4|webm|mov)(?:[?#]|$)/i.test(a),r=i?URL.createObjectURL(t):t,o=s?document.createElement("video"):new Image;o.crossOrigin="anonymous",o instanceof HTMLVideoElement&&(o.muted=!0,o.playsInline=!0,o.preload="auto");const n=()=>{o instanceof HTMLVideoElement?(o.pause(),o.removeAttribute("src"),o.load()):o.src="",i&&URL.revokeObjectURL(r)};try{const t=H(o,s?"loadeddata":"load",e);o.src=r,await t;const i=o instanceof HTMLVideoElement?o.videoWidth:o.naturalWidth,a=o instanceof HTMLVideoElement?o.videoHeight:o.naturalHeight;return{source:o,width:i,height:a,duration:o instanceof HTMLVideoElement?o.duration:0,animated:s,async seek(t,e){if(!(o instanceof HTMLVideoElement))return;if(!Number.isFinite(o.duration)||o.duration<=0)throw new Error("Video duration is unavailable.");const i=Math.max(0,Math.min(o.duration-.001,t%o.duration));if(Math.abs(o.currentTime-i)<.001&&o.readyState>=2)return;const a=H(o,"seeked",e);o.currentTime=i,await a},frame:()=>o,destroy:n}}catch(t){throw n(),t}}var K=t=>{if(t?.aborted)throw new DOMException("Export cancelled","AbortError")};async function Q(t,e,i){const{format:a,signal:s}=i,r=Math.round(i.width),o=Math.round(i.height);if(!Number.isFinite(r)||!Number.isFinite(o)||r<2||o<2||r>4096||o>4096||r*o>16777216)throw new Error("Choose export dimensions between 2 and 4096 pixels.");if(!["png","jpeg","mp4","webm","gif"].includes(a))throw new Error("Unknown export format.");if(void 0!==i.fps&&!Number.isFinite(i.fps))throw new Error("Frames per second must be finite.");const n=Math.max(1,Math.min(60,Math.round(i.fps??24))),h=i.duration??5;if(!Number.isFinite(h)||h<=0||h>60)throw new Error("Choose a duration from 0 to 60 seconds.");const l="png"===a||"jpeg"===a,c=i.time??0;if(!Number.isFinite(c)||c<0)throw new Error("Image time must be a finite non-negative number.");if(void 0!==i.motionTime&&(!Number.isFinite(i.motionTime)||i.motionTime<0))throw new Error("Motion time must be a finite non-negative number.");if(!l&&r*o>8294400)throw new Error("Video exports support up to 3840 × 2160 pixels.");if("gif"===a&&(r*o>921600||h*n>600))throw new Error("GIF export supports up to 1280 × 720 and 600 frames. Use MP4 for larger exports.");if(void 0!==i.referenceWidth&&(!Number.isFinite(i.referenceWidth)||i.referenceWidth<1))throw new Error("Reference width must be a positive number.");if("gif"===a&&n>30)throw new Error("GIF exports support up to 30 fps. Choose MP4 or WebM for higher frame rates.");const m=document.createElement("canvas"),f=V(m,M(e),{maxDimension:4096,maxCells:i.maxCells??12e3,pixelRatio:r/(i.referenceWidth??Math.min(r,960))});let d;try{if(K(s),i.onProgress?.(0),l){if(f.render(await t.frame(c,s),c,r,o,i.motionTime),"unavailable"===m.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");K(s);const e=await new Promise((t,e)=>m.toBlob(i=>i?t(i):e(new Error("Image export failed.")),"png"===a?"image/png":"image/jpeg",i.quality??.92));return i.onProgress?.(1),e}const e=Math.ceil(h*n);if("gif"===a){const a=await import("gifenc"),{GIFEncoder:l,quantize:c,applyPalette:d}="function"==typeof a.GIFEncoder?a:a.default,u=l(),g=m.getContext("2d");for(let a=0;a<e;a++){K(s);const l=a/n;if(f.invalidate(),f.render(await t.frame(l,s),l,r,o),"unavailable"===m.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");const p=g.getImageData(0,0,r,o).data,M=c(p,256),x=d(p,M);u.writeFrame(x,r,o,{palette:M,delay:10*(Math.round(100*Math.min((a+1)/n,h))-Math.round(100*a/n)),repeat:0}),i.onProgress?.((a+1)/e*.98),await new Promise(t=>setTimeout(t,0))}return u.finish(),i.onProgress?.(1),new Blob([new Uint8Array(u.bytes())],{type:"image/gif"})}const{Output:u,Mp4OutputFormat:g,WebMOutputFormat:p,BufferTarget:M,CanvasSource:x,canEncodeVideo:v}=await import("mediabunny"),b="mp4"===a?"avc":"vp9";if(!await v(b,{width:r,height:o}))throw new Error(`${a.toUpperCase()} encoding is unavailable in this browser. Try another format or a current browser with WebCodecs.`);const w=new u({format:"mp4"===a?new g({fastStart:"in-memory"}):new p,target:new M});m.width=r,m.height=o,d=()=>w.cancel();const y=new x(m,{codec:b,bitrate:Math.max(5e5,Math.round(r*o*n*.15))});w.addVideoTrack(y,{frameRate:n}),m.width=r,m.height=o,await w.start();for(let a=0;a<e;a++){K(s);const l=a/n;if(f.invalidate(),f.render(await t.frame(l,s),l,r,o),"unavailable"===m.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");await y.add(l,Math.min(1/n,h-l)),i.onProgress?.((a+1)/e*.98),a%4==0&&await new Promise(t=>setTimeout(t,0))}return y.close(),K(s),await w.finalize(),d=void 0,i.onProgress?.(1),new Blob([w.target.buffer],{type:"mp4"===a?"video/mp4":"video/webm"})}catch(t){throw await(d?.().catch(()=>{})),t}finally{f.destroy(),m.width=m.height=1}}async function J(t,e,i={}){const a=await $(e,i.signal);try{return Z(t,a,i)}catch(t){throw a.destroy(),t}}function Z(t,e,i={}){let a=M(i.settings),s=i.width??e.width,o=i.height??e.height;const n=V(t,a,i),h=new r;let l=0,c=!1,m=!0,f=!1,d=!0,u=0,g=0,p=0,x=0,v=-1,b=!1!==i.adaptive,k=0,S=0,E=0;const A=matchMedia("(prefers-reduced-motion: reduce)"),F=e.source instanceof HTMLVideoElement?e.source:null,T=()=>{c||l||!d||document.hidden||(l=requestAnimationFrame(L))},R=()=>!f&&!A.matches&&d&&!document.hidden,C=()=>{F&&(F.loop=!0,R()?F.play().catch(()=>{f=!0,m=!0,T()}):F.pause()),p=0,m=!0,T()};function L(t){if(l=0,c||!d||document.hidden)return;const r=R();r&&(u+=p?Math.min(.1,(t-p)/1e3):0),p=t;const M=function(t){return I(t)||P(t)||t.effects.grain>0||t.effects.dust>0||t.effects.glitch>0}(a),y=r&&(e.animated||M),A=F?.getVideoPlaybackQuality?.().totalVideoFrames??-1,C=!F||A<0||A!==v;if(m||n.active||y&&(C||M)&&t-x>=1e3/Math.max(1,Math.min(60,i.fps??60))-.5){const r=performance.now();try{e.animated&&!F&&n.invalidate();const[t,l]=w(s,o,a);g=h.update(u,a.motion.type,a.motion.speed),n.render(e.frame(F?.currentTime??u),u,t,l,g);const c=performance.now()-r;i.onFrame?.(F?.currentTime??u,c),S=S?.9*S+.1*c:c,++k>20&&b&&(y||n.active)&&(E=S>13?E+1:0,E>=12&&n.maxCells>3e3&&(n.setBudget(Math.max(3e3,.8*n.maxCells)),i.onQualityChange?.(n.maxCells),E=0,S=0))}catch(t){f=!0,i.onError?.(t instanceof Error?t:new Error(String(t)))}m=!1,x=t,v=A}r&&(y||n.active)&&T()}const X=e=>{if(!R())return;const i=t.getBoundingClientRect();n.pointer((e.clientX-i.left)/i.width,(e.clientY-i.top)/i.height,e.timeStamp),T()},D=()=>{n.leave(),T()},N=new IntersectionObserver(([t])=>{d=t.isIntersecting,C()});N.observe(t),t.addEventListener("pointermove",X),t.addEventListener("pointerleave",D),t.addEventListener("pointercancel",D),document.addEventListener("visibilitychange",C),A.addEventListener("change",C);const Y=()=>{c||(c=!0,cancelAnimationFrame(l),N.disconnect(),t.removeEventListener("pointermove",X),t.removeEventListener("pointerleave",D),t.removeEventListener("pointercancel",D),document.removeEventListener("visibilitychange",C),A.removeEventListener("change",C),i.signal?.removeEventListener("abort",Y),n.destroy(),e.destroy())};if(i.signal?.addEventListener("abort",Y,{once:!0}),i.signal?.aborted)throw Y(),new DOMException("Cancelled","AbortError");return C(),{canvas:t,media:e,update(t){a=y(a,t),n.configure(a),m=!0,T()},resize(t,e,i){void 0!==i&&n.setPixelRatio(i),s=Math.max(2,t),o=Math.max(2,e),m=!0,T()},pause(t=!0){f=t,C()},async seek(t){u=Math.max(0,t),await e.seek(u),n.invalidate(),m=!0,T()},redraw(){n.invalidate(),m=!0,T()},get time(){return F?.currentTime??u},get motionTime(){return g},get paused(){return f||A.matches},setAdaptive(t){b=t,k=E=S=0},setBudget(t){n.setBudget(t),i.onQualityChange?.(n.maxCells),m=!0,T()},get pixelRatio(){return n.pixelRatio},get maxCells(){return n.maxCells},get capabilities(){return n.capabilities},destroy:Y}}var tt={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")},et=Object.keys(tt);async function it(t,e="Standard",i="#ffffff"){if(!Object.prototype.hasOwnProperty.call(tt,e))throw new Error("Unknown text font.");const{default:a}=await import("figlet/browser"),s=await tt[e]();a.parseFont(e,s.default),a.defaults({fetchFontIfMissing:!1});const r=a.textSync(t.slice(0,120),{font:e}),o=r.split("\n"),n=Math.max(1,...o.map(t=>t.length)),h=Math.max(1,o.length),l=Math.min(1,2048/(9*n)),c=document.createElement("canvas");c.width=Math.ceil(9*n*l+32),c.height=Math.ceil(15*h*l+32);const m=c.getContext("2d");return m.fillStyle="#080808",m.fillRect(0,0,c.width,c.height),m.fillStyle=i,m.font=15*l+"px monospace",m.textBaseline="top",o.forEach((t,e)=>m.fillText(t,16,16+15*e*l)),{canvas:c,ascii:r}}var at={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:" ⠁⠃⠇⡇⣇⣧⣷⣿"}},st=at;export{c as BLEND_MODES,at as CHARACTER_SETS,f as DEFAULT_STUDIO_SETTINGS,l as DITHER_ALGORITHMS,st as STUDIO_CHARACTER_SETS,t as STUDIO_HOVERS,S as STUDIO_LOOKS,e as STUDIO_MOTIONS,m as STUDIO_PALETTES,h as STUDIO_STYLES,et as STUDIO_TEXT_FONTS,V as createStudioRenderer,it as createStudioText,Q as exportStudio,$ as loadStudioMedia,J as mountStudio,Z as mountStudioMedia,M as normalizeStudioSettings,v as parseStudioSettings,A as restyleStudio,x as serializeStudioSettings,b as studioCrop,w as studioDimensions,k as studioGrid,E as studioLook,W as studioSourceSize,y as updateStudioSettings};//# sourceMappingURL=studio.js.map
|
|
1
|
+
var t=[{value:"none",label:"Off",group:"Still",description:"Keep the artwork still under the pointer."},{value:"trail",label:"Trail",group:"Change characters",description:"A fluid wake changes character density and settles behind your cursor."},{value:"dissolve",label:"Dissolve",group:"Change characters",description:"Erase a soft path through the characters; the image gradually reforms."},{value:"contour",label:"Contour",group:"Change characters",description:"Fine tonal rings trace your path without moving the grid."},{value:"etch",label:"Emboss",group:"Change characters",description:"Press a light-and-shadow impression into the characters; the grid stays fixed."},{value:"water",label:"Water",group:"Move the image",description:"Soft ripples refract the image and settle after your stroke."},{value:"silk",label:"Silk",group:"Move the image",description:"Directional folds follow the movement of your hand."},{value:"vortex",label:"Vortex",group:"Move the image",description:"A swirling wake curls through the image."},{value:"magnetic",label:"Magnetic Pull",group:"Move the image",description:"The image gathers toward your stroke, then relaxes."},{value:"scatter",label:"Scatter",group:"Move the image",description:"A textured outward scatter settles behind your cursor."},{value:"elastic",label:"Elastic",group:"Move the image",description:"Push the image with your stroke; it recoils and springs back into place."},{value:"rake",label:"Rake",group:"Move the image",description:"Comb the image into alternating ribbons that glide back into alignment."}],e=[{value:"none",mode:"none",group:"Still",label:"Off",description:"Keep the image still. Hover stays available."},{value:"caustics",mode:"caustics",group:"Light and texture",label:"Caustics",description:"Soft ribbons of light travel across a stationary character grid."},{value:"current",mode:"current",group:"Flow and depth",label:"Slow Current",description:"A gentle flow through the image, with steady edges."},{value:"reform",mode:"reform",group:"Rebuild",label:"Reveal & Reform",description:"Disperse, gather, then hold the complete image."},{value:"sheen",mode:"sheen",group:"Light and texture",label:"Sheen",description:"A broad diagonal light sweep; characters stay anchored."},{value:"tidal",mode:"tidal",group:"Flow and depth",label:"Tidal Rings",description:"Concentric currents travel outward, with protected edges."},{value:"grain",mode:"grain",group:"Light and texture",label:"Living Grain",description:"Slow, individually phased tonal changes on a stationary grid."},{value:"parallax",mode:"parallax",group:"Flow and depth",label:"Parallax",description:"A shallow, continuous drift through the image, with the edges held in place."},{value:"weave",mode:"weave",group:"Flow and depth",label:"Woven Flow",description:"Interlaced bands move in opposing directions, like a flexible printed fabric."},{value:"print",mode:"print",group:"Rebuild",label:"Print Shift",description:"Staggered rows lift, soften and register back into the image."},{value:"trace",mode:"trace",group:"Light and texture",label:"Contour Light",description:"Light follows the source image’s tonal contours; every character stays anchored."}],i=t=>Math.max(0,Math.min(1,t)),a=(t,e,a)=>{const s=i((a-t)/(e-t));return s*s*(3-2*s)},s=(t,e)=>{const i=(.06711056*t+.00583715*e)%1*52.9829189;return i-Math.floor(i)},r=class{constructor(){this.last=null,this.mode="none",this.phase=0}update(t,e,i=1){return Number.isFinite(t)?((e!==this.mode||null!==this.last&&t<this.last)&&(this.mode=e,this.phase=0,this.last=t),null!==this.last&&(this.phase+=Math.max(0,t-this.last)*Math.max(.1,Math.min(3,Number.isFinite(i)?i:1))),this.last=t,this.phase):this.phase}};function o(t,e,r,o,n,h=.5){if(n[0]=n[1]=n[2]=0,n[3]=1,"none"===t)return n;const l=o*Math.PI/6,c=a(0,.12,Math.min(e,1-e,r,1-r));if("caustics"===t){const t=Math.sin(9*e+5*r+l)+Math.sin(8*r-3*e-l),i=Math.pow(Math.max(0,1-.72*Math.abs(t)),3);n[2]=(.22*i-.045)*c}else if("current"===t)n[0]=Math.sin(9*r+l)*Math.cos(7*e-l)*10*c,n[1]=Math.cos(8*e+l)*Math.sin(6*r-l)*7*c;else if("sheen"===t)n[2]=.2*Math.pow(.5+.5*Math.cos(5*e+3*r-l),8)-.025;else if("tidal"===t){const t=e-.5,i=r-.5,a=Math.hypot(t,i),s=Math.sin(22*a-l)*c;n[0]=t*s*9,n[1]=i*s*9,n[2]=.035*s}else if("grain"===t){const t=s(Math.floor(160*e),Math.floor(100*r))*Math.PI*2;n[2]=.07*Math.sin(l+t)}else if("parallax"===t){const t=.45+.55*Math.max(0,1-1.4*Math.hypot(e-.5,r-.5));n[0]=12*Math.sin(l)*t*c,n[1]=6*(Math.cos(l)-1)*t*c}else if("weave"===t)n[0]=Math.sin(r*Math.PI*6+l)*Math.sin(l)*8*c,n[1]=Math.sin(e*Math.PI*6-l)*Math.sin(l)*6*c;else if("print"===t){const t=Math.floor(24*r),e=((o+3*s(t,3))%12+12)%12,i=a(1,2.5,e)*(1-a(3.5,5,e));n[0]=Math.sin(2.4*t)*i*9*c,n[1]=5*-i*c,n[2]=.22*-i,n[3]=1-.45*i}else if("trace"===t){const t=.5+.5*Math.cos(l);n[2]=.22*Math.pow(Math.max(0,1-Math.abs(i(h)-t)/.16),3)-.015}else if("reform"===t){const t=(o%12+12)%12,i=s(Math.floor(160*e),Math.floor(100*r)),h=.65*e+.2*r+.15*i+.08*Math.sin(8*e-5*r),m=a(1.8+1.2*h,3.8+1.2*h,t)*(1-a(5+1.7*h,7.2+1.7*h,t));n[0]=Math.sin(9*r+l)*m*(1-m)*24*c,n[1]=-m*(1-m)*(8+12*i)*c,n[2]=.45*-m,n[3]=1-.9*m}return n}function n(t,e){const a=Math.max(0,Math.min(2,Number.isFinite(e)?e:1));return t[0]*=a,t[1]*=a,t[2]*=a,t[3]=i(1+(t[3]-1)*a),t}var h=["rgb","red","green","blue"],l=t=>Math.max(0,Math.min(1,t));function c(t){const e=new Map([[0,0],[1,1]]);if(Array.isArray(t))for(const i of t.slice(0,64)){if(!Array.isArray(i)||i.length<2||"number"!=typeof i[0]||!Number.isFinite(i[0])||"number"!=typeof i[1]||!Number.isFinite(i[1]))continue;const t=Math.round(255*l(i[0]))/255;!e.has(t)&&e.size>=16||e.set(t,l(i[1]))}return[...e].sort((t,e)=>t[0]-e[0])}function m(t){const e=t&&"object"==typeof t?t:{};return Object.fromEntries(h.map(t=>[t,c(e[t])]))}function f(t){const e=c(t),i=e.length,a=e.slice(1).map((t,i)=>t[0]-e[i][0]),s=e.slice(1).map((t,i)=>(t[1]-e[i][1])/a[i]),r=new Float64Array(i);r[0]=s[0],r[i-1]=s[i-2];for(let t=1;t<i-1;t++){const e=s[t-1],i=s[t];if(e*i<=0)continue;const o=2*a[t]+a[t-1],n=a[t]+2*a[t-1];r[t]=(o+n)/(o/e+n/i)}const o=new Uint8Array(256);let n=0;for(let t=0;t<256;t++){const s=t/255;for(;n<i-2&&s>e[n+1][0];)n++;const h=a[n],c=(s-e[n][0])/h,m=c*c,f=m*c,d=(2*f-3*m+1)*e[n][1]+(f-2*m+c)*h*r[n]+(-2*f+3*m)*e[n+1][1]+(f-m)*h*r[n+1];o[t]=Math.round(255*l(d))}return o}var d=["ascii","blocks","braille","dots","lines","cross","diagonal","diamond","mixed","pixel","mosaic","lego","voxel","disco","dither","hex","led","cmyk"],u=["none","bayer2","bayer4","bayer8","bayer16","floyd-steinberg","atkinson","stucki","sierra","sierra-lite","burkes","jarvis","halftone","lines","noise","vertical-lines","diagonal-lines","radial","blue-noise"],g=["source-over","multiply","screen","overlay","soft-light","hard-light","color-dodge","color-burn","hue","saturation","color","luminosity"],p={original:[],gray4:["#000000","#555555","#aaaaaa","#ffffff"],gray8:["#000000","#242424","#494949","#6d6d6d","#929292","#b6b6b6","#dbdbdb","#ffffff"],rgb8:["#000000","#ff0000","#00ff00","#0000ff","#ffff00","#ff00ff","#00ffff","#ffffff"],cyberpunk:["#08081a","#3c1670","#ed299a","#29dfef","#fff7bf"],pastel:["#393448","#a5b4d4","#9ed9c6","#e7aac1","#f5e8be"],mono:["#080808","#f2f2e8"],asciify:["#080808","#625b38","#a19558","#e8b900"],gameboy:["#0f380f","#306230","#8bac0f","#9bbc0f"],cga:["#000000","#55ffff","#ff55ff","#ffffff"],pico8:["#000000","#1d2b53","#7e2553","#008751","#ab5236","#5f574f","#c2c3c7","#fff1e8","#ff004d","#ffa300","#ffec27","#00e436","#29adff","#83769c","#ff77a8","#ffccaa"],c64:["#000000","#ffffff","#880000","#aaffee","#cc44cc","#00cc55","#0000aa","#eeee77","#dd8855","#664400","#ff7777","#333333","#777777","#aaff66","#0088ff","#bbbbbb"],amber:["#100b00","#5f3b00","#c98014","#ffd17c"],ice:["#081b29","#25586e","#69a6b3","#d9ece7"],risograph:["#f4ebd0","#f2594b","#2853a5","#29232e"],sepia:["#201b17","#6b5039","#b49868","#f6e6c5"],nord:["#2e3440","#4c566a","#88c0d0","#eceff4"],dusk:["#211b35","#654271","#c3788c","#f5c9a3"],forest:["#101f1b","#355747","#87a16f","#e4e3ba"],ocean:["#071b33","#17577f","#3fa7a4","#d9efde"],newsprint:["#191919","#666666","#aaaaaa","#eee9df"],custom:["#080808","#e8b900"]},M={version:1,aspectRatio:"original",style:"ascii",cellSize:6,charset:" .:-=+*#%@",colorMode:"accent",ink:"#e8b900",crop:{x:.5,y:.5,zoom:1,rotation:0},backdrop:{mode:"solid",color:"#080808",color2:"#393323",blur:12,opacity:1},color:{brightness:0,contrast:1,saturation:1,grayscale:0,tint:"#e8b900",amount:0,blend:"source-over",blackPoint:0,whitePoint:1,gamma:1,shadows:0,highlights:0,curves:{rgb:[[0,0],[1,1]],red:[[0,0],[1,1]],green:[[0,0],[1,1]],blue:[[0,0],[1,1]]},denoise:0},dither:{algorithm:"none",palette:"mono",colors:["#080808","#e8b900"],amount:1,scale:2,threshold:.5,motion:"none",speed:1,direction:45,colorSpace:"rgb"},mask:{enabled:!1,invert:!1,shapes:[]},lights:[],effects:{bloom:0,characterBloom:0,grain:0,dust:0,scanlines:0,crt:0,prism:0,rgbSplit:0,sharpen:0,vignette:0,glitch:0,pixelate:0,blur:0,blurType:"gaussian",angle:0,focus:.5,halftone:0},motion:{type:"none",speed:1,amount:1},hover:{effect:"trail",strength:.55,radius:.2,edgeSafe:!1}},x=t=>t&&"object"==typeof t&&!Array.isArray(t)?t:{},v=(t,e,i,a)=>"number"==typeof t&&Number.isFinite(t)?Math.min(a,Math.max(i,t)):e,b=(t,e)=>"string"==typeof t&&/^#[\da-f]{6}$/i.test(t)?t:e,w=(t,e,i)=>e.includes(t)?t:i;function y(i={}){const a=x(i),s=M;if(void 0!==a.version&&1!==a.version)throw new Error("Unsupported studio settings version. Update asciify-engine.");const r=x(a.crop),o=x(a.backdrop),n=x(a.color),h=x(a.dither),l=x(a.mask),c=x(a.effects),f=x(a.motion),y=x(a.hover),k={...s.effects};for(const t of["bloom","characterBloom","grain","dust","scanlines","crt","prism","rgbSplit","sharpen","vignette","glitch","pixelate","halftone"])k[t]=v(c[t],0,0,1);k.blur=v(c.blur,0,0,24),k.blurType=w(c.blurType,["gaussian","directional","radial","progressive"],s.effects.blurType),k.angle=v(c.angle,0,-180,180),k.focus=v(c.focus,.5,0,1);let S=2048;return{version:1,aspectRatio:w(a.aspectRatio,["original","16:9","9:16","1:1","4:3","3:4","21:9"],"original"),style:w(a.style,d,s.style),cellSize:v(a.cellSize,s.cellSize,["pixel","mosaic","lego","voxel","disco","dots","hex","led","cmyk"].includes(String(a.style))?1:3,60),charset:"string"==typeof a.charset&&a.charset.length?Array.from(a.charset).slice(0,128).join(""):s.charset,colorMode:w(a.colorMode,["accent","source","gray"],s.colorMode),ink:b(a.ink,s.ink),crop:{x:v(r.x,.5,0,1),y:v(r.y,.5,0,1),zoom:v(r.zoom,1,1,5),rotation:90*Math.round(v(r.rotation,0,-360,360)/90)},backdrop:{mode:w(o.mode,["solid","transparent","source","blurred","gradient"],s.backdrop.mode),color:b(o.color,s.backdrop.color),color2:b(o.color2,s.backdrop.color2),blur:v(o.blur,12,0,32),opacity:v(o.opacity,1,0,1)},color:{brightness:v(n.brightness,0,-1,1),contrast:v(n.contrast,1,0,3),saturation:v(n.saturation,1,0,3),grayscale:v(n.grayscale,0,0,1),tint:b(n.tint,s.color.tint),amount:v(n.amount,0,0,1),blend:w(n.blend,g,s.color.blend),blackPoint:v(n.blackPoint,0,0,.99),whitePoint:Math.max(v(n.blackPoint,0,0,.99)+1/255,v(n.whitePoint,1,1/255,1)),gamma:v(n.gamma,1,.25,4),shadows:v(n.shadows,0,-1,1),highlights:v(n.highlights,0,-1,1),curves:m(n.curves),denoise:v(n.denoise,0,0,1)},dither:{algorithm:w(h.algorithm,u,"none"),palette:"string"==typeof h.palette&&Object.prototype.hasOwnProperty.call(p,h.palette)?h.palette:"mono",colors:Array.isArray(h.colors)&&h.colors.length>=2?h.colors.slice(0,32).map(t=>b(t,"#000000")):[...s.dither.colors],amount:v(h.amount,1,0,2),scale:Math.round(v(h.scale,2,1,12)),threshold:v(h.threshold,.5,0,1),motion:w(h.motion,["none","drift","shimmer"],"none"),speed:v(h.speed,1,.1,3),direction:v(h.direction,45,-180,180),colorSpace:w(h.colorSpace,["rgb","luminance"],"rgb")},mask:{enabled:!0===l.enabled,invert:!0===l.invert,shapes:Array.isArray(l.shapes)?l.shapes.slice(0,64).map(t=>{const e=x(t),i=w(e.kind,["rectangle","ellipse","brush"],"rectangle"),a="brush"===i&&Array.isArray(e.points)?e.points.slice(0,S).map(t=>Array.isArray(t)?[Math.round(1e4*v(t[0],0,0,1))/1e4,Math.round(1e4*v(t[1],0,0,1))/1e4]:[0,0]):[];return S-=a.length,{kind:i,x:v(e.x,0,0,1),y:v(e.y,0,0,1),width:v(e.width,.5,0,1),height:v(e.height,.5,0,1),size:v(e.size,.05,.005,.5),points:a}}):[]},lights:Array.isArray(a.lights)?a.lights.slice(0,4).map(t=>{const e=x(t);return{x:v(e.x,.5,0,1),y:v(e.y,.5,0,1),radius:v(e.radius,.3,.02,1),intensity:v(e.intensity,.5,0,1),color:b(e.color,"#ffffff")}}):[],effects:k,motion:{type:w(f.type,e.map(t=>t.mode),"none"),speed:v(f.speed,1,.1,3),amount:v(f.amount,1,0,2)},hover:{effect:w(y.effect,t.map(t=>t.value),"trail"),strength:v(y.strength,.55,0,1),radius:v(y.radius,.2,.1,1),edgeSafe:!0===y.edgeSafe}}}function k(t){return JSON.stringify(y(t))}function S(t){if(t.length>1e5)throw new Error("Settings exceed 100 KB.");return y(JSON.parse(t))}function A(t,e,i,a,s){const r=Math.abs(s.rotation/90)%2==1,o=r?e:t,n=r?t:e,h=Math.max(i/o,a/n)*s.zoom;return{width:o*h,height:n*h,x:(i-o*h)*s.x,y:(a-n*h)*s.y,scale:h,rotated:r}}function E(t,e,i){if(Math.abs(i.crop.rotation/90)%2==1&&([t,e]=[e,t]),"original"===i.aspectRatio)return[t,e];const[a,s]=i.aspectRatio.split(":").map(Number);return t/e>a/s?[Math.round(e*a/s),e]:[t,Math.round(t*s/a)]}function F(t,e){const i={...t,...e};for(const a of["crop","backdrop","color","dither","mask","effects","motion","hover"])e[a]&&Object.assign(i,{[a]:{...t[a],...e[a]}});return e.color?.curves&&(i.color.curves={...t.color.curves,...e.color.curves}),y(i)}function T(t,e,i,a=12e3,s=1){const r=Math.max(2,Number.isFinite(t)?t:960),o=Math.max(2,Number.isFinite(e)?e:540),n=Math.max(1,Math.floor(Number.isFinite(a)?a:12e3)),h=Math.max(.01,Number.isFinite(s)?s:1),l=["dither","pixel","mosaic","lego","voxel","disco","dots","hex","led","cmyk"].includes(i.style)?1:1.65;let c=Math.max(1,Math.ceil(Math.sqrt(r*o/(n*l))/h));for(;Math.ceil(r/(c*h))*Math.ceil(o/(c*h*l))>n;)c++;const m="dither"===i.style?i.dither.scale:i.cellSize,f=Math.max(c,m)*h;return{cell:f,rowHeight:f*l,columns:Math.ceil(r/f),rows:Math.ceil(o/(f*l)),minimum:c,limited:m<c}}var P=[["ascii","Signature ASCII","Brand ink and clean characters.",{}],["print","Newsprint","Fine diffusion on warm paper.",{style:"dither",dither:{algorithm:"floyd-steinberg",palette:"newsprint"}}],["handheld","Pocket camera","Four-tone ordered dither.",{style:"dither",dither:{algorithm:"bayer4",palette:"gameboy",scale:3}}],["riso","Two inks","Limited-color print texture.",{style:"dither",dither:{algorithm:"atkinson",palette:"risograph",scale:2}}],["night","Night signal","Gray characters and optical fringe.",{ink:"#888888",effects:{prism:.7,scanlines:.2,vignette:.3}}],["terminal","Phosphor","Green glyphs with a soft glow.",{ink:"#83efad",effects:{bloom:.4,scanlines:.35,crt:.2}}],["mosaic","Mosaic study","Separated color tiles.",{style:"mosaic",cellSize:14,colorMode:"source"}],["bricks","Brickwork","Colorful studded cells.",{style:"lego",cellSize:18,colorMode:"source"}],["voxel","Little volumes","Three-face isometric tiles.",{style:"voxel",cellSize:22,colorMode:"source"}],["disco","Mirror room","Faceted tiles and warm light.",{style:"disco",cellSize:18,colorMode:"source",lights:[{x:.35,y:.25,radius:.25,intensity:.45,color:"#fff2d4"}]}],["wallpaper","Wallpaper","Living ASCII over a softened source.",{backdrop:{mode:"blurred",blur:18,opacity:.55},ink:"#f2e9c9",motion:{type:"caustics",speed:.5}}],["blueprint","Blueprint","Linework in a cool monochrome.",{style:"lines",ink:"#9bccdf",backdrop:{mode:"solid",color:"#0a1e30"}}]].map(([t,e,i,a])=>({id:t,name:e,description:i,settings:y(a)}));function I(t){const e=P.find(e=>e.id===t);if(!e)throw new Error("Unknown studio look.");return y(e.settings)}function R(t,e=Math.random){const i=P.filter(e=>e.settings.style!==t.style||e.settings.ink!==t.ink),a=I(i[Math.min(i.length-1,Math.max(0,Math.floor(e()*i.length)))].id);return a.aspectRatio=t.aspectRatio,a.crop={...t.crop},a.mask=y(t).mask,a}function C(t,e,i,a,s,r){a=Math.max(0,Math.min(e-1,a)),s=Math.max(0,Math.min(i-1,s));const o=Math.floor(a),n=Math.floor(s),h=a-o,l=s-n,c=4*(n*e+o);if(0===h&&0===l){for(let e=0;e<4;e++)r[e]=t[c+e];return}const m=4*(n*e+Math.min(e-1,o+1)),f=4*(Math.min(i-1,n+1)*e+o),d=4*(Math.min(i-1,n+1)*e+Math.min(e-1,o+1)),u=(1-h)*(1-l)*t[c+3],g=h*(1-l)*t[m+3],p=(1-h)*l*t[f+3],M=h*l*t[d+3],x=u+g+p+M;for(let e=0;e<3;e++)r[e]=x?(t[c+e]*u+t[m+e]*g+t[f+e]*p+t[d+e]*M)/x:0;r[3]=x}function L(t){const e=function(t){const e=t.blackPoint??0,i=t.whitePoint??1,a=t.gamma??1,s=t.shadows??0,r=t.highlights??0;if(0===e&&1===i&&1===a&&0===s&&0===r)return null;const o=[0,.25+.2*s,.5,.75+.2*r,1],n=o.slice(1).map((t,e)=>4*(t-o[e])),h=[n[0],...n.slice(1).map((t,e)=>2*t*n[e]/(t+n[e])),n[3]],l=new Uint8Array(256);for(let t=0;t<256;t++){const s=Math.pow(Math.max(0,Math.min(1,(t/255-e)/(i-e))),1/a),r=Math.min(3,Math.floor(4*s)),n=4*s-r,c=n*n,m=c*n,f=(2*m-3*c+1)*o[r]+(m-2*c+n)*h[r]/4+(-2*m+3*c)*o[r+1]+(m-c)*h[r+1]/4;l[t]=Math.round(255*Math.max(0,Math.min(1,f)))}return l}(t),i=t.curves;if(!e&&(!i||Object.values(i).every(t=>t.every(([t,e])=>t===e))))return null;const a=f(i?.rgb),s=[i?.red,i?.green,i?.blue].map(f),r=new Uint8Array(768);for(let t=0;t<256;t++)for(let i=0;i<3;i++)r[256*i+t]=s[i][a[e?e[t]:t]];return r}var X=class{constructor(t=0){this.amount=0,this.weights=new Float32Array(256),this.source=new Uint8ClampedArray(0),this.configure(t)}configure(t=0){const e=Math.max(0,Math.min(1,Number.isFinite(t)?t:0));if(e===this.amount)return;if(this.amount=e,0===e)return void(this.source=new Uint8ClampedArray(0));const i=8+24*e;for(let t=0;t<256;t++)this.weights[t]=Math.exp(-t*t/(2*i*i))}apply(t,e,i){if(!this.amount)return;if(!Number.isInteger(e)||!Number.isInteger(i)||e<1||i<1||e*i*4!==t.length)throw new Error("Denoise dimensions do not match the source.");this.source.length!==t.length&&(this.source=new Uint8ClampedArray(t.length));const a=this.source;a.set(t);for(let s=0;s<i;s++)for(let r=0;r<e;r++){const o=4*(s*e+r);if(!a[o+3])continue;const n=a[o],h=a[o+1],l=a[o+2];let c=0,m=0,f=0,d=0;for(let t=-1;t<=1;t++){const o=s+t;if(!(o<0||o>=i))for(let i=-1;i<=1;i++){const s=r+i;if(s<0||s>=e)continue;const u=4*(o*e+s);if(!a[u+3])continue;const g=Math.max(Math.abs(a[u]-n),Math.abs(a[u+1]-h),Math.abs(a[u+2]-l)),p=this.weights[g]*(0===i?1:.6)*(0===t?1:.6)*a[u+3];c+=a[u]*p,m+=a[u+1]*p,f+=a[u+2]*p,d+=p}}t[o]=n+(c/d-n)*this.amount,t[o+1]=h+(m/d-h)*this.amount,t[o+2]=l+(f/d-l)*this.amount}}},N=new Set(["none","floyd-steinberg","atkinson","stucki","sierra","sierra-lite","burkes","jarvis"]);function D(t){return"dither"===t.style&&("shimmer"===t.dither.motion||"drift"===t.dither.motion&&t.dither.amount>0&&!N.has(t.dither.algorithm))}function U(t){return"none"!==t.motion.type&&(t.motion.amount??1)>0}var O="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",Y="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",B=new Uint16Array(4096);for(let t=0;t<B.length;t++)B[t]=O.indexOf(Y[2*t])<<6|O.indexOf(Y[2*t+1]);var z=(t,e)=>{const i=43758.5453*Math.sin(127.1*t+311.7*e);return i-Math.floor(i)};var W=new Map([2,4,8,16].map(t=>[t,Float64Array.from({length:t*t},(e,i)=>function(t,e,i){let a=0;for(let s=1;s<i;s*=2){const i=(Math.floor(t/s)%2+2)%2;a=4*a+[[0,2],[3,1]][(Math.floor(e/s)%2+2)%2][i]}return(a+.5)/(i*i)-.5}(i%t,Math.floor(i/t),t))])),q={"floyd-steinberg":[[1,0,7/16],[-1,1,3/16],[0,1,5/16],[1,1,1/16]],atkinson:[[1,0,.125],[2,0,.125],[-1,1,.125],[0,1,.125],[1,1,.125],[0,2,.125]],stucki:[[1,0,8/42],[2,0,4/42],[-2,1,2/42],[-1,1,4/42],[0,1,8/42],[1,1,4/42],[2,1,2/42],[-2,2,1/42],[-1,2,2/42],[0,2,4/42],[1,2,2/42],[2,2,1/42]],sierra:[[1,0,5/32],[2,0,3/32],[-2,1,2/32],[-1,1,4/32],[0,1,5/32],[1,1,4/32],[2,1,2/32],[-1,2,2/32],[0,2,3/32],[1,2,2/32]],"sierra-lite":[[1,0,.5],[-1,1,.25],[0,1,.25]],burkes:[[1,0,.25],[2,0,4/32],[-2,1,2/32],[-1,1,4/32],[0,1,.25],[1,1,4/32],[2,1,2/32]],jarvis:[[1,0,7/48],[2,0,5/48],[-2,1,3/48],[-1,1,5/48],[0,1,7/48],[1,1,5/48],[2,1,3/48],[-2,2,1/48],[-1,2,3/48],[0,2,5/48],[1,2,3/48],[2,2,1/48]]},G=t=>[parseInt(t.slice(1,3),16),parseInt(t.slice(3,5),16),parseInt(t.slice(5,7),16)];function j(t,e,i){const a=Math.min(t*Math.max(1,i),(1-t)*Math.max(1,i),e*Math.max(1,1/i),(1-e)*Math.max(1,1/i)),s=Math.max(0,Math.min(1,(a-.035)/.105));return s*s*s*(s*(6*s-15)+10)}var V=t=>["dissolve","silk","vortex","magnetic","scatter","etch","elastic","rake"].includes(t),H=class{constructor(t,e){this.edgeSafe=!1,this.previous=null,this.peak=0,this.scatterDirections=null,this.springX=null,this.springY=null,this.mode="dissolve",this.width=t,this.height=e;const i=t*e;this.pixels=new Uint8Array(4*i),this.ink=new Float32Array(i),this.targetX=new Float32Array(i),this.targetY=new Float32Array(i),this.offsetX=new Float32Array(i),this.offsetY=new Float32Array(i),this.edge=new Float32Array(i);for(let i=0;i<e;i++)for(let a=0;a<t;a++)this.edge[i*t+a]=j(a/(t-1),i/(e-1),t/e);this.clear()}get active(){return this.peak>2e-4}setMode(t){if("elastic"!==t||this.springX||(this.springX=new Float32Array(this.ink.length),this.springY=new Float32Array(this.ink.length)),"scatter"===t&&!this.scatterDirections){const t=this.scatterDirections=new Float64Array(this.width*this.height*2);for(let e=0;e<this.height;e++)for(let i=0;i<this.width;i++){const a=43758.5453*Math.sin(127.1*i+311.7*e),s=(a-Math.floor(a))*Math.PI*2,r=2*(e*this.width+i);t[r]=.7*Math.cos(s),t[r+1]=.7*Math.sin(s)}}t!==this.mode&&(this.mode=t,this.clear())}clear(){for(const t of[this.ink,this.targetX,this.targetY,this.offsetX,this.offsetY,this.pixels])t.fill(0);if(this.previous=null,this.peak=0,this.springX?.fill(0),this.springY?.fill(0),"dissolve"!==this.mode)for(let t=0;t<this.pixels.length;t+=4)this.pixels[t]=this.pixels[t+2]=128}leave(){this.previous=null}move(t,e,i){if(!Number.isFinite(t+e+i))return;t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e));const a=this.previous;this.previous={x:t,y:e};const s=this.width,r=this.height,o=Math.max(1,s/r),n=Math.max(1,r/s),h=a?(t-a.x)*o:0,l=a?(e-a.y)*n:0,c=Math.hypot(h,l);if(!a&&"dissolve"!==this.mode&&"etch"!==this.mode)return;if(a&&c<1e-4)return;const m=.035+.11*Math.max(.1,Math.min(1,i)),f=Math.min(128,Math.max(1,Math.ceil(c/(.45*m)))),d=c?h/c:1,u=c?l/c:0,g=Math.min(1,c/(m*f)*2.2);for(let i=0;i<f;i++){const h=(i+.5)/f,l=a?a.x+(t-a.x)*h:t,c=a?a.y+(e-a.y)*h:e,p=Math.max(0,Math.floor((l-2.5*m/o)*(s-1))),M=Math.min(s-1,Math.ceil((l+2.5*m/o)*(s-1))),x=Math.max(0,Math.floor((c-2.5*m/n)*(r-1))),v=Math.min(r-1,Math.ceil((c+2.5*m/n)*(r-1)));for(let t=x;t<=v;t++)for(let e=p;e<=M;e++){const i=(e/(s-1)-l)*o/m,a=(t/(r-1)-c)*n/m,h=Math.exp(1.5*-(i*i+a*a)),f=t*s+e;if("dissolve"===this.mode||"etch"===this.mode)this.ink[f]=Math.max(this.ink[f],h);else if("elastic"===this.mode)this.springX[f]=Math.max(-24,Math.min(24,this.springX[f]+d*h*g*8)),this.springY[f]=Math.max(-24,Math.min(24,this.springY[f]+u*h*g*8));else{const s=(-i*u+a*d)*h*2.8,r="rake"===this.mode?d*Math.sin(t*Math.PI/3)*h*2:"magnetic"===this.mode?-i*h*2.5:"scatter"===this.mode?(i+this.scatterDirections[2*f])*h*2:"silk"===this.mode?d*s:-a*h*2.5,o="rake"===this.mode?u*Math.sin(e*Math.PI/3)*h*2:"magnetic"===this.mode?-a*h*2.5:"scatter"===this.mode?(a+this.scatterDirections[2*f+1])*h*2:"silk"===this.mode?u*s:i*h*2.5;this.targetX[f]=Math.max(-1,Math.min(1,this.targetX[f]+r*g)),this.targetY[f]=Math.max(-1,Math.min(1,this.targetY[f]+o*g))}}}this.peak=1}step(t){if(!this.active||!Number.isFinite(t))return;const e=Math.max(0,Math.min(.05,t)),i=Math.exp(-("dissolve"===this.mode?2.15:3.2)*e),a=1-Math.exp(-22*e);let s=0;const r=Math.sqrt(336),o=Math.exp(-8*e),n=Math.cos(r*e),h=Math.sin(r*e)/r;for(let t=0;t<this.ink.length;t++)if("etch"===this.mode)this.ink[t]*=i,s=Math.max(s,this.ink[t]);else if("dissolve"===this.mode){this.ink[t]*=i,s=Math.max(s,this.ink[t]);const e=Math.round(65535*this.ink[t]);this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e}else{if("elastic"===this.mode){const e=this.offsetX[t],i=this.offsetY[t],a=this.springX[t],r=this.springY[t];this.offsetX[t]=Math.max(-1,Math.min(1,o*(e*n+(a+8*e)*h))),this.offsetY[t]=Math.max(-1,Math.min(1,o*(i*n+(r+8*i)*h))),this.springX[t]=o*(a*n-(8*a+400*e)*h),this.springY[t]=o*(r*n-(8*r+400*i)*h),s=Math.max(s,.05*Math.abs(this.springX[t]),.05*Math.abs(this.springY[t]))}else this.targetX[t]*=i,this.targetY[t]*=i,this.offsetX[t]+=(this.targetX[t]-this.offsetX[t])*a,this.offsetY[t]+=(this.targetY[t]-this.offsetY[t])*a;s=Math.max(s,Math.abs(this.offsetX[t]),Math.abs(this.offsetY[t]),Math.abs(this.targetX[t]),Math.abs(this.targetY[t]));const e=Math.round(this.offsetX[t]*(this.edgeSafe?this.edge[t]:1)*32767+32768),r=Math.round(this.offsetY[t]*(this.edgeSafe?this.edge[t]:1)*32767+32768);this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e,this.pixels[4*t+2]=r>>>8,this.pixels[4*t+3]=255&r}if("etch"===this.mode)for(let t=0;t<this.height;t++)for(let e=0;e<this.width;e++){const i=t*this.width+e,a=3*(this.ink[t*this.width+Math.max(0,e-1)]-this.ink[t*this.width+Math.min(this.width-1,e+1)]+this.ink[Math.max(0,t-1)*this.width+e]-this.ink[Math.min(this.height-1,t+1)*this.width+e]);this.offsetX[i]=Math.max(-1,Math.min(1,a))*(this.edgeSafe?this.edge[i]:1);const s=Math.round(32767*this.offsetX[i]+32768);this.pixels[4*i]=s>>>8,this.pixels[4*i+1]=255&s}this.peak=s,this.active||this.clear()}sample(t,e,i){const a=Math.max(0,Math.min(this.width-1.001,t*(this.width-1))),s=Math.max(0,Math.min(this.height-1.001,e*(this.height-1))),r=Math.floor(a),o=Math.floor(s),n=a-r,h=s-o,l=o*this.width+r,c=l+this.width,m=t=>(t[l]*(1-n)+t[l+1]*n)*(1-h)+(t[c]*(1-n)+t[c+1]*n)*h;if("etch"===this.mode)return i[0]=i[1]=0,void(i[2]=3*m(this.offsetX));i[0]=m(this.offsetX)*(this.edgeSafe?j(t,e,this.width/this.height):1)*.08,i[1]=m(this.offsetY)*(this.edgeSafe?j(t,e,this.width/this.height):1)*.08,i[2]="dissolve"===this.mode?6*-m(this.ink):0}},K=class{constructor(t,e){this.rings=[],this.previous=null,this.elapsed=1,this.echoPeak=0,this.width=t,this.height=e,this.pixels=new Uint8Array(t*e*4),this.echo=new Float32Array(t*e)}get active(){return this.rings.length>0||this.echoPeak>2e-4}clear(){this.rings=[],this.previous=null,this.elapsed=1,this.pixels.fill(0),this.echo.fill(0),this.echoPeak=0}leave(){this.previous=null}move(t,e,i){const a=Math.max(1,this.width/this.height),s=Math.max(1,this.height/this.width);this.previous&&(Math.hypot((t-this.previous.x)*a,(e-this.previous.y)*s)<.065||this.elapsed<.3)||4!==this.rings.length&&(this.previous={x:t,y:e},this.elapsed=0,this.rings.push({x:t,y:e,age:0,radius:i}))}ringSample(t,e){const i=Math.max(1,this.width/this.height),a=Math.max(1,this.height/this.width);let s=0;for(const r of this.rings){const o=.015+r.age*(.15+.22*r.radius),n=.009+.014*r.radius,h=(Math.hypot((t-r.x)*i,(e-r.y)*a)-o)/n,l=Math.sin(Math.min(1,r.age/.07)*Math.PI/2)*Math.max(0,1-r.age/1.35)**2;s=Math.max(s,Math.exp(-h*h)*l)}return s}sample(t,e){const i=Math.max(0,Math.min(this.width-1,Math.round(t*(this.width-1)))),a=Math.max(0,Math.min(this.height-1,Math.round(e*(this.height-1))));return Math.max(this.ringSample(t,e),this.echo[a*this.width+i])}step(t){if(!Number.isFinite(t))return;const e=Math.max(0,Math.min(.05,t));this.elapsed+=e;for(const t of this.rings)t.age+=e;if(this.rings=this.rings.filter(t=>t.age<1.35),!this.active)return void this.pixels.fill(0);const i=Math.exp(-5.5*e);let a=0;for(let t=0;t<this.height;t++)for(let e=0;e<this.width;e++){const s=t*this.width+e;this.echo[s]=Math.max(this.ringSample(e/(this.width-1),t/(this.height-1)),this.echo[s]*i),a=Math.max(a,this.echo[s]);const r=Math.round(65535*this.echo[s]),o=4*s;this.pixels[o]=r>>>8,this.pixels[o+1]=255&r}this.echoPeak=a,this.active||(this.echo.fill(0),this.pixels.fill(0))}},Q=class{constructor(t,e){this.previous=null,this.peak=0,this.width=t,this.height=e;const i=t*e;this.pixels=new Uint8Array(4*i),this.signal=new Float32Array(i),this.offsetX=new Float32Array(i),this.offsetY=new Float32Array(i),this.driftX=new Float32Array(i),this.driftY=new Float32Array(i),this.u=new Float32Array(i),this.v=new Float32Array(i),this.ink=new Float32Array(i),this.a=new Float32Array(i),this.b=new Float32Array(i),this.c=new Float32Array(i),this.pressure=new Float32Array(i),this.pressureNext=new Float32Array(i),this.divergence=new Float32Array(i),this.curl=new Float32Array(i)}get active(){return this.peak>2e-4}clear(){for(const t of[this.u,this.v,this.ink,this.a,this.b,this.c,this.pressure,this.pressureNext,this.divergence,this.curl,this.signal,this.pixels,this.offsetX,this.offsetY,this.driftX,this.driftY])t.fill(0);this.previous=null,this.peak=0}leave(){this.previous=null}move(t,e,i,a=performance.now()){if(!Number.isFinite(t+e+i+a))return;t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e)),i=Math.max(.1,Math.min(1,i));const s=this.previous;if(this.previous={x:t,y:e,time:a},!s)return;const r=(t-s.x)*(this.width-1),o=(e-s.y)*(this.height-1),n=Math.hypot(r,o);if(n<.001)return;const h=Math.min(this.width,this.height),l=a>s.time?Math.max(1/240,(a-s.time)/1e3):1/60,c=Math.min(12,n/h/l),m=1-Math.exp(-c/2.2),f=h*(.022+.075*i)*(.65+.95*m),d=Math.min(128,Math.max(1,Math.ceil(n/(.4*f)))),u=n/f*(.32+.22*m)/d,g=r/n,p=o/n,M=-p,x=g,v=n*(2+18*m)/d;for(let i=0;i<d;i++){const a=(i+.5)/d,r=(s.x+(t-s.x)*a)*(this.width-1),o=(s.y+(e-s.y)*a)*(this.height-1),n=Math.max(1,Math.floor(r-3*f)),h=Math.min(this.width-2,Math.ceil(r+3*f)),l=Math.max(1,Math.floor(o-3*f)),c=Math.min(this.height-2,Math.ceil(o+3*f));for(let t=l;t<=c;t++)for(let e=n;e<=h;e++){const i=((e-r)*g+(t-o)*p)/f,a=((e-r)*M+(t-o)*x)/f,s=Math.exp(-i*i*.65-a*a*1.7),n=t*this.width+e;this.ink[n]=1-(1-this.ink[n])*Math.exp(-s*u);const h=1-a*a*.55,l=i*a*.7;this.u[n]=Math.max(-80,Math.min(80,this.u[n]+(g*h+M*l)*s*v)),this.v[n]=Math.max(-80,Math.min(80,this.v[n]+(p*h+x*l)*s*v))}}this.peak=1}read(t,e,i){const a=0|(e=Math.max(.5,Math.min(this.width-1.5,e))),s=0|(i=Math.max(.5,Math.min(this.height-1.5,i))),r=e-a,o=i-s,n=s*this.width+a;return(t[n]*(1-r)+t[n+1]*r)*(1-o)+(t[n+this.width]*(1-r)+t[n+this.width+1]*r)*o}sample(t,e){return this.read(this.signal,t*(this.width-1),e*(this.height-1))}displacement(t,e,i){i[0]=this.read(this.offsetX,t*(this.width-1),e*(this.height-1)),i[1]=this.read(this.offsetY,t*(this.width-1),e*(this.height-1))}step(t){if(!this.active||!Number.isFinite(t))return;let e=Math.max(0,Math.min(.05,t));const i=this.width,a=this.height;for(;e>1e-7;){const t=Math.min(1/60,e);e-=t;const s=Math.exp(-1.9*t),r=Math.exp(-3.2*t);for(let e=1;e<a-1;e++)for(let o=1;o<i-1;o++){const n=e*i+o,h=Math.max(.5,Math.min(i-1.5,o-this.u[n]*t)),l=Math.max(.5,Math.min(a-1.5,e-this.v[n]*t)),c=0|h,m=0|l,f=h-c,d=l-m,u=m*i+c,g=(1-f)*(1-d),p=f*(1-d),M=(1-f)*d,x=f*d;this.a[n]=(this.u[u]*g+this.u[u+1]*p+this.u[u+i]*M+this.u[u+i+1]*x)*s,this.b[n]=(this.v[u]*g+this.v[u+1]*p+this.v[u+i]*M+this.v[u+i+1]*x)*s,this.c[n]=(this.ink[u]*g+this.ink[u+1]*p+this.ink[u+i]*M+this.ink[u+i+1]*x)*r}[this.u,this.a]=[this.a,this.u],[this.v,this.b]=[this.b,this.v],[this.ink,this.c]=[this.c,this.ink];for(let t=1;t<a-1;t++)for(let e=1;e<i-1;e++){const a=t*i+e;this.curl[a]=.5*(this.v[a+1]-this.v[a-1]-this.u[a+i]+this.u[a-i])}for(let e=1;e<a-1;e++)for(let a=1;a<i-1;a++){const s=e*i+a,r=Math.abs(this.curl[s+1])-Math.abs(this.curl[s-1]),o=Math.abs(this.curl[s+i])-Math.abs(this.curl[s-i]),n=Math.hypot(r,o)+1e-4,h=this.curl[s]*t*10,l=Math.hypot(this.u[s],this.v[s]);this.u[s]+=o/n*h,this.v[s]-=r/n*h;const c=Math.min(1,l/(Math.hypot(this.u[s],this.v[s])+1e-6));this.u[s]*=c,this.v[s]*=c,this.divergence[s]=-.5*(this.u[s+1]-this.u[s-1]+this.v[s+i]-this.v[s-i])}this.pressure.fill(0);for(let t=0;t<4;t++){for(let t=1;t<a-1;t++)for(let e=1;e<i-1;e++){const a=t*i+e;this.pressureNext[a]=.25*(this.divergence[a]+this.pressure[a-1]+this.pressure[a+1]+this.pressure[a-i]+this.pressure[a+i])}[this.pressure,this.pressureNext]=[this.pressureNext,this.pressure]}let o=0;for(let e=1;e<a-1;e++)for(let a=1;a<i-1;a++){const s=e*i+a;this.u[s]=Math.max(-80,Math.min(80,this.u[s]-.5*(this.pressure[s+1]-this.pressure[s-1]))),this.v[s]=Math.max(-80,Math.min(80,this.v[s]-.5*(this.pressure[s+i]-this.pressure[s-i]))),this.driftX[s]+=(3.6*this.u[s]-58*this.offsetX[s]-12*this.driftX[s])*t,this.driftY[s]+=(3.6*this.v[s]-58*this.offsetY[s]-12*this.driftY[s])*t,this.offsetX[s]=Math.max(-2,Math.min(2,this.offsetX[s]+this.driftX[s]*t)),this.offsetY[s]=Math.max(-2,Math.min(2,this.offsetY[s]+this.driftY[s]*t)),this.signal[s]=1-Math.exp(.06*-Math.hypot(this.u[s],this.v[s])-.16*this.ink[s]),o=Math.max(o,this.signal[s])}this.peak=o}if(this.active)for(let t=0;t<this.ink.length;t++){const e=Math.round(65535*Math.min(1,this.signal[t]));this.pixels[4*t]=e>>>8,this.pixels[4*t+1]=255&e,this.pixels[4*t+2]=Math.round(128+63.5*this.offsetX[t]),this.pixels[4*t+3]=Math.round(128+63.5*this.offsetY[t])}else this.clear()}};function J(t,e){const i=Math.max(0,Math.min(1,e/.38));return t+(1-2*t)*(i*i*(3-2*i))}var Z=(t,e)=>"water"===t?30*e/.55:"silk"===t?28*e:"vortex"===t?38*e:["magnetic","scatter","elastic","rake"].includes(t)?32*e:0,_=class{constructor(t=1){this.mode="water",this.amount=.55,this.radius=.2,this.lensX=.5,this.lensY=.5,this.lensStrength=0,this.previous=null,this.energy=0,this.pending=!1,this.remainder=0,t=Math.max(.25,Math.min(4,t)),this.columns=Math.round(t>=1?128:128*t),this.rows=Math.round(t>=1?128/t:128),this.xScale=Math.max(1,t),this.yScale=Math.max(1,1/t),this.heights=new Float32Array(this.columns*this.rows),this.velocity=new Float32Array(this.heights.length),this.next=new Float32Array(this.heights.length),this.normals=new Float32Array(2*this.heights.length),this.edgeMask=new Float32Array(this.heights.length);for(let e=0;e<this.rows;e++)for(let i=0;i<this.columns;i++)this.edgeMask[e*this.columns+i]=j(i/(this.columns-1),e/(this.rows-1),t);this.refraction={width:this.columns,height:this.rows,pixels:new Uint8Array(4*this.heights.length),strength:30,mode:"water",focus:[.5,.5,0,.2]},this.waterPixels=this.refraction.pixels,this.trail=new Q(this.columns,this.rows),this.contour=new K(this.columns,this.rows),this.afterimage=new H(this.columns,this.rows),this.clear()}get invertsDensity(){return"trail"===this.mode}get densityTrail(){return["trail","contour","dissolve","etch"].includes(this.mode)}get hasRefraction(){return this.active||this.lensStrength>15e-5}get active(){return V(this.mode)?this.afterimage.active:"contour"===this.mode?this.contour.active:"trail"===this.mode?this.trail.active:this.pending||this.energy>15e-5}setMode(t){t!==this.mode&&(this.clear(),this.mode=t,this.refraction.mode=t,V(t)&&this.afterimage.setMode(t),this.refraction.pixels="trail"===t?this.trail.pixels:"contour"===t?this.contour.pixels:V(t)?this.afterimage.pixels:this.waterPixels,this.refraction.strength=Z(t,this.amount))}configure(t,e=.55,i=.2,a=!1){this.setMode(t),this.refraction.edgeSafe=a,this.afterimage.edgeSafe=a,this.amount=Number.isFinite(e)?Math.max(0,Math.min(1,e)):.55,this.radius=Number.isFinite(i)?Math.max(.1,Math.min(1,i)):.2,this.refraction.strength=Z(t,this.amount),this.refraction.focus[2]=this.densityTrail?this.amount:this.lensStrength*this.amount,this.refraction.focus[3]=this.radius}move(t,e,i){if("none"===this.mode||0===this.amount)return;if(!Number.isFinite(t+e))return;if(t=Math.max(0,Math.min(1,t)),e=Math.max(0,Math.min(1,e)),V(this.mode))return void this.afterimage.move(t,e,this.radius);if("contour"===this.mode)return void this.contour.move(t,e,this.radius);if("trail"===this.mode)return void this.trail.move(t,e,this.radius,i);if("water"!==this.mode)return!this.previous&&this.lensStrength<.001&&(this.lensX=t,this.lensY=e),this.previous={x:t,y:e},void(this.pending=!0);if(!this.previous)return void(this.previous={x:t,y:e});const a=this.previous;this.previous={x:t,y:e};const s=(t-a.x)*this.xScale,r=(e-a.y)*this.yScale,o=Math.hypot(s,r);if(o<1e-5)return;const n=.035+.1*this.radius,h=3*n,l=Math.min(192,Math.max(1,Math.ceil(o/(.5*n)))),c=95*Math.min(o,1)/l;for(let i=0;i<l;i++){const s=(i+.5)/l,r=a.x+(t-a.x)*s,o=a.y+(e-a.y)*s,m=Math.max(1,Math.floor((r-h/this.xScale)*(this.columns-1))),f=Math.min(this.columns-2,Math.ceil((r+h/this.xScale)*(this.columns-1))),d=Math.max(1,Math.floor((o-h/this.yScale)*(this.rows-1))),u=Math.min(this.rows-2,Math.ceil((o+h/this.yScale)*(this.rows-1)));for(let t=d;t<=u;t++)for(let e=m;e<=f;e++){const i=(e/(this.columns-1)-r)*this.xScale,a=(t/(this.rows-1)-o)*this.yScale,s=Math.exp(-(i*i+a*a)/(n*n))*c,h=t*this.columns+e;this.velocity[h]=Math.max(-12,this.velocity[h]-s)}}this.pending=!0}leave(){this.afterimage.leave(),this.contour.leave(),this.trail.leave(),this.previous=null,"water"!==this.mode&&this.lensStrength&&(this.pending=!0)}clear(){this.trail.clear(),this.contour.clear(),this.afterimage.clear(),this.heights.fill(0),this.velocity.fill(0),this.next.fill(0),this.normals.fill(0),this.refraction.focus[2]=0,this.previous=null,this.lensStrength=0,this.energy=0,this.pending=!1,this.remainder=0;for(let t=0;t<this.waterPixels.length;t+=4)this.waterPixels[t]=this.waterPixels[t+2]=128,this.waterPixels[t+1]=this.waterPixels[t+3]=0}step(t){if(!this.active||!Number.isFinite(t))return;if(V(this.mode))return void this.afterimage.step(t);if("contour"===this.mode)return void this.contour.step(t);if("trail"===this.mode)return void this.trail.step(t);if("water"!==this.mode)return void this.stepLight(Math.max(0,Math.min(.05,t)));this.remainder+=Math.max(0,Math.min(.05,t));const e=1/120,i=Math.exp(-3.8*e),a=.3*Math.min(this.columns,this.rows);for(;this.remainder+1e-8>=e;){this.remainder-=e;let t=0;for(let s=1;s<this.rows-1;s++)for(let r=1;r<this.columns-1;r++){const o=s*this.columns+r,n=this.heights[o],h=this.heights[o-1]+this.heights[o+1]+this.heights[o-this.columns]+this.heights[o+this.columns]-4*n,l=Math.min(r,s,this.columns-1-r,this.rows-1-s),c=l<5?.88+.024*l:1,m=(this.velocity[o]+(h*a*a-8*n)*e)*i*c;this.velocity[o]=m,this.next[o]=(n+m*e)*c,t=Math.max(t,Math.abs(this.next[o]),.1*Math.abs(m))}this.heights.set(this.next),this.energy=t,this.pending=!1}if(!this.active)return void this.clear();const s=.18*Math.min(this.columns,this.rows);for(let t=0;t<this.rows;t++)for(let e=0;e<this.columns;e++){const i=t*this.columns+e,a=(this.heights[t*this.columns+Math.max(0,e-1)]-this.heights[t*this.columns+Math.min(this.columns-1,e+1)])*s,r=(this.heights[Math.max(0,t-1)*this.columns+e]-this.heights[Math.min(this.rows-1,t+1)*this.columns+e])*s,o=Math.tanh(a)*(this.refraction.edgeSafe?this.edgeMask[i]:1),n=Math.tanh(r)*(this.refraction.edgeSafe?this.edgeMask[i]:1);this.normals[2*i]=o,this.normals[2*i+1]=n;const h=Math.round(32767*o+32768),l=Math.round(32767*n+32768);this.refraction.pixels[4*i]=h>>>8,this.refraction.pixels[4*i+1]=255&h,this.refraction.pixels[4*i+2]=l>>>8,this.refraction.pixels[4*i+3]=255&l}}stepLight(t){const e=this.previous,i=1-Math.exp(-30*t),a=1-Math.exp(-12*t);e&&(this.lensX+=(e.x-this.lensX)*i,this.lensY+=(e.y-this.lensY)*i),this.lensStrength+=((e?1:0)-this.lensStrength)*a,this.energy=Math.max(e?Math.abs(e.x-this.lensX)+Math.abs(e.y-this.lensY):0,Math.abs((e?1:0)-this.lensStrength)),this.pending=!1,e||this.active?this.refraction.focus=[this.lensX,this.lensY,this.lensStrength*this.amount,this.radius]:this.clear()}sample(t,e,i){if(V(this.mode))return this.afterimage.sample(t,e,i),i[0]*=this.amount,i[1]*=this.amount,void(i[2]*=this.amount);if("contour"===this.mode)return i[0]=i[1]=0,void(i[2]=this.contour.sample(t,e)*this.amount*3);if("trail"===this.mode)return i[0]=i[1]=0,void(i[2]=this.trail.sample(t,e)*this.amount*3);const a=Math.max(0,Math.min(this.columns-1.001,t*(this.columns-1))),s=Math.max(0,Math.min(this.rows-1.001,e*(this.rows-1))),r=Math.floor(a),o=Math.floor(s),n=a-r,h=s-o,l=2*(o*this.columns+r),c=l+2*this.columns;for(let t=0;t<2;t++)i[t]=.08*((this.normals[l+t]*(1-n)+this.normals[l+2+t]*n)*(1-h)+(this.normals[c+t]*(1-n)+this.normals[c+2+t]*n)*h);i[0]*=this.amount/.55,i[1]*=this.amount/.55,i[2]="light"===this.mode||"scan"===this.mode?function(t,e,i,a){const[s,r,o,n]=i.focus,h=(t-s)*Math.max(1,a)/n,l=(e-r)*Math.max(1,1/a)/n;return"light"===i.mode?Math.exp(-3*(h*h+l*l))*o:"scan"===i.mode?(1.3*Math.exp(-h*h*110)-.3*Math.exp(-h*h*12))*Math.exp(-l*l*1.8)*o:0}(t,e,this.refraction,this.xScale/this.yScale):0}};function $(t){return"videoWidth"in t?[t.videoWidth,t.videoHeight]:"naturalWidth"in t?[t.naturalWidth,t.naturalHeight]:[t.width,t.height]}var tt=(t=!1)=>{const e=document.createElement("canvas"),i=e.getContext("2d",{willReadFrequently:t});if(!i)throw new Error("Canvas 2D is unavailable.");return{canvas:e,ctx:i}},et=(t,e,i)=>{t.width===e&&t.height===i||(t.width=e,t.height=i)},it={blocks:" ░▒▓█",braille:" ⠁⠃⠇⡇⣇⣧⣷⣿",lines:" -═╪╬",cross:" ·+xX#",diagonal:" /╱╳",diamond:" ·◇◈◆",mixed:" .:+/◇#@"};function at(t,e={},i={}){const a=t.getContext("2d");if(!a)throw new Error("Canvas is already owned by another renderer.");const s=tt(),r=tt(!0),h=tt(),l=tt(),c=tt(),m=tt(),f=tt(),d=tt(),u=tt(),g=tt();let M,x=0,v=y(e),b=0,w="",k="",S="",E=new Uint8ClampedArray(0),F=new Uint8ClampedArray(0),P=0,I=0,R=0,N=null,O="",Y=new _,j=0;const V=[0,0,0],H=[0,0,0,1],K=[0,0,0,0];let Q=L(v.color);const Z=new X(v.color.denoise),at=Math.max(64,Math.min(4096,Number.isFinite(i.maxDimension)?i.maxDimension:960)),st=Math.max(256,Math.min(1048576,Number.isFinite(i.maxCells)?i.maxCells:12e3));let rt=st,ot=Math.max(.1,Math.min(8,i.pixelRatio??1));return{canvas:t,render:function(e,i=0,y=960,L=540,X=i*v.motion.speed){if(Number.isFinite(i)||(i=0),!Number.isFinite(y)||!Number.isFinite(L)||y<1||L<1)throw new Error("Render dimensions must be positive finite numbers.");const[tt,st]=$(e);if(!tt||!st)return;const nt=Math.min(1,at/Math.max(y,L)),ht=Math.max(2,Math.round(y*nt)),lt=Math.max(2,Math.round(L*nt));et(t,ht,lt),et(s.canvas,ht,lt),et(h.canvas,ht,lt),et(l.canvas,ht,lt),et(c.canvas,ht,lt),j!==ht/lt&&(j=ht/lt,Y=new _(j)),Y.configure(v.hover.effect,v.hover.strength,v.hover.radius,v.hover.edgeSafe),Y.step(Math.max(0,Math.min(.05,i-R))),R=i;const ct="currentTime"in e?e.getVideoPlaybackQuality?.().totalVideoFrames??e.currentTime:0,mt=[b,ht,lt,ct].join(":"),ft="dither"===v.style,dt=T(ht,lt,v,rt,ot),ut=dt.cell,gt=dt.rowHeight,pt=dt.columns,Mt=dt.rows;if(w!==mt||N!==e||P!==pt||I!==Mt){N=e,w=mt,k="",S="",P=pt,I=Mt,s.ctx.clearRect(0,0,ht,lt),s.ctx.save();const t=A(tt,st,ht,lt,v.crop);s.ctx.translate(t.x+t.width/2,t.y+t.height/2),s.ctx.rotate(v.crop.rotation*Math.PI/180),s.ctx.drawImage(e,-tt*t.scale/2,-st*t.scale/2,tt*t.scale,st*t.scale),s.ctx.restore(),et(r.canvas,P,I),r.ctx.clearRect(0,0,P,I),r.ctx.drawImage(s.canvas,0,0,P,I),E=r.ctx.getImageData(0,0,P,I).data,Z.apply(E,P,I);const i=v.color;for(let t=0;t<E.length;t+=4){const e=.299*E[t]+.587*E[t+1]+.114*E[t+2];for(let a=0;a<3;a++){const s=e+(E[t+a]-e)*i.saturation;E[t+a]=((s*(1-i.grayscale)+e*i.grayscale)/255-.5)*i.contrast*255+127.5+255*i.brightness}}Q&&function(t,e){for(let i=0;i<t.length;i+=4)t[i+3]&&(t[i]=e[t[i]],t[i+1]=e[256+t[i+1]],t[i+2]=e[512+t[i+2]])}(E,Q)}const xt=U(v),vt=D(v),bt=!Y.active&&!xt&&!vt,wt=[mt,P,I,ut,gt,ot].join(":");if(!bt||S!==wt){h.ctx.clearRect(0,0,ht,lt),h.ctx.globalAlpha=1,h.ctx.globalCompositeOperation="source-over";const t=X,e=xt?v.motion.type:"none",a=["none","caustics","sheen","grain","trace"].includes(e);if(ft){const a=bt;if(!a||k!==mt){F.length!==E.length&&(F=new Uint8ClampedArray(E.length));const s=F;if(s.set(E),Y.active||"none"!==e)for(let i=0;i<I;i++)for(let a=0;a<P;a++){const r=a/P,h=i/I;let l=a,c=i,m=0,f=1,d=1;Y.active&&(Y.sample(r,h,V),l-=V[0]*P,c-=V[1]*I,m=V[2]/3);const u=4*(i*P+a);o(e,r,h,t,H,(.299*E[u]+.587*E[u+1]+.114*E[u+2])/255),n(H,v.motion.amount??1),l-=H[0]/960*P,c-=H[1]/960*I,f=1+H[2],d=H[3],l=Math.max(0,Math.min(P-1,l)),c=Math.max(0,Math.min(I-1,c));const g=Math.floor(l),p=Math.floor(c),M=l-g,x=c-p,b=4*(i*P+a),w=4*(p*P+g),y=4*(p*P+Math.min(P-1,g+1)),k=4*(Math.min(I-1,p+1)*P+g),S=4*(Math.min(I-1,p+1)*P+Math.min(P-1,g+1));for(let t=0;t<3;t++){const e=((E[w+t]*(1-M)+E[y+t]*M)*(1-x)+(E[k+t]*(1-M)+E[S+t]*M)*x)/255;let i=(["trail","contour"].includes(v.hover.effect)?J(e,m):"etch"===v.hover.effect?Math.max(0,Math.min(1,e+.35*m)):"dissolve"===v.hover.effect?e*Math.max(0,1+m):e)*f;s[b+t]=255*i}s[b+3]=E[w+3]*d}!function(t,e,i,a,s=0){const{algorithm:r,amount:o,threshold:n}=a,h="blue-noise"===r,l=r.startsWith("bayer")?Number(r.slice(5)):0,c=W.get(l),m=l-1,f="luminance"===a.colorSpace,d=("custom"===a.palette?a.colors:p[a.palette]??p.mono).map(G),u=q[r],g=u?new Float32Array(3*e*3):null,M="drift"===a.motion?s*a.speed*3:0,x=(a.direction??45)*Math.PI/180,v=Math.round(Math.cos(x)*M),b=Math.round(Math.sin(x)*M),w=(t,e)=>(t%e+e)%e,y=d.map(t=>.299*t[0]+.587*t[1]+.114*t[2]),k="shimmer"===a.motion?.15*Math.sin(s*a.speed*2):0;for(let a=0;a<i;a++)for(let s=0;s<e;s++){const p=4*(a*e+s),x=3*(a%3*e+s);if(0===t[p+3]){g&&(g[x]=g[x+1]=g[x+2]=0);continue}let S=0;const A=h?(B[64*(a-b&63)+(s-v&63)]+.5)/B.length:0;c?S=c[(a-b&m)*l+(s-v&m)]:"noise"===r?S=z(s-v,a-b)-.5:"lines"===r?S=w(a-b,4)/3-.5:"vertical-lines"===r?S=w(s-v,4)/3-.5:"diagonal-lines"===r?S=w(s-v+a-b,4)/3-.5:"radial"===r?S=w(Math.hypot(s-e/2,a-i/2)-M,6)/6-.5:"halftone"===r&&(S=Math.hypot(w(s-v,6)-2.5,w(a-b,6)-2.5)/3.54-.5);const E=128*(S*o+k+(.5-n)),F=t[p]+E+(g?.[x]??0),T=t[p+1]+E+(g?.[x+1]??0),P=t[p+2]+E+(g?.[x+2]??0);let I=0,R=0,C=0;if(d.length){let t=1/0,e=1/0,i=0,a=0;const s=.299*F+.587*T+.114*P;for(let r=0;r<d.length;r++){const o=d[r],n=f?(s-y[r])**2:(F-o[0])**2*.299+(T-o[1])**2*.587+(P-o[2])**2*.114;n<t?(h&&(e=t,a=i,i=r),t=n,[I,R,C]=o):h&&n<e&&(e=n,a=r)}if(h&&o>0&&Number.isFinite(e)){const t=d[a],e=t[0]-I,r=t[1]-R,n=t[2]-C,h=y[a]-y[i],l=f?h*h:e*e*.299+r*r*.587+n*n*.114,c=f?(s-y[i])*h:(F-I)*e*.299+(T-R)*r*.587+(P-C)*n*.114;A<(l?Math.max(0,Math.min(1,c/l*o)):0)&&([I,R,C]=t)}}else if(h){const t=Math.max(0,Math.min(1,.5+(A-.5)*o));I=51*Math.floor(F/51+1-t),R=51*Math.floor(T/51+1-t),C=51*Math.floor(P/51+1-t)}else I=51*Math.round(F/51),R=51*Math.round(T/51),C=51*Math.round(P/51);if(t[p]=I,t[p+1]=R,t[p+2]=C,g&&u){g[x]=g[x+1]=g[x+2]=0;for(const[t,r,n]of u){const h=s+t;if(h<0||h>=e||a+r>=i)continue;const l=3*((a+r)%3*e+h);g[l]+=(F-I)*n*o,g[l+1]+=(T-R)*n*o,g[l+2]+=(P-C)*n*o}}}}(s,P,I,v.dither,i),r.ctx.putImageData(new ImageData(s,P,I),0,0),k=a?mt:""}h.ctx.imageSmoothingEnabled=!1,h.ctx.drawImage(r.canvas,0,0,ht,lt)}else{const i=Array.from(it[v.style]??v.charset),s=h.ctx,r=G(v.ink),l="ascii"===v.style||!!it[v.style],c=Math.max(3,Math.round(.92*gt)),m=Math.ceil(ut+4),d=Math.ceil(gt+4),u=[i.join(""),c,m,d,v.ink,v.colorMode].join(":");if(l&&u!==O&&(O=u,et(f.canvas,m*i.length,d),f.ctx.clearRect(0,0,f.canvas.width,d),f.ctx.font=`${c}px monospace`,f.ctx.textBaseline="middle",f.ctx.textAlign="center",f.ctx.fillStyle="accent"===v.colorMode?v.ink:"#ffffff",i.forEach((t,e)=>f.ctx.fillText(t,e*m+m/2,d/2))),"lego"===v.style&&x!==ut){x=ut,et(g.canvas,Math.ceil(ut),Math.ceil(gt));const t=g.ctx;t.clearRect(0,0,g.canvas.width,g.canvas.height),t.fillStyle="rgba(255,255,255,.2)",t.strokeStyle="rgba(0,0,0,.25)",t.lineWidth=Math.max(.5,.6*ot),t.beginPath(),t.arc(ut/2,gt/2,.28*ut,0,2*Math.PI),t.fill(),t.stroke()}s.font=`${c}px monospace`,s.textBaseline="middle",s.textAlign="center";for(let h=0;h<I;h++)for(let c=0;c<P;c++){let u=c,p=h,M=0;if(Y.active&&(Y.sample(c/P,h/I,V),u=Math.max(0,Math.min(P-1,c-V[0]*P)),p=Math.max(0,Math.min(I-1,h-V[1]*I)),M=V[2]/3),C(E,P,I,u,p,K),!K[3])continue;const x=K[0],b=K[1],w=K[2],y=(.299*x+.587*b+.114*w)/255;let k=y;["trail","contour"].includes(v.hover.effect)&&M?k=J(k,M):"etch"===v.hover.effect?k=Math.max(0,Math.min(1,k+.35*M)):"dissolve"===v.hover.effect&&(k*=Math.max(0,1+M));let S=c*ut,A=h*gt,F=1;o(e,c/P,h/I,t,H,y),n(H,v.motion.amount??1),S+=H[0]*ht/960,A+=H[1]*lt/960,k=Math.max(0,Math.min(1,k+H[2])),F=H[3]*K[3]/255,l||"accent"!==v.colorMode||"cmyk"===v.style||(F*=k),s.globalAlpha=F;const T=255*(k-y),R="source"===v.colorMode?`rgb(${x+T},${b+T},${w+T})`:"gray"===v.colorMode?`rgb(${Math.round(255*k)},${Math.round(255*k)},${Math.round(255*k)})`:v.ink;if(s.fillStyle=R,l){const t=Math.max(0,Math.min(i.length-1,Math.round(k*(i.length-1))));"accent"===v.colorMode?s.drawImage(f.canvas,t*m,0,m,d,a?Math.round(S+(ut-m)/2):S+(ut-m)/2,a?Math.round(A+(gt-d)/2):A+(gt-d)/2,m,d):s.fillText(i[t],S+ut/2,A+gt/2)}else if("dots"===v.style)s.beginPath(),s.arc(S+ut/2,A+gt/2,.48*ut*Math.sqrt(k),0,2*Math.PI),s.fill();else if("led"===v.style)s.beginPath(),s.arc(S+ut/2,A+gt/2,.39*ut,0,2*Math.PI),s.fill(),s.globalAlpha=.35*F,s.fillStyle="#ffffff",s.beginPath(),s.arc(S+.43*ut,A+.4*gt,.11*ut,0,2*Math.PI),s.fill();else if("hex"===v.style){const t=S+ut/2,e=A+gt/2;s.beginPath();for(let i=0;i<6;i++){const a=Math.PI/3*i,r=t+Math.cos(a)*ut*.49,o=e+Math.sin(a)*gt*.49;0===i?s.moveTo(r,o):s.lineTo(r,o)}s.closePath(),s.fill()}else if("cmyk"===v.style){s.fillStyle="#ffffff",s.fillRect(S,A,ut,gt);const t=(t,e)=>Math.max(0,Math.min(255,"source"===v.colorMode?t+T:"gray"===v.colorMode?255*k:e*k)),e=t(x,r[0]),i=t(b,r[1]),a=t(w,r[2]),o=1-Math.max(e,i,a)/255,n=Math.max(.001,1-o),h=[["#00ffff",(1-e/255-o)/n,.36,.36],["#ff00ff",(1-i/255-o)/n,.64,.36],["#ffff00",(1-a/255-o)/n,.5,.66],["#000000",o,.5,.5]];s.globalCompositeOperation="multiply";for(const[t,e,i,a]of h)s.fillStyle=t,s.beginPath(),s.arc(S+ut*i,A+gt*a,.48*ut*Math.sqrt(Math.max(0,e)),0,2*Math.PI),s.fill();s.globalCompositeOperation="source-over"}else if("voxel"===v.style){const t=S+ut/2,e=A+gt/2;s.beginPath(),s.moveTo(t,A),s.lineTo(S+ut,A+.25*gt),s.lineTo(t,e),s.lineTo(S,A+.25*gt),s.closePath(),s.fill(),s.globalAlpha=.72*F,s.beginPath(),s.moveTo(S,A+.25*gt),s.lineTo(t,e),s.lineTo(t,A+gt),s.lineTo(S,A+.75*gt),s.closePath(),s.fill(),s.globalAlpha=.42*F,s.beginPath(),s.moveTo(t,e),s.lineTo(S+ut,A+.25*gt),s.lineTo(S+ut,A+.75*gt),s.lineTo(t,A+gt),s.closePath(),s.fill()}else{const t="pixel"===v.style?0:Math.max(.5,.06*ut);s.fillRect(S,A,ut-t,gt-t),"lego"===v.style&&s.drawImage(g.canvas,S,A),"disco"===v.style&&(s.fillStyle=`rgba(255,255,255,${.1+.25*z(c,h)})`,s.fillRect(S,A,ut-t,.35*gt),s.fillStyle="rgba(0,0,0,.25)",s.fillRect(S,A+.65*gt,ut-t,.35*gt-t))}}}h.ctx.globalAlpha=1,(v.color.amount||v.lights.length)&&(et(d.canvas,ht,lt),d.ctx.clearRect(0,0,ht,lt),d.ctx.drawImage(h.canvas,0,0)),v.color.amount&&(h.ctx.save(),h.ctx.globalCompositeOperation=v.color.blend,h.ctx.globalAlpha=v.color.amount,h.ctx.fillStyle=v.color.tint,h.ctx.fillRect(0,0,ht,lt),h.ctx.restore());for(const t of v.lights){const e=t.radius*Math.max(ht,lt),i=h.ctx.createRadialGradient(t.x*ht,t.y*lt,0,t.x*ht,t.y*lt,e);i.addColorStop(0,t.color),i.addColorStop(1,"transparent"),h.ctx.save(),h.ctx.globalCompositeOperation="screen",h.ctx.globalAlpha=t.intensity,h.ctx.fillStyle=i,h.ctx.fillRect(0,0,ht,lt),h.ctx.restore()}if((v.color.amount||v.lights.length)&&(h.ctx.globalCompositeOperation="destination-in",h.ctx.drawImage(d.canvas,0,0),h.ctx.globalCompositeOperation="source-over"),v.mask.enabled&&v.mask.shapes.length){const t=c.ctx;t.clearRect(0,0,ht,lt),t.fillStyle="#fff",t.strokeStyle="#fff",t.lineCap="round",t.lineJoin="round";for(const e of v.mask.shapes){if(t.beginPath(),"ellipse"===e.kind)t.ellipse((e.x+e.width/2)*ht,(e.y+e.height/2)*lt,e.width*ht/2,e.height*lt/2,0,0,2*Math.PI);else{if("rectangle"!==e.kind){if(t.lineWidth=(e.size??.05)*ht,1===e.points?.length){t.arc(e.points[0][0]*ht,e.points[0][1]*lt,t.lineWidth/2,0,2*Math.PI),t.fill();continue}e.points?.forEach(([e,i],a)=>a?t.lineTo(e*ht,i*lt):t.moveTo(e*ht,i*lt)),t.stroke();continue}t.rect(e.x*ht,e.y*lt,e.width*ht,e.height*lt)}t.fill()}h.ctx.globalCompositeOperation=v.mask.invert?"destination-out":"destination-in",h.ctx.drawImage(c.canvas,0,0),h.ctx.globalCompositeOperation="source-over"}const M=l.ctx;M.clearRect(0,0,ht,lt),M.globalAlpha=v.backdrop.opacity;const b=v.backdrop;if("solid"===b.mode&&(M.fillStyle=b.color,M.fillRect(0,0,ht,lt)),"gradient"===b.mode){const t=M.createLinearGradient(0,0,ht,lt);t.addColorStop(0,b.color),t.addColorStop(1,b.color2),M.fillStyle=t,M.fillRect(0,0,ht,lt)}if("source"===b.mode&&M.drawImage(s.canvas,0,0),"blurred"===b.mode){const t=Math.max(1,b.blur);et(m.canvas,Math.max(2,Math.round(ht/t)),Math.max(2,Math.round(lt/t))),m.ctx.drawImage(s.canvas,0,0,m.canvas.width,m.canvas.height),M.imageSmoothingEnabled=!0,M.drawImage(m.canvas,0,0,ht,lt)}M.globalAlpha=1,v.effects.characterBloom>0&&(et(u.canvas,Math.max(2,Math.round(ht/3)),Math.max(2,Math.round(lt/3))),u.ctx.clearRect(0,0,u.canvas.width,u.canvas.height),u.ctx.drawImage(h.canvas,0,0,u.canvas.width,u.canvas.height),M.save(),M.globalAlpha=.8*v.effects.characterBloom,M.globalCompositeOperation="screen",M.filter=`blur(${1+4*v.effects.characterBloom}px)`,M.drawImage(u.canvas,0,0,ht,lt),M.restore()),M.drawImage(h.canvas,0,0),S=bt?wt:""}const yt=Object.entries(v.effects).some(([t,e])=>!["angle","focus","blurType","characterBloom"].includes(t)&&"number"==typeof e&&e>0);a.clearRect(0,0,ht,lt),yt?(void 0===M&&(M=function(){const t=document.createElement("canvas"),e=t.getContext("webgl",{alpha:!0,premultipliedAlpha:!1,antialias:!1,preserveDrawingBuffer:!0});if(!e)return null;const i=[],a=(t,a)=>{const s=e.createShader(t);if(i.push(s),e.shaderSource(s,a),e.compileShader(s),!e.getShaderParameter(s,e.COMPILE_STATUS))throw new Error(e.getShaderInfoLog(s)||"Finish shader failed");return s},s=e.createProgram();if(e.attachShader(s,a(e.VERTEX_SHADER,"attribute vec2 p;varying vec2 uv;void main(){uv=(p+1.)*.5;gl_Position=vec4(p,0.,1.);}")),e.attachShader(s,a(e.FRAGMENT_SHADER,"precision mediump float;varying vec2 uv;uniform sampler2D src;uniform vec2 size;uniform float t,bloom,grain,dust,scanlines,crt,prism,vignette,glitch,pixelate,blur,blurMode,angle,focus,halftone,rgbSplit,sharpen;\n float hash(vec2 p){return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453);}\n vec4 sampleAt(vec2 p){if(min(min(p.x,p.y),min(1.-p.x,1.-p.y))<0.)return vec4(0.);return texture2D(src,vec2(p.x,1.-p.y));}\n void main(){vec2 q=uv,c=q-.5;q=c*(1.+dot(c,c)*crt*.25)+.5;\n if(glitch>0.)q.x+=(hash(vec2(floor(q.y*35.),floor(t*5.)))-.5)*.07*glitch*step(.82,hash(vec2(floor(q.y*35.),floor(t*5.)+3.)));\n if(pixelate>0.){vec2 grid=size/(1.+pixelate*20.);q=(floor(q*grid)+.5)/grid;}\n vec4 base=sampleAt(q);float edge=smoothstep(.12,.65,length(c));\n vec2 shift=vec2((prism*3.*edge+rgbSplit*8.)/size.x,prism*edge/size.y);\n if(prism>0.||rgbSplit>0.)base.rgb=vec3(sampleAt(q+shift).r,base.g,sampleAt(q-shift).b);\n vec2 dir=vec2(cos(angle),sin(angle))/size;float amount=blur;\n if(blurMode>1.5&&blurMode<2.5){dir=normalize(c+vec2(.0001))/size;amount*=length(c)*2.;}\n if(blurMode>2.5)amount*=smoothstep(.05,.5,abs(q.y-focus));\n vec4 blurred=base;\n if(amount>0.){blurred=base*.2;for(int i=1;i<=4;i++){float f=float(i)*amount*.35;vec2 off=dir*f;if(blurMode<.5)off=vec2(cos(float(i)*1.57),sin(float(i)*1.57))*amount/size;blurred+=sampleAt(q+off)*.1+sampleAt(q-off)*.1;}}\n vec3 light=vec3(0.);if(bloom>0.)for(int i=0;i<4;i++){float a=float(i)*1.5708;vec3 s=sampleAt(q+vec2(cos(a),sin(a))*6./size).rgb;light+=max(vec3(0.),s-.35)*.25;}\n vec3 col=blurred.rgb+light*bloom;\n if(sharpen>0.){vec2 px=1./size;vec3 near=sampleAt(q+vec2(px.x,0.)).rgb+sampleAt(q-vec2(px.x,0.)).rgb+sampleAt(q+vec2(0.,px.y)).rgb+sampleAt(q-vec2(0.,px.y)).rgb;col+=(base.rgb*4.-near)*sharpen*.5;}\ncol*=1.-scanlines*.4*(.5+.5*cos(q.y*size.y*3.14159));\n col*=1.-vignette*smoothstep(.15,.72,length(c));\n col+=(hash(floor(q*size)+floor(t*12.))-.5)*grain*.2;\n if(dust>0.)col+=step(1.-dust*.002,hash(floor(q*size*.25)+floor(t*2.)))*.4;\n if(halftone>0.)col*=mix(1.,smoothstep(.1,.65,length(fract(q*size/6.)-.5)),halftone);\n gl_FragColor=vec4(clamp(col,0.,1.),blurred.a);}")),e.linkProgram(s),!e.getProgramParameter(s,e.LINK_STATUS))throw new Error("Finish link failed");e.useProgram(s);const r=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,r),e.bufferData(e.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,1]),e.STATIC_DRAW);const o=e.getAttribLocation(s,"p");e.enableVertexAttribArray(o),e.vertexAttribPointer(o,2,e.FLOAT,!1,0,0);const n=e.createTexture();e.bindTexture(e.TEXTURE_2D,n),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE);const h=["t","bloom","grain","dust","scanlines","crt","prism","rgbSplit","sharpen","vignette","glitch","pixelate","blur","blurMode","angle","focus","halftone"],l=Object.fromEntries(h.map(t=>[t,e.getUniformLocation(s,t)])),c=e.getUniformLocation(s,"size");return{canvas:t,render(i,a,r,o=1){t.width===i.width&&t.height===i.height||(t.width=i.width,t.height=i.height,e.viewport(0,0,t.width,t.height)),e.useProgram(s),e.bindTexture(e.TEXTURE_2D,n),e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,i),e.uniform2f(c,t.width/o,t.height/o);for(const t of h)e.uniform1f(l[t],"t"===t?r:"blurMode"===t?["gaussian","directional","radial","progressive"].indexOf(a.blurType):"angle"===t?a.angle*Math.PI/180:a[t]??0);return e.drawArrays(e.TRIANGLE_STRIP,0,4),t},destroy(){e.deleteTexture(n),e.deleteBuffer(r),e.deleteProgram(s),i.forEach(t=>e.deleteShader(t)),t.width=t.height=1,e.getExtension("WEBGL_lose_context")?.loseContext()}}}()),M?a.drawImage(M.render(l.canvas,v.effects,i,ot),0,0):a.drawImage(l.canvas,0,0),t.dataset.studioFinish=M?"gpu":"unavailable"):(a.drawImage(l.canvas,0,0),t.dataset.studioFinish="none")},setPixelRatio(t){ot=Math.max(.1,Math.min(8,Number.isFinite(t)?t:1))},get pixelRatio(){return ot},setBudget(t){rt=Math.max(256,Math.min(st,Number.isFinite(t)?Math.round(t):st))},get maxCells(){return rt},configure(t){v=y(t),Q=L(v.color),Z.configure(v.color.denoise),b++},pointer:(t,e,i)=>{Y.configure(v.hover.effect,v.hover.strength,v.hover.radius,v.hover.edgeSafe),Y.move(t,e,i)},leave(){Y.leave()},get active(){return Y.active},get settings(){return y(v)},get capabilities(){return{gpuFinish:null!==M}},invalidate(){w=""},destroy(){M?.destroy();for(const t of[s,r,h,l,c,m,f,d,u,g])t.canvas.width=t.canvas.height=1;N=null,E=new Uint8ClampedArray(0)}}}function st(t,e,i){return new Promise((a,s)=>{const r=()=>{l(),a()},o=()=>{l(),s(new Error("Unable to load this media. Check its format and cross-origin permissions."))},n=()=>{l(),s(new DOMException("Cancelled","AbortError"))},h=setTimeout(o,2e4),l=()=>{clearTimeout(h),t.removeEventListener(e,r),t.removeEventListener("error",o),i?.removeEventListener("abort",n)};t.addEventListener(e,r,{once:!0}),t.addEventListener("error",o,{once:!0}),i?.addEventListener("abort",n,{once:!0}),i?.aborted&&n()})}async function rt(t,e){if("string"==typeof t&&t.startsWith("blob:")){const i=await fetch(t,{signal:e}),a=await i.blob();return rt(new File([a],"Imported media",{type:a.type}),e)}const i="string"!=typeof t,a=i?t.name:t;if(i?"image/gif"===t.type:/\.gif(?:[?#]|$)/i.test(a)){const a=await import("gifuct-js"),{parseGIF:s,decompressFrames:r}="function"==typeof a.parseGIF?a:a.default,o=i?await t.arrayBuffer():await fetch(t,{signal:e}).then(t=>{if(!t.ok)throw new Error("GIF download failed.");return t.arrayBuffer()});if(e?.aborted)throw new DOMException("Cancelled","AbortError");const n=s(o),h=n.lsd.width,l=n.lsd.height;if(h*l>4e6)throw new Error("GIF is too large. Use a smaller GIF or an MP4.");const c=n.frames.filter(t=>"image"in t).length;if(!c||c*h*l*4>128e6)throw new Error("GIF exceeds the decoded memory budget. Use MP4 for long animations.");const m=r(n,!0);if(m.length*h*l*4>128e6)throw new Error("GIF exceeds the 128 MB decoded budget. Use MP4 for long animations.");const f=document.createElement("canvas");f.width=h,f.height=l;const d=f.getContext("2d"),u=document.createElement("canvas"),g=u.getContext("2d"),p=m.reduce((t,e)=>t+Math.max(20,e.delay),0)/1e3;let M=-1,x=null;const v=t=>{const e=(t%p+p)%p*1e3;let i=0,a=0;for(;a<m.length-1&&(i+=Math.max(20,m[a].delay),!(e<i));a++);a<M&&(d.clearRect(0,0,h,l),M=-1,x=null);for(let t=M+1;t<=a;t++){const e=m[t-1];2===e?.disposalType&&d.clearRect(e.dims.left,e.dims.top,e.dims.width,e.dims.height),3===e?.disposalType&&x&&d.putImageData(x,0,0);const i=m[t];x=3===i.disposalType?d.getImageData(0,0,h,l):null,u.width=i.dims.width,u.height=i.dims.height,g.putImageData(new ImageData(new Uint8ClampedArray(i.patch),u.width,u.height),0,0),d.drawImage(u,i.dims.left,i.dims.top)}return M=a,f};return v(0),{source:f,width:h,height:l,duration:p,animated:!0,seek:async()=>{},frame:v,destroy(){f.width=u.width=1,m.length=0,x=null}}}const s=i?t.type.startsWith("video/"):/\.(mp4|webm|mov)(?:[?#]|$)/i.test(a),r=i?URL.createObjectURL(t):t,o=s?document.createElement("video"):new Image;o.crossOrigin="anonymous",o instanceof HTMLVideoElement&&(o.muted=!0,o.playsInline=!0,o.preload="auto");const n=()=>{o instanceof HTMLVideoElement?(o.pause(),o.removeAttribute("src"),o.load()):o.src="",i&&URL.revokeObjectURL(r)};try{const t=st(o,s?"loadeddata":"load",e);o.src=r,await t;const i=o instanceof HTMLVideoElement?o.videoWidth:o.naturalWidth,a=o instanceof HTMLVideoElement?o.videoHeight:o.naturalHeight;return{source:o,width:i,height:a,duration:o instanceof HTMLVideoElement?o.duration:0,animated:s,async seek(t,e){if(!(o instanceof HTMLVideoElement))return;if(!Number.isFinite(o.duration)||o.duration<=0)throw new Error("Video duration is unavailable.");const i=Math.max(0,Math.min(o.duration-.001,t%o.duration));if(Math.abs(o.currentTime-i)<.001&&o.readyState>=2)return;const a=st(o,"seeked",e);o.currentTime=i,await a},frame:()=>o,destroy:n}}catch(t){throw n(),t}}var ot=t=>{if(t?.aborted)throw new DOMException("Export cancelled","AbortError")};async function nt(t,e,i){const{format:a,signal:s}=i,r=Math.round(i.width),o=Math.round(i.height);if(!Number.isFinite(r)||!Number.isFinite(o)||r<2||o<2||r>4096||o>4096||r*o>16777216)throw new Error("Choose export dimensions between 2 and 4096 pixels.");if(!["png","jpeg","mp4","webm","gif"].includes(a))throw new Error("Unknown export format.");if(void 0!==i.fps&&!Number.isFinite(i.fps))throw new Error("Frames per second must be finite.");const n=Math.max(1,Math.min(60,Math.round(i.fps??24))),h=i.duration??5;if(!Number.isFinite(h)||h<=0||h>60)throw new Error("Choose a duration from 0 to 60 seconds.");const l="png"===a||"jpeg"===a,c=i.time??0;if(!Number.isFinite(c)||c<0)throw new Error("Image time must be a finite non-negative number.");if(void 0!==i.motionTime&&(!Number.isFinite(i.motionTime)||i.motionTime<0))throw new Error("Motion time must be a finite non-negative number.");if(!l&&r*o>8294400)throw new Error("Video exports support up to 3840 × 2160 pixels.");if("gif"===a&&(r*o>921600||h*n>600))throw new Error("GIF export supports up to 1280 × 720 and 600 frames. Use MP4 for larger exports.");if(void 0!==i.referenceWidth&&(!Number.isFinite(i.referenceWidth)||i.referenceWidth<1))throw new Error("Reference width must be a positive number.");if("gif"===a&&n>30)throw new Error("GIF exports support up to 30 fps. Choose MP4 or WebM for higher frame rates.");const m=document.createElement("canvas"),f=at(m,y(e),{maxDimension:4096,maxCells:i.maxCells??12e3,pixelRatio:r/(i.referenceWidth??Math.min(r,960))});let d;try{if(ot(s),i.onProgress?.(0),l){if(f.render(await t.frame(c,s),c,r,o,i.motionTime),"unavailable"===m.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");ot(s);const e=await new Promise((t,e)=>m.toBlob(i=>i?t(i):e(new Error("Image export failed.")),"png"===a?"image/png":"image/jpeg",i.quality??.92));return i.onProgress?.(1),e}const e=Math.ceil(h*n);if("gif"===a){const a=await import("gifenc"),{GIFEncoder:l,quantize:c,applyPalette:d}="function"==typeof a.GIFEncoder?a:a.default,u=l(),g=m.getContext("2d");for(let a=0;a<e;a++){ot(s);const l=a/n;if(f.invalidate(),f.render(await t.frame(l,s),l,r,o),"unavailable"===m.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");const p=g.getImageData(0,0,r,o).data,M=c(p,256),x=d(p,M);u.writeFrame(x,r,o,{palette:M,delay:10*(Math.round(100*Math.min((a+1)/n,h))-Math.round(100*a/n)),repeat:0}),i.onProgress?.((a+1)/e*.98),await new Promise(t=>setTimeout(t,0))}return u.finish(),i.onProgress?.(1),new Blob([new Uint8Array(u.bytes())],{type:"image/gif"})}const{Output:u,Mp4OutputFormat:g,WebMOutputFormat:p,BufferTarget:M,CanvasSource:x,canEncodeVideo:v}=await import("mediabunny"),b="mp4"===a?"avc":"vp9";if(!await v(b,{width:r,height:o}))throw new Error(`${a.toUpperCase()} encoding is unavailable in this browser. Try another format or a current browser with WebCodecs.`);const w=new u({format:"mp4"===a?new g({fastStart:"in-memory"}):new p,target:new M});m.width=r,m.height=o,d=()=>w.cancel();const y=new x(m,{codec:b,bitrate:Math.max(5e5,Math.round(r*o*n*.15))});w.addVideoTrack(y,{frameRate:n}),m.width=r,m.height=o,await w.start();for(let a=0;a<e;a++){ot(s);const l=a/n;if(f.invalidate(),f.render(await t.frame(l,s),l,r,o),"unavailable"===m.dataset.studioFinish)throw new Error("Optical effects need WebGL. Disable these effects or export in a supported browser.");await y.add(l,Math.min(1/n,h-l)),i.onProgress?.((a+1)/e*.98),a%4==0&&await new Promise(t=>setTimeout(t,0))}return y.close(),ot(s),await w.finalize(),d=void 0,i.onProgress?.(1),new Blob([w.target.buffer],{type:"mp4"===a?"video/mp4":"video/webm"})}catch(t){throw await(d?.().catch(()=>{})),t}finally{f.destroy(),m.width=m.height=1}}async function ht(t,e,i={}){const a=await rt(e,i.signal);try{return lt(t,a,i)}catch(t){throw a.destroy(),t}}function lt(t,e,i={}){let a=y(i.settings),s=i.width??e.width,o=i.height??e.height;const n=at(t,a,i),h=new r;let l=0,c=!1,m=!0,f=!1,d=!0,u=0,g=0,p=0,M=0,x=-1,v=!1!==i.adaptive,b=0,w=0,k=0;const S=matchMedia("(prefers-reduced-motion: reduce)"),A=e.source instanceof HTMLVideoElement?e.source:null,T=()=>{c||l||!d||document.hidden||(l=requestAnimationFrame(R))},P=()=>!f&&!S.matches&&d&&!document.hidden,I=()=>{A&&(A.loop=!0,P()?A.play().catch(()=>{f=!0,m=!0,T()}):A.pause()),p=0,m=!0,T()};function R(t){if(l=0,c||!d||document.hidden)return;const r=P();r&&(u+=p?Math.min(.1,(t-p)/1e3):0),p=t;const y=function(t){return U(t)||D(t)||t.effects.grain>0||t.effects.dust>0||t.effects.glitch>0}(a),S=r&&(e.animated||y),F=A?.getVideoPlaybackQuality?.().totalVideoFrames??-1,I=!A||F<0||F!==x;if(m||n.active||S&&(I||y)&&t-M>=1e3/Math.max(1,Math.min(60,i.fps??60))-.5){const r=performance.now();try{e.animated&&!A&&n.invalidate();const[t,l]=E(s,o,a);g=h.update(u,a.motion.type,a.motion.speed),n.render(e.frame(A?.currentTime??u),u,t,l,g);const c=performance.now()-r;i.onFrame?.(A?.currentTime??u,c),w=w?.9*w+.1*c:c,++b>20&&v&&(S||n.active)&&(k=w>13?k+1:0,k>=12&&n.maxCells>3e3&&(n.setBudget(Math.max(3e3,.8*n.maxCells)),i.onQualityChange?.(n.maxCells),k=0,w=0))}catch(t){f=!0,i.onError?.(t instanceof Error?t:new Error(String(t)))}m=!1,M=t,x=F}r&&(S||n.active)&&T()}const C=e=>{if(!P())return;const i=t.getBoundingClientRect();n.pointer((e.clientX-i.left)/i.width,(e.clientY-i.top)/i.height,e.timeStamp),T()},L=()=>{n.leave(),T()},X=new IntersectionObserver(([t])=>{d=t.isIntersecting,I()});X.observe(t),t.addEventListener("pointermove",C),t.addEventListener("pointerleave",L),t.addEventListener("pointercancel",L),document.addEventListener("visibilitychange",I),S.addEventListener("change",I);const N=()=>{c||(c=!0,cancelAnimationFrame(l),X.disconnect(),t.removeEventListener("pointermove",C),t.removeEventListener("pointerleave",L),t.removeEventListener("pointercancel",L),document.removeEventListener("visibilitychange",I),S.removeEventListener("change",I),i.signal?.removeEventListener("abort",N),n.destroy(),e.destroy())};if(i.signal?.addEventListener("abort",N,{once:!0}),i.signal?.aborted)throw N(),new DOMException("Cancelled","AbortError");return I(),{canvas:t,media:e,update(t){a=F(a,t),n.configure(a),m=!0,T()},resize(t,e,i){void 0!==i&&n.setPixelRatio(i),s=Math.max(2,t),o=Math.max(2,e),m=!0,T()},pause(t=!0){f=t,I()},async seek(t){u=Math.max(0,t),await e.seek(u),n.invalidate(),m=!0,T()},redraw(){n.invalidate(),m=!0,T()},get time(){return A?.currentTime??u},get settings(){return y(a)},get motionTime(){return g},get paused(){return f||S.matches},setAdaptive(t){v=t,b=k=w=0},setBudget(t){n.setBudget(t),i.onQualityChange?.(n.maxCells),m=!0,T()},get pixelRatio(){return n.pixelRatio},get maxCells(){return n.maxCells},get capabilities(){return n.capabilities},destroy:N}}var ct={Standard:()=>import("figlet/fonts/Standard"),Slant:()=>import("figlet/fonts/Slant"),Small:()=>import("figlet/fonts/Small"),Big:()=>import("figlet/fonts/Big"),Banner:()=>import("figlet/fonts/Banner"),Block:()=>import("figlet/fonts/Block"),Bubble:()=>import("figlet/fonts/Bubble"),Digital:()=>import("figlet/fonts/Digital"),Doom:()=>import("figlet/fonts/Doom"),Lean:()=>import("figlet/fonts/Lean"),Mini:()=>import("figlet/fonts/Mini"),Script:()=>import("figlet/fonts/Script"),Shadow:()=>import("figlet/fonts/Shadow"),Speed:()=>import("figlet/fonts/Speed"),Starwars:()=>import("figlet/fonts/Star Wars"),Stop:()=>import("figlet/fonts/Stop"),Straight:()=>import("figlet/fonts/Straight"),Thin:()=>import("figlet/fonts/Thin"),ThreeD:()=>import("figlet/fonts/3-D"),Univers:()=>import("figlet/fonts/Univers"),Wavy:()=>import("figlet/fonts/Wavy")},mt=Object.keys(ct);async function ft(t,e="Standard",i="#ffffff"){if(!Object.prototype.hasOwnProperty.call(ct,e))throw new Error("Unknown text font.");const{default:a}=await import("figlet/browser"),s=await ct[e]();a.parseFont(e,s.default),a.defaults({fetchFontIfMissing:!1});const r=a.textSync(t.slice(0,120),{font:e}),o=r.split("\n"),n=Math.max(1,...o.map(t=>t.length)),h=Math.max(1,o.length),l=Math.min(1,2048/(9*n)),c=document.createElement("canvas");c.width=Math.ceil(9*n*l+32),c.height=Math.ceil(15*h*l+32);const m=c.getContext("2d");return m.fillStyle="#080808",m.fillRect(0,0,c.width,c.height),m.fillStyle=i,m.font=15*l+"px monospace",m.textBaseline="top",o.forEach((t,e)=>m.fillText(t,16,16+15*e*l)),{canvas:c,ascii:r}}var dt={standard:{label:"Classic ASCII",chars:" .:-=+*#%@"},asciify:{label:"Asciify",chars:" .:-=+ASCIIFY#@"},minimal:{label:"Minimal",chars:" .:+"},detailed:{label:"Detailed",chars:" .,:;i1tfLCG08@"},letters:{label:"Letters",chars:" .ilLCFTYASMW"},technical:{label:"Technical",chars:" .:;>_/[{}]=+*#@$"},blocks:{label:"Tonal blocks",chars:" ░▒▓█"},braille:{label:"Braille",chars:" ⠁⠃⠇⡇⣇⣧⣷⣿"}},ut=dt;export{g as BLEND_MODES,dt as CHARACTER_SETS,M as DEFAULT_STUDIO_SETTINGS,u as DITHER_ALGORITHMS,ut as STUDIO_CHARACTER_SETS,h as STUDIO_CURVE_CHANNELS,t as STUDIO_HOVERS,P as STUDIO_LOOKS,e as STUDIO_MOTIONS,p as STUDIO_PALETTES,d as STUDIO_STYLES,mt as STUDIO_TEXT_FONTS,f as createStudioCurveLookup,at as createStudioRenderer,ft as createStudioText,nt as exportStudio,rt as loadStudioMedia,ht as mountStudio,lt as mountStudioMedia,c as normalizeStudioCurve,m as normalizeStudioCurves,y as normalizeStudioSettings,S as parseStudioSettings,R as restyleStudio,k as serializeStudioSettings,A as studioCrop,E as studioDimensions,T as studioGrid,I as studioLook,$ as studioSourceSize,F as updateStudioSettings};//# sourceMappingURL=studio.js.map
|
|
@@ -27,7 +27,7 @@ export async function createComposition(
|
|
|
27
27
|
async function exportComposition(format: StudioExportFormat, cancellation?: AbortSignal) {
|
|
28
28
|
// Snapshot before loading another media instance. Export never seeks the
|
|
29
29
|
// live preview or picks up slider edits made while encoding.
|
|
30
|
-
const frozen =
|
|
30
|
+
const frozen = player.settings;
|
|
31
31
|
const time = player.time;
|
|
32
32
|
const motionTime = player.motionTime;
|
|
33
33
|
const referenceWidth = canvas.width / player.pixelRatio;
|
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: "4.
|
|
5
|
+
tested-engine: "4.6.0"
|
|
6
6
|
updated: "2026-10-07"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Asciify Engine
|
|
10
10
|
|
|
11
|
-
Use the published `asciify-engine` npm package for browser canvas rendering. Tested against **4.
|
|
11
|
+
Use the published `asciify-engine` npm package for browser canvas rendering. Tested against **4.6.0**. Check the application's installed version and its public types before using newer options; a local checkout can contain unpublished changes.
|
|
12
12
|
|
|
13
13
|
- Agent entry: https://asciify.org/skill (redirects to this Markdown document).
|
|
14
14
|
- Playground: https://asciify.org/editor
|
|
@@ -147,3 +147,7 @@ Legacy `CHARSETS`, `ART_STYLE_PRESETS`, `CHARSET_SEQUENCES`, `LIVING_STYLE_PRESE
|
|
|
147
147
|
## Fine dither and creative controls (4.2)
|
|
148
148
|
|
|
149
149
|
Studio adds `hex`, `led`, and `cmyk` render styles, directional/radial dither patterns, additional palettes, luminance mapping, RGB split, sharpening, and adjustable still-image motion strength. Read [studio-workspace.md](references/studio-workspace.md#fine-detail-and-controls-42) for exact options, density budgets and preview/export consistency. These are local Canvas/WebGL effects, not AI generation or a claim of parity with every competing catalog.
|
|
150
|
+
|
|
151
|
+
From 4.5, `dither.algorithm: 'blue-noise'` uses a precomputed dispersed threshold tile, separate from white `noise`. Studio `color` also accepts `blackPoint`, `whitePoint`, `gamma`, `shadows` and `highlights` to shape detail before conversion. All are neutral by default. Read [tonal detail and blue noise](references/studio-workspace.md#tonal-detail-and-blue-noise-45) before adding these controls; they belong to `/studio`, not core `AsciiOptions`.
|
|
152
|
+
|
|
153
|
+
From 4.6, Studio adds `color.curves` (RGB, red, green, blue) and optional edge-preserving `color.denoise`. `player.settings` returns a detached snapshot for saving or exporting after updates. Read [channel curves and source noise](references/studio-workspace.md#channel-curves-and-source-noise-46) for point limits, update semantics and the processing budget. Do not turn noise reduction on by default or apply it again to the already-rendered characters.
|
|
@@ -40,7 +40,7 @@ Start with `normalizeStudioSettings({ ... })`, `DEFAULT_STUDIO_SETTINGS`, or `st
|
|
|
40
40
|
- `aspectRatio`: `original`, `16:9`, `9:16`, `1:1`, `4:3`, `3:4`, `21:9`. `studioDimensions` resolves dimensions from the source and rotation.
|
|
41
41
|
- `crop`: normalized `x`/`y` anchor, `zoom` 1–5, rotation in 90-degree steps. Cover framing fills the output.
|
|
42
42
|
- `backdrop`: `solid`, `transparent`, `source`, `blurred`, or `gradient`; `color`, `color2`, `opacity`, `blur`. A wallpaper look is an opt-in composition, not an operating-system wallpaper installer.
|
|
43
|
-
- `color`: brightness, contrast, saturation, grayscale, tint amount/color and blend mode. Tint and lights retain the artwork alpha rather than filling empty glyph cells.
|
|
43
|
+
- `color`: brightness, contrast, saturation, grayscale, tint amount/color and blend mode. From 4.5, input black/white points, gamma, shadows and highlights are also available. Tint and lights retain the artwork alpha rather than filling empty glyph cells.
|
|
44
44
|
- `dither`: algorithm, palette/custom colors, amount, scale, threshold, pattern motion (`none`, `drift`, `shimmer`) and speed. Diffusion and ordered patterns differ; animated thresholds can shimmer intentionally.
|
|
45
45
|
- `mask`: enable/invert and a list of rectangle, ellipse, or brush shapes. Coordinates are normalized to the output canvas. Masks are bounded to 64 shapes and 2,048 total brush points. Masking affects the artwork; the backdrop remains visible.
|
|
46
46
|
- `lights`: at most four colored radial lights with normalized position, radius, and intensity. This is 2D illumination, not physically based material lighting.
|
|
@@ -185,3 +185,57 @@ Stationary artwork, masks, lights, backdrops and character bloom are cached whil
|
|
|
185
185
|
Use `STUDIO_HOVERS` and `STUDIO_MOTIONS` to show all eleven hovers and ten still-image motions, plus Off, grouped by behavior. New hover IDs are `etch`, `elastic`, `rake`; new motion IDs are `parallax`, `weave`, `print`, `trace`. `hover.radius` and `hover.strength` are independent of `motion.speed` and `motion.amount`. All remain serialized in look links and saved projects. A static photo needs no video input or AI service to animate.
|
|
186
186
|
|
|
187
187
|
Example: `player.update({ motion: { type: 'trace', speed: 1, amount: .7 }, hover: { effect: 'etch', radius: .45, strength: .65 } })`. Tone and character choices remain yours. See [effect behaviors and combinations](studio-effects.md#catalogs-and-useful-combinations-44). Do not run several looping thumbnail canvases just to display this catalog; apply the selected treatment to one shared preview.
|
|
188
|
+
|
|
189
|
+
## Tonal detail and blue noise (4.5)
|
|
190
|
+
|
|
191
|
+
Use `color.gamma` to lift midtones (above 1) or deepen them (below 1), from 0.25 to 4. `color.shadows` and `color.highlights` range from −1 to 1; positive lifts that region, negative darkens it. They form a monotone curve with fixed black, middle and white anchors. This is a bounded tonal curve, not a freely editable per-channel curve graph. It cannot recover clipped source detail.
|
|
192
|
+
|
|
193
|
+
`color.blackPoint` (0–0.99, default 0) and `color.whitePoint` (default 1) map the input range before gamma. White is normalized to at least 1/255 above black. These controls apply equally to all 18 renderers before dither/character conversion, preserve source alpha, and round-trip in settings. Neutral settings skip the transform. The 256-entry lookup is rebuilt on configuration changes and reused for source frames. Reset with `{ blackPoint: 0, whitePoint: 1, gamma: 1, shadows: 0, highlights: 0 }`.
|
|
194
|
+
|
|
195
|
+
`blue-noise` uses a deterministic 64×64 toroidal rank tile generated offline with void-and-cluster relaxation. It suppresses low-frequency clumping; it is not white noise with a different label. A palette-pair projection controls coverage, preserving flat grayscale means for a black/white palette at full strength. Arbitrary color palettes still approximate the source. The original palette uses web-safe channel quantization. The rank tile is 8 KiB in memory, loads only with `/studio`, and has no network request or runtime generator.
|
|
196
|
+
|
|
197
|
+
Keep `dither.motion: 'none'` for a stationary pattern. `drift`, direction and speed translate the matrix; `shimmer` modulates tone. As with Bayer, stable thresholds do not guarantee flicker-free source video—changing source tones can change the quantized result. Start around a 320×180 sampling grid for animated artwork, then measure the target device. More detail is an explicit CPU tradeoff.
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
const player = await mountStudio(canvas, '/portrait.jpg', {
|
|
201
|
+
settings: {
|
|
202
|
+
style: 'dither',
|
|
203
|
+
color: { gamma: 1.12, shadows: .15, highlights: -.12 },
|
|
204
|
+
dither: { algorithm: 'blue-noise', palette: 'gray8', scale: 3 },
|
|
205
|
+
motion: { type: 'trace', speed: .7, amount: .25 },
|
|
206
|
+
},
|
|
207
|
+
maxDimension: 960,
|
|
208
|
+
maxCells: 65536,
|
|
209
|
+
});
|
|
210
|
+
// Use the same player.settings for live embedding and independent export.
|
|
211
|
+
// On unmount: player.destroy().
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Channel curves and source noise (4.6)
|
|
215
|
+
|
|
216
|
+
`color.curves` accepts `rgb`, `red`, `green` and `blue` arrays of `[input, output]` points in 0–1. Each curve holds up to 16 points including input endpoints 0 and 1. Missing endpoints use the identity; coordinates are clamped, input positions quantize to 1/255, repeated inputs retain the last valid point and points are sorted. Output points may reverse direction for an intentional inverted/solarized treatment. Shape-preserving cubic interpolation avoids overshoot between points. `createStudioCurveLookup(points)` returns the same 256 samples used by the renderer for a custom graph; `normalizeStudioCurve` and `STUDIO_CURVE_CHANNELS` are public helpers.
|
|
217
|
+
|
|
218
|
+
Incremental `player.update({color:{curves:{red: [...]}}})` preserves the other channels. Each supplied channel array replaces that channel. Reset a channel with `[[0,0],[1,1]]`; reset all with `normalizeStudioCurves({})`. Keep input ordering and show precise values in a curve editor; do not call an arbitrary point graph a fixed shadow/highlight control.
|
|
219
|
+
|
|
220
|
+
`color.denoise` is 0–1, default 0. It performs a bounded 3×3 edge-preserving filter on sampled source pixels, preserving alpha and excluding hidden transparent colors. Use it for small source noise; strong settings can remove intentional texture and do not recover clipped or missing detail. It is not generative restoration or temporal video denoising.
|
|
221
|
+
|
|
222
|
+
Processing order: crop/sample → reduce noise → brightness/contrast/saturation/grayscale → levels/gamma/shadow/highlight tone → RGB curve → individual channel curves → style/dither → composition/finish. Use `colorMode:'source'` to retain the resulting colors; accent and gray modes use the adjusted source tones for their own ink mapping. The backdrop remains its existing source/background pipeline.
|
|
223
|
+
|
|
224
|
+
Curves compile to three 256-entry tables only when configured. Noise reduction uses one bounded source copy; static images reuse their processed pixels during motion/hover. Video must process changed source frames, so dense one-pixel sampling adds CPU cost. Start with the default 12,000-cell budget or measure a larger budget on the target device. Neutral settings skip both processing paths; root/core/hover entry points do not load them.
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
player.update({
|
|
228
|
+
color: {
|
|
229
|
+
denoise: .25,
|
|
230
|
+
curves: {
|
|
231
|
+
rgb: [[0,0], [.25,.2], [.75,.8], [1,1]],
|
|
232
|
+
blue: [[0,.04], [1,.95]],
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
});
|
|
236
|
+
const saved = serializeStudioSettings(player.settings);
|
|
237
|
+
// For export, snapshot player.settings once before async media loading.
|
|
238
|
+
// The independent export renderer applies the same source controls.
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
`player.settings` is an owned snapshot, not a live mutable reference. Use `player.update()` to edit. Reuse it for JSON, independent PNG/video export and restoring a live component. Check installed version before using this getter (4.6+).
|
|
@@ -62,3 +62,10 @@ This requested minor version contains breaking API removals: `CHARSETS`, `ART_ST
|
|
|
62
62
|
## 4.4
|
|
63
63
|
|
|
64
64
|
Adds Emboss, Elastic and Rake hover; Parallax, Woven Flow, Print Shift and Contour Light motion. Existing IDs, defaults, saved projects and v1 settings remain valid. `STUDIO_HOVERS` and `STUDIO_MOTIONS` are now shared public catalogs in `/studio` and `/hover`; generate selection controls from them. The four new ambient IDs are also accepted by core `animationStyle`. Keep only one owner for motion.
|
|
65
|
+
### 4.5 tonal controls and blue noise
|
|
66
|
+
|
|
67
|
+
Adds the `blue-noise` dither algorithm and optional Studio `color.blackPoint`, `whitePoint`, `gamma`, `shadows`, and `highlights` fields. Existing render defaults and existing dither output are unchanged. The serialized settings version remains 1; older engines will ignore these new choices, so check the installed package before using them. Refresh the agent skill separately from the npm dependency. These are Studio features, not additional core `AsciiOptions`.
|
|
68
|
+
|
|
69
|
+
### 4.6 channel curves and source noise
|
|
70
|
+
|
|
71
|
+
Adds Studio `color.curves` and `color.denoise` with neutral defaults. Curves support independently editable RGB/red/green/blue control points; incremental updates merge channels, replacing only supplied point arrays. `player.settings` returns a detached current snapshot for persistence/export. Settings version remains 1; older packages ignore the new fields and do not expose the getter. Read the installed types, update the runtime dependency and refresh the agent skill together when adopting these APIs. Root/core/hover behavior is unchanged.
|