85 lines
2.2 KiB
TypeScript
85 lines
2.2 KiB
TypeScript
import type { RGBColor as RGBColorString } from '../../ink/styles.js'
|
|
import type { RGBColor as RGBColorType } from './types.js'
|
|
|
|
export function getDefaultCharacters(): string[] {
|
|
if (process.env.TERM === 'xterm-ghostty') {
|
|
return ['·', '✢', '✳', '✶', '✻', '*'] // Use * instead of ✽ for Ghostty because the latter renders in a way that's slightly offset
|
|
}
|
|
return process.platform === 'darwin'
|
|
? ['·', '✢', '✳', '✶', '✻', '✽']
|
|
: ['·', '✢', '*', '✶', '✻', '✽']
|
|
}
|
|
|
|
// Interpolate between two RGB colors
|
|
export function interpolateColor(
|
|
color1: RGBColorType,
|
|
color2: RGBColorType,
|
|
t: number, // 0 to 1
|
|
): RGBColorType {
|
|
return {
|
|
r: Math.round(color1.r + (color2.r - color1.r) * t),
|
|
g: Math.round(color1.g + (color2.g - color1.g) * t),
|
|
b: Math.round(color1.b + (color2.b - color1.b) * t),
|
|
}
|
|
}
|
|
|
|
// Convert RGB object to rgb() color string for Text component
|
|
export function toRGBColor(color: RGBColorType): RGBColorString {
|
|
return `rgb(${color.r},${color.g},${color.b})`
|
|
}
|
|
|
|
// HSL hue (0-360) to RGB, using voice-mode waveform parameters (s=0.7, l=0.6).
|
|
export function hueToRgb(hue: number): RGBColorType {
|
|
const h = ((hue % 360) + 360) % 360
|
|
const s = 0.7
|
|
const l = 0.6
|
|
const c = (1 - Math.abs(2 * l - 1)) * s
|
|
const x = c * (1 - Math.abs(((h / 60) % 2) - 1))
|
|
const m = l - c / 2
|
|
let r = 0
|
|
let g = 0
|
|
let b = 0
|
|
if (h < 60) {
|
|
r = c
|
|
g = x
|
|
} else if (h < 120) {
|
|
r = x
|
|
g = c
|
|
} else if (h < 180) {
|
|
g = c
|
|
b = x
|
|
} else if (h < 240) {
|
|
g = x
|
|
b = c
|
|
} else if (h < 300) {
|
|
r = x
|
|
b = c
|
|
} else {
|
|
r = c
|
|
b = x
|
|
}
|
|
return {
|
|
r: Math.round((r + m) * 255),
|
|
g: Math.round((g + m) * 255),
|
|
b: Math.round((b + m) * 255),
|
|
}
|
|
}
|
|
|
|
const RGB_CACHE = new Map<string, RGBColorType | null>()
|
|
|
|
export function parseRGB(colorStr: string): RGBColorType | null {
|
|
const cached = RGB_CACHE.get(colorStr)
|
|
if (cached !== undefined) return cached
|
|
|
|
const match = colorStr.match(/rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/)
|
|
const result = match
|
|
? {
|
|
r: parseInt(match[1]!, 10),
|
|
g: parseInt(match[2]!, 10),
|
|
b: parseInt(match[3]!, 10),
|
|
}
|
|
: null
|
|
RGB_CACHE.set(colorStr, result)
|
|
return result
|
|
}
|