@blockrun/franklin 3.2.2 → 3.2.3

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.
Files changed (2) hide show
  1. package/dist/banner.js +73 -72
  2. package/package.json +1 -1
package/dist/banner.js CHANGED
@@ -2,44 +2,47 @@ import chalk from 'chalk';
2
2
  // ─── Ben Franklin portrait ─────────────────────────────────────────────────
3
3
  //
4
4
  // Generated once, at build time, from the Joseph Duplessis 1785 oil painting
5
- // of Benjamin Franklin (same source as the portrait on the US $100 bill).
6
- // Public domain image from Wikimedia Commons:
5
+ // of Benjamin Franklin (same source used for the engraving on the US $100
6
+ // bill). Public domain image from Wikimedia Commons:
7
7
  // https://commons.wikimedia.org/wiki/File:BenFranklinDuplessis.jpg
8
8
  //
9
9
  // Pipeline:
10
10
  // 1. Crop the 2403×2971 original to a 1400×1400 square centred on the face
11
11
  // (sips --cropToHeightWidth 1400 1400 --cropOffset 400 500)
12
- // 2. Convert via chafa:
13
- // chafa --size=30x14 --symbols=block --colors=256 ben-face.jpg
14
- // 3. Strip cursor visibility control codes (\x1b[?25l / \x1b[?25h)
15
- // 4. Paste here as hex-escaped string array (readable + diff-friendly)
12
+ // 2. Convert with ascii-image-converter in braille mode:
13
+ // ascii-image-converter ben-face.jpg --dimensions 34,16 --braille \
14
+ // --threshold 110
16
15
  //
17
- // Visible dimensions: ~28 characters wide × 14 rows tall.
16
+ // Braille characters (U+2800..U+28FF) encode 2×4 dot matrices per cell, so
17
+ // a 34×16 braille output gives 68×64 = 4,352 effective "pixels" — 2.7× the
18
+ // resolution of chafa half-block mode at the same visible size. For a face,
19
+ // which is all about silhouette + key features, this is a massive win.
18
20
  //
19
- // Rendered best in a 256-color or truecolor terminal. Degrades gracefully
20
- // on ancient terminals but those are long gone and we don't support them.
21
+ // The output is pure Unicode no ANSI escape codes, no color tinting baked
22
+ // in which means it's trivial to wrap in chalk.hex() at render time for
23
+ // brand tinting, and it ships as a clean readable TS array.
21
24
  const BEN_PORTRAIT_ROWS = [
22
- '\x1b[0m\x1b[38;5;16;48;5;16m \x1b[38;5;232m▁\x1b[38;5;235;48;5;232m▂\x1b[38;5;58;48;5;233m▄\x1b[38;5;95;48;5;234m▆\x1b[38;5;137;48;5;58m▄\x1b[38;5;173m▅\x1b[48;5;94m▅\x1b[48;5;58m▆▅\x1b[48;5;237m▄\x1b[38;5;137;48;5;234m▃\x1b[38;5;235;48;5;233m▂ \x1b[38;5;233;48;5;232m▂▅\x1b[48;5;233m \x1b[0m',
23
- '\x1b[38;5;16;48;5;16m \x1b[38;5;235;48;5;232m▗\x1b[38;5;233;48;5;236m▘\x1b[38;5;8;48;5;239m▌\x1b[38;5;95;48;5;137m▋\x1b[38;5;137;48;5;179m▘ \x1b[38;5;179;48;5;173m▃\x1b[48;5;179m \x1b[48;5;173m▊\x1b[38;5;58;48;5;137m▝\x1b[38;5;94;48;5;235m▖\x1b[38;5;234;48;5;233m▅▄▂ ▂▗▄▃\x1b[0m',
24
- '\x1b[38;5;16;48;5;16m \x1b[38;5;235;48;5;232m▗\x1b[38;5;236;48;5;237m▍ \x1b[38;5;58;48;5;94m▋\x1b[38;5;95;48;5;173m▌\x1b[48;5;179m \x1b[38;5;179;48;5;215m▍\x1b[48;5;221m▔\x1b[38;5;222;48;5;180m▍\x1b[48;5;179m \x1b[38;5;173m▕\x1b[38;5;179;48;5;173m▅\x1b[38;5;137m▕\x1b[38;5;95;48;5;58m▍\x1b[38;5;58;48;5;235m▖\x1b[38;5;235;48;5;234m▖▃▄ \x1b[0m',
25
- '\x1b[38;5;16;48;5;16m \x1b[38;5;233m▗\x1b[48;5;235m▏\x1b[38;5;237;48;5;238m▊\x1b[38;5;238;48;5;236m▌\x1b[38;5;236;48;5;58m▖\x1b[38;5;95;48;5;179m▌ \x1b[38;5;137m▗\x1b[38;5;94m▄\x1b[38;5;58m▄\x1b[38;5;94m▄\x1b[38;5;137m▖\x1b[38;5;173m▗\x1b[38;5;131m▗\x1b[38;5;58;48;5;137m▃\x1b[38;5;131;48;5;58m▘\x1b[38;5;234m▕\x1b[48;5;236m▖\x1b[38;5;236;48;5;235m▃ \x1b[38;5;234m▝\x1b[38;5;235;48;5;234m▃\x1b[0m',
26
- '\x1b[38;5;16;48;5;16m \x1b[38;5;235;48;5;232m▂\x1b[38;5;236;48;5;234m▄\x1b[38;5;237;48;5;236m▗\x1b[38;5;8;48;5;239m▖\x1b[38;5;240;48;5;8m▎\x1b[38;5;94;48;5;236m▕\x1b[38;5;137;48;5;179m▍ \x1b[38;5;94;48;5;137m▝\x1b[38;5;173;48;5;94m▂\x1b[38;5;137;48;5;58m▂\x1b[48;5;94m▃\x1b[48;5;179m▘\x1b[38;5;173m▝\x1b[38;5;137;48;5;235m▍\x1b[38;5;94;48;5;236m▝\x1b[38;5;235;48;5;94m▖\x1b[38;5;52;48;5;58m▖\x1b[38;5;235;48;5;233m▝\x1b[48;5;236m▁\x1b[48;5;235m \x1b[0m',
27
- '\x1b[38;5;232;48;5;16m▗\x1b[38;5;233;48;5;236m▌\x1b[38;5;95;48;5;239m▅\x1b[48;5;240m▃\x1b[38;5;94;48;5;238m▖\x1b[38;5;240;48;5;8m▝\x1b[38;5;95;48;5;236m▘\x1b[38;5;236;48;5;95m▘\x1b[38;5;173;48;5;179m▏ \x1b[38;5;215m▄ \x1b[38;5;179;48;5;137m▅\x1b[38;5;137;48;5;179m▘\x1b[38;5;216m▘\x1b[38;5;179;48;5;216m▃\x1b[48;5;94m▌\x1b[38;5;94;48;5;131m▘\x1b[38;5;95;48;5;94m▋\x1b[38;5;94;48;5;52m▃\x1b[38;5;52;48;5;233m▎\x1b[38;5;233;48;5;235m▅\x1b[38;5;234m▂ \x1b[0m',
28
- '\x1b[38;5;233;48;5;232m▕\x1b[38;5;234;48;5;236m▘\x1b[38;5;8;48;5;95m▌ \x1b[38;5;236m▃\x1b[38;5;58;48;5;234m▘\x1b[38;5;94m▝\x1b[48;5;137m▎\x1b[38;5;179;48;5;173m▍\x1b[38;5;173;48;5;179m▌▆▖▃▞\x1b[38;5;94;48;5;173m▗\x1b[48;5;179m▄\x1b[38;5;179;48;5;58m▘\x1b[38;5;94;48;5;52m▝\x1b[38;5;130;48;5;131m▃\x1b[38;5;94;48;5;58m▍\x1b[38;5;52;48;5;232m▎\x1b[38;5;232;48;5;233m▌\x1b[38;5;233;48;5;234m▏\x1b[38;5;234;48;5;235m▎\x1b[38;5;236m▌▅▄ \x1b[0m',
29
- '\x1b[38;5;232;48;5;235m▋\x1b[38;5;58;48;5;236m▝\x1b[48;5;58m \x1b[38;5;239;48;5;94m▅\x1b[38;5;237;48;5;235m▂\x1b[38;5;235;48;5;233m▂\x1b[38;5;234;48;5;94m▄\x1b[38;5;94;48;5;137m▖\x1b[48;5;173m \x1b[38;5;173;48;5;179m▃ \x1b[38;5;137m▂▃▂\x1b[38;5;131;48;5;137m▃\x1b[38;5;58;48;5;131m▝\x1b[38;5;94;48;5;52m▅\x1b[48;5;94m \x1b[48;5;58m▍\x1b[38;5;235;48;5;232m▎\x1b[38;5;232;48;5;233m▋\x1b[38;5;233;48;5;234m▍\x1b[38;5;235;48;5;236m▏ \x1b[38;5;236;48;5;235m▎ \x1b[0m',
30
- '\x1b[38;5;234;48;5;235m▏\x1b[38;5;236;48;5;237m▋\x1b[38;5;237;48;5;8m▃\x1b[38;5;235;48;5;238m▗\x1b[38;5;237m▖\x1b[38;5;58;48;5;234m▌\x1b[38;5;234;48;5;233m▎\x1b[38;5;236;48;5;137m▎\x1b[38;5;137;48;5;173m▄ \x1b[38;5;173;48;5;179m▄▃ \x1b[38;5;179;48;5;215m▅\x1b[38;5;173;48;5;179m▄\x1b[38;5;179;48;5;137m▘\x1b[38;5;137;48;5;131m▌\x1b[48;5;94m \x1b[38;5;58m▗\x1b[38;5;233;48;5;58m▗\x1b[48;5;233m \x1b[38;5;234;48;5;236m▘ \x1b[38;5;236;48;5;235m▃▞\x1b[38;5;235;48;5;236m▄\x1b[48;5;235m \x1b[0m',
31
- '\x1b[38;5;234;48;5;235m▏▆\x1b[38;5;235;48;5;237m▌\x1b[38;5;236m▝\x1b[38;5;237;48;5;234m▍\x1b[38;5;234;48;5;233m▖\x1b[38;5;240;48;5;234m▗\x1b[38;5;101;48;5;186m▌\x1b[38;5;137m▝\x1b[48;5;137m \x1b[48;5;173m▆▄▃\x1b[38;5;131m▂\x1b[38;5;130;48;5;137m▂\x1b[38;5;58;48;5;94m▃\x1b[48;5;58m \x1b[38;5;234;48;5;233m▏\x1b[38;5;235;48;5;234m▅\x1b[48;5;236m▌ ▝ \x1b[48;5;235m \x1b[0m',
32
- '\x1b[38;5;234;48;5;233m▕\x1b[38;5;239;48;5;235m▂\x1b[38;5;95m▃\x1b[48;5;237m▄\x1b[48;5;236m▄\x1b[48;5;235m▄\x1b[38;5;236;48;5;240m▘\x1b[38;5;101;48;5;95m▕\x1b[48;5;186m▖\x1b[38;5;179;48;5;229m▝\x1b[38;5;223;48;5;137m▃\x1b[38;5;137;48;5;131m▁\x1b[38;5;95m▅\x1b[38;5;94m▂\x1b[48;5;94m \x1b[38;5;58m▗\x1b[38;5;94;48;5;58m▔\x1b[38;5;236m▁ \x1b[48;5;235m▆\x1b[38;5;235;48;5;236m▍\x1b[38;5;236;48;5;235m▆\x1b[48;5;236m \x1b[38;5;235m▅\x1b[48;5;235m \x1b[0m',
33
- '\x1b[38;5;237;48;5;95m▔ \x1b[38;5;137;48;5;101m▝\x1b[48;5;187m▅\x1b[38;5;180;48;5;229m▂\x1b[38;5;143;48;5;222m▔\x1b[38;5;186;48;5;58m▅\x1b[38;5;179m▂\x1b[38;5;95m▁\x1b[38;5;235m▂\x1b[38;5;236m▄\x1b[48;5;233m▌\x1b[38;5;235m▔\x1b[38;5;233;48;5;236m▅\x1b[38;5;234m▃\x1b[38;5;235m▁ ▔\x1b[48;5;235m \x1b[0m',
34
- '\x1b[38;5;101;48;5;137m▔\x1b[38;5;95;48;5;101m▄▔\x1b[38;5;101;48;5;95m▄ ▗ \x1b[38;5;240m▖\x1b[38;5;95;48;5;101m▘\x1b[38;5;137m▔\x1b[48;5;222m▅\x1b[48;5;186m▃\x1b[48;5;179m▂\x1b[38;5;101;48;5;95m▌\x1b[48;5;58m \x1b[38;5;238;48;5;236m▁\x1b[38;5;180;48;5;234m▃\x1b[48;5;235m▄\x1b[38;5;179;48;5;234m▃\x1b[38;5;95m▁\x1b[38;5;234;48;5;235m▊\x1b[48;5;236m▆\x1b[38;5;235m▃\x1b[38;5;234m▂\x1b[38;5;235m▁ \x1b[38;5;236;48;5;235m▎\x1b[0m',
35
- '\x1b[38;5;137;48;5;137m \x1b[48;5;95m▄ \x1b[38;5;95;48;5;101m▖\x1b[48;5;137m▝\x1b[48;5;95m \x1b[38;5;101m▅\x1b[48;5;239m▋\x1b[48;5;95m \x1b[38;5;95;48;5;137m▋\x1b[38;5;101;48;5;95m▍\x1b[38;5;95;48;5;101m▖\x1b[38;5;101;48;5;95m▆\x1b[38;5;239m▗\x1b[38;5;101m▄ \x1b[38;5;95;48;5;137m▅\x1b[38;5;137;48;5;180m▅\x1b[38;5;180;48;5;186m▃\x1b[48;5;143m▆\x1b[38;5;95m▔\x1b[38;5;143;48;5;235m▖\x1b[48;5;234m \x1b[38;5;235m▆\x1b[38;5;234;48;5;235m▝\x1b[38;5;235;48;5;234m▞\x1b[38;5;234;48;5;235m▄ \x1b[0m',
25
+ '⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣤⣴⣶⣶⣦⣤⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀',
26
+ '⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀',
27
+ '⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀',
28
+ '⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀',
29
+ '⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⠁⣀⠀⠉⣿⣿⣿⠋⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀',
30
+ '⠀⠀⠀⠀⠀⠀⠀⢀⠀⢠⣿⣿⣿⣾⣤⣴⣴⣿⣿⣷⠀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀',
31
+ '⠀⠀⠀⢠⡄⠀⠀⠁⢀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⢾⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀',
32
+ '⠀⠀⠀⠸⡔⠂⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿⣛⣛⠛⠁⠈⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀',
33
+ '⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⢿⣿⠿⢷⠄⠀⠙⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀',
34
+ '⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀',
35
+ '⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀',
36
+ '⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⡿⣿⡿⣿⣏⠛⠛⠙⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀',
37
+ '⠀⠀⡴⠺⠖⢒⣂⢄⡀⣹⣿⣿⣿⣶⣙⠂⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀',
38
+ '⣶⣤⣄⡀⠈⠻⠿⡙⠗⠸⡻⣿⡻⣿⣿⣷⣦⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀',
39
+ '⣿⡟⠻⣿⣦⡀⠀⢁⡆⠀⠹⢿⣿⣮⣟⠿⣿⠏⠀⠀⣀⣴⣶⣦⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀',
40
+ '⣿⣷⣄⠈⠿⣷⡀⣾⣿⡀⢦⢸⣿⡹⣿⣿⡆⣤⡐⠻⡻⣿⣿⣿⣿⣦⠀⠀⠀⠀⠀⠀⠀⠀',
36
41
  ];
37
42
  // ─── FRANKLIN text banner (gold → emerald gradient) ────────────────────────
38
43
  //
39
- // Kept from v3.1.0. The text is laid out as 6 block-letter rows. Each row
40
- // is tinted with a color interpolated between GOLD_START and EMERALD_END,
41
- // giving the smooth vertical gradient that's been Franklin's banner since
42
- // v3.1.0.
44
+ // Kept from v3.1.0. 6 block-letter rows, each tinted with an interpolated
45
+ // colour between GOLD_START and EMERALD_END for a smooth vertical gradient.
43
46
  const FRANKLIN_ART = [
44
47
  ' ███████╗██████╗ █████╗ ███╗ ██╗██╗ ██╗██╗ ██╗███╗ ██╗',
45
48
  ' ██╔════╝██╔══██╗██╔══██╗████╗ ██║██║ ██╔╝██║ ██║████╗ ██║',
@@ -69,23 +72,19 @@ function interpolateHex(start, end, t) {
69
72
  }
70
73
  // ─── Banner layout ─────────────────────────────────────────────────────────
71
74
  // Minimum terminal width to show the side-by-side portrait + text layout.
72
- // The portrait is ~28 chars, the FRANKLIN text is ~65 chars, plus a 3-char
73
- // gap = 96 chars. We add a small margin so 100 cols is the threshold.
74
- const MIN_WIDTH_FOR_PORTRAIT = 100;
75
+ // Portrait: 34 cols braille, FRANKLIN text: ~65 cols, gap: 3 cols,
76
+ // total: ~102 cols. Add a 3-col margin of safety 105.
77
+ const MIN_WIDTH_FOR_PORTRAIT = 105;
75
78
  /**
76
- * Pad a line to an exact visual width, ignoring ANSI escape codes when
77
- * measuring. Used to align the portrait's right edge before the text block.
79
+ * Pad a line to an exact visual width. Braille characters have no ANSI
80
+ * escape codes and are all 1 cell wide, so this is a straightforward
81
+ * codepoint count.
78
82
  */
79
- function padVisible(s, targetWidth) {
80
- // Strip ANSI color codes to measure visible length
81
- // eslint-disable-next-line no-control-regex
82
- const visible = s.replace(/\x1b\[[0-9;]*m/g, '');
83
- // Unicode block characters are width 1 (they're half-blocks, not double-width)
84
- const current = [...visible].length;
83
+ function padBraillePortrait(s, targetWidth) {
84
+ const current = [...s].length;
85
85
  if (current >= targetWidth)
86
86
  return s;
87
- // Append a reset + padding so background colors don't bleed into the gap
88
- return s + '\x1b[0m' + ' '.repeat(targetWidth - current);
87
+ return s + ' '.repeat(targetWidth - current);
89
88
  }
90
89
  export function printBanner(version) {
91
90
  const termWidth = process.stdout.columns ?? 80;
@@ -98,37 +97,42 @@ export function printBanner(version) {
98
97
  }
99
98
  }
100
99
  /**
101
- * Full layout: Ben Franklin portrait on the left, FRANKLIN text block on the
102
- * right. Portrait is 14 rows × ~28 chars, text is 6 rows text is vertically
103
- * centred inside the portrait with 4 rows of padding above and 4 below,
104
- * tagline sitting right under the FRANKLIN block.
100
+ * Full layout: Ben Franklin braille portrait on the left, FRANKLIN gradient
101
+ * text on the right. Portrait is 16 rows × 34 cols, text is 6 rows + 1-row
102
+ * tagline. Text starts at portrait row 5 so the FRANKLIN block aligns with
103
+ * Ben's face region (head at rows 1-4, face at rows 5-10, shoulders 11-16),
104
+ * giving the classic "portrait and nameplate" composition.
105
105
  *
106
- * [portrait row 1] (empty)
107
- * [portrait row 2] (empty)
108
- * [portrait row 3] (empty)
109
- * [portrait row 4] (empty)
110
- * [portrait row 5] ███████╗██████╗ █████╗ ...
111
- * [portrait row 6] ██╔════╝██╔══██╗██╔══██╗...
112
- * [portrait row 7] █████╗ ██████╔╝███████║...
113
- * [portrait row 8] ██╔══╝ ██╔══██╗██╔══██║...
114
- * [portrait row 9] ██║ ██║ ██║██║ ██║...
115
- * [portrait row 10] ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝...
116
- * [portrait row 11] blockrun.ai · The AI agent with a wallet · vX
117
- * [portrait row 12] (empty)
118
- * [portrait row 13] (empty)
119
- * [portrait row 14] (empty)
106
+ * row 1 ⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣤⣴⣶⣶⣦⣤⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
107
+ * row 2 ⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⣿⣿⣿⣿⣷⡄⠀⠀⠀⠀⠀⠀⠀⠀
108
+ * row 3 ⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⠀⠀⠀⠀⠀⠀⠀
109
+ * row 4 ⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡆⠀⠀⠀⠀⠀⠀
110
+ * row 5 ⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿⣿⠁... ███████╗██████╗ █████╗ ...
111
+ * row 6 ⠀⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣾... ██╔════╝██╔══██╗██╔══██╗...
112
+ * row 7 ⠀⠀⠀⢠⡄⠀⠀⠀⢀⣾⣿... █████╗ ██████╔╝███████║...
113
+ * row 8 ⠀⠀⠀⠸⡔⠂⠀⠀⠘⣿⣿... ██╔══╝ ██╔══██╗██╔══██║...
114
+ * row 9 ⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿... ██║ ██║ ██║██║ ██║...
115
+ * row 10 ⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿... ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝...
116
+ * row 11 ⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⣿... blockrun.ai · The AI agent with a wallet · vX
117
+ * row 12 ⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿...
118
+ * row 13-16: neck, collar, body
120
119
  */
121
120
  function printSideBySide(version) {
122
- const TEXT_TOP_OFFSET = 4; // rows of portrait above the text
123
- const PORTRAIT_WIDTH = 29; // columns (char width) of the portrait + 1 pad
124
- const GAP = ' '; // gap between portrait and text
121
+ const TEXT_TOP_OFFSET = 4; // text block starts at portrait row 5 (0-indexed row 4)
122
+ const PORTRAIT_WIDTH = 35; // 34 cols braille + 1 trailing space
123
+ const GAP = ' ';
125
124
  const portraitRows = BEN_PORTRAIT_ROWS;
126
125
  const textRows = FRANKLIN_ART.length;
127
126
  const totalRows = Math.max(portraitRows.length, TEXT_TOP_OFFSET + textRows + 2);
127
+ // Tint the braille portrait in dim white for a "pencil portrait" feel.
128
+ // Braille chars carry no colour on their own — chalk wraps them in an
129
+ // ANSI colour sequence at render time.
130
+ const portraitTint = chalk.hex('#E8E8E8');
128
131
  for (let i = 0; i < totalRows; i++) {
129
- const portraitLine = i < portraitRows.length
130
- ? padVisible(portraitRows[i], PORTRAIT_WIDTH)
132
+ const rawPortraitLine = i < portraitRows.length
133
+ ? padBraillePortrait(portraitRows[i], PORTRAIT_WIDTH)
131
134
  : ' '.repeat(PORTRAIT_WIDTH);
135
+ const portraitLine = portraitTint(rawPortraitLine);
132
136
  // Text column content
133
137
  let textCol = '';
134
138
  const textIdx = i - TEXT_TOP_OFFSET;
@@ -140,24 +144,21 @@ function printSideBySide(version) {
140
144
  }
141
145
  else if (textIdx === textRows) {
142
146
  // Tagline row sits right under the FRANKLIN block.
143
- // The big block-letter "FRANKLIN" above already says the product
144
- // name — the tagline uses that real estate for the parent brand URL
145
- // (blockrun.ai, which is a real live domain unlike franklin.run
146
- // which we own but haven't deployed yet, see v3.1.0 changelog).
147
+ // The big block-letter FRANKLIN above already says the product name
148
+ // — the tagline uses that line for the parent brand URL
149
+ // (blockrun.ai a real live domain; see v3.1.0 notes for why
150
+ // franklin.run is explicitly NOT used here).
147
151
  textCol =
148
152
  chalk.bold.hex(GOLD_START)(' blockrun.ai') +
149
153
  chalk.dim(' · The AI agent with a wallet · v' + version);
150
154
  }
151
- // Write with a reset at the very start to prevent stray bg from the
152
- // previous line bleeding into the current row's portrait column.
153
- process.stdout.write('\x1b[0m' + portraitLine + GAP + textCol + '\x1b[0m\n');
155
+ process.stdout.write(portraitLine + GAP + textCol + '\n');
154
156
  }
155
- // Trailing blank line for breathing room
156
157
  process.stdout.write('\n');
157
158
  }
158
159
  /**
159
160
  * Compact layout for narrow terminals: just the FRANKLIN text block with
160
- * its gradient, no portrait. Matches the v3.1.0 banner exactly.
161
+ * its gradient, no portrait.
161
162
  */
162
163
  function printTextOnly(version) {
163
164
  const textRows = FRANKLIN_ART.length;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/franklin",
3
- "version": "3.2.2",
3
+ "version": "3.2.3",
4
4
  "description": "Franklin — The AI agent with a wallet. Spends USDC autonomously to get real work done. Pay per action, no subscriptions.",
5
5
  "type": "module",
6
6
  "exports": {