braille-radar
v0.1.1
Published
Braille dot-matrix radar (spider) charts for terminals — framework-free TypeScript
Downloads
29
Maintainers
Readme
braille-radar
Braille dot-matrix radar (spider) charts for terminals. Framework-free TypeScript —
works with console.log, any TUI, or your own renderer. Zero runtime dependencies.
Gemma 4 26B-A4B (Q4 QAT) 100K CONTEXT
158 days ago · MoE (25B / 4B) · Text and vision
INTELLIGENCE
26%
⡠⠒⡗⠢⡀
⣀⠔⠉ ⡇ ⠈⠑⢄⡀
ACCURACY ⢀⠤⠊ ⡠⠒⡗⠢⡀ ⠈⠢⢄ SPEED
High (Q4) ⡠⠒⠁ ⣀⠔⠉ ⡇ ⠈⠑⢄⡀ ⠑⠢⡀ ~26-31 tok/s
⠰⡫⠤⣀⣀⣀⣀⣀⡠⠤⠤⠤⢄⡀⡀ ⠈⠢⢄⣀⡠⠬⡳
⢣ ⠈⢣⠑⠒⡴⠭⣀⡀⡇⣈⣑⠦⡔⠒⠉⡏ ⢠⠃
⠈⡆ ⠸⡀ ⠸⡀ ⡰⠉⡀ ⡜ ⡸ ⡎
⠸⡀ ⢇ ⢀⠎⠤⠤⠬⢶⠁ ⢠⠃ ⡜
⢱ ⢸⡆⡠⠃ ⠱⡀⡎ ⢰⠁
⢇ ⢀⠟⠒⠒⠒⠒⠒⠒⠒⠒⠚⢆ ⢀⠇
MEMORY ⠘⣴⣁⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣀⣱⡜ SPECULATION
Tight (17.7 GB) NoneIn a real terminal the profile renders in bright cyan, the grid in dim slate, labels in light text, and details in muted gray.
Why
Terminals are a character grid, which normally caps chart resolution at one pixel per cell. This library packs a 2×4 grid of Unicode Braille dots into every cell, giving charts twice the horizontal and four times the vertical resolution — that's the classic dotted aesthetic you see above, with smooth diagonal lines instead of ASCII staircases.
- Renderer-agnostic frames. Rendering returns rows of
{ text, tone }runs with semantic tones (profile,guide,label,detail). Color them with the bundled ANSI layer, or feed the runs to OpenTUI/Ink<span>s, HTML, or anything else. - Any axis count. The pentagon layout is the headline chart; the generic renderer handles 3+ axes with configurable rings, spokes, center, and radius.
- Animated transitions. Eased (cubic ease-out) interpolation between profiles, including smooth retargeting while a transition is in flight.
- Unassessed axes. A value of
undefinedkeeps the label but draws no edge — no fake zeros.
Install
npm install braille-radarRequires Node 20+. Works with Node, Bun, Deno, and bundlers.
Quick start
import { frameToString, renderPentagonRadar, type PentagonRadarAxes } from "braille-radar"
const axes: PentagonRadarAxes = [
{ value: 0.26, label: "INTELLIGENCE", detail: "26%" },
{ value: 0.32, label: "SPEED", detail: "~26-31 tok/s" },
{ value: 0, label: "SPECULATION", detail: "None" },
{ value: 0.74, label: "MEMORY", detail: "Tight (17.7 GB)" },
{ value: 0.62, label: "ACCURACY", detail: "High (Q4)" },
]
console.log(frameToString(renderPentagonRadar(axes)))Axis values are normalized to [0, 1] (out-of-range values are clamped). Axis
order runs clockwise from the top vertex.
Pentagon charts
renderPentagonRadar(axes, values?, columns?, rows?) renders the labeled
five-axis chart at 56×15 by default.
import {
pentagonRadarValues,
renderPentagonRadar,
} from "braille-radar"
const values = pentagonRadarValues(axes) // clamped, extracted values
const frame = renderPentagonRadar(axes, values)Animating between profiles
Transitions run over PENTAGON_RADAR_DURATION_MS (220 ms) with a cubic ease-out
curve. Retargeting mid-flight continues from the currently displayed values, so
rapid selection changes never jump:
import {
pentagonRadarTransitionValues,
retargetPentagonRadar,
type PentagonRadarTransition,
} from "braille-radar"
let transition: PentagonRadarTransition | null = null
function selectProfile(next: PentagonRadarValues, now: number): void {
const current = transition === null
? pentagonRadarValues(axes)
: pentagonRadarTransitionValues(transition, now)
transition = retargetPentagonRadar(current, next, transition, now)
}
function draw(now: number): void {
const values = transition !== null
? pentagonRadarTransitionValues(transition, now)
: undefined
console.log(frameToString(renderPentagonRadar(axes, values)))
}See examples/animate.ts for a complete 25 fps loop.
Generic N-axis charts
import { frameToString, generateRadarValues, renderRadar } from "braille-radar"
const values = generateRadarValues({
seed: 7, // deterministic demo data
targetIndex: 3,
pointCount: 6, // any axis count >= 3
valueRange: [0.3, 1],
})
console.log(frameToString(renderRadar(values, {
columns: 44,
rows: 16,
guides: { ringCount: 4, spokes: false }, // or `false` to disable
// center: { x: 44, y: 32 }, // dot coordinates, optional
// radius: 30, // defaults to the largest that fits
})))Output & colors
| Export | Purpose |
|---|---|
| frameToString(frame, palette?) | Flattens a frame into an ANSI-colored string |
| frameToPlainText(frame) | Same, with no escape sequences |
| defaultPalette, rgb, rgbHex | Dark-terminal palette and 24-bit color helpers |
import { defaultPalette, frameToString, rgbHex, type RadarPalette } from "braille-radar"
const palette: RadarPalette = {
...defaultPalette,
profile: rgbHex("#e879f9"), // magenta profile
}
console.log(frameToString(frame, palette))Palette entries are SGR escape sequences; an empty string emits no escape, so
unstyled tones stay plain. Because consecutive same-tone runs are pre-merged,
frames also compose well — zip rows of two charts to place them side by side
(examples/profiles.ts).
API overview
Pentagon (src/pentagon.ts)
| Export | Purpose |
|---|---|
| renderPentagonRadar(axes, values?, columns?, rows?) | Labeled five-axis chart |
| pentagonRadarValues(axes) | Extract and clamp axis values |
| interpolatePentagonRadar(from, to, progress) | Eased interpolation |
| retargetPentagonRadar(current, next, previous, now) | Start/restart a transition |
| pentagonRadarTransitionValues(transition, now) | Values at a timestamp |
| PENTAGON_RADAR_COLUMNS / _ROWS / _DURATION_MS | Defaults: 56×15, 220 ms |
Generic (src/radar.ts)
| Export | Purpose |
|---|---|
| renderRadar(values, options) | Any axis count ≥ 3, configurable geometry and guides |
| renderRadarCells(values, options) | Low-level cell grid (individual Braille characters) |
| radarRuns(frame) | Group cells into same-tone runs |
| interpolateRadarValues(from, to, progress) | Linear interpolation |
| generateRadarValues({ seed, targetIndex, pointCount, valueRange }) | Deterministic profiles for demos/tests |
Examples
| Command | Shows |
|---|---|
| npm run example:basic | Labeled pentagon, default palette |
| npm run example:profiles | Two charts side by side, custom palettes |
| npm run example:animate | Eased transitions between profiles (Ctrl+C to stop) |
| npm run example:generic | 3/6/8-axis charts with varied guide configurations |
Development
npm install
npm test # vitest
npm run typecheck
npm run build # emit ESM + declarations to dist/Tests cover exact-frame rendering across axis counts, guide variants, unassessed axes, clamping and input validation, eased transitions and mid-flight retargeting, ANSI output, and a golden-frame layout regression test.
Releasing
- Update
versioninpackage.json. - Run the full checks:
npm run typecheck && npm test && npm run build. - Inspect the tarball:
npm pack(runsprepack→ build automatically). - Publish:
npm publish.
Attribution
This library was extracted from
Magnitude, an AI coding agent
platform, where it powers the local-model assessment radar in the CLI. The
original implementation lives in cli/src/components/radar.ts and
cli/src/components/pentagon-radar.ts.
Changes made during extraction: the Effect Option dependency was replaced with
plain number | undefined values, tone names were unified, and the ANSI output
layer (src/ansi.ts) was added so charts render without a TUI framework.
License
Apache-2.0 © Magnitude AI Inc.
This project continues the copyright of the repository it was extracted from.
