unicode-animations

18 braille spinner animations as raw frame data

npm install unicode-animations
import spinners from 'unicode-animations'

const { frames, interval } = spinners.braille
let i = 0

const timer = setInterval(() => {
  process.stdout.write(`\r${frames[i++ % frames.length]} Loading...`)
}, interval)

await doWork()
clearInterval(timer)
process.stdout.write('\r✔ Done.\n')
// ESM
import spinners from 'unicode-animations'

// CJS
const spinners = require('unicode-animations')

Each spinner is a { frames: string[], interval: number } object.

CLI tool — spinner during async work
import spinners from 'unicode-animations'

const { frames, interval } = spinners.braille
let i = 0

const spinner = setInterval(() => {
  process.stdout.write(`\r\x1B[2K  ${frames[i++ % frames.length]} Deploying...`)
}, interval)

await deploy()

clearInterval(spinner)
process.stdout.write('\r\x1B[2K  ✔ Deployed.\n')
Reusable spinner helper
import spinners from 'unicode-animations'

function createSpinner(msg, name = 'braille') {
  const { frames, interval } = spinners[name]
  let i = 0, text = msg
  const timer = setInterval(() => {
    process.stdout.write(`\r\x1B[2K  ${frames[i++ % frames.length]} ${text}`)
  }, interval)

  return {
    update(msg) { text = msg },
    stop(msg) { clearInterval(timer); process.stdout.write(`\r\x1B[2K  ✔ ${msg}\n`) },
  }
}

const s = createSpinner('Connecting to database...')
const db = await connect()
s.update(`Running ${migrations.length} migrations...`)
await db.migrate(migrations)
s.stop('Database ready.')
Multi-step pipeline
import spinners from 'unicode-animations'

async function runWithSpinner(label, fn, name = 'braille') {
  const { frames, interval } = spinners[name]
  let i = 0
  const timer = setInterval(() => {
    process.stdout.write(`\r\x1B[2K  ${frames[i++ % frames.length]} ${label}`)
  }, interval)
  const result = await fn()
  clearInterval(timer)
  process.stdout.write(`\r\x1B[2K  ✔ ${label}\n`)
  return result
}

await runWithSpinner('Linting...', lint, 'scan')
await runWithSpinner('Running tests...', test, 'helix')
await runWithSpinner('Building...', build, 'cascade')
await runWithSpinner('Publishing...', publish, 'braille')
React component
import { useState, useEffect } from 'react'
import spinners from 'unicode-animations'

function Spinner({ name = 'braille', children }) {
  const [frame, setFrame] = useState(0)
  const s = spinners[name]

  useEffect(() => {
    const timer = setInterval(
      () => setFrame(f => (f + 1) % s.frames.length),
      s.interval
    )
    return () => clearInterval(timer)
  }, [name])

  return <span style={{ fontFamily: 'monospace' }}>{s.frames[frame]} {children}</span>
}

// Usage: <Spinner name="helix">Generating response...</Spinner>
Browser — status indicator
import spinners from 'unicode-animations'

const el = document.getElementById('status')
const { frames, interval } = spinners.orbit
let i = 0

const spinner = setInterval(() => {
  el.textContent = `${frames[i++ % frames.length]} Syncing...`
}, interval)

await sync()
clearInterval(spinner)
el.textContent = '✔ Synced'
Classic braille
NamePreviewInterval
braille⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏80ms
braillewave⠁⠂⠄⡀⠂⠄⡀⢀100ms
dna⠋⠉⠙⠚⠉⠙⠚⠒80ms
Grid animations (braille)
NameFramesInterval
scan1070ms
rain12100ms
scanline6120ms
pulse5180ms
snake1680ms
sparkle6150ms
cascade1260ms
columns2660ms
orbit8100ms
breathe17100ms
waverows1690ms
checkerboard4250ms
helix1680ms
fillsweep11100ms
diagswipe1660ms

Create your own braille spinners using the grid utilities:

import { gridToBraille, makeGrid } from 'unicode-animations'

// Create a 4-row × 4-col grid
const grid = makeGrid(4, 4)
grid[0][0] = true
grid[1][1] = true
grid[2][2] = true
grid[3][3] = true

console.log(gridToBraille(grid)) // diagonal braille pattern

makeGrid(rows, cols) returns a boolean[][]. Set cells to true to raise dots. gridToBraille(grid) converts it to a braille string (2 dot-columns per character).

Spinner
interface Spinner {
  readonly frames: readonly string[]
  readonly interval: number
}
Exports from 'unicode-animations'
ExportType
default / spinnersRecord<BrailleSpinnerName, Spinner>
gridToBraille(grid)(boolean[][]) => string
makeGrid(rows, cols)(number, number) => boolean[][]
SpinnerTypeScript interface
BrailleSpinnerNameUnion type of all 18 spinner names

The subpath 'unicode-animations/braille' re-exports everything from the main entrypoint.