Pin
pin is a lightweight, customizable terminal spinner library for Go applications
Install / Use
/learn @yarlson/PinREADME
pin
pin is a lightweight, customizable terminal spinner library for Go applications. It provides an elegant way to show progress and status in CLI applications with support for colors, custom symbols, and flexible positioning.

Features
- 🎨 Customizable colors for all spinner elements via functional options
- 🔄 Smooth braille-pattern animation
- 🎯 Flexible positioning (spinner before/after message)
- 💫 Configurable prefix and separator
- 🔤 UTF-8 symbol support
- ✨ Ability to update the spinner message dynamically
- 🖼️ Customizable spinner frames for unique animation effects
- ⚙️ No external dependencies – uses only the Go standard library
- 🚀 Compatible with Go 1.11 and later
- ⏹ Automatically disables animations in non-interactive (piped) environments to prevent output corruption
Installation
go get github.com/yarlson/pin
Quick Start
p := pin.New("Loading...",
pin.WithSpinnerColor(pin.ColorCyan),
pin.WithTextColor(pin.ColorYellow),
)
cancel := p.Start(context.Background())
defer cancel()
// do some work
p.Stop("Done!")
Custom Output Writer
You can direct spinner output to an alternative writer (for example, os.Stderr) using the WithWriter option:
p := pin.New("Processing...",
pin.WithSpinnerColor(pin.ColorCyan),
pin.WithTextColor(pin.ColorYellow),
pin.WithWriter(os.Stderr), // output will be written to stderr
)
cancel := p.Start(context.Background())
defer cancel()
// perform your work
p.Stop("Done!")
Non-interactive Behavior
When the spinner detects that stdout is not connected to an interactive terminal (for example, when output is piped), it disables animations and outputs messages as plain text. In this mode:
- The initial message is printed immediately when the spinner starts.
- Any updated messages are printed as soon as you call
UpdateMessage(). - The final done message is printed when you call
Stop().
Examples
Basic Progress Indicator
p := pin.New("Processing data")
cancel := p.Start(context.Background())
defer cancel()
// ... do work ...
p.UpdateMessage("Almost there...")
// finish work
p.Stop("Completed!")
Styled Output
p := pin.New("Uploading",
pin.WithPrefix("Transfer"),
pin.WithSeparator("→"),
pin.WithSpinnerColor(pin.ColorBlue),
pin.WithTextColor(pin.ColorCyan),
pin.WithPrefixColor(pin.ColorYellow),
)
p.Start()
// ... do work ...
p.Stop("Upload complete")
Right-side Spinner
p := pin.New("Downloading", pin.WithPosition(pin.PositionRight))
cancel := p.Start(context.Background())
defer cancel()
// ... do work ...
p.Stop("Downloaded")
Custom Styling & Message Updating
p := pin.New("Processing",
pin.WithPrefix("Task"),
pin.WithSeparator(":"),
pin.WithSeparatorColor(pin.ColorWhite),
pin.WithDoneSymbol('✔'),
pin.WithDoneSymbolColor(pin.ColorGreen),
)
cancel := p.Start(context.Background())
defer cancel()
// ... do work ...
p.UpdateMessage("Almost done...")
// finish work
p.Stop("Success")
Failure Indicator
You can express a failure state with the spinner using the new Fail() method. Customize the failure appearance with WithFailSymbol, WithFailSymbolColor, and (optionally) WithFailColor.
p := pin.New("Deploying",
pin.WithFailSymbol('✖'),
pin.WithFailSymbolColor(pin.ColorRed),
)
cancel := p.Start(context.Background())
defer cancel()
// ... perform tasks ...
p.Fail("Deployment failed")
API Reference
Creating a New Spinner
p := pin.New("message", /* options... */)
Available Options
WithSpinnerColor(color Color)– sets the spinner's animation color.WithTextColor(color Color)– sets the color of the message text.WithPrefix(prefix string)– sets text to display before the spinner.WithPrefixColor(color Color)– sets the color of the prefix text.WithSeparator(separator string)– sets the separator text between prefix and message.WithSeparatorColor(color Color)– sets the color of the separator.WithDoneSymbol(symbol rune)– sets the symbol displayed upon completion.WithDoneSymbolColor(color Color)– sets the color of the done symbol.WithFailSymbol(symbol rune)– sets the symbol displayed upon failure.WithFailSymbolColor(color Color)– sets the color of the failure symbol.WithFailColor(color Color)– sets the color of the failure message text.WithPosition(pos Position)– sets the spinner's position relative to the message.WithSpinnerFrames(frames []rune)– sets the spinner's frames.WithWriter(w io.Writer)– sets a custom writer for spinner output.
Available Colors
ColorDefaultColorBlackColorRedColorGreenColorYellowColorBlueColorMagentaColorCyanColorGrayColorWhite
Development & Compatibility
This library is written using only the Go standard library and supports Go version 1.11 and later.
Running Tests
go test -v ./...
Prompt
The LLM prompt example in example/prompt.md shows you how to quickly integrate pin into your codebase.
Contributing
- Fork the repository
- Create your feature branch:
git checkout -b feature/amazing-feature - Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
License
MIT License – see LICENSE for details
Acknowledgments
Inspired by elegant CLI spinners and the need for a simple, flexible progress indicator in Go applications.
Related Skills
node-connect
352.5kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
111.3kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
352.5kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
352.5kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
