termlings 0.1.4 → 0.1.6
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/bin/termlings.js +27 -15
- package/package.json +1 -1
- package/src/index.ts +27 -13
package/bin/termlings.js
CHANGED
|
@@ -377,11 +377,13 @@ function getTraitColors(traits2, bw2 = false) {
|
|
|
377
377
|
if (bw2) {
|
|
378
378
|
const fg = hueToGray(traits2.faceHue);
|
|
379
379
|
const dg = Math.round(fg * 0.55);
|
|
380
|
+
const bg = Math.round(fg * 0.18);
|
|
380
381
|
const hg = hueToGray(traits2.hatHue);
|
|
381
382
|
return {
|
|
382
383
|
faceRgb: [fg, fg, fg],
|
|
383
384
|
darkRgb: [dg, dg, dg],
|
|
384
|
-
hatRgb: [hg, hg, hg]
|
|
385
|
+
hatRgb: [hg, hg, hg],
|
|
386
|
+
bgRgb: [bg, bg, bg]
|
|
385
387
|
};
|
|
386
388
|
}
|
|
387
389
|
const faceHueDeg = traits2.faceHue * 30;
|
|
@@ -389,30 +391,35 @@ function getTraitColors(traits2, bw2 = false) {
|
|
|
389
391
|
return {
|
|
390
392
|
faceRgb: hslToRgb(faceHueDeg, 0.5, 0.5),
|
|
391
393
|
darkRgb: hslToRgb(faceHueDeg, 0.5, 0.28),
|
|
392
|
-
hatRgb: hslToRgb(hatHueDeg, 0.5, 0.5)
|
|
394
|
+
hatRgb: hslToRgb(hatHueDeg, 0.5, 0.5),
|
|
395
|
+
bgRgb: hslToRgb(faceHueDeg, 0.5, 0.1)
|
|
393
396
|
};
|
|
394
397
|
}
|
|
395
|
-
function renderSVG(dna2, pixelSize = 10, frame = 0, background = "
|
|
398
|
+
function renderSVG(dna2, pixelSize = 10, frame = 0, background = "auto", padding = 1, bw2 = false) {
|
|
396
399
|
const traits2 = decodeDNA(dna2);
|
|
397
400
|
const grid = generateGrid(traits2, frame);
|
|
398
|
-
const { faceRgb: faceRgb2, darkRgb: darkRgb2, hatRgb: hatRgb2 } = getTraitColors(traits2, bw2);
|
|
401
|
+
const { faceRgb: faceRgb2, darkRgb: darkRgb2, hatRgb: hatRgb2, bgRgb: bgRgb2 } = getTraitColors(traits2, bw2);
|
|
399
402
|
const toHex = (r, g, b) => `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
|
|
400
403
|
const faceHex = toHex(...faceRgb2);
|
|
401
404
|
const darkHex = toHex(...darkRgb2);
|
|
402
405
|
const hatHex = toHex(...hatRgb2);
|
|
406
|
+
const resolvedBg = background === "auto" ? toHex(...bgRgb2) : background;
|
|
403
407
|
const cols = 9;
|
|
404
408
|
const rows = grid.length;
|
|
405
409
|
const pad = padding;
|
|
406
|
-
const
|
|
407
|
-
const
|
|
410
|
+
const side = Math.max(cols, rows) + pad * 2;
|
|
411
|
+
const w = side * pixelSize;
|
|
412
|
+
const h = side * pixelSize;
|
|
413
|
+
const ox = Math.floor((side - cols) / 2);
|
|
414
|
+
const oy = Math.floor((side - rows) / 2);
|
|
408
415
|
const half = Math.round(pixelSize / 2);
|
|
409
416
|
const quarter = Math.round(pixelSize / 4);
|
|
410
417
|
const rects = [];
|
|
411
418
|
for (let y = 0; y < rows; y++) {
|
|
412
419
|
for (let x = 0; x < cols; x++) {
|
|
413
420
|
const cell = grid[y][x];
|
|
414
|
-
const rx = (x +
|
|
415
|
-
const ry = (y +
|
|
421
|
+
const rx = (x + ox) * pixelSize;
|
|
422
|
+
const ry = (y + oy) * pixelSize;
|
|
416
423
|
if (cell === "f") {
|
|
417
424
|
rects.push(`<rect x="${rx}" y="${ry}" width="${pixelSize}" height="${pixelSize}" fill="${faceHex}"/>`);
|
|
418
425
|
} else if (cell === "l") {
|
|
@@ -443,7 +450,7 @@ function renderSVG(dna2, pixelSize = 10, frame = 0, background = "#000", padding
|
|
|
443
450
|
}
|
|
444
451
|
}
|
|
445
452
|
}
|
|
446
|
-
const bg =
|
|
453
|
+
const bg = resolvedBg ? `<rect width="${w}" height="${h}" fill="${resolvedBg}"/>
|
|
447
454
|
` : "";
|
|
448
455
|
return `<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${h}" viewBox="0 0 ${w} ${h}" shape-rendering="crispEdges">
|
|
449
456
|
${bg}${rects.join("\n")}
|
|
@@ -492,13 +499,14 @@ function renderTerminal(dna2, frame = 0, bw2 = false) {
|
|
|
492
499
|
}
|
|
493
500
|
return lines.join("\n");
|
|
494
501
|
}
|
|
495
|
-
function renderLayeredSVG(dna2, pixelSize = 10, bw2 = false) {
|
|
502
|
+
function renderLayeredSVG(dna2, pixelSize = 10, bw2 = false, padding = 0) {
|
|
496
503
|
const traits2 = decodeDNA(dna2);
|
|
497
|
-
const { faceRgb: faceRgb2, darkRgb: darkRgb2, hatRgb: hatRgb2 } = getTraitColors(traits2, bw2);
|
|
504
|
+
const { faceRgb: faceRgb2, darkRgb: darkRgb2, hatRgb: hatRgb2, bgRgb: bgRgb2 } = getTraitColors(traits2, bw2);
|
|
498
505
|
const toHex = (r, g, b) => `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
|
|
499
506
|
const faceHex = toHex(...faceRgb2);
|
|
500
507
|
const darkHex = toHex(...darkRgb2);
|
|
501
508
|
const hatHex = toHex(...hatRgb2);
|
|
509
|
+
const bgHex = toHex(...bgRgb2);
|
|
502
510
|
const half = Math.round(pixelSize / 2);
|
|
503
511
|
const quarter = Math.round(pixelSize / 4);
|
|
504
512
|
const cols = 9;
|
|
@@ -511,8 +519,12 @@ function renderLayeredSVG(dna2, pixelSize = 10, bw2 = false) {
|
|
|
511
519
|
const legVariant = LEGS[traits2.legs];
|
|
512
520
|
const legFrameCount2 = legVariant.length;
|
|
513
521
|
const totalRows = hatRows.length + 1 + 1 + 2 + 2 + 1;
|
|
514
|
-
const
|
|
515
|
-
const
|
|
522
|
+
const pad = padding;
|
|
523
|
+
const side = Math.max(cols, totalRows) + pad * 2;
|
|
524
|
+
const w = side * pixelSize;
|
|
525
|
+
const h = side * pixelSize;
|
|
526
|
+
const ox = Math.floor((side - cols) / 2);
|
|
527
|
+
const oy = Math.floor((side - totalRows) / 2);
|
|
516
528
|
function px(cell, rx, ry) {
|
|
517
529
|
if (cell === "_") return "";
|
|
518
530
|
if (cell === "f") return `<rect x="${rx}" y="${ry}" width="${pixelSize}" height="${pixelSize}" fill="${faceHex}"/>`;
|
|
@@ -531,7 +543,7 @@ function renderLayeredSVG(dna2, pixelSize = 10, bw2 = false) {
|
|
|
531
543
|
let out = "";
|
|
532
544
|
for (let y = 0; y < rows.length; y++) {
|
|
533
545
|
for (let x = 0; x < cols; x++) {
|
|
534
|
-
out += px(rows[y][x], x * pixelSize, (startY + y) * pixelSize);
|
|
546
|
+
out += px(rows[y][x], (x + ox) * pixelSize, (startY + y + oy) * pixelSize);
|
|
535
547
|
}
|
|
536
548
|
}
|
|
537
549
|
return out;
|
|
@@ -550,7 +562,7 @@ function renderLayeredSVG(dna2, pixelSize = 10, bw2 = false) {
|
|
|
550
562
|
const legs2 = legFrameCount2 > 2 ? renderRows([legVariant[2]], lY) : "";
|
|
551
563
|
const legs3 = legFrameCount2 > 3 ? renderRows([legVariant[3]], lY) : "";
|
|
552
564
|
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${h}" viewBox="0 0 ${w} ${h}" shape-rendering="crispEdges"><g class="tg-bob">${staticRects}<g class="tg-mouth-0">${mouth0}</g><g class="tg-mouth-1">${mouth1}</g><g class="tg-body-0">${body0}</g><g class="tg-body-1">${body1}</g><g class="tg-body-2">${body2}</g></g><g class="tg-legs-0">${legs0}</g>` + (legs1 ? `<g class="tg-legs-1">${legs1}</g>` : "") + (legs2 ? `<g class="tg-legs-2">${legs2}</g>` : "") + (legs3 ? `<g class="tg-legs-3">${legs3}</g>` : "") + `</svg>`;
|
|
553
|
-
return { svg, legFrames: legFrameCount2, rows: totalRows };
|
|
565
|
+
return { svg, legFrames: legFrameCount2, rows: totalRows, bgHex };
|
|
554
566
|
}
|
|
555
567
|
function getAvatarCSS() {
|
|
556
568
|
return `
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -443,15 +443,18 @@ export function getTraitColors(traits: DecodedDNA, bw = false): {
|
|
|
443
443
|
faceRgb: [number, number, number];
|
|
444
444
|
darkRgb: [number, number, number];
|
|
445
445
|
hatRgb: [number, number, number];
|
|
446
|
+
bgRgb: [number, number, number];
|
|
446
447
|
} {
|
|
447
448
|
if (bw) {
|
|
448
449
|
const fg = hueToGray(traits.faceHue);
|
|
449
450
|
const dg = Math.round(fg * 0.55);
|
|
451
|
+
const bg = Math.round(fg * 0.18);
|
|
450
452
|
const hg = hueToGray(traits.hatHue);
|
|
451
453
|
return {
|
|
452
454
|
faceRgb: [fg, fg, fg],
|
|
453
455
|
darkRgb: [dg, dg, dg],
|
|
454
456
|
hatRgb: [hg, hg, hg],
|
|
457
|
+
bgRgb: [bg, bg, bg],
|
|
455
458
|
};
|
|
456
459
|
}
|
|
457
460
|
const faceHueDeg = traits.faceHue * 30;
|
|
@@ -460,6 +463,7 @@ export function getTraitColors(traits: DecodedDNA, bw = false): {
|
|
|
460
463
|
faceRgb: hslToRgb(faceHueDeg, 0.5, 0.5),
|
|
461
464
|
darkRgb: hslToRgb(faceHueDeg, 0.5, 0.28),
|
|
462
465
|
hatRgb: hslToRgb(hatHueDeg, 0.5, 0.5),
|
|
466
|
+
bgRgb: hslToRgb(faceHueDeg, 0.5, 0.1),
|
|
463
467
|
};
|
|
464
468
|
}
|
|
465
469
|
|
|
@@ -467,11 +471,11 @@ export function getTraitColors(traits: DecodedDNA, bw = false): {
|
|
|
467
471
|
* Render a DNA string as an SVG string with transparent background.
|
|
468
472
|
* Each pixel is rendered as a square rect. 1-cell padding around the grid.
|
|
469
473
|
*/
|
|
470
|
-
export function renderSVG(dna: string, pixelSize = 10, frame = 0, background: string | null = '
|
|
474
|
+
export function renderSVG(dna: string, pixelSize = 10, frame = 0, background: string | null = 'auto', padding = 1, bw = false): string {
|
|
471
475
|
const traits = decodeDNA(dna);
|
|
472
476
|
const grid = generateGrid(traits, frame);
|
|
473
477
|
|
|
474
|
-
const { faceRgb, darkRgb, hatRgb } = getTraitColors(traits, bw);
|
|
478
|
+
const { faceRgb, darkRgb, hatRgb, bgRgb } = getTraitColors(traits, bw);
|
|
475
479
|
|
|
476
480
|
const toHex = (r: number, g: number, b: number) =>
|
|
477
481
|
`#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
|
|
@@ -479,12 +483,16 @@ export function renderSVG(dna: string, pixelSize = 10, frame = 0, background: st
|
|
|
479
483
|
const faceHex = toHex(...faceRgb);
|
|
480
484
|
const darkHex = toHex(...darkRgb);
|
|
481
485
|
const hatHex = toHex(...hatRgb);
|
|
486
|
+
const resolvedBg = background === 'auto' ? toHex(...bgRgb) : background;
|
|
482
487
|
|
|
483
488
|
const cols = 9;
|
|
484
489
|
const rows = grid.length;
|
|
485
490
|
const pad = padding;
|
|
486
|
-
const
|
|
487
|
-
const
|
|
491
|
+
const side = Math.max(cols, rows) + pad * 2;
|
|
492
|
+
const w = side * pixelSize;
|
|
493
|
+
const h = side * pixelSize;
|
|
494
|
+
const ox = Math.floor((side - cols) / 2);
|
|
495
|
+
const oy = Math.floor((side - rows) / 2);
|
|
488
496
|
|
|
489
497
|
const half = Math.round(pixelSize / 2);
|
|
490
498
|
const quarter = Math.round(pixelSize / 4);
|
|
@@ -492,8 +500,8 @@ export function renderSVG(dna: string, pixelSize = 10, frame = 0, background: st
|
|
|
492
500
|
for (let y = 0; y < rows; y++) {
|
|
493
501
|
for (let x = 0; x < cols; x++) {
|
|
494
502
|
const cell = grid[y][x];
|
|
495
|
-
const rx = (x +
|
|
496
|
-
const ry = (y +
|
|
503
|
+
const rx = (x + ox) * pixelSize;
|
|
504
|
+
const ry = (y + oy) * pixelSize;
|
|
497
505
|
if (cell === "f") {
|
|
498
506
|
rects.push(`<rect x="${rx}" y="${ry}" width="${pixelSize}" height="${pixelSize}" fill="${faceHex}"/>`);
|
|
499
507
|
} else if (cell === "l") {
|
|
@@ -530,7 +538,7 @@ export function renderSVG(dna: string, pixelSize = 10, frame = 0, background: st
|
|
|
530
538
|
}
|
|
531
539
|
}
|
|
532
540
|
|
|
533
|
-
const bg =
|
|
541
|
+
const bg = resolvedBg ? `<rect width="${w}" height="${h}" fill="${resolvedBg}"/>\n` : '';
|
|
534
542
|
return `<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${h}" viewBox="0 0 ${w} ${h}" shape-rendering="crispEdges">\n${bg}${rects.join("\n")}\n</svg>`;
|
|
535
543
|
}
|
|
536
544
|
|
|
@@ -596,14 +604,15 @@ export function renderTerminal(dna: string, frame = 0, bw = false): string {
|
|
|
596
604
|
* Returns the SVG string, number of leg frames, and total row count.
|
|
597
605
|
* Used by framework components for CSS-only animation (no JS timers).
|
|
598
606
|
*/
|
|
599
|
-
export function renderLayeredSVG(dna: string, pixelSize = 10, bw = false): {
|
|
607
|
+
export function renderLayeredSVG(dna: string, pixelSize = 10, bw = false, padding = 0): {
|
|
600
608
|
svg: string;
|
|
601
609
|
legFrames: number;
|
|
602
610
|
rows: number;
|
|
611
|
+
bgHex: string;
|
|
603
612
|
} {
|
|
604
613
|
const traits = decodeDNA(dna);
|
|
605
614
|
|
|
606
|
-
const { faceRgb, darkRgb, hatRgb } = getTraitColors(traits, bw);
|
|
615
|
+
const { faceRgb, darkRgb, hatRgb, bgRgb } = getTraitColors(traits, bw);
|
|
607
616
|
|
|
608
617
|
const toHex = (r: number, g: number, b: number) =>
|
|
609
618
|
`#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
|
|
@@ -611,6 +620,7 @@ export function renderLayeredSVG(dna: string, pixelSize = 10, bw = false): {
|
|
|
611
620
|
const faceHex = toHex(...faceRgb);
|
|
612
621
|
const darkHex = toHex(...darkRgb);
|
|
613
622
|
const hatHex = toHex(...hatRgb);
|
|
623
|
+
const bgHex = toHex(...bgRgb);
|
|
614
624
|
|
|
615
625
|
const half = Math.round(pixelSize / 2);
|
|
616
626
|
const quarter = Math.round(pixelSize / 4);
|
|
@@ -627,8 +637,12 @@ export function renderLayeredSVG(dna: string, pixelSize = 10, bw = false): {
|
|
|
627
637
|
|
|
628
638
|
// hat + face + eyes + 2 mouth + 2 body + 1 legs
|
|
629
639
|
const totalRows = hatRows.length + 1 + 1 + 2 + 2 + 1;
|
|
630
|
-
const
|
|
631
|
-
const
|
|
640
|
+
const pad = padding;
|
|
641
|
+
const side = Math.max(cols, totalRows) + pad * 2;
|
|
642
|
+
const w = side * pixelSize;
|
|
643
|
+
const h = side * pixelSize;
|
|
644
|
+
const ox = Math.floor((side - cols) / 2);
|
|
645
|
+
const oy = Math.floor((side - totalRows) / 2);
|
|
632
646
|
|
|
633
647
|
function px(cell: Pixel, rx: number, ry: number): string {
|
|
634
648
|
if (cell === "_") return "";
|
|
@@ -649,7 +663,7 @@ export function renderLayeredSVG(dna: string, pixelSize = 10, bw = false): {
|
|
|
649
663
|
let out = "";
|
|
650
664
|
for (let y = 0; y < rows.length; y++) {
|
|
651
665
|
for (let x = 0; x < cols; x++) {
|
|
652
|
-
out += px(rows[y][x], x * pixelSize, (startY + y) * pixelSize);
|
|
666
|
+
out += px(rows[y][x], (x + ox) * pixelSize, (startY + y + oy) * pixelSize);
|
|
653
667
|
}
|
|
654
668
|
}
|
|
655
669
|
return out;
|
|
@@ -691,7 +705,7 @@ export function renderLayeredSVG(dna: string, pixelSize = 10, bw = false): {
|
|
|
691
705
|
(legs3 ? `<g class="tg-legs-3">${legs3}</g>` : "") +
|
|
692
706
|
`</svg>`;
|
|
693
707
|
|
|
694
|
-
return { svg, legFrames: legFrameCount, rows: totalRows };
|
|
708
|
+
return { svg, legFrames: legFrameCount, rows: totalRows, bgHex };
|
|
695
709
|
}
|
|
696
710
|
|
|
697
711
|
/**
|