/** * KHAELOR * File: src/tui/components/sparkline.ts * Description: Braille sparkline — 2×4 dots per cell, used by /cost per-turn graphs (TUI v2 §3). * * Author: Simon-Pierre Boucher * Contact: contact@spboucher.ai */ // Braille dot bits by (column 0-1, row 0-3), per the Unicode braille block. const DOT_BITS: number[][] = [ [0x01, 0x02, 0x04, 0x40], [0x08, 0x10, 0x20, 0x80], ]; /** * Render a numeric series as a braille sparkline: `⣀⣄⣤⣶⣿⣷⣄`. Two values per * cell, four vertical levels per dot column. Empty/flat series render as a * flat baseline — no fabricated variance (Absolute Rule #4). */ export function brailleSparkline(values: readonly number[], maxCells?: number): string { if (values.length === 0) return ""; const max = Math.max(...values); const levels = values.map((value) => { if (max <= 0) return 1; return Math.max(1, Math.min(4, Math.ceil((value / max) * 4))); }); const cellCount = Math.ceil(levels.length / 2); const cells: string[] = []; for (let cell = 0; cell < cellCount; cell += 1) { let bits = 0; for (let column = 0; column < 2; column += 1) { const level = levels[cell * 2 + column]; if (level === undefined) continue; for (let row = 4 - level; row < 4; row += 1) { bits |= (DOT_BITS[column] as number[])[row] as number; } } cells.push(String.fromCharCode(0x2800 + bits)); } const rendered = cells.join(""); if (maxCells !== undefined && cells.length > maxCells) { return rendered.slice(cells.length - maxCells); } return rendered; }