Created
June 27, 2025 19:07
-
-
Save koad/b6e31f66e5c1f57808b4b4b608efd806 to your computer and use it in GitHub Desktop.
Animated terminal prompt with rainbow spinner in nodejs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* ๐ Animated Terminal Prompt with Rainbow Spinner | |
* | |
* A beautiful, animated command-line prompt that features: | |
* - Braille pattern spinner animation | |
* - Smooth rainbow color transitions | |
* - Graceful Ctrl+C handling | |
* - Real-time prompt updates | |
* | |
* Author: koad | |
* Version: 0.0.1 | |
* License: MIT | |
*/ | |
// Import Node.js readline module for terminal input/output handling | |
const readline = require('readline'); | |
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
// ๐จ ANSI ESCAPE CODES - Terminal formatting and color control sequences | |
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
const RESET = '\x1b[0m'; // Reset all formatting back to default | |
const BOLD = '\x1b[1m'; // Make text bold/bright | |
const CLEAR_LINE = '\x1b[2K'; // Clear entire current line | |
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
// โ๏ธ CONFIGURATION - Timing and behavior settings | |
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
// Update interval in milliseconds (69ms โ 14.5 FPS for smooth animation) | |
const PROMPT_UPDATE_INTERVAL = 69; | |
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
// ๐ก๏ธ TTY VALIDATION - Ensure we're running in a proper terminal | |
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
// Check if stdin is connected to a terminal (TTY) | |
// This prevents issues when script is piped or redirected | |
if (!process.stdin.isTTY) { | |
console.error('Error: stdin is not a TTY.'); | |
console.error('This script requires a terminal environment to function properly.'); | |
process.exit(1); | |
} | |
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
// ๐ฎ RAW MODE SETUP - Enable character-by-character input processing | |
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
// Enable raw mode to capture individual keystrokes without waiting for Enter | |
process.stdin.setRawMode(true); | |
// Start reading from stdin | |
process.stdin.resume(); | |
// Set character encoding to UTF-8 for proper Unicode support | |
process.stdin.setEncoding('utf8'); | |
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
// ๐ช GRACEFUL EXIT HANDLER - Clean Ctrl+C handling | |
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
// Listen for raw keyboard input to handle Ctrl+C gracefully | |
process.stdin.on('data', (key) => { | |
// Check for Ctrl+C (ASCII code 3, Unicode \u0003) | |
if (key === '\u0003') { | |
console.log(""); | |
console.log("๐ Ctrl+C detected, exiting gracefully..."); | |
console.log(""); | |
process.exit(); | |
} | |
}); | |
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
// ๐ READLINE INTERFACE - Terminal input/output management | |
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
// Create readline interface for handling line-based input | |
const rl = readline.createInterface({ | |
input: process.stdin, // Read from standard input | |
output: process.stdout // Write to standard output | |
}); | |
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
// ๐ BRAILLE SPINNER - Unicode Braille patterns for smooth animation | |
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
// Array of Braille pattern characters that create a spinning effect | |
// These Unicode characters (U+2800 block) form a smooth circular animation | |
// Each character represents different dot patterns in a 2x4 Braille cell | |
const spinner = Array.from('โ โ โ โขโกโ โ โ โ โ ขโข โฃโกโ โ โ โ ฃโขขโฃ โฃโกโ โ โ โขฃโฃขโฃคโฃโกโ โ โ ซโฃฃโฃฆโฃดโฃโกโ โ ปโขซโฃงโฃถโฃผโฃโกโ ฟโขปโฃซโฃทโฃพโฃฝโฃโกฟโขฟโฃปโฃฏโฃทโฃพโฃฝโฃโกฟโขฟโฃปโฃฏโฃงโฃถโฃผโฃโกโ ฟโขปโฃซโฃฃโฃฆโฃดโฃโกโ โ ปโขซโขฃโฃขโฃคโฃโกโ โ โ ซโ ฃโขขโฃ โฃโกโ โ โ โ โ ขโข โฃโกโ โ โ โ โ โ โขโกโ โ โ '); | |
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
// ๐จ COLOR CONVERSION - HSL to RGB to ANSI 24-bit color | |
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
/** | |
* Converts HSL color values to ANSI 24-bit color escape sequence | |
* | |
* @param {number} h - Hue (0-360 degrees) | |
* @param {number} s - Saturation (0-100 percent, default: 100) | |
* @param {number} l - Lightness (0-100 percent, default: 69) | |
* @returns {string} ANSI escape sequence for 24-bit color | |
* | |
* The magic number 69 for lightness provides optimal visibility | |
* across different terminal backgrounds (not too dark, not too bright) | |
*/ | |
function hslToAnsi(h, s = 100, l = 69) { | |
// Convert percentages to decimal (0-1 range) | |
s /= 100; | |
l /= 100; | |
// HSL to RGB conversion algorithm | |
// k(n) calculates the hue sector for each RGB component | |
const k = n => (n + h / 30) % 12; | |
// Calculate chroma (color intensity) | |
const a = s * Math.min(l, 1 - l); | |
// RGB component calculation function | |
const f = n => | |
l - a * Math.max(-1, Math.min(k(n) - 3, 9 - k(n), 1)); | |
// Calculate RGB values and convert to 0-255 range | |
const [r, g, b] = [f(0), f(8), f(4)].map(v => Math.round(v * 255)); | |
// Return ANSI 24-bit color escape sequence | |
// Format: \x1b[38;2;{r};{g};{b}m (38 = foreground, 2 = RGB mode) | |
return `\x1b[38;2;${r};${g};${b}m`; | |
} | |
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
// ๐ ANIMATION ENGINE - Prompt update and rendering logic | |
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
// Global tick counter for animation timing | |
let tick = 0; | |
/** | |
* Updates the animated prompt with new spinner position and color | |
* | |
* This function: | |
* 1. Cycles through spinner characters | |
* 2. Calculates rainbow hue based on tick count | |
* 3. Generates colored ANSI escape sequences | |
* 4. Clears the current line | |
* 5. Renders the new prompt | |
*/ | |
function updatePrompt() { | |
// Get current spinner character (cycles through array) | |
const icon = spinner[tick % spinner.length]; | |
// Calculate hue for rainbow effect (multiplied by 3 for faster color cycling) | |
// Modulo 360 keeps hue in valid range (0-359 degrees) | |
const hue = (tick * 3) % 360; | |
// Convert hue to ANSI color code | |
const color = hslToAnsi(hue); | |
// Construct the animated prompt string | |
const prompt = `${BOLD}${color}${icon}${RESET} Waiting for agent ${BOLD}${color}โฏ${RESET} `; | |
// Set the new prompt (but don't display it yet) | |
rl.setPrompt(prompt); | |
// Clear current line and move cursor to beginning | |
// This prevents visual artifacts from previous prompt | |
readline.cursorTo(process.stdout, 0); | |
process.stdout.write(CLEAR_LINE); | |
// Display the prompt while preserving any user input | |
// Parameter 'true' preserves the current input line | |
rl.prompt(true); | |
// Increment tick counter for next animation frame | |
tick++; | |
} | |
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
// ๐ฅ INPUT HANDLER - Process user commands | |
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
// Listen for completed input lines (when user presses Enter) | |
rl.on('line', (line) => { | |
// TODO: Add your command processing logic here | |
// console.log(`\nYou typed: ${line}`); | |
// This is where you can: | |
// - Parse user commands | |
// - Execute system operations | |
// - Send data to APIs | |
// - Process AI agent requests | |
// - Handle file operations | |
// - etc. | |
// For now, we just silently accept input and continue the animation | |
}); | |
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
// ๐ INITIALIZATION - Start the application | |
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ | |
// Clear terminal screen for clean start | |
console.clear(); | |
// Display application header | |
console.log('๐ค koad:io nodejs prompt; v0.0.1'); | |
console.log('โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ'); | |
console.log('๐ก Type commands and press Enter'); | |
console.log('๐ Press Ctrl+C to exit'); | |
console.log(''); | |
// Start the animation loop | |
// Updates prompt every PROMPT_UPDATE_INTERVAL milliseconds | |
setInterval(updatePrompt, PROMPT_UPDATE_INTERVAL); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment