asciify-engine 1.0.13 → 1.0.15

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.cjs CHANGED
@@ -381,7 +381,7 @@ async function gifToAsciiFrames(buffer, options, targetWidth, targetHeight, onPr
381
381
  prevCtx.clearRect(0, 0, logicalW, logicalH);
382
382
  prevCtx.drawImage(compCanvas, 0, 0);
383
383
  }
384
- const frameImageData = new ImageData(patch, dims.width, dims.height);
384
+ const frameImageData = new ImageData(new Uint8ClampedArray(patch.buffer), dims.width, dims.height);
385
385
  const tempCanvas = document.createElement("canvas");
386
386
  tempCanvas.width = dims.width;
387
387
  tempCanvas.height = dims.height;
@@ -832,7 +832,7 @@ async function asciifyVideo(source, canvas, { fontSize = 10, style = "classic",
832
832
  cancelAnimationFrame(animId);
833
833
  };
834
834
  }
835
- var EMBED_CDN_VERSION = "1.0.12";
835
+ var EMBED_CDN_VERSION = "1.0.15";
836
836
  function buildEmbedOpts(options, rows, cols, width, height, fps, animated) {
837
837
  const o = {
838
838
  r: rows,
@@ -999,6 +999,335 @@ function renderWaveBackground(ctx, width, height, time, mousePos = { x: 0.5, y:
999
999
  }
1000
1000
  }
1001
1001
  }
1002
+ function renderRainBackground(ctx, width, height, time, options = {}) {
1003
+ const {
1004
+ fontSize = 13,
1005
+ chars = "0123456789ABCDEF@#$&*+=/<>",
1006
+ accentColor = "#d4ff00",
1007
+ color,
1008
+ speed = 1,
1009
+ density = 0.55,
1010
+ tailLength = 14,
1011
+ lightMode = false
1012
+ } = options;
1013
+ const charW = fontSize * 0.62;
1014
+ const lineH = fontSize * 1.4;
1015
+ const cols = Math.ceil(width / charW);
1016
+ const rows = Math.ceil(height / lineH);
1017
+ ctx.clearRect(0, 0, width, height);
1018
+ ctx.font = `${fontSize}px monospace`;
1019
+ ctx.textBaseline = "top";
1020
+ let br = 255, bg = 255, bb = 255;
1021
+ if (lightMode) {
1022
+ br = 0;
1023
+ bg = 0;
1024
+ bb = 0;
1025
+ }
1026
+ if (color) {
1027
+ const p = _parseColor(color);
1028
+ if (p) {
1029
+ br = p.r;
1030
+ bg = p.g;
1031
+ bb = p.b;
1032
+ }
1033
+ }
1034
+ let acR = 212, acG = 255, acB = 0;
1035
+ const ap = _parseColor(accentColor);
1036
+ if (ap) {
1037
+ acR = ap.r;
1038
+ acG = ap.g;
1039
+ acB = ap.b;
1040
+ }
1041
+ const period = rows + tailLength;
1042
+ for (let c = 0; c < cols; c++) {
1043
+ if (_hash2(c * 17, 3) > density) continue;
1044
+ const colSpeed = (0.5 + _hash2(c * 31, 7) * 1.5) * speed;
1045
+ const phase = _hash2(c * 13, 11) * period;
1046
+ const headRow = Math.floor((time * colSpeed * 7 + phase) % period);
1047
+ const x = c * charW;
1048
+ for (let k = 0; k <= tailLength; k++) {
1049
+ const row = headRow - (tailLength - k);
1050
+ if (row < 0 || row >= rows) continue;
1051
+ const y = row * lineH;
1052
+ const charSeed = _hash2(c * 53 + Math.floor(time * 5 + k), row * 7);
1053
+ const ch = chars[Math.floor(charSeed * chars.length)];
1054
+ const t = k / tailLength;
1055
+ if (k === tailLength) {
1056
+ ctx.fillStyle = `rgba(${acR},${acG},${acB},${lightMode ? 0.7 : 0.85})`;
1057
+ } else {
1058
+ const alpha = lightMode ? t * 0.22 : t * 0.15;
1059
+ ctx.fillStyle = `rgba(${br},${bg},${bb},${alpha})`;
1060
+ }
1061
+ ctx.fillText(ch, x, y);
1062
+ }
1063
+ }
1064
+ }
1065
+ function renderStarsBackground(ctx, width, height, time, mousePos = { x: 0.5, y: 0.5 }, options = {}) {
1066
+ const {
1067
+ fontSize = 14,
1068
+ chars = " . \xB7 * + \xB0 \u2605",
1069
+ accentColor = "#d4ff00",
1070
+ color,
1071
+ speed = 1,
1072
+ count = 180,
1073
+ lightMode = false
1074
+ } = options;
1075
+ ctx.clearRect(0, 0, width, height);
1076
+ ctx.textBaseline = "middle";
1077
+ ctx.textAlign = "center";
1078
+ const cx = width * (0.2 + mousePos.x * 0.6);
1079
+ const cy = height * (0.2 + mousePos.y * 0.6);
1080
+ const maxR = Math.sqrt(width * width + height * height) * 0.65;
1081
+ let br = 255, bg = 255, bb = 255;
1082
+ if (lightMode) {
1083
+ br = 0;
1084
+ bg = 0;
1085
+ bb = 0;
1086
+ }
1087
+ if (color) {
1088
+ const p = _parseColor(color);
1089
+ if (p) {
1090
+ br = p.r;
1091
+ bg = p.g;
1092
+ bb = p.b;
1093
+ }
1094
+ }
1095
+ let acR = 212, acG = 255, acB = 0;
1096
+ const ap = _parseColor(accentColor);
1097
+ if (ap) {
1098
+ acR = ap.r;
1099
+ acG = ap.g;
1100
+ acB = ap.b;
1101
+ }
1102
+ const charArr = chars.replace(/ /g, "").split("");
1103
+ if (charArr.length === 0) return;
1104
+ for (let i = 0; i < count; i++) {
1105
+ const angle = _hash2(i * 17, 3) * Math.PI * 2;
1106
+ const baseSpd = 0.15 + _hash2(i * 31, 7) * 0.85;
1107
+ const phase = _hash2(i * 13, 11);
1108
+ const r = (time * baseSpd * speed * 0.22 + phase) % 1;
1109
+ const x = cx + Math.cos(angle) * r * maxR;
1110
+ const y = cy + Math.sin(angle) * r * maxR;
1111
+ if (x < -20 || x > width + 20 || y < -20 || y > height + 20) continue;
1112
+ const sz = Math.max(6, fontSize * (0.4 + r * 0.9));
1113
+ ctx.font = `${sz}px monospace`;
1114
+ const charIdx = Math.min(charArr.length - 1, Math.floor(r * charArr.length));
1115
+ const ch = charArr[charIdx];
1116
+ const isAccent = r > 0.72;
1117
+ const alpha = lightMode ? r * 0.28 : r * 0.2;
1118
+ ctx.fillStyle = isAccent ? `rgba(${acR},${acG},${acB},${Math.min(lightMode ? 0.45 : 0.32, alpha * 2.2)})` : `rgba(${br},${bg},${bb},${alpha})`;
1119
+ ctx.fillText(ch, x, y);
1120
+ }
1121
+ ctx.textAlign = "left";
1122
+ }
1123
+ function renderPulseBackground(ctx, width, height, time, mousePos = { x: 0.5, y: 0.5 }, options = {}) {
1124
+ const {
1125
+ fontSize = 13,
1126
+ chars = " .:-=+*#%@",
1127
+ accentColor = "#d4ff00",
1128
+ color,
1129
+ rings = 6,
1130
+ speed = 1,
1131
+ sharpness = 4,
1132
+ lightMode = false
1133
+ } = options;
1134
+ const charW = fontSize * 0.62;
1135
+ const lineH = fontSize * 1.4;
1136
+ const cols = Math.ceil(width / charW);
1137
+ const rows = Math.ceil(height / lineH);
1138
+ ctx.clearRect(0, 0, width, height);
1139
+ ctx.font = `${fontSize}px monospace`;
1140
+ ctx.textBaseline = "top";
1141
+ const maxR = Math.sqrt(width * width + height * height) * 0.5;
1142
+ const ox = mousePos.x * width;
1143
+ const oy = mousePos.y * height;
1144
+ let br = 255, bg2 = 255, bb = 255;
1145
+ if (lightMode) {
1146
+ br = 0;
1147
+ bg2 = 0;
1148
+ bb = 0;
1149
+ }
1150
+ if (color) {
1151
+ const p = _parseColor(color);
1152
+ if (p) {
1153
+ br = p.r;
1154
+ bg2 = p.g;
1155
+ bb = p.b;
1156
+ }
1157
+ }
1158
+ let acR = 212, acG = 255, acB = 0;
1159
+ const ap = _parseColor(accentColor);
1160
+ if (ap) {
1161
+ acR = ap.r;
1162
+ acG = ap.g;
1163
+ acB = ap.b;
1164
+ }
1165
+ const t = time * speed;
1166
+ for (let row = 0; row < rows; row++) {
1167
+ for (let col = 0; col < cols; col++) {
1168
+ const px = col * charW + charW * 0.5;
1169
+ const py = row * lineH + lineH * 0.5;
1170
+ const dist = Math.sqrt((px - ox) ** 2 + (py - oy) ** 2);
1171
+ const norm = dist / maxR;
1172
+ const phase = (norm * rings - t * 1.4) % 1;
1173
+ const wave = Math.pow(Math.max(0, Math.cos(phase * Math.PI * 2)), sharpness);
1174
+ if (wave < 0.02) continue;
1175
+ const charIdx = Math.floor(wave * (chars.length - 1));
1176
+ const ch = chars[charIdx];
1177
+ if (ch === " ") continue;
1178
+ const isAccent = wave > 0.75;
1179
+ const alpha = lightMode ? wave * 0.22 : wave * 0.14;
1180
+ ctx.fillStyle = isAccent ? `rgba(${acR},${acG},${acB},${lightMode ? 0.5 : 0.35})` : `rgba(${br},${bg2},${bb},${alpha})`;
1181
+ ctx.fillText(ch, col * charW, row * lineH);
1182
+ }
1183
+ }
1184
+ }
1185
+ function renderNoiseBackground(ctx, width, height, time, mousePos = { x: 0.5, y: 0.5 }, options = {}) {
1186
+ const {
1187
+ fontSize = 14,
1188
+ chars = " .\xB7:;=+*#%@\u2591\u2592\u2593",
1189
+ accentColor = "#d4ff00",
1190
+ color,
1191
+ octaves = 4,
1192
+ speed = 1,
1193
+ scale = 1,
1194
+ accentThreshold = 0.78,
1195
+ mouseWarp = 0.3,
1196
+ lightMode = false
1197
+ } = options;
1198
+ const charW = fontSize * 0.62;
1199
+ const lineH = fontSize * 1.4;
1200
+ const cols = Math.ceil(width / charW);
1201
+ const rows = Math.ceil(height / lineH);
1202
+ ctx.clearRect(0, 0, width, height);
1203
+ ctx.font = `${fontSize}px monospace`;
1204
+ ctx.textBaseline = "top";
1205
+ let br = 255, bgc = 255, bb = 255;
1206
+ if (lightMode) {
1207
+ br = 0;
1208
+ bgc = 0;
1209
+ bb = 0;
1210
+ }
1211
+ if (color) {
1212
+ const p = _parseColor(color);
1213
+ if (p) {
1214
+ br = p.r;
1215
+ bgc = p.g;
1216
+ bb = p.b;
1217
+ }
1218
+ }
1219
+ let acR = 212, acG = 255, acB = 0;
1220
+ const ap = _parseColor(accentColor);
1221
+ if (ap) {
1222
+ acR = ap.r;
1223
+ acG = ap.g;
1224
+ acB = ap.b;
1225
+ }
1226
+ const noiseScale = 0.035 * scale;
1227
+ const t = time * speed;
1228
+ const oct = Math.min(6, Math.max(1, octaves));
1229
+ const fbmN = (x, y) => {
1230
+ let v = 0, amp = 0.5, freq = 1, norm = 0;
1231
+ for (let o = 0; o < oct; o++) {
1232
+ v += _vnoise(x * freq, y * freq) * amp;
1233
+ norm += amp;
1234
+ amp *= 0.5;
1235
+ freq *= 2.1;
1236
+ }
1237
+ return v / norm;
1238
+ };
1239
+ for (let row = 0; row < rows; row++) {
1240
+ for (let col = 0; col < cols; col++) {
1241
+ const nx = col * noiseScale + t * 0.06;
1242
+ const ny = row * noiseScale * 1.3 - t * 0.04;
1243
+ const dx = col / cols - mousePos.x;
1244
+ const dy = row / rows - mousePos.y;
1245
+ const dist = Math.sqrt(dx * dx + dy * dy);
1246
+ const warp = mouseWarp > 0 ? Math.max(0, 1 - dist / mouseWarp) * 0.12 : 0;
1247
+ const wx = nx + warp * Math.sin(t * 1.3 + dy * 8);
1248
+ const wy = ny + warp * Math.cos(t * 0.9 + dx * 8);
1249
+ const raw = fbmN(wx, wy);
1250
+ const norm2 = raw * 0.5 + 0.5;
1251
+ if (norm2 < 0.12) continue;
1252
+ const charIdx = Math.floor(norm2 * (chars.length - 1));
1253
+ const ch = chars[charIdx];
1254
+ if (ch === " ") continue;
1255
+ const isAccent = norm2 > accentThreshold;
1256
+ const alpha = lightMode ? norm2 * 0.2 : norm2 * 0.13;
1257
+ ctx.fillStyle = isAccent ? `rgba(${acR},${acG},${acB},${lightMode ? 0.42 : 0.28})` : `rgba(${br},${bgc},${bb},${alpha})`;
1258
+ ctx.fillText(ch, col * charW, row * lineH);
1259
+ }
1260
+ }
1261
+ }
1262
+ function renderGridBackground(ctx, width, height, time, mousePos = { x: 0.5, y: 0.5 }, options = {}) {
1263
+ const {
1264
+ fontSize = 12,
1265
+ chars = "\xB7-=+|/",
1266
+ accentColor = "#d4ff00",
1267
+ color,
1268
+ bands = 3,
1269
+ speed = 1,
1270
+ bandWidth = 0.12,
1271
+ glitch = true,
1272
+ lightMode = false
1273
+ } = options;
1274
+ const charW = fontSize * 0.62;
1275
+ const lineH = fontSize * 1.4;
1276
+ const cols = Math.ceil(width / charW);
1277
+ const rows = Math.ceil(height / lineH);
1278
+ ctx.clearRect(0, 0, width, height);
1279
+ ctx.font = `${fontSize}px monospace`;
1280
+ ctx.textBaseline = "top";
1281
+ let br = 255, bgv = 255, bb = 255;
1282
+ if (lightMode) {
1283
+ br = 0;
1284
+ bgv = 0;
1285
+ bb = 0;
1286
+ }
1287
+ if (color) {
1288
+ const p = _parseColor(color);
1289
+ if (p) {
1290
+ br = p.r;
1291
+ bgv = p.g;
1292
+ bb = p.b;
1293
+ }
1294
+ }
1295
+ let acR = 212, acG = 255, acB = 0;
1296
+ const ap = _parseColor(accentColor);
1297
+ if (ap) {
1298
+ acR = ap.r;
1299
+ acG = ap.g;
1300
+ acB = ap.b;
1301
+ }
1302
+ const t = time * speed;
1303
+ for (let row = 0; row < rows; row++) {
1304
+ for (let col = 0; col < cols; col++) {
1305
+ const ny = row / rows;
1306
+ const scanPhase = ((ny * bands - t * 0.5) % 1 + 1) % 1;
1307
+ const bandIntensity = Math.max(0, 1 - scanPhase / bandWidth);
1308
+ const gridSeed = _hash2(col * 3, row * 7);
1309
+ const gridBase = (gridSeed * 0.5 + 0.5) * 0.35;
1310
+ let glitchBump = 0;
1311
+ if (glitch) {
1312
+ const dx = col / cols - mousePos.x;
1313
+ const dy = ny - mousePos.y;
1314
+ const d = Math.sqrt(dx * dx + dy * dy);
1315
+ if (d < 0.18) {
1316
+ const g = _hash2(col * 11 + Math.floor(t * 12), row * 5);
1317
+ glitchBump = Math.max(0, 1 - d / 0.18) * (g > 0.5 ? g - 0.3 : 0);
1318
+ }
1319
+ }
1320
+ const intensity = Math.min(1, gridBase + bandIntensity * 0.8 + glitchBump * 0.6);
1321
+ if (intensity < 0.04) continue;
1322
+ const charIdx = Math.floor(intensity * (chars.length - 1));
1323
+ const ch = chars[charIdx];
1324
+ const isAccent = bandIntensity > 0.55;
1325
+ const alpha = lightMode ? intensity * 0.2 : intensity * 0.12;
1326
+ ctx.fillStyle = isAccent ? `rgba(${acR},${acG},${acB},${lightMode ? 0.46 : 0.28})` : `rgba(${br},${bgv},${bb},${alpha})`;
1327
+ ctx.fillText(ch, col * charW, row * lineH);
1328
+ }
1329
+ }
1330
+ }
1002
1331
  function _parseColor(c) {
1003
1332
  const hex = c.match(/^#([0-9a-f]{3,8})$/i)?.[1];
1004
1333
  if (hex) {
@@ -1011,6 +1340,7 @@ function _parseColor(c) {
1011
1340
  }
1012
1341
  function asciiBackground(target, options = {}) {
1013
1342
  const {
1343
+ type = "wave",
1014
1344
  opacity = 0.2,
1015
1345
  className,
1016
1346
  zIndex = 0,
@@ -1050,16 +1380,49 @@ function asciiBackground(target, options = {}) {
1050
1380
  if (colorScheme === "dark") return false;
1051
1381
  return mq.matches;
1052
1382
  };
1053
- let parsedColor = null;
1054
- if (color) parsedColor = _parseColor(color);
1055
- const buildOpts = () => ({
1383
+ const parsedColor = color ? _parseColor(color) : null;
1384
+ const buildWaveOpts = () => ({
1056
1385
  ...renderOpts,
1057
1386
  lightMode: renderOpts.lightMode !== void 0 ? renderOpts.lightMode : isLight(),
1058
1387
  baseColor: parsedColor ? `rgba(${parsedColor.r},${parsedColor.g},${parsedColor.b},{a})` : renderOpts.baseColor
1059
1388
  });
1060
- const optsRef = { current: buildOpts() };
1389
+ const buildRainOpts = () => ({
1390
+ ...renderOpts,
1391
+ lightMode: renderOpts.lightMode !== void 0 ? renderOpts.lightMode : isLight(),
1392
+ color: color ?? renderOpts.color
1393
+ });
1394
+ const buildStarsOpts = () => ({
1395
+ ...renderOpts,
1396
+ lightMode: renderOpts.lightMode !== void 0 ? renderOpts.lightMode : isLight(),
1397
+ color: color ?? renderOpts.color
1398
+ });
1399
+ const buildPulseOpts = () => ({
1400
+ ...renderOpts,
1401
+ lightMode: renderOpts.lightMode !== void 0 ? renderOpts.lightMode : isLight(),
1402
+ color: color ?? renderOpts.color
1403
+ });
1404
+ const buildNoiseOpts = () => ({
1405
+ ...renderOpts,
1406
+ lightMode: renderOpts.lightMode !== void 0 ? renderOpts.lightMode : isLight(),
1407
+ color: color ?? renderOpts.color
1408
+ });
1409
+ const buildGridOpts = () => ({
1410
+ ...renderOpts,
1411
+ lightMode: renderOpts.lightMode !== void 0 ? renderOpts.lightMode : isLight(),
1412
+ color: color ?? renderOpts.color
1413
+ });
1414
+ const optsRef = { current: buildWaveOpts() };
1415
+ const rebuildOpts = () => {
1416
+ if (type === "rain") optsRef.current = buildRainOpts();
1417
+ else if (type === "stars") optsRef.current = buildStarsOpts();
1418
+ else if (type === "pulse") optsRef.current = buildPulseOpts();
1419
+ else if (type === "noise") optsRef.current = buildNoiseOpts();
1420
+ else if (type === "grid") optsRef.current = buildGridOpts();
1421
+ else optsRef.current = buildWaveOpts();
1422
+ };
1423
+ rebuildOpts();
1061
1424
  const onSchemeChange = () => {
1062
- optsRef.current = buildOpts();
1425
+ rebuildOpts();
1063
1426
  };
1064
1427
  if (colorScheme === "auto") mq.addEventListener("change", onSchemeChange);
1065
1428
  const resize = () => {
@@ -1083,7 +1446,19 @@ function asciiBackground(target, options = {}) {
1083
1446
  smoothMouse.x += (mouse.x - smoothMouse.x) * 0.07;
1084
1447
  smoothMouse.y += (mouse.y - smoothMouse.y) * 0.07;
1085
1448
  const r = container.getBoundingClientRect();
1086
- renderWaveBackground(ctx, r.width, r.height, time, smoothMouse, optsRef.current);
1449
+ if (type === "rain") {
1450
+ renderRainBackground(ctx, r.width, r.height, time, optsRef.current);
1451
+ } else if (type === "stars") {
1452
+ renderStarsBackground(ctx, r.width, r.height, time, smoothMouse, optsRef.current);
1453
+ } else if (type === "pulse") {
1454
+ renderPulseBackground(ctx, r.width, r.height, time, smoothMouse, optsRef.current);
1455
+ } else if (type === "noise") {
1456
+ renderNoiseBackground(ctx, r.width, r.height, time, smoothMouse, optsRef.current);
1457
+ } else if (type === "grid") {
1458
+ renderGridBackground(ctx, r.width, r.height, time, smoothMouse, optsRef.current);
1459
+ } else {
1460
+ renderWaveBackground(ctx, r.width, r.height, time, smoothMouse, optsRef.current);
1461
+ }
1087
1462
  time += 0.016;
1088
1463
  raf = requestAnimationFrame(tick);
1089
1464
  };
@@ -1563,6 +1938,11 @@ exports.gifToAsciiFrames = gifToAsciiFrames;
1563
1938
  exports.imageToAsciiFrame = imageToAsciiFrame;
1564
1939
  exports.mountWaveBackground = mountWaveBackground;
1565
1940
  exports.renderFrameToCanvas = renderFrameToCanvas;
1941
+ exports.renderGridBackground = renderGridBackground;
1942
+ exports.renderNoiseBackground = renderNoiseBackground;
1943
+ exports.renderPulseBackground = renderPulseBackground;
1944
+ exports.renderRainBackground = renderRainBackground;
1945
+ exports.renderStarsBackground = renderStarsBackground;
1566
1946
  exports.renderWaveBackground = renderWaveBackground;
1567
1947
  exports.tryCreateWebGLRenderer = tryCreateWebGLRenderer;
1568
1948
  exports.videoToAsciiFrames = videoToAsciiFrames;