asciify-engine 1.0.15 → 1.0.17

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
@@ -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.15";
835
+ var EMBED_CDN_VERSION = "1.0.17";
836
836
  function buildEmbedOpts(options, rows, cols, width, height, fps, animated) {
837
837
  const o = {
838
838
  r: rows,
@@ -1328,6 +1328,305 @@ function renderGridBackground(ctx, width, height, time, mousePos = { x: 0.5, y:
1328
1328
  }
1329
1329
  }
1330
1330
  }
1331
+ function renderAuroraBackground(ctx, width, height, time, mousePos = { x: 0.5, y: 0.5 }, options = {}) {
1332
+ const {
1333
+ fontSize = 14,
1334
+ chars = " \xB7\u2219\u2022:;+=\u2261\u2263#@",
1335
+ color,
1336
+ accentColor = "#d4ff00",
1337
+ speed = 1,
1338
+ layers = 5,
1339
+ softness = 1.2,
1340
+ mouseRipple = 0.2,
1341
+ lightMode = false
1342
+ } = options;
1343
+ const charW = fontSize * 0.62;
1344
+ const lineH = fontSize * 1.4;
1345
+ const cols = Math.ceil(width / charW);
1346
+ const rows = Math.ceil(height / lineH);
1347
+ ctx.clearRect(0, 0, width, height);
1348
+ ctx.font = `${fontSize}px monospace`;
1349
+ ctx.textBaseline = "top";
1350
+ let cr = 255, cg = 255, cb = 255;
1351
+ if (lightMode) {
1352
+ cr = 0;
1353
+ cg = 0;
1354
+ cb = 0;
1355
+ }
1356
+ if (color) {
1357
+ const p = _parseColor(color);
1358
+ if (p) {
1359
+ cr = p.r;
1360
+ cg = p.g;
1361
+ cb = p.b;
1362
+ }
1363
+ }
1364
+ let acR = 212, acG = 255, acB = 0;
1365
+ const ap = _parseColor(accentColor);
1366
+ if (ap) {
1367
+ acR = ap.r;
1368
+ acG = ap.g;
1369
+ acB = ap.b;
1370
+ }
1371
+ const t = time * speed;
1372
+ const layerParams = [];
1373
+ for (let l = 0; l < layers; l++) {
1374
+ const seed = _hash2(l * 17, l * 31 + 7);
1375
+ const seed2 = _hash2(l * 23 + 5, l * 11);
1376
+ layerParams.push({
1377
+ fx: 0.8 + seed * 2.2,
1378
+ // x spatial frequency
1379
+ fy: 1.2 + seed2 * 1.8,
1380
+ // y spatial frequency
1381
+ phase: seed * Math.PI * 4,
1382
+ // phase offset
1383
+ dt: (0.3 + _hash2(l * 7, l * 13 + 3) * 0.5) * (l % 2 === 0 ? 1 : -1),
1384
+ // drift speed & direction
1385
+ amp: 0.55 + _hash2(l * 29, l * 3) * 0.45
1386
+ // amplitude weight
1387
+ });
1388
+ }
1389
+ for (let row = 0; row < rows; row++) {
1390
+ const ny = row / rows;
1391
+ for (let col = 0; col < cols; col++) {
1392
+ const nx = col / cols;
1393
+ const mdx = nx - mousePos.x;
1394
+ const mdy = ny - mousePos.y;
1395
+ const md = Math.sqrt(mdx * mdx + mdy * mdy);
1396
+ const warp = mouseRipple * Math.exp(-md * md / 0.06);
1397
+ const wx = nx + mdx * warp;
1398
+ const wy = ny + mdy * warp;
1399
+ let sum = 0;
1400
+ let totalAmp = 0;
1401
+ for (let l = 0; l < layers; l++) {
1402
+ const { fx, fy, phase, dt, amp } = layerParams[l];
1403
+ const wave = Math.sin(wx * fx * Math.PI * 2 + t * dt + phase) * Math.cos(wy * fy * Math.PI * 2 + t * dt * 0.7 + phase * 1.3);
1404
+ sum += wave * amp;
1405
+ totalAmp += amp;
1406
+ }
1407
+ const rawVal = sum / totalAmp;
1408
+ const curved = 0.5 + 0.5 * Math.tanh(rawVal * softness * 2.2);
1409
+ if (curved < 0.12) continue;
1410
+ const normalized = (curved - 0.12) / 0.88;
1411
+ const charIdx = Math.min(chars.length - 1, Math.floor(normalized * chars.length));
1412
+ const ch = chars[charIdx];
1413
+ const isAccent = curved > 0.82;
1414
+ const alpha = lightMode ? curved * 0.18 : curved * 0.14;
1415
+ ctx.fillStyle = isAccent ? `rgba(${acR},${acG},${acB},${lightMode ? 0.5 : 0.32})` : `rgba(${cr},${cg},${cb},${alpha})`;
1416
+ ctx.fillText(ch, col * charW, row * lineH);
1417
+ }
1418
+ }
1419
+ }
1420
+ function renderSilkBackground(ctx, width, height, time, options = {}) {
1421
+ const {
1422
+ fontSize = 13,
1423
+ color,
1424
+ accentColor = "#d4ff00",
1425
+ speed = 0.4,
1426
+ layers = 4,
1427
+ turbulence = 0.8,
1428
+ lightMode = false
1429
+ } = options;
1430
+ const charW = fontSize * 0.62;
1431
+ const lineH = fontSize * 1.4;
1432
+ const cols = Math.ceil(width / charW);
1433
+ const rows = Math.ceil(height / lineH);
1434
+ ctx.clearRect(0, 0, width, height);
1435
+ ctx.font = `${fontSize}px monospace`;
1436
+ ctx.textBaseline = "top";
1437
+ let cr = 255, cg = 255, cb = 255;
1438
+ if (lightMode) {
1439
+ cr = 0;
1440
+ cg = 0;
1441
+ cb = 0;
1442
+ }
1443
+ if (color) {
1444
+ const p = _parseColor(color);
1445
+ if (p) {
1446
+ cr = p.r;
1447
+ cg = p.g;
1448
+ cb = p.b;
1449
+ }
1450
+ }
1451
+ let acR = 212, acG = 255, acB = 0;
1452
+ const ap = _parseColor(accentColor);
1453
+ if (ap) {
1454
+ acR = ap.r;
1455
+ acG = ap.g;
1456
+ acB = ap.b;
1457
+ }
1458
+ const t = time * speed;
1459
+ const dirChars = ["\u2500", "\u2500", "\u254C", "\xB7", "\u254C", "\u2500", "\u2500", "\u254C", "\xB7"];
1460
+ for (let row = 0; row < rows; row++) {
1461
+ const ny = row / rows;
1462
+ for (let col = 0; col < cols; col++) {
1463
+ const nx = col / cols;
1464
+ let angleSum = 0;
1465
+ let intensitySum = 0;
1466
+ for (let l = 0; l < layers; l++) {
1467
+ const ls = _hash2(l * 13, l * 7 + 3);
1468
+ const ls2 = _hash2(l * 29, l * 11 + 1);
1469
+ const fx = 1.1 + ls * 2.4;
1470
+ const fy = 0.9 + ls2 * 2;
1471
+ const ph = ls * Math.PI * 6;
1472
+ const dr = (0.2 + _hash2(l * 41, l * 17) * 0.5) * (l % 2 === 0 ? 1 : -1.3);
1473
+ const u = Math.sin(nx * fx * Math.PI * 2 + t * dr + ph);
1474
+ const v = Math.cos(ny * fy * Math.PI * 2 + t * dr * 0.6 + ph * 1.7);
1475
+ const cross = Math.sin(nx * fy * Math.PI * turbulence + ny * fx * Math.PI * turbulence + t * dr * 0.4);
1476
+ angleSum += Math.atan2(v + cross * 0.3, u);
1477
+ intensitySum += (u * v + 1) * 0.5;
1478
+ }
1479
+ const angle = angleSum / layers;
1480
+ const intensity = Math.min(1, intensitySum / layers);
1481
+ if (intensity < 0.1) continue;
1482
+ const angleNorm = (angle + Math.PI) / (Math.PI * 2);
1483
+ const charIdx = Math.floor(angleNorm * dirChars.length) % dirChars.length;
1484
+ const ch = dirChars[charIdx];
1485
+ const isAccent = intensity > 0.8;
1486
+ const alpha = lightMode ? intensity * 0.16 : intensity * 0.13;
1487
+ ctx.fillStyle = isAccent ? `rgba(${acR},${acG},${acB},${lightMode ? 0.44 : 0.26})` : `rgba(${cr},${cg},${cb},${alpha})`;
1488
+ ctx.fillText(ch, col * charW, row * lineH);
1489
+ }
1490
+ }
1491
+ }
1492
+ function renderVoidBackground(ctx, width, height, time, mousePos = { x: 0.5, y: 0.5 }, options = {}) {
1493
+ const {
1494
+ fontSize = 13,
1495
+ chars = " \xB7:;=+*#%@",
1496
+ color,
1497
+ accentColor = "#d4ff00",
1498
+ speed = 1,
1499
+ radius = 0.38,
1500
+ swirl = 3,
1501
+ lightMode = false
1502
+ } = options;
1503
+ const charW = fontSize * 0.62;
1504
+ const lineH = fontSize * 1.4;
1505
+ const cols = Math.ceil(width / charW);
1506
+ const rows = Math.ceil(height / lineH);
1507
+ const aspect = width / height;
1508
+ ctx.clearRect(0, 0, width, height);
1509
+ ctx.font = `${fontSize}px monospace`;
1510
+ ctx.textBaseline = "top";
1511
+ let cr = 255, cg = 255, cb = 255;
1512
+ if (lightMode) {
1513
+ cr = 0;
1514
+ cg = 0;
1515
+ cb = 0;
1516
+ }
1517
+ if (color) {
1518
+ const p = _parseColor(color);
1519
+ if (p) {
1520
+ cr = p.r;
1521
+ cg = p.g;
1522
+ cb = p.b;
1523
+ }
1524
+ }
1525
+ let acR = 212, acG = 255, acB = 0;
1526
+ const ap = _parseColor(accentColor);
1527
+ if (ap) {
1528
+ acR = ap.r;
1529
+ acG = ap.g;
1530
+ acB = ap.b;
1531
+ }
1532
+ const t = time * speed;
1533
+ for (let row = 0; row < rows; row++) {
1534
+ const ny = row / rows;
1535
+ for (let col = 0; col < cols; col++) {
1536
+ const nx = col / cols;
1537
+ const dx = (nx - mousePos.x) * aspect;
1538
+ const dy = ny - mousePos.y;
1539
+ const dist = Math.sqrt(dx * dx + dy * dy);
1540
+ const r = dist / radius;
1541
+ if (r > 1) {
1542
+ const outerNoise = _hash2(col * 3, row * 7) * Math.max(0, 1 - (r - 1) * 3);
1543
+ if (outerNoise < 0.62) continue;
1544
+ const alpha2 = outerNoise * (lightMode ? 0.05 : 0.04);
1545
+ const ch2 = chars[1];
1546
+ ctx.fillStyle = `rgba(${cr},${cg},${cb},${alpha2})`;
1547
+ ctx.fillText(ch2, col * charW, row * lineH);
1548
+ continue;
1549
+ }
1550
+ const baseAngle = Math.atan2(dy, dx * aspect);
1551
+ const swirlAmt = (1 - r) * swirl;
1552
+ const angle = baseAngle + swirlAmt + t * 0.4;
1553
+ const pulseRing = Math.max(0, 1 - Math.abs(r - (0.15 + 0.12 * Math.sin(t * 1.1))) / 0.07);
1554
+ const gravity = Math.pow(1 - r, 2.2);
1555
+ const intensity = Math.min(1, gravity + pulseRing * 0.6);
1556
+ if (intensity < 0.06) continue;
1557
+ const angleIdx = Math.floor((angle % (Math.PI * 2) + Math.PI * 2) % (Math.PI * 2) / (Math.PI * 2) * 4);
1558
+ const densityI = Math.floor(intensity * (chars.length - 1));
1559
+ const charIdx = Math.min(chars.length - 1, densityI);
1560
+ const ch = chars[charIdx + (angleIdx > 2 && densityI > 2 ? 0 : 0)];
1561
+ const isAccent = pulseRing > 0.35 || r < 0.08;
1562
+ const alpha = lightMode ? intensity * 0.22 : intensity * 0.18;
1563
+ ctx.fillStyle = isAccent ? `rgba(${acR},${acG},${acB},${lightMode ? 0.55 : 0.38})` : `rgba(${cr},${cg},${cb},${alpha})`;
1564
+ ctx.fillText(ch, col * charW, row * lineH);
1565
+ }
1566
+ }
1567
+ }
1568
+ function renderMorphBackground(ctx, width, height, time, options = {}) {
1569
+ const {
1570
+ fontSize = 14,
1571
+ chars = " \xB7\u2219\u2022:-=+*#",
1572
+ color,
1573
+ accentColor = "#d4ff00",
1574
+ speed = 0.5,
1575
+ harmonics = 3,
1576
+ lightMode = false
1577
+ } = options;
1578
+ const charW = fontSize * 0.62;
1579
+ const lineH = fontSize * 1.4;
1580
+ const cols = Math.ceil(width / charW);
1581
+ const rows = Math.ceil(height / lineH);
1582
+ ctx.clearRect(0, 0, width, height);
1583
+ ctx.font = `${fontSize}px monospace`;
1584
+ ctx.textBaseline = "top";
1585
+ let cr = 255, cg = 255, cb = 255;
1586
+ if (lightMode) {
1587
+ cr = 0;
1588
+ cg = 0;
1589
+ cb = 0;
1590
+ }
1591
+ if (color) {
1592
+ const p = _parseColor(color);
1593
+ if (p) {
1594
+ cr = p.r;
1595
+ cg = p.g;
1596
+ cb = p.b;
1597
+ }
1598
+ }
1599
+ let acR = 212, acG = 255, acB = 0;
1600
+ const ap = _parseColor(accentColor);
1601
+ if (ap) {
1602
+ acR = ap.r;
1603
+ acG = ap.g;
1604
+ acB = ap.b;
1605
+ }
1606
+ const t = time * speed;
1607
+ for (let row = 0; row < rows; row++) {
1608
+ for (let col = 0; col < cols; col++) {
1609
+ let v = 0;
1610
+ for (let h = 0; h < harmonics; h++) {
1611
+ const fBase = _hash2(col * (h + 3) + 7, row * (h + 5) + 11);
1612
+ const fineF = 0.18 + fBase * 1.4;
1613
+ const phase = _hash2(col * (h + 7), row * (h + 9) + 3) * Math.PI * 2;
1614
+ const weight = 1 / (h + 1);
1615
+ v += Math.sin(t * fineF + phase) * weight;
1616
+ }
1617
+ const maxV = Array.from({ length: harmonics }, (_, h) => 1 / (h + 1)).reduce((a, b) => a + b, 0);
1618
+ const norm = (v / maxV + 1) * 0.5;
1619
+ if (norm < 0.28) continue;
1620
+ const remapped = (norm - 0.28) / 0.72;
1621
+ const charIdx = Math.min(chars.length - 1, Math.floor(remapped * chars.length));
1622
+ const ch = chars[charIdx];
1623
+ const isAccent = norm > 0.88;
1624
+ const alpha = lightMode ? remapped * 0.17 : remapped * 0.13;
1625
+ ctx.fillStyle = isAccent ? `rgba(${acR},${acG},${acB},${lightMode ? 0.45 : 0.28})` : `rgba(${cr},${cg},${cb},${alpha})`;
1626
+ ctx.fillText(ch, col * charW, row * lineH);
1627
+ }
1628
+ }
1629
+ }
1331
1630
  function _parseColor(c) {
1332
1631
  const hex = c.match(/^#([0-9a-f]{3,8})$/i)?.[1];
1333
1632
  if (hex) {
@@ -1411,6 +1710,26 @@ function asciiBackground(target, options = {}) {
1411
1710
  lightMode: renderOpts.lightMode !== void 0 ? renderOpts.lightMode : isLight(),
1412
1711
  color: color ?? renderOpts.color
1413
1712
  });
1713
+ const buildAuroraOpts = () => ({
1714
+ ...renderOpts,
1715
+ lightMode: renderOpts.lightMode !== void 0 ? renderOpts.lightMode : isLight(),
1716
+ color: color ?? renderOpts.color
1717
+ });
1718
+ const buildSilkOpts = () => ({
1719
+ ...renderOpts,
1720
+ lightMode: renderOpts.lightMode !== void 0 ? renderOpts.lightMode : isLight(),
1721
+ color: color ?? renderOpts.color
1722
+ });
1723
+ const buildVoidOpts = () => ({
1724
+ ...renderOpts,
1725
+ lightMode: renderOpts.lightMode !== void 0 ? renderOpts.lightMode : isLight(),
1726
+ color: color ?? renderOpts.color
1727
+ });
1728
+ const buildMorphOpts = () => ({
1729
+ ...renderOpts,
1730
+ lightMode: renderOpts.lightMode !== void 0 ? renderOpts.lightMode : isLight(),
1731
+ color: color ?? renderOpts.color
1732
+ });
1414
1733
  const optsRef = { current: buildWaveOpts() };
1415
1734
  const rebuildOpts = () => {
1416
1735
  if (type === "rain") optsRef.current = buildRainOpts();
@@ -1418,6 +1737,10 @@ function asciiBackground(target, options = {}) {
1418
1737
  else if (type === "pulse") optsRef.current = buildPulseOpts();
1419
1738
  else if (type === "noise") optsRef.current = buildNoiseOpts();
1420
1739
  else if (type === "grid") optsRef.current = buildGridOpts();
1740
+ else if (type === "aurora") optsRef.current = buildAuroraOpts();
1741
+ else if (type === "silk") optsRef.current = buildSilkOpts();
1742
+ else if (type === "void") optsRef.current = buildVoidOpts();
1743
+ else if (type === "morph") optsRef.current = buildMorphOpts();
1421
1744
  else optsRef.current = buildWaveOpts();
1422
1745
  };
1423
1746
  rebuildOpts();
@@ -1456,6 +1779,14 @@ function asciiBackground(target, options = {}) {
1456
1779
  renderNoiseBackground(ctx, r.width, r.height, time, smoothMouse, optsRef.current);
1457
1780
  } else if (type === "grid") {
1458
1781
  renderGridBackground(ctx, r.width, r.height, time, smoothMouse, optsRef.current);
1782
+ } else if (type === "aurora") {
1783
+ renderAuroraBackground(ctx, r.width, r.height, time, smoothMouse, optsRef.current);
1784
+ } else if (type === "silk") {
1785
+ renderSilkBackground(ctx, r.width, r.height, time, optsRef.current);
1786
+ } else if (type === "void") {
1787
+ renderVoidBackground(ctx, r.width, r.height, time, smoothMouse, optsRef.current);
1788
+ } else if (type === "morph") {
1789
+ renderMorphBackground(ctx, r.width, r.height, time, optsRef.current);
1459
1790
  } else {
1460
1791
  renderWaveBackground(ctx, r.width, r.height, time, smoothMouse, optsRef.current);
1461
1792
  }
@@ -1937,12 +2268,16 @@ exports.generateEmbedCode = generateEmbedCode;
1937
2268
  exports.gifToAsciiFrames = gifToAsciiFrames;
1938
2269
  exports.imageToAsciiFrame = imageToAsciiFrame;
1939
2270
  exports.mountWaveBackground = mountWaveBackground;
2271
+ exports.renderAuroraBackground = renderAuroraBackground;
1940
2272
  exports.renderFrameToCanvas = renderFrameToCanvas;
1941
2273
  exports.renderGridBackground = renderGridBackground;
2274
+ exports.renderMorphBackground = renderMorphBackground;
1942
2275
  exports.renderNoiseBackground = renderNoiseBackground;
1943
2276
  exports.renderPulseBackground = renderPulseBackground;
1944
2277
  exports.renderRainBackground = renderRainBackground;
2278
+ exports.renderSilkBackground = renderSilkBackground;
1945
2279
  exports.renderStarsBackground = renderStarsBackground;
2280
+ exports.renderVoidBackground = renderVoidBackground;
1946
2281
  exports.renderWaveBackground = renderWaveBackground;
1947
2282
  exports.tryCreateWebGLRenderer = tryCreateWebGLRenderer;
1948
2283
  exports.videoToAsciiFrames = videoToAsciiFrames;