@fxshelf/glyph-rain 0.1.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/LICENSE +21 -0
- package/README.md +51 -0
- package/dist/glyph-rain.iife.js +865 -0
- package/dist/glyph-rain.iife.js.map +1 -0
- package/dist/index.cjs +825 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +77 -0
- package/dist/index.d.ts +77 -0
- package/dist/index.js +819 -0
- package/dist/index.js.map +1 -0
- package/docs//344/275/277/347/224/250/350/257/264/346/230/216.md +45 -0
- package/docs//345/212/250/346/225/210/350/257/264/346/230/216-/344/270/223/344/270/232.md +18 -0
- package/docs//345/212/250/346/225/210/350/257/264/346/230/216-/345/244/247/347/231/275/350/257/235.md +7 -0
- package/package.json +85 -0
- package/src/core/atlas.ts +28 -0
- package/src/core/createGlyphRain.ts +514 -0
- package/src/core/shaders.ts +208 -0
- package/src/core/supports.ts +13 -0
- package/src/core/types.ts +95 -0
- package/src/react/GlyphRain.tsx +126 -0
- package/src/react/index.ts +10 -0
- package/src/vue/GlyphRain.vue +181 -0
- package/src/vue/index.ts +1 -0
- package/src/vue-shim.d.ts +5 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,819 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useRef, useState, useSyncExternalStore, useEffect } from 'react';
|
|
3
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
// src/react/GlyphRain.tsx
|
|
6
|
+
|
|
7
|
+
// src/core/atlas.ts
|
|
8
|
+
function buildAtlas(charset) {
|
|
9
|
+
const glyphs = Array.from(new Set(Array.from(charset))).filter(
|
|
10
|
+
(g) => g.trim().length > 0
|
|
11
|
+
);
|
|
12
|
+
if (glyphs.length === 0) glyphs.push("0", "1");
|
|
13
|
+
const count = glyphs.length;
|
|
14
|
+
const grid = Math.max(Math.ceil(Math.sqrt(count)), 1);
|
|
15
|
+
const cellPx = 64;
|
|
16
|
+
const canvas = document.createElement("canvas");
|
|
17
|
+
canvas.width = grid * cellPx;
|
|
18
|
+
canvas.height = grid * cellPx;
|
|
19
|
+
const ctx = canvas.getContext("2d");
|
|
20
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
21
|
+
ctx.fillStyle = "#ffffff";
|
|
22
|
+
ctx.textAlign = "center";
|
|
23
|
+
ctx.textBaseline = "middle";
|
|
24
|
+
ctx.font = `600 ${Math.round(cellPx * 0.72)}px ui-monospace, SFMono-Regular, Menlo, monospace`;
|
|
25
|
+
for (let i = 0; i < count; i++) {
|
|
26
|
+
const x = (i % grid + 0.5) * cellPx;
|
|
27
|
+
const y = (Math.floor(i / grid) + 0.5) * cellPx;
|
|
28
|
+
ctx.fillText(glyphs[i], x, y);
|
|
29
|
+
}
|
|
30
|
+
return { canvas, count, grid };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// src/core/shaders.ts
|
|
34
|
+
var VERT = `#version 300 es
|
|
35
|
+
precision highp float;
|
|
36
|
+
layout(location = 0) in vec2 aPos;
|
|
37
|
+
out vec2 vUv;
|
|
38
|
+
void main () {
|
|
39
|
+
vUv = aPos * 0.5 + 0.5;
|
|
40
|
+
gl_Position = vec4(aPos, 0.0, 1.0);
|
|
41
|
+
}`;
|
|
42
|
+
var FRAG = `#version 300 es
|
|
43
|
+
precision highp float;
|
|
44
|
+
in vec2 vUv;
|
|
45
|
+
out vec4 outColor;
|
|
46
|
+
uniform sampler2D uContent;
|
|
47
|
+
uniform sampler2D uAtlas;
|
|
48
|
+
uniform sampler2D uWake;
|
|
49
|
+
uniform vec2 uResolution;
|
|
50
|
+
uniform float uTime;
|
|
51
|
+
uniform float uCell;
|
|
52
|
+
uniform float uGlyphCount;
|
|
53
|
+
uniform float uAtlasGrid;
|
|
54
|
+
uniform vec3 uColor;
|
|
55
|
+
uniform vec3 uHeadColor;
|
|
56
|
+
uniform float uSpeed;
|
|
57
|
+
uniform float uSpeedVar;
|
|
58
|
+
uniform float uDensity;
|
|
59
|
+
uniform float uTrail;
|
|
60
|
+
uniform float uGlow;
|
|
61
|
+
uniform float uMutate;
|
|
62
|
+
uniform float uFlicker;
|
|
63
|
+
uniform float uLayers;
|
|
64
|
+
uniform float uDim;
|
|
65
|
+
uniform float uLight;
|
|
66
|
+
uniform float uLightRadius;
|
|
67
|
+
uniform float uLightHeight;
|
|
68
|
+
uniform float uRelief;
|
|
69
|
+
uniform float uStir;
|
|
70
|
+
uniform float uScroll;
|
|
71
|
+
uniform float uPageLum;
|
|
72
|
+
uniform float uHasContent;
|
|
73
|
+
|
|
74
|
+
float hash11(float p) {
|
|
75
|
+
p = fract(p * 0.1031);
|
|
76
|
+
p *= p + 33.33;
|
|
77
|
+
p *= p + p;
|
|
78
|
+
return fract(p);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
float hash21(vec2 p) {
|
|
82
|
+
vec3 q = fract(vec3(p.xyx) * 0.1031);
|
|
83
|
+
q += dot(q, q.yzx + 33.33);
|
|
84
|
+
return fract((q.x + q.y) * q.z);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
float glyphMask(vec2 px, float cell, float seed) {
|
|
88
|
+
vec2 id = floor(px / cell);
|
|
89
|
+
vec2 f = fract(px / cell);
|
|
90
|
+
f = f * 0.74 + 0.13;
|
|
91
|
+
f.x = 1.0 - f.x;
|
|
92
|
+
float tick = floor(uTime * uMutate * 1.6 + hash21(id + seed) * 9.0);
|
|
93
|
+
float idx = floor(
|
|
94
|
+
hash21(id * 1.71 + vec2(seed + tick * 7.31, tick * 0.613)) * uGlyphCount
|
|
95
|
+
);
|
|
96
|
+
float gx = mod(idx, uAtlasGrid);
|
|
97
|
+
float gy = floor(idx / uAtlasGrid);
|
|
98
|
+
vec2 auv = (vec2(gx, gy) + f) / uAtlasGrid;
|
|
99
|
+
return texture(uAtlas, auv).a;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
float colSpeed(float col, float seed) {
|
|
103
|
+
float variance = mix(0.35, 1.0, hash11(col * 0.37 + seed + 3.1));
|
|
104
|
+
return uSpeed * mix(1.0, variance, uSpeedVar) * 0.5;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
float colOffset(float col, float seed) {
|
|
108
|
+
return hash11(col * 1.713 + seed) * 9.0;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
vec2 wakeAt(float xpx) {
|
|
112
|
+
float u = clamp(xpx / max(uResolution.x, 1.0), 0.0, 1.0);
|
|
113
|
+
return texture(uWake, vec2(u, 0.5)).rg;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
float lum(vec3 c) {
|
|
117
|
+
return dot(c, vec3(0.299, 0.587, 0.114));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
void main () {
|
|
121
|
+
vec2 frag = vec2(gl_FragCoord.x, uResolution.y - gl_FragCoord.y + uScroll);
|
|
122
|
+
vec2 cuv = vec2(vUv.x, 1.0 - vUv.y);
|
|
123
|
+
float yn = 1.0 - frag.y / uResolution.y;
|
|
124
|
+
|
|
125
|
+
const float scales[3] = float[3](1.0, 1.5, 2.2);
|
|
126
|
+
const float weights[3] = float[3](1.0, 0.45, 0.22);
|
|
127
|
+
const float seeds[3] = float[3](0.0, 19.7, 41.3);
|
|
128
|
+
|
|
129
|
+
float g = 0.0;
|
|
130
|
+
float headG = 0.0;
|
|
131
|
+
for (int l = 0; l < 3; l++) {
|
|
132
|
+
if (float(l) >= uLayers) break;
|
|
133
|
+
float cell = uCell * scales[l];
|
|
134
|
+
float col = floor(frag.x / cell);
|
|
135
|
+
float sp = colSpeed(col, seeds[l]);
|
|
136
|
+
float off = colOffset(col, seeds[l]);
|
|
137
|
+
vec2 wk = uStir > 0.0 ? wakeAt((col + 0.5) * cell) : vec2(0.0);
|
|
138
|
+
float exc = uStir * wk.y;
|
|
139
|
+
float T = uTime * sp + off + sp * wk.x;
|
|
140
|
+
float phase = fract(yn + T);
|
|
141
|
+
float cyc = floor(yn + T);
|
|
142
|
+
float gate = step(hash21(vec2(col, cyc) + seeds[l]), uDensity);
|
|
143
|
+
float b = clamp(uTrail / (phase * 22.0), 0.0, 1.3) - 0.04;
|
|
144
|
+
if (b <= 0.0 || gate < 0.5) continue;
|
|
145
|
+
float flick = 1.0 + uFlicker * 0.6 *
|
|
146
|
+
sin(uTime * 14.0 + hash21(vec2(col, cyc)) * 40.0 + phase * 30.0);
|
|
147
|
+
float m = glyphMask(frag, cell, seeds[l] + cyc * 0.173);
|
|
148
|
+
float cellYn = cell / uResolution.y;
|
|
149
|
+
float head = 1.0 - smoothstep(0.0, cellYn * 1.2, phase);
|
|
150
|
+
g += m * b * flick * weights[l] * (1.0 + head * uGlow * 1.4) *
|
|
151
|
+
(1.0 + exc * 1.6);
|
|
152
|
+
headG += m * head * weights[l] * uGlow * (1.0 + exc * 1.1);
|
|
153
|
+
}
|
|
154
|
+
g = max(g, 0.0);
|
|
155
|
+
|
|
156
|
+
if (uHasContent < 0.5) {
|
|
157
|
+
vec3 rainCol = mix(uColor, uHeadColor, clamp(headG, 0.0, 1.0));
|
|
158
|
+
float a = clamp(g, 0.0, 1.0);
|
|
159
|
+
outColor = vec4(rainCol * a, a);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
vec2 e = vec2(3.0, 0.0) / uResolution;
|
|
164
|
+
vec4 content = texture(uContent, cuv);
|
|
165
|
+
float lC = lum(content.rgb);
|
|
166
|
+
float lX1 = lum(texture(uContent, clamp(cuv - e.xy, 0.0, 1.0)).rgb);
|
|
167
|
+
float lX2 = lum(texture(uContent, clamp(cuv + e.xy, 0.0, 1.0)).rgb);
|
|
168
|
+
float lY1 = lum(texture(uContent, clamp(cuv - e.yx, 0.0, 1.0)).rgb);
|
|
169
|
+
float lY2 = lum(texture(uContent, clamp(cuv + e.yx, 0.0, 1.0)).rgb);
|
|
170
|
+
vec3 N = normalize(vec3(
|
|
171
|
+
-(lX2 - lX1) * uRelief * 4.0,
|
|
172
|
+
-(lY2 - lY1) * uRelief * 4.0,
|
|
173
|
+
1.0
|
|
174
|
+
));
|
|
175
|
+
float reliefMix = clamp(uRelief, 0.0, 1.0);
|
|
176
|
+
vec2 e2 = vec2(30.0, 0.0) / uResolution;
|
|
177
|
+
float bgL = (lC
|
|
178
|
+
+ lum(texture(uContent, clamp(cuv - e2.xy, 0.0, 1.0)).rgb)
|
|
179
|
+
+ lum(texture(uContent, clamp(cuv + e2.xy, 0.0, 1.0)).rgb)
|
|
180
|
+
+ lum(texture(uContent, clamp(cuv - e2.yx, 0.0, 1.0)).rgb)
|
|
181
|
+
+ lum(texture(uContent, clamp(cuv + e2.yx, 0.0, 1.0)).rgb)) * 0.2;
|
|
182
|
+
float bright = smoothstep(0.55, 0.8, uPageLum) * smoothstep(0.2, 0.45, bgL);
|
|
183
|
+
|
|
184
|
+
float lightSum = 0.0;
|
|
185
|
+
float sigma2 = uLightRadius * uLightRadius * 0.5;
|
|
186
|
+
float reach = uLightRadius * 1.6;
|
|
187
|
+
float stride = max(1.0, ceil((uLightRadius * 1.7) / (uCell * 12.0)));
|
|
188
|
+
float baseCol = floor(floor(frag.x / uCell) / stride);
|
|
189
|
+
for (int o = -12; o <= 12; o++) {
|
|
190
|
+
float c = (baseCol + float(o)) * stride;
|
|
191
|
+
if (c < 0.0) continue;
|
|
192
|
+
float dx = (c + 0.5) * uCell - frag.x;
|
|
193
|
+
float wx = 1.0 - smoothstep(reach * 0.7, reach, abs(dx));
|
|
194
|
+
if (wx <= 0.0) continue;
|
|
195
|
+
float sp = colSpeed(c, 0.0);
|
|
196
|
+
float off = colOffset(c, 0.0);
|
|
197
|
+
vec2 wk = uStir > 0.0 ? wakeAt((c + 0.5) * uCell) : vec2(0.0);
|
|
198
|
+
float lampBoost = 1.0 + uStir * wk.y * 1.4;
|
|
199
|
+
float T = uTime * sp + off + sp * wk.x;
|
|
200
|
+
float s = 1.0 - frag.y / uResolution.y + T;
|
|
201
|
+
float k0 = floor(s);
|
|
202
|
+
for (int h = 0; h < 2; h++) {
|
|
203
|
+
float k = k0 + float(h);
|
|
204
|
+
float gate = step(hash21(vec2(c, k)), uDensity);
|
|
205
|
+
if (gate < 0.5) continue;
|
|
206
|
+
float lamp = 0.6 + 0.4 * hash11(c * 3.97 + k * 0.713);
|
|
207
|
+
float headDocY = (1.0 - (k - T)) * uResolution.y;
|
|
208
|
+
vec3 dv = vec3(dx, headDocY - frag.y, uLightHeight);
|
|
209
|
+
float d2 = dot(dv, dv);
|
|
210
|
+
float att = exp(-d2 / sigma2);
|
|
211
|
+
vec3 L = dv * inversesqrt(max(d2, 1.0));
|
|
212
|
+
float dif = mix(1.0, 0.25 + 0.75 * max(dot(N, L), 0.0), reliefMix);
|
|
213
|
+
lightSum += att * dif * wx * lamp * lampBoost;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
float ls = lightSum * uLight * (0.6 + 0.4 * uGlow);
|
|
217
|
+
float lit = 2.2 * ls / (ls + 1.1);
|
|
218
|
+
|
|
219
|
+
float dimEff = uDim * (1.0 - bright);
|
|
220
|
+
float shade = mix(
|
|
221
|
+
clamp(1.0 - dimEff, 0.0, 1.0),
|
|
222
|
+
1.0,
|
|
223
|
+
smoothstep(0.0, 1.0, lit)
|
|
224
|
+
);
|
|
225
|
+
vec3 col = content.rgb * shade;
|
|
226
|
+
col += uColor * lit * 0.14 * (1.0 - lC * 0.75) * (1.0 - bright);
|
|
227
|
+
col += uColor * clamp(lit - 1.0, 0.0, 1.0) * 0.1 * (1.0 - bright);
|
|
228
|
+
|
|
229
|
+
vec3 glyphCol = mix(uColor, uColor * 0.24 + vec3(0.02), lC * (1.0 - bright));
|
|
230
|
+
glyphCol = mix(glyphCol, uHeadColor, clamp(headG, 0.0, 1.0));
|
|
231
|
+
glyphCol = mix(glyphCol, vec3(1.0), bright * clamp(headG - 0.6, 0.0, 0.4));
|
|
232
|
+
float gA = clamp(g, 0.0, 1.0);
|
|
233
|
+
float knock = gA * mix(mix(0.3, 0.88, lC), 1.0, bright);
|
|
234
|
+
float paint = min(g, 1.5) * mix(1.0, mix(0.92, 1.0, bright), lC);
|
|
235
|
+
col = col * (1.0 - knock) + glyphCol * paint;
|
|
236
|
+
|
|
237
|
+
float alpha = max(content.a, gA);
|
|
238
|
+
col = clamp(col, vec3(0.0), vec3(alpha));
|
|
239
|
+
outColor = vec4(col, alpha);
|
|
240
|
+
}`;
|
|
241
|
+
|
|
242
|
+
// src/core/supports.ts
|
|
243
|
+
function supportsHtmlInCanvas() {
|
|
244
|
+
if (typeof document === "undefined") return false;
|
|
245
|
+
const probe = document.createElement("canvas");
|
|
246
|
+
const ctx = probe.getContext("2d");
|
|
247
|
+
return Boolean(
|
|
248
|
+
ctx && typeof ctx.drawElementImage === "function" && typeof probe.requestPaint === "function"
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// src/core/types.ts
|
|
253
|
+
var DEFAULT_CHARSET = "\uFF71\uFF72\uFF73\uFF74\uFF75\uFF76\uFF77\uFF78\uFF79\uFF7A\uFF7B\uFF7C\uFF7D\uFF7E\uFF7F\uFF80\uFF81\uFF82\uFF83\uFF84\uFF85\uFF86\uFF87\uFF88\uFF89\uFF8A\uFF8B\uFF8C\uFF8D\uFF8E\uFF8F\uFF90\uFF91\uFF92\uFF93\uFF94\uFF95\uFF96\uFF97\uFF98\uFF99\uFF9A\uFF9B\uFF9C\uFF9D0123456789Z*+-<>\xA6=:.";
|
|
254
|
+
var DEFAULTS = {
|
|
255
|
+
charset: DEFAULT_CHARSET,
|
|
256
|
+
cell: 15,
|
|
257
|
+
color: [0.267, 0.455, 1],
|
|
258
|
+
headColor: [0.169, 0.416, 1],
|
|
259
|
+
speed: 0.2,
|
|
260
|
+
speedVariance: 0.5,
|
|
261
|
+
density: 0.15,
|
|
262
|
+
trail: 0.65,
|
|
263
|
+
glow: 1.75,
|
|
264
|
+
mutate: 0,
|
|
265
|
+
flicker: 0,
|
|
266
|
+
layers: 2,
|
|
267
|
+
dim: 0.5,
|
|
268
|
+
light: 2.8,
|
|
269
|
+
lightRadius: 240,
|
|
270
|
+
lightHeight: 172,
|
|
271
|
+
relief: 0.05,
|
|
272
|
+
stir: 0.7,
|
|
273
|
+
stirRadius: 260,
|
|
274
|
+
settle: 0.9
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
// src/core/createGlyphRain.ts
|
|
278
|
+
function createGlyphRain(elements, options = {}) {
|
|
279
|
+
const config = { ...DEFAULTS, ...options };
|
|
280
|
+
const { source, content, output } = elements;
|
|
281
|
+
const maybeGl = output.getContext("webgl2", {
|
|
282
|
+
alpha: true,
|
|
283
|
+
depth: false,
|
|
284
|
+
stencil: false,
|
|
285
|
+
antialias: false,
|
|
286
|
+
premultipliedAlpha: true
|
|
287
|
+
});
|
|
288
|
+
if (!maybeGl || maybeGl.isContextLost()) return null;
|
|
289
|
+
const gl = maybeGl;
|
|
290
|
+
const sourceCtx = source.getContext("2d");
|
|
291
|
+
const paintable = source;
|
|
292
|
+
const htmlInCanvas = Boolean(
|
|
293
|
+
sourceCtx && typeof sourceCtx.drawElementImage === "function" && typeof paintable.requestPaint === "function"
|
|
294
|
+
);
|
|
295
|
+
let contentDirty = false;
|
|
296
|
+
let pageLum = 0;
|
|
297
|
+
let wake = () => {
|
|
298
|
+
};
|
|
299
|
+
function readPageLum() {
|
|
300
|
+
try {
|
|
301
|
+
const probe = document.createElement("canvas");
|
|
302
|
+
probe.width = probe.height = 1;
|
|
303
|
+
const pctx = probe.getContext("2d", { willReadFrequently: true });
|
|
304
|
+
if (!pctx) return 0;
|
|
305
|
+
let el = content;
|
|
306
|
+
while (el instanceof Element) {
|
|
307
|
+
const bgColor = getComputedStyle(el).backgroundColor;
|
|
308
|
+
if (bgColor && bgColor !== "transparent") {
|
|
309
|
+
pctx.clearRect(0, 0, 1, 1);
|
|
310
|
+
pctx.fillStyle = bgColor;
|
|
311
|
+
pctx.fillRect(0, 0, 1, 1);
|
|
312
|
+
const d = pctx.getImageData(0, 0, 1, 1).data;
|
|
313
|
+
if (d[3] > 128) {
|
|
314
|
+
return (0.2126 * d[0] + 0.7152 * d[1] + 0.0722 * d[2]) / 255;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
el = el.parentElement;
|
|
318
|
+
}
|
|
319
|
+
} catch {
|
|
320
|
+
}
|
|
321
|
+
return 0;
|
|
322
|
+
}
|
|
323
|
+
if (htmlInCanvas) {
|
|
324
|
+
paintable.onpaint = () => {
|
|
325
|
+
try {
|
|
326
|
+
sourceCtx.reset();
|
|
327
|
+
sourceCtx.drawElementImage(content, 0, 0);
|
|
328
|
+
contentDirty = true;
|
|
329
|
+
wake();
|
|
330
|
+
} catch {
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
function compile(type, text) {
|
|
335
|
+
const shader = gl.createShader(type);
|
|
336
|
+
gl.shaderSource(shader, text);
|
|
337
|
+
gl.compileShader(shader);
|
|
338
|
+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
339
|
+
console.error("GlyphRain shader error:", gl.getShaderInfoLog(shader));
|
|
340
|
+
}
|
|
341
|
+
return shader;
|
|
342
|
+
}
|
|
343
|
+
const vertexShader = compile(gl.VERTEX_SHADER, VERT);
|
|
344
|
+
const fragmentShader = compile(gl.FRAGMENT_SHADER, FRAG);
|
|
345
|
+
const program = gl.createProgram();
|
|
346
|
+
gl.attachShader(program, vertexShader);
|
|
347
|
+
gl.attachShader(program, fragmentShader);
|
|
348
|
+
gl.linkProgram(program);
|
|
349
|
+
const uniforms = {};
|
|
350
|
+
const uniformCount = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
|
|
351
|
+
for (let i = 0; i < uniformCount; i++) {
|
|
352
|
+
const info = gl.getActiveUniform(program, i);
|
|
353
|
+
uniforms[info.name] = gl.getUniformLocation(program, info.name);
|
|
354
|
+
}
|
|
355
|
+
const quad = gl.createBuffer();
|
|
356
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, quad);
|
|
357
|
+
gl.bufferData(
|
|
358
|
+
gl.ARRAY_BUFFER,
|
|
359
|
+
new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]),
|
|
360
|
+
gl.STATIC_DRAW
|
|
361
|
+
);
|
|
362
|
+
gl.enableVertexAttribArray(0);
|
|
363
|
+
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
|
|
364
|
+
const contentTexture = gl.createTexture();
|
|
365
|
+
gl.bindTexture(gl.TEXTURE_2D, contentTexture);
|
|
366
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
367
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
368
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
369
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
370
|
+
gl.texImage2D(
|
|
371
|
+
gl.TEXTURE_2D,
|
|
372
|
+
0,
|
|
373
|
+
gl.RGBA,
|
|
374
|
+
1,
|
|
375
|
+
1,
|
|
376
|
+
0,
|
|
377
|
+
gl.RGBA,
|
|
378
|
+
gl.UNSIGNED_BYTE,
|
|
379
|
+
new Uint8Array([0, 0, 0, 0])
|
|
380
|
+
);
|
|
381
|
+
const atlasTexture = gl.createTexture();
|
|
382
|
+
let atlasCount = 1;
|
|
383
|
+
let atlasGrid = 1;
|
|
384
|
+
let atlasCharset = "";
|
|
385
|
+
function syncAtlas() {
|
|
386
|
+
if (config.charset === atlasCharset) return;
|
|
387
|
+
atlasCharset = config.charset;
|
|
388
|
+
const atlas = buildAtlas(config.charset);
|
|
389
|
+
atlasCount = atlas.count;
|
|
390
|
+
atlasGrid = atlas.grid;
|
|
391
|
+
gl.bindTexture(gl.TEXTURE_2D, atlasTexture);
|
|
392
|
+
gl.texParameteri(
|
|
393
|
+
gl.TEXTURE_2D,
|
|
394
|
+
gl.TEXTURE_MIN_FILTER,
|
|
395
|
+
gl.LINEAR_MIPMAP_LINEAR
|
|
396
|
+
);
|
|
397
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
398
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
399
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
400
|
+
gl.texImage2D(
|
|
401
|
+
gl.TEXTURE_2D,
|
|
402
|
+
0,
|
|
403
|
+
gl.RGBA,
|
|
404
|
+
gl.RGBA,
|
|
405
|
+
gl.UNSIGNED_BYTE,
|
|
406
|
+
atlas.canvas
|
|
407
|
+
);
|
|
408
|
+
gl.generateMipmap(gl.TEXTURE_2D);
|
|
409
|
+
}
|
|
410
|
+
syncAtlas();
|
|
411
|
+
let dpr = 1;
|
|
412
|
+
function syncCanvasSize() {
|
|
413
|
+
dpr = Math.min(window.devicePixelRatio || 1, 2);
|
|
414
|
+
const width = Math.max(1, Math.round(output.clientWidth * dpr));
|
|
415
|
+
const height = Math.max(1, Math.round(output.clientHeight * dpr));
|
|
416
|
+
if (output.width !== width || output.height !== height) {
|
|
417
|
+
output.width = width;
|
|
418
|
+
output.height = height;
|
|
419
|
+
}
|
|
420
|
+
if (htmlInCanvas) {
|
|
421
|
+
const cssWidth = Math.max(1, Math.round(source.clientWidth));
|
|
422
|
+
const cssHeight = Math.max(1, Math.round(source.clientHeight));
|
|
423
|
+
if (source.width !== cssWidth * dpr || source.height !== cssHeight * dpr) {
|
|
424
|
+
source.width = cssWidth * dpr;
|
|
425
|
+
source.height = cssHeight * dpr;
|
|
426
|
+
}
|
|
427
|
+
paintable.requestPaint();
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
syncCanvasSize();
|
|
431
|
+
function uploadContent() {
|
|
432
|
+
if (!htmlInCanvas || !contentDirty) return;
|
|
433
|
+
contentDirty = false;
|
|
434
|
+
pageLum = readPageLum();
|
|
435
|
+
gl.bindTexture(gl.TEXTURE_2D, contentTexture);
|
|
436
|
+
gl.texImage2D(
|
|
437
|
+
gl.TEXTURE_2D,
|
|
438
|
+
0,
|
|
439
|
+
gl.RGBA,
|
|
440
|
+
gl.RGBA,
|
|
441
|
+
gl.UNSIGNED_BYTE,
|
|
442
|
+
source
|
|
443
|
+
);
|
|
444
|
+
sourceCtx.clearRect(0, 0, source.width, source.height);
|
|
445
|
+
}
|
|
446
|
+
let time = 7.3;
|
|
447
|
+
const WAKE_RES = 256;
|
|
448
|
+
const wakeCharge = new Float32Array(WAKE_RES);
|
|
449
|
+
const wakeField = new Float32Array(WAKE_RES * 2);
|
|
450
|
+
let wakeLive = false;
|
|
451
|
+
let wakeTouched = false;
|
|
452
|
+
let pointerX = 0;
|
|
453
|
+
let tracking = false;
|
|
454
|
+
const wakeTexture = gl.createTexture();
|
|
455
|
+
gl.bindTexture(gl.TEXTURE_2D, wakeTexture);
|
|
456
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
457
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
458
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
459
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
460
|
+
gl.texImage2D(
|
|
461
|
+
gl.TEXTURE_2D,
|
|
462
|
+
0,
|
|
463
|
+
gl.RG32F,
|
|
464
|
+
WAKE_RES,
|
|
465
|
+
1,
|
|
466
|
+
0,
|
|
467
|
+
gl.RG,
|
|
468
|
+
gl.FLOAT,
|
|
469
|
+
wakeField
|
|
470
|
+
);
|
|
471
|
+
function stirAmount() {
|
|
472
|
+
return Math.min(Math.max(config.stir, 0), 1);
|
|
473
|
+
}
|
|
474
|
+
function wakeSpan() {
|
|
475
|
+
const width = Math.max(output.clientWidth, 1);
|
|
476
|
+
const px = Math.min(Math.max(config.stirRadius, 8), 2e3);
|
|
477
|
+
return Math.max(px / width, 1 / WAKE_RES);
|
|
478
|
+
}
|
|
479
|
+
function stepWake(delta) {
|
|
480
|
+
const stir = stirAmount();
|
|
481
|
+
const settleT = Math.min(Math.max(config.settle, 0.05), 8);
|
|
482
|
+
const decay = Math.exp(-delta / settleT);
|
|
483
|
+
const span = wakeSpan();
|
|
484
|
+
const drive = stir > 1e-3 && !reducedMotion;
|
|
485
|
+
const track = drive && tracking;
|
|
486
|
+
let live = false;
|
|
487
|
+
for (let i = 0; i < WAKE_RES; i++) {
|
|
488
|
+
let charge = wakeCharge[i] * decay;
|
|
489
|
+
if (track) {
|
|
490
|
+
const d = Math.abs((i + 0.5) / WAKE_RES - pointerX) / span;
|
|
491
|
+
if (d < 1) {
|
|
492
|
+
const t = 1 - d;
|
|
493
|
+
const target = t * t * (3 - 2 * t);
|
|
494
|
+
if (target > charge) charge = target;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
if (charge < 1e-4) charge = 0;
|
|
498
|
+
wakeCharge[i] = charge;
|
|
499
|
+
if (charge > 0) {
|
|
500
|
+
live = true;
|
|
501
|
+
if (drive) {
|
|
502
|
+
wakeField[i * 2] += delta * stir * 2.2 * charge;
|
|
503
|
+
wakeTouched = true;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
wakeField[i * 2 + 1] = charge;
|
|
507
|
+
}
|
|
508
|
+
if (!live && !wakeLive) return;
|
|
509
|
+
wakeLive = live;
|
|
510
|
+
gl.bindTexture(gl.TEXTURE_2D, wakeTexture);
|
|
511
|
+
gl.texSubImage2D(
|
|
512
|
+
gl.TEXTURE_2D,
|
|
513
|
+
0,
|
|
514
|
+
0,
|
|
515
|
+
0,
|
|
516
|
+
WAKE_RES,
|
|
517
|
+
1,
|
|
518
|
+
gl.RG,
|
|
519
|
+
gl.FLOAT,
|
|
520
|
+
wakeField
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
function render() {
|
|
524
|
+
uploadContent();
|
|
525
|
+
gl.useProgram(program);
|
|
526
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
527
|
+
gl.bindTexture(gl.TEXTURE_2D, contentTexture);
|
|
528
|
+
gl.uniform1i(uniforms.uContent, 0);
|
|
529
|
+
gl.activeTexture(gl.TEXTURE1);
|
|
530
|
+
gl.bindTexture(gl.TEXTURE_2D, atlasTexture);
|
|
531
|
+
gl.uniform1i(uniforms.uAtlas, 1);
|
|
532
|
+
gl.activeTexture(gl.TEXTURE2);
|
|
533
|
+
gl.bindTexture(gl.TEXTURE_2D, wakeTexture);
|
|
534
|
+
gl.uniform1i(uniforms.uWake, 2);
|
|
535
|
+
gl.uniform2f(uniforms.uResolution, output.width, output.height);
|
|
536
|
+
gl.uniform1f(uniforms.uTime, time);
|
|
537
|
+
gl.uniform1f(uniforms.uCell, Math.min(Math.max(config.cell, 8), 64) * dpr);
|
|
538
|
+
gl.uniform1f(uniforms.uGlyphCount, atlasCount);
|
|
539
|
+
gl.uniform1f(uniforms.uAtlasGrid, atlasGrid);
|
|
540
|
+
gl.uniform3f(
|
|
541
|
+
uniforms.uColor,
|
|
542
|
+
config.color[0],
|
|
543
|
+
config.color[1],
|
|
544
|
+
config.color[2]
|
|
545
|
+
);
|
|
546
|
+
gl.uniform3f(
|
|
547
|
+
uniforms.uHeadColor,
|
|
548
|
+
config.headColor[0],
|
|
549
|
+
config.headColor[1],
|
|
550
|
+
config.headColor[2]
|
|
551
|
+
);
|
|
552
|
+
gl.uniform1f(uniforms.uSpeed, Math.min(Math.max(config.speed, 0.05), 3));
|
|
553
|
+
gl.uniform1f(
|
|
554
|
+
uniforms.uSpeedVar,
|
|
555
|
+
Math.min(Math.max(config.speedVariance, 0), 1)
|
|
556
|
+
);
|
|
557
|
+
gl.uniform1f(uniforms.uDensity, Math.min(Math.max(config.density, 0), 1));
|
|
558
|
+
gl.uniform1f(uniforms.uTrail, Math.min(Math.max(config.trail, 0.2), 3));
|
|
559
|
+
gl.uniform1f(uniforms.uGlow, Math.min(Math.max(config.glow, 0), 3));
|
|
560
|
+
gl.uniform1f(uniforms.uMutate, Math.min(Math.max(config.mutate, 0), 4));
|
|
561
|
+
gl.uniform1f(uniforms.uFlicker, Math.min(Math.max(config.flicker, 0), 1));
|
|
562
|
+
gl.uniform1f(
|
|
563
|
+
uniforms.uLayers,
|
|
564
|
+
Math.round(Math.min(Math.max(config.layers, 1), 3))
|
|
565
|
+
);
|
|
566
|
+
gl.uniform1f(uniforms.uDim, Math.min(Math.max(config.dim, 0), 1));
|
|
567
|
+
gl.uniform1f(uniforms.uLight, Math.min(Math.max(config.light, 0), 3));
|
|
568
|
+
gl.uniform1f(
|
|
569
|
+
uniforms.uLightRadius,
|
|
570
|
+
Math.min(Math.max(config.lightRadius, 20), 600) * dpr
|
|
571
|
+
);
|
|
572
|
+
gl.uniform1f(uniforms.uLightHeight, Math.max(config.lightHeight, 4) * dpr);
|
|
573
|
+
gl.uniform1f(uniforms.uRelief, Math.min(Math.max(config.relief, 0), 2));
|
|
574
|
+
gl.uniform1f(uniforms.uStir, wakeTouched ? stirAmount() : 0);
|
|
575
|
+
gl.uniform1f(uniforms.uScroll, content.scrollTop * dpr);
|
|
576
|
+
gl.uniform1f(uniforms.uPageLum, pageLum);
|
|
577
|
+
gl.uniform1f(uniforms.uHasContent, htmlInCanvas ? 1 : 0);
|
|
578
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
579
|
+
gl.viewport(0, 0, output.width, output.height);
|
|
580
|
+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
|
581
|
+
}
|
|
582
|
+
let raf = 0;
|
|
583
|
+
let lastTime = performance.now();
|
|
584
|
+
let destroyed = false;
|
|
585
|
+
let running = false;
|
|
586
|
+
let visible = true;
|
|
587
|
+
const motionQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
588
|
+
let reducedMotion = motionQuery.matches;
|
|
589
|
+
function frame(now) {
|
|
590
|
+
if (destroyed) return;
|
|
591
|
+
if (!visible) {
|
|
592
|
+
running = false;
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
const delta = Math.min((now - lastTime) / 1e3, 1 / 30);
|
|
596
|
+
lastTime = now;
|
|
597
|
+
if (!reducedMotion) time += delta;
|
|
598
|
+
stepWake(delta);
|
|
599
|
+
render();
|
|
600
|
+
if (reducedMotion && !contentDirty) {
|
|
601
|
+
running = false;
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
raf = requestAnimationFrame(frame);
|
|
605
|
+
}
|
|
606
|
+
function start() {
|
|
607
|
+
if (destroyed || running || !visible) return;
|
|
608
|
+
running = true;
|
|
609
|
+
lastTime = performance.now();
|
|
610
|
+
raf = requestAnimationFrame(frame);
|
|
611
|
+
}
|
|
612
|
+
wake = start;
|
|
613
|
+
start();
|
|
614
|
+
function onMotionChange() {
|
|
615
|
+
reducedMotion = motionQuery.matches;
|
|
616
|
+
if (reducedMotion) {
|
|
617
|
+
tracking = false;
|
|
618
|
+
wakeCharge.fill(0);
|
|
619
|
+
for (let i = 0; i < WAKE_RES; i++) wakeField[i * 2 + 1] = 0;
|
|
620
|
+
wakeLive = true;
|
|
621
|
+
}
|
|
622
|
+
start();
|
|
623
|
+
}
|
|
624
|
+
motionQuery.addEventListener("change", onMotionChange);
|
|
625
|
+
content.addEventListener("scroll", start, { passive: true });
|
|
626
|
+
const pointerHost = output.parentElement ?? output;
|
|
627
|
+
function pointerNorm(event) {
|
|
628
|
+
const box = output.getBoundingClientRect();
|
|
629
|
+
if (box.width < 1) return -1;
|
|
630
|
+
return (event.clientX - box.left) / box.width;
|
|
631
|
+
}
|
|
632
|
+
function onPointerMove(event) {
|
|
633
|
+
if (reducedMotion) return;
|
|
634
|
+
const x = pointerNorm(event);
|
|
635
|
+
if (x < 0) return;
|
|
636
|
+
pointerX = x;
|
|
637
|
+
tracking = true;
|
|
638
|
+
start();
|
|
639
|
+
}
|
|
640
|
+
function onPointerLeave() {
|
|
641
|
+
tracking = false;
|
|
642
|
+
}
|
|
643
|
+
function onPointerDown(event) {
|
|
644
|
+
if (reducedMotion || stirAmount() <= 1e-3) return;
|
|
645
|
+
const x = pointerNorm(event);
|
|
646
|
+
if (x < 0) return;
|
|
647
|
+
pointerX = x;
|
|
648
|
+
tracking = true;
|
|
649
|
+
const span = wakeSpan() * 1.8;
|
|
650
|
+
for (let i = 0; i < WAKE_RES; i++) {
|
|
651
|
+
const d = Math.abs((i + 0.5) / WAKE_RES - x) / span;
|
|
652
|
+
if (d >= 1) continue;
|
|
653
|
+
const t = 1 - d;
|
|
654
|
+
const burst = t * t * (3 - 2 * t);
|
|
655
|
+
if (burst > wakeCharge[i]) wakeCharge[i] = burst;
|
|
656
|
+
}
|
|
657
|
+
start();
|
|
658
|
+
}
|
|
659
|
+
pointerHost.addEventListener("pointermove", onPointerMove, { passive: true });
|
|
660
|
+
pointerHost.addEventListener("pointerleave", onPointerLeave, { passive: true });
|
|
661
|
+
pointerHost.addEventListener("pointercancel", onPointerLeave, { passive: true });
|
|
662
|
+
pointerHost.addEventListener("pointerdown", onPointerDown, { passive: true });
|
|
663
|
+
const observer = new ResizeObserver(() => {
|
|
664
|
+
syncCanvasSize();
|
|
665
|
+
start();
|
|
666
|
+
});
|
|
667
|
+
observer.observe(output);
|
|
668
|
+
observer.observe(content);
|
|
669
|
+
const intersection = new IntersectionObserver((entries) => {
|
|
670
|
+
visible = entries[entries.length - 1]?.isIntersecting ?? true;
|
|
671
|
+
if (visible) start();
|
|
672
|
+
});
|
|
673
|
+
intersection.observe(output);
|
|
674
|
+
return {
|
|
675
|
+
setOptions(next) {
|
|
676
|
+
let changed = false;
|
|
677
|
+
for (const [key, value] of Object.entries(next)) {
|
|
678
|
+
const prev = config[key];
|
|
679
|
+
if (Array.isArray(value) && Array.isArray(prev)) {
|
|
680
|
+
if (value.length !== prev.length || value.some((item, i) => item !== prev[i])) {
|
|
681
|
+
changed = true;
|
|
682
|
+
break;
|
|
683
|
+
}
|
|
684
|
+
} else if (prev !== value) {
|
|
685
|
+
changed = true;
|
|
686
|
+
break;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
Object.assign(config, next);
|
|
690
|
+
if (!changed) return;
|
|
691
|
+
syncAtlas();
|
|
692
|
+
syncCanvasSize();
|
|
693
|
+
start();
|
|
694
|
+
},
|
|
695
|
+
resize() {
|
|
696
|
+
syncCanvasSize();
|
|
697
|
+
start();
|
|
698
|
+
},
|
|
699
|
+
destroy() {
|
|
700
|
+
destroyed = true;
|
|
701
|
+
cancelAnimationFrame(raf);
|
|
702
|
+
observer.disconnect();
|
|
703
|
+
intersection.disconnect();
|
|
704
|
+
motionQuery.removeEventListener("change", onMotionChange);
|
|
705
|
+
content.removeEventListener("scroll", start);
|
|
706
|
+
pointerHost.removeEventListener("pointermove", onPointerMove);
|
|
707
|
+
pointerHost.removeEventListener("pointerleave", onPointerLeave);
|
|
708
|
+
pointerHost.removeEventListener("pointercancel", onPointerLeave);
|
|
709
|
+
pointerHost.removeEventListener("pointerdown", onPointerDown);
|
|
710
|
+
gl.deleteTexture(contentTexture);
|
|
711
|
+
gl.deleteTexture(atlasTexture);
|
|
712
|
+
gl.deleteTexture(wakeTexture);
|
|
713
|
+
gl.deleteProgram(program);
|
|
714
|
+
gl.deleteShader(vertexShader);
|
|
715
|
+
gl.deleteShader(fragmentShader);
|
|
716
|
+
gl.deleteBuffer(quad);
|
|
717
|
+
if (htmlInCanvas) paintable.onpaint = null;
|
|
718
|
+
}
|
|
719
|
+
};
|
|
720
|
+
}
|
|
721
|
+
var emptySubscribe = () => () => {
|
|
722
|
+
};
|
|
723
|
+
function GlyphRain({
|
|
724
|
+
children,
|
|
725
|
+
className,
|
|
726
|
+
style,
|
|
727
|
+
...options
|
|
728
|
+
}) {
|
|
729
|
+
const sourceRef = useRef(null);
|
|
730
|
+
const contentRef = useRef(null);
|
|
731
|
+
const outputRef = useRef(null);
|
|
732
|
+
const instanceRef = useRef(null);
|
|
733
|
+
const [initialOptions] = useState(options);
|
|
734
|
+
const [failed, setFailed] = useState(false);
|
|
735
|
+
const supported = useSyncExternalStore(
|
|
736
|
+
emptySubscribe,
|
|
737
|
+
supportsHtmlInCanvas,
|
|
738
|
+
() => false
|
|
739
|
+
);
|
|
740
|
+
const native = supported && !failed;
|
|
741
|
+
useEffect(() => {
|
|
742
|
+
const source = sourceRef.current;
|
|
743
|
+
const content = contentRef.current;
|
|
744
|
+
const output = outputRef.current;
|
|
745
|
+
if (!source || !content || !output) return;
|
|
746
|
+
instanceRef.current = createGlyphRain(
|
|
747
|
+
{ source, content, output },
|
|
748
|
+
initialOptions
|
|
749
|
+
);
|
|
750
|
+
if (native && !instanceRef.current) setFailed(true);
|
|
751
|
+
return () => {
|
|
752
|
+
instanceRef.current?.destroy();
|
|
753
|
+
instanceRef.current = null;
|
|
754
|
+
};
|
|
755
|
+
}, [initialOptions, native]);
|
|
756
|
+
useEffect(() => {
|
|
757
|
+
instanceRef.current?.setOptions(options);
|
|
758
|
+
});
|
|
759
|
+
return /* @__PURE__ */ jsxs("div", { className, style: { position: "relative", ...style }, children: [
|
|
760
|
+
/* @__PURE__ */ jsx(
|
|
761
|
+
"canvas",
|
|
762
|
+
{
|
|
763
|
+
ref: sourceRef,
|
|
764
|
+
layoutsubtree: "true",
|
|
765
|
+
suppressHydrationWarning: true,
|
|
766
|
+
style: native ? {
|
|
767
|
+
position: "absolute",
|
|
768
|
+
inset: 0,
|
|
769
|
+
width: "100%",
|
|
770
|
+
height: "100%"
|
|
771
|
+
} : { display: "none" },
|
|
772
|
+
children: native ? /* @__PURE__ */ jsx(
|
|
773
|
+
"div",
|
|
774
|
+
{
|
|
775
|
+
ref: contentRef,
|
|
776
|
+
style: {
|
|
777
|
+
position: "relative",
|
|
778
|
+
width: "100%",
|
|
779
|
+
height: "100%",
|
|
780
|
+
overflow: "auto"
|
|
781
|
+
},
|
|
782
|
+
children
|
|
783
|
+
}
|
|
784
|
+
) : null
|
|
785
|
+
}
|
|
786
|
+
),
|
|
787
|
+
!native ? /* @__PURE__ */ jsx(
|
|
788
|
+
"div",
|
|
789
|
+
{
|
|
790
|
+
ref: contentRef,
|
|
791
|
+
style: {
|
|
792
|
+
position: "relative",
|
|
793
|
+
width: "100%",
|
|
794
|
+
height: "100%",
|
|
795
|
+
overflow: "auto"
|
|
796
|
+
},
|
|
797
|
+
children
|
|
798
|
+
}
|
|
799
|
+
) : null,
|
|
800
|
+
/* @__PURE__ */ jsx(
|
|
801
|
+
"canvas",
|
|
802
|
+
{
|
|
803
|
+
ref: outputRef,
|
|
804
|
+
"aria-hidden": true,
|
|
805
|
+
style: {
|
|
806
|
+
position: "absolute",
|
|
807
|
+
inset: 0,
|
|
808
|
+
width: "100%",
|
|
809
|
+
height: "100%",
|
|
810
|
+
pointerEvents: "none"
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
)
|
|
814
|
+
] });
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
export { DEFAULTS, DEFAULT_CHARSET, GlyphRain, createGlyphRain, supportsHtmlInCanvas };
|
|
818
|
+
//# sourceMappingURL=index.js.map
|
|
819
|
+
//# sourceMappingURL=index.js.map
|