npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@shoru/spindle

v1.0.7

Published

A lightweight, singleton-based CLI multi-spinner library for Node.js

Readme

Spindle

A lightweight, singleton-based CLI multi-spinner library for Node.js. Run multiple spinners simultaneously without visual corruption, with automatic console interception.

Node.js Downloads npm Types

Installation · Quick Start · API


✨ Features

  • 🔄 Multiple Concurrent Spinners - Run as many spinners as you need
  • 🎨 Customizable Colors - 17 color options for spinner customization
  • 📝 Console Interception - console.log and friends work seamlessly without breaking spinners
  • Final States - Complete spinners with success, failure, warning, or info icons
  • 🧹 Automatic Cleanup - Graceful handling of process exit, SIGINT, and SIGTERM
  • 📦 Singleton Architecture - Centralized render management for flicker-free output

Installation

npm install @shoru/spindle

📦 Installation

npm install @shoru/spindle

Requires Node.js 18+


Quick Start

import { spindle } from '@shoru/spindle';

const spinner = spindle('Loading...').start();

// Do some async work
await someAsyncTask();

spinner.succeed('Done!');

API

Creating a Spindle

import { spindle, Spindle } from '@shoru/spindle';

// Using factory function (recommended)
const spinner = spindle('Initial text');

// Using constructor
const spinner = new Spindle('Initial text');

Methods

.start(text?)

Starts the spinner. Optionally updates the text.

spinner.start();
spinner.start('New loading message...');

.stop()

Stops the spinner without displaying a final message.

spinner.stop();

.succeed(text?)

Stops with a green checkmark (✔).

spinner.succeed('Task completed successfully');

.fail(text?)

Stops with a red cross (✖).

spinner.fail('Task failed');

.warn(text?)

Stops with a yellow warning sign (⚠).

spinner.warn('Task completed with warnings');

.info(text?)

Stops with a blue info icon (ℹ).

spinner.info('Additional information');

Properties

.text / .title

Get or set the spinner text. Both properties are interchangeable.

spinner.text = 'Downloading files...';
console.log(spinner.text); // 'Downloading files...'

.color

Get or set the spinner color.

spinner.color = 'magenta';

.isSpinning

Check if the spinner is currently active.

if (spinner.isSpinning) {
  spinner.succeed('Finished');
}

Available Colors

| Standard | Bright | |----------|--------| | black | gray/grey | | red | redBright | | green | greenBright | | yellow | yellowBright | | blue | blueBright | | magenta | magentaBright | | cyan | cyanBright | | white | whiteBright |

Default: cyan

RendererManager

The RendererManager singleton coordinates all active spinners. You typically don't need to interact with it directly, but it's available for advanced use cases.

import { RendererManager } from '@shoru/spindle';

// Check if any spinners are active
if (RendererManager.isActive()) {
  console.log('Spinners are running');
}

// Get count of active spinners
const count = RendererManager.getActiveCount();

// Force reset all spinners (use with caution)
RendererManager.reset(true);

TypeScript Support

Full TypeScript support with exported types:

import { 
  Spindle, 
  spindle, 
  SpinnerColor, 
  FinalState, 
  TaskState,
  Renderable 
} from '@shoru/spindle';

const color: SpinnerColor = 'cyan';
const state: FinalState = 'completed';

How It Works

  1. Singleton Renderer: A single RendererManager coordinates all spinner instances
  2. Console Interception: When spinners are active, console methods are intercepted and buffered
  3. Unified Rendering: All spinners render to a single output using log-update
  4. Clean Output: Buffered logs are flushed above the spinner display
  5. Graceful Cleanup: Process signals trigger proper cleanup to restore console state

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create feature branch git checkout -b feature/amazing-feature
  3. Commit changes git commit -m 'Add amazing feature'
  4. Push git push origin feature/amazing-feature
  5. Open Pull Request

License This project is licensed under the MIT License — see the LICENSE file for details.

Made with ❤️ for the Node.js CLI community

⬆ Back to Top