unicode-animations 0.1.9 → 1.0.0

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.
@@ -7,6 +7,9 @@ const path = require('path');
7
7
  const ci = process.env.CI || process.env.CONTINUOUS_INTEGRATION || process.env.GITHUB_ACTIONS;
8
8
  if (ci) process.exit(0);
9
9
 
10
+ // Skip postinstall when run via npx (temporary install for CLI usage)
11
+ if (__dirname.includes('_npx')) process.exit(0);
12
+
10
13
  let out;
11
14
  try {
12
15
  const fd = fs.openSync('/dev/tty', 'w');
@@ -28,82 +31,130 @@ try {
28
31
  const DURATION = 3000;
29
32
  const INTERVAL = 80;
30
33
 
31
- const d = '\x1B[2m';
32
- const b = '\x1B[1m';
33
- const r = '\x1B[0m';
34
- const c = '\x1B[36m';
35
- const g = '\x1B[32m';
36
- const w = '\x1B[37m';
37
- const m = '\x1B[35m';
38
- const hide = '\x1B[?25l';
39
- const show = '\x1B[?25h';
40
-
41
- out.write(hide);
42
- const cleanup = () => { try { out.write(show); } catch {} };
34
+ const B = '\x1B[1m';
35
+ const D = '\x1B[2m';
36
+ const R = '\x1B[0m';
37
+ const HIDE = '\x1B[?25l';
38
+ const SHOW = '\x1B[?25h';
39
+
40
+ out.write(HIDE);
41
+ const cleanup = () => { try { out.write(SHOW); } catch {} };
43
42
  process.on('SIGINT', () => { cleanup(); process.exit(0); });
44
43
 
45
- // Header
46
- out.write(`
47
- ${b}${w} ██╗ ██╗███╗ ██╗██╗ ██████╗ ██████╗ ██████╗ ███████╗${r}
48
- ${b}${w} ██║ ██║████╗ ██║██║██╔════╝██╔═══██╗██╔══██╗██╔════╝${r}
49
- ${b}${w} ██║ ██║██╔██╗ ██║██║██║ ██║ ██║██║ ██║█████╗${r}
50
- ${b}${w} ██║ ██║██║╚██╗██║██║██║ ██║ ██║██║ ██║██╔══╝${r}
51
- ${b}${w} ╚██████╔╝██║ ╚████║██║╚██████╗╚██████╔╝██████╔╝███████╗${r}
52
- ${d} ╚═════╝ ╚═╝ ╚═══╝╚═╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝${r}
53
- ${b}${c} a n i m a t i o n s${r}
54
-
55
- `);
56
-
57
- // Braille spinners only, 2 columns of 9
58
- const left = [
59
- ['Braille', S.braille],
60
- ['Orbit', S.orbit],
61
- ['Breathe', S.breathe],
62
- ['Snake', S.snake],
63
- ['Fill Sweep', S.fillsweep],
64
- ['Diag Swipe', S.diagswipe],
65
- ['Pulse', S.pulse],
66
- ['Scanline', S.scanline],
67
- ['Columns', S.columns],
68
- ];
44
+ // Narrow terminal fallback
45
+ const termCols = out.columns || 80;
46
+ if (termCols < 60) {
47
+ out.write(`\n ${B}unicode-animations${R} ${D}— 18 braille spinners${R}\n\n`);
48
+ cleanup();
49
+ return;
50
+ }
69
51
 
70
- const right = [
71
- ['Checkerboard', S.checkerboard],
72
- ['Scan', S.scan],
73
- ['Rain', S.rain],
74
- ['Sparkle', S.sparkle],
75
- ['Cascade', S.cascade],
76
- ['Wave Rows', S.waverows],
77
- ['Helix', S.helix],
78
- ['Braille Wave', S.braillewave],
79
- ['DNA', S.dna],
80
- ];
52
+ function pad(str, n) { return str + ' '.repeat(Math.max(0, n - str.length)); }
81
53
 
82
- const ROWS = left.length;
54
+ // ─── Title (box-drawing art) ───
55
+ const titleLines = [
56
+ '██╗ ██╗███╗ ██╗██╗ ██████╗ ██████╗ ██████╗ ███████╗',
57
+ '██║ ██║████╗ ██║██║██╔════╝██╔═══██╗██╔══██╗██╔════╝',
58
+ '██║ ██║██╔██╗ ██║██║██║ ██║ ██║██║ ██║█████╗ ',
59
+ '██║ ██║██║╚██╗██║██║██║ ██║ ██║██║ ██║██╔══╝ ',
60
+ '╚██████╔╝██║ ╚████║██║╚██████╗╚██████╔╝██████╔╝███████╗',
61
+ ' ╚═════╝ ╚═╝ ╚═══╝╚═╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝',
62
+ ];
63
+ const titleW = 57;
64
+
65
+ // ─── Spinner grid: 3 cols × 6 rows ───
66
+ const layout = [
67
+ ['braille', 'scan', 'rain'],
68
+ ['orbit', 'pulse', 'sparkle'],
69
+ ['breathe', 'cascade', 'waverows'],
70
+ ['snake', 'columns', 'helix'],
71
+ ['fillsweep', 'scanline', 'braillewave'],
72
+ ['diagswipe', 'checkerboard', 'dna'],
73
+ ];
74
+ const NPAD = 13;
75
+
76
+ // Compute max frame width per column for consistent spacing
77
+ const colFPad = [0, 1, 2].map(c => {
78
+ let max = 0;
79
+ for (const row of layout) {
80
+ const sp = S[row[c]];
81
+ for (const f of sp.frames) max = Math.max(max, [...f].length);
82
+ }
83
+ return max;
84
+ });
85
+ const GRID_W = colFPad.reduce((sum, fp) => sum + fp + 1 + NPAD, 0) + 4;
86
+ const CONTENT_W = Math.max(GRID_W, titleW) + 4;
87
+
88
+ // ─── Crop marks ───
89
+ const ARM = 1;
90
+ const inner = Math.max(0, CONTENT_W - 2 - ARM * 2);
91
+ const cropPad = ' ';
92
+ const topCrop = cropPad + '\u280F' + '\u2809'.repeat(ARM) + ' '.repeat(inner) + '\u2809'.repeat(ARM) + '\u28B9';
93
+ const botCrop = cropPad + '\u28C7' + '\u28C0'.repeat(ARM) + ' '.repeat(inner) + '\u28C0'.repeat(ARM) + '\u28F8';
94
+
95
+ // Center each element within the crop frame
96
+ function centerPad(w) {
97
+ return cropPad + ' '.repeat(Math.max(0, Math.floor((CONTENT_W - w) / 2)));
98
+ }
99
+ // Left-align all content to the same column, centered as a block within crops
100
+ const contentW = Math.max(GRID_W, titleW);
101
+ const contentPad = cropPad + ' '.repeat(Math.max(0, Math.floor((CONTENT_W - contentW) / 2)));
83
102
 
84
- function pad(str, n) { return str + ' '.repeat(Math.max(0, n - str.length)); }
103
+ // ─── Render spinner grid ───
104
+ const ROWS = layout.length;
85
105
 
86
106
  function renderGrid(tick) {
87
107
  let buf = '';
88
- for (let i = 0; i < ROWS; i++) {
89
- const [ln, ls] = left[i];
90
- const [rn, rs] = right[i];
91
- const lf = ls.frames[tick % ls.frames.length];
92
- const rf = rs.frames[tick % rs.frames.length];
93
- buf += ` ${m}${pad(lf, 3)}${r} ${d}${pad(ln, 12)}${r} ${m}${pad(rf, 12)}${r} ${d}${rn}${r}\n`;
108
+ for (const row of layout) {
109
+ let line = contentPad;
110
+ for (let c = 0; c < 3; c++) {
111
+ const name = row[c];
112
+ const sp = S[name];
113
+ const frame = sp.frames[tick % sp.frames.length];
114
+ line += B + pad(frame, colFPad[c]) + R + ' ' + D + pad(name, NPAD) + R;
115
+ if (c < 2) line += ' ';
116
+ }
117
+ buf += line + '\n';
94
118
  }
95
119
  return buf;
96
120
  }
97
121
 
122
+ // ─── Print static top ───
123
+ let top = '\n';
124
+ top += topCrop + '\n';
125
+ top += '\n';
126
+ for (let i = 0; i < titleLines.length; i++) {
127
+ const style = i === titleLines.length - 1 ? D : B;
128
+ top += contentPad + style + titleLines[i] + R + '\n';
129
+ }
130
+ top += contentPad + D + 'BRAILLE ANIMATIONS' + R + '\n';
131
+ top += '\n';
132
+ out.write(top);
133
+
134
+ // ─── Print first frame of spinners ───
98
135
  out.write(renderGrid(0));
99
136
 
137
+ // ─── Animate ───
100
138
  let tick = 1;
101
139
  const start = Date.now();
102
140
 
103
141
  const timer = setInterval(() => {
104
142
  if (Date.now() - start >= DURATION) {
105
143
  clearInterval(timer);
106
- out.write(`\n ${g}${b}✔${r} ${b}unicode-animations${r} ${d}— 18 braille spinners + 4 classics${r}\n\n`);
144
+ // Print static bottom
145
+ let bot = '\n';
146
+ const cmds = [
147
+ ['npx unicode-animations', 'demo all spinners'],
148
+ ['npx unicode-animations --list', 'list all spinners'],
149
+ ['npx unicode-animations --web', 'open in browser'],
150
+ ];
151
+ for (const [left, right] of cmds) {
152
+ const gap = ' '.repeat(Math.max(2, contentW - left.length - right.length));
153
+ bot += contentPad + D + left + R + gap + D + right + R + '\n';
154
+ }
155
+ bot += '\n';
156
+ bot += botCrop + '\n\n';
157
+ out.write(bot);
107
158
  cleanup();
108
159
  return;
109
160
  }
@@ -111,6 +162,7 @@ ${b}${c} a n i m a t i o n s${r}
111
162
  out.write(renderGrid(tick));
112
163
  tick++;
113
164
  }, INTERVAL);
165
+
114
166
  } catch {
115
167
  try { out.write('\x1B[?25h'); } catch {}
116
168
  process.exit(0);