zeptospin
v1.0.0
Published
Ultra-lightweight, zero-dependency terminal spinner with built-in cursor safety and CI detection.
Maintainers
Readme
zeptospin ⚡️
Ultra-lightweight (~1.5kB minified + gzipped), zero-dependency, type-safe terminal spinner for Node.js.
Highly optimized, pure TypeScript/JavaScript terminal spinner. It behaves similarly to ora and yocto-spinner, but has zero external dependencies (no picocolors, cli-spinners, or chalk), built-in process exit/SIGINT cursor safety, and clean CI log output.
Features
- 📦 Sub-2kB weight: Extremely small install footprint.
- 🎨 Built-in ANSI Colors: Tiny color utility built directly in the library.
- 🚀 Zero Dependencies: Safely import without polluting your node_modules.
- 🛡️ Cursor & Signal Safety: Listens to exit signals (
SIGINT,SIGTERM,uncaughtException) to automatically restore the terminal cursor if aborted mid-run. - 📺 CI / Non-TTY Detection: Automatically detects non-interactive terminals or CI environments and falls back to a clean list-like output instead of animating.
- 🛠️ Fully Typed: Written in TypeScript with standard ESM and CommonJS support.
- 🎁 Preset Animations: Built-in classic animations like
dots,line,pulse, andarrow. - 🤝 Promise Wrapper: Easily wrap any async operation to automatically spin and resolve.
Install
npm install zeptospinUsage
import { zeptospin } from 'zeptospin';
// Create and start the spinner
const spinner = zeptospin('Loading user profile...').start();
// Perform some async task
await delay(1500);
// Resolve with success
spinner.success('Profile loaded successfully!');All Resolution Types
const spinner = zeptospin('Working...').start();
spinner.success('Done!'); // ✔ Done!
spinner.error('Failed!'); // ✖ Failed!
spinner.warn('Warning!'); // ⚠ Warning!
spinner.info('Info!'); // ℹ Info!Dynamic Resolution Overrides
You can pass an options object to final state methods to override both the text and the status symbol (e.g. using custom emojis or icons):
spinner.success({ text: 'Deploy complete!', symbol: '🚀' }); // 🚀 Deploy complete!
spinner.error({ text: 'Service crashed!', symbol: '💥' }); // 💥 Service crashed!Promise Tracking with spinPromise
Track a promise's lifecycle automatically. The spinner starts on invocation and resolves into a checkmark or error symbol when the promise finishes:
import { spinPromise } from 'zeptospin';
// Runs async task, automatically outputting success or error symbols upon completion
const result = await spinPromise(fetchUserData(userId), {
text: 'Connecting to database...',
successText: 'User database fetched!',
errorText: 'Failed to retrieve database!',
color: 'magenta'
});Presets and Customization
You can choose from built-in animation presets ('dots' | 'line' | 'pulse' | 'arrow') or specify custom frames:
import { zeptospin } from 'zeptospin';
// Using a built-in 'pulse' preset
const spinner = zeptospin({
text: 'Compiling project...',
type: 'pulse', // ░ ▒ ▓ █ ▓ ▒ ░
color: 'green'
}).start();
// Custom frames and interval
const customSpinner = zeptospin({
text: 'Downloading assets...',
frames: ['◐', '◓', '◑', '◒'],
interval: 150,
color: 'blue'
}).start();API
zeptospin(optionsOrText?) or createSpinner(optionsOrText?)
Instantiates and returns a new ZeptoSpin instance.
Options
text(string): The text to display next to the spinner.color(string): The color of the spinner frame. Options:'red' | 'green' | 'yellow' | 'blue' | 'magenta' | 'cyan' | 'white' | 'gray'. Default:'cyan'.stream(NodeJS.WriteStream): The terminal stream to write to. Default:process.stderr.frames(string[]): Array of frames to animate. Default:['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'].interval(number): Frame duration in milliseconds. Default:80.type(string): Built-in animation preset. Options:'dots' | 'line' | 'pulse' | 'arrow'.silent(boolean): Iftrue, the spinner will be silent and won't write to the stream.successText(string): Default final success text when usingspinPromise.errorText(string): Default final error text when usingspinPromise.
Instance Methods
.start(text?)
Starts the spinner animation. If text is passed, it updates the text.
.stop()
Stops the spinner animation and cleans up intervals. If interactive, it clears the line and restores the cursor.
.update(optionsOrText)
Dynamically update any spinner configuration on the fly:
spinner.update('Still working...');
spinner.update({ color: 'green', text: 'Almost there!', type: 'line' });.success(optionsOrText?)
Stops the spinner, clears the line, prints success symbol with text, and restores the cursor. Accepts string text or { text, symbol } overrides.
.error(optionsOrText?)
Stops the spinner, clears the line, prints error symbol with text, and restores the cursor. Accepts string text or { text, symbol } overrides.
.warn(optionsOrText?)
Stops the spinner, clears the line, prints warning symbol with text, and restores the cursor. Accepts string text or { text, symbol } overrides.
.info(optionsOrText?)
Stops the spinner, clears the line, prints info symbol with text, and restores the cursor. Accepts string text or { text, symbol } overrides.
.stopAndPersist(symbol, text?)
Stops the spinner, clears the line, prints a custom prefix symbol followed by text, and restores the cursor.
Utility Functions
spinPromise(promise, optionsOrText)
Wraps a promise to run a spinner during its execution. Returns the resolved promise value or throws the rejected error.
License
MIT © 2026
