diff --git a/ascii-frames.ts b/ascii-frames.ts index a97c85e..032191c 100644 --- a/ascii-frames.ts +++ b/ascii-frames.ts @@ -139,6 +139,584 @@ export const mustachiMustacheOnly = [ "", ] +// Face Reworked - Integrated eyes + mustache with per-section ANSI colors +// Lines 0-3: eyes (white foreground, black background) +// Lines 4-8: mustache with mixed section colors + +export type AnsiColor = "black" | "white" | "magenta" | "grey"; + +export interface FaceSection { + text: string; + fg: AnsiColor; + bg: AnsiColor; +} + +export type FaceRow = FaceSection[]; + +export const faceReworked: FaceRow[] = [ + // Lines 0-3: eyes (white on black) + [ + { text: " ▄█████▄ ", fg: "white", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "▀▀▀▀▀", fg: "magenta", bg: "white" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ▄███▀▀▀███▄ ", fg: "white", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "▄███████▄", fg: "white", bg: "magenta" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ███ █████ ", fg: "white", bg: "black" }, + { text: "█", fg: "magenta", bg: "black" }, + { text: "█████████", fg: "white", bg: "black" }, + { text: "█ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ███▄ ▄███ ", fg: "white", bg: "black" }, + { text: "█", fg: "magenta", bg: "black" }, + { text: "█████████", fg: "white", bg: "black" }, + { text: "█ ", fg: "magenta", bg: "black" }, + ], + // Line 4: transition with mixed sections + [ + { text: " ", fg: "black", bg: "black" }, + { text: "▀████", fg: "white", bg: "black" }, + { text: "▄███", fg: "magenta", bg: "white" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: " ", fg: "black", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "███▄", fg: "magenta", bg: "white" }, + { text: "██▀▀", fg: "white", bg: "magenta" }, + { text: "▀ ", fg: "magenta", bg: "black" }, + ], + // Line 5: mixed sections with per-char colors + [ + { text: "▄", fg: "magenta", bg: "black" }, + { text: " ", fg: "black", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "████████▄", fg: "magenta", bg: "black" }, + { text: "████████", fg: "magenta", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: " ", fg: "black", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + ], + // Lines 6-8: mustache (magenta on black) with black spaces + [ + { text: "▀", fg: "magenta", bg: "black" }, + { text: "█████████████████████████", fg: "magenta", bg: "black" }, + { text: "▀", fg: "magenta", bg: "black" }, + ], + [ + { text: " ", fg: "black", bg: "black" }, + { text: "▀█████████▀", fg: "magenta", bg: "black" }, + { text: " ", fg: "black", bg: "black" }, + { text: "▀█████████▀", fg: "magenta", bg: "black" }, + { text: " ", fg: "black", bg: "black" }, + ], + [ + { text: " ", fg: "black", bg: "black" }, + { text: "▀▀███▀▀", fg: "magenta", bg: "black" }, + { text: " ", fg: "black", bg: "black" }, + { text: "▀▀███▀▀", fg: "magenta", bg: "black" }, + { text: " ", fg: "black", bg: "black" }, + ], +]; + +// Reworked Face - Eye variants for animation (lines 0-4) +// Each position has different pupil placement in lines 0-3, line 4 stays same + +export const faceReworkedEyes: Record = { + // Center pupil (default) + center: [ + [ + { text: " ▄█████▄ ", fg: "white", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "▀▀▀▀▀", fg: "magenta", bg: "white" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ▄███▀▀▀███▄ ", fg: "white", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "▄███████▄", fg: "white", bg: "magenta" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ███ █████ ", fg: "white", bg: "black" }, + { text: "█", fg: "magenta", bg: "black" }, + { text: "█████████", fg: "white", bg: "black" }, + { text: "█ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ███▄ ▄███ ", fg: "white", bg: "black" }, + { text: "█", fg: "magenta", bg: "black" }, + { text: "█████████", fg: "white", bg: "black" }, + { text: "█ ", fg: "magenta", bg: "black" }, + ], + // Line 4: transition with mixed sections + [ + { text: " ", fg: "black", bg: "black" }, + { text: "▀████", fg: "white", bg: "black" }, + { text: "▄███", fg: "magenta", bg: "white" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: " ", fg: "black", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "███▄", fg: "magenta", bg: "white" }, + { text: "██▀▀", fg: "white", bg: "magenta" }, + { text: "▀ ", fg: "magenta", bg: "black" }, + ], + ], + + // Pupil up + up: [ + [ + { text: " ▄█▀▀▀█▄ ", fg: "white", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "▀▀▀▀▀", fg: "magenta", bg: "white" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ▄██ ████▄ ", fg: "white", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "▄███████▄", fg: "white", bg: "magenta" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ███▄ ▄███ ", fg: "white", bg: "black" }, + { text: "█", fg: "magenta", bg: "black" }, + { text: "█████████", fg: "white", bg: "black" }, + { text: "█ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ███████████ ", fg: "white", bg: "black" }, + { text: "█", fg: "magenta", bg: "black" }, + { text: "█████████", fg: "white", bg: "black" }, + { text: "█ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ▀████", fg: "white", bg: "black" }, + { text: "▄███", fg: "magenta", bg: "white" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "███▄", fg: "magenta", bg: "white" }, + { text: "██▀▀", fg: "white", bg: "magenta" }, + { text: "▀ ", fg: "magenta", bg: "black" }, + ], + ], + + // Pupil down + down: [ + [ + { text: " ▄█████▄ ", fg: "white", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "▀▀▀▀▀", fg: "magenta", bg: "white" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ▄█████████▄ ", fg: "white", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "▄███████▄", fg: "white", bg: "magenta" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ████▀▀▀████ ", fg: "white", bg: "black" }, + { text: "█", fg: "magenta", bg: "black" }, + { text: "█████████", fg: "white", bg: "black" }, + { text: "█ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ███ █████ ", fg: "white", bg: "black" }, + { text: "█", fg: "magenta", bg: "black" }, + { text: "█████████", fg: "white", bg: "black" }, + { text: "█ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ▀█▄ ", fg: "white", bg: "black" }, + { text: "▄███", fg: "magenta", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: " ", fg: "black", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "███▄", fg: "magenta", bg: "white" }, + { text: "██▀▀", fg: "white", bg: "magenta" }, + { text: "▀ ", fg: "magenta", bg: "black" }, + ], + ], + + // Pupil left + left: [ + [ + { text: " ▄█████▄ ", fg: "white", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "▀▀▀▀▀", fg: "magenta", bg: "white" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ▄█▀▀▀█████▄ ", fg: "white", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "▄███████▄", fg: "white", bg: "magenta" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " █ ███████ ", fg: "white", bg: "black" }, + { text: "█", fg: "magenta", bg: "black" }, + { text: "█████████", fg: "white", bg: "black" }, + { text: "█ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " █▄ ▄█████ ", fg: "white", bg: "black" }, + { text: "█", fg: "magenta", bg: "black" }, + { text: "█████████", fg: "white", bg: "black" }, + { text: "█ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ", fg: "black", bg: "black" }, + { text: "▀████", fg: "white", bg: "black" }, + { text: "▄███", fg: "magenta", bg: "white" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: " ", fg: "black", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "███▄", fg: "magenta", bg: "white" }, + { text: "██▀▀", fg: "white", bg: "magenta" }, + { text: "▀ ", fg: "magenta", bg: "black" }, + ], + ], + + // Pupil right + right: [ + [ + { text: " ▄█████▄ ", fg: "white", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "▀▀▀▀▀", fg: "magenta", bg: "white" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ▄█████▀▀▀█▄ ", fg: "white", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "▄███████▄", fg: "white", bg: "magenta" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " █████ ███ ", fg: "white", bg: "black" }, + { text: "█", fg: "magenta", bg: "black" }, + { text: "█████████", fg: "white", bg: "black" }, + { text: "█ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " █████▄ ▄█ ", fg: "white", bg: "black" }, + { text: "█", fg: "magenta", bg: "black" }, + { text: "█████████", fg: "white", bg: "black" }, + { text: "█ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ", fg: "black", bg: "black" }, + { text: "▀████", fg: "white", bg: "black" }, + { text: "▄███", fg: "magenta", bg: "white" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: " ", fg: "black", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "███▄", fg: "magenta", bg: "white" }, + { text: "██▀▀", fg: "white", bg: "magenta" }, + { text: "▀ ", fg: "magenta", bg: "black" }, + ], + ], + + upLeft: [ + [ + { text: " ▄▀▀▀██▄ ", fg: "white", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "▀▀▀▀▀", fg: "magenta", bg: "white" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ▄█ █████▄ ", fg: "white", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "▄███████▄", fg: "white", bg: "magenta" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ██▄ ▄████ ", fg: "white", bg: "black" }, + { text: "█", fg: "magenta", bg: "black" }, + { text: "█████████", fg: "white", bg: "black" }, + { text: "█ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ███████████ ", fg: "white", bg: "black" }, + { text: "█", fg: "magenta", bg: "black" }, + { text: "█████████", fg: "white", bg: "black" }, + { text: "█ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ", fg: "black", bg: "black" }, + { text: "▀████", fg: "white", bg: "black" }, + { text: "▄███", fg: "magenta", bg: "white" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: " ", fg: "black", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "███▄", fg: "magenta", bg: "white" }, + { text: "██▀▀", fg: "white", bg: "magenta" }, + { text: "▀ ", fg: "magenta", bg: "black" }, + ], + ], + + // Pupil up-right diagonal + upRight: [ + [ + { text: " ▄██▀▀▀▄ ", fg: "white", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "▀▀▀▀▀", fg: "magenta", bg: "white" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ▄███ ███▄ ", fg: "white", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "▄███████▄", fg: "white", bg: "magenta" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ████▄ ▄██ ", fg: "white", bg: "black" }, + { text: "█", fg: "magenta", bg: "black" }, + { text: "█████████", fg: "white", bg: "black" }, + { text: "█ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ███████████ ", fg: "white", bg: "black" }, + { text: "█", fg: "magenta", bg: "black" }, + { text: "█████████", fg: "white", bg: "black" }, + { text: "█ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ", fg: "black", bg: "black" }, + { text: "▀████", fg: "white", bg: "black" }, + { text: "▄███", fg: "magenta", bg: "white" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: " ", fg: "black", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "███▄", fg: "magenta", bg: "white" }, + { text: "██▀▀", fg: "white", bg: "magenta" }, + { text: "▀ ", fg: "magenta", bg: "black" }, + ], + ], + + // Pupil down-left diagonal + downLeft: [ + [ + { text: " ▄█████▄ ", fg: "white", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "▀▀▀▀▀", fg: "magenta", bg: "white" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ▄█████████▄ ", fg: "white", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "▄███████▄", fg: "white", bg: "magenta" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " █▀ ▄██████ ", fg: "white", bg: "black" }, + { text: "█", fg: "magenta", bg: "black" }, + { text: "█████████", fg: "white", bg: "black" }, + { text: "█ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " █ ▀▀█████ ", fg: "white", bg: "black" }, + { text: "█", fg: "magenta", bg: "black" }, + { text: "█████████", fg: "white", bg: "black" }, + { text: "█ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ▀▄▄▄█", fg: "white", bg: "black" }, + { text: "▄███", fg: "magenta", bg: "white" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: " ", fg: "black", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "███▄", fg: "magenta", bg: "white" }, + { text: "██▀▀", fg: "white", bg: "magenta" }, + { text: "▀ ", fg: "magenta", bg: "black" }, + ], + ], + + // Pupil down-right diagonal + downRight: [ + [ + { text: " ▄█████▄ ", fg: "white", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "▀▀▀▀▀", fg: "magenta", bg: "white" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ▄███▀▀▀███▄ ", fg: "white", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "▄███████▄", fg: "white", bg: "magenta" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ███ █████ ", fg: "white", bg: "black" }, + { text: "█", fg: "magenta", bg: "black" }, + { text: "█████████", fg: "white", bg: "black" }, + { text: "█ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ███▄ ▄███ ", fg: "white", bg: "black" }, + { text: "█", fg: "magenta", bg: "black" }, + { text: "█████████", fg: "white", bg: "black" }, + { text: "█ ", fg: "magenta", bg: "black" }, + ], + // Line 4: transition with mixed sections + [ + { text: " ", fg: "black", bg: "black" }, + { text: "▀████", fg: "white", bg: "black" }, + { text: "▄███", fg: "magenta", bg: "white" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: " ", fg: "black", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "███▄", fg: "magenta", bg: "white" }, + { text: "██▀▀", fg: "white", bg: "magenta" }, + { text: "▀ ", fg: "magenta", bg: "black" }, + ], + ], +}; + +// Blink frames for reworked face +export const faceReworkedBlink: Record = { + // Half blink - eyelid halfway + half: [ + [ + { text: " ▄█████▄ ", fg: "grey", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "▀▀▀▀▀", fg: "magenta", bg: "magenta" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ▄█████████▄ ", fg: "grey", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "▄███████▄", fg: "magenta", bg: "magenta" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ", fg: "black", bg: "black" }, + { text: "▀▀▀", fg: "grey", bg: "white" }, + { text: "▀▀▀", fg: "grey", bg: "black" }, + { text: "▀▀▀▀▀", fg: "grey", bg: "white" }, + { text: " ", fg: "black", bg: "black" }, + { text: "█", fg: "magenta", bg: "black" }, + { text: "▀▀▀▀▀▀▀▀▀", fg: "magenta", bg: "white" }, + { text: "█ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ███▄ ▄███ ", fg: "white", bg: "black" }, + { text: "█", fg: "magenta", bg: "black" }, + { text: "█████████", fg: "white", bg: "black" }, + { text: "█ ", fg: "magenta", bg: "black" }, + ], + // Line 4: transition with mixed sections + [ + { text: " ", fg: "black", bg: "black" }, + { text: "▀████", fg: "white", bg: "black" }, + { text: "▄███", fg: "magenta", bg: "white" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: " ", fg: "black", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "███▄", fg: "magenta", bg: "white" }, + { text: "██▀▀", fg: "white", bg: "magenta" }, + { text: "▀ ", fg: "magenta", bg: "black" }, + ], + ], + + // Full blink - eyes closed + closed: [ + [ + { text: " ▄█████▄ ", fg: "grey", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "▀▀▀▀▀", fg: "magenta", bg: "magenta" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ▄█████████▄ ", fg: "grey", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "▄███████▄", fg: "magenta", bg: "magenta" }, + { text: "▄ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ███████████ ", fg: "grey", bg: "black" }, + { text: "█", fg: "magenta", bg: "black" }, + { text: "█████████", fg: "magenta", bg: "black" }, + { text: "█ ", fg: "magenta", bg: "black" }, + ], + [ + { text: " ███████████ ", fg: "grey", bg: "black" }, + { text: "█", fg: "magenta", bg: "black" }, + { text: "█████████", fg: "magenta", bg: "black" }, + { text: "█ ", fg: "magenta", bg: "black" }, + ], + // Line 4: transition with mixed sections + [ + { text: " ▀████", fg: "grey", bg: "black" }, + { text: "▄███", fg: "magenta", bg: "grey" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: " ▄", fg: "magenta", bg: "black" }, + { text: "███▄", fg: "magenta", bg: "magenta" }, + { text: "██▀▀", fg: "magenta", bg: "magenta" }, + { text: "▀ ", fg: "magenta", bg: "black" }, + ], + ], +}; + +// Mustache section (lines 5-8) - same for all animations +export const faceReworkedMustache: FaceRow[] = [ + // Line 5 + [ + { text: "▄", fg: "magenta", bg: "black" }, + { text: " ", fg: "black", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: "████████▄", fg: "magenta", bg: "black" }, + { text: "████████", fg: "magenta", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + { text: " ", fg: "black", bg: "black" }, + { text: "▄", fg: "magenta", bg: "black" }, + ], + // Line 6 + [ + { text: "▀", fg: "magenta", bg: "black" }, + { text: "█████████████████████████", fg: "magenta", bg: "black" }, + { text: "▀", fg: "magenta", bg: "black" }, + ], + // Line 7 + [ + { text: " ", fg: "black", bg: "black" }, + { text: "▀█████████▀", fg: "magenta", bg: "black" }, + { text: " ", fg: "black", bg: "black" }, + { text: "▀█████████▀", fg: "magenta", bg: "black" }, + { text: " ", fg: "black", bg: "black" }, + ], + // Line 8 + [ + { text: " ", fg: "black", bg: "black" }, + { text: "▀▀███▀▀", fg: "magenta", bg: "black" }, + { text: " ", fg: "black", bg: "black" }, + { text: "▀▀███▀▀", fg: "magenta", bg: "black" }, + { text: " ", fg: "black", bg: "black" }, + ], +]; + +export const mustachiVintacheOnly = [ + "", + " ░░░░░░ ░░░░░░", + " ░░░░░░░░░░ ░░░░░░░░░░", + " ░░░░░░░░░░░░░░░░░░░░░░░░░░", + " ░░░░░░░░░░▒▒▒▒░░▒▒▒▒░░░░░░░░░░", + " ░░░░ ░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░ ░░░░", + "▒▒░░ ░░░░░░▒▒▒▒▒▒▒▒▒▒██▒▒██▒▒▒▒▒▒▒▒▒▒░░░░░░ ▒▒░░", + "▒▒░░ ░░░░░░░░▒▒▒▒▒▒▒▒▒▒████▒▒████▒▒▒▒▒▒▒▒▒▒░░░░░░░░ ▒▒░░▒", + "▒▒▒▒░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒██████▒▒██████▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░▒▒▒", + "██▒▒▒▒▒▒▒▒▒▒▒▒▒▒██▒▒▒▒██████▓▓██▒▒██████▒▒▓▓██▒▒▒▒▒▒▒▒▒▒▒▒▒▒█", + "████▒▒▒▒▒▒████▒▒▒▒██████████ ██████████▒▒▒▒████▒▒▒▒▒▒▒▒██", + " ████████████████████████ ████████████████████████", + " ██████████████████ ██████████████████", + " ██████████ ██████████", + "", +]; + // Pupil position mapping for look-around animation // All possible eye directions for random transitions export const pupilPositionFrames = [ diff --git a/config.ts b/config.ts index e9b0cfa..8838675 100644 --- a/config.ts +++ b/config.ts @@ -19,6 +19,8 @@ export type Cfg = { personality_mode: "auto" | "off" // Canonical format: "provider/model" (for example "google/gemini-2.5-flash") personality_model: string + logo_style: "default" | "vintage" + face_style: "full" | "reworked" } export type ResolvedMetricVisibility = { @@ -93,6 +95,8 @@ export const cfg = (opts: Record | undefined): Cfg => { personality_enabled: bool(opts?.personality_enabled, true), personality_mode: oneOf(opts?.personality_mode, ["auto", "off"] as const, "auto"), personality_model: canonicalModel(opts?.personality_model), + logo_style: oneOf(opts?.logo_style, ["default", "vintage"] as const, "vintage"), + face_style: oneOf(opts?.face_style, ["full", "reworked"] as const, "reworked"), } } diff --git a/ui/sidebar-mustachi.tsx b/ui/sidebar-mustachi.tsx index 62245be..dea59ee 100644 --- a/ui/sidebar-mustachi.tsx +++ b/ui/sidebar-mustachi.tsx @@ -22,15 +22,16 @@ import { } from "./sidebar/expression-effects.ts" import { deriveLiveAssistantStats } from "./sidebar/metrics.ts" import { resolveProp, type SidebarMustachiProps } from "./sidebar/shared.ts" +import { getAnsiForegroundColor, getAnsiBackgroundColor } from "./zone-colors.ts" -type SegmentedCell = { content: string; zone: FaceSegment["zone"] | "unknown" } +type SegmentedCell = { content: string; zone: FaceSegment["zone"] | "unknown"; fg?: FaceSegment["fg"]; bg?: FaceSegment["bg"] } const buildSegmentedCells = (segments: FaceSegment[], width: number): SegmentedCell[] => { const cells: SegmentedCell[] = [] segments.forEach(segment => { Array.from(segment.content).forEach(content => { - cells.push({ content, zone: segment.zone }) + cells.push({ content, zone: segment.zone, fg: segment.fg, bg: segment.bg }) }) }) @@ -200,15 +201,19 @@ export const SidebarMustachi = (props: SidebarMustachiProps) => { monocleLensOverlay: monocleLensOverlay(), shouldShowExpression: shouldShowExpression(), tongueFrame: tongueFrame(), + faceStyle: props.config.face_style, }).map(({ content, zone, segments }) => { if (segments?.length) { const cells = buildSegmentedCells(segments, SIDEBAR_FACE_WIDTH) return ( - {cells.map(cell => ( - {cell.content} - ))} + {cells.map(cell => { + // Use ANSI colors if available (reworked face) + const fg = cell.fg ? getAnsiForegroundColor(cell.fg) : getSidebarMustachiZoneColor(cell.zone, props.theme) + const bg = cell.bg ? getAnsiBackgroundColor(cell.bg) : getSegmentedCellBackgroundColor(cell) + return {cell.content} + })} ) } diff --git a/ui/sidebar/face-builder.ts b/ui/sidebar/face-builder.ts index 6ebf320..d025480 100644 --- a/ui/sidebar/face-builder.ts +++ b/ui/sidebar/face-builder.ts @@ -5,6 +5,12 @@ import { eyeBlinkClosed, mustachiMustacheSection, tongueFrames, + faceReworked, + faceReworkedEyes, + faceReworkedBlink, + faceReworkedMustache, + type FaceRow, + type AnsiColor, } from "../../ascii-frames.ts" import { applyMonocleLensOverlay, @@ -15,9 +21,11 @@ import { } from "../../utils/animation-utils.ts" import type { SemanticZone } from "../../types.ts" +export type { FaceSection, FaceRow, AnsiColor } from "../../ascii-frames.ts"; + type FaceSegmentZone = SemanticZone | "eyeFill" | "eyeOverlay" | "eyeShadow" | "monocleLens" -export type FaceSegment = { content: string; zone: FaceSegmentZone } +export type FaceSegment = { content: string; zone: FaceSegmentZone; fg?: AnsiColor; bg?: AnsiColor } export type FaceLine = { content: string; zone: SemanticZone; segments?: FaceSegment[] } export const SIDEBAR_FACE_WIDTH = 27 @@ -104,7 +112,72 @@ export const buildMustachiFace = (input: { monocleLensOverlay: MonocleLensOverlay | undefined shouldShowExpression: boolean tongueFrame: number + faceStyle?: "full" | "reworked" }): FaceLine[] => { + // Handle reworked face style with animation variants + if (input.faceStyle === "reworked") { + const lines: FaceLine[] = []; + + // Determine which eye frame to use based on blink and visual state + let eyeFrames: FaceRow[]; + let useSquint = input.visualState !== "idle" && input.blinkFrame === 0; + + if (input.blinkFrame === 1) { + // Half blink + eyeFrames = faceReworkedBlink.half; + } else if (input.blinkFrame === 2) { + // Full blink + eyeFrames = faceReworkedBlink.closed; + } else if (useSquint) { + // Busy state - use center with squint logic (could add squint variants later) + eyeFrames = faceReworkedEyes.center; + } else { + // Normal - use pupil position + // pupilIndex maps to: 0=center, 1=up, 2=down, 3=left, 4=right, 5=upLeft, 6=upRight, 7=downLeft, 8=downRight + const pupilKeys = ["center", "up", "down", "left", "right", "upLeft", "upRight", "downLeft", "downRight"]; + const pupilKey = pupilKeys[input.pupilIndex] || "center"; + eyeFrames = faceReworkedEyes[pupilKey] || faceReworkedEyes.center; + } + + // Add eye frames (first 5 lines: 4 eyes + 1 transition) + eyeFrames.forEach((row) => { + lines.push({ + content: row.map((s) => s.text).join(""), + zone: "eyes" as SemanticZone, + segments: row.map((section) => ({ + content: section.text, + zone: section.fg === "white" ? "eyes" : "mustache", + fg: section.fg, + bg: section.bg, + })), + }); + }); + + // Add mustache (lines 5-8) + faceReworkedMustache.forEach((row) => { + lines.push({ + content: row.map((s) => s.text).join(""), + zone: "mustache" as SemanticZone, + segments: row.map((section) => ({ + content: section.text, + zone: section.fg === "white" ? "eyes" : "mustache", + fg: section.fg, + bg: section.bg, + })), + }); + }); + + // Add tongue if expression is shown + if (input.shouldShowExpression && input.tongueFrame > 0) { + const tongueLines = tongueFrames[input.tongueFrame]; + tongueLines.forEach((line) => { + lines.push({ content: line, zone: "tongue" }); + }); + } + + return lines; + } + const lines: FaceLine[] = [] let eyeFrame = pupilPositionFrames[input.pupilIndex] diff --git a/ui/zone-colors.ts b/ui/zone-colors.ts index 1a1f829..ff4122c 100644 --- a/ui/zone-colors.ts +++ b/ui/zone-colors.ts @@ -1,6 +1,7 @@ import type { TuiThemeCurrent } from "@opencode-ai/plugin/tui" import { zoneColors } from "../ascii-frames.ts" import type { SemanticZone } from "../types.ts" +import type { AnsiColor } from "../ascii-frames.ts" export type ThemeColor = NonNullable @@ -13,6 +14,25 @@ const sidebarMustachiZoneColors = { mustache: "#FF69B4", } as const +// ANSI color to hex mapping for reworked face +const ansiColorToHex: Record = { + white: "#FFFFFF", + magenta: "#FF4466", + black: "#000000", + grey: "#888888", +} + +// Resolve background color from ANSI color +export function getAnsiBackgroundColor(color: AnsiColor): string | undefined { + if (color === "black") return undefined // Transparent (default terminal background) + return ansiColorToHex[color] +} + +// Resolve foreground color from ANSI color +export function getAnsiForegroundColor(color: AnsiColor): string { + return ansiColorToHex[color] +} + export function getSidebarMustachiZoneBackgroundColor(zone: SemanticZone | string): string | undefined { switch (zone) { case "eyeFill":