
Product
Microsoft Teams Notifications Are Now Available in Socket
Socket can now send alerts and supply chain attack notifications to Microsoft Teams, with filters that route the right updates to each channel.
@cleocode/animations
Advanced tools
CLEO terminal animations — braille spinners, progress bars, and sparks for the cleo CLI and CleoOS. Forked from gunnargray-dev/unicode-animations (MIT).
Unicode terminal animations for the cleo CLI and CleoOS — woven on the LOOM, gated by LAFS.
Provides four primitive surfaces, each gated by a single AnimateContext so the
LAFS protocol invariant ("JSON output is the default; human rendering requires
explicit opt-in") holds uniformly:
unicode-animations (MIT, Gunnar Gray)looming, weaving, heartbeat, …) on the same frame datatapestry, cascade, refinery (canon-themed segmented gauges)awaken, sweep, cascade, weave)pnpm add @cleocode/animations
# or
npm install @cleocode/animations
ESM-only. Requires Node ≥ 22.
createSpinnerHandlecreateSpinnerHandle is the canonical owner of \r writes for this package.
It manages the timer, hides/restores the cursor, installs an exit handler so
Ctrl-C doesn't leave a hidden cursor, and routes everything through the
LAFS render gate. Calling process.stdout.write of a string starting with
\r outside this package is a contract violation — always go through the
handle.
import { resolveOutputFormat } from '@cleocode/lafs';
import { createAnimateContext, createSpinnerHandle } from '@cleocode/animations';
const ctx = createAnimateContext({
flagResolution: resolveOutputFormat({ humanFlag: true }),
});
const spinner = createSpinnerHandle(ctx, 'looming', 'Weaving tasks…');
spinner.start();
try {
await doWork();
spinner.stop('✔ Tapestry complete.');
} catch (err) {
spinner.stop();
throw err;
}
Under --json / --quiet / non-TTY / NO_COLOR the handle is a frozen no-op
and emits zero output — call sites stay branch-free.
import { renderProgressBar } from '@cleocode/animations';
function tick(done: number, total: number) {
const ratio = done / total;
const bar = renderProgressBar('refinery', ratio, 36);
process.stdout.write(`\r\x1B[2K ${bar} ${done}/${total}`);
}
import { sparks } from '@cleocode/animations';
async function playSpark(name: 'awaken' | 'sweep' | 'cascade' | 'weave') {
const { frames, interval } = sparks[name];
for (const f of frames) {
process.stdout.write(`\r\x1B[2K ${f}`);
await new Promise(r => setTimeout(r, interval));
}
process.stdout.write('\n');
}
await shipRelease();
await playSpark('cascade');
AnimateContextEvery primitive routes through an AnimateContext so the package obeys the
LAFS protocol uniformly. The context is pure data — no I/O, no timers —
derived from the LAFS FlagResolution plus environment signals.
import { resolveOutputFormat } from '@cleocode/lafs';
import { createAnimateContext, createSpinnerHandle } from '@cleocode/animations';
const flags = resolveOutputFormat({ humanFlag: true });
const ctx = createAnimateContext({ flagResolution: flags });
// Hand `ctx` to any primitive — they all become no-ops when `ctx.enabled === false`.
const spinner = createSpinnerHandle(ctx, 'looming', 'Loading…');
if (!ctx.enabled) {
// ctx.reason ∈ 'format-json' | 'quiet' | 'no-tty' | 'no-color' | 'enabled'
console.log(`silent: ${ctx.reason}`);
}
| Signal | Source | Effect | reason |
|---|---|---|---|
format !== 'human' | LAFS flags | Disable (machine output) | format-json |
quiet === true | LAFS flags | Disable (script-friendly) | quiet |
!isTTY | process.stdout.isTTY | Disable (piped/redirected) | no-tty |
NO_COLOR set | process.env.NO_COLOR | Disable (no-color.org) | no-color |
SILENT_CONTEXT is exported as a frozen always-disabled context for tests and
libraries that want to opt out without constructing a full LAFS resolution.
| Name | Frames | Interval | Name | Frames | Interval |
|---|---|---|---|---|---|
braille | 10 | 80ms | cascade | 14 | 60ms |
braillewave | 8 | 100ms | columns | 26 | 60ms |
dna | 12 | 80ms | orbit | 8 | 100ms |
scan | 10 | 70ms | breathe | 17 | 100ms |
rain | 12 | 100ms | waverows | 16 | 90ms |
scanline | 6 | 120ms | checkerboard | 4 | 250ms |
pulse | 5 | 180ms | helix | 16 | 80ms |
snake | 16 | 80ms | fillsweep | 11 | 100ms |
sparkle | 6 | 150ms | diagswipe | 16 | 60ms |
| Canon name | → Generic | Cleo lore role |
|---|---|---|
looming | helix | Twin strands weaving — task on the LOOM |
weaving | braillewave | Pattern threading across columns |
heartbeat | breathe | Organic in-out pulse — Hearth presence |
awakening | pulse | Radial bloom — first dream / cleo init |
sweeping | scan | Left→right beam — BRAIN integrity Sweep |
watching | orbit | Circular sentinel — sentient daemon tick |
cascade | cascade | Diagonal fall — command-success accent |
tapestry | waverows | Multi-row sinusoidal — wave of tasks shipping |
refinery | columns | Filling stages — memory promotion pipeline |
Canon entries are aliases, not copies — they reference the same Spinner
objects as the generic registry. Renaming a generic spinner automatically
updates the canon view. The mapping is exposed as CANON_TO_GENERIC and
resolveSpinner(name) accepts either form.
renderProgressBar(style, ratio, width) returns a fixed-width string. Three
canon styles:
| Style | Characters | Feel |
|---|---|---|
tapestry | ░ ▒ ▓ █ | Coarse blocks — woven cloth filling cell-by-cell |
cascade | ▏ ▎ ▍ ▌ ▋ ▊ ▉ █ | 1/8 gradient steps — smooth waterfall edge |
refinery | ⠀ ⡀ ⡄ ⡆ ⡇ ⣇ ⣧ ⣷ ⣿ | Braille block stages — BRAIN memory promotion pipeline |
Inputs outside [0, 1] are clamped. width ≤ 0 returns ''.
import { sparks, sparkDurationMs } from '@cleocode/animations';
sparkDurationMs('cascade'); // → ~980ms (frames * interval)
| Spark | Frames | Duration | Played on |
|---|---|---|---|
awaken | 13 × 90ms | ~1.17s | cleo init · first dream · sentient wake |
sweep | 7 × 80ms | ~560ms | BRAIN integrity sweep complete |
cascade | 14 × 70ms | ~980ms | Release shipped · task complete |
weave | 18 × 70ms | ~1.26s | Playbook stage transition · CANT directive accepted |
A self-contained vitrine page ships at scripts/demo.html. Open it in any
browser to preview every spinner, canon alias, progress style, and spark
animating live, with API reference tables and code samples.
# From an npm install
open node_modules/@cleocode/animations/scripts/demo.html # macOS
xdg-open node_modules/@cleocode/animations/scripts/demo.html # Linux
# From the cleo monorepo checkout
open packages/animations/scripts/demo.html # macOS
xdg-open packages/animations/scripts/demo.html # Linux
The page is fully self-contained (no build step, no fetch, no node_modules
runtime requirement) so it can be emailed, dropped into a slide deck, or
hosted as a static asset for design reviews.
npx cleocode-animations # cycle through generic + canon spinners
npx cleocode-animations looming # preview one spinner (generic OR canon)
npx cleocode-animations spark cascade # play one spark and exit
npx cleocode-animations progress # loop through all 3 progress styles
npx cleocode-animations --list # full listing — spinners + sparks + progress
npx cleocode-animations --list-canon # canon aliases only
npx cleocode-animations --list-sparks # sparks only
npx cleocode-animations --list-progress # progress styles only
| Export | Type |
|---|---|
spinners | Record<BrailleSpinnerName, Spinner> |
canonSpinners | Record<CanonSpinnerName, Spinner> |
CANON_TO_GENERIC | Record<CanonSpinnerName, BrailleSpinnerName> |
resolveSpinner(name) | (string) => Spinner | undefined |
gridToBraille(grid) | (boolean[][]) => string |
makeGrid(rows, cols) | (number, number) => boolean[][] |
Spinner | { frames: readonly string[]; interval: number } |
BrailleSpinnerName · CanonSpinnerName | TS string-literal unions |
\r owner)| Export | Type |
|---|---|
createSpinnerHandle(ctx, name, label, options?) | (AnimateContext, name, string, SpinnerHandleOptions?) => SpinnerHandle |
SpinnerHandle | { start(); stop(finalLine?); update(label); enabled: boolean } |
SpinnerHandleOptions | { delayMs?: number } — defaults to 150 |
| Export | Type |
|---|---|
createAnimateContext(input) | (AnimateContextInput) => AnimateContext |
SILENT_CONTEXT | Frozen AnimateContext — always disabled |
AnimateContext | { enabled, reason, inputs } |
AnimateContextInput | { flagResolution, isTTY?, noColor? } |
FlagResolutionLike | { format: 'json' | 'human'; quiet: boolean } |
| Export | Type |
|---|---|
progressBars | Record<ProgressBarStyle, ProgressBarRenderer> |
renderProgressBar(style, ratio, width) | (style, number, number) => string |
ProgressBarStyle | 'tapestry' | 'cascade' | 'refinery' |
sparks | Record<SparkName, Spark> |
sparkDurationMs(name) | (SparkName) => number |
SparkName | 'awaken' | 'sweep' | 'cascade' | 'weave' |
Every animation here is built from two primitives — compose your own:
import { gridToBraille, makeGrid } from '@cleocode/animations';
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
braille dots. gridToBraille(grid) packs them into a braille string (2 dot
columns per character, U+2800 base).
MIT — dual copyright:
unicode-animations project)@cleocode/animations fork)See LICENSE.
FAQs
CLEO terminal animations — braille spinners, progress bars, and sparks for the cleo CLI and CleoOS. Forked from gunnargray-dev/unicode-animations (MIT).
The npm package @cleocode/animations receives a total of 518 weekly downloads. As such, @cleocode/animations popularity was classified as not popular.
We found that @cleocode/animations demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Product
Socket can now send alerts and supply chain attack notifications to Microsoft Teams, with filters that route the right updates to each channel.

Security News
pnpm 12 rewrites the package manager in Rust, cutting install times by up to 90% while preserving pnpm 11 workflows and lockfiles.

Security News
Socket CTO Ahmad Nassri joins AppSec leaders at Black Hat to discuss active malware, package manager risks, and software supply chain defense.