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

@taoya7/rattles

v0.1.0

Published

Minimal terminal spinners for TypeScript/JavaScript. Port of the Rust `rattles` crate.

Readme

@taoya7/rattles

一个面向 TypeScript / JavaScript 的终端 braille spinner 库,移植自 Rust 版本 rattles

  • 内置 33 个 braille 动画预设
  • 支持基于时间的 Rattler 和手动推进的 TickedRattler
  • 支持反向播放、起始偏移、自定义帧间隔
  • 无运行时依赖,支持 ESM + CJS,附带完整类型声明

安装

pnpm add @taoya7/rattles
# 或 npm / yarn / bun

快速开始

import { dots } from "@taoya7/rattles";

const spinner = dots();

const timer = setInterval(() => {
  process.stdout.write(`\r${spinner.currentFrame()} loading...`);
}, 16);

setTimeout(() => {
  clearInterval(timer);
  process.stdout.write("\r✓ done           \n");
}, 3000);

currentFrame() 基于模块加载时创建的共享单调时钟计算当前帧,所以多个 spinner 可以天然保持同步,不需要你自己维护额外的计时器状态。

API

基于时间的 Rattler

import { dots12, Rattler } from "@taoya7/rattles";

const r: Rattler = dots12();

r.currentFrame();     // string:当前时间对应的单行 frame
r.currentFrames();    // string[]:当前时间对应的所有行(多行 spinner)
r.frameAt(250);       // elapsed = 250ms 时对应的 frame
r.frame(3);           // 指定 frame index
r.length;             // 总帧数
r.interval;           // 当前帧间隔(毫秒)
r.isReversed;         // 是否反向

r.setInterval(60);    // 修改播放速度
r.offset(2);          // 设置起始偏移
r.reverse();          // 切换正向 / 反向

手动推进的 TickedRattler

适合你想自己控制推进节奏的场景,比如固定帧循环、测试或逐步调试。

import { sand, TickedRattler } from "@taoya7/rattles";

const t: TickedRattler = sand().intoTicked();

t.currentFrame();     // 当前帧
t.tick();             // 前进 1 帧,并返回新的 frame rows
t.tickBy(3);          // 前进 3 帧
t.reset();            // 重置到起始位置

两个类都实现了 [Symbol.iterator],因此也可以这样使用:

for (const frames of dots()) {
  // frames 的类型是 readonly string[]
}

自定义 spinner

import { defineRattle, singleLineRattle, Rattler } from "@taoya7/rattles";

const Blink = singleLineRattle(1, 400, ["·", "•", "·", " "]);
const blink = () => new Rattler(Blink);

// 多行 spinner
const Pyramid = defineRattle(3, 3, 120, [
  ["  ▲  ", " ▲▲▲ ", "▲▲▲▲▲"],
  ["▲▲▲▲▲", " ▲▲▲ ", "  ▲  "],
]);

预设列表

当前包含原始 Rust 版本中的 33 个 braille 预设:

dots    dots2   dots3   dots4   dots5   dots6   dots7   dots8
dots9   dots10  dots11  dots12  dots13  dots14  dotsCircle
sand    bounce  wave    scan    rain    pulse   snake   sparkle
cascade columns orbit   breathe waveRows checkerboard helix
fillSweep diagSwipe infinity

每个预设都会导出两种形式:

  • 工厂函数,例如 dots(),返回一个新的 Rattler
  • 原始定义对象,例如 DotsDef: Rattle,方便你自己包装

颜色

可以指定颜色。

不过这个库本身不会主动输出 ANSI 颜色控制码currentFrame() 返回的是纯文本 frame。也就是说,颜色由你在输出时自己包裹。

直接使用 ANSI 颜色

import { dots } from "@taoya7/rattles";

const spinner = dots();
const CYAN = "\u001B[36m";
const RESET = "\u001B[0m";

setInterval(() => {
  process.stdout.write(`\r${CYAN}${spinner.currentFrame()}${RESET} fetching...`);
}, 16);

配合 picocolors / chalk / kleur

import pc from "picocolors";
import { snake } from "@taoya7/rattles";

const spinner = snake();

setInterval(() => {
  process.stdout.write(`\r${pc.magenta(spinner.currentFrame())} working...`);
}, 16);

因为 frame 本质上只是字符串,所以任意终端着色库都可以直接配合使用。

示例

仓库里提供了一个交互式展示示例:

pnpm example:showcase
# q / Ctrl-C -> 退出
# r          -> 所有 spinner 切换反向

License

MIT