Skip to content

jayrdeaton/TermPulse

Repository files navigation

termpulse

Animated terminal progress bars, spinners, and status messages for Node.js CLI applications.

Install

npm install termpulse

Bar

import { Bar } from 'termpulse'

const bar = new Bar()
bar.start()
bar.message('Starting...')

setTimeout(() => bar.stop('Done!'), 3000)
const { Bar } = require('termpulse')

Options

const bar = new Bar({
  length: 80,           // bar width (default: terminal width)
  prefix: '[',          // leading clamp (default: '[')
  suffix: ']',          // trailing clamp (default: ']')
  character: '-',       // moving character (default: '-')
  before: ' ',          // fill before position (default: ' ')
  after: ' ',           // fill after position (default: ' ')
  text: '',             // label shown beside the bar (default: '')
  reverse: false,       // put label before the bar (default: false)
  interval: 35,         // ms per frame (default: 35)
  mode: 'bounce',       // 'bounce' | 'loop' | 'loop-reverse' (default: 'bounce')
  progress: 0,          // 0–1 enables determinate mode
  colors: [],           // hex gradient array, e.g. Bar.COLORS.rainbow
  bgColors: [],         // background gradient
  colorFill: false,     // apply dimmed gradient to fill chars
  colorCycle: 0,        // gradient shift speed in cycles/second
  shimmer: 0,           // brightness wave amplitude 0–1
  onBounce: () => {},   // fires on direction reversal
  onLoop: () => {},     // fires on position wrap
  onComplete: () => {}, // fires once when progress reaches 1
  successColor: '#...',  // ✔ color override (default: green)
  failColor: '#...',     // ✖ color override (default: red)
  warnColor: '#...',     // ⚠ color override (default: yellow)
  infoColor: '#...',     // ℹ color override (default: blue)
  glyphs: true,          // include ✔ ✖ ⚠ ℹ in non-TTY output (default: true)
})

Setters

All properties can be changed while the bar is running.

bar.prefix = 'Loading: ['
bar.suffix = '] 42%'
bar.character = '='
bar.before = '-'
bar.after = '-'
bar.empty = '·'           // sets both before and after
bar.text = 'Uploading…'
bar.mode = 'loop'
bar.progress = 0.5        // switch to determinate
bar.progress = undefined  // back to animation
bar.colors = Bar.COLORS.rainbow
bar.colorCycle = 0.5
bar.shimmer = 0.7

Color gradients

Pass an array of hex colors. The gradient is interpolated across the bar by position.

bar.colors = ['#0000ff', '#ff0000']    // blue → red
bar.colors = Bar.COLORS.rainbow        // preset

Built-in presets: blueRed, redBlue, rainbow, heat, cool, sunset.

API

Method Description
bar.start() Begin animation, hide cursor
bar.stop(msg?) Stop animation, restore cursor, optionally print message
bar.message(string) Update the label beside the bar
bar.succeed(msg?) Print ✔ msg line
bar.fail(msg?) Print ✖ msg line
bar.warn(msg?) Print ⚠ msg line
bar.info(msg?) Print ℹ msg line

Spinner

import { Spinner } from 'termpulse'

const spinner = new Spinner({
  frames: Spinner.FRAMES.braille,
  colors: Bar.COLORS.rainbow,
  colorCycle: 1.0,
  text: 'Loading…',
})
spinner.start()

setTimeout(() => spinner.stop('Done!'), 3000)

Options

const spinner = new Spinner({
  frames: Spinner.FRAMES.braille, // frame array (default: braille)
  prefix: '',            // string prepended to the spinner line
  suffix: '',            // string appended to the spinner line
  text: '',              // label shown beside the spinner
  reverse: false,        // put label before the spinner (default: false)
  interval: 80,          // ms per frame (default: 80)
  colors: [],            // hex gradient
  bgColors: [],          // background gradient
  colorCycle: 0,         // gradient shift speed in cycles/second
  shimmer: 0,            // brightness wave amplitude 0–1
  onSpin: () => {},      // fires after each full frame cycle
  successColor: '#...',  // ✔ color override (default: green)
  failColor: '#...',     // ✖ color override (default: red)
  warnColor: '#...',     // ⚠ color override (default: yellow)
  infoColor: '#...',     // ℹ color override (default: blue)
  glyphs: true,          // include ✔ ✖ ⚠ ℹ in non-TTY output (default: true)
})

Built-in frame sets: braille, dots, line, arrow, bounce.

Setters

All properties can be changed while the spinner is running.

spinner.frames     = Spinner.FRAMES.dots
spinner.text       = 'Still working…'
spinner.colors     = Bar.COLORS.heat
spinner.colorCycle = 0.5
spinner.shimmer    = 0.8

API

Method Description
spinner.start() Begin animation, hide cursor
spinner.stop(msg?) Stop animation, restore cursor, optionally print message
spinner.message(string) Update the label beside the spinner
spinner.succeed(msg?) Print ✔ msg line
spinner.fail(msg?) Print ✖ msg line
spinner.warn(msg?) Print ⚠ msg line
spinner.info(msg?) Print ℹ msg line

Select

Interactive single-item picker with animated highlight and optional descriptions.

import { Select } from 'termpulse'

const select = new Select()

const choice = await select.ask('Which framework?', [
  { label: 'React' },
  { label: 'Vue' },
  { label: 'Svelte' },
])

if (choice) console.log(`Picked: ${choice.label}`)
const { Select } = require('termpulse')

Navigate with / or number keys. Press Enter to confirm, or choose the auto-appended Skip item to return null.

Items

Each item requires a label and accepts an optional description:

const items = [
  { label: 'Production',  description: 'live traffic' },
  { label: 'Staging',     description: 'QA sign-off required' },
  { label: 'Development', description: 'breaks often' },
]

You can attach any extra fields to items — whatever type you pass in is what you get back:

interface Env { label: string; url: string }
const env = await select.ask<Env>('Target?', [
  { label: 'Production', url: 'https://example.com' },
])
if (env) deploy(env.url)

Options

const select = new Select({
  skipLabel: 'Skip',         // label for the skip/none item (default: 'Skip')
  promptGlyph: '◆',         // glyph before the prompt line (default: '◆')
  promptColor: '#...',       // color for glyph and selected marker (default: green)
  descriptionColor: '#...',  // color for item descriptions (default: blue)
  selectedPrefix: '>',       // marker shown left of selected item (default: '>')
  selectedSuffix: '<',       // marker shown right of selected item (default: '<')
  colors: [],                // hex gradient for animated selected marker
  colorCycle: 1.0,           // gradient shift speed in cycles/second
  shimmer: 0,                // brightness wave amplitude 0–1
  interval: 80,              // animation frame interval in ms
})

API

Method Description
select.ask(prompt, items) Show prompt and list, resolve with selected item or null if skipped

log

Print a one-line status message without needing an active spinner or bar.

import { log } from 'termpulse'

log.succeed('Deployment complete')
log.fail('Connection refused')
log.warn('Deprecated API in use')
log.info('Listening on port 3000')
const { log } = require('termpulse')

Options

All four methods accept an optional message and an optional options object:

log.succeed(message?, options?)
log.fail(message?, options?)
log.warn(message?, options?)
log.info(message?, options?)
interface LogOptions {
  color?: string   // hex or ANSI color override for the glyph
  glyphs?: boolean // include ✔ ✖ ⚠ ℹ in non-TTY output (default: true)
}

API

Method Glyph Default color
log.succeed(msg?, opts?) green
log.fail(msg?, opts?) red
log.warn(msg?, opts?) yellow
log.info(msg?, opts?) blue

Non-TTY environments

When stdout is not a TTY (piped to a file, CI log, etc.) termpulse automatically adjusts:

  • The animation loop does not start — no bar or spinner frames are written.
  • ANSI colors and cursor escape codes are suppressed.
  • Select.ask() returns null immediately without rendering.
  • stop(msg?), succeed, fail, warn, and info on Bar/Spinner, and all log.* methods, still write their message as plain text, prefixed with the status glyph by default:
✔ Build complete
✖ Connection failed
⚠ Retrying…
ℹ 3 files skipped

Set glyphs: false to omit the glyph prefix and write only the message text.


License

MIT © Jay Deaton

About

Animated terminal progress bars and spinners for Node.js CLI applications

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors