Skip to content

Commit 2398f80

Browse files
authored
feat(cli): improve ASCII animations (#155)
1 parent 3c25e5a commit 2398f80

File tree

1 file changed

+73
-23
lines changed

1 file changed

+73
-23
lines changed

aws/cli-installer/src/ui.mjs

Lines changed: 73 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -454,60 +454,104 @@ export function printTable(headers, rows) {
454454

455455
// ── ASCII Art Animations ─────────────────────────────────────────────────────
456456

457+
const SPINNER_WORDS = [
458+
'tracenoodling', 'spanwrangling', 'metricsniffing', 'logchurning',
459+
'dashgawking', 'alertyawning', 'flamegraphing', 'latencynibbling',
460+
'uptimewishing', 'pagernuzzling', 'histogrambling', 'cardinoodling',
461+
'sampletasting', 'retentionmunching', 'slogandering', 'tracewidgling',
462+
'percentiling', 'scrapetinkling', 'exemplargling', 'aggregoosing',
463+
'downtimesnoozing', 'instrumentoodling', 'correlooking', 'anomasniffing',
464+
'telemetrilling', 'baselinuzzling', 'threshwondering', 'observanoodling',
465+
'spanstitching', 'dashboardling',
466+
];
467+
468+
const GRADIENT_COLORS = [
469+
'#B07FFF', '#A88BFF', '#9E9AFF', '#8FB0FF', '#6EC8F5',
470+
'#6BCBA0', '#6BCB77', '#A0D86B', '#FFD93D', '#FFB347',
471+
'#FF8C6B', '#FF6B6B', '#FF6B9D', '#D07FFF', '#B07FFF',
472+
];
473+
474+
function createWordRotator() {
475+
const shuffled = [...SPINNER_WORDS].sort(() => Math.random() - 0.5);
476+
let idx = 0;
477+
let lastSwap = Date.now();
478+
let offset = 0;
479+
let lastShift = Date.now();
480+
return () => {
481+
const now = Date.now();
482+
if (now - lastSwap >= 10_000) {
483+
idx = (idx + 1) % shuffled.length;
484+
lastSwap = now;
485+
}
486+
if (now - lastShift >= 250) {
487+
offset = (offset + 1) % GRADIENT_COLORS.length;
488+
lastShift = now;
489+
}
490+
const word = shuffled[idx];
491+
const len = GRADIENT_COLORS.length;
492+
return [...word].map((ch, i) =>
493+
chalk.hex(GRADIENT_COLORS[((offset - i) % len + len) % len])(ch)
494+
).join('');
495+
};
496+
}
497+
457498
// Owl searching through data — for OpenSearch domain provisioning
458499
const OPENSEARCH_FRAMES = [
459500
[
501+
'',
502+
" ,___,",
460503
' {o,o} ◇ searching...',
461-
' |)__) ◇ ◇',
504+
' /)__)',
462505
' -"-"- ◇ ◇ ◇',
463-
' /| |\\ ',
464-
' ˢᵉᵃʳᶜʰⁱⁿᵍ ᵗʰᵉ ⁱⁿᵈᵉˣ ',
506+
null,
507+
'',
465508
],
466509
[
510+
'',
511+
" ,___,",
467512
' {O,o} ◈ indexing...',
468-
' |)__) ◈ ◈',
513+
' /)__)',
469514
' -"-"- ◈ ◈ ◈',
470-
' /| |\\ ',
471-
' ˢᶜᵃⁿⁿⁱⁿᵍ ᶜˡᵘˢᵗᵉʳˢ ',
515+
null,
516+
'',
472517
],
473518
[
519+
'',
520+
" ,___,",
474521
' {o,O} ◆ mapping...',
475-
' |)__) ◆ ◆',
522+
' /)__)',
476523
' -"-"- ◆ ◆ ◆',
477-
' /| |\\ ',
478-
' ᵐᵃᵖᵖⁱⁿᵍ ˢʰᵃʳᵈˢ ',
524+
null,
525+
'',
479526
],
480527
[
528+
'',
529+
" ,___,",
481530
' {O,O} ★ found it!',
482-
' |)__) ★ ★',
531+
' /)__)',
483532
' -"-"- ★ ★ ★',
484-
' /| |\\ ',
485-
' ᵃˡᵐᵒˢᵗ ʳᵉᵃᵈʸ... ',
533+
null,
534+
'',
486535
],
487536
];
488537

489538
// Fish swimming back and forth through the pipeline
490539
const FISH_RIGHT = '><(((º>';
491540
const FISH_LEFT = '<º)))><';
492541
const PIPE_WIDTH = 36;
493-
const PIPE_CAPTIONS = [
494-
'ᵈᵃᵗᵃ ᶠˡᵒʷⁱⁿᵍ ᵗʰʳᵒᵘᵍʰ',
495-
'ᵇᵘⁱˡᵈⁱⁿᵍ ᵗʰᵉ ˢᵗʳᵉᵃᵐ',
496-
'ᶜᵒⁿⁿᵉᶜᵗⁱⁿᵍ ⁿᵒᵈᵉˢ',
497-
'ᵃˡᵐᵒˢᵗ ᵗʰᵉʳᵉ...',
498-
];
499542

500-
function buildPipelineFrame(pos, goingRight) {
543+
function buildPipelineFrame(pos, goingRight, caption) {
501544
const fish = goingRight ? FISH_RIGHT : FISH_LEFT;
502545
const lane = ' '.repeat(PIPE_WIDTH);
503546
const row = lane.slice(0, pos) + fish + lane.slice(pos + fish.length);
504547
const pipe = '═'.repeat(PIPE_WIDTH);
505-
const caption = PIPE_CAPTIONS[Math.floor(pos / (PIPE_WIDTH / PIPE_CAPTIONS.length)) % PIPE_CAPTIONS.length];
506548
return [
549+
'',
507550
` ${pipe}`,
508551
` ${row}`,
509552
` ${pipe}`,
510553
` ${caption}`,
554+
'',
511555
];
512556
}
513557

@@ -532,9 +576,15 @@ export function createAsciiAnimation(type) {
532576
// OpenSearch state
533577
let osFrame = 0;
534578

579+
const getWord = createWordRotator();
580+
535581
function getFrame() {
536-
if (isOpenSearch) return OPENSEARCH_FRAMES[(osFrame++) % OPENSEARCH_FRAMES.length];
537-
const frame = buildPipelineFrame(fishPos, goingRight);
582+
const word = getWord();
583+
if (isOpenSearch) {
584+
return OPENSEARCH_FRAMES[(osFrame++) % OPENSEARCH_FRAMES.length]
585+
.map((l) => l === null ? ` ${word}` : l);
586+
}
587+
const frame = buildPipelineFrame(fishPos, goingRight, word);
538588
if (goingRight) { fishPos++; if (fishPos >= maxPos) goingRight = false; }
539589
else { fishPos--; if (fishPos <= 0) goingRight = true; }
540590
return frame;
@@ -570,7 +620,7 @@ export function createAsciiAnimation(type) {
570620
process.on('SIGINT', onSigint);
571621
lineCount = 0;
572622
render();
573-
timer = setInterval(render, isOpenSearch ? 600 : 120);
623+
timer = setInterval(render, isOpenSearch ? 500 : 250);
574624
},
575625
/** Update the status text shown below the art */
576626
setStatus(fn) { statusFn = fn; },

0 commit comments

Comments
 (0)