@toriistudio/shader-ui 0.0.2 → 0.0.4
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/dist/index.d.mts +105 -1
- package/dist/index.d.ts +105 -1
- package/dist/index.js +1595 -5
- package/dist/index.mjs +1600 -4
- package/package.json +6 -2
package/dist/index.mjs
CHANGED
|
@@ -13,7 +13,8 @@ function useScene({
|
|
|
13
13
|
onCreate,
|
|
14
14
|
onRender,
|
|
15
15
|
onResize,
|
|
16
|
-
deps
|
|
16
|
+
deps,
|
|
17
|
+
manualRender = false
|
|
17
18
|
} = {}) {
|
|
18
19
|
const containerRef = useRef(null);
|
|
19
20
|
const contextRef = useRef(null);
|
|
@@ -43,6 +44,10 @@ function useScene({
|
|
|
43
44
|
antialias: true,
|
|
44
45
|
...rendererOptions
|
|
45
46
|
});
|
|
47
|
+
renderer.autoClear = false;
|
|
48
|
+
renderer.autoClearColor = true;
|
|
49
|
+
renderer.autoClearDepth = true;
|
|
50
|
+
renderer.autoClearStencil = true;
|
|
46
51
|
renderer.setPixelRatio(resolvedPixelRatio);
|
|
47
52
|
renderer.setSize(initialWidth, initialHeight, false);
|
|
48
53
|
renderer.setClearColor(0, 0);
|
|
@@ -93,7 +98,9 @@ function useScene({
|
|
|
93
98
|
elapsedTime += delta;
|
|
94
99
|
context.size = { ...sizeRef.current };
|
|
95
100
|
onRenderRef.current?.(context, delta, elapsedTime);
|
|
96
|
-
|
|
101
|
+
if (!manualRender) {
|
|
102
|
+
renderer.render(scene, camera);
|
|
103
|
+
}
|
|
97
104
|
animationFrameId = requestAnimationFrame(renderLoop);
|
|
98
105
|
};
|
|
99
106
|
animationFrameId = requestAnimationFrame(renderLoop);
|
|
@@ -104,13 +111,14 @@ function useScene({
|
|
|
104
111
|
sizeRef.current = { width, height };
|
|
105
112
|
if (camera instanceof THREE.PerspectiveCamera) {
|
|
106
113
|
camera.aspect = width / Math.max(1, height);
|
|
114
|
+
camera.updateProjectionMatrix();
|
|
107
115
|
} else if (camera instanceof THREE.OrthographicCamera) {
|
|
108
116
|
camera.left = -width / 2;
|
|
109
117
|
camera.right = width / 2;
|
|
110
118
|
camera.top = height / 2;
|
|
111
119
|
camera.bottom = -height / 2;
|
|
120
|
+
camera.updateProjectionMatrix();
|
|
112
121
|
}
|
|
113
|
-
camera.updateProjectionMatrix();
|
|
114
122
|
context.size = { ...sizeRef.current };
|
|
115
123
|
onResizeRef.current?.(context, { width, height });
|
|
116
124
|
});
|
|
@@ -1045,9 +1053,1597 @@ function createDiffuseTexture() {
|
|
|
1045
1053
|
texture.generateMipmaps = true;
|
|
1046
1054
|
return texture;
|
|
1047
1055
|
}
|
|
1056
|
+
|
|
1057
|
+
// src/components/EfectoAsciiEffect.tsx
|
|
1058
|
+
import {
|
|
1059
|
+
useCallback as useCallback5,
|
|
1060
|
+
useEffect as useEffect6,
|
|
1061
|
+
useMemo as useMemo3,
|
|
1062
|
+
useRef as useRef6
|
|
1063
|
+
} from "react";
|
|
1064
|
+
import {
|
|
1065
|
+
BlendFunction,
|
|
1066
|
+
Effect,
|
|
1067
|
+
EffectComposer,
|
|
1068
|
+
EffectPass,
|
|
1069
|
+
RenderPass
|
|
1070
|
+
} from "postprocessing";
|
|
1071
|
+
import * as THREE6 from "three";
|
|
1072
|
+
import { Uniform, Vector2 as Vector23 } from "three";
|
|
1073
|
+
|
|
1074
|
+
// src/utils/efectoMediaAdjustments.ts
|
|
1075
|
+
var EFECTO_MEDIA_ADJUSTMENT_DEFAULTS = {
|
|
1076
|
+
brightness: 1,
|
|
1077
|
+
contrast: 1,
|
|
1078
|
+
saturation: 1
|
|
1079
|
+
};
|
|
1080
|
+
var resolveEfectoMediaAdjustments = (adjustments) => ({
|
|
1081
|
+
brightness: typeof adjustments?.brightness === "number" ? adjustments.brightness : EFECTO_MEDIA_ADJUSTMENT_DEFAULTS.brightness,
|
|
1082
|
+
contrast: typeof adjustments?.contrast === "number" ? adjustments.contrast : EFECTO_MEDIA_ADJUSTMENT_DEFAULTS.contrast,
|
|
1083
|
+
saturation: typeof adjustments?.saturation === "number" ? adjustments.saturation : EFECTO_MEDIA_ADJUSTMENT_DEFAULTS.saturation
|
|
1084
|
+
});
|
|
1085
|
+
|
|
1086
|
+
// src/shaders/efecto-ascii-effect/fragment.ts
|
|
1087
|
+
var fragment_default5 = `
|
|
1088
|
+
uniform float cellSize;
|
|
1089
|
+
uniform bool invert;
|
|
1090
|
+
uniform bool colorMode;
|
|
1091
|
+
uniform int asciiStyle;
|
|
1092
|
+
|
|
1093
|
+
// PostFX uniforms
|
|
1094
|
+
uniform float time;
|
|
1095
|
+
uniform vec2 resolution;
|
|
1096
|
+
uniform vec2 mousePos;
|
|
1097
|
+
|
|
1098
|
+
// Tier 1 uniforms
|
|
1099
|
+
uniform float scanlineIntensity;
|
|
1100
|
+
uniform float scanlineCount;
|
|
1101
|
+
uniform float targetFPS;
|
|
1102
|
+
uniform float jitterIntensity;
|
|
1103
|
+
uniform float jitterSpeed;
|
|
1104
|
+
uniform bool mouseGlowEnabled;
|
|
1105
|
+
uniform float mouseGlowRadius;
|
|
1106
|
+
uniform float mouseGlowIntensity;
|
|
1107
|
+
uniform float vignetteIntensity;
|
|
1108
|
+
uniform float vignetteRadius;
|
|
1109
|
+
uniform int colorPalette;
|
|
1110
|
+
|
|
1111
|
+
// Tier 2 uniforms
|
|
1112
|
+
uniform float curvature;
|
|
1113
|
+
uniform float aberrationStrength;
|
|
1114
|
+
uniform float noiseIntensity;
|
|
1115
|
+
uniform float noiseScale;
|
|
1116
|
+
uniform float noiseSpeed;
|
|
1117
|
+
uniform float waveAmplitude;
|
|
1118
|
+
uniform float waveFrequency;
|
|
1119
|
+
uniform float waveSpeed;
|
|
1120
|
+
uniform float glitchIntensity;
|
|
1121
|
+
uniform float glitchFrequency;
|
|
1122
|
+
uniform float brightnessAdjust;
|
|
1123
|
+
uniform float contrastAdjust;
|
|
1124
|
+
|
|
1125
|
+
// =======================
|
|
1126
|
+
// HELPER FUNCTIONS
|
|
1127
|
+
// =======================
|
|
1128
|
+
|
|
1129
|
+
// Pseudo-random function
|
|
1130
|
+
float random(vec2 st) {
|
|
1131
|
+
return fract(sin(dot(st, vec2(12.9898, 78.233))) * 43758.5453);
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
// 2D Noise function
|
|
1135
|
+
float noise(vec2 st) {
|
|
1136
|
+
vec2 i = floor(st);
|
|
1137
|
+
vec2 f = fract(st);
|
|
1138
|
+
float a = random(i);
|
|
1139
|
+
float b = random(i + vec2(1.0, 0.0));
|
|
1140
|
+
float c = random(i + vec2(0.0, 1.0));
|
|
1141
|
+
float d = random(i + vec2(1.0, 1.0));
|
|
1142
|
+
vec2 u = f * f * (3.0 - 2.0 * f);
|
|
1143
|
+
return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
// RGB to HSL conversion
|
|
1147
|
+
vec3 rgb2hsl(vec3 rgb) {
|
|
1148
|
+
float maxVal = max(max(rgb.r, rgb.g), rgb.b);
|
|
1149
|
+
float minVal = min(min(rgb.r, rgb.g), rgb.b);
|
|
1150
|
+
float delta = maxVal - minVal;
|
|
1151
|
+
|
|
1152
|
+
float h = 0.0;
|
|
1153
|
+
float s = 0.0;
|
|
1154
|
+
float l = (maxVal + minVal) * 0.5;
|
|
1155
|
+
|
|
1156
|
+
if (delta > 0.0001) {
|
|
1157
|
+
s = delta / (1.0 - abs(2.0 * l - 1.0));
|
|
1158
|
+
|
|
1159
|
+
if (maxVal == rgb.r) {
|
|
1160
|
+
h = mod((rgb.g - rgb.b) / delta, 6.0);
|
|
1161
|
+
} else if (maxVal == rgb.g) {
|
|
1162
|
+
h = (rgb.b - rgb.r) / delta + 2.0;
|
|
1163
|
+
} else {
|
|
1164
|
+
h = (rgb.r - rgb.g) / delta + 4.0;
|
|
1165
|
+
}
|
|
1166
|
+
h = h / 6.0;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
return vec3(h, s, l);
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
// HSL to RGB conversion
|
|
1173
|
+
vec3 hsl2rgb(vec3 hsl) {
|
|
1174
|
+
float h = hsl.x;
|
|
1175
|
+
float s = hsl.y;
|
|
1176
|
+
float l = hsl.z;
|
|
1177
|
+
|
|
1178
|
+
float c = (1.0 - abs(2.0 * l - 1.0)) * s;
|
|
1179
|
+
float x = c * (1.0 - abs(mod(h * 6.0, 2.0) - 1.0));
|
|
1180
|
+
float m = l - c * 0.5;
|
|
1181
|
+
|
|
1182
|
+
vec3 rgb = vec3(0.0);
|
|
1183
|
+
|
|
1184
|
+
if (h < 1.0/6.0) {
|
|
1185
|
+
rgb = vec3(c, x, 0.0);
|
|
1186
|
+
} else if (h < 2.0/6.0) {
|
|
1187
|
+
rgb = vec3(x, c, 0.0);
|
|
1188
|
+
} else if (h < 3.0/6.0) {
|
|
1189
|
+
rgb = vec3(0.0, c, x);
|
|
1190
|
+
} else if (h < 4.0/6.0) {
|
|
1191
|
+
rgb = vec3(0.0, x, c);
|
|
1192
|
+
} else if (h < 5.0/6.0) {
|
|
1193
|
+
rgb = vec3(x, 0.0, c);
|
|
1194
|
+
} else {
|
|
1195
|
+
rgb = vec3(c, 0.0, x);
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
return rgb + m;
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
// Apply color palette
|
|
1202
|
+
vec3 applyColorPalette(vec3 color, float brightness, int palette) {
|
|
1203
|
+
if (palette == 0) return color; // Original
|
|
1204
|
+
|
|
1205
|
+
vec3 paletteColor = color;
|
|
1206
|
+
|
|
1207
|
+
if (palette == 1) { // Green phosphor
|
|
1208
|
+
paletteColor = vec3(0.0, brightness, 0.0) * 1.5;
|
|
1209
|
+
} else if (palette == 2) { // Amber
|
|
1210
|
+
paletteColor = vec3(brightness * 1.2, brightness * 0.7, 0.0);
|
|
1211
|
+
} else if (palette == 3) { // Cyan
|
|
1212
|
+
paletteColor = vec3(0.0, brightness * 0.9, brightness);
|
|
1213
|
+
} else if (palette == 4) { // Blue
|
|
1214
|
+
paletteColor = vec3(0.0, 0.0, brightness);
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
return paletteColor;
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
// Different character patterns based on style
|
|
1221
|
+
float getChar(float brightness, vec2 p, int style) {
|
|
1222
|
+
vec2 grid = floor(p * 4.0);
|
|
1223
|
+
float val = 0.0;
|
|
1224
|
+
|
|
1225
|
+
if (style == 0) {
|
|
1226
|
+
// Standard ASCII style
|
|
1227
|
+
if (brightness < 0.2) {
|
|
1228
|
+
val = (grid.x == 1.0 && grid.y == 1.0) ? 0.3 : 0.0;
|
|
1229
|
+
} else if (brightness < 0.35) {
|
|
1230
|
+
val = (grid.x == 1.0 || grid.x == 2.0) && (grid.y == 1.0 || grid.y == 2.0) ? 1.0 : 0.0;
|
|
1231
|
+
} else if (brightness < 0.5) {
|
|
1232
|
+
val = (grid.y == 1.0 || grid.y == 2.0) ? 1.0 : 0.0;
|
|
1233
|
+
} else if (brightness < 0.65) {
|
|
1234
|
+
val = (grid.y == 0.0 || grid.y == 3.0) ? 1.0 : (grid.y == 1.0 || grid.y == 2.0) ? 0.5 : 0.0;
|
|
1235
|
+
} else if (brightness < 0.8) {
|
|
1236
|
+
val = (grid.x == 0.0 || grid.x == 2.0 || grid.y == 0.0 || grid.y == 2.0) ? 1.0 : 0.3;
|
|
1237
|
+
} else {
|
|
1238
|
+
val = 1.0;
|
|
1239
|
+
}
|
|
1240
|
+
} else if (style == 1) {
|
|
1241
|
+
// Dense style
|
|
1242
|
+
if (brightness < 0.15) {
|
|
1243
|
+
val = 0.0;
|
|
1244
|
+
} else if (brightness < 0.3) {
|
|
1245
|
+
val = (grid.x >= 1.0 && grid.x <= 2.0 && grid.y >= 1.0 && grid.y <= 2.0) ? 0.6 : 0.0;
|
|
1246
|
+
} else if (brightness < 0.5) {
|
|
1247
|
+
val = (grid.y == 1.0 || grid.y == 2.0) ? 1.0 : 0.3;
|
|
1248
|
+
} else if (brightness < 0.7) {
|
|
1249
|
+
val = (grid.x == 0.0 || grid.x == 3.0 || grid.y == 0.0 || grid.y == 3.0) ? 1.0 : 0.6;
|
|
1250
|
+
} else {
|
|
1251
|
+
val = 1.0;
|
|
1252
|
+
}
|
|
1253
|
+
} else if (style == 2) {
|
|
1254
|
+
// Minimal style
|
|
1255
|
+
if (brightness < 0.25) {
|
|
1256
|
+
val = 0.0;
|
|
1257
|
+
} else if (brightness < 0.4) {
|
|
1258
|
+
val = (grid.x == 2.0 && grid.y == 2.0) ? 1.0 : 0.0;
|
|
1259
|
+
} else if (brightness < 0.6) {
|
|
1260
|
+
val = (grid.x == 1.0 || grid.x == 2.0) && grid.y == 2.0 ? 1.0 : 0.0;
|
|
1261
|
+
} else if (brightness < 0.8) {
|
|
1262
|
+
val = (grid.y == 1.0 || grid.y == 2.0) ? 1.0 : 0.0;
|
|
1263
|
+
} else {
|
|
1264
|
+
val = (grid.x <= 2.0 && grid.y <= 2.0) ? 1.0 : 0.3;
|
|
1265
|
+
}
|
|
1266
|
+
} else if (style == 3) {
|
|
1267
|
+
// Blocks style
|
|
1268
|
+
if (brightness < 0.2) {
|
|
1269
|
+
val = 0.0;
|
|
1270
|
+
} else if (brightness < 0.4) {
|
|
1271
|
+
val = (grid.x >= 1.0 && grid.x <= 2.0 && grid.y >= 1.0 && grid.y <= 2.0) ? 0.8 : 0.0;
|
|
1272
|
+
} else if (brightness < 0.6) {
|
|
1273
|
+
val = (grid.y <= 2.0) ? 0.9 : 0.0;
|
|
1274
|
+
} else if (brightness < 0.8) {
|
|
1275
|
+
val = (grid.x <= 2.0 || grid.y <= 2.0) ? 1.0 : 0.2;
|
|
1276
|
+
} else {
|
|
1277
|
+
val = 1.0;
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
return val;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) {
|
|
1285
|
+
vec2 workingUV = uv;
|
|
1286
|
+
|
|
1287
|
+
// ===========================
|
|
1288
|
+
// TIER 2: PRE-PROCESSING
|
|
1289
|
+
// ===========================
|
|
1290
|
+
|
|
1291
|
+
// Screen curvature
|
|
1292
|
+
if (curvature > 0.0) {
|
|
1293
|
+
vec2 centered = workingUV * 2.0 - 1.0;
|
|
1294
|
+
float dist = dot(centered, centered);
|
|
1295
|
+
centered *= 1.0 + curvature * dist;
|
|
1296
|
+
workingUV = centered * 0.5 + 0.5;
|
|
1297
|
+
|
|
1298
|
+
// Make out-of-bounds transparent so parent background shows through
|
|
1299
|
+
if (workingUV.x < 0.0 || workingUV.x > 1.0 || workingUV.y < 0.0 || workingUV.y > 1.0) {
|
|
1300
|
+
outputColor = vec4(0.0, 0.0, 0.0, 0.0);
|
|
1301
|
+
return;
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
// Wave distortion
|
|
1306
|
+
if (waveAmplitude > 0.0) {
|
|
1307
|
+
workingUV.x += sin(workingUV.y * waveFrequency + time * waveSpeed) * waveAmplitude;
|
|
1308
|
+
workingUV.y += cos(workingUV.x * waveFrequency + time * waveSpeed) * waveAmplitude * 0.5;
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
// ===========================
|
|
1312
|
+
// CORE ASCII RENDERING
|
|
1313
|
+
// ===========================
|
|
1314
|
+
|
|
1315
|
+
vec2 res = resolution;
|
|
1316
|
+
vec2 cellCount = res / cellSize;
|
|
1317
|
+
vec2 cellCoord = floor(workingUV * cellCount);
|
|
1318
|
+
|
|
1319
|
+
// Frame rate control
|
|
1320
|
+
if (targetFPS > 0.0) {
|
|
1321
|
+
float frameTime = 1.0 / targetFPS;
|
|
1322
|
+
float frameIndex = floor(time / frameTime);
|
|
1323
|
+
cellCoord = floor(workingUV * cellCount) + vec2(random(vec2(frameIndex)) * 0.5);
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
vec2 cellUV = (cellCoord + 0.5) / cellCount;
|
|
1327
|
+
|
|
1328
|
+
// Chromatic aberration
|
|
1329
|
+
vec4 cellColor;
|
|
1330
|
+
if (aberrationStrength > 0.0) {
|
|
1331
|
+
float r = texture(inputBuffer, cellUV + vec2(aberrationStrength, 0.0)).r;
|
|
1332
|
+
float g = texture(inputBuffer, cellUV).g;
|
|
1333
|
+
float b = texture(inputBuffer, cellUV - vec2(aberrationStrength, 0.0)).b;
|
|
1334
|
+
cellColor = vec4(r, g, b, 1.0);
|
|
1335
|
+
} else {
|
|
1336
|
+
cellColor = texture(inputBuffer, cellUV);
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
// Calculate brightness
|
|
1340
|
+
float brightness = dot(cellColor.rgb, vec3(0.299, 0.587, 0.114));
|
|
1341
|
+
|
|
1342
|
+
// Contrast and brightness adjustment
|
|
1343
|
+
brightness = (brightness - 0.5) * contrastAdjust + 0.5 + brightnessAdjust;
|
|
1344
|
+
brightness = clamp(brightness, 0.0, 1.0);
|
|
1345
|
+
|
|
1346
|
+
// Time-based noise
|
|
1347
|
+
if (noiseIntensity > 0.0) {
|
|
1348
|
+
float noiseVal = noise(workingUV * noiseScale * 100.0 + time * noiseSpeed);
|
|
1349
|
+
brightness = mix(brightness, noiseVal, noiseIntensity);
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
// Jitter/fuzzy effect
|
|
1353
|
+
if (jitterIntensity > 0.0) {
|
|
1354
|
+
float jitter = random(cellCoord + floor(time * jitterSpeed) * 0.1) - 0.5;
|
|
1355
|
+
brightness += jitter * jitterIntensity;
|
|
1356
|
+
brightness = clamp(brightness, 0.0, 1.0);
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
// RGB Glitch
|
|
1360
|
+
if (glitchIntensity > 0.0 && glitchFrequency > 0.0) {
|
|
1361
|
+
float glitchTrigger = random(vec2(time * glitchFrequency));
|
|
1362
|
+
if (glitchTrigger > 0.9) {
|
|
1363
|
+
float glitchOffset = (random(cellCoord + time) - 0.5) * glitchIntensity;
|
|
1364
|
+
cellColor.r = texture(inputBuffer, cellUV + vec2(glitchOffset, 0.0)).r;
|
|
1365
|
+
cellColor.b = texture(inputBuffer, cellUV - vec2(glitchOffset, 0.0)).b;
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
if (invert) {
|
|
1370
|
+
brightness = 1.0 - brightness;
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
// Get local UV within the cell
|
|
1374
|
+
vec2 localUV = fract(workingUV * cellCount);
|
|
1375
|
+
float charValue = getChar(brightness, localUV, asciiStyle);
|
|
1376
|
+
|
|
1377
|
+
// ===========================
|
|
1378
|
+
// TIER 1: POST-PROCESSING
|
|
1379
|
+
// ===========================
|
|
1380
|
+
|
|
1381
|
+
vec3 finalColor;
|
|
1382
|
+
|
|
1383
|
+
if (colorMode) {
|
|
1384
|
+
finalColor = cellColor.rgb * charValue;
|
|
1385
|
+
} else {
|
|
1386
|
+
finalColor = vec3(brightness * charValue);
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
// Color palette
|
|
1390
|
+
finalColor = applyColorPalette(finalColor, brightness, colorPalette);
|
|
1391
|
+
|
|
1392
|
+
// Mouse glow
|
|
1393
|
+
if (mouseGlowEnabled && mouseGlowRadius > 0.0) {
|
|
1394
|
+
vec2 pixelPos = workingUV * res;
|
|
1395
|
+
float dist = distance(pixelPos, mousePos);
|
|
1396
|
+
float glow = 1.0 - smoothstep(0.0, mouseGlowRadius, dist);
|
|
1397
|
+
glow = pow(glow, 2.0);
|
|
1398
|
+
finalColor *= 1.0 + glow * mouseGlowIntensity;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
// Scanlines
|
|
1402
|
+
if (scanlineIntensity > 0.0) {
|
|
1403
|
+
float scanline = sin(workingUV.y * scanlineCount * 3.14159) * 0.5 + 0.5;
|
|
1404
|
+
finalColor *= 1.0 - scanlineIntensity * (1.0 - scanline);
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
// Vignette
|
|
1408
|
+
if (vignetteIntensity > 0.0) {
|
|
1409
|
+
vec2 centered = workingUV - 0.5;
|
|
1410
|
+
float dist = length(centered) / 0.707; // Normalize to corner distance
|
|
1411
|
+
float vignette = smoothstep(vignetteRadius, vignetteRadius - 0.5, dist);
|
|
1412
|
+
finalColor *= mix(1.0, vignette, vignetteIntensity);
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
outputColor = vec4(finalColor, cellColor.a);
|
|
1416
|
+
}
|
|
1417
|
+
`;
|
|
1418
|
+
|
|
1419
|
+
// src/shaders/efecto-media-image/vertex.glsl
|
|
1420
|
+
var vertex_default5 = "uniform vec2 uvScale;\nuniform vec2 uvOffset;\nvarying vec2 vUv;\n\nvoid main() {\n // Apply texture scale and offset for cover-fill effect\n vUv = uv * uvScale + uvOffset;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n}";
|
|
1421
|
+
|
|
1422
|
+
// src/shaders/efecto-media-image/fragment.glsl
|
|
1423
|
+
var fragment_default6 = "uniform sampler2D map;\nuniform float brightness;\nuniform float contrast;\nuniform float saturation;\nvarying vec2 vUv;\n\nvec3 adjustContrast(vec3 color, float contrastAmount) {\n return (color - 0.5) * contrastAmount + 0.5;\n}\n\nvec3 adjustSaturation(vec3 color, float saturationAmount) {\n float gray = dot(color, vec3(0.299, 0.587, 0.114));\n return mix(vec3(gray), color, saturationAmount);\n}\n\nvoid main() {\n vec4 texel = texture2D(map, vUv);\n vec3 color = texel.rgb;\n\n // Apply brightness\n color *= brightness;\n\n // Apply contrast\n color = adjustContrast(color, contrast);\n\n // Apply saturation\n color = adjustSaturation(color, saturation);\n\n gl_FragColor = vec4(color, texel.a);\n}";
|
|
1424
|
+
|
|
1425
|
+
// src/components/EfectoAsciiEffect.tsx
|
|
1426
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
1427
|
+
var DEFAULT_RESOLUTION = new Vector23(1920, 1080);
|
|
1428
|
+
var DEFAULT_MOUSE_POSITION = new Vector23(0, 0);
|
|
1429
|
+
var PARALLAX_LERP = 0.12;
|
|
1430
|
+
var STYLE_MAP = {
|
|
1431
|
+
standard: 0,
|
|
1432
|
+
dense: 1,
|
|
1433
|
+
minimal: 2,
|
|
1434
|
+
blocks: 3
|
|
1435
|
+
};
|
|
1436
|
+
var COLOR_PALETTE_MAP = {
|
|
1437
|
+
original: 0,
|
|
1438
|
+
green: 1,
|
|
1439
|
+
amber: 2,
|
|
1440
|
+
cyan: 3,
|
|
1441
|
+
blue: 4
|
|
1442
|
+
};
|
|
1443
|
+
var EFECTO_ASCII_COMPONENT_DEFAULTS = {
|
|
1444
|
+
cellSize: 8,
|
|
1445
|
+
invert: false,
|
|
1446
|
+
colorMode: true,
|
|
1447
|
+
asciiStyle: "standard"
|
|
1448
|
+
};
|
|
1449
|
+
var EFECTO_ASCII_POST_PROCESSING_DEFAULTS = {
|
|
1450
|
+
scanlineIntensity: 0,
|
|
1451
|
+
scanlineCount: 200,
|
|
1452
|
+
targetFPS: 0,
|
|
1453
|
+
jitterIntensity: 0,
|
|
1454
|
+
jitterSpeed: 0,
|
|
1455
|
+
mouseGlowEnabled: false,
|
|
1456
|
+
mouseGlowRadius: 200,
|
|
1457
|
+
mouseGlowIntensity: 1.5,
|
|
1458
|
+
vignetteIntensity: 0,
|
|
1459
|
+
vignetteRadius: 0.8,
|
|
1460
|
+
colorPalette: COLOR_PALETTE_MAP.original,
|
|
1461
|
+
curvature: 0,
|
|
1462
|
+
aberrationStrength: 0,
|
|
1463
|
+
noiseIntensity: 0,
|
|
1464
|
+
noiseScale: 0.1,
|
|
1465
|
+
noiseSpeed: 0,
|
|
1466
|
+
waveAmplitude: 0,
|
|
1467
|
+
waveFrequency: 3,
|
|
1468
|
+
waveSpeed: 0.2,
|
|
1469
|
+
glitchIntensity: 0,
|
|
1470
|
+
glitchFrequency: 0,
|
|
1471
|
+
brightnessAdjust: 0,
|
|
1472
|
+
contrastAdjust: 1
|
|
1473
|
+
};
|
|
1474
|
+
var normalizePostProcessing = (overrides) => {
|
|
1475
|
+
const { colorPalette: overridePalette, ...otherOverrides } = overrides ?? {};
|
|
1476
|
+
const merged = {
|
|
1477
|
+
...EFECTO_ASCII_POST_PROCESSING_DEFAULTS,
|
|
1478
|
+
...otherOverrides
|
|
1479
|
+
};
|
|
1480
|
+
const paletteValue = overridePalette === void 0 ? merged.colorPalette : typeof overridePalette === "string" ? COLOR_PALETTE_MAP[overridePalette.toLowerCase()] ?? COLOR_PALETTE_MAP.original : overridePalette;
|
|
1481
|
+
return { ...merged, colorPalette: paletteValue };
|
|
1482
|
+
};
|
|
1483
|
+
var AsciiEffectImpl = class extends Effect {
|
|
1484
|
+
constructor(initialProps) {
|
|
1485
|
+
const uniformEntries = [
|
|
1486
|
+
["cellSize", new Uniform(initialProps.cellSize)],
|
|
1487
|
+
["invert", new Uniform(initialProps.invert)],
|
|
1488
|
+
["colorMode", new Uniform(initialProps.colorMode)],
|
|
1489
|
+
["asciiStyle", new Uniform(initialProps.asciiStyle)],
|
|
1490
|
+
["time", new Uniform(0)],
|
|
1491
|
+
["resolution", new Uniform(initialProps.resolution.clone())],
|
|
1492
|
+
["mousePos", new Uniform(initialProps.mousePos.clone())],
|
|
1493
|
+
["scanlineIntensity", new Uniform(initialProps.scanlineIntensity)],
|
|
1494
|
+
["scanlineCount", new Uniform(initialProps.scanlineCount)],
|
|
1495
|
+
["targetFPS", new Uniform(initialProps.targetFPS)],
|
|
1496
|
+
["jitterIntensity", new Uniform(initialProps.jitterIntensity)],
|
|
1497
|
+
["jitterSpeed", new Uniform(initialProps.jitterSpeed)],
|
|
1498
|
+
["mouseGlowEnabled", new Uniform(initialProps.mouseGlowEnabled)],
|
|
1499
|
+
["mouseGlowRadius", new Uniform(initialProps.mouseGlowRadius)],
|
|
1500
|
+
["mouseGlowIntensity", new Uniform(initialProps.mouseGlowIntensity)],
|
|
1501
|
+
["vignetteIntensity", new Uniform(initialProps.vignetteIntensity)],
|
|
1502
|
+
["vignetteRadius", new Uniform(initialProps.vignetteRadius)],
|
|
1503
|
+
["colorPalette", new Uniform(initialProps.colorPalette)],
|
|
1504
|
+
["curvature", new Uniform(initialProps.curvature)],
|
|
1505
|
+
["aberrationStrength", new Uniform(initialProps.aberrationStrength)],
|
|
1506
|
+
["noiseIntensity", new Uniform(initialProps.noiseIntensity)],
|
|
1507
|
+
["noiseScale", new Uniform(initialProps.noiseScale)],
|
|
1508
|
+
["noiseSpeed", new Uniform(initialProps.noiseSpeed)],
|
|
1509
|
+
["waveAmplitude", new Uniform(initialProps.waveAmplitude)],
|
|
1510
|
+
["waveFrequency", new Uniform(initialProps.waveFrequency)],
|
|
1511
|
+
["waveSpeed", new Uniform(initialProps.waveSpeed)],
|
|
1512
|
+
["glitchIntensity", new Uniform(initialProps.glitchIntensity)],
|
|
1513
|
+
["glitchFrequency", new Uniform(initialProps.glitchFrequency)],
|
|
1514
|
+
["brightnessAdjust", new Uniform(initialProps.brightnessAdjust)],
|
|
1515
|
+
["contrastAdjust", new Uniform(initialProps.contrastAdjust)]
|
|
1516
|
+
];
|
|
1517
|
+
super("AsciiEffect", fragment_default5, {
|
|
1518
|
+
blendFunction: BlendFunction.SRC,
|
|
1519
|
+
uniforms: new Map(uniformEntries)
|
|
1520
|
+
});
|
|
1521
|
+
this.time = 0;
|
|
1522
|
+
this.deltaAccumulator = 0;
|
|
1523
|
+
}
|
|
1524
|
+
updateUniforms(nextProps) {
|
|
1525
|
+
if (nextProps.cellSize !== void 0) {
|
|
1526
|
+
this.uniforms.get("cellSize").value = nextProps.cellSize;
|
|
1527
|
+
}
|
|
1528
|
+
if (nextProps.invert !== void 0) {
|
|
1529
|
+
this.uniforms.get("invert").value = nextProps.invert;
|
|
1530
|
+
}
|
|
1531
|
+
if (nextProps.colorMode !== void 0) {
|
|
1532
|
+
this.uniforms.get("colorMode").value = nextProps.colorMode;
|
|
1533
|
+
}
|
|
1534
|
+
if (nextProps.asciiStyle !== void 0) {
|
|
1535
|
+
this.uniforms.get("asciiStyle").value = nextProps.asciiStyle;
|
|
1536
|
+
}
|
|
1537
|
+
if (nextProps.resolution) {
|
|
1538
|
+
this.setVector2Uniform("resolution", nextProps.resolution);
|
|
1539
|
+
}
|
|
1540
|
+
if (nextProps.mousePos) {
|
|
1541
|
+
this.setVector2Uniform("mousePos", nextProps.mousePos);
|
|
1542
|
+
}
|
|
1543
|
+
const uniformKeys = Object.keys(
|
|
1544
|
+
EFECTO_ASCII_POST_PROCESSING_DEFAULTS
|
|
1545
|
+
);
|
|
1546
|
+
for (const key of uniformKeys) {
|
|
1547
|
+
if (nextProps[key] !== void 0) {
|
|
1548
|
+
this.uniforms.get(key).value = nextProps[key];
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
setVector2Uniform(key, nextValue) {
|
|
1553
|
+
const uniform = this.uniforms.get(key);
|
|
1554
|
+
if (!uniform) {
|
|
1555
|
+
return;
|
|
1556
|
+
}
|
|
1557
|
+
if (uniform.value instanceof Vector23) {
|
|
1558
|
+
uniform.value.copy(nextValue);
|
|
1559
|
+
return;
|
|
1560
|
+
}
|
|
1561
|
+
uniform.value = nextValue.clone();
|
|
1562
|
+
}
|
|
1563
|
+
update(_renderer, _inputBuffer, deltaTime) {
|
|
1564
|
+
const targetFPS = this.uniforms.get("targetFPS").value;
|
|
1565
|
+
if (targetFPS > 0) {
|
|
1566
|
+
const frameDuration = 1 / targetFPS;
|
|
1567
|
+
this.deltaAccumulator += deltaTime;
|
|
1568
|
+
if (this.deltaAccumulator >= frameDuration) {
|
|
1569
|
+
this.time += frameDuration;
|
|
1570
|
+
this.deltaAccumulator = this.deltaAccumulator % frameDuration;
|
|
1571
|
+
}
|
|
1572
|
+
} else {
|
|
1573
|
+
this.time += deltaTime;
|
|
1574
|
+
}
|
|
1575
|
+
this.uniforms.get("time").value = this.time;
|
|
1576
|
+
}
|
|
1577
|
+
};
|
|
1578
|
+
function AsciiEffect({
|
|
1579
|
+
cellSize = EFECTO_ASCII_COMPONENT_DEFAULTS.cellSize,
|
|
1580
|
+
invert = EFECTO_ASCII_COMPONENT_DEFAULTS.invert,
|
|
1581
|
+
colorMode = EFECTO_ASCII_COMPONENT_DEFAULTS.colorMode,
|
|
1582
|
+
asciiStyle: asciiStyleProp = EFECTO_ASCII_COMPONENT_DEFAULTS.asciiStyle,
|
|
1583
|
+
imageUrl,
|
|
1584
|
+
resolution,
|
|
1585
|
+
mousePosition,
|
|
1586
|
+
postProcessing = {},
|
|
1587
|
+
mediaAdjustments,
|
|
1588
|
+
mouseParallax = false,
|
|
1589
|
+
parallaxIntensity = 0.5,
|
|
1590
|
+
className,
|
|
1591
|
+
style,
|
|
1592
|
+
width,
|
|
1593
|
+
height,
|
|
1594
|
+
...divProps
|
|
1595
|
+
}) {
|
|
1596
|
+
const composerRef = useRef6(null);
|
|
1597
|
+
const effectRef = useRef6(null);
|
|
1598
|
+
const assetsRef = useRef6(null);
|
|
1599
|
+
const loadedTextureRef = useRef6(null);
|
|
1600
|
+
const cameraRef = useRef6(null);
|
|
1601
|
+
const mediaUniformsRef = useRef6({
|
|
1602
|
+
map: { value: null },
|
|
1603
|
+
brightness: { value: EFECTO_MEDIA_ADJUSTMENT_DEFAULTS.brightness },
|
|
1604
|
+
contrast: { value: EFECTO_MEDIA_ADJUSTMENT_DEFAULTS.contrast },
|
|
1605
|
+
saturation: { value: EFECTO_MEDIA_ADJUSTMENT_DEFAULTS.saturation },
|
|
1606
|
+
uvScale: { value: new Vector23(1, 1) },
|
|
1607
|
+
uvOffset: { value: new Vector23(0, 0) }
|
|
1608
|
+
});
|
|
1609
|
+
const pointerBoundsRef = useRef6({
|
|
1610
|
+
left: 0,
|
|
1611
|
+
top: 0,
|
|
1612
|
+
width: 1,
|
|
1613
|
+
height: 1
|
|
1614
|
+
});
|
|
1615
|
+
const manualResolutionRef = useRef6(
|
|
1616
|
+
resolution ? resolution.clone() : null
|
|
1617
|
+
);
|
|
1618
|
+
manualResolutionRef.current = resolution ? resolution.clone() : null;
|
|
1619
|
+
const resolutionRef = useRef6(
|
|
1620
|
+
manualResolutionRef.current ? manualResolutionRef.current.clone() : DEFAULT_RESOLUTION.clone()
|
|
1621
|
+
);
|
|
1622
|
+
const autoMouseRef = useRef6(DEFAULT_MOUSE_POSITION.clone());
|
|
1623
|
+
const usesExternalMouseRef = useRef6(Boolean(mousePosition));
|
|
1624
|
+
usesExternalMouseRef.current = Boolean(mousePosition);
|
|
1625
|
+
const viewportSizeRef = useRef6({ width: 1, height: 1 });
|
|
1626
|
+
const meshDisplaySizeRef = useRef6({ width: 1, height: 1 });
|
|
1627
|
+
const parallaxStateRef = useRef6({
|
|
1628
|
+
targetX: 0,
|
|
1629
|
+
targetY: 0,
|
|
1630
|
+
rotationX: 0,
|
|
1631
|
+
rotationY: 0
|
|
1632
|
+
});
|
|
1633
|
+
const parallaxIntensityRef = useRef6(
|
|
1634
|
+
THREE6.MathUtils.clamp(parallaxIntensity ?? 0, 0, 1)
|
|
1635
|
+
);
|
|
1636
|
+
parallaxIntensityRef.current = THREE6.MathUtils.clamp(
|
|
1637
|
+
parallaxIntensity ?? 0,
|
|
1638
|
+
0,
|
|
1639
|
+
1
|
|
1640
|
+
);
|
|
1641
|
+
const normalizedStyle = typeof asciiStyleProp === "string" ? asciiStyleProp.toLowerCase() ?? EFECTO_ASCII_COMPONENT_DEFAULTS.asciiStyle : EFECTO_ASCII_COMPONENT_DEFAULTS.asciiStyle;
|
|
1642
|
+
const asciiStyle = STYLE_MAP[normalizedStyle] ?? STYLE_MAP.standard;
|
|
1643
|
+
const resolvedPostProcessing = useMemo3(
|
|
1644
|
+
() => normalizePostProcessing(postProcessing),
|
|
1645
|
+
[postProcessing]
|
|
1646
|
+
);
|
|
1647
|
+
const resolvedMediaAdjustments = useMemo3(
|
|
1648
|
+
() => resolveEfectoMediaAdjustments(mediaAdjustments),
|
|
1649
|
+
[mediaAdjustments]
|
|
1650
|
+
);
|
|
1651
|
+
const initialEffectPropsRef = useRef6(null);
|
|
1652
|
+
if (!initialEffectPropsRef.current) {
|
|
1653
|
+
initialEffectPropsRef.current = {
|
|
1654
|
+
cellSize,
|
|
1655
|
+
invert,
|
|
1656
|
+
colorMode,
|
|
1657
|
+
asciiStyle,
|
|
1658
|
+
resolution: resolutionRef.current.clone(),
|
|
1659
|
+
mousePos: (mousePosition ?? DEFAULT_MOUSE_POSITION).clone(),
|
|
1660
|
+
...resolvedPostProcessing
|
|
1661
|
+
};
|
|
1662
|
+
}
|
|
1663
|
+
const updateTextureUVTransform = useCallback5(() => {
|
|
1664
|
+
const texture = loadedTextureRef.current;
|
|
1665
|
+
if (!texture || !texture.image) {
|
|
1666
|
+
return;
|
|
1667
|
+
}
|
|
1668
|
+
const { width: planeWidth, height: planeHeight } = meshDisplaySizeRef.current;
|
|
1669
|
+
if (planeWidth <= 0 || planeHeight <= 0) {
|
|
1670
|
+
return;
|
|
1671
|
+
}
|
|
1672
|
+
const image = texture.image;
|
|
1673
|
+
if (!image.width || !image.height) {
|
|
1674
|
+
return;
|
|
1675
|
+
}
|
|
1676
|
+
const imageAspect = image.width / image.height;
|
|
1677
|
+
const planeAspect = planeWidth / planeHeight;
|
|
1678
|
+
let scaleX = 1;
|
|
1679
|
+
let scaleY = 1;
|
|
1680
|
+
if (imageAspect > planeAspect) {
|
|
1681
|
+
scaleX = imageAspect / planeAspect;
|
|
1682
|
+
} else {
|
|
1683
|
+
scaleY = planeAspect / imageAspect;
|
|
1684
|
+
}
|
|
1685
|
+
const uvScaleX = 1 / scaleX;
|
|
1686
|
+
const uvScaleY = 1 / scaleY;
|
|
1687
|
+
const offsetX = (1 - uvScaleX) * 0.5;
|
|
1688
|
+
const offsetY = (1 - uvScaleY) * 0.5;
|
|
1689
|
+
mediaUniformsRef.current.uvScale.value.set(uvScaleX, uvScaleY);
|
|
1690
|
+
mediaUniformsRef.current.uvOffset.value.set(offsetX, offsetY);
|
|
1691
|
+
const assets = assetsRef.current;
|
|
1692
|
+
if (assets) {
|
|
1693
|
+
assets.material.uniforms.uvScale.value.set(
|
|
1694
|
+
uvScaleX,
|
|
1695
|
+
uvScaleY
|
|
1696
|
+
);
|
|
1697
|
+
assets.material.uniforms.uvOffset.value.set(
|
|
1698
|
+
offsetX,
|
|
1699
|
+
offsetY
|
|
1700
|
+
);
|
|
1701
|
+
}
|
|
1702
|
+
}, []);
|
|
1703
|
+
const updateMeshScale = useCallback5(() => {
|
|
1704
|
+
const assets = assetsRef.current;
|
|
1705
|
+
if (!assets) return;
|
|
1706
|
+
const { width: width2, height: height2 } = viewportSizeRef.current;
|
|
1707
|
+
const camera = cameraRef.current;
|
|
1708
|
+
let viewWidth = width2;
|
|
1709
|
+
let viewHeight = height2;
|
|
1710
|
+
if (camera instanceof THREE6.PerspectiveCamera) {
|
|
1711
|
+
const distance = Math.abs(camera.position.z - assets.mesh.position.z);
|
|
1712
|
+
const verticalFov = THREE6.MathUtils.degToRad(camera.fov);
|
|
1713
|
+
viewHeight = 2 * Math.tan(verticalFov / 2) * distance;
|
|
1714
|
+
viewWidth = viewHeight * camera.aspect;
|
|
1715
|
+
}
|
|
1716
|
+
const texture = loadedTextureRef.current;
|
|
1717
|
+
if (!texture || !texture.image) {
|
|
1718
|
+
assets.mesh.scale.set(viewWidth, viewHeight, 1);
|
|
1719
|
+
meshDisplaySizeRef.current = { width: viewWidth, height: viewHeight };
|
|
1720
|
+
return;
|
|
1721
|
+
}
|
|
1722
|
+
const image = texture.image;
|
|
1723
|
+
const imageAspect = image.width && image.height ? image.width / Math.max(1, image.height) : 1;
|
|
1724
|
+
const viewportAspect = viewWidth / Math.max(1, viewHeight);
|
|
1725
|
+
let meshWidth = viewWidth;
|
|
1726
|
+
let meshHeight = viewHeight;
|
|
1727
|
+
if (imageAspect > viewportAspect) {
|
|
1728
|
+
meshHeight = viewHeight;
|
|
1729
|
+
meshWidth = viewHeight * imageAspect;
|
|
1730
|
+
} else {
|
|
1731
|
+
meshWidth = viewWidth;
|
|
1732
|
+
meshHeight = viewWidth / Math.max(1e-4, imageAspect);
|
|
1733
|
+
}
|
|
1734
|
+
assets.mesh.scale.set(meshWidth, meshHeight, 1);
|
|
1735
|
+
meshDisplaySizeRef.current = { width: meshWidth, height: meshHeight };
|
|
1736
|
+
updateTextureUVTransform();
|
|
1737
|
+
}, [updateTextureUVTransform]);
|
|
1738
|
+
const updatePointerBounds = useCallback5(
|
|
1739
|
+
(container = containerRef.current) => {
|
|
1740
|
+
if (!container) return;
|
|
1741
|
+
const bounds = container.getBoundingClientRect();
|
|
1742
|
+
pointerBoundsRef.current = {
|
|
1743
|
+
left: bounds.left,
|
|
1744
|
+
top: bounds.top,
|
|
1745
|
+
width: bounds.width || 1,
|
|
1746
|
+
height: bounds.height || 1
|
|
1747
|
+
};
|
|
1748
|
+
},
|
|
1749
|
+
[]
|
|
1750
|
+
);
|
|
1751
|
+
const resetParallax = useCallback5(() => {
|
|
1752
|
+
parallaxStateRef.current.targetX = 0;
|
|
1753
|
+
parallaxStateRef.current.targetY = 0;
|
|
1754
|
+
parallaxStateRef.current.rotationX = 0;
|
|
1755
|
+
parallaxStateRef.current.rotationY = 0;
|
|
1756
|
+
const mesh = assetsRef.current?.mesh;
|
|
1757
|
+
if (mesh) {
|
|
1758
|
+
mesh.rotation.x = 0;
|
|
1759
|
+
mesh.rotation.y = 0;
|
|
1760
|
+
}
|
|
1761
|
+
}, []);
|
|
1762
|
+
const handleCreate = useCallback5(
|
|
1763
|
+
({ scene, camera, renderer, size }) => {
|
|
1764
|
+
renderer.outputColorSpace = THREE6.SRGBColorSpace;
|
|
1765
|
+
renderer.toneMapping = THREE6.NoToneMapping;
|
|
1766
|
+
if (!manualResolutionRef.current) {
|
|
1767
|
+
resolutionRef.current.set(size.width, size.height);
|
|
1768
|
+
}
|
|
1769
|
+
viewportSizeRef.current = { width: size.width, height: size.height };
|
|
1770
|
+
const geometry = new THREE6.PlaneGeometry(1, 1);
|
|
1771
|
+
const material = new THREE6.ShaderMaterial({
|
|
1772
|
+
vertexShader: vertex_default5,
|
|
1773
|
+
fragmentShader: fragment_default6,
|
|
1774
|
+
uniforms: mediaUniformsRef.current,
|
|
1775
|
+
transparent: true,
|
|
1776
|
+
depthTest: false
|
|
1777
|
+
});
|
|
1778
|
+
material.toneMapped = false;
|
|
1779
|
+
const mesh = new THREE6.Mesh(geometry, material);
|
|
1780
|
+
scene.add(mesh);
|
|
1781
|
+
if (loadedTextureRef.current) {
|
|
1782
|
+
mediaUniformsRef.current.map.value = loadedTextureRef.current;
|
|
1783
|
+
material.uniforms.map.value = loadedTextureRef.current;
|
|
1784
|
+
}
|
|
1785
|
+
assetsRef.current = { mesh, geometry, material };
|
|
1786
|
+
cameraRef.current = camera;
|
|
1787
|
+
updateMeshScale();
|
|
1788
|
+
const composer = new EffectComposer(renderer);
|
|
1789
|
+
const renderPass = new RenderPass(scene, camera);
|
|
1790
|
+
const effect = new AsciiEffectImpl({
|
|
1791
|
+
...initialEffectPropsRef.current,
|
|
1792
|
+
resolution: resolutionRef.current.clone()
|
|
1793
|
+
});
|
|
1794
|
+
const effectPass = new EffectPass(camera, effect);
|
|
1795
|
+
effectPass.renderToScreen = true;
|
|
1796
|
+
composer.addPass(renderPass);
|
|
1797
|
+
composer.addPass(effectPass);
|
|
1798
|
+
composer.setSize(size.width, size.height);
|
|
1799
|
+
composerRef.current = composer;
|
|
1800
|
+
effectRef.current = effect;
|
|
1801
|
+
return () => {
|
|
1802
|
+
composer.dispose();
|
|
1803
|
+
if (assetsRef.current) {
|
|
1804
|
+
scene.remove(assetsRef.current.mesh);
|
|
1805
|
+
assetsRef.current.geometry.dispose();
|
|
1806
|
+
assetsRef.current.material.dispose();
|
|
1807
|
+
assetsRef.current = null;
|
|
1808
|
+
}
|
|
1809
|
+
cameraRef.current = null;
|
|
1810
|
+
loadedTextureRef.current?.dispose();
|
|
1811
|
+
loadedTextureRef.current = null;
|
|
1812
|
+
composerRef.current = null;
|
|
1813
|
+
effectRef.current = null;
|
|
1814
|
+
};
|
|
1815
|
+
},
|
|
1816
|
+
[updateMeshScale]
|
|
1817
|
+
);
|
|
1818
|
+
const handleRender = useCallback5(
|
|
1819
|
+
(_context, delta, _elapsed) => {
|
|
1820
|
+
const assets = assetsRef.current;
|
|
1821
|
+
if (assets) {
|
|
1822
|
+
const enabled = mouseParallax && parallaxIntensityRef.current > 0 && assets.mesh;
|
|
1823
|
+
if (enabled) {
|
|
1824
|
+
parallaxStateRef.current.rotationX += (parallaxStateRef.current.targetX - parallaxStateRef.current.rotationX) * PARALLAX_LERP;
|
|
1825
|
+
parallaxStateRef.current.rotationY += (parallaxStateRef.current.targetY - parallaxStateRef.current.rotationY) * PARALLAX_LERP;
|
|
1826
|
+
assets.mesh.rotation.x = parallaxStateRef.current.rotationX;
|
|
1827
|
+
assets.mesh.rotation.y = parallaxStateRef.current.rotationY;
|
|
1828
|
+
} else if (Math.abs(assets.mesh.rotation.x) > 1e-3 || Math.abs(assets.mesh.rotation.y) > 1e-3) {
|
|
1829
|
+
assets.mesh.rotation.x *= 0.9;
|
|
1830
|
+
assets.mesh.rotation.y *= 0.9;
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
composerRef.current?.render(delta);
|
|
1834
|
+
},
|
|
1835
|
+
[mouseParallax]
|
|
1836
|
+
);
|
|
1837
|
+
const handleResize = useCallback5(
|
|
1838
|
+
(_context, size) => {
|
|
1839
|
+
const composer = composerRef.current;
|
|
1840
|
+
composer?.setSize(size.width, size.height);
|
|
1841
|
+
viewportSizeRef.current = { width: size.width, height: size.height };
|
|
1842
|
+
updateMeshScale();
|
|
1843
|
+
updatePointerBounds(containerRef.current);
|
|
1844
|
+
if (manualResolutionRef.current) {
|
|
1845
|
+
resolutionRef.current.copy(manualResolutionRef.current);
|
|
1846
|
+
} else {
|
|
1847
|
+
resolutionRef.current.set(size.width, size.height);
|
|
1848
|
+
}
|
|
1849
|
+
effectRef.current?.updateUniforms({
|
|
1850
|
+
resolution: resolutionRef.current
|
|
1851
|
+
});
|
|
1852
|
+
if (!usesExternalMouseRef.current) {
|
|
1853
|
+
autoMouseRef.current.set(size.width / 2, size.height / 2);
|
|
1854
|
+
effectRef.current?.updateUniforms({ mousePos: autoMouseRef.current });
|
|
1855
|
+
}
|
|
1856
|
+
},
|
|
1857
|
+
[updateMeshScale, updatePointerBounds]
|
|
1858
|
+
);
|
|
1859
|
+
const { containerRef, contextRef } = useScene({
|
|
1860
|
+
camera: {
|
|
1861
|
+
type: "perspective",
|
|
1862
|
+
near: 0.1,
|
|
1863
|
+
far: 100,
|
|
1864
|
+
position: [0, 0, 10],
|
|
1865
|
+
fov: 50
|
|
1866
|
+
},
|
|
1867
|
+
onCreate: handleCreate,
|
|
1868
|
+
onRender: handleRender,
|
|
1869
|
+
onResize: handleResize,
|
|
1870
|
+
manualRender: true
|
|
1871
|
+
});
|
|
1872
|
+
useEffect6(() => {
|
|
1873
|
+
if (!mouseParallax) {
|
|
1874
|
+
resetParallax();
|
|
1875
|
+
}
|
|
1876
|
+
}, [mouseParallax, resetParallax]);
|
|
1877
|
+
useEffect6(() => {
|
|
1878
|
+
if (!imageUrl) return;
|
|
1879
|
+
let disposed = false;
|
|
1880
|
+
const loader = new THREE6.TextureLoader();
|
|
1881
|
+
loader.load(
|
|
1882
|
+
imageUrl,
|
|
1883
|
+
(texture) => {
|
|
1884
|
+
if (disposed) {
|
|
1885
|
+
texture.dispose();
|
|
1886
|
+
return;
|
|
1887
|
+
}
|
|
1888
|
+
texture.colorSpace = THREE6.SRGBColorSpace;
|
|
1889
|
+
texture.wrapS = THREE6.ClampToEdgeWrapping;
|
|
1890
|
+
texture.wrapT = THREE6.ClampToEdgeWrapping;
|
|
1891
|
+
texture.minFilter = THREE6.LinearFilter;
|
|
1892
|
+
texture.magFilter = THREE6.LinearFilter;
|
|
1893
|
+
loadedTextureRef.current?.dispose();
|
|
1894
|
+
loadedTextureRef.current = texture;
|
|
1895
|
+
mediaUniformsRef.current.map.value = texture;
|
|
1896
|
+
const assets = assetsRef.current;
|
|
1897
|
+
if (assets) {
|
|
1898
|
+
assets.material.uniforms.map.value = texture;
|
|
1899
|
+
}
|
|
1900
|
+
updateMeshScale();
|
|
1901
|
+
updateTextureUVTransform();
|
|
1902
|
+
},
|
|
1903
|
+
void 0,
|
|
1904
|
+
() => {
|
|
1905
|
+
if (disposed) return;
|
|
1906
|
+
loadedTextureRef.current?.dispose();
|
|
1907
|
+
loadedTextureRef.current = null;
|
|
1908
|
+
}
|
|
1909
|
+
);
|
|
1910
|
+
return () => {
|
|
1911
|
+
disposed = true;
|
|
1912
|
+
};
|
|
1913
|
+
}, [imageUrl, updateMeshScale, updateTextureUVTransform]);
|
|
1914
|
+
useEffect6(() => {
|
|
1915
|
+
const effect = effectRef.current;
|
|
1916
|
+
if (!effect) return;
|
|
1917
|
+
effect.updateUniforms({
|
|
1918
|
+
cellSize,
|
|
1919
|
+
invert,
|
|
1920
|
+
colorMode,
|
|
1921
|
+
asciiStyle
|
|
1922
|
+
});
|
|
1923
|
+
}, [asciiStyle, cellSize, colorMode, invert]);
|
|
1924
|
+
useEffect6(() => {
|
|
1925
|
+
if (!effectRef.current) return;
|
|
1926
|
+
effectRef.current.updateUniforms(resolvedPostProcessing);
|
|
1927
|
+
}, [resolvedPostProcessing]);
|
|
1928
|
+
useEffect6(() => {
|
|
1929
|
+
mediaUniformsRef.current.brightness.value = resolvedMediaAdjustments.brightness;
|
|
1930
|
+
mediaUniformsRef.current.contrast.value = resolvedMediaAdjustments.contrast;
|
|
1931
|
+
mediaUniformsRef.current.saturation.value = resolvedMediaAdjustments.saturation;
|
|
1932
|
+
const material = assetsRef.current?.material;
|
|
1933
|
+
if (material) {
|
|
1934
|
+
material.uniforms.brightness.value = resolvedMediaAdjustments.brightness;
|
|
1935
|
+
material.uniforms.contrast.value = resolvedMediaAdjustments.contrast;
|
|
1936
|
+
material.uniforms.saturation.value = resolvedMediaAdjustments.saturation;
|
|
1937
|
+
}
|
|
1938
|
+
}, [resolvedMediaAdjustments]);
|
|
1939
|
+
useEffect6(() => {
|
|
1940
|
+
if (!mousePosition || !effectRef.current) return;
|
|
1941
|
+
effectRef.current.updateUniforms({ mousePos: mousePosition });
|
|
1942
|
+
}, [mousePosition]);
|
|
1943
|
+
useEffect6(() => {
|
|
1944
|
+
if (!resolution || !effectRef.current) return;
|
|
1945
|
+
resolutionRef.current.copy(resolution);
|
|
1946
|
+
manualResolutionRef.current = resolution.clone();
|
|
1947
|
+
effectRef.current.updateUniforms({ resolution });
|
|
1948
|
+
}, [resolution]);
|
|
1949
|
+
useEffect6(() => {
|
|
1950
|
+
if (mousePosition) return;
|
|
1951
|
+
const container = containerRef.current;
|
|
1952
|
+
if (!container) return;
|
|
1953
|
+
updatePointerBounds(container);
|
|
1954
|
+
const updateFromEvent = (event) => {
|
|
1955
|
+
const bounds = pointerBoundsRef.current;
|
|
1956
|
+
autoMouseRef.current.set(
|
|
1957
|
+
event.clientX - bounds.left,
|
|
1958
|
+
bounds.height - (event.clientY - bounds.top)
|
|
1959
|
+
);
|
|
1960
|
+
effectRef.current?.updateUniforms({ mousePos: autoMouseRef.current });
|
|
1961
|
+
if (mouseParallax && bounds.width > 0 && bounds.height > 0) {
|
|
1962
|
+
const normalizedX = ((event.clientX - bounds.left) / bounds.width - 0.5) * 2;
|
|
1963
|
+
const normalizedY = ((event.clientY - bounds.top) / bounds.height - 0.5) * 2;
|
|
1964
|
+
const intensity = parallaxIntensityRef.current;
|
|
1965
|
+
parallaxStateRef.current.targetY = 0.3 * normalizedX * intensity;
|
|
1966
|
+
parallaxStateRef.current.targetX = -0.2 * normalizedY * intensity;
|
|
1967
|
+
}
|
|
1968
|
+
};
|
|
1969
|
+
const handlePointerEnter = () => {
|
|
1970
|
+
updatePointerBounds();
|
|
1971
|
+
};
|
|
1972
|
+
const resetToCenter = () => {
|
|
1973
|
+
const size = contextRef.current?.size ?? {
|
|
1974
|
+
width: container.clientWidth || 1,
|
|
1975
|
+
height: container.clientHeight || 1
|
|
1976
|
+
};
|
|
1977
|
+
autoMouseRef.current.set(size.width / 2, size.height / 2);
|
|
1978
|
+
effectRef.current?.updateUniforms({ mousePos: autoMouseRef.current });
|
|
1979
|
+
if (mouseParallax) {
|
|
1980
|
+
resetParallax();
|
|
1981
|
+
}
|
|
1982
|
+
};
|
|
1983
|
+
resetToCenter();
|
|
1984
|
+
container.addEventListener("pointermove", updateFromEvent);
|
|
1985
|
+
container.addEventListener("pointerenter", handlePointerEnter);
|
|
1986
|
+
container.addEventListener("pointerleave", resetToCenter);
|
|
1987
|
+
return () => {
|
|
1988
|
+
container.removeEventListener("pointermove", updateFromEvent);
|
|
1989
|
+
container.removeEventListener("pointerenter", handlePointerEnter);
|
|
1990
|
+
container.removeEventListener("pointerleave", resetToCenter);
|
|
1991
|
+
};
|
|
1992
|
+
}, [
|
|
1993
|
+
containerRef,
|
|
1994
|
+
contextRef,
|
|
1995
|
+
mouseParallax,
|
|
1996
|
+
mousePosition,
|
|
1997
|
+
resetParallax,
|
|
1998
|
+
updatePointerBounds
|
|
1999
|
+
]);
|
|
2000
|
+
useEffect6(() => {
|
|
2001
|
+
parallaxIntensityRef.current = THREE6.MathUtils.clamp(
|
|
2002
|
+
parallaxIntensity ?? 0,
|
|
2003
|
+
0,
|
|
2004
|
+
1
|
|
2005
|
+
);
|
|
2006
|
+
}, [parallaxIntensity]);
|
|
2007
|
+
return /* @__PURE__ */ jsx5(
|
|
2008
|
+
"div",
|
|
2009
|
+
{
|
|
2010
|
+
ref: containerRef,
|
|
2011
|
+
className,
|
|
2012
|
+
style: {
|
|
2013
|
+
width: width ?? "100%",
|
|
2014
|
+
height: height ?? "100%",
|
|
2015
|
+
...style
|
|
2016
|
+
},
|
|
2017
|
+
...divProps
|
|
2018
|
+
}
|
|
2019
|
+
);
|
|
2020
|
+
}
|
|
2021
|
+
|
|
2022
|
+
// src/components/EfectoAsciiWrapper.tsx
|
|
2023
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
2024
|
+
function EfectoAsciiWrapper({
|
|
2025
|
+
settings,
|
|
2026
|
+
imageUrl,
|
|
2027
|
+
mediaAdjustments,
|
|
2028
|
+
mouseParallax,
|
|
2029
|
+
parallaxIntensity,
|
|
2030
|
+
...passThrough
|
|
2031
|
+
}) {
|
|
2032
|
+
return /* @__PURE__ */ jsx6(
|
|
2033
|
+
AsciiEffect,
|
|
2034
|
+
{
|
|
2035
|
+
asciiStyle: settings.asciiStyle,
|
|
2036
|
+
cellSize: settings.cellSize,
|
|
2037
|
+
invert: settings.invert,
|
|
2038
|
+
colorMode: settings.colorMode,
|
|
2039
|
+
postProcessing: settings.postProcessing,
|
|
2040
|
+
imageUrl,
|
|
2041
|
+
mediaAdjustments,
|
|
2042
|
+
mouseParallax,
|
|
2043
|
+
parallaxIntensity,
|
|
2044
|
+
...passThrough
|
|
2045
|
+
}
|
|
2046
|
+
);
|
|
2047
|
+
}
|
|
2048
|
+
|
|
2049
|
+
// src/components/Efecto.tsx
|
|
2050
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
2051
|
+
var ASCII_BASE_DEFAULTS = {
|
|
2052
|
+
cellSize: EFECTO_ASCII_COMPONENT_DEFAULTS.cellSize,
|
|
2053
|
+
invert: EFECTO_ASCII_COMPONENT_DEFAULTS.invert,
|
|
2054
|
+
colorMode: EFECTO_ASCII_COMPONENT_DEFAULTS.colorMode,
|
|
2055
|
+
asciiStyle: EFECTO_ASCII_COMPONENT_DEFAULTS.asciiStyle
|
|
2056
|
+
};
|
|
2057
|
+
function Efecto({
|
|
2058
|
+
postProcessing,
|
|
2059
|
+
src,
|
|
2060
|
+
mouseParallax = false,
|
|
2061
|
+
parallaxIntensity = 0.5,
|
|
2062
|
+
mediaAdjustments,
|
|
2063
|
+
cellSize,
|
|
2064
|
+
invert,
|
|
2065
|
+
colorMode,
|
|
2066
|
+
style,
|
|
2067
|
+
asciiStyle,
|
|
2068
|
+
...wrapperProps
|
|
2069
|
+
}) {
|
|
2070
|
+
const resolvedStyle = style ?? asciiStyle ?? ASCII_BASE_DEFAULTS.asciiStyle;
|
|
2071
|
+
const baseAsciiProps = {
|
|
2072
|
+
cellSize: cellSize ?? ASCII_BASE_DEFAULTS.cellSize,
|
|
2073
|
+
invert: invert ?? ASCII_BASE_DEFAULTS.invert,
|
|
2074
|
+
colorMode: colorMode ?? ASCII_BASE_DEFAULTS.colorMode,
|
|
2075
|
+
asciiStyle: resolvedStyle
|
|
2076
|
+
};
|
|
2077
|
+
const asciiSettings = {
|
|
2078
|
+
...baseAsciiProps,
|
|
2079
|
+
postProcessing
|
|
2080
|
+
};
|
|
2081
|
+
return /* @__PURE__ */ jsx7(
|
|
2082
|
+
EfectoAsciiWrapper,
|
|
2083
|
+
{
|
|
2084
|
+
settings: asciiSettings,
|
|
2085
|
+
imageUrl: src,
|
|
2086
|
+
mediaAdjustments,
|
|
2087
|
+
mouseParallax,
|
|
2088
|
+
parallaxIntensity,
|
|
2089
|
+
...wrapperProps
|
|
2090
|
+
}
|
|
2091
|
+
);
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
// src/components/Snow.tsx
|
|
2095
|
+
import { useCallback as useCallback6, useEffect as useEffect7, useRef as useRef7 } from "react";
|
|
2096
|
+
import * as THREE7 from "three";
|
|
2097
|
+
|
|
2098
|
+
// src/shaders/snow/fragment.glsl
|
|
2099
|
+
var fragment_default7 = "precision mediump float;\n\nuniform vec3 uColor;\n\nvarying float vAlpha;\n\nvoid main() {\n vec2 uv = gl_PointCoord - 0.5;\n float dist = length(uv);\n float mask = smoothstep(0.5, 0.0, dist);\n if (mask <= 0.01) {\n discard;\n }\n\n float centerGlow = smoothstep(0.22, 0.0, dist);\n vec3 color = mix(uColor * 1.2, uColor, centerGlow);\n\n gl_FragColor = vec4(color, mask * vAlpha);\n}\n";
|
|
2100
|
+
|
|
2101
|
+
// src/shaders/snow/vertex.glsl
|
|
2102
|
+
var vertex_default6 = "uniform float uTime;\nuniform float uFallSpeed;\nuniform float uWindStrength;\nuniform float uTurbulence;\nuniform float uSize;\nuniform float uTwinkleStrength;\nuniform vec3 uArea;\n\nattribute float aSpeed;\nattribute float aSize;\nattribute float aSeed;\n\nvarying float vAlpha;\n\nfloat wrap(float value, float size) {\n return mod(value + size * 0.5, size) - size * 0.5;\n}\n\nvoid main() {\n float height = uArea.y;\n float width = uArea.x;\n float depth = uArea.z;\n\n float fall = uFallSpeed * (0.3 + aSpeed);\n float droppedY = position.y - uTime * fall;\n float wrappedY = wrap(droppedY, height);\n\n float sway =\n sin((wrappedY + aSeed) * 0.45 + uTime * 0.8) * uTurbulence +\n cos(uTime * 0.35 + aSeed) * 0.15;\n float wind = uWindStrength * (0.4 + aSpeed);\n float displacedX = wrap(position.x + sway + wind, width);\n\n float driftZ =\n sin(uTime * 0.25 + aSeed * 1.7) * 0.5 +\n cos((wrappedY + aSeed) * 0.2) * 0.4;\n float displacedZ = wrap(position.z + driftZ, depth);\n\n vec4 modelPosition =\n modelMatrix * vec4(displacedX, wrappedY, displacedZ, 1.0);\n vec4 viewPosition = viewMatrix * modelPosition;\n\n float baseSize = mix(0.45, 1.0, aSize) * uSize;\n float twinkle =\n 1.0 + sin(uTime * (0.6 + aSpeed) + aSeed) * uTwinkleStrength;\n float perspective = clamp(15.0 / max(1.0, -viewPosition.z), 0.5, 3.0);\n gl_PointSize = baseSize * twinkle * perspective;\n gl_Position = projectionMatrix * viewPosition;\n\n vAlpha = mix(0.35, 1.0, aSize);\n}\n";
|
|
2103
|
+
|
|
2104
|
+
// src/components/Snow.tsx
|
|
2105
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
2106
|
+
var AREA_BOUNDS = {
|
|
2107
|
+
width: 36,
|
|
2108
|
+
height: 44,
|
|
2109
|
+
depth: 26
|
|
2110
|
+
};
|
|
2111
|
+
function createSnowGeometry(count) {
|
|
2112
|
+
const geometry = new THREE7.BufferGeometry();
|
|
2113
|
+
const positions = new Float32Array(count * 3);
|
|
2114
|
+
const speeds = new Float32Array(count);
|
|
2115
|
+
const sizes = new Float32Array(count);
|
|
2116
|
+
const seeds = new Float32Array(count);
|
|
2117
|
+
for (let i = 0; i < count; i += 1) {
|
|
2118
|
+
const x = (Math.random() - 0.5) * AREA_BOUNDS.width;
|
|
2119
|
+
const y = (Math.random() - 0.5) * AREA_BOUNDS.height;
|
|
2120
|
+
const z = (Math.random() - 0.5) * AREA_BOUNDS.depth;
|
|
2121
|
+
positions[i * 3] = x;
|
|
2122
|
+
positions[i * 3 + 1] = y;
|
|
2123
|
+
positions[i * 3 + 2] = z;
|
|
2124
|
+
speeds[i] = Math.random();
|
|
2125
|
+
sizes[i] = Math.random();
|
|
2126
|
+
seeds[i] = Math.random() * 100;
|
|
2127
|
+
}
|
|
2128
|
+
geometry.setAttribute("position", new THREE7.BufferAttribute(positions, 3));
|
|
2129
|
+
geometry.setAttribute("aSpeed", new THREE7.BufferAttribute(speeds, 1));
|
|
2130
|
+
geometry.setAttribute("aSize", new THREE7.BufferAttribute(sizes, 1));
|
|
2131
|
+
geometry.setAttribute("aSeed", new THREE7.BufferAttribute(seeds, 1));
|
|
2132
|
+
geometry.computeBoundingSphere();
|
|
2133
|
+
return geometry;
|
|
2134
|
+
}
|
|
2135
|
+
function buildUniforms2({
|
|
2136
|
+
color,
|
|
2137
|
+
fallSpeed,
|
|
2138
|
+
windStrength,
|
|
2139
|
+
turbulence,
|
|
2140
|
+
flakeSize,
|
|
2141
|
+
twinkleStrength
|
|
2142
|
+
}) {
|
|
2143
|
+
return {
|
|
2144
|
+
uTime: { value: 0 },
|
|
2145
|
+
uFallSpeed: { value: fallSpeed },
|
|
2146
|
+
uWindStrength: { value: windStrength },
|
|
2147
|
+
uTurbulence: { value: turbulence },
|
|
2148
|
+
uSize: { value: flakeSize },
|
|
2149
|
+
uTwinkleStrength: { value: twinkleStrength },
|
|
2150
|
+
uColor: { value: new THREE7.Color(color) },
|
|
2151
|
+
uArea: {
|
|
2152
|
+
value: new THREE7.Vector3(
|
|
2153
|
+
AREA_BOUNDS.width,
|
|
2154
|
+
AREA_BOUNDS.height,
|
|
2155
|
+
AREA_BOUNDS.depth
|
|
2156
|
+
)
|
|
2157
|
+
}
|
|
2158
|
+
};
|
|
2159
|
+
}
|
|
2160
|
+
function Snow({
|
|
2161
|
+
className,
|
|
2162
|
+
style,
|
|
2163
|
+
width,
|
|
2164
|
+
height,
|
|
2165
|
+
color,
|
|
2166
|
+
fallSpeed,
|
|
2167
|
+
windStrength,
|
|
2168
|
+
turbulence,
|
|
2169
|
+
flakeSize,
|
|
2170
|
+
twinkleStrength,
|
|
2171
|
+
flakeCount,
|
|
2172
|
+
mouseWindInteraction = false,
|
|
2173
|
+
...divProps
|
|
2174
|
+
}) {
|
|
2175
|
+
const snowRef = useRef7(null);
|
|
2176
|
+
const uniformsRef = useRef7({
|
|
2177
|
+
color,
|
|
2178
|
+
fallSpeed,
|
|
2179
|
+
windStrength,
|
|
2180
|
+
turbulence,
|
|
2181
|
+
flakeSize,
|
|
2182
|
+
twinkleStrength,
|
|
2183
|
+
flakeCount
|
|
2184
|
+
});
|
|
2185
|
+
uniformsRef.current = {
|
|
2186
|
+
color,
|
|
2187
|
+
fallSpeed,
|
|
2188
|
+
windStrength,
|
|
2189
|
+
turbulence,
|
|
2190
|
+
flakeSize,
|
|
2191
|
+
twinkleStrength,
|
|
2192
|
+
flakeCount
|
|
2193
|
+
};
|
|
2194
|
+
const pointerWindOffsetRef = useRef7(0);
|
|
2195
|
+
const pointerWindTargetRef = useRef7(0);
|
|
2196
|
+
const pointerStateRef = useRef7({
|
|
2197
|
+
lastX: 0,
|
|
2198
|
+
lastTime: 0,
|
|
2199
|
+
timeoutId: null
|
|
2200
|
+
});
|
|
2201
|
+
const pointerActiveRef = useRef7(false);
|
|
2202
|
+
const baseWindRef = useRef7(windStrength);
|
|
2203
|
+
useEffect7(() => {
|
|
2204
|
+
baseWindRef.current = windStrength;
|
|
2205
|
+
}, [windStrength]);
|
|
2206
|
+
const handleCreate = useCallback6(({ scene }) => {
|
|
2207
|
+
const uniforms = buildUniforms2(uniformsRef.current);
|
|
2208
|
+
const geometry = createSnowGeometry(
|
|
2209
|
+
Math.max(1, Math.floor(uniformsRef.current.flakeCount))
|
|
2210
|
+
);
|
|
2211
|
+
const material = new THREE7.ShaderMaterial({
|
|
2212
|
+
fragmentShader: fragment_default7,
|
|
2213
|
+
vertexShader: vertex_default6,
|
|
2214
|
+
uniforms,
|
|
2215
|
+
transparent: true,
|
|
2216
|
+
depthWrite: false,
|
|
2217
|
+
blending: THREE7.AdditiveBlending
|
|
2218
|
+
});
|
|
2219
|
+
const points = new THREE7.Points(geometry, material);
|
|
2220
|
+
points.frustumCulled = false;
|
|
2221
|
+
scene.add(points);
|
|
2222
|
+
snowRef.current = { points, geometry, material, uniforms };
|
|
2223
|
+
return () => {
|
|
2224
|
+
scene.remove(points);
|
|
2225
|
+
geometry.dispose();
|
|
2226
|
+
material.dispose();
|
|
2227
|
+
snowRef.current = null;
|
|
2228
|
+
};
|
|
2229
|
+
}, []);
|
|
2230
|
+
const handleRender = useCallback6(
|
|
2231
|
+
(_context, delta, elapsedTime) => {
|
|
2232
|
+
const assets = snowRef.current;
|
|
2233
|
+
if (!assets) return;
|
|
2234
|
+
assets.uniforms.uTime.value = elapsedTime;
|
|
2235
|
+
const currentOffset = pointerWindOffsetRef.current;
|
|
2236
|
+
const targetOffset = pointerWindTargetRef.current;
|
|
2237
|
+
const nextOffset = THREE7.MathUtils.damp(
|
|
2238
|
+
currentOffset,
|
|
2239
|
+
targetOffset,
|
|
2240
|
+
3.5,
|
|
2241
|
+
delta
|
|
2242
|
+
);
|
|
2243
|
+
if (Math.abs(nextOffset - currentOffset) > 5e-5) {
|
|
2244
|
+
pointerWindOffsetRef.current = nextOffset;
|
|
2245
|
+
assets.uniforms.uWindStrength.value = baseWindRef.current + nextOffset;
|
|
2246
|
+
}
|
|
2247
|
+
},
|
|
2248
|
+
[]
|
|
2249
|
+
);
|
|
2250
|
+
const { containerRef } = useScene({
|
|
2251
|
+
camera: {
|
|
2252
|
+
position: [0, 0, 18]
|
|
2253
|
+
},
|
|
2254
|
+
onCreate: handleCreate,
|
|
2255
|
+
onRender: handleRender
|
|
2256
|
+
});
|
|
2257
|
+
useEffect7(() => {
|
|
2258
|
+
const assets = snowRef.current;
|
|
2259
|
+
if (!assets) return;
|
|
2260
|
+
assets.uniforms.uColor.value.set(color);
|
|
2261
|
+
}, [color]);
|
|
2262
|
+
useEffect7(() => {
|
|
2263
|
+
const assets = snowRef.current;
|
|
2264
|
+
if (!assets) return;
|
|
2265
|
+
assets.uniforms.uFallSpeed.value = fallSpeed;
|
|
2266
|
+
}, [fallSpeed]);
|
|
2267
|
+
useEffect7(() => {
|
|
2268
|
+
const assets = snowRef.current;
|
|
2269
|
+
if (!assets) return;
|
|
2270
|
+
assets.uniforms.uWindStrength.value = windStrength + pointerWindOffsetRef.current;
|
|
2271
|
+
}, [windStrength]);
|
|
2272
|
+
useEffect7(() => {
|
|
2273
|
+
const assets = snowRef.current;
|
|
2274
|
+
if (!assets) return;
|
|
2275
|
+
assets.uniforms.uTurbulence.value = turbulence;
|
|
2276
|
+
}, [turbulence]);
|
|
2277
|
+
useEffect7(() => {
|
|
2278
|
+
const assets = snowRef.current;
|
|
2279
|
+
if (!assets) return;
|
|
2280
|
+
assets.uniforms.uSize.value = flakeSize;
|
|
2281
|
+
}, [flakeSize]);
|
|
2282
|
+
useEffect7(() => {
|
|
2283
|
+
const assets = snowRef.current;
|
|
2284
|
+
if (!assets) return;
|
|
2285
|
+
assets.uniforms.uTwinkleStrength.value = twinkleStrength;
|
|
2286
|
+
}, [twinkleStrength]);
|
|
2287
|
+
useEffect7(() => {
|
|
2288
|
+
const assets = snowRef.current;
|
|
2289
|
+
if (!assets) return;
|
|
2290
|
+
const geometry = createSnowGeometry(Math.max(1, Math.floor(flakeCount)));
|
|
2291
|
+
assets.points.geometry.dispose();
|
|
2292
|
+
assets.points.geometry = geometry;
|
|
2293
|
+
assets.geometry = geometry;
|
|
2294
|
+
}, [flakeCount]);
|
|
2295
|
+
useEffect7(() => {
|
|
2296
|
+
const pointerState = pointerStateRef.current;
|
|
2297
|
+
const clearTimeoutIfNeeded = () => {
|
|
2298
|
+
if (pointerState.timeoutId !== null) {
|
|
2299
|
+
window.clearTimeout(pointerState.timeoutId);
|
|
2300
|
+
pointerState.timeoutId = null;
|
|
2301
|
+
}
|
|
2302
|
+
};
|
|
2303
|
+
if (!mouseWindInteraction) {
|
|
2304
|
+
clearTimeoutIfNeeded();
|
|
2305
|
+
pointerWindOffsetRef.current = 0;
|
|
2306
|
+
pointerWindTargetRef.current = 0;
|
|
2307
|
+
pointerState.lastTime = 0;
|
|
2308
|
+
pointerActiveRef.current = false;
|
|
2309
|
+
const assets = snowRef.current;
|
|
2310
|
+
if (assets) {
|
|
2311
|
+
assets.uniforms.uWindStrength.value = windStrength;
|
|
2312
|
+
}
|
|
2313
|
+
return;
|
|
2314
|
+
}
|
|
2315
|
+
const container = containerRef.current;
|
|
2316
|
+
if (!container) return;
|
|
2317
|
+
const scheduleReset = () => {
|
|
2318
|
+
clearTimeoutIfNeeded();
|
|
2319
|
+
pointerState.timeoutId = window.setTimeout(() => {
|
|
2320
|
+
pointerWindTargetRef.current = 0;
|
|
2321
|
+
pointerState.timeoutId = null;
|
|
2322
|
+
}, 220);
|
|
2323
|
+
};
|
|
2324
|
+
const handlePointerMove = (event) => {
|
|
2325
|
+
const isMouse = event.pointerType === "mouse";
|
|
2326
|
+
if (!isMouse && !pointerActiveRef.current) return;
|
|
2327
|
+
const now = performance.now();
|
|
2328
|
+
if (pointerState.lastTime === 0) {
|
|
2329
|
+
pointerState.lastX = event.clientX;
|
|
2330
|
+
pointerState.lastTime = now;
|
|
2331
|
+
return;
|
|
2332
|
+
}
|
|
2333
|
+
const dx = event.clientX - pointerState.lastX;
|
|
2334
|
+
const dt = Math.max(1, now - pointerState.lastTime);
|
|
2335
|
+
const velocity = dx / dt;
|
|
2336
|
+
const offset = THREE7.MathUtils.clamp(velocity * 0.9, -1.6, 1.6);
|
|
2337
|
+
pointerWindTargetRef.current = offset;
|
|
2338
|
+
pointerState.lastX = event.clientX;
|
|
2339
|
+
pointerState.lastTime = now;
|
|
2340
|
+
scheduleReset();
|
|
2341
|
+
};
|
|
2342
|
+
const handlePointerDown = (event) => {
|
|
2343
|
+
pointerActiveRef.current = true;
|
|
2344
|
+
pointerState.lastX = event.clientX;
|
|
2345
|
+
pointerState.lastTime = performance.now();
|
|
2346
|
+
scheduleReset();
|
|
2347
|
+
};
|
|
2348
|
+
const handlePointerUp = () => {
|
|
2349
|
+
pointerActiveRef.current = false;
|
|
2350
|
+
pointerState.lastTime = 0;
|
|
2351
|
+
pointerWindTargetRef.current = 0;
|
|
2352
|
+
scheduleReset();
|
|
2353
|
+
};
|
|
2354
|
+
const handlePointerLeave = () => {
|
|
2355
|
+
pointerActiveRef.current = false;
|
|
2356
|
+
pointerState.lastTime = 0;
|
|
2357
|
+
pointerWindTargetRef.current = 0;
|
|
2358
|
+
clearTimeoutIfNeeded();
|
|
2359
|
+
};
|
|
2360
|
+
container.addEventListener("pointermove", handlePointerMove);
|
|
2361
|
+
container.addEventListener("pointerdown", handlePointerDown);
|
|
2362
|
+
container.addEventListener("pointerup", handlePointerUp);
|
|
2363
|
+
container.addEventListener("pointercancel", handlePointerUp);
|
|
2364
|
+
container.addEventListener("pointerout", handlePointerLeave);
|
|
2365
|
+
container.addEventListener("pointerleave", handlePointerLeave);
|
|
2366
|
+
return () => {
|
|
2367
|
+
container.removeEventListener("pointermove", handlePointerMove);
|
|
2368
|
+
container.removeEventListener("pointerdown", handlePointerDown);
|
|
2369
|
+
container.removeEventListener("pointerup", handlePointerUp);
|
|
2370
|
+
container.removeEventListener("pointercancel", handlePointerUp);
|
|
2371
|
+
container.removeEventListener("pointerout", handlePointerLeave);
|
|
2372
|
+
container.removeEventListener("pointerleave", handlePointerLeave);
|
|
2373
|
+
pointerState.lastTime = 0;
|
|
2374
|
+
pointerWindOffsetRef.current = 0;
|
|
2375
|
+
pointerWindTargetRef.current = 0;
|
|
2376
|
+
pointerActiveRef.current = false;
|
|
2377
|
+
clearTimeoutIfNeeded();
|
|
2378
|
+
const assets = snowRef.current;
|
|
2379
|
+
if (assets) {
|
|
2380
|
+
assets.uniforms.uWindStrength.value = windStrength;
|
|
2381
|
+
}
|
|
2382
|
+
};
|
|
2383
|
+
}, [containerRef, mouseWindInteraction, windStrength]);
|
|
2384
|
+
return /* @__PURE__ */ jsx8(
|
|
2385
|
+
"div",
|
|
2386
|
+
{
|
|
2387
|
+
ref: containerRef,
|
|
2388
|
+
className,
|
|
2389
|
+
style: {
|
|
2390
|
+
width: width ?? "100%",
|
|
2391
|
+
height: height ?? "100%",
|
|
2392
|
+
...style
|
|
2393
|
+
},
|
|
2394
|
+
...divProps
|
|
2395
|
+
}
|
|
2396
|
+
);
|
|
2397
|
+
}
|
|
2398
|
+
|
|
2399
|
+
// src/components/AnimatedDrawingSVG.tsx
|
|
2400
|
+
import clsx from "clsx";
|
|
2401
|
+
import { useEffect as useEffect8, useLayoutEffect, useRef as useRef8 } from "react";
|
|
2402
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
2403
|
+
var PATH_SELECTOR = "path, line, polyline, polygon, circle, ellipse";
|
|
2404
|
+
function AnimatedDrawingSVG({
|
|
2405
|
+
svgMarkup,
|
|
2406
|
+
animated = true,
|
|
2407
|
+
size,
|
|
2408
|
+
onAnimated,
|
|
2409
|
+
delay,
|
|
2410
|
+
className,
|
|
2411
|
+
style,
|
|
2412
|
+
...divProps
|
|
2413
|
+
}) {
|
|
2414
|
+
const containerRef = useRef8(null);
|
|
2415
|
+
const animationsRef = useRef8([]);
|
|
2416
|
+
const parserRef = useRef8(null);
|
|
2417
|
+
const onAnimatedRef = useRef8(onAnimated);
|
|
2418
|
+
const animationRunIdRef = useRef8(0);
|
|
2419
|
+
const onAnimationCompleteRef = useRef8(false);
|
|
2420
|
+
const timeoutRef = useRef8([]);
|
|
2421
|
+
const monitorRafRef = useRef8(null);
|
|
2422
|
+
const sanitizedMarkup = (svgMarkup ?? "").toString().trim();
|
|
2423
|
+
const normalizedDelay = typeof delay === "number" && delay > 0 ? delay : 0;
|
|
2424
|
+
useEffect8(() => {
|
|
2425
|
+
onAnimatedRef.current = onAnimated;
|
|
2426
|
+
}, [onAnimated]);
|
|
2427
|
+
useEffect8(() => {
|
|
2428
|
+
return () => {
|
|
2429
|
+
animationsRef.current.forEach((animation) => animation.cancel());
|
|
2430
|
+
animationsRef.current = [];
|
|
2431
|
+
timeoutRef.current.forEach((id) => window.clearTimeout(id));
|
|
2432
|
+
timeoutRef.current = [];
|
|
2433
|
+
if (monitorRafRef.current !== null) {
|
|
2434
|
+
cancelAnimationFrame(monitorRafRef.current);
|
|
2435
|
+
monitorRafRef.current = null;
|
|
2436
|
+
}
|
|
2437
|
+
};
|
|
2438
|
+
}, []);
|
|
2439
|
+
useLayoutEffect(() => {
|
|
2440
|
+
const container = containerRef.current;
|
|
2441
|
+
if (!container) return;
|
|
2442
|
+
let rafId = null;
|
|
2443
|
+
let delayId = null;
|
|
2444
|
+
let started = false;
|
|
2445
|
+
if (normalizedDelay > 0) {
|
|
2446
|
+
container.style.visibility = "hidden";
|
|
2447
|
+
} else {
|
|
2448
|
+
container.style.removeProperty("visibility");
|
|
2449
|
+
}
|
|
2450
|
+
animationRunIdRef.current += 1;
|
|
2451
|
+
const currentRunId = animationRunIdRef.current;
|
|
2452
|
+
onAnimationCompleteRef.current = false;
|
|
2453
|
+
timeoutRef.current.forEach((id) => window.clearTimeout(id));
|
|
2454
|
+
timeoutRef.current = [];
|
|
2455
|
+
const markComplete = () => {
|
|
2456
|
+
if (animationRunIdRef.current === currentRunId && !onAnimationCompleteRef.current) {
|
|
2457
|
+
onAnimationCompleteRef.current = true;
|
|
2458
|
+
onAnimatedRef.current?.();
|
|
2459
|
+
}
|
|
2460
|
+
};
|
|
2461
|
+
animationsRef.current.forEach((animation) => animation.cancel());
|
|
2462
|
+
animationsRef.current = [];
|
|
2463
|
+
if (monitorRafRef.current !== null) {
|
|
2464
|
+
cancelAnimationFrame(monitorRafRef.current);
|
|
2465
|
+
monitorRafRef.current = null;
|
|
2466
|
+
}
|
|
2467
|
+
if (!sanitizedMarkup) {
|
|
2468
|
+
container.replaceChildren();
|
|
2469
|
+
markComplete();
|
|
2470
|
+
return;
|
|
2471
|
+
}
|
|
2472
|
+
const parser = parserRef.current ?? new DOMParser();
|
|
2473
|
+
parserRef.current = parser;
|
|
2474
|
+
let parsed;
|
|
2475
|
+
try {
|
|
2476
|
+
parsed = parser.parseFromString(sanitizedMarkup, "image/svg+xml");
|
|
2477
|
+
} catch {
|
|
2478
|
+
return;
|
|
2479
|
+
}
|
|
2480
|
+
if (parsed.querySelector("parsererror")) {
|
|
2481
|
+
return;
|
|
2482
|
+
}
|
|
2483
|
+
const parsedSvg = parsed.querySelector("svg");
|
|
2484
|
+
if (!parsedSvg) {
|
|
2485
|
+
container.replaceChildren();
|
|
2486
|
+
onAnimatedRef.current?.();
|
|
2487
|
+
return;
|
|
2488
|
+
}
|
|
2489
|
+
const svgElement = document.importNode(parsedSvg, true);
|
|
2490
|
+
svgElement.setAttribute("preserveAspectRatio", "xMidYMid meet");
|
|
2491
|
+
if (size !== void 0) {
|
|
2492
|
+
svgElement.removeAttribute("width");
|
|
2493
|
+
svgElement.removeAttribute("height");
|
|
2494
|
+
const sizeValue = typeof size === "number" ? `${Math.max(0, size)}px` : `${size}`;
|
|
2495
|
+
svgElement.style.width = sizeValue;
|
|
2496
|
+
svgElement.style.height = "auto";
|
|
2497
|
+
} else {
|
|
2498
|
+
svgElement.style.width = "100%";
|
|
2499
|
+
svgElement.style.height = "100%";
|
|
2500
|
+
svgElement.style.maxWidth = "100%";
|
|
2501
|
+
svgElement.style.maxHeight = "100%";
|
|
2502
|
+
}
|
|
2503
|
+
svgElement.style.display = "block";
|
|
2504
|
+
container.replaceChildren(svgElement);
|
|
2505
|
+
const runAnimations = () => {
|
|
2506
|
+
const drawTargets = Array.from(
|
|
2507
|
+
svgElement.querySelectorAll(PATH_SELECTOR)
|
|
2508
|
+
);
|
|
2509
|
+
const scheduleFallback = (delay2) => {
|
|
2510
|
+
const fallbackId = window.setTimeout(markComplete, delay2);
|
|
2511
|
+
timeoutRef.current.push(fallbackId);
|
|
2512
|
+
};
|
|
2513
|
+
if (!drawTargets.length) {
|
|
2514
|
+
if (!animated) {
|
|
2515
|
+
markComplete();
|
|
2516
|
+
} else {
|
|
2517
|
+
Promise.resolve().then(() => {
|
|
2518
|
+
markComplete();
|
|
2519
|
+
});
|
|
2520
|
+
}
|
|
2521
|
+
return;
|
|
2522
|
+
}
|
|
2523
|
+
let maxDuration = 0;
|
|
2524
|
+
const resolveTimingValue = (value, fallback) => {
|
|
2525
|
+
if (typeof value === "number") {
|
|
2526
|
+
return value;
|
|
2527
|
+
}
|
|
2528
|
+
if (typeof value === "string") {
|
|
2529
|
+
const parsed2 = Number.parseFloat(value);
|
|
2530
|
+
return Number.isFinite(parsed2) ? parsed2 : fallback;
|
|
2531
|
+
}
|
|
2532
|
+
if (typeof value === "object" && value !== null) {
|
|
2533
|
+
const parsed2 = Number.parseFloat(value.toString());
|
|
2534
|
+
return Number.isFinite(parsed2) ? parsed2 : fallback;
|
|
2535
|
+
}
|
|
2536
|
+
return fallback;
|
|
2537
|
+
};
|
|
2538
|
+
drawTargets.forEach((element, index) => {
|
|
2539
|
+
const length = typeof element.getTotalLength === "function" ? element.getTotalLength() : null;
|
|
2540
|
+
if (!length || Number.isNaN(length)) {
|
|
2541
|
+
element.style.removeProperty("stroke-dasharray");
|
|
2542
|
+
element.style.removeProperty("stroke-dashoffset");
|
|
2543
|
+
return;
|
|
2544
|
+
}
|
|
2545
|
+
const dashValue = `${length}`;
|
|
2546
|
+
element.style.strokeDasharray = dashValue;
|
|
2547
|
+
element.style.strokeDashoffset = animated ? dashValue : "0";
|
|
2548
|
+
if (!element.style.strokeLinecap) {
|
|
2549
|
+
element.style.strokeLinecap = "round";
|
|
2550
|
+
}
|
|
2551
|
+
if (!animated) {
|
|
2552
|
+
return;
|
|
2553
|
+
}
|
|
2554
|
+
const animation = element.animate(
|
|
2555
|
+
[{ strokeDashoffset: dashValue }, { strokeDashoffset: "0" }],
|
|
2556
|
+
{
|
|
2557
|
+
duration: Math.min(6500, Math.max(1200, length * 12)),
|
|
2558
|
+
delay: index * 120,
|
|
2559
|
+
easing: "ease-in-out",
|
|
2560
|
+
fill: "forwards"
|
|
2561
|
+
}
|
|
2562
|
+
);
|
|
2563
|
+
const timing = animation.effect?.getTiming();
|
|
2564
|
+
const baseDuration = Math.min(6500, Math.max(1200, length * 12));
|
|
2565
|
+
const total = resolveTimingValue(timing?.delay, index * 120) + resolveTimingValue(timing?.duration, baseDuration);
|
|
2566
|
+
if (total > maxDuration) {
|
|
2567
|
+
maxDuration = total;
|
|
2568
|
+
}
|
|
2569
|
+
animationsRef.current.push(animation);
|
|
2570
|
+
});
|
|
2571
|
+
if (!animated) {
|
|
2572
|
+
markComplete();
|
|
2573
|
+
return;
|
|
2574
|
+
}
|
|
2575
|
+
const startMonitor = () => {
|
|
2576
|
+
const monitor = () => {
|
|
2577
|
+
if (animationRunIdRef.current !== currentRunId) {
|
|
2578
|
+
return;
|
|
2579
|
+
}
|
|
2580
|
+
const allFinished = animationsRef.current.every((animation) => {
|
|
2581
|
+
const state = animation.playState;
|
|
2582
|
+
return state === "finished" || state === "idle";
|
|
2583
|
+
});
|
|
2584
|
+
if (allFinished) {
|
|
2585
|
+
if (monitorRafRef.current !== null) {
|
|
2586
|
+
cancelAnimationFrame(monitorRafRef.current);
|
|
2587
|
+
monitorRafRef.current = null;
|
|
2588
|
+
}
|
|
2589
|
+
markComplete();
|
|
2590
|
+
return;
|
|
2591
|
+
}
|
|
2592
|
+
monitorRafRef.current = requestAnimationFrame(monitor);
|
|
2593
|
+
};
|
|
2594
|
+
if (monitorRafRef.current !== null) {
|
|
2595
|
+
cancelAnimationFrame(monitorRafRef.current);
|
|
2596
|
+
}
|
|
2597
|
+
monitorRafRef.current = requestAnimationFrame(monitor);
|
|
2598
|
+
};
|
|
2599
|
+
startMonitor();
|
|
2600
|
+
if (animated && maxDuration > 0) {
|
|
2601
|
+
scheduleFallback(maxDuration + 50);
|
|
2602
|
+
}
|
|
2603
|
+
};
|
|
2604
|
+
const triggerStart = () => {
|
|
2605
|
+
if (started) return;
|
|
2606
|
+
started = true;
|
|
2607
|
+
container.style.removeProperty("visibility");
|
|
2608
|
+
rafId = requestAnimationFrame(runAnimations);
|
|
2609
|
+
};
|
|
2610
|
+
if (normalizedDelay > 0) {
|
|
2611
|
+
delayId = window.setTimeout(triggerStart, normalizedDelay);
|
|
2612
|
+
} else {
|
|
2613
|
+
triggerStart();
|
|
2614
|
+
}
|
|
2615
|
+
return () => {
|
|
2616
|
+
if (delayId !== null) {
|
|
2617
|
+
window.clearTimeout(delayId);
|
|
2618
|
+
}
|
|
2619
|
+
if (rafId !== null) {
|
|
2620
|
+
cancelAnimationFrame(rafId);
|
|
2621
|
+
}
|
|
2622
|
+
};
|
|
2623
|
+
}, [sanitizedMarkup, animated, size, normalizedDelay]);
|
|
2624
|
+
return /* @__PURE__ */ jsx9(
|
|
2625
|
+
"div",
|
|
2626
|
+
{
|
|
2627
|
+
ref: containerRef,
|
|
2628
|
+
className: clsx(
|
|
2629
|
+
"flex items-center justify-center [&_svg]:block",
|
|
2630
|
+
className
|
|
2631
|
+
),
|
|
2632
|
+
style: {
|
|
2633
|
+
...style
|
|
2634
|
+
},
|
|
2635
|
+
...divProps
|
|
2636
|
+
}
|
|
2637
|
+
);
|
|
2638
|
+
}
|
|
1048
2639
|
export {
|
|
2640
|
+
AnimatedDrawingSVG,
|
|
2641
|
+
EFECTO_ASCII_COMPONENT_DEFAULTS,
|
|
2642
|
+
EFECTO_ASCII_POST_PROCESSING_DEFAULTS,
|
|
2643
|
+
Efecto,
|
|
1049
2644
|
FractalFlower,
|
|
1050
2645
|
MenuGlitch,
|
|
1051
2646
|
OranoParticles,
|
|
1052
|
-
ShaderArt
|
|
2647
|
+
ShaderArt,
|
|
2648
|
+
Snow
|
|
1053
2649
|
};
|