Rattles Terminal Spinners

作者 reason-machines2384a003145a無授權條款83 個星標收錄於 2026年10月8日更新於 2026年10月8日儲存庫3 個月前更新

Minimal terminal spinner library for Rust with preset collection and no-std support

AI 產生的概覽

Rattles Rust 函式庫參考:終端機載入動畫預設、自訂關鍵影格、no_std 與 ratatui 用法。

功能
本技能介紹用於終端機載入動畫的 Rattles Rust 函式庫,涵蓋安裝方式、預設分類(箭頭、ASCII、盲文、emoji)以及 Rattler 與 TickedRattler 介面。它說明如何依系統時鐘、經過時間或索引取得影格,以及如何用 rattle! 巨集定義自訂載入動畫。另提供 ratatui、tokio 與 no_std 環境的整合範例與常見問題排解說明。
適用情境
適用於為 Rust 命令列應用程式加入動態載入指示器,包括 no_std 目標。也適合將載入動畫整合至 ratatui 介面或定義自訂關鍵影格時使用。
執行需求
需要 Rust 工具鏈與 rattles crate(0.1 版);整合範例可選用 ratatui 與 tokio crate。不附帶指令碼,僅為說明性內容。

Rattles Terminal Spinners

Skill by ara.so — Daily 2026 Skills collection.

Rattles is a minimal, zero-dependency Rust library for terminal spinners. It has no runtime or lifecycle — spinners are constructed directly in render loops with negligible cost. Supports no_std environments.

Installation

toml
# Cargo.toml[dependencies]rattles = "0.1"  # with std (default)
# no_stdrattles = { version = "0.1", default-features = false }

Or via CLI:

sh
cargo add rattles
# no_std variantcargo add rattles --no-default-features

Core Concepts

  • Rattler: a spinner definition (frames + interval). Stateless and cheap to construct.
  • TickedRattler: stateful wrapper for tick-based driving (required in no_std).
  • Presets: built-in spinners organized by category.
  • rattle! macro: define custom spinners at compile time.

Basic Usage (std)

rust
use std::{io::Write, time::Duration};use rattles::presets::prelude as presets;
fn main() {    let rattle = presets::dots();
    loop {        print!("\r{}", rattle.current_frame());        std::io::stdout().flush().unwrap();        std::thread::sleep(Duration::from_millis(80));    }}

current_frame() uses the system clock internally — no state needed.

Preset Categories

rust
use rattles::presets::{arrows, ascii, braille, emoji};use rattles::presets::prelude as presets; // re-exports all presets
// Arrowslet s = arrows::arrow();let s = arrows::arrow2();
// ASCIIlet s = ascii::line();let s = ascii::pipe();
// Braillelet s = braille::dots();let s = braille::dots2();
// Emojilet s = emoji::earth();let s = emoji::clock();
// Prelude exampleslet s = presets::waverows();let s = presets::dots();

Rattler API

rust
use rattles::presets::prelude as presets;use std::time::Duration;
let rattle = presets::dots();
// Get frame based on system clock (std only)let frame: &str = rattle.current_frame();
// Get frame at specific elapsed duration (std + no_std)let frame = rattle.frame_at(Duration::from_millis(500));
// Get frame by indexlet frame = rattle.frame(3);
// Change animation intervallet rattle = presets::dots().set_interval(Duration::from_millis(50));
// Reverse directionlet rattle = presets::waverows().reverse();
// Convert to tick-based (stateful)let mut ticked = presets::dots().into_ticked();

TickedRattler (Stateful / no_std-friendly)

rust
use rattles::presets::prelude as presets;
let mut rattle = presets::dots().into_ticked();
loop {    rattle.tick();    let frame = rattle.current_frame();    // render frame...}

TickedRattler must be stored (it holds state). Suitable for no_std contexts where the global clock is unavailable.

Index-Based Animation (no_std)

rust
use rattles::presets::prelude as presets;
let rattle = presets::dots();let mut i = 0usize;
loop {    let frame = rattle.frame(i);    i = i.wrapping_add(1);    // render frame...}

Time-Based Animation with External Clock (no_std)

rust
use rattles::presets::prelude as presets;use core::time::Duration;
let rattle = presets::dots();
// elapsed comes from your platform's timerlet elapsed: Duration = get_elapsed(); // your implementationlet frame = rattle.frame_at(elapsed);

Custom Spinners with rattle! Macro

rust
use rattles::rattle;
rattle!(    MySpinner,   // generated struct name    my_spinner,  // generated constructor function name    1,           // row count (width of spinner)    120,         // interval in milliseconds    ["⣾", "⣷", "⣯", "⣟", "⣻", "⣽"]  // keyframes);
// Use it like any presetlet s = my_spinner();println!("{}", s.current_frame());

Multi-row custom spinner:

rust
rattle!(    Wide,    wide_spinner,    3,   // 3 characters wide    80,    ["[   ]", "[=  ]", "[== ]", "[===]", "[ ==]", "[  =]"]);

Ratatui Integration

rust
// examples/ratatui.rs patternuse rattles::presets::prelude as presets;use ratatui::{    backend::CrosstermBackend,    widgets::Paragraph,    Terminal,};
fn ui(frame: &mut ratatui::Frame, rattle: &rattles::Rattler) {    let spinner_text = rattle.current_frame();    let paragraph = Paragraph::new(format!("{} Loading...", spinner_text));    frame.render_widget(paragraph, frame.size());}
fn main() -> std::io::Result<()> {    let rattle = presets::dots();
    // standard ratatui event loop    loop {        terminal.draw(|f| ui(f, &rattle))?;        std::thread::sleep(std::time::Duration::from_millis(16));
        // break on user input...    }    Ok(())}

Since Rattler is stateless, pass it by reference anywhere — no Arc<Mutex<>> needed.

no_std Setup

toml
[dependencies]rattles = { version = "0.1", default-features = false }
rust
#![no_std]use rattles::presets::prelude as presets;
// Option 1: tick-basedlet mut rattle = presets::dots().into_ticked();rattle.tick();let frame = rattle.current_frame();
// Option 2: index-basedlet rattle = presets::dots();let frame = rattle.frame(42);
// Option 3: duration-based (external clock)let rattle = presets::dots();let frame = rattle.frame_at(core::time::Duration::from_millis(840));

Common Patterns

Spinner with message

rust
use rattles::presets::prelude as presets;use std::{io::Write, time::Duration};
fn main() {    let rattle = presets::dots();    let message = "Fetching data...";
    loop {        print!("\r{} {}", rattle.current_frame(), message);        std::io::stdout().flush().unwrap();        std::thread::sleep(Duration::from_millis(80));    }}

Async-compatible (tokio)

rust
use rattles::presets::prelude as presets;use tokio::time::{sleep, Duration};
#[tokio::main]async fn main() {    let rattle = presets::dots();
    let spinner = tokio::spawn(async move {        loop {            print!("\r{}", rattle.current_frame());            std::io::stdout().flush().unwrap();            sleep(Duration::from_millis(80)).await;        }    });
    // do your async work    do_work().await;    spinner.abort();    println!("\rDone!     ");}

Collecting all frames

rust
let rattle = presets::dots();let frames: Vec<&str> = (0..rattle.frame_count())    .map(|i| rattle.frame(i))    .collect();

Troubleshooting

Spinner not animating (stuck on first frame)

  • Ensure you're flushing stdout: std::io::stdout().flush().unwrap()
  • Use \r to overwrite the line, not \n
  • The sleep interval should match or be shorter than the spinner's interval

current_frame() not available in no_std

  • Use frame_at(duration), frame(index), or into_ticked() instead
  • Disable default features: rattles = { version = "...", default-features = false }

Custom spinner not compiling

  • Keyframes must be string literals in the rattle! macro array
  • Row count must match the visual width of each keyframe string

Spinner looks garbled in terminal

  • Some braille/emoji frames require a terminal with Unicode support
  • Test with ASCII presets (ascii::line()) to verify basic functionality first

來源與署名

來源:reason-machines/trending-skills位於skills/rattles-terminal-spinners提交2384a00

授權條款: 無授權條款

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架