@cleocode/animations 2026.5.29 → 2026.5.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +77 -0
- package/README.md +290 -0
- package/dist/src/animate-context.d.ts +115 -0
- package/dist/src/animate-context.d.ts.map +1 -0
- package/dist/src/animate-context.js +85 -0
- package/dist/src/animate-context.js.map +1 -0
- package/dist/src/braille.d.ts +32 -0
- package/dist/src/braille.d.ts.map +1 -1
- package/dist/src/braille.js +52 -0
- package/dist/src/braille.js.map +1 -1
- package/dist/src/index.d.ts +18 -6
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +23 -6
- package/dist/src/index.js.map +1 -1
- package/dist/src/progress.d.ts +50 -0
- package/dist/src/progress.d.ts.map +1 -0
- package/dist/src/progress.js +121 -0
- package/dist/src/progress.js.map +1 -0
- package/dist/src/spark.d.ts +47 -0
- package/dist/src/spark.d.ts.map +1 -0
- package/dist/src/spark.js +115 -0
- package/dist/src/spark.js.map +1 -0
- package/dist/src/spinner-handle.d.ts +97 -0
- package/dist/src/spinner-handle.d.ts.map +1 -0
- package/dist/src/spinner-handle.js +177 -0
- package/dist/src/spinner-handle.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +20 -2
- package/scripts/demo.cjs +208 -51
- package/scripts/demo.html +807 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@cleocode/animations` are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
|
+
Versions follow the **monorepo-wide CalVer** (`YYYY.M.PATCH`) — the version
|
|
7
|
+
shipped on npm is set by the git tag at release time via
|
|
8
|
+
`.github/workflows/release.yml`. **Do not bump `package.json` by hand.**
|
|
9
|
+
|
|
10
|
+
## [2026.5.29] — initial release
|
|
11
|
+
|
|
12
|
+
Initial published version. The 2026.5.29 line on npm has three patches
|
|
13
|
+
because trusted-publisher setup required claiming the package name manually
|
|
14
|
+
before the OIDC pipeline could take over; subsequent `2026.5.30` and
|
|
15
|
+
`2026.5.31` patches were also hand-published while iterating on the API
|
|
16
|
+
surface. From the next monorepo release tag onward, the central pipeline
|
|
17
|
+
drives every version bump.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
- Initial port of [`gunnargray-dev/unicode-animations`](https://github.com/gunnargray-dev/unicode-animations) (MIT)
|
|
21
|
+
into `packages/animations/` as a workspace package.
|
|
22
|
+
- 18 braille spinner animations: 3 hand-curated single-char classics
|
|
23
|
+
(`braille`, `braillewave`, `dna`) + 15 procedurally generated grid
|
|
24
|
+
animations (`scan`, `rain`, `pulse`, `helix`, `cascade`, `orbit`, …).
|
|
25
|
+
- Grid utilities `gridToBraille(grid)` and `makeGrid(rows, cols)` for
|
|
26
|
+
composing custom braille animations.
|
|
27
|
+
- **Canon spinner aliases** — 9 workshop-vocabulary names pointing at the
|
|
28
|
+
same `Spinner` objects as the generic registry (aliases, not copies):
|
|
29
|
+
`looming → helix`, `weaving → braillewave`, `heartbeat → breathe`,
|
|
30
|
+
`awakening → pulse`, `sweeping → scan`, `watching → orbit`,
|
|
31
|
+
`cascade → cascade`, `tapestry → waverows`, `refinery → columns`.
|
|
32
|
+
Exposed as `canonSpinners`, `CANON_TO_GENERIC`, `resolveSpinner(name)`.
|
|
33
|
+
- **`AnimateContext`** — pure-data render gate consumed by every primitive.
|
|
34
|
+
Disables animations when `format !== 'human'`, `quiet`, `!isTTY`, or
|
|
35
|
+
`NO_COLOR`. Carries `reason` for diagnostics. `SILENT_CONTEXT` exported
|
|
36
|
+
as a frozen always-disabled context.
|
|
37
|
+
- **Progress bar primitives** — three canon styles via
|
|
38
|
+
`renderProgressBar(style, ratio, width)`:
|
|
39
|
+
- `tapestry` — coarse Unicode blocks (`░▒▓█`)
|
|
40
|
+
- `cascade` — 1/8 gradient steps (`▏▎▍▌▋▊▉█`)
|
|
41
|
+
- `refinery` — braille block stages (`⠀⡀⡄⡆⡇⣇⣧⣷⣿`)
|
|
42
|
+
- **Spark primitives** — 4 one-shot canon flares: `awaken`, `sweep`,
|
|
43
|
+
`cascade`, `weave`. Helper `sparkDurationMs(name)`.
|
|
44
|
+
- **`createSpinnerHandle(ctx, name, label, options?)`** — the canonical
|
|
45
|
+
owner of `\r` writes for this package. Wraps a `Spinner` with a managed
|
|
46
|
+
timer, cursor hide/show, exit-handler restoration, idempotent `start()` /
|
|
47
|
+
`stop()`, and `update(label)`. Returns a frozen no-op handle when
|
|
48
|
+
`AnimateContext.enabled` is `false`. Process-level `exit` / `SIGINT` /
|
|
49
|
+
`SIGTERM` listeners are installed exactly **once per process** via a
|
|
50
|
+
shared module-scoped registry, so N concurrent handles add 1 listener
|
|
51
|
+
per signal (not N) — well clear of Node's default 10-listener warning
|
|
52
|
+
threshold even with heavy orchestrator fan-out.
|
|
53
|
+
- **`scripts/demo.html`** — Cleo-themed self-contained vitrine page (open
|
|
54
|
+
in any browser, no build step). Previews every primitive animating live,
|
|
55
|
+
with API tables, code samples, and a light/dark theme toggle.
|
|
56
|
+
- **`scripts/demo.cjs`** (`cleocode-animations` bin) — terminal preview CLI
|
|
57
|
+
covering generic + canon spinners, sparks, and progress bars. Subcommands:
|
|
58
|
+
`--list` / `--list-canon` / `--list-sparks` / `--list-progress` /
|
|
59
|
+
`spark <name>` / `progress`.
|
|
60
|
+
- **`exports` map subpaths** for every public module —
|
|
61
|
+
`./animate-context`, `./progress`, `./spark`, `./spinner-handle`,
|
|
62
|
+
`./braille`, `./package.json` — for tree-shaking and discoverability.
|
|
63
|
+
- **`README.md`** — install, quick start, AnimateContext, registries,
|
|
64
|
+
canon mapping, full API surface, custom-spinner recipe, attribution.
|
|
65
|
+
- 153 tests covering frame-data snapshots, canon contract, AnimateContext
|
|
66
|
+
precedence, progress-bar boundaries, spark decay, SpinnerHandle
|
|
67
|
+
idempotency / cursor management / context-disabled no-op behavior, and
|
|
68
|
+
the process-level listener-count invariant (≤ 1 listener per signal,
|
|
69
|
+
regardless of how many handles run concurrently).
|
|
70
|
+
- LICENSE: MIT, dual-copyright (Gunnar Gray + CLEO Code).
|
|
71
|
+
- ESM-only, built via `tsc -p tsconfig.build.json` (matches monorepo
|
|
72
|
+
conventions; dropped upstream's `tsup` + CJS/IIFE bundling).
|
|
73
|
+
- Wired into `.github/workflows/release.yml` (version-sync iterator and
|
|
74
|
+
publish chain, positioned between `git-shim` and `core`) and
|
|
75
|
+
`scripts/execute-payload.mjs` (`PUBLISHED_PACKAGES` list).
|
|
76
|
+
|
|
77
|
+
[2026.5.29]: https://www.npmjs.com/package/@cleocode/animations/v/2026.5.29
|
package/README.md
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
# @cleocode/animations
|
|
2
|
+
|
|
3
|
+
**Unicode terminal animations for the cleo CLI and CleoOS** — woven on the LOOM, gated by LAFS.
|
|
4
|
+
|
|
5
|
+
Provides four primitive surfaces, each gated by a single `AnimateContext` so the
|
|
6
|
+
LAFS protocol invariant ("JSON output is the default; human rendering requires
|
|
7
|
+
explicit opt-in") holds uniformly:
|
|
8
|
+
|
|
9
|
+
- **18 generic braille spinners** — frame-cycled loaders ported from
|
|
10
|
+
[`unicode-animations`](https://github.com/gunnargray-dev/unicode-animations) (MIT, Gunnar Gray)
|
|
11
|
+
- **9 canon spinner aliases** — workshop vocabulary (`looming`, `weaving`, `heartbeat`, …) on the same frame data
|
|
12
|
+
- **3 progress bar styles** — `tapestry`, `cascade`, `refinery` (canon-themed segmented gauges)
|
|
13
|
+
- **4 sparks** — one-shot accents (`awaken`, `sweep`, `cascade`, `weave`)
|
|
14
|
+
|
|
15
|
+
[](https://www.npmjs.com/package/@cleocode/animations)
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pnpm add @cleocode/animations
|
|
21
|
+
# or
|
|
22
|
+
npm install @cleocode/animations
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
ESM-only. Requires Node ≥ 22.
|
|
26
|
+
|
|
27
|
+
## Quick start
|
|
28
|
+
|
|
29
|
+
### Spinner during async work — `createSpinnerHandle`
|
|
30
|
+
|
|
31
|
+
`createSpinnerHandle` is the canonical owner of `\r` writes for this package.
|
|
32
|
+
It manages the timer, hides/restores the cursor, installs an exit handler so
|
|
33
|
+
`Ctrl-C` doesn't leave a hidden cursor, and routes everything through the
|
|
34
|
+
LAFS render gate. **Calling `process.stdout.write` of a string starting with
|
|
35
|
+
`\r` outside this package is a contract violation** — always go through the
|
|
36
|
+
handle.
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import { resolveOutputFormat } from '@cleocode/lafs';
|
|
40
|
+
import { createAnimateContext, createSpinnerHandle } from '@cleocode/animations';
|
|
41
|
+
|
|
42
|
+
const ctx = createAnimateContext({
|
|
43
|
+
flagResolution: resolveOutputFormat({ humanFlag: true }),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const spinner = createSpinnerHandle(ctx, 'looming', 'Weaving tasks…');
|
|
47
|
+
spinner.start();
|
|
48
|
+
try {
|
|
49
|
+
await doWork();
|
|
50
|
+
spinner.stop('✔ Tapestry complete.');
|
|
51
|
+
} catch (err) {
|
|
52
|
+
spinner.stop();
|
|
53
|
+
throw err;
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Under `--json` / `--quiet` / non-TTY / `NO_COLOR` the handle is a frozen no-op
|
|
58
|
+
and emits zero output — call sites stay branch-free.
|
|
59
|
+
|
|
60
|
+
### Progress bar with a known ratio
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import { renderProgressBar } from '@cleocode/animations';
|
|
64
|
+
|
|
65
|
+
function tick(done: number, total: number) {
|
|
66
|
+
const ratio = done / total;
|
|
67
|
+
const bar = renderProgressBar('refinery', ratio, 36);
|
|
68
|
+
process.stdout.write(`\r\x1B[2K ${bar} ${done}/${total}`);
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### One-shot spark on success
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import { sparks } from '@cleocode/animations';
|
|
76
|
+
|
|
77
|
+
async function playSpark(name: 'awaken' | 'sweep' | 'cascade' | 'weave') {
|
|
78
|
+
const { frames, interval } = sparks[name];
|
|
79
|
+
for (const f of frames) {
|
|
80
|
+
process.stdout.write(`\r\x1B[2K ${f}`);
|
|
81
|
+
await new Promise(r => setTimeout(r, interval));
|
|
82
|
+
}
|
|
83
|
+
process.stdout.write('\n');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
await shipRelease();
|
|
87
|
+
await playSpark('cascade');
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## LAFS-aware rendering — `AnimateContext`
|
|
91
|
+
|
|
92
|
+
Every primitive routes through an `AnimateContext` so the package obeys the
|
|
93
|
+
LAFS protocol uniformly. The context is **pure data** — no I/O, no timers —
|
|
94
|
+
derived from the LAFS `FlagResolution` plus environment signals.
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
import { resolveOutputFormat } from '@cleocode/lafs';
|
|
98
|
+
import { createAnimateContext, createSpinnerHandle } from '@cleocode/animations';
|
|
99
|
+
|
|
100
|
+
const flags = resolveOutputFormat({ humanFlag: true });
|
|
101
|
+
const ctx = createAnimateContext({ flagResolution: flags });
|
|
102
|
+
|
|
103
|
+
// Hand `ctx` to any primitive — they all become no-ops when `ctx.enabled === false`.
|
|
104
|
+
const spinner = createSpinnerHandle(ctx, 'looming', 'Loading…');
|
|
105
|
+
|
|
106
|
+
if (!ctx.enabled) {
|
|
107
|
+
// ctx.reason ∈ 'format-json' | 'quiet' | 'no-tty' | 'no-color' | 'enabled'
|
|
108
|
+
console.log(`silent: ${ctx.reason}`);
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
| Signal | Source | Effect | `reason` |
|
|
113
|
+
|---|---|---|---|
|
|
114
|
+
| `format !== 'human'` | LAFS flags | Disable (machine output) | `format-json` |
|
|
115
|
+
| `quiet === true` | LAFS flags | Disable (script-friendly) | `quiet` |
|
|
116
|
+
| `!isTTY` | `process.stdout.isTTY` | Disable (piped/redirected) | `no-tty` |
|
|
117
|
+
| `NO_COLOR` set | `process.env.NO_COLOR` | Disable ([no-color.org](https://no-color.org)) | `no-color` |
|
|
118
|
+
|
|
119
|
+
`SILENT_CONTEXT` is exported as a frozen always-disabled context for tests and
|
|
120
|
+
libraries that want to opt out without constructing a full LAFS resolution.
|
|
121
|
+
|
|
122
|
+
## Spinner registry
|
|
123
|
+
|
|
124
|
+
### Generic — 18 braille loaders
|
|
125
|
+
|
|
126
|
+
| Name | Frames | Interval | Name | Frames | Interval |
|
|
127
|
+
|---|---|---|---|---|---|
|
|
128
|
+
| `braille` | 10 | 80ms | `cascade` | 14 | 60ms |
|
|
129
|
+
| `braillewave` | 8 | 100ms | `columns` | 26 | 60ms |
|
|
130
|
+
| `dna` | 12 | 80ms | `orbit` | 8 | 100ms |
|
|
131
|
+
| `scan` | 10 | 70ms | `breathe` | 17 | 100ms |
|
|
132
|
+
| `rain` | 12 | 100ms | `waverows` | 16 | 90ms |
|
|
133
|
+
| `scanline` | 6 | 120ms | `checkerboard` | 4 | 250ms |
|
|
134
|
+
| `pulse` | 5 | 180ms | `helix` | 16 | 80ms |
|
|
135
|
+
| `snake` | 16 | 80ms | `fillsweep` | 11 | 100ms |
|
|
136
|
+
| `sparkle` | 6 | 150ms | `diagswipe` | 16 | 60ms |
|
|
137
|
+
|
|
138
|
+
### Canon — 9 workshop aliases
|
|
139
|
+
|
|
140
|
+
| Canon name | → Generic | Cleo lore role |
|
|
141
|
+
|---|---|---|
|
|
142
|
+
| `looming` | `helix` | Twin strands weaving — task on the LOOM |
|
|
143
|
+
| `weaving` | `braillewave` | Pattern threading across columns |
|
|
144
|
+
| `heartbeat` | `breathe` | Organic in-out pulse — Hearth presence |
|
|
145
|
+
| `awakening` | `pulse` | Radial bloom — first dream / `cleo init` |
|
|
146
|
+
| `sweeping` | `scan` | Left→right beam — BRAIN integrity Sweep |
|
|
147
|
+
| `watching` | `orbit` | Circular sentinel — sentient daemon tick |
|
|
148
|
+
| `cascade` | `cascade` | Diagonal fall — command-success accent |
|
|
149
|
+
| `tapestry` | `waverows` | Multi-row sinusoidal — wave of tasks shipping |
|
|
150
|
+
| `refinery` | `columns` | Filling stages — memory promotion pipeline |
|
|
151
|
+
|
|
152
|
+
Canon entries are **aliases**, not copies — they reference the same `Spinner`
|
|
153
|
+
objects as the generic registry. Renaming a generic spinner automatically
|
|
154
|
+
updates the canon view. The mapping is exposed as `CANON_TO_GENERIC` and
|
|
155
|
+
`resolveSpinner(name)` accepts either form.
|
|
156
|
+
|
|
157
|
+
## Progress bars
|
|
158
|
+
|
|
159
|
+
`renderProgressBar(style, ratio, width)` returns a fixed-width string. Three
|
|
160
|
+
canon styles:
|
|
161
|
+
|
|
162
|
+
| Style | Characters | Feel |
|
|
163
|
+
|---|---|---|
|
|
164
|
+
| `tapestry` | `░ ▒ ▓ █` | Coarse blocks — woven cloth filling cell-by-cell |
|
|
165
|
+
| `cascade` | `▏ ▎ ▍ ▌ ▋ ▊ ▉ █` | 1/8 gradient steps — smooth waterfall edge |
|
|
166
|
+
| `refinery` | `⠀ ⡀ ⡄ ⡆ ⡇ ⣇ ⣧ ⣷ ⣿` | Braille block stages — BRAIN memory promotion pipeline |
|
|
167
|
+
|
|
168
|
+
Inputs outside `[0, 1]` are clamped. `width` ≤ 0 returns `''`.
|
|
169
|
+
|
|
170
|
+
## Sparks — one-shot accents
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
import { sparks, sparkDurationMs } from '@cleocode/animations';
|
|
174
|
+
|
|
175
|
+
sparkDurationMs('cascade'); // → ~980ms (frames * interval)
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
| Spark | Frames | Duration | Played on |
|
|
179
|
+
|---|---|---|---|
|
|
180
|
+
| `awaken` | 13 × 90ms | ~1.17s | `cleo init` · first dream · sentient wake |
|
|
181
|
+
| `sweep` | 7 × 80ms | ~560ms | BRAIN integrity sweep complete |
|
|
182
|
+
| `cascade` | 14 × 70ms | ~980ms | Release shipped · task complete |
|
|
183
|
+
| `weave` | 18 × 70ms | ~1.26s | Playbook stage transition · CANT directive accepted |
|
|
184
|
+
|
|
185
|
+
## Browser demo
|
|
186
|
+
|
|
187
|
+
A self-contained vitrine page ships at `scripts/demo.html`. Open it in any
|
|
188
|
+
browser to preview every spinner, canon alias, progress style, and spark
|
|
189
|
+
animating live, with API reference tables and code samples.
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
# From an npm install
|
|
193
|
+
open node_modules/@cleocode/animations/scripts/demo.html # macOS
|
|
194
|
+
xdg-open node_modules/@cleocode/animations/scripts/demo.html # Linux
|
|
195
|
+
|
|
196
|
+
# From the cleo monorepo checkout
|
|
197
|
+
open packages/animations/scripts/demo.html # macOS
|
|
198
|
+
xdg-open packages/animations/scripts/demo.html # Linux
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The page is fully self-contained (no build step, no fetch, no `node_modules`
|
|
202
|
+
runtime requirement) so it can be emailed, dropped into a slide deck, or
|
|
203
|
+
hosted as a static asset for design reviews.
|
|
204
|
+
|
|
205
|
+
## Terminal demo
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
npx cleocode-animations # cycle through generic + canon spinners
|
|
209
|
+
npx cleocode-animations looming # preview one spinner (generic OR canon)
|
|
210
|
+
npx cleocode-animations spark cascade # play one spark and exit
|
|
211
|
+
npx cleocode-animations progress # loop through all 3 progress styles
|
|
212
|
+
|
|
213
|
+
npx cleocode-animations --list # full listing — spinners + sparks + progress
|
|
214
|
+
npx cleocode-animations --list-canon # canon aliases only
|
|
215
|
+
npx cleocode-animations --list-sparks # sparks only
|
|
216
|
+
npx cleocode-animations --list-progress # progress styles only
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## API surface
|
|
220
|
+
|
|
221
|
+
### Spinners
|
|
222
|
+
|
|
223
|
+
| Export | Type |
|
|
224
|
+
|---|---|
|
|
225
|
+
| `spinners` | `Record<BrailleSpinnerName, Spinner>` |
|
|
226
|
+
| `canonSpinners` | `Record<CanonSpinnerName, Spinner>` |
|
|
227
|
+
| `CANON_TO_GENERIC` | `Record<CanonSpinnerName, BrailleSpinnerName>` |
|
|
228
|
+
| `resolveSpinner(name)` | `(string) => Spinner \| undefined` |
|
|
229
|
+
| `gridToBraille(grid)` | `(boolean[][]) => string` |
|
|
230
|
+
| `makeGrid(rows, cols)` | `(number, number) => boolean[][]` |
|
|
231
|
+
| `Spinner` | `{ frames: readonly string[]; interval: number }` |
|
|
232
|
+
| `BrailleSpinnerName` · `CanonSpinnerName` | TS string-literal unions |
|
|
233
|
+
|
|
234
|
+
### SpinnerHandle (canonical `\r` owner)
|
|
235
|
+
|
|
236
|
+
| Export | Type |
|
|
237
|
+
|---|---|
|
|
238
|
+
| `createSpinnerHandle(ctx, name, label, options?)` | `(AnimateContext, name, string, SpinnerHandleOptions?) => SpinnerHandle` |
|
|
239
|
+
| `SpinnerHandle` | `{ start(); stop(finalLine?); update(label); enabled: boolean }` |
|
|
240
|
+
| `SpinnerHandleOptions` | `{ delayMs?: number }` — defaults to `150` |
|
|
241
|
+
|
|
242
|
+
### AnimateContext
|
|
243
|
+
|
|
244
|
+
| Export | Type |
|
|
245
|
+
|---|---|
|
|
246
|
+
| `createAnimateContext(input)` | `(AnimateContextInput) => AnimateContext` |
|
|
247
|
+
| `SILENT_CONTEXT` | Frozen `AnimateContext` — always disabled |
|
|
248
|
+
| `AnimateContext` | `{ enabled, reason, inputs }` |
|
|
249
|
+
| `AnimateContextInput` | `{ flagResolution, isTTY?, noColor? }` |
|
|
250
|
+
| `FlagResolutionLike` | `{ format: 'json' \| 'human'; quiet: boolean }` |
|
|
251
|
+
|
|
252
|
+
### Progress + Sparks
|
|
253
|
+
|
|
254
|
+
| Export | Type |
|
|
255
|
+
|---|---|
|
|
256
|
+
| `progressBars` | `Record<ProgressBarStyle, ProgressBarRenderer>` |
|
|
257
|
+
| `renderProgressBar(style, ratio, width)` | `(style, number, number) => string` |
|
|
258
|
+
| `ProgressBarStyle` | `'tapestry' \| 'cascade' \| 'refinery'` |
|
|
259
|
+
| `sparks` | `Record<SparkName, Spark>` |
|
|
260
|
+
| `sparkDurationMs(name)` | `(SparkName) => number` |
|
|
261
|
+
| `SparkName` | `'awaken' \| 'sweep' \| 'cascade' \| 'weave'` |
|
|
262
|
+
|
|
263
|
+
## Custom spinners
|
|
264
|
+
|
|
265
|
+
Every animation here is built from two primitives — compose your own:
|
|
266
|
+
|
|
267
|
+
```ts
|
|
268
|
+
import { gridToBraille, makeGrid } from '@cleocode/animations';
|
|
269
|
+
|
|
270
|
+
const grid = makeGrid(4, 4);
|
|
271
|
+
grid[0][0] = true;
|
|
272
|
+
grid[1][1] = true;
|
|
273
|
+
grid[2][2] = true;
|
|
274
|
+
grid[3][3] = true;
|
|
275
|
+
|
|
276
|
+
console.log(gridToBraille(grid)); // diagonal braille pattern
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
`makeGrid(rows, cols)` returns a `boolean[][]`. Set cells to `true` to raise
|
|
280
|
+
braille dots. `gridToBraille(grid)` packs them into a braille string (2 dot
|
|
281
|
+
columns per character, U+2800 base).
|
|
282
|
+
|
|
283
|
+
## License
|
|
284
|
+
|
|
285
|
+
MIT — dual copyright:
|
|
286
|
+
|
|
287
|
+
- © 2024 Gunnar Gray (original `unicode-animations` project)
|
|
288
|
+
- © 2026 CLEO Code (`@cleocode/animations` fork)
|
|
289
|
+
|
|
290
|
+
See `LICENSE`.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AnimateContext — render-gate for terminal animations.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* Every animation primitive in this package (spinners, progress bars, sparks)
|
|
6
|
+
* routes its output through an {@link AnimateContext}. When the context is
|
|
7
|
+
* "silent" — JSON mode, --quiet, non-TTY pipes, or NO_COLOR — the primitive
|
|
8
|
+
* returns no-op handles so callers do not have to branch on output mode.
|
|
9
|
+
*
|
|
10
|
+
* This mirrors the LAFS protocol invariant from `@cleocode/lafs`: JSON output
|
|
11
|
+
* is the default, human-readable rendering requires explicit opt-in. By
|
|
12
|
+
* keeping the gate logic in one place we guarantee that every animation
|
|
13
|
+
* surface obeys the same rules:
|
|
14
|
+
*
|
|
15
|
+
* - `format === 'human'` — animations enabled
|
|
16
|
+
* - `format === 'json'` — animations disabled (machine output)
|
|
17
|
+
* - `quiet === true` — animations disabled (script-friendly)
|
|
18
|
+
* - `isTTY === false` — animations disabled (piped/redirected)
|
|
19
|
+
* - `noColor === true` — animations disabled (NO_COLOR env)
|
|
20
|
+
*
|
|
21
|
+
* The context is intentionally pure data — no I/O, no timers — so it can be
|
|
22
|
+
* constructed once at command entry and threaded through long-running ops.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Minimal subset of the LAFS `FlagResolution` shape that AnimateContext needs.
|
|
26
|
+
*
|
|
27
|
+
* @remarks
|
|
28
|
+
* Declared structurally rather than imported from `@cleocode/lafs` to keep
|
|
29
|
+
* `@cleocode/animations` zero-dep. Anything that produces a `{ format, quiet }`
|
|
30
|
+
* pair — including `resolveOutputFormat()` from LAFS — satisfies this contract.
|
|
31
|
+
*/
|
|
32
|
+
export interface FlagResolutionLike {
|
|
33
|
+
/** Resolved output format. */
|
|
34
|
+
readonly format: 'json' | 'human';
|
|
35
|
+
/** When true, suppress non-essential output. */
|
|
36
|
+
readonly quiet: boolean;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Inputs to {@link createAnimateContext}.
|
|
40
|
+
*
|
|
41
|
+
* @remarks
|
|
42
|
+
* `flagResolution` is the load-bearing input — pass the value returned by
|
|
43
|
+
* `resolveOutputFormat()` from `@cleocode/lafs`. The other fields default to
|
|
44
|
+
* inspecting the current Node.js process environment when omitted, which is
|
|
45
|
+
* the right call for nearly every CLI use case.
|
|
46
|
+
*/
|
|
47
|
+
export interface AnimateContextInput {
|
|
48
|
+
/** Resolved LAFS flags governing output format and quietness. */
|
|
49
|
+
readonly flagResolution: FlagResolutionLike;
|
|
50
|
+
/**
|
|
51
|
+
* Whether stdout is attached to a TTY. Defaults to `process.stdout.isTTY`.
|
|
52
|
+
* Pass `false` explicitly when rendering to a buffer or redirected stream.
|
|
53
|
+
*/
|
|
54
|
+
readonly isTTY?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Whether the `NO_COLOR` standard is in effect (https://no-color.org).
|
|
57
|
+
* Defaults to `process.env.NO_COLOR != null`. Pass `false` to override.
|
|
58
|
+
*/
|
|
59
|
+
readonly noColor?: boolean;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Resolved render-gate context — consult `enabled` before rendering anything.
|
|
63
|
+
*
|
|
64
|
+
* @remarks
|
|
65
|
+
* `reason` carries diagnostic provenance (which gate disabled rendering) so
|
|
66
|
+
* verbose-mode callers can surface why animations are silent without
|
|
67
|
+
* re-implementing the gate logic.
|
|
68
|
+
*/
|
|
69
|
+
export interface AnimateContext {
|
|
70
|
+
/** Whether animation rendering is permitted. */
|
|
71
|
+
readonly enabled: boolean;
|
|
72
|
+
/** When `enabled === false`, the rule that disabled rendering. */
|
|
73
|
+
readonly reason: 'enabled' | 'format-json' | 'quiet' | 'no-tty' | 'no-color';
|
|
74
|
+
/** Echo of the inputs used to derive this context — useful for diagnostics. */
|
|
75
|
+
readonly inputs: {
|
|
76
|
+
readonly format: 'json' | 'human';
|
|
77
|
+
readonly quiet: boolean;
|
|
78
|
+
readonly isTTY: boolean;
|
|
79
|
+
readonly noColor: boolean;
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Construct an {@link AnimateContext} from LAFS flags + environment signals.
|
|
84
|
+
*
|
|
85
|
+
* @param input - LAFS flag resolution plus optional TTY / NO_COLOR overrides
|
|
86
|
+
* @returns The resolved context with `enabled` flag and diagnostic `reason`
|
|
87
|
+
*
|
|
88
|
+
* @remarks
|
|
89
|
+
* Precedence (first match disables): `format !== 'human'` →
|
|
90
|
+
* `quiet === true` → `isTTY === false` → `noColor === true`. All four checks
|
|
91
|
+
* fire independently; rendering is enabled only when every gate passes.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```ts
|
|
95
|
+
* import { resolveOutputFormat } from '@cleocode/lafs';
|
|
96
|
+
* import { createAnimateContext, createSpinnerHandle } from '@cleocode/animations';
|
|
97
|
+
*
|
|
98
|
+
* const flagResolution = resolveOutputFormat({ humanFlag: true });
|
|
99
|
+
* const context = createAnimateContext({ flagResolution });
|
|
100
|
+
* const spinner = createSpinnerHandle(context, 'looming', 'Weaving tasks…');
|
|
101
|
+
* spinner.start();
|
|
102
|
+
* await doWork();
|
|
103
|
+
* spinner.stop('Done.');
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
export declare function createAnimateContext(input: AnimateContextInput): AnimateContext;
|
|
107
|
+
/**
|
|
108
|
+
* A silent context — guarantees every primitive returns a no-op handle.
|
|
109
|
+
*
|
|
110
|
+
* @remarks
|
|
111
|
+
* Useful for tests and for libraries that want to opt out of animations
|
|
112
|
+
* without constructing a full LAFS flag resolution.
|
|
113
|
+
*/
|
|
114
|
+
export declare const SILENT_CONTEXT: AnimateContext;
|
|
115
|
+
//# sourceMappingURL=animate-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"animate-context.d.ts","sourceRoot":"","sources":["../../src/animate-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC,8BAA8B;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IAClC,gDAAgD;IAChD,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,mBAAmB;IAClC,iEAAiE;IACjE,QAAQ,CAAC,cAAc,EAAE,kBAAkB,CAAC;IAC5C;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC7B,gDAAgD;IAChD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,CAAC;IAC7E,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,EAAE;QACf,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QAClC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;QACxB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;QACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;KAC3B,CAAC;CACH;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,mBAAmB,GAAG,cAAc,CAsB/E;AAED;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,EAAE,cAS3B,CAAC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AnimateContext — render-gate for terminal animations.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* Every animation primitive in this package (spinners, progress bars, sparks)
|
|
6
|
+
* routes its output through an {@link AnimateContext}. When the context is
|
|
7
|
+
* "silent" — JSON mode, --quiet, non-TTY pipes, or NO_COLOR — the primitive
|
|
8
|
+
* returns no-op handles so callers do not have to branch on output mode.
|
|
9
|
+
*
|
|
10
|
+
* This mirrors the LAFS protocol invariant from `@cleocode/lafs`: JSON output
|
|
11
|
+
* is the default, human-readable rendering requires explicit opt-in. By
|
|
12
|
+
* keeping the gate logic in one place we guarantee that every animation
|
|
13
|
+
* surface obeys the same rules:
|
|
14
|
+
*
|
|
15
|
+
* - `format === 'human'` — animations enabled
|
|
16
|
+
* - `format === 'json'` — animations disabled (machine output)
|
|
17
|
+
* - `quiet === true` — animations disabled (script-friendly)
|
|
18
|
+
* - `isTTY === false` — animations disabled (piped/redirected)
|
|
19
|
+
* - `noColor === true` — animations disabled (NO_COLOR env)
|
|
20
|
+
*
|
|
21
|
+
* The context is intentionally pure data — no I/O, no timers — so it can be
|
|
22
|
+
* constructed once at command entry and threaded through long-running ops.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Construct an {@link AnimateContext} from LAFS flags + environment signals.
|
|
26
|
+
*
|
|
27
|
+
* @param input - LAFS flag resolution plus optional TTY / NO_COLOR overrides
|
|
28
|
+
* @returns The resolved context with `enabled` flag and diagnostic `reason`
|
|
29
|
+
*
|
|
30
|
+
* @remarks
|
|
31
|
+
* Precedence (first match disables): `format !== 'human'` →
|
|
32
|
+
* `quiet === true` → `isTTY === false` → `noColor === true`. All four checks
|
|
33
|
+
* fire independently; rendering is enabled only when every gate passes.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* import { resolveOutputFormat } from '@cleocode/lafs';
|
|
38
|
+
* import { createAnimateContext, createSpinnerHandle } from '@cleocode/animations';
|
|
39
|
+
*
|
|
40
|
+
* const flagResolution = resolveOutputFormat({ humanFlag: true });
|
|
41
|
+
* const context = createAnimateContext({ flagResolution });
|
|
42
|
+
* const spinner = createSpinnerHandle(context, 'looming', 'Weaving tasks…');
|
|
43
|
+
* spinner.start();
|
|
44
|
+
* await doWork();
|
|
45
|
+
* spinner.stop('Done.');
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export function createAnimateContext(input) {
|
|
49
|
+
const format = input.flagResolution.format;
|
|
50
|
+
const quiet = input.flagResolution.quiet;
|
|
51
|
+
const isTTY = input.isTTY ?? Boolean(process.stdout.isTTY);
|
|
52
|
+
const noColor = input.noColor ?? process.env.NO_COLOR != null;
|
|
53
|
+
const inputs = { format, quiet, isTTY, noColor };
|
|
54
|
+
if (format !== 'human') {
|
|
55
|
+
return { enabled: false, reason: 'format-json', inputs };
|
|
56
|
+
}
|
|
57
|
+
if (quiet) {
|
|
58
|
+
return { enabled: false, reason: 'quiet', inputs };
|
|
59
|
+
}
|
|
60
|
+
if (!isTTY) {
|
|
61
|
+
return { enabled: false, reason: 'no-tty', inputs };
|
|
62
|
+
}
|
|
63
|
+
if (noColor) {
|
|
64
|
+
return { enabled: false, reason: 'no-color', inputs };
|
|
65
|
+
}
|
|
66
|
+
return { enabled: true, reason: 'enabled', inputs };
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* A silent context — guarantees every primitive returns a no-op handle.
|
|
70
|
+
*
|
|
71
|
+
* @remarks
|
|
72
|
+
* Useful for tests and for libraries that want to opt out of animations
|
|
73
|
+
* without constructing a full LAFS flag resolution.
|
|
74
|
+
*/
|
|
75
|
+
export const SILENT_CONTEXT = Object.freeze({
|
|
76
|
+
enabled: false,
|
|
77
|
+
reason: 'format-json',
|
|
78
|
+
inputs: Object.freeze({
|
|
79
|
+
format: 'json',
|
|
80
|
+
quiet: false,
|
|
81
|
+
isTTY: false,
|
|
82
|
+
noColor: false,
|
|
83
|
+
}),
|
|
84
|
+
});
|
|
85
|
+
//# sourceMappingURL=animate-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"animate-context.js","sourceRoot":"","sources":["../../src/animate-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AA+DH;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAA0B;IAC7D,MAAM,MAAM,GAAG,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC;IAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC;IACzC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3D,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,IAAI,CAAC;IAE9D,MAAM,MAAM,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAW,CAAC;IAE1D,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;QACvB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,CAAC;IAC3D,CAAC;IACD,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IACrD,CAAC;IACD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IACtD,CAAC;IACD,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;IACxD,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;AACtD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,cAAc,GAAmB,MAAM,CAAC,MAAM,CAAC;IAC1D,OAAO,EAAE,KAAK;IACd,MAAM,EAAE,aAAa;IACrB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;QACpB,MAAM,EAAE,MAAM;QACd,KAAK,EAAE,KAAK;QACZ,KAAK,EAAE,KAAK;QACZ,OAAO,EAAE,KAAK;KACf,CAAC;CACH,CAAC,CAAC"}
|
package/dist/src/braille.d.ts
CHANGED
|
@@ -25,4 +25,36 @@ export declare function gridToBraille(grid: boolean[][]): string;
|
|
|
25
25
|
export declare function makeGrid(rows: number, cols: number): boolean[][];
|
|
26
26
|
export declare const spinners: Record<BrailleSpinnerName, Spinner>;
|
|
27
27
|
export default spinners;
|
|
28
|
+
/**
|
|
29
|
+
* Canon-themed spinner identifiers drawn from CLEO workshop vocabulary.
|
|
30
|
+
*
|
|
31
|
+
* @remarks
|
|
32
|
+
* Each canon name is an alias pointing at the same {@link Spinner} object
|
|
33
|
+
* registered in {@link spinners} under its generic name.
|
|
34
|
+
*/
|
|
35
|
+
export type CanonSpinnerName = 'looming' | 'weaving' | 'heartbeat' | 'awakening' | 'sweeping' | 'watching' | 'cascade' | 'tapestry' | 'refinery';
|
|
36
|
+
/**
|
|
37
|
+
* Canon-name → generic-name lookup table.
|
|
38
|
+
*
|
|
39
|
+
* @remarks
|
|
40
|
+
* Exposed so consumers can render the underlying generic name in diagnostics
|
|
41
|
+
* (`looming → helix`) without hardcoding the relationship.
|
|
42
|
+
*/
|
|
43
|
+
export declare const CANON_TO_GENERIC: Record<CanonSpinnerName, BrailleSpinnerName>;
|
|
44
|
+
/**
|
|
45
|
+
* Canon-themed spinner registry — aliases on top of {@link spinners}.
|
|
46
|
+
*
|
|
47
|
+
* @remarks
|
|
48
|
+
* Each entry references the same {@link Spinner} object as the generic
|
|
49
|
+
* registry, so frame data is never duplicated. Renaming a generic spinner
|
|
50
|
+
* automatically updates the canon view.
|
|
51
|
+
*/
|
|
52
|
+
export declare const canonSpinners: Record<CanonSpinnerName, Spinner>;
|
|
53
|
+
/**
|
|
54
|
+
* Resolve any spinner name (generic OR canon) to its {@link Spinner}.
|
|
55
|
+
*
|
|
56
|
+
* @param name - Either a {@link BrailleSpinnerName} or a {@link CanonSpinnerName}
|
|
57
|
+
* @returns The matching spinner, or `undefined` if the name is not registered.
|
|
58
|
+
*/
|
|
59
|
+
export declare function resolveSpinner(name: string): Spinner | undefined;
|
|
28
60
|
//# sourceMappingURL=braille.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"braille.d.ts","sourceRoot":"","sources":["../../src/braille.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,MAAM,kBAAkB,GAC1B,SAAS,GACT,aAAa,GACb,KAAK,GACL,MAAM,GACN,MAAM,GACN,UAAU,GACV,OAAO,GACP,OAAO,GACP,SAAS,GACT,SAAS,GACT,SAAS,GACT,OAAO,GACP,SAAS,GACT,UAAU,GACV,cAAc,GACd,OAAO,GACP,WAAW,GACX,WAAW,CAAC;AAqBhB;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,GAAG,MAAM,CAkBvD;AAED,+CAA+C;AAC/C,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE,EAAE,CAGhE;AA8XD,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,kBAAkB,EAAE,OAAO,CA4CxD,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
|
1
|
+
{"version":3,"file":"braille.d.ts","sourceRoot":"","sources":["../../src/braille.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,MAAM,kBAAkB,GAC1B,SAAS,GACT,aAAa,GACb,KAAK,GACL,MAAM,GACN,MAAM,GACN,UAAU,GACV,OAAO,GACP,OAAO,GACP,SAAS,GACT,SAAS,GACT,SAAS,GACT,OAAO,GACP,SAAS,GACT,UAAU,GACV,cAAc,GACd,OAAO,GACP,WAAW,GACX,WAAW,CAAC;AAqBhB;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,GAAG,MAAM,CAkBvD;AAED,+CAA+C;AAC/C,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE,EAAE,CAGhE;AA8XD,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,kBAAkB,EAAE,OAAO,CA4CxD,CAAC;AAEF,eAAe,QAAQ,CAAC;AA2BxB;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,SAAS,GACT,WAAW,GACX,WAAW,GACX,UAAU,GACV,UAAU,GACV,SAAS,GACT,UAAU,GACV,UAAU,CAAC;AAEf;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,EAAE,kBAAkB,CAUzE,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,gBAAgB,EAAE,OAAO,CAU3D,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAQhE"}
|
package/dist/src/braille.js
CHANGED
|
@@ -460,4 +460,56 @@ export const spinners = {
|
|
|
460
460
|
diagswipe: { frames: genDiagonalSwipe(), interval: 60 },
|
|
461
461
|
};
|
|
462
462
|
export default spinners;
|
|
463
|
+
/**
|
|
464
|
+
* Canon-name → generic-name lookup table.
|
|
465
|
+
*
|
|
466
|
+
* @remarks
|
|
467
|
+
* Exposed so consumers can render the underlying generic name in diagnostics
|
|
468
|
+
* (`looming → helix`) without hardcoding the relationship.
|
|
469
|
+
*/
|
|
470
|
+
export const CANON_TO_GENERIC = {
|
|
471
|
+
looming: 'helix',
|
|
472
|
+
weaving: 'braillewave',
|
|
473
|
+
heartbeat: 'breathe',
|
|
474
|
+
awakening: 'pulse',
|
|
475
|
+
sweeping: 'scan',
|
|
476
|
+
watching: 'orbit',
|
|
477
|
+
cascade: 'cascade',
|
|
478
|
+
tapestry: 'waverows',
|
|
479
|
+
refinery: 'columns',
|
|
480
|
+
};
|
|
481
|
+
/**
|
|
482
|
+
* Canon-themed spinner registry — aliases on top of {@link spinners}.
|
|
483
|
+
*
|
|
484
|
+
* @remarks
|
|
485
|
+
* Each entry references the same {@link Spinner} object as the generic
|
|
486
|
+
* registry, so frame data is never duplicated. Renaming a generic spinner
|
|
487
|
+
* automatically updates the canon view.
|
|
488
|
+
*/
|
|
489
|
+
export const canonSpinners = {
|
|
490
|
+
looming: spinners[CANON_TO_GENERIC.looming],
|
|
491
|
+
weaving: spinners[CANON_TO_GENERIC.weaving],
|
|
492
|
+
heartbeat: spinners[CANON_TO_GENERIC.heartbeat],
|
|
493
|
+
awakening: spinners[CANON_TO_GENERIC.awakening],
|
|
494
|
+
sweeping: spinners[CANON_TO_GENERIC.sweeping],
|
|
495
|
+
watching: spinners[CANON_TO_GENERIC.watching],
|
|
496
|
+
cascade: spinners[CANON_TO_GENERIC.cascade],
|
|
497
|
+
tapestry: spinners[CANON_TO_GENERIC.tapestry],
|
|
498
|
+
refinery: spinners[CANON_TO_GENERIC.refinery],
|
|
499
|
+
};
|
|
500
|
+
/**
|
|
501
|
+
* Resolve any spinner name (generic OR canon) to its {@link Spinner}.
|
|
502
|
+
*
|
|
503
|
+
* @param name - Either a {@link BrailleSpinnerName} or a {@link CanonSpinnerName}
|
|
504
|
+
* @returns The matching spinner, or `undefined` if the name is not registered.
|
|
505
|
+
*/
|
|
506
|
+
export function resolveSpinner(name) {
|
|
507
|
+
if (name in spinners) {
|
|
508
|
+
return spinners[name];
|
|
509
|
+
}
|
|
510
|
+
if (name in canonSpinners) {
|
|
511
|
+
return canonSpinners[name];
|
|
512
|
+
}
|
|
513
|
+
return undefined;
|
|
514
|
+
}
|
|
463
515
|
//# sourceMappingURL=braille.js.map
|