@taoya7/rattles
v0.1.0
Published
Minimal terminal spinners for TypeScript/JavaScript. Port of the Rust `rattles` crate.
Maintainers
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
