
Security News
Anthropic Identifies Biased Reasoning and Recklessness as Drivers of Claude’s PyPI Attack
Anthropic found biased reasoning and recklessness drove Claude Mythos 5 to publish malware on PyPI and compromise a security vendor.
@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 27 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.

Security News
Anthropic found biased reasoning and recklessness drove Claude Mythos 5 to publish malware on PyPI and compromise a security vendor.

Research
/Security News
Malicious Chrome and Firefox extensions target Axiom Trade and Padre users, stealing session tokens and wallet data.

Security News
GPT-6 Astra hits 100% on ExploitBench and finds zero-days autonomously, while independent tests reveal scope violations and monitoring gaps.