react-video-ascii 1.1.0 → 1.2.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 CHANGED
@@ -77,6 +77,7 @@ const sources = ['/video1.mp4', '/video2.mp4'];
77
77
  | `clickEffect` | `boolean \| ClickEffectOptions` | `true` | — | Click effects. `true` uses defaults. |
78
78
  | `revealEffect` | `boolean \| RevealEffectOptions` | `false` | — | Reveal animation on load. `true` uses defaults. |
79
79
  | `cropFocus` | `'left' \| 'center' \| 'right'` | `'center'` | — | Determines where to anchor the cropping around. |
80
+ | `maxDpr` | `number` | *(uncapped)* | `1–4` | Caps the device-pixel ratio the canvas renders at (renders normally at sharpest res). |
80
81
  | `className` | `string` | — | — | CSS class on the outer container. |
81
82
 
82
83
  ---
@@ -1,3 +1,3 @@
1
1
  import { Props } from '../lib/ascii-props';
2
- declare function VideoAscii({ src, videoMode, numColsRaw, brightnessRaw, saturationRaw, bgOpacityRaw, revealEffect, chars, mouseEffect, clickEffect, charMode, className, cropFocus, }: Props): import("react/jsx-runtime").JSX.Element;
2
+ declare function VideoAscii({ src, videoMode, numColsRaw, brightnessRaw, saturationRaw, bgOpacityRaw, revealEffect, chars, mouseEffect, clickEffect, charMode, className, cropFocus, maxDpr: maxDprRaw, }: Props): import("react/jsx-runtime").JSX.Element;
3
3
  export default VideoAscii;
@@ -33,6 +33,7 @@ export interface Props {
33
33
  charMode?: 'shape' | 'luminance';
34
34
  className?: string;
35
35
  cropFocus?: 'left' | 'center' | 'right';
36
+ maxDpr?: number;
36
37
  }
37
38
  export interface ParsedProps {
38
39
  numCols: number;
@@ -59,5 +60,6 @@ export interface ParsedProps {
59
60
  revealType: string;
60
61
  revealDuration: number;
61
62
  revealEffectFlag: number;
63
+ maxDpr: number;
62
64
  }
63
- export declare function parseProps(numColsRaw: number, brightnessRaw: number, saturationRaw: number, bgOpacityRaw: number, mouseEffect: boolean | MouseEffectOptions, clickEffect: boolean | ClickEffectOptions, revealEffect: boolean | RevealEffectOptions): ParsedProps;
65
+ export declare function parseProps(numColsRaw: number, brightnessRaw: number, saturationRaw: number, bgOpacityRaw: number, mouseEffect: boolean | MouseEffectOptions, clickEffect: boolean | ClickEffectOptions, revealEffect: boolean | RevealEffectOptions, maxDprRaw?: number): ParsedProps;
@@ -8,8 +8,11 @@ interface ClickEffectRefs {
8
8
  clickBrightnessRef: {
9
9
  current: number;
10
10
  };
11
+ pixelScaleRef: {
12
+ current: number;
13
+ };
11
14
  }
12
- export declare function createClickEffect({ clickEnabledRef, clickSpeedRef, clickBrightnessRef, }: ClickEffectRefs): {
15
+ export declare function createClickEffect({ clickEnabledRef, clickSpeedRef, clickBrightnessRef, pixelScaleRef, }: ClickEffectRefs): {
13
16
  handleClick(e: MouseEvent, canvas: HTMLCanvasElement): void;
14
17
  tick(gl: WebGL2RenderingContext, canvas: HTMLCanvasElement, ripplePositionsLoc: WebGLUniformLocation | null, rippleRadiiLoc: WebGLUniformLocation | null, rippleBrightnessesLoc: WebGLUniformLocation | null): void;
15
18
  };
@@ -20,6 +20,7 @@ export interface GLResources {
20
20
  p1ExponentLoc: WebGLUniformLocation | null;
21
21
  p1CropOffsetLoc: WebGLUniformLocation | null;
22
22
  p1CropScaleLoc: WebGLUniformLocation | null;
23
+ p1GridOffsetLoc: WebGLUniformLocation | null;
23
24
  revealEffectFlagLoc: WebGLUniformLocation | null;
24
25
  mouseEffectFlagLoc: WebGLUniformLocation | null;
25
26
  clickEffectFlagLoc: WebGLUniformLocation | null;
@@ -45,5 +46,6 @@ export interface GLResources {
45
46
  gridSizeLoc: WebGLUniformLocation | null;
46
47
  cropOffsetLoc: WebGLUniformLocation | null;
47
48
  cropScaleLoc: WebGLUniformLocation | null;
49
+ gridOffsetLoc: WebGLUniformLocation | null;
48
50
  }
49
51
  export declare function createGLResources(gl: WebGL2RenderingContext): GLResources | null;
@@ -0,0 +1,7 @@
1
+ export interface DevicePixelSize {
2
+ width: number;
3
+ height: number;
4
+ cssWidth: number;
5
+ cssHeight: number;
6
+ }
7
+ export declare function observeDevicePixelSize(el: Element, cb: (size: DevicePixelSize) => void): () => void;
@@ -13,7 +13,7 @@ interface ScatterRefs {
13
13
  };
14
14
  }
15
15
  export declare function createScatterEffect({ scatterEnabledRef, mouseRadiusRef, durationRef, scatterCharsRef, }: ScatterRefs): {
16
- setup(gl: WebGL2RenderingContext, cols: number, rows: number, cw: number, ch: number, scatterStateTexture: WebGLTexture): void;
16
+ setup(gl: WebGL2RenderingContext, cols: number, rows: number, cw: number, ch: number, offX: number, offY: number, scatterStateTexture: WebGLTexture): void;
17
17
  handleMouseMove(x: number, y: number, t: number): void;
18
18
  handleMouseLeave(): void;
19
19
  reset(gl: WebGL2RenderingContext): void;
@@ -13,7 +13,7 @@ interface SpreadRefs {
13
13
  };
14
14
  }
15
15
  export declare function createSpreadEffect({ spreadEnabledRef, scatterCharsRef, spreadExpandDurationRef, spreadSpeedRef, }: SpreadRefs): {
16
- setup(gl: WebGL2RenderingContext, cols: number, rows: number, cw: number, ch: number, spreadStateTexture: WebGLTexture): void;
16
+ setup(gl: WebGL2RenderingContext, cols: number, rows: number, cw: number, ch: number, offX: number, offY: number, spreadStateTexture: WebGLTexture): void;
17
17
  handleClick(e: MouseEvent, canvas: HTMLCanvasElement): void;
18
18
  tick(gl: WebGL2RenderingContext): void;
19
19
  };
@@ -51,35 +51,36 @@ function a(e, t, n) {
51
51
  //#endregion
52
52
  //#region src/lib/ascii-props.ts
53
53
  var o = " `.',-_:!;|\"~+^lr[](\\/L)>t<v=Tz?icf1{sIxY*jJno}CZyVwmSXRqM$O%#9&NW0Q@";
54
- function s(e, t, n, r, i, a, o) {
55
- let s = !!i, c = typeof i == "object" ? i : {}, l = c.style ?? "brighten", u = s && l !== "scatter", d = s && l === "scatter", f = c.scatterChars ?? "->o", p = c.trailLen ?? 15, m = c.trailDecay ?? 10, h = c.duration ?? 1, g = c.radius ?? (l === "scatter" ? .05 : .08), _ = c.brightness ?? 2, v = !!a, y = typeof a == "object" ? a : {}, b = y.style ?? "ripple", x = v && b !== "spread", S = v && b === "spread", C = y.brightness ?? 1.1, w = y.speed ?? 2, T = y.spreadExpandDuration ?? 1.5, E = y.spreadSpeed ?? 7.5, D = !!o, O = typeof o == "object" ? o : {}, k = O.type ?? "random", A = O.duration ?? .4, j = Math.max(20, Math.min(350, Math.round(e))), M = Math.max(0, Math.min(2, t)), N = Math.max(0, Math.min(2, n)), P = Math.max(0, Math.min(1, r));
56
- A = Math.max(.1, Math.min(4, A)), p = Math.max(0, Math.min(30, Math.round(p))), m = Math.max(1, Math.min(15, m)), h = Math.max(.1, Math.min(4, h)), g = Math.max(.03, Math.min(.2, g)), _ = Math.max(.2, Math.min(5, _)), C = Math.max(1.05, Math.min(2, C)), w = Math.max(.5, Math.min(4, w)), T = Math.max(.5, Math.min(5, T)), E = Math.max(.5, Math.min(10, E));
57
- let F;
58
- return F = D ? k === "diagonal" ? 1 : k === "radial" ? 2 : 3 : 0, {
59
- numCols: j,
60
- brightness: M,
61
- saturation: N,
62
- bgOpacity: P,
63
- mouseEnabled: s,
64
- mouseStyle: l,
65
- brightenEnabled: u,
66
- scatterEnabled: d,
67
- scatterChars: f,
68
- trailLen: p,
69
- trailDecay: m,
70
- duration: h,
71
- mouseRadius: g,
72
- mouseBrightness: _,
73
- clickEnabled: x,
74
- clickBrightness: C,
75
- clickSpeed: w,
76
- spreadEnabled: S,
77
- spreadExpandDuration: T,
78
- spreadSpeed: E,
79
- revealEnabled: D,
80
- revealType: k,
81
- revealDuration: A,
82
- revealEffectFlag: F
54
+ function s(e, t, n, r, i, a, o, s) {
55
+ let c = !!i, l = typeof i == "object" ? i : {}, u = l.style ?? "brighten", d = c && u !== "scatter", f = c && u === "scatter", p = l.scatterChars ?? "->o", m = l.trailLen ?? 15, h = l.trailDecay ?? 10, g = l.duration ?? 1, _ = l.radius ?? (u === "scatter" ? .05 : .08), v = l.brightness ?? 2, y = !!a, b = typeof a == "object" ? a : {}, x = b.style ?? "ripple", S = y && x !== "spread", C = y && x === "spread", w = b.brightness ?? 1.1, T = b.speed ?? 2, E = b.spreadExpandDuration ?? 1.5, D = b.spreadSpeed ?? 7.5, O = !!o, k = typeof o == "object" ? o : {}, A = k.type ?? "random", j = k.duration ?? .4, M = Math.max(20, Math.min(350, Math.round(e))), N = Math.max(0, Math.min(2, t)), P = Math.max(0, Math.min(2, n)), F = Math.max(0, Math.min(1, r));
56
+ j = Math.max(.1, Math.min(4, j)), m = Math.max(0, Math.min(30, Math.round(m))), h = Math.max(1, Math.min(15, h)), g = Math.max(.1, Math.min(4, g)), _ = Math.max(.03, Math.min(.2, _)), v = Math.max(.2, Math.min(5, v)), w = Math.max(1.05, Math.min(2, w)), T = Math.max(.5, Math.min(4, T)), E = Math.max(.5, Math.min(5, E)), D = Math.max(.5, Math.min(10, D));
57
+ let I = s === void 0 ? Infinity : Math.max(1, Math.min(4, s)), L;
58
+ return L = O ? A === "diagonal" ? 1 : A === "radial" ? 2 : 3 : 0, {
59
+ numCols: M,
60
+ brightness: N,
61
+ saturation: P,
62
+ bgOpacity: F,
63
+ mouseEnabled: c,
64
+ mouseStyle: u,
65
+ brightenEnabled: d,
66
+ scatterEnabled: f,
67
+ scatterChars: p,
68
+ trailLen: m,
69
+ trailDecay: h,
70
+ duration: g,
71
+ mouseRadius: _,
72
+ mouseBrightness: v,
73
+ clickEnabled: S,
74
+ clickBrightness: w,
75
+ clickSpeed: T,
76
+ spreadEnabled: C,
77
+ spreadExpandDuration: E,
78
+ spreadSpeed: D,
79
+ revealEnabled: O,
80
+ revealType: A,
81
+ revealDuration: j,
82
+ revealEffectFlag: L,
83
+ maxDpr: I
83
84
  };
84
85
  }
85
86
  //#endregion
@@ -95,7 +96,7 @@ function l(e, t, n) {
95
96
  }
96
97
  //#endregion
97
98
  //#region src/shaders/vertex.glsl
98
- var u = "#version 300 es\n\nin vec2 a_position;\n\nvoid main() {\n gl_Position = vec4(a_position, 0.0, 1.0);\n}", d = "#version 300 es\n\nprecision highp float;\nprecision highp usampler2D;\n\nuniform int u_revealEffectFlag;\nuniform bool u_videoMode;\n\nuniform float u_revealProgress;\nuniform float u_brightness;\nuniform float u_saturation;\nuniform float u_bgOpacity;\n\nuniform bool u_mouseEffect;\n#define MOUSE_TRAIL_LEN 30 \nuniform vec2 u_mousePositions[MOUSE_TRAIL_LEN];\nuniform float u_mouseLifeFracs[MOUSE_TRAIL_LEN]; \nuniform float u_mouseRadius;\nuniform float u_mouseBrightness;\n\nuniform bool u_clickEffect;\n#define MAX_RIPPLES 10\nuniform vec2 u_ripplePositions[MAX_RIPPLES];\nuniform float u_rippleRadii[MAX_RIPPLES]; \nuniform float u_rippleBrightnesses[MAX_RIPPLES]; \n\nuniform bool u_scatterEffect;\nuniform usampler2D u_scatterStateTexture; \nuniform sampler2D u_scatterAtlas; \nuniform float u_scatterNumChars;\n\nuniform bool u_spreadEffect;\nuniform usampler2D u_spreadStateTexture;\n\nuniform bool u_shapeMatching;\n\nuniform sampler2D u_texture;\nuniform sampler2D u_atlas;\nuniform usampler2D u_fboTexture;\nuniform vec2 u_resolution;\nuniform vec2 u_cellsize;\nuniform float u_numChars;\nuniform vec2 u_gridSize;\nuniform vec2 u_cropOffset;\nuniform vec2 u_cropScale;\n\nout vec4 fragColor;\n\nfloat hash(vec2 p) {\n vec3 p3 = fract(vec3(p.xyx) * 0.1031); \n p3 += dot(p3, p3.yzx + 33.33); \n return fract((p3.x + p3.y) * p3.z); \n}\n\nvec3 rgb2hsl(vec3 c) {\n float maxC = max(c.r, max(c.g, c.b));\n float minC = min(c.r, min(c.g, c.b));\n float l = (maxC + minC) * 0.5;\n float d = maxC - minC;\n float h = 0.0, s = 0.0;\n if (d > 0.0) {\n s = d / (1.0 - abs(2.0 * l - 1.0));\n if (maxC == c.r) h = mod((c.g - c.b) / d, 6.0) / 6.0;\n else if (maxC == c.g) h = ((c.b - c.r) / d + 2.0) / 6.0;\n else h = ((c.r - c.g) / d + 4.0) / 6.0;\n }\n return vec3(h, s, l);\n}\n\nvec3 hsl2rgb(vec3 c) {\n float h = c.x, s = c.y, l = c.z;\n float a = s * (1.0 - abs(2.0 * l - 1.0));\n vec3 rgb = clamp(abs(mod(h * 6.0 + vec3(0.0, 4.0, 2.0), 6.0) - 3.0) - 1.0, 0.0, 1.0);\n return l + a * (rgb - 0.5);\n}\n\nvoid main() {\n vec2 fragCoord = vec2(gl_FragCoord.x, u_resolution.y - gl_FragCoord.y); \n vec2 cellCoord = floor(fragCoord / u_cellsize);\n\n if (u_revealEffectFlag == 1) {\n \n float revealThreshold = (cellCoord.x + cellCoord.y) / (u_gridSize.x + u_gridSize.y - 2.0);\n if (revealThreshold > u_revealProgress) {\n fragColor = vec4(0.0, 0.0, 0.0, 1.0);\n return;\n }\n } else if (u_revealEffectFlag == 2) {\n float dist = length(cellCoord / u_gridSize - vec2(0.5));\n float revealThreshold = dist / 0.7071; \n if (revealThreshold > u_revealProgress) {\n fragColor = vec4(0.0, 0.0, 0.0, 1.0);\n return;\n }\n } else if (u_revealEffectFlag == 3) {\n float revealThreshold = hash(cellCoord);\n if (revealThreshold > u_revealProgress) {\n fragColor = vec4(0.0, 0.0, 0.0, 1.0);\n return;\n }\n }\n\n vec2 cellCenter = (cellCoord + 0.5) * u_cellsize; \n \n vec2 rawUV = u_videoMode ? (fragCoord / u_resolution) : (cellCenter / u_resolution);\n vec2 sampleUV = u_cropOffset + rawUV * u_cropScale;\n\n vec3 cellColor = texture(u_texture, sampleUV).rgb;\n float luminosity = dot(cellColor, vec3(0.299, 0.587, 0.114)); \n vec3 hsl = rgb2hsl(cellColor);\n hsl.z = clamp(hsl.z * u_brightness, 0.0, 1.0);\n hsl.y = clamp(hsl.y * u_saturation, 0.0, 1.0);\n cellColor = hsl2rgb(hsl);\n\n vec2 withinCellPos = fract(fragCoord / u_cellsize);\n\n \n float glyphMask = 0.0;\n if (!u_videoMode) {\n uint charInd;\n if (u_shapeMatching) {\n charInd = texelFetch(u_fboTexture, ivec2(cellCoord), 0).r;\n } else {\n charInd = uint(floor(luminosity * (u_numChars - 1.0)));\n }\n float atlasU = (float(charInd) + withinCellPos.x) / u_numChars;\n float atlasV = withinCellPos.y;\n glyphMask = texture(u_atlas, vec2(atlasU, atlasV)).r;\n }\n\n vec3 bgColor = cellColor * u_bgOpacity;\n\n bool scatterHit = false;\n vec3 scatterColor = vec3(0.0);\n if (u_scatterEffect) {\n uint state = texelFetch(u_scatterStateTexture, ivec2(cellCoord), 0).r;\n if (state > 0u) {\n int idx = int(state) - 1;\n float su = (float(idx) + withinCellPos.x) / u_scatterNumChars;\n float mask = texture(u_scatterAtlas, vec2(su, withinCellPos.y)).r;\n \n vec3 scatterBg = u_videoMode ? cellColor : bgColor;\n scatterColor = mix(scatterBg, vec3(1.0), mask);\n scatterHit = true;\n }\n }\n \n if (!scatterHit && u_spreadEffect) { \n uint state = texelFetch(u_spreadStateTexture, ivec2(cellCoord), 0).r;\n if (state > 0u) {\n int idx = int(state) - 1;\n float su = (float(idx) + withinCellPos.x) / u_scatterNumChars;\n float mask = texture(u_scatterAtlas, vec2(su, withinCellPos.y)).r;\n vec3 scatterBg = u_videoMode ? cellColor : bgColor;\n scatterColor = mix(scatterBg, vec3(1.0), mask);\n scatterHit = true;\n }\n }\n\n vec3 finalColor;\n if (scatterHit) {\n finalColor = scatterColor;\n } else {\n finalColor = u_videoMode ? cellColor : mix(bgColor, cellColor, glyphMask);\n\n if (u_mouseEffect) {\n bool inside = false;\n for (int i = 0; i < MOUSE_TRAIL_LEN; i++) {\n if (u_mouseLifeFracs[i] <= 0.0) {\n continue;\n }\n float r = u_mouseRadius * u_mouseLifeFracs[i];\n if (distance(cellCenter, u_mousePositions[i]) < r) {\n inside = true;\n break;\n }\n }\n if (inside) {\n finalColor = clamp(finalColor * u_mouseBrightness, 0.0, 1.0);\n }\n }\n\n if (u_clickEffect) {\n float boost = 1.0;\n for (int i = 0; i < MAX_RIPPLES; i++) {\n if (u_rippleBrightnesses[i] <= 1.0) {\n continue;\n }\n if (distance(cellCenter, u_ripplePositions[i]) < u_rippleRadii[i]) {\n boost *= u_rippleBrightnesses[i];\n }\n }\n if (boost > 1.0) {\n finalColor = clamp(finalColor * boost, 0.0, 1.0);\n }\n }\n }\n\n fragColor = vec4(finalColor, 1.0);\n}", f = "#version 300 es\n\nprecision highp float;\nprecision highp usampler2D;\n\nuniform sampler2D u_texture;\nuniform vec2 u_resolution;\nuniform vec2 u_cellsize;\nuniform int u_circleN;\nuniform sampler2D u_charVectors;\nuniform int u_numCharsInt;\nuniform float u_shapeExponent;\nuniform vec2 u_cropOffset;\nuniform vec2 u_cropScale;\n\nout uvec4 fragCharInd;\n\nvoid main() {\n \n ivec2 cellCoord = ivec2(floor(gl_FragCoord.xy));\n\n const vec2 CIRCLES[6] = vec2[6](\n vec2(0.25, 0.25), vec2(0.75, 0.25),\n vec2(0.25, 0.50), vec2(0.75, 0.50),\n vec2(0.25, 0.75), vec2(0.75, 0.75)\n );\n vec2 radiusUV = vec2(u_cellsize.x / 5.0) / u_resolution * u_cropScale; \n\n float sv[6];\n for (int ci = 0; ci < 6; ci++) {\n \n vec2 centerUV = u_cropOffset + (vec2(cellCoord) + CIRCLES[ci]) * u_cellsize / u_resolution * u_cropScale;\n float total = 0.0;\n int count = 0;\n for (int dx = -u_circleN; dx <= u_circleN; dx++) {\n for (int dy = -u_circleN; dy <= u_circleN; dy++) {\n if (dx*dx + dy*dy <= u_circleN*u_circleN) {\n vec2 sampleUV = centerUV + vec2(float(dx), float(dy)) * radiusUV / float(u_circleN);\n vec3 sc = texture(u_texture, sampleUV).rgb;\n total += dot(sc, vec3(0.299, 0.587, 0.114));\n count++;\n }\n }\n }\n \n sv[ci] = count > 0 ? total / float(count) : 0.0;\n }\n\n float maxVal = 0.0;\n for (int d = 0; d < 6; d++) maxVal = max(maxVal, sv[d]);\n if (maxVal > 0.0) {\n for (int d = 0; d < 6; d++) sv[d] = pow(sv[d] / maxVal, u_shapeExponent) * maxVal;\n }\n\n \n uint bestChar = 0u;\n float bestDist = 1e10;\n for (int i = 0; i < u_numCharsInt; i++) {\n vec4 r0 = texelFetch(u_charVectors, ivec2(i, 0), 0);\n vec4 r1 = texelFetch(u_charVectors, ivec2(i, 1), 0);\n float dist = 0.0;\n float diffs[6] = float[6](\n sv[0] - r0.r, sv[1] - r0.g, sv[2] - r0.b, sv[3] - r0.a,\n sv[4] - r1.r, sv[5] - r1.g\n );\n for (int d = 0; d < 6; d++) {\n dist += diffs[d] * diffs[d];\n }\n if (dist < bestDist) { \n bestDist = dist; bestChar = uint(i); \n }\n }\n\n fragCharInd = uvec4(bestChar, 0u, 0u, 0u);\n}";
99
+ var u = "#version 300 es\n\nin vec2 a_position;\n\nvoid main() {\n gl_Position = vec4(a_position, 0.0, 1.0);\n}", d = "#version 300 es\n\nprecision highp float;\nprecision highp usampler2D;\n\nuniform int u_revealEffectFlag;\nuniform bool u_videoMode;\n\nuniform float u_revealProgress;\nuniform float u_brightness;\nuniform float u_saturation;\nuniform float u_bgOpacity;\n\nuniform bool u_mouseEffect;\n#define MOUSE_TRAIL_LEN 30 \nuniform vec2 u_mousePositions[MOUSE_TRAIL_LEN];\nuniform float u_mouseLifeFracs[MOUSE_TRAIL_LEN]; \nuniform float u_mouseRadius;\nuniform float u_mouseBrightness;\n\nuniform bool u_clickEffect;\n#define MAX_RIPPLES 10\nuniform vec2 u_ripplePositions[MAX_RIPPLES];\nuniform float u_rippleRadii[MAX_RIPPLES]; \nuniform float u_rippleBrightnesses[MAX_RIPPLES]; \n\nuniform bool u_scatterEffect;\nuniform usampler2D u_scatterStateTexture; \nuniform sampler2D u_scatterAtlas; \nuniform float u_scatterNumChars;\n\nuniform bool u_spreadEffect;\nuniform usampler2D u_spreadStateTexture;\n\nuniform bool u_shapeMatching;\n\nuniform sampler2D u_texture;\nuniform sampler2D u_atlas;\nuniform usampler2D u_fboTexture;\nuniform vec2 u_resolution;\nuniform vec2 u_cellsize;\nuniform float u_numChars;\nuniform vec2 u_gridSize;\nuniform vec2 u_cropOffset;\nuniform vec2 u_cropScale;\nuniform vec2 u_gridOffset;\n\nout vec4 fragColor;\n\nfloat hash(vec2 p) {\n vec3 p3 = fract(vec3(p.xyx) * 0.1031); \n p3 += dot(p3, p3.yzx + 33.33); \n return fract((p3.x + p3.y) * p3.z); \n}\n\nvec3 rgb2hsl(vec3 c) {\n float maxC = max(c.r, max(c.g, c.b));\n float minC = min(c.r, min(c.g, c.b));\n float l = (maxC + minC) * 0.5;\n float d = maxC - minC;\n float h = 0.0, s = 0.0;\n if (d > 0.0) {\n s = d / (1.0 - abs(2.0 * l - 1.0));\n if (maxC == c.r) h = mod((c.g - c.b) / d, 6.0) / 6.0;\n else if (maxC == c.g) h = ((c.b - c.r) / d + 2.0) / 6.0;\n else h = ((c.r - c.g) / d + 4.0) / 6.0;\n }\n return vec3(h, s, l);\n}\n\nvec3 hsl2rgb(vec3 c) {\n float h = c.x, s = c.y, l = c.z;\n float a = s * (1.0 - abs(2.0 * l - 1.0));\n vec3 rgb = clamp(abs(mod(h * 6.0 + vec3(0.0, 4.0, 2.0), 6.0) - 3.0) - 1.0, 0.0, 1.0);\n return l + a * (rgb - 0.5);\n}\n\nvoid main() {\n vec2 fragCoord = vec2(gl_FragCoord.x, u_resolution.y - gl_FragCoord.y); \n vec2 gridCoord = fragCoord - u_gridOffset;\n vec2 cellCoordF = floor(gridCoord / u_cellsize);\n bool inGrid = all(greaterThanEqual(cellCoordF, vec2(0.0))) && all(lessThan(cellCoordF, u_gridSize));\n vec2 cellCoord = clamp(cellCoordF, vec2(0.0), u_gridSize - 1.0);\n\n if (u_revealEffectFlag == 1) {\n \n float revealThreshold = (cellCoord.x + cellCoord.y) / (u_gridSize.x + u_gridSize.y - 2.0);\n if (revealThreshold > u_revealProgress) {\n fragColor = vec4(0.0, 0.0, 0.0, 1.0);\n return;\n }\n } else if (u_revealEffectFlag == 2) {\n float dist = length(cellCoord / u_gridSize - vec2(0.5));\n float revealThreshold = dist / 0.7071; \n if (revealThreshold > u_revealProgress) {\n fragColor = vec4(0.0, 0.0, 0.0, 1.0);\n return;\n }\n } else if (u_revealEffectFlag == 3) {\n float revealThreshold = hash(cellCoord);\n if (revealThreshold > u_revealProgress) {\n fragColor = vec4(0.0, 0.0, 0.0, 1.0);\n return;\n }\n }\n\n vec2 cellCenter = u_gridOffset + (cellCoord + 0.5) * u_cellsize; \n \n vec2 rawUV = u_videoMode ? (fragCoord / u_resolution) : (cellCenter / u_resolution);\n vec2 sampleUV = u_cropOffset + rawUV * u_cropScale;\n\n vec3 cellColor = texture(u_texture, sampleUV).rgb;\n float luminosity = dot(cellColor, vec3(0.299, 0.587, 0.114)); \n vec3 hsl = rgb2hsl(cellColor);\n hsl.z = clamp(hsl.z * u_brightness, 0.0, 1.0);\n hsl.y = clamp(hsl.y * u_saturation, 0.0, 1.0);\n cellColor = hsl2rgb(hsl);\n\n vec2 withinCellPos = fract(gridCoord / u_cellsize);\n\n \n float glyphMask = 0.0;\n if (!u_videoMode && inGrid) {\n uint charInd;\n if (u_shapeMatching) {\n charInd = texelFetch(u_fboTexture, ivec2(cellCoord), 0).r;\n } else {\n charInd = uint(floor(luminosity * (u_numChars - 1.0)));\n }\n float atlasU = (float(charInd) + withinCellPos.x) / u_numChars;\n float atlasV = withinCellPos.y;\n glyphMask = texture(u_atlas, vec2(atlasU, atlasV)).r;\n }\n\n vec3 bgColor = cellColor * u_bgOpacity;\n\n bool scatterHit = false;\n vec3 scatterColor = vec3(0.0);\n if (u_scatterEffect && inGrid) {\n uint state = texelFetch(u_scatterStateTexture, ivec2(cellCoord), 0).r;\n if (state > 0u) {\n int idx = int(state) - 1;\n float su = (float(idx) + withinCellPos.x) / u_scatterNumChars;\n float mask = texture(u_scatterAtlas, vec2(su, withinCellPos.y)).r;\n \n vec3 scatterBg = u_videoMode ? cellColor : bgColor;\n scatterColor = mix(scatterBg, vec3(1.0), mask);\n scatterHit = true;\n }\n }\n \n if (!scatterHit && u_spreadEffect && inGrid) { \n uint state = texelFetch(u_spreadStateTexture, ivec2(cellCoord), 0).r;\n if (state > 0u) {\n int idx = int(state) - 1;\n float su = (float(idx) + withinCellPos.x) / u_scatterNumChars;\n float mask = texture(u_scatterAtlas, vec2(su, withinCellPos.y)).r;\n vec3 scatterBg = u_videoMode ? cellColor : bgColor;\n scatterColor = mix(scatterBg, vec3(1.0), mask);\n scatterHit = true;\n }\n }\n\n vec3 finalColor;\n if (scatterHit) {\n finalColor = scatterColor;\n } else {\n finalColor = u_videoMode ? cellColor : mix(bgColor, cellColor, glyphMask);\n\n if (u_mouseEffect) {\n bool inside = false;\n for (int i = 0; i < MOUSE_TRAIL_LEN; i++) {\n if (u_mouseLifeFracs[i] <= 0.0) {\n continue;\n }\n float r = u_mouseRadius * u_mouseLifeFracs[i];\n if (distance(cellCenter, u_mousePositions[i]) < r) {\n inside = true;\n break;\n }\n }\n if (inside) {\n finalColor = clamp(finalColor * u_mouseBrightness, 0.0, 1.0);\n }\n }\n\n if (u_clickEffect) {\n float boost = 1.0;\n for (int i = 0; i < MAX_RIPPLES; i++) {\n if (u_rippleBrightnesses[i] <= 1.0) {\n continue;\n }\n if (distance(cellCenter, u_ripplePositions[i]) < u_rippleRadii[i]) {\n boost *= u_rippleBrightnesses[i];\n }\n }\n if (boost > 1.0) {\n finalColor = clamp(finalColor * boost, 0.0, 1.0);\n }\n }\n }\n\n fragColor = vec4(finalColor, 1.0);\n}", f = "#version 300 es\n\nprecision highp float;\nprecision highp usampler2D;\n\nuniform sampler2D u_texture;\nuniform vec2 u_resolution;\nuniform vec2 u_cellsize;\nuniform int u_circleN;\nuniform sampler2D u_charVectors;\nuniform int u_numCharsInt;\nuniform float u_shapeExponent;\nuniform vec2 u_cropOffset;\nuniform vec2 u_cropScale;\nuniform vec2 u_gridOffset;\n\nout uvec4 fragCharInd;\n\nvoid main() {\n \n ivec2 cellCoord = ivec2(floor(gl_FragCoord.xy));\n\n const vec2 CIRCLES[6] = vec2[6](\n vec2(0.25, 0.25), vec2(0.75, 0.25),\n vec2(0.25, 0.50), vec2(0.75, 0.50),\n vec2(0.25, 0.75), vec2(0.75, 0.75)\n );\n vec2 radiusUV = vec2(u_cellsize.x / 5.0) / u_resolution * u_cropScale; \n\n float sv[6];\n for (int ci = 0; ci < 6; ci++) {\n \n vec2 centerUV = u_cropOffset + (u_gridOffset + (vec2(cellCoord) + CIRCLES[ci]) * u_cellsize) / u_resolution * u_cropScale;\n float total = 0.0;\n int count = 0;\n for (int dx = -u_circleN; dx <= u_circleN; dx++) {\n for (int dy = -u_circleN; dy <= u_circleN; dy++) {\n if (dx*dx + dy*dy <= u_circleN*u_circleN) {\n vec2 sampleUV = centerUV + vec2(float(dx), float(dy)) * radiusUV / float(u_circleN);\n vec3 sc = texture(u_texture, sampleUV).rgb;\n total += dot(sc, vec3(0.299, 0.587, 0.114));\n count++;\n }\n }\n }\n \n sv[ci] = count > 0 ? total / float(count) : 0.0;\n }\n\n float maxVal = 0.0;\n for (int d = 0; d < 6; d++) maxVal = max(maxVal, sv[d]);\n if (maxVal > 0.0) {\n for (int d = 0; d < 6; d++) sv[d] = pow(sv[d] / maxVal, u_shapeExponent) * maxVal;\n }\n\n \n uint bestChar = 0u;\n float bestDist = 1e10;\n for (int i = 0; i < u_numCharsInt; i++) {\n vec4 r0 = texelFetch(u_charVectors, ivec2(i, 0), 0);\n vec4 r1 = texelFetch(u_charVectors, ivec2(i, 1), 0);\n float dist = 0.0;\n float diffs[6] = float[6](\n sv[0] - r0.r, sv[1] - r0.g, sv[2] - r0.b, sv[3] - r0.a,\n sv[4] - r1.r, sv[5] - r1.g\n );\n for (int d = 0; d < 6; d++) {\n dist += diffs[d] * diffs[d];\n }\n if (dist < bestDist) { \n bestDist = dist; bestChar = uint(i); \n }\n }\n\n fragCharInd = uvec4(bestChar, 0u, 0u, 0u);\n}";
99
100
  //#endregion
100
101
  //#region src/lib/create-gl-resources.ts
101
102
  function p(e) {
@@ -121,7 +122,7 @@ function p(e) {
121
122
  let o = e.getAttribLocation(r, "a_position");
122
123
  e.vertexAttribPointer(o, 2, e.FLOAT, !1, 0, 0), e.enableVertexAttribArray(o), e.useProgram(r);
123
124
  let s = e.createTexture();
124
- e.activeTexture(e.TEXTURE0), e.bindTexture(e.TEXTURE_2D, s), 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), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MIN_FILTER, e.NEAREST), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MAG_FILTER, e.NEAREST);
125
+ e.activeTexture(e.TEXTURE0), e.bindTexture(e.TEXTURE_2D, s), 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), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MIN_FILTER, e.LINEAR), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MAG_FILTER, e.LINEAR);
125
126
  let p = e.getUniformLocation(r, "u_texture");
126
127
  e.uniform1i(p, 0);
127
128
  let m = e.createTexture();
@@ -135,14 +136,14 @@ function p(e) {
135
136
  let v = l(e, t, _);
136
137
  if (!v) return null;
137
138
  e.useProgram(v), e.uniform1i(e.getUniformLocation(v, "u_texture"), 0), e.uniform1i(e.getUniformLocation(v, "u_charVectors"), 2);
138
- let y = e.getUniformLocation(v, "u_resolution"), b = e.getUniformLocation(v, "u_cellsize"), x = e.getUniformLocation(v, "u_circleN"), S = e.getUniformLocation(v, "u_numCharsInt"), C = e.getUniformLocation(v, "u_shapeExponent"), w = e.getUniformLocation(v, "u_cropOffset"), T = e.getUniformLocation(v, "u_cropScale"), E = e.createTexture();
139
- e.activeTexture(e.TEXTURE3), e.bindTexture(e.TEXTURE_2D, E), 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), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MIN_FILTER, e.NEAREST), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MAG_FILTER, e.NEAREST);
140
- let D = e.createFramebuffer(), O = e.createTexture();
141
- e.activeTexture(e.TEXTURE4), e.bindTexture(e.TEXTURE_2D, O), 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), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MIN_FILTER, e.NEAREST), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MAG_FILTER, e.NEAREST);
142
- let k = e.createTexture();
143
- e.activeTexture(e.TEXTURE5), e.bindTexture(e.TEXTURE_2D, k), 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), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MIN_FILTER, e.NEAREST), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MAG_FILTER, e.NEAREST);
139
+ let y = e.getUniformLocation(v, "u_resolution"), b = e.getUniformLocation(v, "u_cellsize"), x = e.getUniformLocation(v, "u_circleN"), S = e.getUniformLocation(v, "u_numCharsInt"), C = e.getUniformLocation(v, "u_shapeExponent"), w = e.getUniformLocation(v, "u_cropOffset"), T = e.getUniformLocation(v, "u_cropScale"), E = e.getUniformLocation(v, "u_gridOffset"), D = e.createTexture();
140
+ e.activeTexture(e.TEXTURE3), e.bindTexture(e.TEXTURE_2D, D), 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), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MIN_FILTER, e.NEAREST), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MAG_FILTER, e.NEAREST);
141
+ let O = e.createFramebuffer(), k = e.createTexture();
142
+ e.activeTexture(e.TEXTURE4), e.bindTexture(e.TEXTURE_2D, k), 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), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MIN_FILTER, e.NEAREST), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MAG_FILTER, e.NEAREST);
144
143
  let A = e.createTexture();
145
- return e.activeTexture(e.TEXTURE6), e.bindTexture(e.TEXTURE_2D, A), 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), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MIN_FILTER, e.NEAREST), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MAG_FILTER, e.NEAREST), e.useProgram(r), e.uniform1i(e.getUniformLocation(r, "u_fboTexture"), 3), e.uniform1i(e.getUniformLocation(r, "u_scatterAtlas"), 4), e.uniform1i(e.getUniformLocation(r, "u_scatterStateTexture"), 5), e.uniform1i(e.getUniformLocation(r, "u_spreadStateTexture"), 6), {
144
+ e.activeTexture(e.TEXTURE5), e.bindTexture(e.TEXTURE_2D, A), 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), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MIN_FILTER, e.NEAREST), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MAG_FILTER, e.NEAREST);
145
+ let j = e.createTexture();
146
+ return e.activeTexture(e.TEXTURE6), e.bindTexture(e.TEXTURE_2D, j), 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), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MIN_FILTER, e.NEAREST), e.texParameteri(e.TEXTURE_2D, e.TEXTURE_MAG_FILTER, e.NEAREST), e.useProgram(r), e.uniform1i(e.getUniformLocation(r, "u_fboTexture"), 3), e.uniform1i(e.getUniformLocation(r, "u_scatterAtlas"), 4), e.uniform1i(e.getUniformLocation(r, "u_scatterStateTexture"), 5), e.uniform1i(e.getUniformLocation(r, "u_spreadStateTexture"), 6), {
146
147
  program: r,
147
148
  pass1Program: v,
148
149
  buffer: a,
@@ -152,11 +153,11 @@ function p(e) {
152
153
  texture: s,
153
154
  atlasTexture: m,
154
155
  charVectorsTexture: g,
155
- fboTexture: E,
156
- fbo: D,
157
- scatterAtlasTexture: O,
158
- scatterStateTexture: k,
159
- spreadStateTexture: A,
156
+ fboTexture: D,
157
+ fbo: O,
158
+ scatterAtlasTexture: k,
159
+ scatterStateTexture: A,
160
+ spreadStateTexture: j,
160
161
  p1ResLoc: y,
161
162
  p1CellsizeLoc: b,
162
163
  p1CircleNLoc: x,
@@ -164,6 +165,7 @@ function p(e) {
164
165
  p1ExponentLoc: C,
165
166
  p1CropOffsetLoc: w,
166
167
  p1CropScaleLoc: T,
168
+ p1GridOffsetLoc: E,
167
169
  revealEffectFlagLoc: e.getUniformLocation(r, "u_revealEffectFlag"),
168
170
  mouseEffectFlagLoc: e.getUniformLocation(r, "u_mouseEffect"),
169
171
  clickEffectFlagLoc: e.getUniformLocation(r, "u_clickEffect"),
@@ -188,18 +190,19 @@ function p(e) {
188
190
  numLoc: e.getUniformLocation(r, "u_numChars"),
189
191
  gridSizeLoc: e.getUniformLocation(r, "u_gridSize"),
190
192
  cropOffsetLoc: e.getUniformLocation(r, "u_cropOffset"),
191
- cropScaleLoc: e.getUniformLocation(r, "u_cropScale")
193
+ cropScaleLoc: e.getUniformLocation(r, "u_cropScale"),
194
+ gridOffsetLoc: e.getUniformLocation(r, "u_gridOffset")
192
195
  };
193
196
  }
194
197
  //#endregion
195
198
  //#region src/lib/scatter-effect.ts
196
199
  function m({ scatterEnabledRef: e, mouseRadiusRef: t, durationRef: n, scatterCharsRef: r }) {
197
- let i = new Uint8Array(), a = new Float32Array(), o = new Float32Array(), s = new Uint8Array(), c = null, l = null, u = 0, d = 0, f = -1, p = () => Math.floor(Math.random() * r.current.length), m = 0, h = 0, g = 1, _ = 1, v = null;
200
+ let i = new Uint8Array(), a = new Float32Array(), o = new Float32Array(), s = new Uint8Array(), c = null, l = null, u = 0, d = 0, f = -1, p = () => Math.floor(Math.random() * r.current.length), m = 0, h = 0, g = 1, _ = 1, v = 0, y = 0, b = null;
198
201
  return {
199
- setup(e, t, n, r, f, p) {
200
- m = t, h = n, g = r, _ = f, v = p;
201
- let y = t * n;
202
- i = new Uint8Array(y), a = new Float32Array(y), o = new Float32Array(y), s = new Uint8Array(y), c = null, l = null, u = 0, d = 0, e.activeTexture(e.TEXTURE5), e.bindTexture(e.TEXTURE_2D, p), e.texImage2D(e.TEXTURE_2D, 0, e.R8UI, t, n, 0, e.RED_INTEGER, e.UNSIGNED_BYTE, i);
202
+ setup(e, t, n, r, f, p, x, S) {
203
+ m = t, h = n, g = r, _ = f, v = p, y = x, b = S;
204
+ let C = t * n;
205
+ i = new Uint8Array(C), a = new Float32Array(C), o = new Float32Array(C), s = new Uint8Array(C), c = null, l = null, u = 0, d = 0, e.activeTexture(e.TEXTURE5), e.bindTexture(e.TEXTURE_2D, S), e.texImage2D(e.TEXTURE_2D, 0, e.R8UI, t, n, 0, e.RED_INTEGER, e.UNSIGNED_BYTE, i);
203
206
  },
204
207
  handleMouseMove(t, n, r) {
205
208
  e.current && (l = c, c = {
@@ -212,14 +215,14 @@ function m({ scatterEnabledRef: e, mouseRadiusRef: t, durationRef: n, scatterCha
212
215
  c = null, l = null, u = 0, d = 0;
213
216
  },
214
217
  reset(e) {
215
- i.fill(0), v && m > 0 && (e.activeTexture(e.TEXTURE5), e.bindTexture(e.TEXTURE_2D, v), e.texSubImage2D(e.TEXTURE_2D, 0, 0, 0, m, h, e.RED_INTEGER, e.UNSIGNED_BYTE, i));
218
+ i.fill(0), b && m > 0 && (e.activeTexture(e.TEXTURE5), e.bindTexture(e.TEXTURE_2D, b), e.texSubImage2D(e.TEXTURE_2D, 0, 0, 0, m, h, e.RED_INTEGER, e.UNSIGNED_BYTE, i));
216
219
  },
217
- tick(r, y) {
220
+ tick(r, x) {
218
221
  if (!e.current || m === 0 || h === 0) return;
219
- let b = performance.now(), x = f < 0 ? 0 : Math.min(.1, (b - f) / 1e3);
220
- f = b;
221
- let S = Math.min(y.width, y.height) * t.current, C = !1;
222
- if (c && b - c.t < 80) {
222
+ let S = performance.now(), C = f < 0 ? 0 : Math.min(.1, (S - f) / 1e3);
223
+ f = S;
224
+ let w = Math.min(x.width, x.height) * t.current, T = !1;
225
+ if (c && S - c.t < 80) {
223
226
  if (l) {
224
227
  let e = (c.t - l.t) / 1e3;
225
228
  if (e > 0 && e < .2) {
@@ -227,25 +230,25 @@ function m({ scatterEnabledRef: e, mouseRadiusRef: t, durationRef: n, scatterCha
227
230
  u = u * .7 + t * .3, d = d * .7 + n * .3;
228
231
  }
229
232
  } else u = 0, d = 0;
230
- Math.hypot(u, d) > g * 2 && (C = !0);
233
+ Math.hypot(u, d) > g * 2 && (T = !0);
231
234
  } else u *= .6, d *= .6;
232
- if (s.fill(0), C && c && S > 0) {
233
- let e = c.x, t = c.y, n = Math.max(0, Math.floor((e - S) / g)), r = Math.min(m - 1, Math.floor((e + S) / g)), l = Math.max(0, Math.floor((t - S) / _)), u = Math.min(h - 1, Math.floor((t + S) / _));
235
+ if (s.fill(0), T && c && w > 0) {
236
+ let e = c.x, t = c.y, n = Math.max(0, Math.floor((e - v - w) / g)), r = Math.min(m - 1, Math.floor((e - v + w) / g)), l = Math.max(0, Math.floor((t - y - w) / _)), u = Math.min(h - 1, Math.floor((t - y + w) / _));
234
237
  for (let c = l; c <= u; c++) for (let l = n; l <= r; l++) {
235
- let n = (l + .5) * g, r = (c + .5) * _;
236
- if (Math.hypot(n - e, r - t) > S) continue;
238
+ let n = v + (l + .5) * g, r = y + (c + .5) * _;
239
+ if (Math.hypot(n - e, r - t) > w) continue;
237
240
  let u = c * m + l;
238
241
  s[u] = 1, i[u] === 0 && (i[u] = 1 + p(), o[u] = .5 + Math.random() * 2), a[u] = 1;
239
242
  }
240
243
  }
241
- let w = n.current;
242
- if (x > 0) for (let e = 0; e < h; e++) for (let t = 0; t < m; t++) {
244
+ let E = n.current;
245
+ if (C > 0) for (let e = 0; e < h; e++) for (let t = 0; t < m; t++) {
243
246
  let n = e * m + t;
244
247
  if (i[n] === 0 || s[n]) continue;
245
- let r = t > 0 ? i[n - 1] !== 0 : !1, c = t < m - 1 ? i[n + 1] !== 0 : !1, l = e > 0 ? i[n - m] !== 0 : !1, u = e < h - 1 ? i[n + m] !== 0 : !1, d = (!r || !c || !l || !u ? 5 : 1) * o[n] / w;
246
- a[n] -= d * x, a[n] <= 0 && (i[n] = 0);
248
+ let r = t > 0 ? i[n - 1] !== 0 : !1, c = t < m - 1 ? i[n + 1] !== 0 : !1, l = e > 0 ? i[n - m] !== 0 : !1, u = e < h - 1 ? i[n + m] !== 0 : !1, d = (!r || !c || !l || !u ? 5 : 1) * o[n] / E;
249
+ a[n] -= d * C, a[n] <= 0 && (i[n] = 0);
247
250
  }
248
- r.activeTexture(r.TEXTURE5), r.bindTexture(r.TEXTURE_2D, v), r.texSubImage2D(r.TEXTURE_2D, 0, 0, 0, m, h, r.RED_INTEGER, r.UNSIGNED_BYTE, i);
251
+ r.activeTexture(r.TEXTURE5), r.bindTexture(r.TEXTURE_2D, b), r.texSubImage2D(r.TEXTURE_2D, 0, 0, 0, m, h, r.RED_INTEGER, r.UNSIGNED_BYTE, i);
249
252
  }
250
253
  };
251
254
  }
@@ -275,71 +278,71 @@ function h({ brightenEnabledRef: e, trailLenRef: t, durationRef: n, trailDecayRe
275
278
  //#endregion
276
279
  //#region src/lib/click-effect.ts
277
280
  var g = 10;
278
- function _({ clickEnabledRef: e, clickSpeedRef: t, clickBrightnessRef: n }) {
279
- let r = [];
281
+ function _({ clickEnabledRef: e, clickSpeedRef: t, clickBrightnessRef: n, pixelScaleRef: r }) {
282
+ let i = [];
280
283
  return {
281
284
  handleClick(t, n) {
282
285
  if (!e.current) return;
283
- let i = n.getBoundingClientRect(), a = (t.clientX - i.left) * (n.width / i.width), o = (t.clientY - i.top) * (n.height / i.height);
284
- r.push({
286
+ let r = n.getBoundingClientRect(), a = (t.clientX - r.left) * (n.width / r.width), o = (t.clientY - r.top) * (n.height / r.height);
287
+ i.push({
285
288
  x: a,
286
289
  y: o,
287
290
  t: performance.now()
288
- }), r.length > g && r.shift();
291
+ }), i.length > g && i.shift();
289
292
  },
290
- tick(i, a, o, s, c) {
293
+ tick(a, o, s, c, l) {
291
294
  if (!e.current) return;
292
- let l = performance.now(), u = Math.hypot(a.width, a.height), d = new Float32Array(g * 2), f = new Float32Array(g), p = new Float32Array(g);
293
- for (; r.length > 0 && (l - r[0].t) * t.current >= u;) r.shift();
294
- for (let e = 0; e < r.length; e++) {
295
- let i = (l - r[e].t) * t.current, a = i / u, o = 1 + (n.current - 1) * (1 - a ** 2);
296
- d[e * 2] = r[e].x, d[e * 2 + 1] = r[e].y, f[e] = i, p[e] = o;
295
+ let u = performance.now(), d = Math.hypot(o.width, o.height), f = t.current * r.current, p = new Float32Array(g * 2), m = new Float32Array(g), h = new Float32Array(g);
296
+ for (; i.length > 0 && (u - i[0].t) * f >= d;) i.shift();
297
+ for (let e = 0; e < i.length; e++) {
298
+ let t = (u - i[e].t) * f, r = t / d, a = 1 + (n.current - 1) * (1 - r ** 2);
299
+ p[e * 2] = i[e].x, p[e * 2 + 1] = i[e].y, m[e] = t, h[e] = a;
297
300
  }
298
- i.uniform2fv(o, d), i.uniform1fv(s, f), i.uniform1fv(c, p);
301
+ a.uniform2fv(s, p), a.uniform1fv(c, m), a.uniform1fv(l, h);
299
302
  }
300
303
  };
301
304
  }
302
305
  //#endregion
303
306
  //#region src/lib/spread-effect.ts
304
307
  function v({ spreadEnabledRef: e, scatterCharsRef: t, spreadExpandDurationRef: n, spreadSpeedRef: r }) {
305
- let i = new Uint8Array(), a = new Uint8Array(), o = 0, s = 0, c = 1, l = 1, u = null, d = -1, f = -1, p = () => Math.floor(Math.random() * t.current.length), m = [
308
+ let i = new Uint8Array(), a = new Uint8Array(), o = 0, s = 0, c = 1, l = 1, u = 0, d = 0, f = null, p = -1, m = -1, h = () => Math.floor(Math.random() * t.current.length), g = [
306
309
  [-1, 0],
307
310
  [1, 0],
308
311
  [0, -1],
309
312
  [0, 1]
310
313
  ];
311
314
  return {
312
- setup(e, t, n, r, p, m) {
313
- o = t, s = n, c = r, l = p, u = m;
314
- let h = t * n;
315
- i = new Uint8Array(h), a = new Uint8Array(h), f = -1, d = -1, e.activeTexture(e.TEXTURE6), e.bindTexture(e.TEXTURE_2D, m), e.texImage2D(e.TEXTURE_2D, 0, e.R8UI, t, n, 0, e.RED_INTEGER, e.UNSIGNED_BYTE, i);
315
+ setup(e, t, n, r, h, g, _, v) {
316
+ o = t, s = n, c = r, l = h, u = g, d = _, f = v;
317
+ let y = t * n;
318
+ i = new Uint8Array(y), a = new Uint8Array(y), m = -1, p = -1, e.activeTexture(e.TEXTURE6), e.bindTexture(e.TEXTURE_2D, v), e.texImage2D(e.TEXTURE_2D, 0, e.R8UI, t, n, 0, e.RED_INTEGER, e.UNSIGNED_BYTE, i);
316
319
  },
317
320
  handleClick(t, r) {
318
321
  if (!e.current || o === 0) return;
319
- let u = r.getBoundingClientRect(), d = (t.clientX - u.left) * (r.width / u.width), m = (t.clientY - u.top) * (r.height / u.height), h = Math.floor(d / c), g = Math.floor(m / l);
320
- if (h < 0 || h >= o || g < 0 || g >= s) return;
321
- let _ = g * o + h;
322
- i[_] = 1 + p(), a[_] = 1, f = performance.now() + n.current * 1e3;
322
+ let f = r.getBoundingClientRect(), p = (t.clientX - f.left) * (r.width / f.width), g = (t.clientY - f.top) * (r.height / f.height), _ = Math.floor((p - u) / c), v = Math.floor((g - d) / l);
323
+ if (_ < 0 || _ >= o || v < 0 || v >= s) return;
324
+ let y = v * o + _;
325
+ i[y] = 1 + h(), a[y] = 1, m = performance.now() + n.current * 1e3;
323
326
  },
324
327
  tick(t) {
325
328
  if (!e.current || o === 0 || s === 0) return;
326
- let n = performance.now(), c = d < 0 ? 0 : Math.min(.1, (n - d) / 1e3);
327
- d = n;
328
- let l = f > 0 && n < f;
329
- if (!l && f > 0) {
329
+ let n = performance.now(), c = p < 0 ? 0 : Math.min(.1, (n - p) / 1e3);
330
+ p = n;
331
+ let l = m > 0 && n < m;
332
+ if (!l && m > 0) {
330
333
  for (let e = 0; e < i.length; e++) a[e] === 1 && (a[e] = 2);
331
- f = -1;
334
+ m = -1;
332
335
  }
333
336
  if (c > 0) for (let e = 0; e < s; e++) for (let t = 0; t < o; t++) {
334
337
  let n = e * o + t;
335
338
  if (a[n] !== 0) {
336
- if (l && a[n] === 1) for (let [n, l] of m) {
339
+ if (l && a[n] === 1) for (let [n, l] of g) {
337
340
  let u = e + n, d = t + l;
338
341
  if (u < 0 || u >= s || d < 0 || d >= o) continue;
339
342
  let f = u * o + d;
340
- a[f] === 0 && Math.random() < r.current * c && (i[f] = 1 + p(), a[f] = 1);
343
+ a[f] === 0 && Math.random() < r.current * c && (i[f] = 1 + h(), a[f] = 1);
341
344
  }
342
- else if (a[n] === 2) for (let [l, u] of m) {
345
+ else if (a[n] === 2) for (let [l, u] of g) {
343
346
  let d = e + l, f = t + u;
344
347
  if (d < 0 || d >= s || f < 0 || f >= o || i[d * o + f] === 0) {
345
348
  Math.random() < r.current * c && (i[n] = 0, a[n] = 0);
@@ -348,159 +351,214 @@ function v({ spreadEnabledRef: e, scatterCharsRef: t, spreadExpandDurationRef: n
348
351
  }
349
352
  }
350
353
  }
351
- t.activeTexture(t.TEXTURE6), t.bindTexture(t.TEXTURE_2D, u), t.texSubImage2D(t.TEXTURE_2D, 0, 0, 0, o, s, t.RED_INTEGER, t.UNSIGNED_BYTE, i);
354
+ t.activeTexture(t.TEXTURE6), t.bindTexture(t.TEXTURE_2D, f), t.texSubImage2D(t.TEXTURE_2D, 0, 0, 0, o, s, t.RED_INTEGER, t.UNSIGNED_BYTE, i);
352
355
  }
353
356
  };
354
357
  }
355
358
  //#endregion
359
+ //#region src/lib/device-pixel-size.ts
360
+ function y(e, t) {
361
+ let n = 0, r = 0, i = !1, a = null, o = () => {
362
+ let e = window.devicePixelRatio || 1;
363
+ t({
364
+ width: Math.round(n * e),
365
+ height: Math.round(r * e),
366
+ cssWidth: n,
367
+ cssHeight: r
368
+ });
369
+ }, s = () => {
370
+ a?.();
371
+ let e = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`), t = () => {
372
+ i || (o(), s());
373
+ };
374
+ e.addEventListener("change", t, { once: !0 }), a = () => e.removeEventListener("change", t);
375
+ }, c = new ResizeObserver((e) => {
376
+ let i = e[0], a = i.contentBoxSize?.[0];
377
+ n = a ? a.inlineSize : i.contentRect.width, r = a ? a.blockSize : i.contentRect.height;
378
+ let s = i.devicePixelContentBoxSize?.[0];
379
+ s ? t({
380
+ width: s.inlineSize,
381
+ height: s.blockSize,
382
+ cssWidth: n,
383
+ cssHeight: r
384
+ }) : o();
385
+ });
386
+ try {
387
+ c.observe(e, { box: "device-pixel-content-box" });
388
+ } catch {
389
+ c.observe(e), s();
390
+ }
391
+ return () => {
392
+ i = !0, c.disconnect(), a?.();
393
+ };
394
+ }
395
+ //#endregion
356
396
  //#region src/components/VideoAscii.tsx
357
- function y({ src: i, videoMode: c = !1, numColsRaw: l = 250, brightnessRaw: u = 1, saturationRaw: d = 1, bgOpacityRaw: f = .3, revealEffect: g = !1, chars: y = o, mouseEffect: b = !0, clickEffect: x = !0, charMode: S = "shape", className: C, cropFocus: w = "center" }) {
358
- let T = t(null), E = t(null), D = t(null), O = t(null), k = t(null), { numCols: A, brightness: j, saturation: M, bgOpacity: N, mouseEnabled: P, mouseStyle: F, brightenEnabled: I, scatterEnabled: L, scatterChars: R, trailLen: z, trailDecay: B, duration: V, mouseRadius: H, mouseBrightness: U, clickEnabled: W, clickBrightness: G, clickSpeed: K, spreadEnabled: q, spreadExpandDuration: J, spreadSpeed: Y, revealEnabled: ee, revealDuration: te, revealEffectFlag: ne } = s(l, u, d, f, b, x, g), re = t(j), ie = t(M), ae = t(N), oe = t(P), se = t(F), X = t(I), Z = t(L), ce = t(U), le = t(H), ue = t(z), de = t(B), fe = t(V), Q = t(R), pe = t(W), me = t(G), he = t(K), ge = t(q), _e = t(J), ve = t(Y), ye = t(A), be = t(c), xe = t(w), Se = t(0), Ce = t(0);
397
+ function b({ src: i, videoMode: c = !1, numColsRaw: l = 250, brightnessRaw: u = 1, saturationRaw: d = 1, bgOpacityRaw: f = .3, revealEffect: g = !1, chars: b = o, mouseEffect: x = !0, clickEffect: S = !0, charMode: C = "shape", className: w, cropFocus: T = "center", maxDpr: E }) {
398
+ let D = t(null), O = t(null), k = t(null), A = t(null), j = t(null), { numCols: M, brightness: N, saturation: P, bgOpacity: F, mouseEnabled: I, mouseStyle: L, brightenEnabled: R, scatterEnabled: z, scatterChars: B, trailLen: V, trailDecay: H, duration: U, mouseRadius: ee, mouseBrightness: W, clickEnabled: G, clickBrightness: K, clickSpeed: q, spreadEnabled: J, spreadExpandDuration: Y, spreadSpeed: X, revealEnabled: te, revealDuration: ne, revealEffectFlag: re, maxDpr: ie } = s(l, u, d, f, x, S, g, E), ae = t(N), oe = t(P), se = t(F), ce = t(I), le = t(L), ue = t(R), de = t(z), fe = t(W), pe = t(ee), me = t(V), he = t(H), ge = t(U), Z = t(B), _e = t(G), ve = t(K), ye = t(q), be = t(J), xe = t(Y), Se = t(X), Ce = t(M), we = t(c), Te = t(T), Ee = t(0), De = t(0), Oe = t(ie), ke = t(1), Q = t(null), Ae = t(null);
359
399
  e(() => {
360
- re.current = j, ie.current = M, ae.current = N, oe.current = P, se.current = F, X.current = I, Z.current = L, ce.current = U, le.current = H, ue.current = z, de.current = B, fe.current = V, Q.current !== R && $.current ? (Q.current = R, Te.current?.()) : Q.current = R, pe.current = W, me.current = G, he.current = K, ge.current = q, _e.current = J, ve.current = Y, ye.current = A, be.current = c;
400
+ ae.current = N, oe.current = P, se.current = F, ce.current = I, le.current = L, ue.current = R, de.current = z, fe.current = W, pe.current = ee, me.current = V, he.current = H, ge.current = U, Z.current !== B && $.current ? (Z.current = B, Me.current?.()) : Z.current = B, _e.current = G, ve.current = K, ye.current = q, be.current = J, xe.current = Y, Se.current = X, Ce.current = M, we.current = c;
361
401
  }, [
362
- j,
363
- M,
364
402
  N,
365
403
  P,
366
404
  F,
367
405
  I,
368
406
  L,
369
- U,
370
- H,
371
- z,
372
- B,
373
- V,
374
407
  R,
408
+ z,
375
409
  W,
410
+ ee,
411
+ V,
412
+ H,
413
+ U,
414
+ B,
376
415
  G,
377
416
  K,
378
417
  q,
379
418
  J,
380
419
  Y,
381
- A,
420
+ X,
421
+ M,
382
422
  c
383
423
  ]);
384
- let we = t(null), Te = t(null), Ee = t(null), $ = t(!1);
424
+ let je = t(null), Me = t(null), Ne = t(null), $ = t(!1);
385
425
  return e(() => {
386
- $.current && we.current?.(A);
387
- }, [A]), e(() => {
388
- xe.current = w, $.current && Se.current > 0 && Ee.current?.(Se.current, Ce.current);
389
- }, [w]), e(() => {
426
+ $.current && je.current?.(M);
427
+ }, [M]), e(() => {
428
+ Te.current = T, $.current && Ee.current > 0 && Ne.current?.(Ee.current, De.current);
429
+ }, [T]), e(() => {
430
+ Oe.current = ie, $.current && Q.current && Ae.current?.(Q.current);
431
+ }, [ie]), e(() => {
390
432
  $.current = !1;
391
- let e = [], t = 0, n = 0, r = 1, o = 1, s = 0, c = 0, l = T.current;
392
- if (!l) return;
393
- let u = E.current;
394
- if (!u) return;
395
- let d = l.getContext("webgl2");
433
+ let e = [], t = 0, n = 0, r = 1, o = 1, s = 0, c = 0, l = 0, u = 0, d = D.current;
396
434
  if (!d) return;
397
- d.pixelStorei(d.UNPACK_ALIGNMENT, 1);
398
- let f = p(d);
435
+ let f = O.current;
399
436
  if (!f) return;
400
- let { program: g, pass1Program: b } = f;
401
- O.current = f.atlasTexture, k.current = f.scatterAtlasTexture, d.uniform1i(f.shapeMatchingLoc, +(S === "shape")), d.uniform1i(f.revealEffectFlagLoc, ne), d.uniform1f(f.revealProgressLoc, 0);
402
- let x = m({
403
- scatterEnabledRef: Z,
404
- mouseRadiusRef: le,
405
- durationRef: fe,
406
- scatterCharsRef: Q
407
- }), C = h({
408
- brightenEnabledRef: X,
409
- trailLenRef: ue,
410
- durationRef: fe,
411
- trailDecayRef: de
412
- }), w = _({
413
- clickEnabledRef: pe,
414
- clickSpeedRef: he,
415
- clickBrightnessRef: me
416
- }), A = v({
417
- spreadEnabledRef: ge,
418
- scatterCharsRef: Q,
419
- spreadExpandDurationRef: _e,
420
- spreadSpeedRef: ve
421
- }), j, M = -1, N = -1, P = 0, F = Array.isArray(i) ? i : [i], I = F.length > 1, L = document.createElement("canvas"), R = L.getContext("2d"), z = (i) => {
422
- let u = s > 0 ? s : l.width, p = c > 0 ? c : l.height;
423
- r = Math.max(1, Math.floor(u / i));
437
+ let g = d.getContext("webgl2");
438
+ if (!g) return;
439
+ g.pixelStorei(g.UNPACK_ALIGNMENT, 1);
440
+ let x = p(g);
441
+ if (!x) return;
442
+ let { program: S, pass1Program: w } = x;
443
+ A.current = x.atlasTexture, j.current = x.scatterAtlasTexture, g.uniform1i(x.shapeMatchingLoc, +(C === "shape")), g.uniform1i(x.revealEffectFlagLoc, re), g.uniform1f(x.revealProgressLoc, 0);
444
+ let T = m({
445
+ scatterEnabledRef: de,
446
+ mouseRadiusRef: pe,
447
+ durationRef: ge,
448
+ scatterCharsRef: Z
449
+ }), E = h({
450
+ brightenEnabledRef: ue,
451
+ trailLenRef: me,
452
+ durationRef: ge,
453
+ trailDecayRef: he
454
+ }), M = _({
455
+ clickEnabledRef: _e,
456
+ clickSpeedRef: ye,
457
+ clickBrightnessRef: ve,
458
+ pixelScaleRef: ke
459
+ }), N = v({
460
+ spreadEnabledRef: be,
461
+ scatterCharsRef: Z,
462
+ spreadExpandDurationRef: xe,
463
+ spreadSpeedRef: Se
464
+ }), P, F = -1, I = -1, L = 0, R = Array.isArray(i) ? i : [i], z = R.length > 1, B = document.createElement("canvas"), V = B.getContext("2d"), H = (i) => {
465
+ let f = l > 0 ? l : d.width, p = u > 0 ? u : d.height;
466
+ r = Math.max(1, Math.floor(f / i));
424
467
  let m = r * 2;
425
- if (R.font = `${m}px monospace`, o = Math.max(1, Math.round(m * r / R.measureText("M").width)), t = Math.floor(u / r), n = Math.floor(p / o), l.width = t * r, l.height = n * o, d.viewport(0, 0, l.width, l.height), d.useProgram(g), d.uniform2f(f.resLoc, l.width, l.height), d.useProgram(b), d.uniform2f(f.p1ResLoc, l.width, l.height), d.useProgram(g), x.setup(d, t, n, r, o, f.scatterStateTexture), A.setup(d, t, n, r, o, f.spreadStateTexture), S === "shape") {
426
- e = a(y, r, o);
468
+ if (V.font = `${m}px monospace`, o = Math.max(1, Math.round(m * r / V.measureText("M").width)), t = Math.ceil(f / r), n = Math.ceil(p / o), s = Math.floor((f - t * r) / 2), c = Math.floor((p - n * o) / 2), g.viewport(0, 0, d.width, d.height), g.useProgram(S), g.uniform2f(x.resLoc, d.width, d.height), g.uniform2f(x.gridOffsetLoc, s, c), g.useProgram(w), g.uniform2f(x.p1ResLoc, d.width, d.height), g.uniform2f(x.p1GridOffsetLoc, s, c), g.useProgram(S), T.setup(g, t, n, r, o, s, c, x.scatterStateTexture), N.setup(g, t, n, r, o, s, c, x.spreadStateTexture), C === "shape") {
469
+ e = a(b, r, o);
427
470
  let i = e.length, s = new Float32Array(i * 8);
428
471
  for (let t = 0; t < i; t++) {
429
472
  let n = e[t].vector;
430
473
  s[t * 4 + 0] = n[0], s[t * 4 + 1] = n[1], s[t * 4 + 2] = n[2], s[t * 4 + 3] = n[3], s[i * 4 + t * 4 + 0] = n[4], s[i * 4 + t * 4 + 1] = n[5];
431
474
  }
432
- d.activeTexture(d.TEXTURE2), d.bindTexture(d.TEXTURE_2D, f.charVectorsTexture), d.texImage2D(d.TEXTURE_2D, 0, d.RGBA32F, i, 2, 0, d.RGBA, d.FLOAT, s), d.activeTexture(d.TEXTURE3), d.bindTexture(d.TEXTURE_2D, f.fboTexture), d.texImage2D(d.TEXTURE_2D, 0, d.R8UI, t, n, 0, d.RED_INTEGER, d.UNSIGNED_BYTE, null), d.bindFramebuffer(d.FRAMEBUFFER, f.fbo), d.framebufferTexture2D(d.FRAMEBUFFER, d.COLOR_ATTACHMENT0, d.TEXTURE_2D, f.fboTexture, 0), d.bindFramebuffer(d.FRAMEBUFFER, null);
475
+ g.activeTexture(g.TEXTURE2), g.bindTexture(g.TEXTURE_2D, x.charVectorsTexture), g.texImage2D(g.TEXTURE_2D, 0, g.RGBA32F, i, 2, 0, g.RGBA, g.FLOAT, s), g.activeTexture(g.TEXTURE3), g.bindTexture(g.TEXTURE_2D, x.fboTexture), g.texImage2D(g.TEXTURE_2D, 0, g.R8UI, t, n, 0, g.RED_INTEGER, g.UNSIGNED_BYTE, null), g.bindFramebuffer(g.FRAMEBUFFER, x.fbo), g.framebufferTexture2D(g.FRAMEBUFFER, g.COLOR_ATTACHMENT0, g.TEXTURE_2D, x.fboTexture, 0), g.bindFramebuffer(g.FRAMEBUFFER, null);
433
476
  let c = Math.max(1, Math.round(r / 5));
434
- d.useProgram(b), d.uniform2f(f.p1CellsizeLoc, r, o), d.uniform1i(f.p1CircleNLoc, c), d.uniform1i(f.p1NumCharsLoc, i), d.uniform1f(f.p1ExponentLoc, 2), d.useProgram(g);
477
+ g.useProgram(w), g.uniform2f(x.p1CellsizeLoc, r, o), g.uniform1i(x.p1CircleNLoc, c), g.uniform1i(x.p1NumCharsLoc, i), g.uniform1f(x.p1ExponentLoc, 2), g.useProgram(S);
435
478
  }
436
- d.uniform2f(f.gridSizeLoc, t, n), L.width = y.length * r, L.height = o, R.font = `${o}px monospace`, R.fillStyle = "black", R.fillRect(0, 0, y.length * r, o), R.fillStyle = "white", R.textBaseline = "top";
437
- for (let e = 0; e < y.length; e++) R.fillText(y[e], e * r, 0);
438
- d.activeTexture(d.TEXTURE1), d.bindTexture(d.TEXTURE_2D, O.current), d.texImage2D(d.TEXTURE_2D, 0, d.RGBA, d.RGBA, d.UNSIGNED_BYTE, L), d.uniform1f(f.numLoc, y.length), d.uniform2f(f.sizeLoc, r, o), B();
439
- }, B = () => {
440
- let e = Q.current;
441
- L.width = e.length * r, L.height = o, R.fillStyle = "black", R.fillRect(0, 0, L.width, o), R.fillStyle = "white", R.textBaseline = "top", R.font = `${o}px monospace`;
442
- for (let t = 0; t < e.length; t++) R.fillText(e[t], t * r, 0);
443
- d.activeTexture(d.TEXTURE4), d.bindTexture(d.TEXTURE_2D, k.current), d.texImage2D(d.TEXTURE_2D, 0, d.RGBA, d.RGBA, d.UNSIGNED_BYTE, L), d.uniform1f(f.scatterNumCharsLoc, e.length), x.reset(d);
479
+ g.uniform2f(x.gridSizeLoc, t, n), B.width = b.length * r, B.height = o, V.font = `${o}px monospace`, V.fillStyle = "black", V.fillRect(0, 0, b.length * r, o), V.fillStyle = "white", V.textBaseline = "top";
480
+ for (let e = 0; e < b.length; e++) V.fillText(b[e], e * r, 0);
481
+ g.activeTexture(g.TEXTURE1), g.bindTexture(g.TEXTURE_2D, A.current), g.texImage2D(g.TEXTURE_2D, 0, g.RGBA, g.RGBA, g.UNSIGNED_BYTE, B), g.uniform1f(x.numLoc, b.length), g.uniform2f(x.sizeLoc, r, o), U();
482
+ }, U = () => {
483
+ let e = Z.current;
484
+ B.width = e.length * r, B.height = o, V.fillStyle = "black", V.fillRect(0, 0, B.width, o), V.fillStyle = "white", V.textBaseline = "top", V.font = `${o}px monospace`;
485
+ for (let t = 0; t < e.length; t++) V.fillText(e[t], t * r, 0);
486
+ g.activeTexture(g.TEXTURE4), g.bindTexture(g.TEXTURE_2D, j.current), g.texImage2D(g.TEXTURE_2D, 0, g.RGBA, g.RGBA, g.UNSIGNED_BYTE, B), g.uniform1f(x.scatterNumCharsLoc, e.length), T.reset(g);
444
487
  };
445
- we.current = z, Te.current = B;
446
- let V = (e, t) => {
447
- s = Math.round(e), c = Math.round(t), Se.current = s, Ce.current = c, l.width = s, l.height = c, z(ye.current);
448
- let n = u.videoWidth / u.videoHeight, r = l.width / l.height, i = 1, a = 1, o = 0, p = 0;
449
- if (r > n) a = n / r, p = (1 - a) / 2;
488
+ je.current = H, Me.current = U;
489
+ let ee = (e, t) => {
490
+ l = Math.round(e), u = Math.round(t), Ee.current = l, De.current = u, d.width = l, d.height = u, H(Ce.current);
491
+ let n = f.videoWidth / f.videoHeight, r = d.width / d.height, i = 1, a = 1, o = 0, s = 0;
492
+ if (r > n) a = n / r, s = (1 - a) / 2;
450
493
  else {
451
494
  i = r / n;
452
- let e = xe.current, t = e === "left" ? .25 : e === "right" ? .75 : .5;
495
+ let e = Te.current, t = e === "left" ? .25 : e === "right" ? .75 : .5;
453
496
  o = Math.max(0, Math.min(1 - i, t - i / 2));
454
497
  }
455
- d.uniform2f(f.cropOffsetLoc, o, p), d.uniform2f(f.cropScaleLoc, i, a), d.useProgram(b), d.uniform2f(f.p1CropOffsetLoc, o, p), d.uniform2f(f.p1CropScaleLoc, i, a), d.useProgram(g);
456
- };
457
- Ee.current = V;
458
- let H = (e) => {
459
- if (!oe.current) return;
460
- let t = l.getBoundingClientRect(), n = (e.clientX - t.left) * (l.width / t.width), r = (e.clientY - t.top) * (l.height / t.height), i = performance.now();
461
- C.handleMouseMove(n, r, i), x.handleMouseMove(n, r, i);
498
+ g.uniform2f(x.cropOffsetLoc, o, s), g.uniform2f(x.cropScaleLoc, i, a), g.useProgram(w), g.uniform2f(x.p1CropOffsetLoc, o, s), g.uniform2f(x.p1CropScaleLoc, i, a), g.useProgram(S);
462
499
  };
463
- l.addEventListener("mousemove", H);
464
- let U = () => x.handleMouseLeave();
465
- l.addEventListener("mouseleave", U);
500
+ Ne.current = ee;
466
501
  let W = (e) => {
467
- w.handleClick(e, l), A.handleClick(e, l);
502
+ Q.current = e;
503
+ let t = Math.min(1, Oe.current / (window.devicePixelRatio || 1)), n = Math.max(1, Math.round(e.width * t)), r = Math.max(1, Math.round(e.height * t));
504
+ ke.current = e.cssWidth > 0 ? n / e.cssWidth : 1, ee(n, r);
505
+ };
506
+ Ae.current = W;
507
+ let G = (e) => {
508
+ if (!ce.current) return;
509
+ let t = d.getBoundingClientRect(), n = (e.clientX - t.left) * (d.width / t.width), r = (e.clientY - t.top) * (d.height / t.height), i = performance.now();
510
+ E.handleMouseMove(n, r, i), T.handleMouseMove(n, r, i);
511
+ };
512
+ d.addEventListener("mousemove", G);
513
+ let K = () => T.handleMouseLeave();
514
+ d.addEventListener("mouseleave", K);
515
+ let q = (e) => {
516
+ M.handleClick(e, d), N.handleClick(e, d);
468
517
  };
469
- l.addEventListener("click", W);
470
- let G = () => {
471
- if (d.uniform1i(f.videoModeLoc, +!!be.current), d.uniform1f(f.brightnessLoc, re.current), d.uniform1f(f.saturationLoc, ie.current), d.uniform1f(f.bgOpacityLoc, ae.current), d.uniform1i(f.mouseEffectFlagLoc, +!!X.current), d.uniform1i(f.scatterEffectFlagLoc, +!!Z.current), d.uniform1i(f.clickEffectFlagLoc, +!!pe.current), d.uniform1i(f.spreadEffectFlagLoc, +!!ge.current), d.uniform1f(f.mouseBrightnessLoc, ce.current), d.uniform1f(f.mouseRadiusLoc, Math.min(l.width, l.height) * le.current), ee) {
472
- let e = N < 0 ? 0 : Math.min(1, (performance.now() - N) / (te * 1e3));
473
- d.uniform1f(f.revealProgressLoc, e);
518
+ d.addEventListener("click", q);
519
+ let J = () => {
520
+ if (g.uniform1i(x.videoModeLoc, +!!we.current), g.uniform1f(x.brightnessLoc, ae.current), g.uniform1f(x.saturationLoc, oe.current), g.uniform1f(x.bgOpacityLoc, se.current), g.uniform1i(x.mouseEffectFlagLoc, +!!ue.current), g.uniform1i(x.scatterEffectFlagLoc, +!!de.current), g.uniform1i(x.clickEffectFlagLoc, +!!_e.current), g.uniform1i(x.spreadEffectFlagLoc, +!!be.current), g.uniform1f(x.mouseBrightnessLoc, fe.current), g.uniform1f(x.mouseRadiusLoc, Math.min(d.width, d.height) * pe.current), te) {
521
+ let e = I < 0 ? 0 : Math.min(1, (performance.now() - I) / (ne * 1e3));
522
+ g.uniform1f(x.revealProgressLoc, e);
474
523
  }
475
- $.current && u.currentTime != M && u.readyState >= 2 && (d.activeTexture(d.TEXTURE0), d.bindTexture(d.TEXTURE_2D, f.texture), d.texSubImage2D(d.TEXTURE_2D, 0, 0, 0, d.RGBA, d.UNSIGNED_BYTE, u), M = u.currentTime), C.tick(d, f.mousePositionsLoc, f.mouseLifeFracsLoc), x.tick(d, l), w.tick(d, l, f.ripplePositionsLoc, f.rippleRadiiLoc, f.rippleBrightnessesLoc), A.tick(d), S === "shape" && (d.bindFramebuffer(d.FRAMEBUFFER, f.fbo), d.viewport(0, 0, t, n), d.useProgram(b), d.drawArrays(d.TRIANGLES, 0, 6), d.bindFramebuffer(d.FRAMEBUFFER, null), d.viewport(0, 0, l.width, l.height), d.useProgram(g)), d.drawArrays(d.TRIANGLES, 0, 6), j = requestAnimationFrame(G);
476
- }, K = () => {
477
- let e = D.current;
478
- V(e.clientWidth || u.videoWidth, e.clientHeight || u.videoHeight), d.activeTexture(d.TEXTURE0), d.bindTexture(d.TEXTURE_2D, f.texture), d.texImage2D(d.TEXTURE_2D, 0, d.RGBA, d.RGBA, d.UNSIGNED_BYTE, u), u.play(), N = performance.now(), $.current = !0, j = requestAnimationFrame(G);
479
- }, q = () => {
480
- P = (P + 1) % F.length, u.src = F[P], u.load(), u.addEventListener("canplay", () => u.play(), { once: !0 });
481
- }, J = new ResizeObserver((e) => {
482
- let { width: t, height: n } = e[0].contentRect;
483
- $.current && t > 0 && n > 0 && V(t, n);
484
- });
485
- return D.current && J.observe(D.current), u.addEventListener("loadeddata", K, { once: !0 }), I && u.addEventListener("ended", q), u.readyState >= 2 && u.currentSrc.endsWith(F[0]) ? K() : u.currentSrc.endsWith(F[0]) || u.load(), () => {
486
- J.disconnect(), we.current = null, Te.current = null, Ee.current = null, $.current = !1, cancelAnimationFrame(j), u.removeEventListener("loadeddata", K), I && u.removeEventListener("ended", q), l.removeEventListener("mousemove", H), l.removeEventListener("mouseleave", U), l.removeEventListener("click", W), d.deleteTexture(f.texture), d.deleteTexture(f.charVectorsTexture), d.deleteFramebuffer(f.fbo), d.deleteTexture(f.fboTexture), d.deleteBuffer(f.buffer), d.deleteShader(f.vertShader), d.deleteShader(f.fragShader), d.deleteShader(f.pass1FragShader), d.deleteProgram(g), d.deleteProgram(b), d.deleteTexture(O.current), d.deleteTexture(k.current), d.deleteTexture(f.scatterStateTexture), d.deleteTexture(f.spreadStateTexture);
524
+ $.current && f.currentTime != F && f.readyState >= 2 && (g.activeTexture(g.TEXTURE0), g.bindTexture(g.TEXTURE_2D, x.texture), g.texSubImage2D(g.TEXTURE_2D, 0, 0, 0, g.RGBA, g.UNSIGNED_BYTE, f), F = f.currentTime), E.tick(g, x.mousePositionsLoc, x.mouseLifeFracsLoc), T.tick(g, d), M.tick(g, d, x.ripplePositionsLoc, x.rippleRadiiLoc, x.rippleBrightnessesLoc), N.tick(g), C === "shape" && (g.bindFramebuffer(g.FRAMEBUFFER, x.fbo), g.viewport(0, 0, t, n), g.useProgram(w), g.drawArrays(g.TRIANGLES, 0, 6), g.bindFramebuffer(g.FRAMEBUFFER, null), g.viewport(0, 0, d.width, d.height), g.useProgram(S)), g.drawArrays(g.TRIANGLES, 0, 6), P = requestAnimationFrame(J);
525
+ }, Y = () => {
526
+ let e = k.current, t = Q.current;
527
+ if (t && t.width > 0 && t.height > 0) W(t);
528
+ else {
529
+ let t = window.devicePixelRatio || 1, n = e.clientWidth || f.videoWidth, r = e.clientHeight || f.videoHeight;
530
+ W({
531
+ width: Math.round(n * t),
532
+ height: Math.round(r * t),
533
+ cssWidth: n,
534
+ cssHeight: r
535
+ });
536
+ }
537
+ g.activeTexture(g.TEXTURE0), g.bindTexture(g.TEXTURE_2D, x.texture), g.texImage2D(g.TEXTURE_2D, 0, g.RGBA, g.RGBA, g.UNSIGNED_BYTE, f), f.play(), I = performance.now(), $.current = !0, P = requestAnimationFrame(J);
538
+ }, X = () => {
539
+ L = (L + 1) % R.length, f.src = R[L], f.load(), f.addEventListener("canplay", () => f.play(), { once: !0 });
540
+ }, ie = k.current ? y(k.current, (e) => {
541
+ Q.current = e, $.current && e.width > 0 && e.height > 0 && W(e);
542
+ }) : () => {};
543
+ return f.addEventListener("loadeddata", Y, { once: !0 }), z && f.addEventListener("ended", X), f.readyState >= 2 && f.currentSrc.endsWith(R[0]) ? Y() : f.currentSrc.endsWith(R[0]) || f.load(), () => {
544
+ ie(), je.current = null, Me.current = null, Ne.current = null, Ae.current = null, $.current = !1, cancelAnimationFrame(P), f.removeEventListener("loadeddata", Y), z && f.removeEventListener("ended", X), d.removeEventListener("mousemove", G), d.removeEventListener("mouseleave", K), d.removeEventListener("click", q), g.deleteTexture(x.texture), g.deleteTexture(x.charVectorsTexture), g.deleteFramebuffer(x.fbo), g.deleteTexture(x.fboTexture), g.deleteBuffer(x.buffer), g.deleteShader(x.vertShader), g.deleteShader(x.fragShader), g.deleteShader(x.pass1FragShader), g.deleteProgram(S), g.deleteProgram(w), g.deleteTexture(A.current), g.deleteTexture(j.current), g.deleteTexture(x.scatterStateTexture), g.deleteTexture(x.spreadStateTexture);
487
545
  };
488
546
  }, [
489
547
  i,
490
- S,
491
- y,
548
+ C,
549
+ b,
550
+ re,
492
551
  ne,
493
- te,
494
- ee
552
+ te
495
553
  ]), /* @__PURE__ */ r("div", {
496
- ref: D,
497
- className: C,
554
+ ref: k,
555
+ className: w,
498
556
  style: {
499
557
  height: "100%",
500
558
  width: "100%"
501
559
  },
502
560
  children: [/* @__PURE__ */ n("video", {
503
- ref: E,
561
+ ref: O,
504
562
  muted: !0,
505
563
  playsInline: !0,
506
564
  autoPlay: !0,
@@ -511,7 +569,7 @@ function y({ src: i, videoMode: c = !1, numColsRaw: l = 250, brightnessRaw: u =
511
569
  type: "video/mp4"
512
570
  })
513
571
  }), /* @__PURE__ */ n("canvas", {
514
- ref: T,
572
+ ref: D,
515
573
  style: {
516
574
  width: "100%",
517
575
  height: "100%",
@@ -521,4 +579,4 @@ function y({ src: i, videoMode: c = !1, numColsRaw: l = 250, brightnessRaw: u =
521
579
  });
522
580
  }
523
581
  //#endregion
524
- export { y as VideoAscii };
582
+ export { b as VideoAscii };
@@ -1,4 +1,4 @@
1
- (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require(`react`),require(`react/jsx-runtime`)):typeof define==`function`&&define.amd?define([`exports`,`react`,`react/jsx-runtime`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.ReactVideoAscii={},e.React,e.ReactJSXRuntime))})(this,function(e,t,n){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var r=[[.25,.25],[.75,.25],[.25,.5],[.75,.5],[.25,.75],[.75,.75]];function i(e,t,n){let i=[],a=document.createElement(`canvas`);a.width=t,a.height=n;let o=a.getContext(`2d`,{willReadFrequently:!0});if(!o)return[];o.font=`${n}px monospace`,o.textBaseline=`top`;let s=t/5;for(let a of e){o.fillStyle=`black`,o.fillRect(0,0,t,n),o.fillStyle=`white`,o.fillText(a,0,0);let e=o.getImageData(0,0,t,n),c=[];for(let[i,a]of r){let r=i*t,o=a*n,l=0,u=0;for(let n=Math.floor(r-s);n<=Math.ceil(r+s);n+=1)for(let i=Math.floor(o-s);i<=Math.ceil(o+s);i+=1){let a=r-n,c=o-i;if(a*a+c*c<=s*s){let r=(i*t+n)*4,a=e.data[r];l+=a/255,u++}}let d=u>0?l/u:0;c.push(d)}i.push({char:a,vector:c})}let c=[,,,,,,].fill(0);for(let{vector:e}of i)for(let t=0;t<6;++t)e[t]>c[t]&&(c[t]=e[t]);for(let{vector:e}of i)for(let t=0;t<6;++t)e[t]/=c[t];return i}var a=` \`.',-_:!;|"~+^lr[](\\/L)>t<v=Tz?icf1{sIxY*jJno}CZyVwmSXRqM$O%#9&NW0Q@`;function o(e,t,n,r,i,a,o){let s=!!i,c=typeof i==`object`?i:{},l=c.style??`brighten`,u=s&&l!==`scatter`,d=s&&l===`scatter`,f=c.scatterChars??`->o`,p=c.trailLen??15,m=c.trailDecay??10,h=c.duration??1,g=c.radius??(l===`scatter`?.05:.08),_=c.brightness??2,v=!!a,y=typeof a==`object`?a:{},b=y.style??`ripple`,x=v&&b!==`spread`,S=v&&b===`spread`,C=y.brightness??1.1,w=y.speed??2,T=y.spreadExpandDuration??1.5,E=y.spreadSpeed??7.5,D=!!o,O=typeof o==`object`?o:{},k=O.type??`random`,A=O.duration??.4,j=Math.max(20,Math.min(350,Math.round(e))),M=Math.max(0,Math.min(2,t)),N=Math.max(0,Math.min(2,n)),P=Math.max(0,Math.min(1,r));A=Math.max(.1,Math.min(4,A)),p=Math.max(0,Math.min(30,Math.round(p))),m=Math.max(1,Math.min(15,m)),h=Math.max(.1,Math.min(4,h)),g=Math.max(.03,Math.min(.2,g)),_=Math.max(.2,Math.min(5,_)),C=Math.max(1.05,Math.min(2,C)),w=Math.max(.5,Math.min(4,w)),T=Math.max(.5,Math.min(5,T)),E=Math.max(.5,Math.min(10,E));let F;return F=D?k===`diagonal`?1:k===`radial`?2:3:0,{numCols:j,brightness:M,saturation:N,bgOpacity:P,mouseEnabled:s,mouseStyle:l,brightenEnabled:u,scatterEnabled:d,scatterChars:f,trailLen:p,trailDecay:m,duration:h,mouseRadius:g,mouseBrightness:_,clickEnabled:x,clickBrightness:C,clickSpeed:w,spreadEnabled:S,spreadExpandDuration:T,spreadSpeed:E,revealEnabled:D,revealType:k,revealDuration:A,revealEffectFlag:F}}function s(e,t,n){let r=e.createShader(t);if(!r)throw Error(`Failed to create shader`);return e.shaderSource(r,n),e.compileShader(r),e.getShaderParameter(r,e.COMPILE_STATUS)?r:(console.log(e.getShaderInfoLog(r)),e.deleteShader(r),null)}function c(e,t,n){let r=e.createProgram();return e.attachShader(r,t),e.attachShader(r,n),e.linkProgram(r),e.getProgramParameter(r,e.LINK_STATUS)?r:(console.log(e.getProgramInfoLog(r)),e.deleteProgram(r),null)}var l=`#version 300 es
1
+ (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require(`react`),require(`react/jsx-runtime`)):typeof define==`function`&&define.amd?define([`exports`,`react`,`react/jsx-runtime`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.ReactVideoAscii={},e.React,e.ReactJSXRuntime))})(this,function(e,t,n){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var r=[[.25,.25],[.75,.25],[.25,.5],[.75,.5],[.25,.75],[.75,.75]];function i(e,t,n){let i=[],a=document.createElement(`canvas`);a.width=t,a.height=n;let o=a.getContext(`2d`,{willReadFrequently:!0});if(!o)return[];o.font=`${n}px monospace`,o.textBaseline=`top`;let s=t/5;for(let a of e){o.fillStyle=`black`,o.fillRect(0,0,t,n),o.fillStyle=`white`,o.fillText(a,0,0);let e=o.getImageData(0,0,t,n),c=[];for(let[i,a]of r){let r=i*t,o=a*n,l=0,u=0;for(let n=Math.floor(r-s);n<=Math.ceil(r+s);n+=1)for(let i=Math.floor(o-s);i<=Math.ceil(o+s);i+=1){let a=r-n,c=o-i;if(a*a+c*c<=s*s){let r=(i*t+n)*4,a=e.data[r];l+=a/255,u++}}let d=u>0?l/u:0;c.push(d)}i.push({char:a,vector:c})}let c=[,,,,,,].fill(0);for(let{vector:e}of i)for(let t=0;t<6;++t)e[t]>c[t]&&(c[t]=e[t]);for(let{vector:e}of i)for(let t=0;t<6;++t)e[t]/=c[t];return i}var a=` \`.',-_:!;|"~+^lr[](\\/L)>t<v=Tz?icf1{sIxY*jJno}CZyVwmSXRqM$O%#9&NW0Q@`;function o(e,t,n,r,i,a,o,s){let c=!!i,l=typeof i==`object`?i:{},u=l.style??`brighten`,d=c&&u!==`scatter`,f=c&&u===`scatter`,p=l.scatterChars??`->o`,m=l.trailLen??15,h=l.trailDecay??10,g=l.duration??1,_=l.radius??(u===`scatter`?.05:.08),v=l.brightness??2,y=!!a,b=typeof a==`object`?a:{},x=b.style??`ripple`,S=y&&x!==`spread`,C=y&&x===`spread`,w=b.brightness??1.1,T=b.speed??2,E=b.spreadExpandDuration??1.5,D=b.spreadSpeed??7.5,O=!!o,k=typeof o==`object`?o:{},A=k.type??`random`,j=k.duration??.4,M=Math.max(20,Math.min(350,Math.round(e))),N=Math.max(0,Math.min(2,t)),P=Math.max(0,Math.min(2,n)),F=Math.max(0,Math.min(1,r));j=Math.max(.1,Math.min(4,j)),m=Math.max(0,Math.min(30,Math.round(m))),h=Math.max(1,Math.min(15,h)),g=Math.max(.1,Math.min(4,g)),_=Math.max(.03,Math.min(.2,_)),v=Math.max(.2,Math.min(5,v)),w=Math.max(1.05,Math.min(2,w)),T=Math.max(.5,Math.min(4,T)),E=Math.max(.5,Math.min(5,E)),D=Math.max(.5,Math.min(10,D));let I=s===void 0?1/0:Math.max(1,Math.min(4,s)),L;return L=O?A===`diagonal`?1:A===`radial`?2:3:0,{numCols:M,brightness:N,saturation:P,bgOpacity:F,mouseEnabled:c,mouseStyle:u,brightenEnabled:d,scatterEnabled:f,scatterChars:p,trailLen:m,trailDecay:h,duration:g,mouseRadius:_,mouseBrightness:v,clickEnabled:S,clickBrightness:w,clickSpeed:T,spreadEnabled:C,spreadExpandDuration:E,spreadSpeed:D,revealEnabled:O,revealType:A,revealDuration:j,revealEffectFlag:L,maxDpr:I}}function s(e,t,n){let r=e.createShader(t);if(!r)throw Error(`Failed to create shader`);return e.shaderSource(r,n),e.compileShader(r),e.getShaderParameter(r,e.COMPILE_STATUS)?r:(console.log(e.getShaderInfoLog(r)),e.deleteShader(r),null)}function c(e,t,n){let r=e.createProgram();return e.attachShader(r,t),e.attachShader(r,n),e.linkProgram(r),e.getProgramParameter(r,e.LINK_STATUS)?r:(console.log(e.getProgramInfoLog(r)),e.deleteProgram(r),null)}var l=`#version 300 es
2
2
 
3
3
  in vec2 a_position;
4
4
 
@@ -49,6 +49,7 @@ uniform float u_numChars;
49
49
  uniform vec2 u_gridSize;
50
50
  uniform vec2 u_cropOffset;
51
51
  uniform vec2 u_cropScale;
52
+ uniform vec2 u_gridOffset;
52
53
 
53
54
  out vec4 fragColor;
54
55
 
@@ -82,7 +83,10 @@ vec3 hsl2rgb(vec3 c) {
82
83
 
83
84
  void main() {
84
85
  vec2 fragCoord = vec2(gl_FragCoord.x, u_resolution.y - gl_FragCoord.y);
85
- vec2 cellCoord = floor(fragCoord / u_cellsize);
86
+ vec2 gridCoord = fragCoord - u_gridOffset;
87
+ vec2 cellCoordF = floor(gridCoord / u_cellsize);
88
+ bool inGrid = all(greaterThanEqual(cellCoordF, vec2(0.0))) && all(lessThan(cellCoordF, u_gridSize));
89
+ vec2 cellCoord = clamp(cellCoordF, vec2(0.0), u_gridSize - 1.0);
86
90
 
87
91
  if (u_revealEffectFlag == 1) {
88
92
 
@@ -106,7 +110,7 @@ void main() {
106
110
  }
107
111
  }
108
112
 
109
- vec2 cellCenter = (cellCoord + 0.5) * u_cellsize;
113
+ vec2 cellCenter = u_gridOffset + (cellCoord + 0.5) * u_cellsize;
110
114
 
111
115
  vec2 rawUV = u_videoMode ? (fragCoord / u_resolution) : (cellCenter / u_resolution);
112
116
  vec2 sampleUV = u_cropOffset + rawUV * u_cropScale;
@@ -118,11 +122,11 @@ void main() {
118
122
  hsl.y = clamp(hsl.y * u_saturation, 0.0, 1.0);
119
123
  cellColor = hsl2rgb(hsl);
120
124
 
121
- vec2 withinCellPos = fract(fragCoord / u_cellsize);
125
+ vec2 withinCellPos = fract(gridCoord / u_cellsize);
122
126
 
123
127
 
124
128
  float glyphMask = 0.0;
125
- if (!u_videoMode) {
129
+ if (!u_videoMode && inGrid) {
126
130
  uint charInd;
127
131
  if (u_shapeMatching) {
128
132
  charInd = texelFetch(u_fboTexture, ivec2(cellCoord), 0).r;
@@ -138,7 +142,7 @@ void main() {
138
142
 
139
143
  bool scatterHit = false;
140
144
  vec3 scatterColor = vec3(0.0);
141
- if (u_scatterEffect) {
145
+ if (u_scatterEffect && inGrid) {
142
146
  uint state = texelFetch(u_scatterStateTexture, ivec2(cellCoord), 0).r;
143
147
  if (state > 0u) {
144
148
  int idx = int(state) - 1;
@@ -151,7 +155,7 @@ void main() {
151
155
  }
152
156
  }
153
157
 
154
- if (!scatterHit && u_spreadEffect) {
158
+ if (!scatterHit && u_spreadEffect && inGrid) {
155
159
  uint state = texelFetch(u_spreadStateTexture, ivec2(cellCoord), 0).r;
156
160
  if (state > 0u) {
157
161
  int idx = int(state) - 1;
@@ -217,6 +221,7 @@ uniform int u_numCharsInt;
217
221
  uniform float u_shapeExponent;
218
222
  uniform vec2 u_cropOffset;
219
223
  uniform vec2 u_cropScale;
224
+ uniform vec2 u_gridOffset;
220
225
 
221
226
  out uvec4 fragCharInd;
222
227
 
@@ -234,7 +239,7 @@ void main() {
234
239
  float sv[6];
235
240
  for (int ci = 0; ci < 6; ci++) {
236
241
 
237
- vec2 centerUV = u_cropOffset + (vec2(cellCoord) + CIRCLES[ci]) * u_cellsize / u_resolution * u_cropScale;
242
+ vec2 centerUV = u_cropOffset + (u_gridOffset + (vec2(cellCoord) + CIRCLES[ci]) * u_cellsize) / u_resolution * u_cropScale;
238
243
  float total = 0.0;
239
244
  int count = 0;
240
245
  for (int dx = -u_circleN; dx <= u_circleN; dx++) {
@@ -277,4 +282,4 @@ void main() {
277
282
  }
278
283
 
279
284
  fragCharInd = uvec4(bestChar, 0u, 0u, 0u);
280
- }`;function f(e){let t=s(e,e.VERTEX_SHADER,l),n=s(e,e.FRAGMENT_SHADER,u);if(!t||!n)return null;let r=c(e,t,n);if(!r)return null;let i=new Float32Array([1,1,-1,1,1,-1,-1,-1,-1,1,1,-1]),a=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,a),e.bufferData(e.ARRAY_BUFFER,i,e.STATIC_DRAW);let o=e.getAttribLocation(r,`a_position`);e.vertexAttribPointer(o,2,e.FLOAT,!1,0,0),e.enableVertexAttribArray(o),e.useProgram(r);let f=e.createTexture();e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,f),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),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST);let p=e.getUniformLocation(r,`u_texture`);e.uniform1i(p,0);let m=e.createTexture();e.activeTexture(e.TEXTURE1),e.bindTexture(e.TEXTURE_2D,m),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),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST);let h=e.getUniformLocation(r,`u_atlas`);e.uniform1i(h,1);let g=e.createTexture();e.activeTexture(e.TEXTURE2),e.bindTexture(e.TEXTURE_2D,g),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),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST);let _=s(e,e.FRAGMENT_SHADER,d);if(!_)return null;let v=c(e,t,_);if(!v)return null;e.useProgram(v),e.uniform1i(e.getUniformLocation(v,`u_texture`),0),e.uniform1i(e.getUniformLocation(v,`u_charVectors`),2);let y=e.getUniformLocation(v,`u_resolution`),b=e.getUniformLocation(v,`u_cellsize`),x=e.getUniformLocation(v,`u_circleN`),S=e.getUniformLocation(v,`u_numCharsInt`),C=e.getUniformLocation(v,`u_shapeExponent`),w=e.getUniformLocation(v,`u_cropOffset`),T=e.getUniformLocation(v,`u_cropScale`),E=e.createTexture();e.activeTexture(e.TEXTURE3),e.bindTexture(e.TEXTURE_2D,E),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),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST);let D=e.createFramebuffer(),O=e.createTexture();e.activeTexture(e.TEXTURE4),e.bindTexture(e.TEXTURE_2D,O),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),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST);let k=e.createTexture();e.activeTexture(e.TEXTURE5),e.bindTexture(e.TEXTURE_2D,k),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),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST);let A=e.createTexture();return e.activeTexture(e.TEXTURE6),e.bindTexture(e.TEXTURE_2D,A),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),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST),e.useProgram(r),e.uniform1i(e.getUniformLocation(r,`u_fboTexture`),3),e.uniform1i(e.getUniformLocation(r,`u_scatterAtlas`),4),e.uniform1i(e.getUniformLocation(r,`u_scatterStateTexture`),5),e.uniform1i(e.getUniformLocation(r,`u_spreadStateTexture`),6),{program:r,pass1Program:v,buffer:a,vertShader:t,fragShader:n,pass1FragShader:_,texture:f,atlasTexture:m,charVectorsTexture:g,fboTexture:E,fbo:D,scatterAtlasTexture:O,scatterStateTexture:k,spreadStateTexture:A,p1ResLoc:y,p1CellsizeLoc:b,p1CircleNLoc:x,p1NumCharsLoc:S,p1ExponentLoc:C,p1CropOffsetLoc:w,p1CropScaleLoc:T,revealEffectFlagLoc:e.getUniformLocation(r,`u_revealEffectFlag`),mouseEffectFlagLoc:e.getUniformLocation(r,`u_mouseEffect`),clickEffectFlagLoc:e.getUniformLocation(r,`u_clickEffect`),shapeMatchingLoc:e.getUniformLocation(r,`u_shapeMatching`),revealProgressLoc:e.getUniformLocation(r,`u_revealProgress`),brightnessLoc:e.getUniformLocation(r,`u_brightness`),saturationLoc:e.getUniformLocation(r,`u_saturation`),bgOpacityLoc:e.getUniformLocation(r,`u_bgOpacity`),mouseBrightnessLoc:e.getUniformLocation(r,`u_mouseBrightness`),mousePositionsLoc:e.getUniformLocation(r,`u_mousePositions`),mouseLifeFracsLoc:e.getUniformLocation(r,`u_mouseLifeFracs`),mouseRadiusLoc:e.getUniformLocation(r,`u_mouseRadius`),ripplePositionsLoc:e.getUniformLocation(r,`u_ripplePositions`),rippleRadiiLoc:e.getUniformLocation(r,`u_rippleRadii`),rippleBrightnessesLoc:e.getUniformLocation(r,`u_rippleBrightnesses`),scatterEffectFlagLoc:e.getUniformLocation(r,`u_scatterEffect`),scatterNumCharsLoc:e.getUniformLocation(r,`u_scatterNumChars`),spreadEffectFlagLoc:e.getUniformLocation(r,`u_spreadEffect`),videoModeLoc:e.getUniformLocation(r,`u_videoMode`),resLoc:e.getUniformLocation(r,`u_resolution`),sizeLoc:e.getUniformLocation(r,`u_cellsize`),numLoc:e.getUniformLocation(r,`u_numChars`),gridSizeLoc:e.getUniformLocation(r,`u_gridSize`),cropOffsetLoc:e.getUniformLocation(r,`u_cropOffset`),cropScaleLoc:e.getUniformLocation(r,`u_cropScale`)}}function p({scatterEnabledRef:e,mouseRadiusRef:t,durationRef:n,scatterCharsRef:r}){let i=new Uint8Array,a=new Float32Array,o=new Float32Array,s=new Uint8Array,c=null,l=null,u=0,d=0,f=-1,p=()=>Math.floor(Math.random()*r.current.length),m=0,h=0,g=1,_=1,v=null;return{setup(e,t,n,r,f,p){m=t,h=n,g=r,_=f,v=p;let y=t*n;i=new Uint8Array(y),a=new Float32Array(y),o=new Float32Array(y),s=new Uint8Array(y),c=null,l=null,u=0,d=0,e.activeTexture(e.TEXTURE5),e.bindTexture(e.TEXTURE_2D,p),e.texImage2D(e.TEXTURE_2D,0,e.R8UI,t,n,0,e.RED_INTEGER,e.UNSIGNED_BYTE,i)},handleMouseMove(t,n,r){e.current&&(l=c,c={x:t,y:n,t:r})},handleMouseLeave(){c=null,l=null,u=0,d=0},reset(e){i.fill(0),v&&m>0&&(e.activeTexture(e.TEXTURE5),e.bindTexture(e.TEXTURE_2D,v),e.texSubImage2D(e.TEXTURE_2D,0,0,0,m,h,e.RED_INTEGER,e.UNSIGNED_BYTE,i))},tick(r,y){if(!e.current||m===0||h===0)return;let b=performance.now(),x=f<0?0:Math.min(.1,(b-f)/1e3);f=b;let S=Math.min(y.width,y.height)*t.current,C=!1;if(c&&b-c.t<80){if(l){let e=(c.t-l.t)/1e3;if(e>0&&e<.2){let t=(c.x-l.x)/e,n=(c.y-l.y)/e;u=u*.7+t*.3,d=d*.7+n*.3}}else u=0,d=0;Math.hypot(u,d)>g*2&&(C=!0)}else u*=.6,d*=.6;if(s.fill(0),C&&c&&S>0){let e=c.x,t=c.y,n=Math.max(0,Math.floor((e-S)/g)),r=Math.min(m-1,Math.floor((e+S)/g)),l=Math.max(0,Math.floor((t-S)/_)),u=Math.min(h-1,Math.floor((t+S)/_));for(let c=l;c<=u;c++)for(let l=n;l<=r;l++){let n=(l+.5)*g,r=(c+.5)*_;if(Math.hypot(n-e,r-t)>S)continue;let u=c*m+l;s[u]=1,i[u]===0&&(i[u]=1+p(),o[u]=.5+Math.random()*2),a[u]=1}}let w=n.current;if(x>0)for(let e=0;e<h;e++)for(let t=0;t<m;t++){let n=e*m+t;if(i[n]===0||s[n])continue;let r=t>0?i[n-1]!==0:!1,c=t<m-1?i[n+1]!==0:!1,l=e>0?i[n-m]!==0:!1,u=e<h-1?i[n+m]!==0:!1,d=(!r||!c||!l||!u?5:1)*o[n]/w;a[n]-=d*x,a[n]<=0&&(i[n]=0)}r.activeTexture(r.TEXTURE5),r.bindTexture(r.TEXTURE_2D,v),r.texSubImage2D(r.TEXTURE_2D,0,0,0,m,h,r.RED_INTEGER,r.UNSIGNED_BYTE,i)}}}function m({brightenEnabledRef:e,trailLenRef:t,durationRef:n,trailDecayRef:r}){let i=[];return{handleMouseMove(n,r,a){e.current&&(i.push({x:n,y:r,t:a}),i.length>t.current&&i.shift())},tick(a,o,s){if(!e.current)return;let c=performance.now(),l=new Float32Array(t.current*2),u=new Float32Array(t.current);for(let e=0;e<i.length;e++){let t=c-i[e].t,a=Math.max(0,1-t/(n.current*1e3))**r.current;l[e*2]=i[e].x,l[e*2+1]=i[e].y,u[e]=a}a.uniform2fv(o,l),a.uniform1fv(s,u)}}}var h=10;function g({clickEnabledRef:e,clickSpeedRef:t,clickBrightnessRef:n}){let r=[];return{handleClick(t,n){if(!e.current)return;let i=n.getBoundingClientRect(),a=(t.clientX-i.left)*(n.width/i.width),o=(t.clientY-i.top)*(n.height/i.height);r.push({x:a,y:o,t:performance.now()}),r.length>h&&r.shift()},tick(i,a,o,s,c){if(!e.current)return;let l=performance.now(),u=Math.hypot(a.width,a.height),d=new Float32Array(h*2),f=new Float32Array(h),p=new Float32Array(h);for(;r.length>0&&(l-r[0].t)*t.current>=u;)r.shift();for(let e=0;e<r.length;e++){let i=(l-r[e].t)*t.current,a=i/u,o=1+(n.current-1)*(1-a**2);d[e*2]=r[e].x,d[e*2+1]=r[e].y,f[e]=i,p[e]=o}i.uniform2fv(o,d),i.uniform1fv(s,f),i.uniform1fv(c,p)}}}function _({spreadEnabledRef:e,scatterCharsRef:t,spreadExpandDurationRef:n,spreadSpeedRef:r}){let i=new Uint8Array,a=new Uint8Array,o=0,s=0,c=1,l=1,u=null,d=-1,f=-1,p=()=>Math.floor(Math.random()*t.current.length),m=[[-1,0],[1,0],[0,-1],[0,1]];return{setup(e,t,n,r,p,m){o=t,s=n,c=r,l=p,u=m;let h=t*n;i=new Uint8Array(h),a=new Uint8Array(h),f=-1,d=-1,e.activeTexture(e.TEXTURE6),e.bindTexture(e.TEXTURE_2D,m),e.texImage2D(e.TEXTURE_2D,0,e.R8UI,t,n,0,e.RED_INTEGER,e.UNSIGNED_BYTE,i)},handleClick(t,r){if(!e.current||o===0)return;let u=r.getBoundingClientRect(),d=(t.clientX-u.left)*(r.width/u.width),m=(t.clientY-u.top)*(r.height/u.height),h=Math.floor(d/c),g=Math.floor(m/l);if(h<0||h>=o||g<0||g>=s)return;let _=g*o+h;i[_]=1+p(),a[_]=1,f=performance.now()+n.current*1e3},tick(t){if(!e.current||o===0||s===0)return;let n=performance.now(),c=d<0?0:Math.min(.1,(n-d)/1e3);d=n;let l=f>0&&n<f;if(!l&&f>0){for(let e=0;e<i.length;e++)a[e]===1&&(a[e]=2);f=-1}if(c>0)for(let e=0;e<s;e++)for(let t=0;t<o;t++){let n=e*o+t;if(a[n]!==0){if(l&&a[n]===1)for(let[n,l]of m){let u=e+n,d=t+l;if(u<0||u>=s||d<0||d>=o)continue;let f=u*o+d;a[f]===0&&Math.random()<r.current*c&&(i[f]=1+p(),a[f]=1)}else if(a[n]===2)for(let[l,u]of m){let d=e+l,f=t+u;if(d<0||d>=s||f<0||f>=o||i[d*o+f]===0){Math.random()<r.current*c&&(i[n]=0,a[n]=0);break}}}}t.activeTexture(t.TEXTURE6),t.bindTexture(t.TEXTURE_2D,u),t.texSubImage2D(t.TEXTURE_2D,0,0,0,o,s,t.RED_INTEGER,t.UNSIGNED_BYTE,i)}}}function v({src:e,videoMode:r=!1,numColsRaw:s=250,brightnessRaw:c=1,saturationRaw:l=1,bgOpacityRaw:u=.3,revealEffect:d=!1,chars:h=a,mouseEffect:v=!0,clickEffect:y=!0,charMode:b=`shape`,className:x,cropFocus:S=`center`}){let C=(0,t.useRef)(null),w=(0,t.useRef)(null),T=(0,t.useRef)(null),E=(0,t.useRef)(null),D=(0,t.useRef)(null),{numCols:O,brightness:k,saturation:A,bgOpacity:j,mouseEnabled:M,mouseStyle:N,brightenEnabled:P,scatterEnabled:F,scatterChars:I,trailLen:L,trailDecay:R,duration:z,mouseRadius:B,mouseBrightness:V,clickEnabled:H,clickBrightness:U,clickSpeed:W,spreadEnabled:G,spreadExpandDuration:K,spreadSpeed:q,revealEnabled:ee,revealDuration:te,revealEffectFlag:ne}=o(s,c,l,u,v,y,d),re=(0,t.useRef)(k),ie=(0,t.useRef)(A),ae=(0,t.useRef)(j),oe=(0,t.useRef)(M),J=(0,t.useRef)(N),Y=(0,t.useRef)(P),X=(0,t.useRef)(F),se=(0,t.useRef)(V),Z=(0,t.useRef)(B),ce=(0,t.useRef)(L),le=(0,t.useRef)(R),ue=(0,t.useRef)(z),Q=(0,t.useRef)(I),de=(0,t.useRef)(H),fe=(0,t.useRef)(U),pe=(0,t.useRef)(W),me=(0,t.useRef)(G),he=(0,t.useRef)(K),ge=(0,t.useRef)(q),_e=(0,t.useRef)(O),ve=(0,t.useRef)(r),ye=(0,t.useRef)(S),be=(0,t.useRef)(0),xe=(0,t.useRef)(0);(0,t.useEffect)(()=>{re.current=k,ie.current=A,ae.current=j,oe.current=M,J.current=N,Y.current=P,X.current=F,se.current=V,Z.current=B,ce.current=L,le.current=R,ue.current=z,Q.current!==I&&$.current?(Q.current=I,Ce.current?.()):Q.current=I,de.current=H,fe.current=U,pe.current=W,me.current=G,he.current=K,ge.current=q,_e.current=O,ve.current=r},[k,A,j,M,N,P,F,V,B,L,R,z,I,H,U,W,G,K,q,O,r]);let Se=(0,t.useRef)(null),Ce=(0,t.useRef)(null),we=(0,t.useRef)(null),$=(0,t.useRef)(!1);return(0,t.useEffect)(()=>{$.current&&Se.current?.(O)},[O]),(0,t.useEffect)(()=>{ye.current=S,$.current&&be.current>0&&we.current?.(be.current,xe.current)},[S]),(0,t.useEffect)(()=>{$.current=!1;let t=[],n=0,r=0,a=1,o=1,s=0,c=0,l=C.current;if(!l)return;let u=w.current;if(!u)return;let d=l.getContext(`webgl2`);if(!d)return;d.pixelStorei(d.UNPACK_ALIGNMENT,1);let v=f(d);if(!v)return;let{program:y,pass1Program:x}=v;E.current=v.atlasTexture,D.current=v.scatterAtlasTexture,d.uniform1i(v.shapeMatchingLoc,+(b===`shape`)),d.uniform1i(v.revealEffectFlagLoc,ne),d.uniform1f(v.revealProgressLoc,0);let S=p({scatterEnabledRef:X,mouseRadiusRef:Z,durationRef:ue,scatterCharsRef:Q}),O=m({brightenEnabledRef:Y,trailLenRef:ce,durationRef:ue,trailDecayRef:le}),k=g({clickEnabledRef:de,clickSpeedRef:pe,clickBrightnessRef:fe}),A=_({spreadEnabledRef:me,scatterCharsRef:Q,spreadExpandDurationRef:he,spreadSpeedRef:ge}),j,M=-1,N=-1,P=0,F=Array.isArray(e)?e:[e],I=F.length>1,L=document.createElement(`canvas`),R=L.getContext(`2d`),z=e=>{let u=s>0?s:l.width,f=c>0?c:l.height;a=Math.max(1,Math.floor(u/e));let p=a*2;if(R.font=`${p}px monospace`,o=Math.max(1,Math.round(p*a/R.measureText(`M`).width)),n=Math.floor(u/a),r=Math.floor(f/o),l.width=n*a,l.height=r*o,d.viewport(0,0,l.width,l.height),d.useProgram(y),d.uniform2f(v.resLoc,l.width,l.height),d.useProgram(x),d.uniform2f(v.p1ResLoc,l.width,l.height),d.useProgram(y),S.setup(d,n,r,a,o,v.scatterStateTexture),A.setup(d,n,r,a,o,v.spreadStateTexture),b===`shape`){t=i(h,a,o);let e=t.length,s=new Float32Array(e*8);for(let n=0;n<e;n++){let r=t[n].vector;s[n*4+0]=r[0],s[n*4+1]=r[1],s[n*4+2]=r[2],s[n*4+3]=r[3],s[e*4+n*4+0]=r[4],s[e*4+n*4+1]=r[5]}d.activeTexture(d.TEXTURE2),d.bindTexture(d.TEXTURE_2D,v.charVectorsTexture),d.texImage2D(d.TEXTURE_2D,0,d.RGBA32F,e,2,0,d.RGBA,d.FLOAT,s),d.activeTexture(d.TEXTURE3),d.bindTexture(d.TEXTURE_2D,v.fboTexture),d.texImage2D(d.TEXTURE_2D,0,d.R8UI,n,r,0,d.RED_INTEGER,d.UNSIGNED_BYTE,null),d.bindFramebuffer(d.FRAMEBUFFER,v.fbo),d.framebufferTexture2D(d.FRAMEBUFFER,d.COLOR_ATTACHMENT0,d.TEXTURE_2D,v.fboTexture,0),d.bindFramebuffer(d.FRAMEBUFFER,null);let c=Math.max(1,Math.round(a/5));d.useProgram(x),d.uniform2f(v.p1CellsizeLoc,a,o),d.uniform1i(v.p1CircleNLoc,c),d.uniform1i(v.p1NumCharsLoc,e),d.uniform1f(v.p1ExponentLoc,2),d.useProgram(y)}d.uniform2f(v.gridSizeLoc,n,r),L.width=h.length*a,L.height=o,R.font=`${o}px monospace`,R.fillStyle=`black`,R.fillRect(0,0,h.length*a,o),R.fillStyle=`white`,R.textBaseline=`top`;for(let e=0;e<h.length;e++)R.fillText(h[e],e*a,0);d.activeTexture(d.TEXTURE1),d.bindTexture(d.TEXTURE_2D,E.current),d.texImage2D(d.TEXTURE_2D,0,d.RGBA,d.RGBA,d.UNSIGNED_BYTE,L),d.uniform1f(v.numLoc,h.length),d.uniform2f(v.sizeLoc,a,o),B()},B=()=>{let e=Q.current;L.width=e.length*a,L.height=o,R.fillStyle=`black`,R.fillRect(0,0,L.width,o),R.fillStyle=`white`,R.textBaseline=`top`,R.font=`${o}px monospace`;for(let t=0;t<e.length;t++)R.fillText(e[t],t*a,0);d.activeTexture(d.TEXTURE4),d.bindTexture(d.TEXTURE_2D,D.current),d.texImage2D(d.TEXTURE_2D,0,d.RGBA,d.RGBA,d.UNSIGNED_BYTE,L),d.uniform1f(v.scatterNumCharsLoc,e.length),S.reset(d)};Se.current=z,Ce.current=B;let V=(e,t)=>{s=Math.round(e),c=Math.round(t),be.current=s,xe.current=c,l.width=s,l.height=c,z(_e.current);let n=u.videoWidth/u.videoHeight,r=l.width/l.height,i=1,a=1,o=0,f=0;if(r>n)a=n/r,f=(1-a)/2;else{i=r/n;let e=ye.current,t=e===`left`?.25:e===`right`?.75:.5;o=Math.max(0,Math.min(1-i,t-i/2))}d.uniform2f(v.cropOffsetLoc,o,f),d.uniform2f(v.cropScaleLoc,i,a),d.useProgram(x),d.uniform2f(v.p1CropOffsetLoc,o,f),d.uniform2f(v.p1CropScaleLoc,i,a),d.useProgram(y)};we.current=V;let H=e=>{if(!oe.current)return;let t=l.getBoundingClientRect(),n=(e.clientX-t.left)*(l.width/t.width),r=(e.clientY-t.top)*(l.height/t.height),i=performance.now();O.handleMouseMove(n,r,i),S.handleMouseMove(n,r,i)};l.addEventListener(`mousemove`,H);let U=()=>S.handleMouseLeave();l.addEventListener(`mouseleave`,U);let W=e=>{k.handleClick(e,l),A.handleClick(e,l)};l.addEventListener(`click`,W);let G=()=>{if(d.uniform1i(v.videoModeLoc,+!!ve.current),d.uniform1f(v.brightnessLoc,re.current),d.uniform1f(v.saturationLoc,ie.current),d.uniform1f(v.bgOpacityLoc,ae.current),d.uniform1i(v.mouseEffectFlagLoc,+!!Y.current),d.uniform1i(v.scatterEffectFlagLoc,+!!X.current),d.uniform1i(v.clickEffectFlagLoc,+!!de.current),d.uniform1i(v.spreadEffectFlagLoc,+!!me.current),d.uniform1f(v.mouseBrightnessLoc,se.current),d.uniform1f(v.mouseRadiusLoc,Math.min(l.width,l.height)*Z.current),ee){let e=N<0?0:Math.min(1,(performance.now()-N)/(te*1e3));d.uniform1f(v.revealProgressLoc,e)}$.current&&u.currentTime!=M&&u.readyState>=2&&(d.activeTexture(d.TEXTURE0),d.bindTexture(d.TEXTURE_2D,v.texture),d.texSubImage2D(d.TEXTURE_2D,0,0,0,d.RGBA,d.UNSIGNED_BYTE,u),M=u.currentTime),O.tick(d,v.mousePositionsLoc,v.mouseLifeFracsLoc),S.tick(d,l),k.tick(d,l,v.ripplePositionsLoc,v.rippleRadiiLoc,v.rippleBrightnessesLoc),A.tick(d),b===`shape`&&(d.bindFramebuffer(d.FRAMEBUFFER,v.fbo),d.viewport(0,0,n,r),d.useProgram(x),d.drawArrays(d.TRIANGLES,0,6),d.bindFramebuffer(d.FRAMEBUFFER,null),d.viewport(0,0,l.width,l.height),d.useProgram(y)),d.drawArrays(d.TRIANGLES,0,6),j=requestAnimationFrame(G)},K=()=>{let e=T.current;V(e.clientWidth||u.videoWidth,e.clientHeight||u.videoHeight),d.activeTexture(d.TEXTURE0),d.bindTexture(d.TEXTURE_2D,v.texture),d.texImage2D(d.TEXTURE_2D,0,d.RGBA,d.RGBA,d.UNSIGNED_BYTE,u),u.play(),N=performance.now(),$.current=!0,j=requestAnimationFrame(G)},q=()=>{P=(P+1)%F.length,u.src=F[P],u.load(),u.addEventListener(`canplay`,()=>u.play(),{once:!0})},J=new ResizeObserver(e=>{let{width:t,height:n}=e[0].contentRect;$.current&&t>0&&n>0&&V(t,n)});return T.current&&J.observe(T.current),u.addEventListener(`loadeddata`,K,{once:!0}),I&&u.addEventListener(`ended`,q),u.readyState>=2&&u.currentSrc.endsWith(F[0])?K():u.currentSrc.endsWith(F[0])||u.load(),()=>{J.disconnect(),Se.current=null,Ce.current=null,we.current=null,$.current=!1,cancelAnimationFrame(j),u.removeEventListener(`loadeddata`,K),I&&u.removeEventListener(`ended`,q),l.removeEventListener(`mousemove`,H),l.removeEventListener(`mouseleave`,U),l.removeEventListener(`click`,W),d.deleteTexture(v.texture),d.deleteTexture(v.charVectorsTexture),d.deleteFramebuffer(v.fbo),d.deleteTexture(v.fboTexture),d.deleteBuffer(v.buffer),d.deleteShader(v.vertShader),d.deleteShader(v.fragShader),d.deleteShader(v.pass1FragShader),d.deleteProgram(y),d.deleteProgram(x),d.deleteTexture(E.current),d.deleteTexture(D.current),d.deleteTexture(v.scatterStateTexture),d.deleteTexture(v.spreadStateTexture)}},[e,b,h,ne,te,ee]),(0,n.jsxs)(`div`,{ref:T,className:x,style:{height:`100%`,width:`100%`},children:[(0,n.jsx)(`video`,{ref:w,muted:!0,playsInline:!0,autoPlay:!0,loop:!Array.isArray(e)||e.length===1,style:{display:`none`},children:(0,n.jsx)(`source`,{src:Array.isArray(e)?e[0]:e,type:`video/mp4`})}),(0,n.jsx)(`canvas`,{ref:C,style:{width:`100%`,height:`100%`,display:`block`}})]})}e.VideoAscii=v});
285
+ }`;function f(e){let t=s(e,e.VERTEX_SHADER,l),n=s(e,e.FRAGMENT_SHADER,u);if(!t||!n)return null;let r=c(e,t,n);if(!r)return null;let i=new Float32Array([1,1,-1,1,1,-1,-1,-1,-1,1,1,-1]),a=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,a),e.bufferData(e.ARRAY_BUFFER,i,e.STATIC_DRAW);let o=e.getAttribLocation(r,`a_position`);e.vertexAttribPointer(o,2,e.FLOAT,!1,0,0),e.enableVertexAttribArray(o),e.useProgram(r);let f=e.createTexture();e.activeTexture(e.TEXTURE0),e.bindTexture(e.TEXTURE_2D,f),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),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.LINEAR);let p=e.getUniformLocation(r,`u_texture`);e.uniform1i(p,0);let m=e.createTexture();e.activeTexture(e.TEXTURE1),e.bindTexture(e.TEXTURE_2D,m),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),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST);let h=e.getUniformLocation(r,`u_atlas`);e.uniform1i(h,1);let g=e.createTexture();e.activeTexture(e.TEXTURE2),e.bindTexture(e.TEXTURE_2D,g),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),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST);let _=s(e,e.FRAGMENT_SHADER,d);if(!_)return null;let v=c(e,t,_);if(!v)return null;e.useProgram(v),e.uniform1i(e.getUniformLocation(v,`u_texture`),0),e.uniform1i(e.getUniformLocation(v,`u_charVectors`),2);let y=e.getUniformLocation(v,`u_resolution`),b=e.getUniformLocation(v,`u_cellsize`),x=e.getUniformLocation(v,`u_circleN`),S=e.getUniformLocation(v,`u_numCharsInt`),C=e.getUniformLocation(v,`u_shapeExponent`),w=e.getUniformLocation(v,`u_cropOffset`),T=e.getUniformLocation(v,`u_cropScale`),E=e.getUniformLocation(v,`u_gridOffset`),D=e.createTexture();e.activeTexture(e.TEXTURE3),e.bindTexture(e.TEXTURE_2D,D),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),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST);let O=e.createFramebuffer(),k=e.createTexture();e.activeTexture(e.TEXTURE4),e.bindTexture(e.TEXTURE_2D,k),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),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST);let A=e.createTexture();e.activeTexture(e.TEXTURE5),e.bindTexture(e.TEXTURE_2D,A),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),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST);let j=e.createTexture();return e.activeTexture(e.TEXTURE6),e.bindTexture(e.TEXTURE_2D,j),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),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST),e.useProgram(r),e.uniform1i(e.getUniformLocation(r,`u_fboTexture`),3),e.uniform1i(e.getUniformLocation(r,`u_scatterAtlas`),4),e.uniform1i(e.getUniformLocation(r,`u_scatterStateTexture`),5),e.uniform1i(e.getUniformLocation(r,`u_spreadStateTexture`),6),{program:r,pass1Program:v,buffer:a,vertShader:t,fragShader:n,pass1FragShader:_,texture:f,atlasTexture:m,charVectorsTexture:g,fboTexture:D,fbo:O,scatterAtlasTexture:k,scatterStateTexture:A,spreadStateTexture:j,p1ResLoc:y,p1CellsizeLoc:b,p1CircleNLoc:x,p1NumCharsLoc:S,p1ExponentLoc:C,p1CropOffsetLoc:w,p1CropScaleLoc:T,p1GridOffsetLoc:E,revealEffectFlagLoc:e.getUniformLocation(r,`u_revealEffectFlag`),mouseEffectFlagLoc:e.getUniformLocation(r,`u_mouseEffect`),clickEffectFlagLoc:e.getUniformLocation(r,`u_clickEffect`),shapeMatchingLoc:e.getUniformLocation(r,`u_shapeMatching`),revealProgressLoc:e.getUniformLocation(r,`u_revealProgress`),brightnessLoc:e.getUniformLocation(r,`u_brightness`),saturationLoc:e.getUniformLocation(r,`u_saturation`),bgOpacityLoc:e.getUniformLocation(r,`u_bgOpacity`),mouseBrightnessLoc:e.getUniformLocation(r,`u_mouseBrightness`),mousePositionsLoc:e.getUniformLocation(r,`u_mousePositions`),mouseLifeFracsLoc:e.getUniformLocation(r,`u_mouseLifeFracs`),mouseRadiusLoc:e.getUniformLocation(r,`u_mouseRadius`),ripplePositionsLoc:e.getUniformLocation(r,`u_ripplePositions`),rippleRadiiLoc:e.getUniformLocation(r,`u_rippleRadii`),rippleBrightnessesLoc:e.getUniformLocation(r,`u_rippleBrightnesses`),scatterEffectFlagLoc:e.getUniformLocation(r,`u_scatterEffect`),scatterNumCharsLoc:e.getUniformLocation(r,`u_scatterNumChars`),spreadEffectFlagLoc:e.getUniformLocation(r,`u_spreadEffect`),videoModeLoc:e.getUniformLocation(r,`u_videoMode`),resLoc:e.getUniformLocation(r,`u_resolution`),sizeLoc:e.getUniformLocation(r,`u_cellsize`),numLoc:e.getUniformLocation(r,`u_numChars`),gridSizeLoc:e.getUniformLocation(r,`u_gridSize`),cropOffsetLoc:e.getUniformLocation(r,`u_cropOffset`),cropScaleLoc:e.getUniformLocation(r,`u_cropScale`),gridOffsetLoc:e.getUniformLocation(r,`u_gridOffset`)}}function p({scatterEnabledRef:e,mouseRadiusRef:t,durationRef:n,scatterCharsRef:r}){let i=new Uint8Array,a=new Float32Array,o=new Float32Array,s=new Uint8Array,c=null,l=null,u=0,d=0,f=-1,p=()=>Math.floor(Math.random()*r.current.length),m=0,h=0,g=1,_=1,v=0,y=0,b=null;return{setup(e,t,n,r,f,p,x,S){m=t,h=n,g=r,_=f,v=p,y=x,b=S;let C=t*n;i=new Uint8Array(C),a=new Float32Array(C),o=new Float32Array(C),s=new Uint8Array(C),c=null,l=null,u=0,d=0,e.activeTexture(e.TEXTURE5),e.bindTexture(e.TEXTURE_2D,S),e.texImage2D(e.TEXTURE_2D,0,e.R8UI,t,n,0,e.RED_INTEGER,e.UNSIGNED_BYTE,i)},handleMouseMove(t,n,r){e.current&&(l=c,c={x:t,y:n,t:r})},handleMouseLeave(){c=null,l=null,u=0,d=0},reset(e){i.fill(0),b&&m>0&&(e.activeTexture(e.TEXTURE5),e.bindTexture(e.TEXTURE_2D,b),e.texSubImage2D(e.TEXTURE_2D,0,0,0,m,h,e.RED_INTEGER,e.UNSIGNED_BYTE,i))},tick(r,x){if(!e.current||m===0||h===0)return;let S=performance.now(),C=f<0?0:Math.min(.1,(S-f)/1e3);f=S;let w=Math.min(x.width,x.height)*t.current,T=!1;if(c&&S-c.t<80){if(l){let e=(c.t-l.t)/1e3;if(e>0&&e<.2){let t=(c.x-l.x)/e,n=(c.y-l.y)/e;u=u*.7+t*.3,d=d*.7+n*.3}}else u=0,d=0;Math.hypot(u,d)>g*2&&(T=!0)}else u*=.6,d*=.6;if(s.fill(0),T&&c&&w>0){let e=c.x,t=c.y,n=Math.max(0,Math.floor((e-v-w)/g)),r=Math.min(m-1,Math.floor((e-v+w)/g)),l=Math.max(0,Math.floor((t-y-w)/_)),u=Math.min(h-1,Math.floor((t-y+w)/_));for(let c=l;c<=u;c++)for(let l=n;l<=r;l++){let n=v+(l+.5)*g,r=y+(c+.5)*_;if(Math.hypot(n-e,r-t)>w)continue;let u=c*m+l;s[u]=1,i[u]===0&&(i[u]=1+p(),o[u]=.5+Math.random()*2),a[u]=1}}let E=n.current;if(C>0)for(let e=0;e<h;e++)for(let t=0;t<m;t++){let n=e*m+t;if(i[n]===0||s[n])continue;let r=t>0?i[n-1]!==0:!1,c=t<m-1?i[n+1]!==0:!1,l=e>0?i[n-m]!==0:!1,u=e<h-1?i[n+m]!==0:!1,d=(!r||!c||!l||!u?5:1)*o[n]/E;a[n]-=d*C,a[n]<=0&&(i[n]=0)}r.activeTexture(r.TEXTURE5),r.bindTexture(r.TEXTURE_2D,b),r.texSubImage2D(r.TEXTURE_2D,0,0,0,m,h,r.RED_INTEGER,r.UNSIGNED_BYTE,i)}}}function m({brightenEnabledRef:e,trailLenRef:t,durationRef:n,trailDecayRef:r}){let i=[];return{handleMouseMove(n,r,a){e.current&&(i.push({x:n,y:r,t:a}),i.length>t.current&&i.shift())},tick(a,o,s){if(!e.current)return;let c=performance.now(),l=new Float32Array(t.current*2),u=new Float32Array(t.current);for(let e=0;e<i.length;e++){let t=c-i[e].t,a=Math.max(0,1-t/(n.current*1e3))**r.current;l[e*2]=i[e].x,l[e*2+1]=i[e].y,u[e]=a}a.uniform2fv(o,l),a.uniform1fv(s,u)}}}var h=10;function g({clickEnabledRef:e,clickSpeedRef:t,clickBrightnessRef:n,pixelScaleRef:r}){let i=[];return{handleClick(t,n){if(!e.current)return;let r=n.getBoundingClientRect(),a=(t.clientX-r.left)*(n.width/r.width),o=(t.clientY-r.top)*(n.height/r.height);i.push({x:a,y:o,t:performance.now()}),i.length>h&&i.shift()},tick(a,o,s,c,l){if(!e.current)return;let u=performance.now(),d=Math.hypot(o.width,o.height),f=t.current*r.current,p=new Float32Array(h*2),m=new Float32Array(h),g=new Float32Array(h);for(;i.length>0&&(u-i[0].t)*f>=d;)i.shift();for(let e=0;e<i.length;e++){let t=(u-i[e].t)*f,r=t/d,a=1+(n.current-1)*(1-r**2);p[e*2]=i[e].x,p[e*2+1]=i[e].y,m[e]=t,g[e]=a}a.uniform2fv(s,p),a.uniform1fv(c,m),a.uniform1fv(l,g)}}}function _({spreadEnabledRef:e,scatterCharsRef:t,spreadExpandDurationRef:n,spreadSpeedRef:r}){let i=new Uint8Array,a=new Uint8Array,o=0,s=0,c=1,l=1,u=0,d=0,f=null,p=-1,m=-1,h=()=>Math.floor(Math.random()*t.current.length),g=[[-1,0],[1,0],[0,-1],[0,1]];return{setup(e,t,n,r,h,g,_,v){o=t,s=n,c=r,l=h,u=g,d=_,f=v;let y=t*n;i=new Uint8Array(y),a=new Uint8Array(y),m=-1,p=-1,e.activeTexture(e.TEXTURE6),e.bindTexture(e.TEXTURE_2D,v),e.texImage2D(e.TEXTURE_2D,0,e.R8UI,t,n,0,e.RED_INTEGER,e.UNSIGNED_BYTE,i)},handleClick(t,r){if(!e.current||o===0)return;let f=r.getBoundingClientRect(),p=(t.clientX-f.left)*(r.width/f.width),g=(t.clientY-f.top)*(r.height/f.height),_=Math.floor((p-u)/c),v=Math.floor((g-d)/l);if(_<0||_>=o||v<0||v>=s)return;let y=v*o+_;i[y]=1+h(),a[y]=1,m=performance.now()+n.current*1e3},tick(t){if(!e.current||o===0||s===0)return;let n=performance.now(),c=p<0?0:Math.min(.1,(n-p)/1e3);p=n;let l=m>0&&n<m;if(!l&&m>0){for(let e=0;e<i.length;e++)a[e]===1&&(a[e]=2);m=-1}if(c>0)for(let e=0;e<s;e++)for(let t=0;t<o;t++){let n=e*o+t;if(a[n]!==0){if(l&&a[n]===1)for(let[n,l]of g){let u=e+n,d=t+l;if(u<0||u>=s||d<0||d>=o)continue;let f=u*o+d;a[f]===0&&Math.random()<r.current*c&&(i[f]=1+h(),a[f]=1)}else if(a[n]===2)for(let[l,u]of g){let d=e+l,f=t+u;if(d<0||d>=s||f<0||f>=o||i[d*o+f]===0){Math.random()<r.current*c&&(i[n]=0,a[n]=0);break}}}}t.activeTexture(t.TEXTURE6),t.bindTexture(t.TEXTURE_2D,f),t.texSubImage2D(t.TEXTURE_2D,0,0,0,o,s,t.RED_INTEGER,t.UNSIGNED_BYTE,i)}}}function v(e,t){let n=0,r=0,i=!1,a=null,o=()=>{let e=window.devicePixelRatio||1;t({width:Math.round(n*e),height:Math.round(r*e),cssWidth:n,cssHeight:r})},s=()=>{a?.();let e=window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`),t=()=>{i||(o(),s())};e.addEventListener(`change`,t,{once:!0}),a=()=>e.removeEventListener(`change`,t)},c=new ResizeObserver(e=>{let i=e[0],a=i.contentBoxSize?.[0];n=a?a.inlineSize:i.contentRect.width,r=a?a.blockSize:i.contentRect.height;let s=i.devicePixelContentBoxSize?.[0];s?t({width:s.inlineSize,height:s.blockSize,cssWidth:n,cssHeight:r}):o()});try{c.observe(e,{box:`device-pixel-content-box`})}catch{c.observe(e),s()}return()=>{i=!0,c.disconnect(),a?.()}}function y({src:e,videoMode:r=!1,numColsRaw:s=250,brightnessRaw:c=1,saturationRaw:l=1,bgOpacityRaw:u=.3,revealEffect:d=!1,chars:h=a,mouseEffect:y=!0,clickEffect:b=!0,charMode:x=`shape`,className:S,cropFocus:C=`center`,maxDpr:w}){let T=(0,t.useRef)(null),E=(0,t.useRef)(null),D=(0,t.useRef)(null),O=(0,t.useRef)(null),k=(0,t.useRef)(null),{numCols:A,brightness:j,saturation:M,bgOpacity:N,mouseEnabled:P,mouseStyle:F,brightenEnabled:I,scatterEnabled:L,scatterChars:R,trailLen:z,trailDecay:B,duration:V,mouseRadius:H,mouseBrightness:U,clickEnabled:W,clickBrightness:G,clickSpeed:K,spreadEnabled:q,spreadExpandDuration:J,spreadSpeed:Y,revealEnabled:ee,revealDuration:te,revealEffectFlag:ne,maxDpr:X}=o(s,c,l,u,y,b,d,w),re=(0,t.useRef)(j),ie=(0,t.useRef)(M),ae=(0,t.useRef)(N),oe=(0,t.useRef)(P),se=(0,t.useRef)(F),ce=(0,t.useRef)(I),le=(0,t.useRef)(L),ue=(0,t.useRef)(U),de=(0,t.useRef)(H),fe=(0,t.useRef)(z),pe=(0,t.useRef)(B),me=(0,t.useRef)(V),Z=(0,t.useRef)(R),he=(0,t.useRef)(W),ge=(0,t.useRef)(G),_e=(0,t.useRef)(K),ve=(0,t.useRef)(q),ye=(0,t.useRef)(J),be=(0,t.useRef)(Y),xe=(0,t.useRef)(A),Se=(0,t.useRef)(r),Ce=(0,t.useRef)(C),we=(0,t.useRef)(0),Te=(0,t.useRef)(0),Ee=(0,t.useRef)(X),De=(0,t.useRef)(1),Q=(0,t.useRef)(null),Oe=(0,t.useRef)(null);(0,t.useEffect)(()=>{re.current=j,ie.current=M,ae.current=N,oe.current=P,se.current=F,ce.current=I,le.current=L,ue.current=U,de.current=H,fe.current=z,pe.current=B,me.current=V,Z.current!==R&&$.current?(Z.current=R,Ae.current?.()):Z.current=R,he.current=W,ge.current=G,_e.current=K,ve.current=q,ye.current=J,be.current=Y,xe.current=A,Se.current=r},[j,M,N,P,F,I,L,U,H,z,B,V,R,W,G,K,q,J,Y,A,r]);let ke=(0,t.useRef)(null),Ae=(0,t.useRef)(null),je=(0,t.useRef)(null),$=(0,t.useRef)(!1);return(0,t.useEffect)(()=>{$.current&&ke.current?.(A)},[A]),(0,t.useEffect)(()=>{Ce.current=C,$.current&&we.current>0&&je.current?.(we.current,Te.current)},[C]),(0,t.useEffect)(()=>{Ee.current=X,$.current&&Q.current&&Oe.current?.(Q.current)},[X]),(0,t.useEffect)(()=>{$.current=!1;let t=[],n=0,r=0,a=1,o=1,s=0,c=0,l=0,u=0,d=T.current;if(!d)return;let y=E.current;if(!y)return;let b=d.getContext(`webgl2`);if(!b)return;b.pixelStorei(b.UNPACK_ALIGNMENT,1);let S=f(b);if(!S)return;let{program:C,pass1Program:w}=S;O.current=S.atlasTexture,k.current=S.scatterAtlasTexture,b.uniform1i(S.shapeMatchingLoc,+(x===`shape`)),b.uniform1i(S.revealEffectFlagLoc,ne),b.uniform1f(S.revealProgressLoc,0);let A=p({scatterEnabledRef:le,mouseRadiusRef:de,durationRef:me,scatterCharsRef:Z}),j=m({brightenEnabledRef:ce,trailLenRef:fe,durationRef:me,trailDecayRef:pe}),M=g({clickEnabledRef:he,clickSpeedRef:_e,clickBrightnessRef:ge,pixelScaleRef:De}),N=_({spreadEnabledRef:ve,scatterCharsRef:Z,spreadExpandDurationRef:ye,spreadSpeedRef:be}),P,F=-1,I=-1,L=0,R=Array.isArray(e)?e:[e],z=R.length>1,B=document.createElement(`canvas`),V=B.getContext(`2d`),H=e=>{let f=l>0?l:d.width,p=u>0?u:d.height;a=Math.max(1,Math.floor(f/e));let m=a*2;if(V.font=`${m}px monospace`,o=Math.max(1,Math.round(m*a/V.measureText(`M`).width)),n=Math.ceil(f/a),r=Math.ceil(p/o),s=Math.floor((f-n*a)/2),c=Math.floor((p-r*o)/2),b.viewport(0,0,d.width,d.height),b.useProgram(C),b.uniform2f(S.resLoc,d.width,d.height),b.uniform2f(S.gridOffsetLoc,s,c),b.useProgram(w),b.uniform2f(S.p1ResLoc,d.width,d.height),b.uniform2f(S.p1GridOffsetLoc,s,c),b.useProgram(C),A.setup(b,n,r,a,o,s,c,S.scatterStateTexture),N.setup(b,n,r,a,o,s,c,S.spreadStateTexture),x===`shape`){t=i(h,a,o);let e=t.length,s=new Float32Array(e*8);for(let n=0;n<e;n++){let r=t[n].vector;s[n*4+0]=r[0],s[n*4+1]=r[1],s[n*4+2]=r[2],s[n*4+3]=r[3],s[e*4+n*4+0]=r[4],s[e*4+n*4+1]=r[5]}b.activeTexture(b.TEXTURE2),b.bindTexture(b.TEXTURE_2D,S.charVectorsTexture),b.texImage2D(b.TEXTURE_2D,0,b.RGBA32F,e,2,0,b.RGBA,b.FLOAT,s),b.activeTexture(b.TEXTURE3),b.bindTexture(b.TEXTURE_2D,S.fboTexture),b.texImage2D(b.TEXTURE_2D,0,b.R8UI,n,r,0,b.RED_INTEGER,b.UNSIGNED_BYTE,null),b.bindFramebuffer(b.FRAMEBUFFER,S.fbo),b.framebufferTexture2D(b.FRAMEBUFFER,b.COLOR_ATTACHMENT0,b.TEXTURE_2D,S.fboTexture,0),b.bindFramebuffer(b.FRAMEBUFFER,null);let c=Math.max(1,Math.round(a/5));b.useProgram(w),b.uniform2f(S.p1CellsizeLoc,a,o),b.uniform1i(S.p1CircleNLoc,c),b.uniform1i(S.p1NumCharsLoc,e),b.uniform1f(S.p1ExponentLoc,2),b.useProgram(C)}b.uniform2f(S.gridSizeLoc,n,r),B.width=h.length*a,B.height=o,V.font=`${o}px monospace`,V.fillStyle=`black`,V.fillRect(0,0,h.length*a,o),V.fillStyle=`white`,V.textBaseline=`top`;for(let e=0;e<h.length;e++)V.fillText(h[e],e*a,0);b.activeTexture(b.TEXTURE1),b.bindTexture(b.TEXTURE_2D,O.current),b.texImage2D(b.TEXTURE_2D,0,b.RGBA,b.RGBA,b.UNSIGNED_BYTE,B),b.uniform1f(S.numLoc,h.length),b.uniform2f(S.sizeLoc,a,o),U()},U=()=>{let e=Z.current;B.width=e.length*a,B.height=o,V.fillStyle=`black`,V.fillRect(0,0,B.width,o),V.fillStyle=`white`,V.textBaseline=`top`,V.font=`${o}px monospace`;for(let t=0;t<e.length;t++)V.fillText(e[t],t*a,0);b.activeTexture(b.TEXTURE4),b.bindTexture(b.TEXTURE_2D,k.current),b.texImage2D(b.TEXTURE_2D,0,b.RGBA,b.RGBA,b.UNSIGNED_BYTE,B),b.uniform1f(S.scatterNumCharsLoc,e.length),A.reset(b)};ke.current=H,Ae.current=U;let W=(e,t)=>{l=Math.round(e),u=Math.round(t),we.current=l,Te.current=u,d.width=l,d.height=u,H(xe.current);let n=y.videoWidth/y.videoHeight,r=d.width/d.height,i=1,a=1,o=0,s=0;if(r>n)a=n/r,s=(1-a)/2;else{i=r/n;let e=Ce.current,t=e===`left`?.25:e===`right`?.75:.5;o=Math.max(0,Math.min(1-i,t-i/2))}b.uniform2f(S.cropOffsetLoc,o,s),b.uniform2f(S.cropScaleLoc,i,a),b.useProgram(w),b.uniform2f(S.p1CropOffsetLoc,o,s),b.uniform2f(S.p1CropScaleLoc,i,a),b.useProgram(C)};je.current=W;let G=e=>{Q.current=e;let t=Math.min(1,Ee.current/(window.devicePixelRatio||1)),n=Math.max(1,Math.round(e.width*t)),r=Math.max(1,Math.round(e.height*t));De.current=e.cssWidth>0?n/e.cssWidth:1,W(n,r)};Oe.current=G;let K=e=>{if(!oe.current)return;let t=d.getBoundingClientRect(),n=(e.clientX-t.left)*(d.width/t.width),r=(e.clientY-t.top)*(d.height/t.height),i=performance.now();j.handleMouseMove(n,r,i),A.handleMouseMove(n,r,i)};d.addEventListener(`mousemove`,K);let q=()=>A.handleMouseLeave();d.addEventListener(`mouseleave`,q);let J=e=>{M.handleClick(e,d),N.handleClick(e,d)};d.addEventListener(`click`,J);let Y=()=>{if(b.uniform1i(S.videoModeLoc,+!!Se.current),b.uniform1f(S.brightnessLoc,re.current),b.uniform1f(S.saturationLoc,ie.current),b.uniform1f(S.bgOpacityLoc,ae.current),b.uniform1i(S.mouseEffectFlagLoc,+!!ce.current),b.uniform1i(S.scatterEffectFlagLoc,+!!le.current),b.uniform1i(S.clickEffectFlagLoc,+!!he.current),b.uniform1i(S.spreadEffectFlagLoc,+!!ve.current),b.uniform1f(S.mouseBrightnessLoc,ue.current),b.uniform1f(S.mouseRadiusLoc,Math.min(d.width,d.height)*de.current),ee){let e=I<0?0:Math.min(1,(performance.now()-I)/(te*1e3));b.uniform1f(S.revealProgressLoc,e)}$.current&&y.currentTime!=F&&y.readyState>=2&&(b.activeTexture(b.TEXTURE0),b.bindTexture(b.TEXTURE_2D,S.texture),b.texSubImage2D(b.TEXTURE_2D,0,0,0,b.RGBA,b.UNSIGNED_BYTE,y),F=y.currentTime),j.tick(b,S.mousePositionsLoc,S.mouseLifeFracsLoc),A.tick(b,d),M.tick(b,d,S.ripplePositionsLoc,S.rippleRadiiLoc,S.rippleBrightnessesLoc),N.tick(b),x===`shape`&&(b.bindFramebuffer(b.FRAMEBUFFER,S.fbo),b.viewport(0,0,n,r),b.useProgram(w),b.drawArrays(b.TRIANGLES,0,6),b.bindFramebuffer(b.FRAMEBUFFER,null),b.viewport(0,0,d.width,d.height),b.useProgram(C)),b.drawArrays(b.TRIANGLES,0,6),P=requestAnimationFrame(Y)},X=()=>{let e=D.current,t=Q.current;if(t&&t.width>0&&t.height>0)G(t);else{let t=window.devicePixelRatio||1,n=e.clientWidth||y.videoWidth,r=e.clientHeight||y.videoHeight;G({width:Math.round(n*t),height:Math.round(r*t),cssWidth:n,cssHeight:r})}b.activeTexture(b.TEXTURE0),b.bindTexture(b.TEXTURE_2D,S.texture),b.texImage2D(b.TEXTURE_2D,0,b.RGBA,b.RGBA,b.UNSIGNED_BYTE,y),y.play(),I=performance.now(),$.current=!0,P=requestAnimationFrame(Y)},se=()=>{L=(L+1)%R.length,y.src=R[L],y.load(),y.addEventListener(`canplay`,()=>y.play(),{once:!0})},Me=D.current?v(D.current,e=>{Q.current=e,$.current&&e.width>0&&e.height>0&&G(e)}):()=>{};return y.addEventListener(`loadeddata`,X,{once:!0}),z&&y.addEventListener(`ended`,se),y.readyState>=2&&y.currentSrc.endsWith(R[0])?X():y.currentSrc.endsWith(R[0])||y.load(),()=>{Me(),ke.current=null,Ae.current=null,je.current=null,Oe.current=null,$.current=!1,cancelAnimationFrame(P),y.removeEventListener(`loadeddata`,X),z&&y.removeEventListener(`ended`,se),d.removeEventListener(`mousemove`,K),d.removeEventListener(`mouseleave`,q),d.removeEventListener(`click`,J),b.deleteTexture(S.texture),b.deleteTexture(S.charVectorsTexture),b.deleteFramebuffer(S.fbo),b.deleteTexture(S.fboTexture),b.deleteBuffer(S.buffer),b.deleteShader(S.vertShader),b.deleteShader(S.fragShader),b.deleteShader(S.pass1FragShader),b.deleteProgram(C),b.deleteProgram(w),b.deleteTexture(O.current),b.deleteTexture(k.current),b.deleteTexture(S.scatterStateTexture),b.deleteTexture(S.spreadStateTexture)}},[e,x,h,ne,te,ee]),(0,n.jsxs)(`div`,{ref:D,className:S,style:{height:`100%`,width:`100%`},children:[(0,n.jsx)(`video`,{ref:E,muted:!0,playsInline:!0,autoPlay:!0,loop:!Array.isArray(e)||e.length===1,style:{display:`none`},children:(0,n.jsx)(`source`,{src:Array.isArray(e)?e[0]:e,type:`video/mp4`})}),(0,n.jsx)(`canvas`,{ref:T,style:{width:`100%`,height:`100%`,display:`block`}})]})}e.VideoAscii=y});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-video-ascii",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "type": "module",
5
5
  "description": "React component that renders videos as ASCII animations using WebGL2.",
6
6
  "author": "Lucas Jin",