@olwiba/dx 0.0.15 → 0.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/ascii-gif.d.ts +1 -0
- package/dist/ascii-gif.js +80 -5
- package/dist/ascii-gif.js.map +1 -1
- package/dist/cli.js +242 -6
- package/dist/generate-assets.d.ts +12 -0
- package/dist/generate-assets.js +127 -0
- package/dist/generate-assets.js.map +1 -0
- package/package.json +15 -2
package/dist/ascii-gif.d.ts
CHANGED
package/dist/ascii-gif.js
CHANGED
|
@@ -1318,6 +1318,48 @@ async function generateAsciiGif(options) {
|
|
|
1318
1318
|
const layout = composeAsciiText(font, options.text);
|
|
1319
1319
|
const bounds = getLayoutBounds(layout);
|
|
1320
1320
|
const accentColumns = getAsciiAccentColumns(font, options.text, options.accent ?? "");
|
|
1321
|
+
const width = Math.ceil(bounds.cols * ASCII_CHAR_WIDTH * scale) + padding * 2;
|
|
1322
|
+
const height = bounds.rows * ASCII_CHAR_HEIGHT * scale + padding * 2;
|
|
1323
|
+
const frameCount = Math.max(1, Math.round(fps * duration));
|
|
1324
|
+
const delay = Math.max(1, Math.round(100 / fps));
|
|
1325
|
+
const frames = [];
|
|
1326
|
+
if (options.rowColors && options.rowColors.length > 0) {
|
|
1327
|
+
const uniqueRowColors = [...new Set(options.rowColors)];
|
|
1328
|
+
const rowPalette = createRowColorPalette({
|
|
1329
|
+
backgroundColor: options.backgroundColor ?? "#0a0a0a",
|
|
1330
|
+
blendColor: options.blendColor ?? options.backgroundColor ?? "#0a0a0a",
|
|
1331
|
+
rowColors: uniqueRowColors,
|
|
1332
|
+
levels,
|
|
1333
|
+
transparent: options.transparent ?? false
|
|
1334
|
+
});
|
|
1335
|
+
for (let frame = 0; frame < frameCount; frame++) {
|
|
1336
|
+
frames.push(
|
|
1337
|
+
renderIndexedAsciiFrameWithRowColors({
|
|
1338
|
+
layout,
|
|
1339
|
+
phase: frame / frameCount,
|
|
1340
|
+
width,
|
|
1341
|
+
height,
|
|
1342
|
+
scale,
|
|
1343
|
+
levels,
|
|
1344
|
+
bounds,
|
|
1345
|
+
padding,
|
|
1346
|
+
rowColorsInput: options.rowColors,
|
|
1347
|
+
uniqueRowColors
|
|
1348
|
+
})
|
|
1349
|
+
);
|
|
1350
|
+
}
|
|
1351
|
+
const bytes2 = encodeGif({
|
|
1352
|
+
width,
|
|
1353
|
+
height,
|
|
1354
|
+
delay,
|
|
1355
|
+
palette: rowPalette.table,
|
|
1356
|
+
frames,
|
|
1357
|
+
transparent: options.transparent ?? false
|
|
1358
|
+
});
|
|
1359
|
+
mkdirSync(path.dirname(options.outputPath), { recursive: true });
|
|
1360
|
+
writeFileSync(options.outputPath, bytes2);
|
|
1361
|
+
return;
|
|
1362
|
+
}
|
|
1321
1363
|
const palette = createPalette({
|
|
1322
1364
|
backgroundColor: options.backgroundColor ?? "#0a0a0a",
|
|
1323
1365
|
blendColor: options.blendColor ?? options.backgroundColor ?? "#0a0a0a",
|
|
@@ -1326,11 +1368,6 @@ async function generateAsciiGif(options) {
|
|
|
1326
1368
|
levels,
|
|
1327
1369
|
transparent: options.transparent ?? false
|
|
1328
1370
|
});
|
|
1329
|
-
const width = Math.ceil(bounds.cols * ASCII_CHAR_WIDTH * scale) + padding * 2;
|
|
1330
|
-
const height = bounds.rows * ASCII_CHAR_HEIGHT * scale + padding * 2;
|
|
1331
|
-
const frameCount = Math.max(1, Math.round(fps * duration));
|
|
1332
|
-
const delay = Math.max(1, Math.round(100 / fps));
|
|
1333
|
-
const frames = [];
|
|
1334
1371
|
for (let frame = 0; frame < frameCount; frame++) {
|
|
1335
1372
|
frames.push(
|
|
1336
1373
|
renderIndexedAsciiFrame({
|
|
@@ -1379,6 +1416,44 @@ function renderIndexedAsciiFrame(options) {
|
|
|
1379
1416
|
}
|
|
1380
1417
|
return pixels;
|
|
1381
1418
|
}
|
|
1419
|
+
function renderIndexedAsciiFrameWithRowColors(options) {
|
|
1420
|
+
const pixels = new Uint8Array(options.width * options.height);
|
|
1421
|
+
const charWidth = Math.round(ASCII_CHAR_WIDTH * options.scale);
|
|
1422
|
+
const charHeight = Math.round(ASCII_CHAR_HEIGHT * options.scale);
|
|
1423
|
+
for (const cell of options.layout.cells) {
|
|
1424
|
+
const intensity = getAsciiCellIntensity(cell, { phase: options.phase });
|
|
1425
|
+
const level = Math.max(0, Math.min(options.levels - 1, Math.round(intensity * (options.levels - 1))));
|
|
1426
|
+
const rowColor = options.rowColorsInput[cell.row % options.rowColorsInput.length] ?? options.rowColorsInput[0];
|
|
1427
|
+
const colorSetIndex = Math.max(0, options.uniqueRowColors.indexOf(rowColor));
|
|
1428
|
+
const colorIndex = 1 + colorSetIndex * options.levels + level;
|
|
1429
|
+
const x0 = options.padding + Math.round((cell.col - options.bounds.minCol) * ASCII_CHAR_WIDTH * options.scale);
|
|
1430
|
+
const y0 = options.padding + (cell.row - options.bounds.minRow) * charHeight;
|
|
1431
|
+
const x1 = Math.min(options.width, x0 + charWidth);
|
|
1432
|
+
const y1 = Math.min(options.height, y0 + charHeight);
|
|
1433
|
+
for (let y = y0; y < y1; y++) {
|
|
1434
|
+
const row = y * options.width;
|
|
1435
|
+
for (let x = x0; x < x1; x++) {
|
|
1436
|
+
pixels[row + x] = colorIndex;
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
return pixels;
|
|
1441
|
+
}
|
|
1442
|
+
function createRowColorPalette(options) {
|
|
1443
|
+
const bg = parseColor(options.backgroundColor);
|
|
1444
|
+
const blend = parseColor(options.blendColor);
|
|
1445
|
+
const table = [bg.r, bg.g, bg.b];
|
|
1446
|
+
for (const colorHex of options.rowColors) {
|
|
1447
|
+
const color = parseColor(colorHex);
|
|
1448
|
+
for (let level = 0; level < options.levels; level++) {
|
|
1449
|
+
const alpha = level / (options.levels - 1);
|
|
1450
|
+
const mixed = mix(blend, color, alpha);
|
|
1451
|
+
table.push(mixed.r, mixed.g, mixed.b);
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
while (table.length < 256 * 3) table.push(0, 0, 0);
|
|
1455
|
+
return { table: Uint8Array.from(table.slice(0, 256 * 3)) };
|
|
1456
|
+
}
|
|
1382
1457
|
function getLayoutBounds(layout) {
|
|
1383
1458
|
if (layout.cells.length === 0) {
|
|
1384
1459
|
return { minCol: 0, minRow: 0, cols: Math.max(1, layout.cols), rows: Math.max(1, layout.rows) };
|
package/dist/ascii-gif.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ascii/compose.ts","../src/ascii/figlet.ts","../src/ascii/render.ts","../src/ascii/fonts/dosrebel-data.ts","../src/ascii/fonts.ts","../src/ascii-gif.ts"],"names":[],"mappings":"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AA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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","file":"ascii-gif.js","sourcesContent":["import type { FigletFont } from \"./figlet\"\n\nexport interface AsciiCell {\n ch: \"█\" | \"░\"\n col: number\n row: number\n}\n\nexport interface AsciiTextLayout {\n cells: AsciiCell[]\n cols: number\n rows: number\n}\n\nexport function composeAsciiText(font: FigletFont, text: string): AsciiTextLayout {\n const charBlocks: Array<{ lines: string[]; width: number }> = []\n\n for (const ch of text) {\n const code = ch.charCodeAt(0)\n const glyph = font.chars.get(code) ?? font.chars.get(32)\n if (!glyph) continue\n\n const width = Math.max(...glyph.map((line) => line.length))\n charBlocks.push({\n lines: glyph.map((line) => line.padEnd(width)),\n width,\n })\n }\n\n const cols = charBlocks.reduce((sum, block) => sum + block.width, 0)\n const rows = font.height\n const cells: AsciiCell[] = []\n let offsetX = 0\n\n for (const block of charBlocks) {\n for (let row = 0; row < rows; row++) {\n const line = block.lines[row] ?? \"\"\n for (let col = 0; col < line.length; col++) {\n const ch = line[col]\n if (ch === \"█\" || ch === \"░\") {\n cells.push({ ch, col: offsetX + col, row })\n }\n }\n }\n offsetX += block.width\n }\n\n return { cells, cols, rows }\n}\n\nexport function getAsciiAccentColumns(\n font: FigletFont,\n text: string,\n accent: string,\n): Set<number> {\n if (!accent) return new Set<number>()\n\n const columns = new Set<number>()\n const accentRanges: Array<{ start: number; end: number }> = []\n let searchFrom = 0\n while (true) {\n const idx = text.indexOf(accent, searchFrom)\n if (idx === -1) break\n accentRanges.push({ start: idx, end: idx + accent.length })\n searchFrom = idx + 1\n }\n if (accentRanges.length === 0) return columns\n\n let offsetX = 0\n let charIndex = 0\n\n for (const ch of text) {\n const code = ch.charCodeAt(0)\n const glyph = font.chars.get(code) ?? font.chars.get(32)\n if (!glyph) { charIndex++; continue }\n\n const width = Math.max(...glyph.map((line) => line.length))\n if (accentRanges.some((r) => charIndex >= r.start && charIndex < r.end)) {\n for (let col = 0; col < width; col++) columns.add(offsetX + col)\n }\n offsetX += width\n charIndex++\n }\n\n return columns\n}\n","export interface FigletFont {\n height: number\n baseline: number\n hardblank: string\n chars: Map<number, string[]>\n}\n\nexport function parseFigletFont(raw: string): FigletFont {\n const lines = raw.split(\"\\n\")\n\n if (lines[0]?.charCodeAt(0) === 0xfeff) {\n lines[0] = lines[0].slice(1)\n }\n\n const header = lines[0]\n if (!header?.startsWith(\"flf2a\")) {\n throw new Error(\"Invalid FIGlet font: missing flf2a header\")\n }\n\n const hardblank = header[5] ?? \"$\"\n const parts = header.slice(6).trim().split(/\\s+/)\n const height = Number.parseInt(parts[0] ?? \"\", 10)\n const baseline = Number.parseInt(parts[1] ?? \"\", 10)\n const commentLines = Number.parseInt(parts[4] ?? \"\", 10)\n\n if (!Number.isFinite(height) || height <= 0) {\n throw new Error(\"Invalid FIGlet font: missing character height\")\n }\n\n const dataStart = 1 + (Number.isFinite(commentLines) ? commentLines : 0)\n const chars = new Map<number, string[]>()\n let lineIndex = dataStart\n let ascii = 32\n\n while (lineIndex + height <= lines.length && ascii <= 126) {\n const charLines: string[] = []\n for (let row = 0; row < height; row++) {\n const line = (lines[lineIndex + row] ?? \"\")\n .replace(/@+$/, \"\")\n .replaceAll(hardblank, \" \")\n charLines.push(line)\n }\n\n chars.set(ascii, charLines)\n lineIndex += height\n ascii++\n }\n\n return { height, baseline, hardblank, chars }\n}\n","import type { AsciiCell, AsciiTextLayout } from \"./compose\"\n\nexport const ASCII_CHAR_WIDTH = 7.5\nexport const ASCII_CHAR_HEIGHT = 15\n\nexport interface AsciiWave {\n cx: number\n cy: number\n t: number\n}\n\nexport interface AsciiPointer {\n x: number\n y: number\n active: boolean\n}\n\nexport interface AsciiFrameState {\n time?: number\n phase?: number\n pointer?: AsciiPointer\n waves?: AsciiWave[]\n}\n\nexport interface AsciiRenderOptions extends AsciiFrameState {\n accentColumns?: ReadonlySet<number>\n color: string\n accentColor?: string\n charWidth?: number\n charHeight?: number\n}\n\nexport interface AsciiFrameContext {\n clearRect(x: number, y: number, width: number, height: number): void\n fillRect(x: number, y: number, width: number, height: number): void\n globalAlpha: number\n fillStyle: string\n}\n\nexport function getAsciiCanvasSize(\n layout: AsciiTextLayout,\n charWidth = ASCII_CHAR_WIDTH,\n charHeight = ASCII_CHAR_HEIGHT,\n) {\n return {\n width: Math.ceil(layout.cols * charWidth),\n height: layout.rows * charHeight,\n }\n}\n\nexport function getAsciiCellIntensity(cell: AsciiCell, options: AsciiFrameState): number {\n const time = options.time ?? 0\n const loop = options.phase == null ? null : options.phase * Math.PI * 2\n\n if (cell.ch === \"░\") {\n const drift =\n loop == null\n ? Math.sin(time * 0.3 + cell.col * 0.1) * 0.03\n : Math.sin(loop + cell.col * 0.1) * 0.03\n return 0.15 + drift\n }\n\n if (loop != null) {\n return getLoopIntensity(cell, loop)\n }\n\n const noise = getLiveNoise(cell, time)\n\n const seed = cell.col * 7.13 + cell.row * 13.37\n const flickerPhase = Math.sin(seed) * 1000\n const flickerWave = Math.sin(time * 0.8 + flickerPhase)\n const flicker = flickerWave > 0.97 ? 0.15 : 0\n\n let intensity = 0.7 + noise + flicker\n const charWidth = ASCII_CHAR_WIDTH\n const charHeight = ASCII_CHAR_HEIGHT\n\n if (options.pointer?.active) {\n const mdx = cell.col * charWidth + charWidth / 2 - options.pointer.x\n const mdy = cell.row * charHeight + charHeight / 2 - options.pointer.y\n const mDist = Math.sqrt(mdx * mdx + mdy * mdy)\n const radius = 80\n if (mDist < radius) {\n const falloff = 1 - mDist / radius\n const ripple = Math.sin(mDist * 0.08 - time * 4) * 0.12 * falloff * falloff\n intensity = Math.min(1, intensity + falloff * 0.2 + ripple)\n }\n }\n\n const px = cell.col * charWidth + charWidth / 2\n const py = cell.row * charHeight + charHeight / 2\n for (const wave of options.waves ?? []) {\n const wdx = px - wave.cx\n const wdy = py - wave.cy\n const dist = Math.sqrt(wdx * wdx + wdy * wdy)\n const age = time - wave.t\n const waveRadius = age * 200\n const delta = dist - waveRadius\n const fade = Math.exp(-age * 1.5)\n const ring = Math.exp(-delta * delta * 0.002) * fade\n intensity = Math.min(1, intensity + ring * 0.5 * Math.sin(delta * 0.06 + 1.5))\n }\n\n return Math.max(0.5, Math.min(1, intensity))\n}\n\nexport function renderAsciiFrameToContext(\n ctx: AsciiFrameContext,\n layout: AsciiTextLayout,\n options: AsciiRenderOptions,\n) {\n const charWidth = options.charWidth ?? ASCII_CHAR_WIDTH\n const charHeight = options.charHeight ?? ASCII_CHAR_HEIGHT\n const { width, height } = getAsciiCanvasSize(layout, charWidth, charHeight)\n const accentColor = options.accentColor ?? options.color\n\n ctx.clearRect(0, 0, width, height)\n\n for (const cell of layout.cells) {\n const isAccent = options.accentColumns?.has(cell.col) ?? false\n ctx.globalAlpha = getAsciiCellIntensity(cell, options)\n ctx.fillStyle = isAccent ? accentColor : options.color\n ctx.fillRect(cell.col * charWidth, cell.row * charHeight, charWidth, charHeight)\n }\n\n ctx.globalAlpha = 1\n}\n\nfunction getLiveNoise(cell: AsciiCell, time: number): number {\n const nx = cell.col * 0.18 + time * 0.9\n const ny = cell.row * 0.3 + time * 0.55\n return (\n Math.sin(nx) * 0.12 +\n Math.sin(ny * 1.4 + nx * 0.6) * 0.1 +\n Math.sin(nx * 0.4 - ny * 0.8 + time * 1.6) * 0.08 +\n Math.sin((cell.col + cell.row) * 0.15 + time * 0.4) * 0.07\n )\n}\n\nfunction getLoopIntensity(cell: AsciiCell, loop: number): number {\n const flow =\n Math.sin(cell.col * 0.08 + loop) * 0.055 +\n Math.sin(cell.row * 0.22 - loop * 0.75) * 0.04\n const shimmer = (Math.sin(cell.col * 0.16 + cell.row * 0.08 - loop * 2) + 1) / 2\n const highlight = Math.pow(shimmer, 4) * 0.22\n const intensity = 0.68 + flow + highlight\n\n return Math.max(0.55, Math.min(1, intensity))\n}\n","// @generated from dosrebel.flf. Do not edit by hand.\nexport const dosrebelFont: string = \"flf2a$ 11 8 35 -1 15\\nRebel by Valerie Mates (popcorn@cyberspace.org), based on a font by Ron Bliss\\n(who sometimes goes by the name \\\"rebel\\\" because his initials are REB).\\nNOTE: THIS FONT ONLY WORKS IN MS-DOS.\\nMay 27, 1994\\n\\nExplanation of first line:\\nflf2 - \\\"magic number\\\" for file identification\\na - should always be `a', for now\\n$ - the \\\"hardblank\\\" -- prints as a blank, but can't be smushed\\n11 - height of a character\\n8 - height of a character, not including descenders\\n35 - max line length (excluding comment lines) + a fudge factor\\n-1 - default smushmode for this font (like \\\"-m 15\\\" on command line)\\n15 - number of comment lines\\n\\n$$$@\\n$$$@\\n$$$@\\n$$$@\\n$$$@\\n$$$@\\n$$$@\\n$$$@\\n$$$@\\n$$$@\\n$$$@@\\n ███@\\n░███@\\n░███@\\n░███@\\n░███@\\n░░░ @\\n ███@\\n░░░ @\\n @\\n @\\n @@\\n ██ ██@\\n░██░██@\\n░░ ░░ @\\n @\\n @\\n @\\n @\\n @\\n @\\n @\\n @@\\n ███ ███ @\\n ████████████@\\n░░░███░░███░ @\\n ████████████@\\n░░░███░░███░ @\\n ░░░ ░░░ @\\n @\\n @\\n @\\n @\\n @@\\n ███ @\\n ██████ @\\n ███░░░ @\\n ░░█████ @\\n ░░░░███ @\\n ██████ @\\n ░░░███ @\\n ░░░ @\\n @\\n @\\n @@\\n ███ ███@\\n ░░░ ███░ @\\n ███░ @\\n ███░ @\\n ███░ @\\n ███░ @\\n ███░ ███ @\\n░░░ ░░░ @\\n @\\n @\\n @@\\n ██████ @\\n ███░░███ @\\n ░░██████ @\\n ██████ @\\n░███░░███ @\\n░███ ░░███ @\\n░░█████░███@\\n ░░░░░ ░░░ @\\n @\\n @\\n @@\\n ██@\\n ███@\\n░░░ @\\n @\\n @\\n @\\n @\\n @\\n @\\n @\\n @@\\n ███@\\n ███ @\\n ███ @\\n░███ @\\n░███ @\\n░░███ @\\n ░░███@\\n ░░░ @\\n @\\n @\\n @@\\n ███ @\\n░░███ @\\n ░░███@\\n ░███@\\n ░███@\\n ███ @\\n ██░ @\\n░░░ @\\n @\\n @\\n @@\\n ███ @\\n ███ ░███ ███@\\n░░░█████████░ @\\n ░░░█████░ @\\n █████████ @\\n ███░░███░░███@\\n░░░ ░███ ░░░ @\\n ░░░ @\\n @\\n @\\n @@\\n @\\n ███ @\\n ░███ @\\n ███████████@\\n░░░░░███░░░ @\\n ░███ @\\n ░░░ @\\n @\\n @\\n @\\n @@\\n @\\n @\\n @\\n @\\n @\\n @\\n ██@\\n ██ @\\n░░ @\\n @\\n @@\\n @\\n @\\n @\\n ██████████@\\n░░░░░░░░░░ @\\n @\\n @\\n @\\n @\\n @\\n @@\\n @\\n @\\n @\\n @\\n @\\n @\\n ██@\\n░░ @\\n @\\n @\\n @@\\n ███@\\n ███░ @\\n ███░ @\\n ███░ @\\n ███░ @\\n ███░ @\\n ███░ @\\n░░░ @\\n @\\n @\\n @@\\n █████ @\\n ███░░░███ @\\n ███ ░░███@\\n░███ ░███@\\n░███ ░███@\\n░░███ ███ @\\n ░░░█████░ @\\n ░░░░░░ @\\n @\\n @\\n @@\\n ████ @\\n░░███ @\\n ░███ @\\n ░███ @\\n ░███ @\\n ░███ @\\n █████@\\n░░░░░ @\\n @\\n @\\n @@\\n ████████ @\\n ███░░░░███@\\n░░░ ░███@\\n ███████ @\\n ███░░░░ @\\n ███ █@\\n░██████████@\\n░░░░░░░░░░ @\\n @\\n @\\n @@\\n ████████ @\\n ███░░░░███@\\n░░░ ░███@\\n ██████░ @\\n ░░░░░░███@\\n ███ ░███@\\n░░████████ @\\n ░░░░░░░░ @\\n @\\n @\\n @@\\n █████ █████ @\\n░░███ ░░███ @\\n ░███ ░███ █@\\n ░███████████@\\n ░░░░░░░███░█@\\n ░███░ @\\n █████ @\\n ░░░░░ @\\n @\\n @\\n @@\\n ██████████@\\n░███░░░░░░█@\\n░███ ░ @\\n░█████████ @\\n░░░░░░░░███@\\n ███ ░███@\\n░░████████ @\\n ░░░░░░░░ @\\n @\\n @\\n @@\\n ████████ @\\n ███░░░░███@\\n░███ ░░░ @\\n░█████████ @\\n░███░░░░███@\\n░███ ░███@\\n░░████████ @\\n ░░░░░░░░ @\\n @\\n @\\n @@\\n ██████████@\\n░███░░░░███@\\n░░░ ███ @\\n ███ @\\n ███ @\\n ███ @\\n ███ @\\n ░░░ @\\n @\\n @\\n @@\\n ████████ @\\n ███░░░░███ @\\n░███ ░███ @\\n░░████████ @\\n ███░░░░███ @\\n░███ ░███ @\\n░░████████ @\\n ░░░░░░░░ @\\n @\\n @\\n @@\\n ████████ @\\n ███░░░░███@\\n░███ ░███@\\n░░█████████@\\n ░░░░░░░███@\\n ███ ░███@\\n░░████████ @\\n ░░░░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n ██@\\n░░ @\\n @\\n @\\n ██@\\n░░ @\\n @\\n @\\n @@\\n @\\n @\\n @\\n @\\n ██@\\n ░░ @\\n ██@\\n ██ @\\n░░ @\\n @\\n @@\\n ███@\\n ███░ @\\n ███░ @\\n ███░ @\\n░░░███ @\\n ░░░███ @\\n ░░░███@\\n ░░░ @\\n @\\n @\\n @@\\n @\\n @\\n █████████@\\n░░░░░░░░░ @\\n █████████@\\n░░░░░░░░░ @\\n @\\n @\\n @\\n @\\n @@\\n ███ @\\n░░░███ @\\n ░░░███ @\\n ░░░███@\\n ███░ @\\n ███░ @\\n ███░ @\\n░░░ @\\n @\\n @\\n @@\\n ███████ @\\n ███░░░███@\\n░░░ ░███@\\n ███████ @\\n ░███░░░ @\\n ░░░ @\\n ███ @\\n ░░░ @\\n @\\n @\\n @@\\n █████████ @\\n ███░░░░░░ @\\n░███ ██████ @\\n░███░███░███@\\n░███░███░███@\\n░███░░░ ░███@\\n░░█████████ @\\n ░░░░░░░░░ @\\n @\\n @\\n @@\\n █████████ @\\n ███░░░░░███ @\\n ░███ ░███ @\\n ░███████████ @\\n ░███░░░░░███ @\\n ░███ ░███ @\\n █████ █████@\\n░░░░░ ░░░░░ @\\n @\\n @\\n @@\\n ███████████ @\\n░░███░░░░░███@\\n ░███ ░███@\\n ░██████████ @\\n ░███░░░░░███@\\n ░███ ░███@\\n ███████████ @\\n░░░░░░░░░░░ @\\n @\\n @\\n @@\\n █████████ @\\n ███░░░░░███@\\n ███ ░░░ @\\n░███ @\\n░███ @\\n░░███ ███@\\n ░░█████████ @\\n ░░░░░░░░░ @\\n @\\n @\\n @@\\n ██████████ @\\n░░███░░░░███ @\\n ░███ ░░███@\\n ░███ ░███@\\n ░███ ░███@\\n ░███ ███ @\\n ██████████ @\\n░░░░░░░░░░ @\\n @\\n @\\n @@\\n ██████████@\\n░░███░░░░░█@\\n ░███ █ ░ @\\n ░██████ @\\n ░███░░█ @\\n ░███ ░ █@\\n ██████████@\\n░░░░░░░░░░ @\\n @\\n @\\n @@\\n ███████████@\\n░░███░░░░░░█@\\n ░███ █ ░ @\\n ░███████ @\\n ░███░░░█ @\\n ░███ ░ @\\n █████ @\\n░░░░░ @\\n @\\n @\\n @@\\n █████████ @\\n ███░░░░░███@\\n ███ ░░░ @\\n░███ @\\n░███ █████@\\n░░███ ░░███ @\\n ░░█████████ @\\n ░░░░░░░░░ @\\n @\\n @\\n @@\\n █████ █████@\\n░░███ ░░███ @\\n ░███ ░███ @\\n ░███████████ @\\n ░███░░░░░███ @\\n ░███ ░███ @\\n █████ █████@\\n░░░░░ ░░░░░ @\\n @\\n @\\n @@\\n █████@\\n░░███ @\\n ░███ @\\n ░███ @\\n ░███ @\\n ░███ @\\n █████@\\n░░░░░ @\\n @\\n @\\n @@\\n █████@\\n ░░███ @\\n ░███ @\\n ░███ @\\n ░███ @\\n ███ ░███ @\\n░░████████ @\\n ░░░░░░░░ @\\n @\\n @\\n @@\\n █████ ████@\\n░░███ ███░ @\\n ░███ ███ @\\n ░███████ @\\n ░███░░███ @\\n ░███ ░░███ @\\n █████ ░░████@\\n░░░░░ ░░░░ @\\n @\\n @\\n @@\\n █████ @\\n░░███ @\\n ░███ @\\n ░███ @\\n ░███ @\\n ░███ █@\\n ███████████@\\n░░░░░░░░░░░ @\\n @\\n @\\n @@\\n ██████ ██████@\\n░░██████ ██████ @\\n ░███░█████░███ @\\n ░███░░███ ░███ @\\n ░███ ░░░ ░███ @\\n ░███ ░███ @\\n █████ █████@\\n░░░░░ ░░░░░ @\\n @\\n @\\n @@\\n ██████ █████@\\n░░██████ ░░███ @\\n ░███░███ ░███ @\\n ░███░░███░███ @\\n ░███ ░░██████ @\\n ░███ ░░█████ @\\n █████ ░░█████@\\n░░░░░ ░░░░░ @\\n @\\n @\\n @@\\n ███████ @\\n ███░░░░░███ @\\n ███ ░░███@\\n░███ ░███@\\n░███ ░███@\\n░░███ ███ @\\n ░░░███████░ @\\n ░░░░░░░ @\\n @\\n @\\n @@\\n ███████████ @\\n░░███░░░░░███@\\n ░███ ░███@\\n ░██████████ @\\n ░███░░░░░░ @\\n ░███ @\\n █████ @\\n░░░░░ @\\n @\\n @\\n @@\\n ██████ @\\n ███░░░░███ @\\n ███ ░░███@\\n░███ ░███@\\n░███ ██░███@\\n░░███ ░░████ @\\n ░░░██████░██@\\n ░░░░░░ ░░ @\\n @\\n @\\n @@\\n ███████████ @\\n░░███░░░░░███ @\\n ░███ ░███ @\\n ░██████████ @\\n ░███░░░░░███ @\\n ░███ ░███ @\\n █████ █████@\\n░░░░░ ░░░░░ @\\n @\\n @\\n @@\\n █████████ @\\n ███░░░░░███@\\n░███ ░░░ @\\n░░█████████ @\\n ░░░░░░░░███@\\n ███ ░███@\\n░░█████████ @\\n ░░░░░░░░░ @\\n @\\n @\\n @@\\n ███████████@\\n░█░░░███░░░█@\\n░ ░███ ░ @\\n ░███ @\\n ░███ @\\n ░███ @\\n █████ @\\n ░░░░░ @\\n @\\n @\\n @@\\n █████ █████@\\n░░███ ░░███ @\\n ░███ ░███ @\\n ░███ ░███ @\\n ░███ ░███ @\\n ░███ ░███ @\\n ░░████████ @\\n ░░░░░░░░ @\\n @\\n @\\n @@\\n █████ █████@\\n░░███ ░░███ @\\n ░███ ░███ @\\n ░███ ░███ @\\n ░░███ ███ @\\n ░░░█████░ @\\n ░░███ @\\n ░░░ @\\n @\\n @\\n @@\\n █████ ███ █████@\\n░░███ ░███ ░░███ @\\n ░███ ░███ ░███ @\\n ░███ ░███ ░███ @\\n ░░███ █████ ███ @\\n ░░░█████░█████░ @\\n ░░███ ░░███ @\\n ░░░ ░░░ @\\n @\\n @\\n @@\\n █████ █████@\\n░░███ ░░███ @\\n ░░███ ███ @\\n ░░█████ @\\n ███░███ @\\n ███ ░░███ @\\n █████ █████@\\n░░░░░ ░░░░░ @\\n @\\n @\\n @@\\n █████ █████@\\n░░███ ░░███ @\\n ░░███ ███ @\\n ░░█████ @\\n ░░███ @\\n ░███ @\\n █████ @\\n ░░░░░ @\\n @\\n @\\n @@\\n ███████████@\\n░█░░░░░░███ @\\n░ ███░ @\\n ███ @\\n ███ @\\n ████ █@\\n ███████████@\\n░░░░░░░░░░░ @\\n @\\n @\\n @@\\n █████@\\n░███░ @\\n░███ @\\n░███ @\\n░███ @\\n░███ @\\n░█████@\\n░░░░░ @\\n @\\n @\\n @@\\n ███ @\\n░░███ @\\n ░░███ @\\n ░░███ @\\n ░░███ @\\n ░░███ @\\n ░░███@\\n ░░░ @\\n @\\n @\\n @@\\n █████@\\n░░░███@\\n ░███@\\n ░███@\\n ░███@\\n ░███@\\n █████@\\n░░░░░ @\\n @\\n @\\n @@\\n ██ @\\n ████ @\\n ██░░██@\\n░░ ░░ @\\n @\\n @\\n @\\n @\\n @\\n @\\n @@\\n @\\n @\\n @\\n @\\n @\\n @\\n █████████@\\n░░░░░░░░░ @\\n @\\n @\\n @@\\n ██ @\\n░███@\\n░░░ @\\n @\\n @\\n @\\n @\\n @\\n @\\n @\\n @@\\n @\\n @\\n ██████ @\\n ░░░░░███ @\\n ███████ @\\n ███░░███ @\\n░░████████@\\n ░░░░░░░░ @\\n @\\n @\\n @@\\n █████ @\\n░░███ @\\n ░███████ @\\n ░███░░███@\\n ░███ ░███@\\n ░███ ░███@\\n ████████ @\\n░░░░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n ██████ @\\n ███░░███@\\n░███ ░░░ @\\n░███ ███@\\n░░██████ @\\n ░░░░░░ @\\n @\\n @\\n @@\\n █████@\\n ░░███ @\\n ███████ @\\n ███░░███ @\\n░███ ░███ @\\n░███ ░███ @\\n░░████████@\\n ░░░░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n ██████ @\\n ███░░███@\\n░███████ @\\n░███░░░ @\\n░░██████ @\\n ░░░░░░ @\\n @\\n @\\n @@\\n ██████ @\\n ███░░███@\\n ░███ ░░░ @\\n ███████ @\\n░░░███░ @\\n ░███ @\\n █████ @\\n ░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n ███████@\\n ███░░███@\\n░███ ░███@\\n░███ ░███@\\n░░███████@\\n ░░░░░███@\\n ███ ░███@\\n░░██████ @\\n ░░░░░░ @@\\n █████ @\\n░░███ @\\n ░███████ @\\n ░███░░███ @\\n ░███ ░███ @\\n ░███ ░███ @\\n ████ █████@\\n░░░░ ░░░░░ @\\n @\\n @\\n @@\\n ███ @\\n ░░░ @\\n ████ @\\n░░███ @\\n ░███ @\\n ░███ @\\n █████@\\n░░░░░ @\\n @\\n @\\n @@\\n ███ @\\n ░░░ @\\n █████@\\n ░░███ @\\n ░███ @\\n ░███ @\\n ░███ @\\n ░███ @\\n ███ ░███ @\\n░░██████ @\\n ░░░░░░ @@\\n █████ @\\n░░███ @\\n ░███ █████@\\n ░███░░███ @\\n ░██████░ @\\n ░███░░███ @\\n ████ █████@\\n░░░░ ░░░░░ @\\n @\\n @\\n @@\\n ████ @\\n░░███ @\\n ░███ @\\n ░███ @\\n ░███ @\\n ░███ @\\n █████@\\n░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n █████████████ @\\n░░███░░███░░███ @\\n ░███ ░███ ░███ @\\n ░███ ░███ ░███ @\\n █████░███ █████@\\n░░░░░ ░░░ ░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n ████████ @\\n░░███░░███ @\\n ░███ ░███ @\\n ░███ ░███ @\\n ████ █████@\\n░░░░ ░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n ██████ @\\n ███░░███@\\n░███ ░███@\\n░███ ░███@\\n░░██████ @\\n ░░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n ████████ @\\n░░███░░███@\\n ░███ ░███@\\n ░███ ░███@\\n ░███████ @\\n ░███░░░ @\\n ░███ @\\n █████ @\\n░░░░░ @@\\n @\\n @\\n ████████@\\n ███░░███ @\\n░███ ░███ @\\n░███ ░███ @\\n░░███████ @\\n ░░░░░███ @\\n ░███ @\\n █████@\\n ░░░░░ @@\\n @\\n @\\n ████████ @\\n░░███░░███@\\n ░███ ░░░ @\\n ░███ @\\n █████ @\\n░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n █████ @\\n ███░░ @\\n░░█████ @\\n ░░░░███@\\n ██████ @\\n░░░░░░ @\\n @\\n @\\n @@\\n █████ @\\n ░░███ @\\n ███████ @\\n░░░███░ @\\n ░███ @\\n ░███ ███@\\n ░░█████ @\\n ░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n █████ ████@\\n░░███ ░███ @\\n ░███ ░███ @\\n ░███ ░███ @\\n ░░████████@\\n ░░░░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n █████ █████@\\n░░███ ░░███ @\\n ░███ ░███ @\\n ░░███ ███ @\\n ░░█████ @\\n ░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n █████ ███ █████@\\n░░███ ░███░░███ @\\n ░███ ░███ ░███ @\\n ░░███████████ @\\n ░░████░████ @\\n ░░░░ ░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n █████ █████@\\n░░███ ░░███ @\\n ░░░█████░ @\\n ███░░░███ @\\n █████ █████@\\n░░░░░ ░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n █████ ████@\\n░░███ ░███ @\\n ░███ ░███ @\\n ░███ ░███ @\\n ░░███████ @\\n ░░░░░███ @\\n ███ ░███ @\\n ░░██████ @\\n ░░░░░░ @@\\n @\\n @\\n █████████@\\n ░█░░░░███ @\\n ░ ███░ @\\n ███░ █@\\n █████████@\\n ░░░░░░░░░ @\\n @\\n @\\n @@\\n ███@\\n ██░ @\\n ██ @\\n ███ @\\n░░░██ @\\n ░░██ @\\n ░░███@\\n ░░░ @\\n @\\n @\\n @@\\n ███@\\n░███@\\n░███@\\n░███@\\n░███@\\n░███@\\n░███@\\n░░░ @\\n @\\n @\\n @@\\n ███ @\\n░░░██ @\\n ░░██ @\\n ░░███@\\n ██░ @\\n ██ @\\n ███ @\\n░░░ @\\n @\\n @\\n @@\\n @\\n ███ ███@\\n ███░███░ @\\n░░░ ░░░ @\\n @\\n @\\n @\\n @\\n @\\n @\\n @@\\n ███ ███ @\\n ░░░ ░░░ @\\n ███████ @\\n ███░░░███ @\\n ░█████████ @\\n ░███░░░███ @\\n █████ █████@\\n░░░░░ ░░░░░ @\\n @\\n @\\n @@\\n ███ ███ @\\n░░░ ░░░ @\\n ███████ @\\n ███░░░███@\\n░███ ░███@\\n░███ ░███@\\n░░███████ @\\n ░░░░░░░ @\\n @\\n @\\n @@\\n ███ ███ @\\n ░░░ ░░░ @\\n █████ █████@\\n░░███ ░░███ @\\n ░███ ░███ @\\n ░███ ░███ @\\n ░░███████ @\\n ░░░░░░░ @\\n @\\n @\\n @@\\n ███ ███ @\\n░░░ ░░░ @\\n ██████ @\\n ░░░░░███ @\\n ███████ @\\n ███░░███ @\\n░░████████@\\n ░░░░░░░░ @\\n @\\n @\\n @@\\n ███ ███ @\\n░░░ ░░░ @\\n ███████ @\\n ███░░░███@\\n░███ ░███@\\n░███ ░███@\\n░░███████ @\\n ░░░░░░░ @\\n @\\n @\\n @@\\n ███ ███ @\\n ░░░ ░░░ @\\n █████ █████@\\n░░███ ░░███ @\\n ░███ ░███ @\\n ░███ ░███ @\\n ░░█████████@\\n ░░░░░░░░░ @\\n @\\n @\\n @@\\n █████████ @\\n ███░░░░░███@\\n ░███ ░███@\\n ░██████████ @\\n ░███░░░░░███@\\n ░███ ░███@\\n ████ ██████ @\\n░░░░ ░░░░░░ @\\n @\\n @\\n @@\\n\"\n\n","import { dosrebelFont } from \"./fonts/dosrebel-data\"\n\nexport { dosrebelFont }\n\nexport const asciiFonts = {\n dosrebel: dosrebelFont,\n} as const\n\nexport type AsciiFontName = keyof typeof asciiFonts\n\nexport function getAsciiFont(name: AsciiFontName): string {\n return asciiFonts[name]\n}\n","import { mkdirSync, readFileSync, writeFileSync } from \"node:fs\"\nimport path from \"node:path\"\nimport {\n ASCII_CHAR_HEIGHT,\n ASCII_CHAR_WIDTH,\n asciiFonts,\n composeAsciiText,\n getAsciiAccentColumns,\n getAsciiCellIntensity,\n parseFigletFont,\n type AsciiFontName,\n type AsciiTextLayout,\n} from \"./ascii/index\"\n\ninterface RGB {\n r: number\n g: number\n b: number\n}\n\nexport interface GenerateAsciiGifOptions {\n text: string\n accent?: string\n font?: AsciiFontName | string\n outputPath: string\n color?: string\n accentColor?: string\n backgroundColor?: string\n blendColor?: string\n fps?: number\n duration?: number\n scale?: number\n levels?: number\n padding?: number\n transparent?: boolean\n}\n\nexport async function generateAsciiGif(options: GenerateAsciiGifOptions): Promise<void> {\n const fps = options.fps ?? 24\n const duration = options.duration ?? 2.4\n const scale = options.scale ?? 2\n const levels = Math.max(2, Math.min(48, options.levels ?? 32))\n const padding = Math.max(0, Math.round(options.padding ?? 16))\n const fontRaw = resolveFont(options.font ?? \"dosrebel\")\n const font = parseFigletFont(fontRaw)\n const layout = composeAsciiText(font, options.text)\n const bounds = getLayoutBounds(layout)\n const accentColumns = getAsciiAccentColumns(font, options.text, options.accent ?? \"\")\n const palette = createPalette({\n backgroundColor: options.backgroundColor ?? \"#0a0a0a\",\n blendColor: options.blendColor ?? options.backgroundColor ?? \"#0a0a0a\",\n color: options.color ?? \"#e5e5e5\",\n accentColor: options.accentColor ?? options.color ?? \"#38bdf8\",\n levels,\n transparent: options.transparent ?? false,\n })\n const width = Math.ceil(bounds.cols * ASCII_CHAR_WIDTH * scale) + padding * 2\n const height = bounds.rows * ASCII_CHAR_HEIGHT * scale + padding * 2\n const frameCount = Math.max(1, Math.round(fps * duration))\n const delay = Math.max(1, Math.round(100 / fps))\n const frames: Uint8Array[] = []\n\n for (let frame = 0; frame < frameCount; frame++) {\n frames.push(\n renderIndexedAsciiFrame({\n layout,\n accentColumns,\n phase: frame / frameCount,\n width,\n height,\n scale,\n levels,\n bounds,\n padding,\n }),\n )\n }\n\n const bytes = encodeGif({\n width,\n height,\n delay,\n palette: palette.table,\n frames,\n transparent: options.transparent ?? false,\n })\n\n mkdirSync(path.dirname(options.outputPath), { recursive: true })\n writeFileSync(options.outputPath, bytes)\n}\n\ninterface RenderIndexedFrameOptions {\n layout: AsciiTextLayout\n accentColumns: ReadonlySet<number>\n phase: number\n width: number\n height: number\n scale: number\n levels: number\n bounds: LayoutBounds\n padding: number\n}\n\ninterface LayoutBounds {\n minCol: number\n minRow: number\n cols: number\n rows: number\n}\n\nfunction renderIndexedAsciiFrame(options: RenderIndexedFrameOptions): Uint8Array {\n const pixels = new Uint8Array(options.width * options.height)\n const charWidth = Math.round(ASCII_CHAR_WIDTH * options.scale)\n const charHeight = Math.round(ASCII_CHAR_HEIGHT * options.scale)\n\n for (const cell of options.layout.cells) {\n const intensity = getAsciiCellIntensity(cell, { phase: options.phase })\n const level = Math.max(0, Math.min(options.levels - 1, Math.round(intensity * (options.levels - 1))))\n const offset = options.accentColumns.has(cell.col) ? 1 + options.levels : 1\n const colorIndex = offset + level\n const x0 = options.padding + Math.round((cell.col - options.bounds.minCol) * ASCII_CHAR_WIDTH * options.scale)\n const y0 = options.padding + (cell.row - options.bounds.minRow) * charHeight\n const x1 = Math.min(options.width, x0 + charWidth)\n const y1 = Math.min(options.height, y0 + charHeight)\n\n for (let y = y0; y < y1; y++) {\n const row = y * options.width\n for (let x = x0; x < x1; x++) {\n pixels[row + x] = colorIndex\n }\n }\n }\n\n return pixels\n}\n\nfunction getLayoutBounds(layout: AsciiTextLayout): LayoutBounds {\n if (layout.cells.length === 0) {\n return { minCol: 0, minRow: 0, cols: Math.max(1, layout.cols), rows: Math.max(1, layout.rows) }\n }\n\n let minCol = Number.POSITIVE_INFINITY\n let maxCol = Number.NEGATIVE_INFINITY\n let minRow = Number.POSITIVE_INFINITY\n let maxRow = Number.NEGATIVE_INFINITY\n\n for (const cell of layout.cells) {\n minCol = Math.min(minCol, cell.col)\n maxCol = Math.max(maxCol, cell.col)\n minRow = Math.min(minRow, cell.row)\n maxRow = Math.max(maxRow, cell.row)\n }\n\n return {\n minCol,\n minRow,\n cols: maxCol - minCol + 1,\n rows: maxRow - minRow + 1,\n }\n}\n\nfunction resolveFont(font: AsciiFontName | string): string {\n if (font in asciiFonts) return asciiFonts[font as AsciiFontName]\n return readFileSync(font, \"utf-8\")\n}\n\nfunction createPalette(options: {\n backgroundColor: string\n blendColor: string\n color: string\n accentColor: string\n levels: number\n transparent: boolean\n}) {\n const bg = parseColor(options.backgroundColor)\n const blend = parseColor(options.blendColor)\n const base = parseColor(options.color)\n const accent = parseColor(options.accentColor)\n const table: number[] = [bg.r, bg.g, bg.b]\n\n for (let level = 0; level < options.levels; level++) {\n const alpha = level / (options.levels - 1)\n const mixed = mix(blend, base, alpha)\n table.push(mixed.r, mixed.g, mixed.b)\n }\n\n for (let level = 0; level < options.levels; level++) {\n const alpha = level / (options.levels - 1)\n const mixed = mix(blend, accent, alpha)\n table.push(mixed.r, mixed.g, mixed.b)\n }\n\n while (table.length < 256 * 3) table.push(0, 0, 0)\n return { table: Uint8Array.from(table.slice(0, 256 * 3)) }\n}\n\nfunction parseColor(input: string): RGB {\n const color = input.trim()\n const shortHex = /^#([0-9a-f]{3})$/i.exec(color)\n if (shortHex) {\n const [r, g, b] = shortHex[1].split(\"\").map((part) => Number.parseInt(part + part, 16))\n return { r, g, b }\n }\n\n const longHex = /^#([0-9a-f]{6})$/i.exec(color)\n if (longHex) {\n const value = longHex[1]\n return {\n r: Number.parseInt(value.slice(0, 2), 16),\n g: Number.parseInt(value.slice(2, 4), 16),\n b: Number.parseInt(value.slice(4, 6), 16),\n }\n }\n\n const rgb = /^rgb\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)$/i.exec(color)\n if (rgb) {\n return {\n r: clampByte(Number.parseInt(rgb[1], 10)),\n g: clampByte(Number.parseInt(rgb[2], 10)),\n b: clampByte(Number.parseInt(rgb[3], 10)),\n }\n }\n\n throw new Error(`Unsupported color \"${input}\". Use #rgb, #rrggbb, or rgb(r,g,b).`)\n}\n\nfunction mix(a: RGB, b: RGB, amount: number): RGB {\n return {\n r: clampByte(a.r + (b.r - a.r) * amount),\n g: clampByte(a.g + (b.g - a.g) * amount),\n b: clampByte(a.b + (b.b - a.b) * amount),\n }\n}\n\nfunction clampByte(value: number): number {\n return Math.max(0, Math.min(255, Math.round(value)))\n}\n\ninterface EncodeGifOptions {\n width: number\n height: number\n delay: number\n palette: Uint8Array\n frames: Uint8Array[]\n transparent: boolean\n}\n\nfunction encodeGif(options: EncodeGifOptions): Uint8Array {\n const bytes: number[] = []\n writeAscii(bytes, \"GIF89a\")\n writeU16(bytes, options.width)\n writeU16(bytes, options.height)\n bytes.push(0xf7, 0, 0)\n pushBytes(bytes, options.palette)\n bytes.push(0x21, 0xff, 0x0b)\n writeAscii(bytes, \"NETSCAPE2.0\")\n bytes.push(0x03, 0x01)\n writeU16(bytes, 0)\n bytes.push(0)\n\n for (const frame of options.frames) {\n bytes.push(0x21, 0xf9, 0x04, options.transparent ? 0x05 : 0x04)\n writeU16(bytes, options.delay)\n bytes.push(0, 0)\n bytes.push(0x2c)\n writeU16(bytes, 0)\n writeU16(bytes, 0)\n writeU16(bytes, options.width)\n writeU16(bytes, options.height)\n bytes.push(0)\n bytes.push(8)\n writeSubBlocks(bytes, lzwEncode(frame, 8))\n }\n\n bytes.push(0x3b)\n return Uint8Array.from(bytes)\n}\n\nfunction lzwEncode(indices: Uint8Array, minCodeSize: number): Uint8Array {\n const clearCode = 1 << minCodeSize\n const endCode = clearCode + 1\n let codeSize = minCodeSize + 1\n const output: number[] = []\n const writeCode = createBitWriter(output)\n\n writeCode(clearCode, codeSize)\n\n let codesSinceClear = 0\n for (const index of indices) {\n if (codesSinceClear >= 240) {\n writeCode(clearCode, codeSize)\n codeSize = minCodeSize + 1\n codesSinceClear = 0\n }\n writeCode(index, codeSize)\n codesSinceClear++\n }\n\n writeCode(endCode, codeSize)\n writeCode(-1, 0)\n\n return Uint8Array.from(output)\n}\n\nfunction createBitWriter(output: number[]) {\n let buffer = 0\n let bitCount = 0\n\n return (code: number, size: number) => {\n if (code < 0) {\n if (bitCount > 0) output.push(buffer & 0xff)\n buffer = 0\n bitCount = 0\n return\n }\n\n buffer |= code << bitCount\n bitCount += size\n\n while (bitCount >= 8) {\n output.push(buffer & 0xff)\n buffer >>= 8\n bitCount -= 8\n }\n }\n}\n\nfunction writeSubBlocks(bytes: number[], data: Uint8Array) {\n for (let offset = 0; offset < data.length; offset += 255) {\n const chunk = data.slice(offset, offset + 255)\n bytes.push(chunk.length)\n pushBytes(bytes, chunk)\n }\n bytes.push(0)\n}\n\nfunction writeAscii(bytes: number[], value: string) {\n for (let i = 0; i < value.length; i++) bytes.push(value.charCodeAt(i))\n}\n\nfunction writeU16(bytes: number[], value: number) {\n bytes.push(value & 0xff, (value >> 8) & 0xff)\n}\n\nfunction pushBytes(bytes: number[], values: Uint8Array) {\n for (const value of values) bytes.push(value)\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/ascii/compose.ts","../src/ascii/figlet.ts","../src/ascii/render.ts","../src/ascii/fonts/dosrebel-data.ts","../src/ascii/fonts.ts","../src/ascii-gif.ts"],"names":["bytes"],"mappings":"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AA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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","file":"ascii-gif.js","sourcesContent":["import type { FigletFont } from \"./figlet\"\n\nexport interface AsciiCell {\n ch: \"█\" | \"░\"\n col: number\n row: number\n}\n\nexport interface AsciiTextLayout {\n cells: AsciiCell[]\n cols: number\n rows: number\n}\n\nexport function composeAsciiText(font: FigletFont, text: string): AsciiTextLayout {\n const charBlocks: Array<{ lines: string[]; width: number }> = []\n\n for (const ch of text) {\n const code = ch.charCodeAt(0)\n const glyph = font.chars.get(code) ?? font.chars.get(32)\n if (!glyph) continue\n\n const width = Math.max(...glyph.map((line) => line.length))\n charBlocks.push({\n lines: glyph.map((line) => line.padEnd(width)),\n width,\n })\n }\n\n const cols = charBlocks.reduce((sum, block) => sum + block.width, 0)\n const rows = font.height\n const cells: AsciiCell[] = []\n let offsetX = 0\n\n for (const block of charBlocks) {\n for (let row = 0; row < rows; row++) {\n const line = block.lines[row] ?? \"\"\n for (let col = 0; col < line.length; col++) {\n const ch = line[col]\n if (ch === \"█\" || ch === \"░\") {\n cells.push({ ch, col: offsetX + col, row })\n }\n }\n }\n offsetX += block.width\n }\n\n return { cells, cols, rows }\n}\n\nexport function getAsciiAccentColumns(\n font: FigletFont,\n text: string,\n accent: string,\n): Set<number> {\n if (!accent) return new Set<number>()\n\n const columns = new Set<number>()\n const accentRanges: Array<{ start: number; end: number }> = []\n let searchFrom = 0\n while (true) {\n const idx = text.indexOf(accent, searchFrom)\n if (idx === -1) break\n accentRanges.push({ start: idx, end: idx + accent.length })\n searchFrom = idx + 1\n }\n if (accentRanges.length === 0) return columns\n\n let offsetX = 0\n let charIndex = 0\n\n for (const ch of text) {\n const code = ch.charCodeAt(0)\n const glyph = font.chars.get(code) ?? font.chars.get(32)\n if (!glyph) { charIndex++; continue }\n\n const width = Math.max(...glyph.map((line) => line.length))\n if (accentRanges.some((r) => charIndex >= r.start && charIndex < r.end)) {\n for (let col = 0; col < width; col++) columns.add(offsetX + col)\n }\n offsetX += width\n charIndex++\n }\n\n return columns\n}\n","export interface FigletFont {\n height: number\n baseline: number\n hardblank: string\n chars: Map<number, string[]>\n}\n\nexport function parseFigletFont(raw: string): FigletFont {\n const lines = raw.split(\"\\n\")\n\n if (lines[0]?.charCodeAt(0) === 0xfeff) {\n lines[0] = lines[0].slice(1)\n }\n\n const header = lines[0]\n if (!header?.startsWith(\"flf2a\")) {\n throw new Error(\"Invalid FIGlet font: missing flf2a header\")\n }\n\n const hardblank = header[5] ?? \"$\"\n const parts = header.slice(6).trim().split(/\\s+/)\n const height = Number.parseInt(parts[0] ?? \"\", 10)\n const baseline = Number.parseInt(parts[1] ?? \"\", 10)\n const commentLines = Number.parseInt(parts[4] ?? \"\", 10)\n\n if (!Number.isFinite(height) || height <= 0) {\n throw new Error(\"Invalid FIGlet font: missing character height\")\n }\n\n const dataStart = 1 + (Number.isFinite(commentLines) ? commentLines : 0)\n const chars = new Map<number, string[]>()\n let lineIndex = dataStart\n let ascii = 32\n\n while (lineIndex + height <= lines.length && ascii <= 126) {\n const charLines: string[] = []\n for (let row = 0; row < height; row++) {\n const line = (lines[lineIndex + row] ?? \"\")\n .replace(/@+$/, \"\")\n .replaceAll(hardblank, \" \")\n charLines.push(line)\n }\n\n chars.set(ascii, charLines)\n lineIndex += height\n ascii++\n }\n\n return { height, baseline, hardblank, chars }\n}\n","import type { AsciiCell, AsciiTextLayout } from \"./compose\"\n\nexport const ASCII_CHAR_WIDTH = 7.5\nexport const ASCII_CHAR_HEIGHT = 15\n\nexport interface AsciiWave {\n cx: number\n cy: number\n t: number\n}\n\nexport interface AsciiPointer {\n x: number\n y: number\n active: boolean\n}\n\nexport interface AsciiFrameState {\n time?: number\n phase?: number\n pointer?: AsciiPointer\n waves?: AsciiWave[]\n}\n\nexport interface AsciiRenderOptions extends AsciiFrameState {\n accentColumns?: ReadonlySet<number>\n color: string\n accentColor?: string\n charWidth?: number\n charHeight?: number\n}\n\nexport interface AsciiFrameContext {\n clearRect(x: number, y: number, width: number, height: number): void\n fillRect(x: number, y: number, width: number, height: number): void\n globalAlpha: number\n fillStyle: string\n}\n\nexport function getAsciiCanvasSize(\n layout: AsciiTextLayout,\n charWidth = ASCII_CHAR_WIDTH,\n charHeight = ASCII_CHAR_HEIGHT,\n) {\n return {\n width: Math.ceil(layout.cols * charWidth),\n height: layout.rows * charHeight,\n }\n}\n\nexport function getAsciiCellIntensity(cell: AsciiCell, options: AsciiFrameState): number {\n const time = options.time ?? 0\n const loop = options.phase == null ? null : options.phase * Math.PI * 2\n\n if (cell.ch === \"░\") {\n const drift =\n loop == null\n ? Math.sin(time * 0.3 + cell.col * 0.1) * 0.03\n : Math.sin(loop + cell.col * 0.1) * 0.03\n return 0.15 + drift\n }\n\n if (loop != null) {\n return getLoopIntensity(cell, loop)\n }\n\n const noise = getLiveNoise(cell, time)\n\n const seed = cell.col * 7.13 + cell.row * 13.37\n const flickerPhase = Math.sin(seed) * 1000\n const flickerWave = Math.sin(time * 0.8 + flickerPhase)\n const flicker = flickerWave > 0.97 ? 0.15 : 0\n\n let intensity = 0.7 + noise + flicker\n const charWidth = ASCII_CHAR_WIDTH\n const charHeight = ASCII_CHAR_HEIGHT\n\n if (options.pointer?.active) {\n const mdx = cell.col * charWidth + charWidth / 2 - options.pointer.x\n const mdy = cell.row * charHeight + charHeight / 2 - options.pointer.y\n const mDist = Math.sqrt(mdx * mdx + mdy * mdy)\n const radius = 80\n if (mDist < radius) {\n const falloff = 1 - mDist / radius\n const ripple = Math.sin(mDist * 0.08 - time * 4) * 0.12 * falloff * falloff\n intensity = Math.min(1, intensity + falloff * 0.2 + ripple)\n }\n }\n\n const px = cell.col * charWidth + charWidth / 2\n const py = cell.row * charHeight + charHeight / 2\n for (const wave of options.waves ?? []) {\n const wdx = px - wave.cx\n const wdy = py - wave.cy\n const dist = Math.sqrt(wdx * wdx + wdy * wdy)\n const age = time - wave.t\n const waveRadius = age * 200\n const delta = dist - waveRadius\n const fade = Math.exp(-age * 1.5)\n const ring = Math.exp(-delta * delta * 0.002) * fade\n intensity = Math.min(1, intensity + ring * 0.5 * Math.sin(delta * 0.06 + 1.5))\n }\n\n return Math.max(0.5, Math.min(1, intensity))\n}\n\nexport function renderAsciiFrameToContext(\n ctx: AsciiFrameContext,\n layout: AsciiTextLayout,\n options: AsciiRenderOptions,\n) {\n const charWidth = options.charWidth ?? ASCII_CHAR_WIDTH\n const charHeight = options.charHeight ?? ASCII_CHAR_HEIGHT\n const { width, height } = getAsciiCanvasSize(layout, charWidth, charHeight)\n const accentColor = options.accentColor ?? options.color\n\n ctx.clearRect(0, 0, width, height)\n\n for (const cell of layout.cells) {\n const isAccent = options.accentColumns?.has(cell.col) ?? false\n ctx.globalAlpha = getAsciiCellIntensity(cell, options)\n ctx.fillStyle = isAccent ? accentColor : options.color\n ctx.fillRect(cell.col * charWidth, cell.row * charHeight, charWidth, charHeight)\n }\n\n ctx.globalAlpha = 1\n}\n\nfunction getLiveNoise(cell: AsciiCell, time: number): number {\n const nx = cell.col * 0.18 + time * 0.9\n const ny = cell.row * 0.3 + time * 0.55\n return (\n Math.sin(nx) * 0.12 +\n Math.sin(ny * 1.4 + nx * 0.6) * 0.1 +\n Math.sin(nx * 0.4 - ny * 0.8 + time * 1.6) * 0.08 +\n Math.sin((cell.col + cell.row) * 0.15 + time * 0.4) * 0.07\n )\n}\n\nfunction getLoopIntensity(cell: AsciiCell, loop: number): number {\n const flow =\n Math.sin(cell.col * 0.08 + loop) * 0.055 +\n Math.sin(cell.row * 0.22 - loop * 0.75) * 0.04\n const shimmer = (Math.sin(cell.col * 0.16 + cell.row * 0.08 - loop * 2) + 1) / 2\n const highlight = Math.pow(shimmer, 4) * 0.22\n const intensity = 0.68 + flow + highlight\n\n return Math.max(0.55, Math.min(1, intensity))\n}\n","// @generated from dosrebel.flf. Do not edit by hand.\nexport const dosrebelFont: string = \"flf2a$ 11 8 35 -1 15\\nRebel by Valerie Mates (popcorn@cyberspace.org), based on a font by Ron Bliss\\n(who sometimes goes by the name \\\"rebel\\\" because his initials are REB).\\nNOTE: THIS FONT ONLY WORKS IN MS-DOS.\\nMay 27, 1994\\n\\nExplanation of first line:\\nflf2 - \\\"magic number\\\" for file identification\\na - should always be `a', for now\\n$ - the \\\"hardblank\\\" -- prints as a blank, but can't be smushed\\n11 - height of a character\\n8 - height of a character, not including descenders\\n35 - max line length (excluding comment lines) + a fudge factor\\n-1 - default smushmode for this font (like \\\"-m 15\\\" on command line)\\n15 - number of comment lines\\n\\n$$$@\\n$$$@\\n$$$@\\n$$$@\\n$$$@\\n$$$@\\n$$$@\\n$$$@\\n$$$@\\n$$$@\\n$$$@@\\n ███@\\n░███@\\n░███@\\n░███@\\n░███@\\n░░░ @\\n ███@\\n░░░ @\\n @\\n @\\n @@\\n ██ ██@\\n░██░██@\\n░░ ░░ @\\n @\\n @\\n @\\n @\\n @\\n @\\n @\\n @@\\n ███ ███ @\\n ████████████@\\n░░░███░░███░ @\\n ████████████@\\n░░░███░░███░ @\\n ░░░ ░░░ @\\n @\\n @\\n @\\n @\\n @@\\n ███ @\\n ██████ @\\n ███░░░ @\\n ░░█████ @\\n ░░░░███ @\\n ██████ @\\n ░░░███ @\\n ░░░ @\\n @\\n @\\n @@\\n ███ ███@\\n ░░░ ███░ @\\n ███░ @\\n ███░ @\\n ███░ @\\n ███░ @\\n ███░ ███ @\\n░░░ ░░░ @\\n @\\n @\\n @@\\n ██████ @\\n ███░░███ @\\n ░░██████ @\\n ██████ @\\n░███░░███ @\\n░███ ░░███ @\\n░░█████░███@\\n ░░░░░ ░░░ @\\n @\\n @\\n @@\\n ██@\\n ███@\\n░░░ @\\n @\\n @\\n @\\n @\\n @\\n @\\n @\\n @@\\n ███@\\n ███ @\\n ███ @\\n░███ @\\n░███ @\\n░░███ @\\n ░░███@\\n ░░░ @\\n @\\n @\\n @@\\n ███ @\\n░░███ @\\n ░░███@\\n ░███@\\n ░███@\\n ███ @\\n ██░ @\\n░░░ @\\n @\\n @\\n @@\\n ███ @\\n ███ ░███ ███@\\n░░░█████████░ @\\n ░░░█████░ @\\n █████████ @\\n ███░░███░░███@\\n░░░ ░███ ░░░ @\\n ░░░ @\\n @\\n @\\n @@\\n @\\n ███ @\\n ░███ @\\n ███████████@\\n░░░░░███░░░ @\\n ░███ @\\n ░░░ @\\n @\\n @\\n @\\n @@\\n @\\n @\\n @\\n @\\n @\\n @\\n ██@\\n ██ @\\n░░ @\\n @\\n @@\\n @\\n @\\n @\\n ██████████@\\n░░░░░░░░░░ @\\n @\\n @\\n @\\n @\\n @\\n @@\\n @\\n @\\n @\\n @\\n @\\n @\\n ██@\\n░░ @\\n @\\n @\\n @@\\n ███@\\n ███░ @\\n ███░ @\\n ███░ @\\n ███░ @\\n ███░ @\\n ███░ @\\n░░░ @\\n @\\n @\\n @@\\n █████ @\\n ███░░░███ @\\n ███ ░░███@\\n░███ ░███@\\n░███ ░███@\\n░░███ ███ @\\n ░░░█████░ @\\n ░░░░░░ @\\n @\\n @\\n @@\\n ████ @\\n░░███ @\\n ░███ @\\n ░███ @\\n ░███ @\\n ░███ @\\n █████@\\n░░░░░ @\\n @\\n @\\n @@\\n ████████ @\\n ███░░░░███@\\n░░░ ░███@\\n ███████ @\\n ███░░░░ @\\n ███ █@\\n░██████████@\\n░░░░░░░░░░ @\\n @\\n @\\n @@\\n ████████ @\\n ███░░░░███@\\n░░░ ░███@\\n ██████░ @\\n ░░░░░░███@\\n ███ ░███@\\n░░████████ @\\n ░░░░░░░░ @\\n @\\n @\\n @@\\n █████ █████ @\\n░░███ ░░███ @\\n ░███ ░███ █@\\n ░███████████@\\n ░░░░░░░███░█@\\n ░███░ @\\n █████ @\\n ░░░░░ @\\n @\\n @\\n @@\\n ██████████@\\n░███░░░░░░█@\\n░███ ░ @\\n░█████████ @\\n░░░░░░░░███@\\n ███ ░███@\\n░░████████ @\\n ░░░░░░░░ @\\n @\\n @\\n @@\\n ████████ @\\n ███░░░░███@\\n░███ ░░░ @\\n░█████████ @\\n░███░░░░███@\\n░███ ░███@\\n░░████████ @\\n ░░░░░░░░ @\\n @\\n @\\n @@\\n ██████████@\\n░███░░░░███@\\n░░░ ███ @\\n ███ @\\n ███ @\\n ███ @\\n ███ @\\n ░░░ @\\n @\\n @\\n @@\\n ████████ @\\n ███░░░░███ @\\n░███ ░███ @\\n░░████████ @\\n ███░░░░███ @\\n░███ ░███ @\\n░░████████ @\\n ░░░░░░░░ @\\n @\\n @\\n @@\\n ████████ @\\n ███░░░░███@\\n░███ ░███@\\n░░█████████@\\n ░░░░░░░███@\\n ███ ░███@\\n░░████████ @\\n ░░░░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n ██@\\n░░ @\\n @\\n @\\n ██@\\n░░ @\\n @\\n @\\n @@\\n @\\n @\\n @\\n @\\n ██@\\n ░░ @\\n ██@\\n ██ @\\n░░ @\\n @\\n @@\\n ███@\\n ███░ @\\n ███░ @\\n ███░ @\\n░░░███ @\\n ░░░███ @\\n ░░░███@\\n ░░░ @\\n @\\n @\\n @@\\n @\\n @\\n █████████@\\n░░░░░░░░░ @\\n █████████@\\n░░░░░░░░░ @\\n @\\n @\\n @\\n @\\n @@\\n ███ @\\n░░░███ @\\n ░░░███ @\\n ░░░███@\\n ███░ @\\n ███░ @\\n ███░ @\\n░░░ @\\n @\\n @\\n @@\\n ███████ @\\n ███░░░███@\\n░░░ ░███@\\n ███████ @\\n ░███░░░ @\\n ░░░ @\\n ███ @\\n ░░░ @\\n @\\n @\\n @@\\n █████████ @\\n ███░░░░░░ @\\n░███ ██████ @\\n░███░███░███@\\n░███░███░███@\\n░███░░░ ░███@\\n░░█████████ @\\n ░░░░░░░░░ @\\n @\\n @\\n @@\\n █████████ @\\n ███░░░░░███ @\\n ░███ ░███ @\\n ░███████████ @\\n ░███░░░░░███ @\\n ░███ ░███ @\\n █████ █████@\\n░░░░░ ░░░░░ @\\n @\\n @\\n @@\\n ███████████ @\\n░░███░░░░░███@\\n ░███ ░███@\\n ░██████████ @\\n ░███░░░░░███@\\n ░███ ░███@\\n ███████████ @\\n░░░░░░░░░░░ @\\n @\\n @\\n @@\\n █████████ @\\n ███░░░░░███@\\n ███ ░░░ @\\n░███ @\\n░███ @\\n░░███ ███@\\n ░░█████████ @\\n ░░░░░░░░░ @\\n @\\n @\\n @@\\n ██████████ @\\n░░███░░░░███ @\\n ░███ ░░███@\\n ░███ ░███@\\n ░███ ░███@\\n ░███ ███ @\\n ██████████ @\\n░░░░░░░░░░ @\\n @\\n @\\n @@\\n ██████████@\\n░░███░░░░░█@\\n ░███ █ ░ @\\n ░██████ @\\n ░███░░█ @\\n ░███ ░ █@\\n ██████████@\\n░░░░░░░░░░ @\\n @\\n @\\n @@\\n ███████████@\\n░░███░░░░░░█@\\n ░███ █ ░ @\\n ░███████ @\\n ░███░░░█ @\\n ░███ ░ @\\n █████ @\\n░░░░░ @\\n @\\n @\\n @@\\n █████████ @\\n ███░░░░░███@\\n ███ ░░░ @\\n░███ @\\n░███ █████@\\n░░███ ░░███ @\\n ░░█████████ @\\n ░░░░░░░░░ @\\n @\\n @\\n @@\\n █████ █████@\\n░░███ ░░███ @\\n ░███ ░███ @\\n ░███████████ @\\n ░███░░░░░███ @\\n ░███ ░███ @\\n █████ █████@\\n░░░░░ ░░░░░ @\\n @\\n @\\n @@\\n █████@\\n░░███ @\\n ░███ @\\n ░███ @\\n ░███ @\\n ░███ @\\n █████@\\n░░░░░ @\\n @\\n @\\n @@\\n █████@\\n ░░███ @\\n ░███ @\\n ░███ @\\n ░███ @\\n ███ ░███ @\\n░░████████ @\\n ░░░░░░░░ @\\n @\\n @\\n @@\\n █████ ████@\\n░░███ ███░ @\\n ░███ ███ @\\n ░███████ @\\n ░███░░███ @\\n ░███ ░░███ @\\n █████ ░░████@\\n░░░░░ ░░░░ @\\n @\\n @\\n @@\\n █████ @\\n░░███ @\\n ░███ @\\n ░███ @\\n ░███ @\\n ░███ █@\\n ███████████@\\n░░░░░░░░░░░ @\\n @\\n @\\n @@\\n ██████ ██████@\\n░░██████ ██████ @\\n ░███░█████░███ @\\n ░███░░███ ░███ @\\n ░███ ░░░ ░███ @\\n ░███ ░███ @\\n █████ █████@\\n░░░░░ ░░░░░ @\\n @\\n @\\n @@\\n ██████ █████@\\n░░██████ ░░███ @\\n ░███░███ ░███ @\\n ░███░░███░███ @\\n ░███ ░░██████ @\\n ░███ ░░█████ @\\n █████ ░░█████@\\n░░░░░ ░░░░░ @\\n @\\n @\\n @@\\n ███████ @\\n ███░░░░░███ @\\n ███ ░░███@\\n░███ ░███@\\n░███ ░███@\\n░░███ ███ @\\n ░░░███████░ @\\n ░░░░░░░ @\\n @\\n @\\n @@\\n ███████████ @\\n░░███░░░░░███@\\n ░███ ░███@\\n ░██████████ @\\n ░███░░░░░░ @\\n ░███ @\\n █████ @\\n░░░░░ @\\n @\\n @\\n @@\\n ██████ @\\n ███░░░░███ @\\n ███ ░░███@\\n░███ ░███@\\n░███ ██░███@\\n░░███ ░░████ @\\n ░░░██████░██@\\n ░░░░░░ ░░ @\\n @\\n @\\n @@\\n ███████████ @\\n░░███░░░░░███ @\\n ░███ ░███ @\\n ░██████████ @\\n ░███░░░░░███ @\\n ░███ ░███ @\\n █████ █████@\\n░░░░░ ░░░░░ @\\n @\\n @\\n @@\\n █████████ @\\n ███░░░░░███@\\n░███ ░░░ @\\n░░█████████ @\\n ░░░░░░░░███@\\n ███ ░███@\\n░░█████████ @\\n ░░░░░░░░░ @\\n @\\n @\\n @@\\n ███████████@\\n░█░░░███░░░█@\\n░ ░███ ░ @\\n ░███ @\\n ░███ @\\n ░███ @\\n █████ @\\n ░░░░░ @\\n @\\n @\\n @@\\n █████ █████@\\n░░███ ░░███ @\\n ░███ ░███ @\\n ░███ ░███ @\\n ░███ ░███ @\\n ░███ ░███ @\\n ░░████████ @\\n ░░░░░░░░ @\\n @\\n @\\n @@\\n █████ █████@\\n░░███ ░░███ @\\n ░███ ░███ @\\n ░███ ░███ @\\n ░░███ ███ @\\n ░░░█████░ @\\n ░░███ @\\n ░░░ @\\n @\\n @\\n @@\\n █████ ███ █████@\\n░░███ ░███ ░░███ @\\n ░███ ░███ ░███ @\\n ░███ ░███ ░███ @\\n ░░███ █████ ███ @\\n ░░░█████░█████░ @\\n ░░███ ░░███ @\\n ░░░ ░░░ @\\n @\\n @\\n @@\\n █████ █████@\\n░░███ ░░███ @\\n ░░███ ███ @\\n ░░█████ @\\n ███░███ @\\n ███ ░░███ @\\n █████ █████@\\n░░░░░ ░░░░░ @\\n @\\n @\\n @@\\n █████ █████@\\n░░███ ░░███ @\\n ░░███ ███ @\\n ░░█████ @\\n ░░███ @\\n ░███ @\\n █████ @\\n ░░░░░ @\\n @\\n @\\n @@\\n ███████████@\\n░█░░░░░░███ @\\n░ ███░ @\\n ███ @\\n ███ @\\n ████ █@\\n ███████████@\\n░░░░░░░░░░░ @\\n @\\n @\\n @@\\n █████@\\n░███░ @\\n░███ @\\n░███ @\\n░███ @\\n░███ @\\n░█████@\\n░░░░░ @\\n @\\n @\\n @@\\n ███ @\\n░░███ @\\n ░░███ @\\n ░░███ @\\n ░░███ @\\n ░░███ @\\n ░░███@\\n ░░░ @\\n @\\n @\\n @@\\n █████@\\n░░░███@\\n ░███@\\n ░███@\\n ░███@\\n ░███@\\n █████@\\n░░░░░ @\\n @\\n @\\n @@\\n ██ @\\n ████ @\\n ██░░██@\\n░░ ░░ @\\n @\\n @\\n @\\n @\\n @\\n @\\n @@\\n @\\n @\\n @\\n @\\n @\\n @\\n █████████@\\n░░░░░░░░░ @\\n @\\n @\\n @@\\n ██ @\\n░███@\\n░░░ @\\n @\\n @\\n @\\n @\\n @\\n @\\n @\\n @@\\n @\\n @\\n ██████ @\\n ░░░░░███ @\\n ███████ @\\n ███░░███ @\\n░░████████@\\n ░░░░░░░░ @\\n @\\n @\\n @@\\n █████ @\\n░░███ @\\n ░███████ @\\n ░███░░███@\\n ░███ ░███@\\n ░███ ░███@\\n ████████ @\\n░░░░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n ██████ @\\n ███░░███@\\n░███ ░░░ @\\n░███ ███@\\n░░██████ @\\n ░░░░░░ @\\n @\\n @\\n @@\\n █████@\\n ░░███ @\\n ███████ @\\n ███░░███ @\\n░███ ░███ @\\n░███ ░███ @\\n░░████████@\\n ░░░░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n ██████ @\\n ███░░███@\\n░███████ @\\n░███░░░ @\\n░░██████ @\\n ░░░░░░ @\\n @\\n @\\n @@\\n ██████ @\\n ███░░███@\\n ░███ ░░░ @\\n ███████ @\\n░░░███░ @\\n ░███ @\\n █████ @\\n ░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n ███████@\\n ███░░███@\\n░███ ░███@\\n░███ ░███@\\n░░███████@\\n ░░░░░███@\\n ███ ░███@\\n░░██████ @\\n ░░░░░░ @@\\n █████ @\\n░░███ @\\n ░███████ @\\n ░███░░███ @\\n ░███ ░███ @\\n ░███ ░███ @\\n ████ █████@\\n░░░░ ░░░░░ @\\n @\\n @\\n @@\\n ███ @\\n ░░░ @\\n ████ @\\n░░███ @\\n ░███ @\\n ░███ @\\n █████@\\n░░░░░ @\\n @\\n @\\n @@\\n ███ @\\n ░░░ @\\n █████@\\n ░░███ @\\n ░███ @\\n ░███ @\\n ░███ @\\n ░███ @\\n ███ ░███ @\\n░░██████ @\\n ░░░░░░ @@\\n █████ @\\n░░███ @\\n ░███ █████@\\n ░███░░███ @\\n ░██████░ @\\n ░███░░███ @\\n ████ █████@\\n░░░░ ░░░░░ @\\n @\\n @\\n @@\\n ████ @\\n░░███ @\\n ░███ @\\n ░███ @\\n ░███ @\\n ░███ @\\n █████@\\n░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n █████████████ @\\n░░███░░███░░███ @\\n ░███ ░███ ░███ @\\n ░███ ░███ ░███ @\\n █████░███ █████@\\n░░░░░ ░░░ ░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n ████████ @\\n░░███░░███ @\\n ░███ ░███ @\\n ░███ ░███ @\\n ████ █████@\\n░░░░ ░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n ██████ @\\n ███░░███@\\n░███ ░███@\\n░███ ░███@\\n░░██████ @\\n ░░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n ████████ @\\n░░███░░███@\\n ░███ ░███@\\n ░███ ░███@\\n ░███████ @\\n ░███░░░ @\\n ░███ @\\n █████ @\\n░░░░░ @@\\n @\\n @\\n ████████@\\n ███░░███ @\\n░███ ░███ @\\n░███ ░███ @\\n░░███████ @\\n ░░░░░███ @\\n ░███ @\\n █████@\\n ░░░░░ @@\\n @\\n @\\n ████████ @\\n░░███░░███@\\n ░███ ░░░ @\\n ░███ @\\n █████ @\\n░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n █████ @\\n ███░░ @\\n░░█████ @\\n ░░░░███@\\n ██████ @\\n░░░░░░ @\\n @\\n @\\n @@\\n █████ @\\n ░░███ @\\n ███████ @\\n░░░███░ @\\n ░███ @\\n ░███ ███@\\n ░░█████ @\\n ░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n █████ ████@\\n░░███ ░███ @\\n ░███ ░███ @\\n ░███ ░███ @\\n ░░████████@\\n ░░░░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n █████ █████@\\n░░███ ░░███ @\\n ░███ ░███ @\\n ░░███ ███ @\\n ░░█████ @\\n ░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n █████ ███ █████@\\n░░███ ░███░░███ @\\n ░███ ░███ ░███ @\\n ░░███████████ @\\n ░░████░████ @\\n ░░░░ ░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n █████ █████@\\n░░███ ░░███ @\\n ░░░█████░ @\\n ███░░░███ @\\n █████ █████@\\n░░░░░ ░░░░░ @\\n @\\n @\\n @@\\n @\\n @\\n █████ ████@\\n░░███ ░███ @\\n ░███ ░███ @\\n ░███ ░███ @\\n ░░███████ @\\n ░░░░░███ @\\n ███ ░███ @\\n ░░██████ @\\n ░░░░░░ @@\\n @\\n @\\n █████████@\\n ░█░░░░███ @\\n ░ ███░ @\\n ███░ █@\\n █████████@\\n ░░░░░░░░░ @\\n @\\n @\\n @@\\n ███@\\n ██░ @\\n ██ @\\n ███ @\\n░░░██ @\\n ░░██ @\\n ░░███@\\n ░░░ @\\n @\\n @\\n @@\\n ███@\\n░███@\\n░███@\\n░███@\\n░███@\\n░███@\\n░███@\\n░░░ @\\n @\\n @\\n @@\\n ███ @\\n░░░██ @\\n ░░██ @\\n ░░███@\\n ██░ @\\n ██ @\\n ███ @\\n░░░ @\\n @\\n @\\n @@\\n @\\n ███ ███@\\n ███░███░ @\\n░░░ ░░░ @\\n @\\n @\\n @\\n @\\n @\\n @\\n @@\\n ███ ███ @\\n ░░░ ░░░ @\\n ███████ @\\n ███░░░███ @\\n ░█████████ @\\n ░███░░░███ @\\n █████ █████@\\n░░░░░ ░░░░░ @\\n @\\n @\\n @@\\n ███ ███ @\\n░░░ ░░░ @\\n ███████ @\\n ███░░░███@\\n░███ ░███@\\n░███ ░███@\\n░░███████ @\\n ░░░░░░░ @\\n @\\n @\\n @@\\n ███ ███ @\\n ░░░ ░░░ @\\n █████ █████@\\n░░███ ░░███ @\\n ░███ ░███ @\\n ░███ ░███ @\\n ░░███████ @\\n ░░░░░░░ @\\n @\\n @\\n @@\\n ███ ███ @\\n░░░ ░░░ @\\n ██████ @\\n ░░░░░███ @\\n ███████ @\\n ███░░███ @\\n░░████████@\\n ░░░░░░░░ @\\n @\\n @\\n @@\\n ███ ███ @\\n░░░ ░░░ @\\n ███████ @\\n ███░░░███@\\n░███ ░███@\\n░███ ░███@\\n░░███████ @\\n ░░░░░░░ @\\n @\\n @\\n @@\\n ███ ███ @\\n ░░░ ░░░ @\\n █████ █████@\\n░░███ ░░███ @\\n ░███ ░███ @\\n ░███ ░███ @\\n ░░█████████@\\n ░░░░░░░░░ @\\n @\\n @\\n @@\\n █████████ @\\n ███░░░░░███@\\n ░███ ░███@\\n ░██████████ @\\n ░███░░░░░███@\\n ░███ ░███@\\n ████ ██████ @\\n░░░░ ░░░░░░ @\\n @\\n @\\n @@\\n\"\n\n","import { dosrebelFont } from \"./fonts/dosrebel-data\"\n\nexport { dosrebelFont }\n\nexport const asciiFonts = {\n dosrebel: dosrebelFont,\n} as const\n\nexport type AsciiFontName = keyof typeof asciiFonts\n\nexport function getAsciiFont(name: AsciiFontName): string {\n return asciiFonts[name]\n}\n","import { mkdirSync, readFileSync, writeFileSync } from \"node:fs\"\nimport path from \"node:path\"\nimport {\n ASCII_CHAR_HEIGHT,\n ASCII_CHAR_WIDTH,\n asciiFonts,\n composeAsciiText,\n getAsciiAccentColumns,\n getAsciiCellIntensity,\n parseFigletFont,\n type AsciiFontName,\n type AsciiTextLayout,\n} from \"./ascii/index\"\n\ninterface RGB {\n r: number\n g: number\n b: number\n}\n\nexport interface GenerateAsciiGifOptions {\n text: string\n accent?: string\n font?: AsciiFontName | string\n outputPath: string\n color?: string\n accentColor?: string\n rowColors?: string[]\n backgroundColor?: string\n blendColor?: string\n fps?: number\n duration?: number\n scale?: number\n levels?: number\n padding?: number\n transparent?: boolean\n}\n\nexport async function generateAsciiGif(options: GenerateAsciiGifOptions): Promise<void> {\n const fps = options.fps ?? 24\n const duration = options.duration ?? 2.4\n const scale = options.scale ?? 2\n const levels = Math.max(2, Math.min(48, options.levels ?? 32))\n const padding = Math.max(0, Math.round(options.padding ?? 16))\n const fontRaw = resolveFont(options.font ?? \"dosrebel\")\n const font = parseFigletFont(fontRaw)\n const layout = composeAsciiText(font, options.text)\n const bounds = getLayoutBounds(layout)\n const accentColumns = getAsciiAccentColumns(font, options.text, options.accent ?? \"\")\n const width = Math.ceil(bounds.cols * ASCII_CHAR_WIDTH * scale) + padding * 2\n const height = bounds.rows * ASCII_CHAR_HEIGHT * scale + padding * 2\n const frameCount = Math.max(1, Math.round(fps * duration))\n const delay = Math.max(1, Math.round(100 / fps))\n const frames: Uint8Array[] = []\n\n // Row-colors path — one palette set per unique row color, applied by cell.row\n if (options.rowColors && options.rowColors.length > 0) {\n const uniqueRowColors = [...new Set(options.rowColors)]\n const rowPalette = createRowColorPalette({\n backgroundColor: options.backgroundColor ?? \"#0a0a0a\",\n blendColor: options.blendColor ?? options.backgroundColor ?? \"#0a0a0a\",\n rowColors: uniqueRowColors,\n levels,\n transparent: options.transparent ?? false,\n })\n for (let frame = 0; frame < frameCount; frame++) {\n frames.push(\n renderIndexedAsciiFrameWithRowColors({\n layout,\n phase: frame / frameCount,\n width,\n height,\n scale,\n levels,\n bounds,\n padding,\n rowColorsInput: options.rowColors,\n uniqueRowColors,\n }),\n )\n }\n const bytes = encodeGif({\n width,\n height,\n delay,\n palette: rowPalette.table,\n frames,\n transparent: options.transparent ?? false,\n })\n mkdirSync(path.dirname(options.outputPath), { recursive: true })\n writeFileSync(options.outputPath, bytes)\n return\n }\n\n const palette = createPalette({\n backgroundColor: options.backgroundColor ?? \"#0a0a0a\",\n blendColor: options.blendColor ?? options.backgroundColor ?? \"#0a0a0a\",\n color: options.color ?? \"#e5e5e5\",\n accentColor: options.accentColor ?? options.color ?? \"#38bdf8\",\n levels,\n transparent: options.transparent ?? false,\n })\n\n for (let frame = 0; frame < frameCount; frame++) {\n frames.push(\n renderIndexedAsciiFrame({\n layout,\n accentColumns,\n phase: frame / frameCount,\n width,\n height,\n scale,\n levels,\n bounds,\n padding,\n }),\n )\n }\n\n const bytes = encodeGif({\n width,\n height,\n delay,\n palette: palette.table,\n frames,\n transparent: options.transparent ?? false,\n })\n\n mkdirSync(path.dirname(options.outputPath), { recursive: true })\n writeFileSync(options.outputPath, bytes)\n}\n\ninterface RenderIndexedFrameOptions {\n layout: AsciiTextLayout\n accentColumns: ReadonlySet<number>\n phase: number\n width: number\n height: number\n scale: number\n levels: number\n bounds: LayoutBounds\n padding: number\n}\n\ninterface LayoutBounds {\n minCol: number\n minRow: number\n cols: number\n rows: number\n}\n\nfunction renderIndexedAsciiFrame(options: RenderIndexedFrameOptions): Uint8Array {\n const pixels = new Uint8Array(options.width * options.height)\n const charWidth = Math.round(ASCII_CHAR_WIDTH * options.scale)\n const charHeight = Math.round(ASCII_CHAR_HEIGHT * options.scale)\n\n for (const cell of options.layout.cells) {\n const intensity = getAsciiCellIntensity(cell, { phase: options.phase })\n const level = Math.max(0, Math.min(options.levels - 1, Math.round(intensity * (options.levels - 1))))\n const offset = options.accentColumns.has(cell.col) ? 1 + options.levels : 1\n const colorIndex = offset + level\n const x0 = options.padding + Math.round((cell.col - options.bounds.minCol) * ASCII_CHAR_WIDTH * options.scale)\n const y0 = options.padding + (cell.row - options.bounds.minRow) * charHeight\n const x1 = Math.min(options.width, x0 + charWidth)\n const y1 = Math.min(options.height, y0 + charHeight)\n\n for (let y = y0; y < y1; y++) {\n const row = y * options.width\n for (let x = x0; x < x1; x++) {\n pixels[row + x] = colorIndex\n }\n }\n }\n\n return pixels\n}\n\ninterface RenderWithRowColorsOptions {\n layout: AsciiTextLayout\n phase: number\n width: number\n height: number\n scale: number\n levels: number\n bounds: LayoutBounds\n padding: number\n rowColorsInput: string[]\n uniqueRowColors: string[]\n}\n\nfunction renderIndexedAsciiFrameWithRowColors(options: RenderWithRowColorsOptions): Uint8Array {\n const pixels = new Uint8Array(options.width * options.height)\n const charWidth = Math.round(ASCII_CHAR_WIDTH * options.scale)\n const charHeight = Math.round(ASCII_CHAR_HEIGHT * options.scale)\n\n for (const cell of options.layout.cells) {\n const intensity = getAsciiCellIntensity(cell, { phase: options.phase })\n const level = Math.max(0, Math.min(options.levels - 1, Math.round(intensity * (options.levels - 1))))\n const rowColor = options.rowColorsInput[cell.row % options.rowColorsInput.length] ?? options.rowColorsInput[0]!\n const colorSetIndex = Math.max(0, options.uniqueRowColors.indexOf(rowColor))\n const colorIndex = 1 + colorSetIndex * options.levels + level\n const x0 = options.padding + Math.round((cell.col - options.bounds.minCol) * ASCII_CHAR_WIDTH * options.scale)\n const y0 = options.padding + (cell.row - options.bounds.minRow) * charHeight\n const x1 = Math.min(options.width, x0 + charWidth)\n const y1 = Math.min(options.height, y0 + charHeight)\n for (let y = y0; y < y1; y++) {\n const row = y * options.width\n for (let x = x0; x < x1; x++) {\n pixels[row + x] = colorIndex\n }\n }\n }\n\n return pixels\n}\n\nfunction createRowColorPalette(options: {\n backgroundColor: string\n blendColor: string\n rowColors: string[]\n levels: number\n transparent: boolean\n}) {\n const bg = parseColor(options.backgroundColor)\n const blend = parseColor(options.blendColor)\n const table: number[] = [bg.r, bg.g, bg.b]\n\n for (const colorHex of options.rowColors) {\n const color = parseColor(colorHex)\n for (let level = 0; level < options.levels; level++) {\n const alpha = level / (options.levels - 1)\n const mixed = mix(blend, color, alpha)\n table.push(mixed.r, mixed.g, mixed.b)\n }\n }\n\n while (table.length < 256 * 3) table.push(0, 0, 0)\n return { table: Uint8Array.from(table.slice(0, 256 * 3)) }\n}\n\nfunction getLayoutBounds(layout: AsciiTextLayout): LayoutBounds {\n if (layout.cells.length === 0) {\n return { minCol: 0, minRow: 0, cols: Math.max(1, layout.cols), rows: Math.max(1, layout.rows) }\n }\n\n let minCol = Number.POSITIVE_INFINITY\n let maxCol = Number.NEGATIVE_INFINITY\n let minRow = Number.POSITIVE_INFINITY\n let maxRow = Number.NEGATIVE_INFINITY\n\n for (const cell of layout.cells) {\n minCol = Math.min(minCol, cell.col)\n maxCol = Math.max(maxCol, cell.col)\n minRow = Math.min(minRow, cell.row)\n maxRow = Math.max(maxRow, cell.row)\n }\n\n return {\n minCol,\n minRow,\n cols: maxCol - minCol + 1,\n rows: maxRow - minRow + 1,\n }\n}\n\nfunction resolveFont(font: AsciiFontName | string): string {\n if (font in asciiFonts) return asciiFonts[font as AsciiFontName]\n return readFileSync(font, \"utf-8\")\n}\n\nfunction createPalette(options: {\n backgroundColor: string\n blendColor: string\n color: string\n accentColor: string\n levels: number\n transparent: boolean\n}) {\n const bg = parseColor(options.backgroundColor)\n const blend = parseColor(options.blendColor)\n const base = parseColor(options.color)\n const accent = parseColor(options.accentColor)\n const table: number[] = [bg.r, bg.g, bg.b]\n\n for (let level = 0; level < options.levels; level++) {\n const alpha = level / (options.levels - 1)\n const mixed = mix(blend, base, alpha)\n table.push(mixed.r, mixed.g, mixed.b)\n }\n\n for (let level = 0; level < options.levels; level++) {\n const alpha = level / (options.levels - 1)\n const mixed = mix(blend, accent, alpha)\n table.push(mixed.r, mixed.g, mixed.b)\n }\n\n while (table.length < 256 * 3) table.push(0, 0, 0)\n return { table: Uint8Array.from(table.slice(0, 256 * 3)) }\n}\n\nfunction parseColor(input: string): RGB {\n const color = input.trim()\n const shortHex = /^#([0-9a-f]{3})$/i.exec(color)\n if (shortHex) {\n const [r, g, b] = shortHex[1].split(\"\").map((part) => Number.parseInt(part + part, 16))\n return { r, g, b }\n }\n\n const longHex = /^#([0-9a-f]{6})$/i.exec(color)\n if (longHex) {\n const value = longHex[1]\n return {\n r: Number.parseInt(value.slice(0, 2), 16),\n g: Number.parseInt(value.slice(2, 4), 16),\n b: Number.parseInt(value.slice(4, 6), 16),\n }\n }\n\n const rgb = /^rgb\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*\\)$/i.exec(color)\n if (rgb) {\n return {\n r: clampByte(Number.parseInt(rgb[1], 10)),\n g: clampByte(Number.parseInt(rgb[2], 10)),\n b: clampByte(Number.parseInt(rgb[3], 10)),\n }\n }\n\n throw new Error(`Unsupported color \"${input}\". Use #rgb, #rrggbb, or rgb(r,g,b).`)\n}\n\nfunction mix(a: RGB, b: RGB, amount: number): RGB {\n return {\n r: clampByte(a.r + (b.r - a.r) * amount),\n g: clampByte(a.g + (b.g - a.g) * amount),\n b: clampByte(a.b + (b.b - a.b) * amount),\n }\n}\n\nfunction clampByte(value: number): number {\n return Math.max(0, Math.min(255, Math.round(value)))\n}\n\ninterface EncodeGifOptions {\n width: number\n height: number\n delay: number\n palette: Uint8Array\n frames: Uint8Array[]\n transparent: boolean\n}\n\nfunction encodeGif(options: EncodeGifOptions): Uint8Array {\n const bytes: number[] = []\n writeAscii(bytes, \"GIF89a\")\n writeU16(bytes, options.width)\n writeU16(bytes, options.height)\n bytes.push(0xf7, 0, 0)\n pushBytes(bytes, options.palette)\n bytes.push(0x21, 0xff, 0x0b)\n writeAscii(bytes, \"NETSCAPE2.0\")\n bytes.push(0x03, 0x01)\n writeU16(bytes, 0)\n bytes.push(0)\n\n for (const frame of options.frames) {\n bytes.push(0x21, 0xf9, 0x04, options.transparent ? 0x05 : 0x04)\n writeU16(bytes, options.delay)\n bytes.push(0, 0)\n bytes.push(0x2c)\n writeU16(bytes, 0)\n writeU16(bytes, 0)\n writeU16(bytes, options.width)\n writeU16(bytes, options.height)\n bytes.push(0)\n bytes.push(8)\n writeSubBlocks(bytes, lzwEncode(frame, 8))\n }\n\n bytes.push(0x3b)\n return Uint8Array.from(bytes)\n}\n\nfunction lzwEncode(indices: Uint8Array, minCodeSize: number): Uint8Array {\n const clearCode = 1 << minCodeSize\n const endCode = clearCode + 1\n let codeSize = minCodeSize + 1\n const output: number[] = []\n const writeCode = createBitWriter(output)\n\n writeCode(clearCode, codeSize)\n\n let codesSinceClear = 0\n for (const index of indices) {\n if (codesSinceClear >= 240) {\n writeCode(clearCode, codeSize)\n codeSize = minCodeSize + 1\n codesSinceClear = 0\n }\n writeCode(index, codeSize)\n codesSinceClear++\n }\n\n writeCode(endCode, codeSize)\n writeCode(-1, 0)\n\n return Uint8Array.from(output)\n}\n\nfunction createBitWriter(output: number[]) {\n let buffer = 0\n let bitCount = 0\n\n return (code: number, size: number) => {\n if (code < 0) {\n if (bitCount > 0) output.push(buffer & 0xff)\n buffer = 0\n bitCount = 0\n return\n }\n\n buffer |= code << bitCount\n bitCount += size\n\n while (bitCount >= 8) {\n output.push(buffer & 0xff)\n buffer >>= 8\n bitCount -= 8\n }\n }\n}\n\nfunction writeSubBlocks(bytes: number[], data: Uint8Array) {\n for (let offset = 0; offset < data.length; offset += 255) {\n const chunk = data.slice(offset, offset + 255)\n bytes.push(chunk.length)\n pushBytes(bytes, chunk)\n }\n bytes.push(0)\n}\n\nfunction writeAscii(bytes: number[], value: string) {\n for (let i = 0; i < value.length; i++) bytes.push(value.charCodeAt(i))\n}\n\nfunction writeU16(bytes: number[], value: number) {\n bytes.push(value & 0xff, (value >> 8) & 0xff)\n}\n\nfunction pushBytes(bytes: number[], values: Uint8Array) {\n for (const value of values) bytes.push(value)\n}\n"]}
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { mkdirSync, writeFileSync, readFileSync } from 'fs';
|
|
3
3
|
import path, { join } from 'path';
|
|
4
|
+
import { createRequire } from 'module';
|
|
4
5
|
import { createInterface } from 'readline/promises';
|
|
5
6
|
import { stdout, stdin } from 'process';
|
|
6
7
|
|
|
@@ -1367,6 +1368,48 @@ async function generateAsciiGif(options) {
|
|
|
1367
1368
|
const layout = composeAsciiText(font, options.text);
|
|
1368
1369
|
const bounds = getLayoutBounds(layout);
|
|
1369
1370
|
const accentColumns = getAsciiAccentColumns(font, options.text, options.accent ?? "");
|
|
1371
|
+
const width = Math.ceil(bounds.cols * ASCII_CHAR_WIDTH * scale) + padding * 2;
|
|
1372
|
+
const height = bounds.rows * ASCII_CHAR_HEIGHT * scale + padding * 2;
|
|
1373
|
+
const frameCount = Math.max(1, Math.round(fps * duration));
|
|
1374
|
+
const delay = Math.max(1, Math.round(100 / fps));
|
|
1375
|
+
const frames = [];
|
|
1376
|
+
if (options.rowColors && options.rowColors.length > 0) {
|
|
1377
|
+
const uniqueRowColors = [...new Set(options.rowColors)];
|
|
1378
|
+
const rowPalette = createRowColorPalette({
|
|
1379
|
+
backgroundColor: options.backgroundColor ?? "#0a0a0a",
|
|
1380
|
+
blendColor: options.blendColor ?? options.backgroundColor ?? "#0a0a0a",
|
|
1381
|
+
rowColors: uniqueRowColors,
|
|
1382
|
+
levels,
|
|
1383
|
+
transparent: options.transparent ?? false
|
|
1384
|
+
});
|
|
1385
|
+
for (let frame = 0; frame < frameCount; frame++) {
|
|
1386
|
+
frames.push(
|
|
1387
|
+
renderIndexedAsciiFrameWithRowColors({
|
|
1388
|
+
layout,
|
|
1389
|
+
phase: frame / frameCount,
|
|
1390
|
+
width,
|
|
1391
|
+
height,
|
|
1392
|
+
scale,
|
|
1393
|
+
levels,
|
|
1394
|
+
bounds,
|
|
1395
|
+
padding,
|
|
1396
|
+
rowColorsInput: options.rowColors,
|
|
1397
|
+
uniqueRowColors
|
|
1398
|
+
})
|
|
1399
|
+
);
|
|
1400
|
+
}
|
|
1401
|
+
const bytes2 = encodeGif({
|
|
1402
|
+
width,
|
|
1403
|
+
height,
|
|
1404
|
+
delay,
|
|
1405
|
+
palette: rowPalette.table,
|
|
1406
|
+
frames,
|
|
1407
|
+
transparent: options.transparent ?? false
|
|
1408
|
+
});
|
|
1409
|
+
mkdirSync(path.dirname(options.outputPath), { recursive: true });
|
|
1410
|
+
writeFileSync(options.outputPath, bytes2);
|
|
1411
|
+
return;
|
|
1412
|
+
}
|
|
1370
1413
|
const palette = createPalette({
|
|
1371
1414
|
backgroundColor: options.backgroundColor ?? "#0a0a0a",
|
|
1372
1415
|
blendColor: options.blendColor ?? options.backgroundColor ?? "#0a0a0a",
|
|
@@ -1375,11 +1418,6 @@ async function generateAsciiGif(options) {
|
|
|
1375
1418
|
levels,
|
|
1376
1419
|
transparent: options.transparent ?? false
|
|
1377
1420
|
});
|
|
1378
|
-
const width = Math.ceil(bounds.cols * ASCII_CHAR_WIDTH * scale) + padding * 2;
|
|
1379
|
-
const height = bounds.rows * ASCII_CHAR_HEIGHT * scale + padding * 2;
|
|
1380
|
-
const frameCount = Math.max(1, Math.round(fps * duration));
|
|
1381
|
-
const delay = Math.max(1, Math.round(100 / fps));
|
|
1382
|
-
const frames = [];
|
|
1383
1421
|
for (let frame = 0; frame < frameCount; frame++) {
|
|
1384
1422
|
frames.push(
|
|
1385
1423
|
renderIndexedAsciiFrame({
|
|
@@ -1428,6 +1466,44 @@ function renderIndexedAsciiFrame(options) {
|
|
|
1428
1466
|
}
|
|
1429
1467
|
return pixels;
|
|
1430
1468
|
}
|
|
1469
|
+
function renderIndexedAsciiFrameWithRowColors(options) {
|
|
1470
|
+
const pixels = new Uint8Array(options.width * options.height);
|
|
1471
|
+
const charWidth = Math.round(ASCII_CHAR_WIDTH * options.scale);
|
|
1472
|
+
const charHeight = Math.round(ASCII_CHAR_HEIGHT * options.scale);
|
|
1473
|
+
for (const cell of options.layout.cells) {
|
|
1474
|
+
const intensity = getAsciiCellIntensity(cell, { phase: options.phase });
|
|
1475
|
+
const level = Math.max(0, Math.min(options.levels - 1, Math.round(intensity * (options.levels - 1))));
|
|
1476
|
+
const rowColor = options.rowColorsInput[cell.row % options.rowColorsInput.length] ?? options.rowColorsInput[0];
|
|
1477
|
+
const colorSetIndex = Math.max(0, options.uniqueRowColors.indexOf(rowColor));
|
|
1478
|
+
const colorIndex = 1 + colorSetIndex * options.levels + level;
|
|
1479
|
+
const x0 = options.padding + Math.round((cell.col - options.bounds.minCol) * ASCII_CHAR_WIDTH * options.scale);
|
|
1480
|
+
const y0 = options.padding + (cell.row - options.bounds.minRow) * charHeight;
|
|
1481
|
+
const x1 = Math.min(options.width, x0 + charWidth);
|
|
1482
|
+
const y1 = Math.min(options.height, y0 + charHeight);
|
|
1483
|
+
for (let y = y0; y < y1; y++) {
|
|
1484
|
+
const row = y * options.width;
|
|
1485
|
+
for (let x = x0; x < x1; x++) {
|
|
1486
|
+
pixels[row + x] = colorIndex;
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
return pixels;
|
|
1491
|
+
}
|
|
1492
|
+
function createRowColorPalette(options) {
|
|
1493
|
+
const bg = parseColor(options.backgroundColor);
|
|
1494
|
+
const blend = parseColor(options.blendColor);
|
|
1495
|
+
const table = [bg.r, bg.g, bg.b];
|
|
1496
|
+
for (const colorHex of options.rowColors) {
|
|
1497
|
+
const color = parseColor(colorHex);
|
|
1498
|
+
for (let level = 0; level < options.levels; level++) {
|
|
1499
|
+
const alpha = level / (options.levels - 1);
|
|
1500
|
+
const mixed = mix(blend, color, alpha);
|
|
1501
|
+
table.push(mixed.r, mixed.g, mixed.b);
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
while (table.length < 256 * 3) table.push(0, 0, 0);
|
|
1505
|
+
return { table: Uint8Array.from(table.slice(0, 256 * 3)) };
|
|
1506
|
+
}
|
|
1431
1507
|
function getLayoutBounds(layout) {
|
|
1432
1508
|
if (layout.cells.length === 0) {
|
|
1433
1509
|
return { minCol: 0, minRow: 0, cols: Math.max(1, layout.cols), rows: Math.max(1, layout.rows) };
|
|
@@ -1598,15 +1674,146 @@ var init_ascii_gif = __esm({
|
|
|
1598
1674
|
init_ascii();
|
|
1599
1675
|
}
|
|
1600
1676
|
});
|
|
1677
|
+
|
|
1678
|
+
// src/generate-assets.ts
|
|
1679
|
+
var generate_assets_exports = {};
|
|
1680
|
+
__export(generate_assets_exports, {
|
|
1681
|
+
generateAssets: () => generateAssets
|
|
1682
|
+
});
|
|
1683
|
+
function toKebabCase(name) {
|
|
1684
|
+
return name.replace(/([A-Z])/g, (_, ch) => `-${ch.toLowerCase()}`).replace(/^-/, "").toLowerCase();
|
|
1685
|
+
}
|
|
1686
|
+
function escapeXml(str) {
|
|
1687
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1688
|
+
}
|
|
1689
|
+
function getLucideIconInner(iconName) {
|
|
1690
|
+
const kebab = toKebabCase(iconName);
|
|
1691
|
+
const req = createRequire(import.meta.url);
|
|
1692
|
+
let iconPath;
|
|
1693
|
+
try {
|
|
1694
|
+
iconPath = req.resolve(`lucide-static/icons/${kebab}.svg`);
|
|
1695
|
+
} catch {
|
|
1696
|
+
throw new Error(
|
|
1697
|
+
`Unknown Lucide icon: "${iconName}" (tried "${kebab}.svg"). Browse icons at https://lucide.dev/icons`
|
|
1698
|
+
);
|
|
1699
|
+
}
|
|
1700
|
+
const svg = readFileSync(iconPath, "utf-8");
|
|
1701
|
+
return svg.replace(/<svg[^>]*>/, "").replace(/<\/svg>/, "").replace(/\sstroke="currentColor"/g, "").replace(/\sfill="none"/g, "").trim();
|
|
1702
|
+
}
|
|
1703
|
+
function buildIconSvg(inner, color, size) {
|
|
1704
|
+
const pad = Math.round(size * 0.18);
|
|
1705
|
+
const area = size - pad * 2;
|
|
1706
|
+
const scale = area / 24;
|
|
1707
|
+
const rx = Math.round(size * 0.16);
|
|
1708
|
+
const sw = (2 / scale).toFixed(4);
|
|
1709
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}">
|
|
1710
|
+
<rect width="${size}" height="${size}" rx="${rx}" fill="${color}"/>
|
|
1711
|
+
<g transform="translate(${pad} ${pad}) scale(${scale})" stroke="white" fill="none" stroke-width="${sw}" stroke-linecap="round" stroke-linejoin="round">
|
|
1712
|
+
${inner}
|
|
1713
|
+
</g>
|
|
1714
|
+
</svg>`;
|
|
1715
|
+
}
|
|
1716
|
+
function buildOgSvg(inner, name, color) {
|
|
1717
|
+
const iconPx = 180;
|
|
1718
|
+
const iconX = Math.round((1200 - iconPx) / 2);
|
|
1719
|
+
const iconY = 160;
|
|
1720
|
+
const scale = iconPx / 24;
|
|
1721
|
+
const sw = (2.5 / scale).toFixed(4);
|
|
1722
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="630">
|
|
1723
|
+
<defs>
|
|
1724
|
+
<radialGradient id="rg" cx="50%" cy="40%" r="65%">
|
|
1725
|
+
<stop offset="0%" stop-color="${color}" stop-opacity="0.22"/>
|
|
1726
|
+
<stop offset="100%" stop-color="#000000" stop-opacity="0"/>
|
|
1727
|
+
</radialGradient>
|
|
1728
|
+
</defs>
|
|
1729
|
+
<rect width="1200" height="630" fill="#09090b"/>
|
|
1730
|
+
<rect width="1200" height="630" fill="url(#rg)"/>
|
|
1731
|
+
<g transform="translate(${iconX} ${iconY}) scale(${scale})" stroke="${color}" fill="none" stroke-width="${sw}" stroke-linecap="round" stroke-linejoin="round">
|
|
1732
|
+
${inner}
|
|
1733
|
+
</g>
|
|
1734
|
+
<text x="600" y="470" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" font-size="72" font-weight="700" fill="white" text-anchor="middle" letter-spacing="-1">${escapeXml(name)}</text>
|
|
1735
|
+
</svg>`;
|
|
1736
|
+
}
|
|
1737
|
+
async function generateAssets(config) {
|
|
1738
|
+
const { name, icon, color, outputDir } = config;
|
|
1739
|
+
let sharpFn;
|
|
1740
|
+
try {
|
|
1741
|
+
sharpFn = (await import('sharp')).default;
|
|
1742
|
+
} catch {
|
|
1743
|
+
throw new Error(
|
|
1744
|
+
"sharp is required for asset generation.\nInstall it in your project: bun add sharp lucide-static"
|
|
1745
|
+
);
|
|
1746
|
+
}
|
|
1747
|
+
mkdirSync(outputDir, { recursive: true });
|
|
1748
|
+
const faviconDir = join(outputDir, "favicon");
|
|
1749
|
+
mkdirSync(faviconDir, { recursive: true });
|
|
1750
|
+
const inner = getLucideIconInner(icon);
|
|
1751
|
+
const written = [];
|
|
1752
|
+
for (const size of FAVICON_SIZES) {
|
|
1753
|
+
const svg = buildIconSvg(inner, color, size);
|
|
1754
|
+
const png = await sharpFn(Buffer.from(svg)).png().toBuffer();
|
|
1755
|
+
const dest = join(faviconDir, `favicon-${size}.png`);
|
|
1756
|
+
writeFileSync(dest, png);
|
|
1757
|
+
written.push(dest);
|
|
1758
|
+
}
|
|
1759
|
+
for (const [filename, size] of NAMED_ICONS) {
|
|
1760
|
+
const svg = buildIconSvg(inner, color, size);
|
|
1761
|
+
const png = await sharpFn(Buffer.from(svg)).png().toBuffer();
|
|
1762
|
+
const dest = join(outputDir, filename);
|
|
1763
|
+
writeFileSync(dest, png);
|
|
1764
|
+
written.push(dest);
|
|
1765
|
+
}
|
|
1766
|
+
const ogSvg = buildOgSvg(inner, name, color);
|
|
1767
|
+
const ogPng = await sharpFn(Buffer.from(ogSvg)).png().toBuffer();
|
|
1768
|
+
const ogDest = join(outputDir, "og-image.png");
|
|
1769
|
+
writeFileSync(ogDest, ogPng);
|
|
1770
|
+
written.push(ogDest);
|
|
1771
|
+
const manifest = {
|
|
1772
|
+
name,
|
|
1773
|
+
short_name: name,
|
|
1774
|
+
theme_color: color,
|
|
1775
|
+
background_color: "#09090b",
|
|
1776
|
+
display: "standalone",
|
|
1777
|
+
icons: [
|
|
1778
|
+
{ src: "/android-chrome-192x192.png", sizes: "192x192", type: "image/png" },
|
|
1779
|
+
{
|
|
1780
|
+
src: "/android-chrome-512x512.png",
|
|
1781
|
+
sizes: "512x512",
|
|
1782
|
+
type: "image/png",
|
|
1783
|
+
purpose: "maskable"
|
|
1784
|
+
}
|
|
1785
|
+
]
|
|
1786
|
+
};
|
|
1787
|
+
const manifestDest = join(outputDir, "manifest.json");
|
|
1788
|
+
writeFileSync(manifestDest, JSON.stringify(manifest, null, 2) + "\n");
|
|
1789
|
+
written.push(manifestDest);
|
|
1790
|
+
const robotsDest = join(outputDir, "robots.txt");
|
|
1791
|
+
writeFileSync(robotsDest, "User-agent: *\nAllow: /\n");
|
|
1792
|
+
written.push(robotsDest);
|
|
1793
|
+
return { files: written };
|
|
1794
|
+
}
|
|
1795
|
+
var FAVICON_SIZES, NAMED_ICONS;
|
|
1796
|
+
var init_generate_assets = __esm({
|
|
1797
|
+
"src/generate-assets.ts"() {
|
|
1798
|
+
FAVICON_SIZES = [16, 32, 48, 64];
|
|
1799
|
+
NAMED_ICONS = [
|
|
1800
|
+
["apple-touch-icon.png", 180],
|
|
1801
|
+
["android-chrome-192x192.png", 192],
|
|
1802
|
+
["android-chrome-512x512.png", 512]
|
|
1803
|
+
];
|
|
1804
|
+
}
|
|
1805
|
+
});
|
|
1601
1806
|
var DEFAULT_SOURCE = "https://olwiba.com/skills/manifest.json";
|
|
1602
1807
|
var [command, subcommand] = process.argv.slice(2);
|
|
1603
1808
|
if (command === "skills" && subcommand === "install") {
|
|
1604
1809
|
await runSkillsInstall();
|
|
1605
1810
|
} else if (command === "ascii-gif") {
|
|
1606
1811
|
await runAsciiGif();
|
|
1812
|
+
} else if (command === "generate-assets") {
|
|
1813
|
+
await runGenerateAssets();
|
|
1607
1814
|
} else {
|
|
1608
1815
|
process.stdout.write(
|
|
1609
|
-
"Usage:\n dx skills install [--source <url>] [--target claude|amp] [--all] [--name a,b,c]\n dx ascii-gif --text <text> --out <file.gif>\n"
|
|
1816
|
+
"Usage:\n dx skills install [--source <url>] [--target claude|amp] [--all] [--name a,b,c]\n dx ascii-gif --text <text> --out <file.gif>\n dx generate-assets --name <app> --icon <lucide-icon> --color <#hex> [--out <dir>]\n"
|
|
1610
1817
|
);
|
|
1611
1818
|
}
|
|
1612
1819
|
async function runSkillsInstall() {
|
|
@@ -1763,6 +1970,35 @@ function parseFlags(args) {
|
|
|
1763
1970
|
}
|
|
1764
1971
|
return flags;
|
|
1765
1972
|
}
|
|
1973
|
+
async function runGenerateAssets() {
|
|
1974
|
+
const { generateAssets: generateAssets2 } = await Promise.resolve().then(() => (init_generate_assets(), generate_assets_exports));
|
|
1975
|
+
const flags = parseFlags(process.argv.slice(3));
|
|
1976
|
+
const name = flags.name;
|
|
1977
|
+
const icon = flags.icon;
|
|
1978
|
+
const color = flags.color;
|
|
1979
|
+
const outputDir = flags.out ?? flags.output ?? "public";
|
|
1980
|
+
if (!name || !icon || !color) {
|
|
1981
|
+
process.stderr.write(
|
|
1982
|
+
"Usage: dx generate-assets --name <app> --icon <lucide-icon> --color <#hex> [--out <dir>]\n"
|
|
1983
|
+
);
|
|
1984
|
+
process.exitCode = 1;
|
|
1985
|
+
return;
|
|
1986
|
+
}
|
|
1987
|
+
process.stdout.write(`Generating assets for "${name}"\u2026
|
|
1988
|
+
`);
|
|
1989
|
+
try {
|
|
1990
|
+
const result = await generateAssets2({ name, icon, color, outputDir });
|
|
1991
|
+
process.stdout.write(`Generated ${result.files.length} files in ${outputDir}/
|
|
1992
|
+
`);
|
|
1993
|
+
for (const f of result.files) process.stdout.write(` ${f}
|
|
1994
|
+
`);
|
|
1995
|
+
} catch (err) {
|
|
1996
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1997
|
+
process.stderr.write(`Error: ${message}
|
|
1998
|
+
`);
|
|
1999
|
+
process.exitCode = 1;
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
1766
2002
|
function parseNumberFlag(value) {
|
|
1767
2003
|
if (value == null) return void 0;
|
|
1768
2004
|
const parsed = Number(value);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface GenerateAssetsConfig {
|
|
2
|
+
name: string;
|
|
3
|
+
icon: string;
|
|
4
|
+
color: string;
|
|
5
|
+
outputDir: string;
|
|
6
|
+
}
|
|
7
|
+
interface GenerateAssetsResult {
|
|
8
|
+
files: string[];
|
|
9
|
+
}
|
|
10
|
+
declare function generateAssets(config: GenerateAssetsConfig): Promise<GenerateAssetsResult>;
|
|
11
|
+
|
|
12
|
+
export { type GenerateAssetsConfig, type GenerateAssetsResult, generateAssets };
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync, readFileSync } from 'fs';
|
|
2
|
+
import { createRequire } from 'module';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
|
|
5
|
+
// src/generate-assets.ts
|
|
6
|
+
function toKebabCase(name) {
|
|
7
|
+
return name.replace(/([A-Z])/g, (_, ch) => `-${ch.toLowerCase()}`).replace(/^-/, "").toLowerCase();
|
|
8
|
+
}
|
|
9
|
+
function escapeXml(str) {
|
|
10
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
11
|
+
}
|
|
12
|
+
function getLucideIconInner(iconName) {
|
|
13
|
+
const kebab = toKebabCase(iconName);
|
|
14
|
+
const req = createRequire(import.meta.url);
|
|
15
|
+
let iconPath;
|
|
16
|
+
try {
|
|
17
|
+
iconPath = req.resolve(`lucide-static/icons/${kebab}.svg`);
|
|
18
|
+
} catch {
|
|
19
|
+
throw new Error(
|
|
20
|
+
`Unknown Lucide icon: "${iconName}" (tried "${kebab}.svg"). Browse icons at https://lucide.dev/icons`
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
const svg = readFileSync(iconPath, "utf-8");
|
|
24
|
+
return svg.replace(/<svg[^>]*>/, "").replace(/<\/svg>/, "").replace(/\sstroke="currentColor"/g, "").replace(/\sfill="none"/g, "").trim();
|
|
25
|
+
}
|
|
26
|
+
function buildIconSvg(inner, color, size) {
|
|
27
|
+
const pad = Math.round(size * 0.18);
|
|
28
|
+
const area = size - pad * 2;
|
|
29
|
+
const scale = area / 24;
|
|
30
|
+
const rx = Math.round(size * 0.16);
|
|
31
|
+
const sw = (2 / scale).toFixed(4);
|
|
32
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}">
|
|
33
|
+
<rect width="${size}" height="${size}" rx="${rx}" fill="${color}"/>
|
|
34
|
+
<g transform="translate(${pad} ${pad}) scale(${scale})" stroke="white" fill="none" stroke-width="${sw}" stroke-linecap="round" stroke-linejoin="round">
|
|
35
|
+
${inner}
|
|
36
|
+
</g>
|
|
37
|
+
</svg>`;
|
|
38
|
+
}
|
|
39
|
+
function buildOgSvg(inner, name, color) {
|
|
40
|
+
const iconPx = 180;
|
|
41
|
+
const iconX = Math.round((1200 - iconPx) / 2);
|
|
42
|
+
const iconY = 160;
|
|
43
|
+
const scale = iconPx / 24;
|
|
44
|
+
const sw = (2.5 / scale).toFixed(4);
|
|
45
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="630">
|
|
46
|
+
<defs>
|
|
47
|
+
<radialGradient id="rg" cx="50%" cy="40%" r="65%">
|
|
48
|
+
<stop offset="0%" stop-color="${color}" stop-opacity="0.22"/>
|
|
49
|
+
<stop offset="100%" stop-color="#000000" stop-opacity="0"/>
|
|
50
|
+
</radialGradient>
|
|
51
|
+
</defs>
|
|
52
|
+
<rect width="1200" height="630" fill="#09090b"/>
|
|
53
|
+
<rect width="1200" height="630" fill="url(#rg)"/>
|
|
54
|
+
<g transform="translate(${iconX} ${iconY}) scale(${scale})" stroke="${color}" fill="none" stroke-width="${sw}" stroke-linecap="round" stroke-linejoin="round">
|
|
55
|
+
${inner}
|
|
56
|
+
</g>
|
|
57
|
+
<text x="600" y="470" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif" font-size="72" font-weight="700" fill="white" text-anchor="middle" letter-spacing="-1">${escapeXml(name)}</text>
|
|
58
|
+
</svg>`;
|
|
59
|
+
}
|
|
60
|
+
var FAVICON_SIZES = [16, 32, 48, 64];
|
|
61
|
+
var NAMED_ICONS = [
|
|
62
|
+
["apple-touch-icon.png", 180],
|
|
63
|
+
["android-chrome-192x192.png", 192],
|
|
64
|
+
["android-chrome-512x512.png", 512]
|
|
65
|
+
];
|
|
66
|
+
async function generateAssets(config) {
|
|
67
|
+
const { name, icon, color, outputDir } = config;
|
|
68
|
+
let sharpFn;
|
|
69
|
+
try {
|
|
70
|
+
sharpFn = (await import('sharp')).default;
|
|
71
|
+
} catch {
|
|
72
|
+
throw new Error(
|
|
73
|
+
"sharp is required for asset generation.\nInstall it in your project: bun add sharp lucide-static"
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
mkdirSync(outputDir, { recursive: true });
|
|
77
|
+
const faviconDir = join(outputDir, "favicon");
|
|
78
|
+
mkdirSync(faviconDir, { recursive: true });
|
|
79
|
+
const inner = getLucideIconInner(icon);
|
|
80
|
+
const written = [];
|
|
81
|
+
for (const size of FAVICON_SIZES) {
|
|
82
|
+
const svg = buildIconSvg(inner, color, size);
|
|
83
|
+
const png = await sharpFn(Buffer.from(svg)).png().toBuffer();
|
|
84
|
+
const dest = join(faviconDir, `favicon-${size}.png`);
|
|
85
|
+
writeFileSync(dest, png);
|
|
86
|
+
written.push(dest);
|
|
87
|
+
}
|
|
88
|
+
for (const [filename, size] of NAMED_ICONS) {
|
|
89
|
+
const svg = buildIconSvg(inner, color, size);
|
|
90
|
+
const png = await sharpFn(Buffer.from(svg)).png().toBuffer();
|
|
91
|
+
const dest = join(outputDir, filename);
|
|
92
|
+
writeFileSync(dest, png);
|
|
93
|
+
written.push(dest);
|
|
94
|
+
}
|
|
95
|
+
const ogSvg = buildOgSvg(inner, name, color);
|
|
96
|
+
const ogPng = await sharpFn(Buffer.from(ogSvg)).png().toBuffer();
|
|
97
|
+
const ogDest = join(outputDir, "og-image.png");
|
|
98
|
+
writeFileSync(ogDest, ogPng);
|
|
99
|
+
written.push(ogDest);
|
|
100
|
+
const manifest = {
|
|
101
|
+
name,
|
|
102
|
+
short_name: name,
|
|
103
|
+
theme_color: color,
|
|
104
|
+
background_color: "#09090b",
|
|
105
|
+
display: "standalone",
|
|
106
|
+
icons: [
|
|
107
|
+
{ src: "/android-chrome-192x192.png", sizes: "192x192", type: "image/png" },
|
|
108
|
+
{
|
|
109
|
+
src: "/android-chrome-512x512.png",
|
|
110
|
+
sizes: "512x512",
|
|
111
|
+
type: "image/png",
|
|
112
|
+
purpose: "maskable"
|
|
113
|
+
}
|
|
114
|
+
]
|
|
115
|
+
};
|
|
116
|
+
const manifestDest = join(outputDir, "manifest.json");
|
|
117
|
+
writeFileSync(manifestDest, JSON.stringify(manifest, null, 2) + "\n");
|
|
118
|
+
written.push(manifestDest);
|
|
119
|
+
const robotsDest = join(outputDir, "robots.txt");
|
|
120
|
+
writeFileSync(robotsDest, "User-agent: *\nAllow: /\n");
|
|
121
|
+
written.push(robotsDest);
|
|
122
|
+
return { files: written };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export { generateAssets };
|
|
126
|
+
//# sourceMappingURL=generate-assets.js.map
|
|
127
|
+
//# sourceMappingURL=generate-assets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/generate-assets.ts"],"names":[],"mappings":"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","file":"generate-assets.js","sourcesContent":["import { mkdirSync, readFileSync, writeFileSync } from \"node:fs\"\nimport { createRequire } from \"node:module\"\nimport { join } from \"node:path\"\n\nexport interface GenerateAssetsConfig {\n name: string\n icon: string\n color: string\n outputDir: string\n}\n\nexport interface GenerateAssetsResult {\n files: string[]\n}\n\nfunction toKebabCase(name: string): string {\n return name\n .replace(/([A-Z])/g, (_, ch: string) => `-${ch.toLowerCase()}`)\n .replace(/^-/, \"\")\n .toLowerCase()\n}\n\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\")\n}\n\nfunction getLucideIconInner(iconName: string): string {\n const kebab = toKebabCase(iconName)\n const req = createRequire(import.meta.url)\n let iconPath: string\n try {\n iconPath = req.resolve(`lucide-static/icons/${kebab}.svg`)\n } catch {\n throw new Error(\n `Unknown Lucide icon: \"${iconName}\" (tried \"${kebab}.svg\"). ` +\n `Browse icons at https://lucide.dev/icons`,\n )\n }\n const svg = readFileSync(iconPath, \"utf-8\")\n // Strip outer <svg> wrapper; clear inherited stroke/fill so parent <g> controls them\n return svg\n .replace(/<svg[^>]*>/, \"\")\n .replace(/<\\/svg>/, \"\")\n .replace(/\\sstroke=\"currentColor\"/g, \"\")\n .replace(/\\sfill=\"none\"/g, \"\")\n .trim()\n}\n\nfunction buildIconSvg(inner: string, color: string, size: number): string {\n const pad = Math.round(size * 0.18)\n const area = size - pad * 2\n const scale = area / 24\n const rx = Math.round(size * 0.16)\n // Inverse-scale stroke so it renders at ~2px regardless of size\n const sw = (2 / scale).toFixed(4)\n\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${size}\" height=\"${size}\">\n <rect width=\"${size}\" height=\"${size}\" rx=\"${rx}\" fill=\"${color}\"/>\n <g transform=\"translate(${pad} ${pad}) scale(${scale})\" stroke=\"white\" fill=\"none\" stroke-width=\"${sw}\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n ${inner}\n </g>\n</svg>`\n}\n\nfunction buildOgSvg(inner: string, name: string, color: string): string {\n const iconPx = 180\n const iconX = Math.round((1200 - iconPx) / 2) // 510\n const iconY = 160\n const scale = iconPx / 24\n // ~2.5px strokes at final 180px icon size\n const sw = (2.5 / scale).toFixed(4)\n\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1200\" height=\"630\">\n <defs>\n <radialGradient id=\"rg\" cx=\"50%\" cy=\"40%\" r=\"65%\">\n <stop offset=\"0%\" stop-color=\"${color}\" stop-opacity=\"0.22\"/>\n <stop offset=\"100%\" stop-color=\"#000000\" stop-opacity=\"0\"/>\n </radialGradient>\n </defs>\n <rect width=\"1200\" height=\"630\" fill=\"#09090b\"/>\n <rect width=\"1200\" height=\"630\" fill=\"url(#rg)\"/>\n <g transform=\"translate(${iconX} ${iconY}) scale(${scale})\" stroke=\"${color}\" fill=\"none\" stroke-width=\"${sw}\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n ${inner}\n </g>\n <text x=\"600\" y=\"470\" font-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif\" font-size=\"72\" font-weight=\"700\" fill=\"white\" text-anchor=\"middle\" letter-spacing=\"-1\">${escapeXml(name)}</text>\n</svg>`\n}\n\nconst FAVICON_SIZES = [16, 32, 48, 64] as const\n\nconst NAMED_ICONS: Array<[string, number]> = [\n [\"apple-touch-icon.png\", 180],\n [\"android-chrome-192x192.png\", 192],\n [\"android-chrome-512x512.png\", 512],\n]\n\nexport async function generateAssets(\n config: GenerateAssetsConfig,\n): Promise<GenerateAssetsResult> {\n const { name, icon, color, outputDir } = config\n\n let sharpFn: typeof import(\"sharp\")\n try {\n sharpFn = (await import(\"sharp\")).default\n } catch {\n throw new Error(\n \"sharp is required for asset generation.\\n\" +\n \"Install it in your project: bun add sharp lucide-static\",\n )\n }\n\n mkdirSync(outputDir, { recursive: true })\n\n const faviconDir = join(outputDir, \"favicon\")\n mkdirSync(faviconDir, { recursive: true })\n\n const inner = getLucideIconInner(icon)\n const written: string[] = []\n\n // favicon/favicon-{size}.png\n for (const size of FAVICON_SIZES) {\n const svg = buildIconSvg(inner, color, size)\n const png = await sharpFn(Buffer.from(svg)).png().toBuffer()\n const dest = join(faviconDir, `favicon-${size}.png`)\n writeFileSync(dest, png)\n written.push(dest)\n }\n\n // apple-touch-icon, android-chrome-*\n for (const [filename, size] of NAMED_ICONS) {\n const svg = buildIconSvg(inner, color, size)\n const png = await sharpFn(Buffer.from(svg)).png().toBuffer()\n const dest = join(outputDir, filename)\n writeFileSync(dest, png)\n written.push(dest)\n }\n\n // og-image.png\n const ogSvg = buildOgSvg(inner, name, color)\n const ogPng = await sharpFn(Buffer.from(ogSvg)).png().toBuffer()\n const ogDest = join(outputDir, \"og-image.png\")\n writeFileSync(ogDest, ogPng)\n written.push(ogDest)\n\n // manifest.json\n const manifest = {\n name,\n short_name: name,\n theme_color: color,\n background_color: \"#09090b\",\n display: \"standalone\",\n icons: [\n { src: \"/android-chrome-192x192.png\", sizes: \"192x192\", type: \"image/png\" },\n {\n src: \"/android-chrome-512x512.png\",\n sizes: \"512x512\",\n type: \"image/png\",\n purpose: \"maskable\",\n },\n ],\n }\n const manifestDest = join(outputDir, \"manifest.json\")\n writeFileSync(manifestDest, JSON.stringify(manifest, null, 2) + \"\\n\")\n written.push(manifestDest)\n\n // robots.txt\n const robotsDest = join(outputDir, \"robots.txt\")\n writeFileSync(robotsDest, \"User-agent: *\\nAllow: /\\n\")\n written.push(robotsDest)\n\n return { files: written }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olwiba/dx",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.17",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -35,6 +35,10 @@
|
|
|
35
35
|
"./ascii-gif": {
|
|
36
36
|
"import": "./dist/ascii-gif.js",
|
|
37
37
|
"types": "./dist/ascii-gif.d.ts"
|
|
38
|
+
},
|
|
39
|
+
"./generate-assets": {
|
|
40
|
+
"import": "./dist/generate-assets.js",
|
|
41
|
+
"types": "./dist/generate-assets.d.ts"
|
|
38
42
|
}
|
|
39
43
|
},
|
|
40
44
|
"files": [
|
|
@@ -49,6 +53,7 @@
|
|
|
49
53
|
"@types/node": "^22.5.4",
|
|
50
54
|
"eslint": "^9.0.0",
|
|
51
55
|
"puppeteer-core": "^24.0.0",
|
|
56
|
+
"sharp": "^0.33.0",
|
|
52
57
|
"tsup": "^8.4.0",
|
|
53
58
|
"typescript": "^5.7.2"
|
|
54
59
|
},
|
|
@@ -57,7 +62,9 @@
|
|
|
57
62
|
"puppeteer-core": ">=22.0.0",
|
|
58
63
|
"@typescript-eslint/eslint-plugin": ">=8.0.0",
|
|
59
64
|
"@typescript-eslint/parser": ">=8.0.0",
|
|
60
|
-
"eslint-plugin-react-hooks": ">=5.0.0"
|
|
65
|
+
"eslint-plugin-react-hooks": ">=5.0.0",
|
|
66
|
+
"sharp": ">=0.32.0",
|
|
67
|
+
"lucide-static": ">=0.400.0"
|
|
61
68
|
},
|
|
62
69
|
"peerDependenciesMeta": {
|
|
63
70
|
"@typescript-eslint/eslint-plugin": {
|
|
@@ -71,6 +78,12 @@
|
|
|
71
78
|
},
|
|
72
79
|
"puppeteer-core": {
|
|
73
80
|
"optional": true
|
|
81
|
+
},
|
|
82
|
+
"sharp": {
|
|
83
|
+
"optional": true
|
|
84
|
+
},
|
|
85
|
+
"lucide-static": {
|
|
86
|
+
"optional": true
|
|
74
87
|
}
|
|
75
88
|
},
|
|
76
89
|
"homepage": "https://github.com/Olwiba/olwibaDX#readme",
|