颜色

OpenTUI 使用 RGBA 类进行颜色表示。该类在内部存储 8 位 RGBA 通道值以及打包的元数据,但提供了处理不同颜色格式的方法。

每种颜色还在打包的值中携带颜色意图:RGB 快照、索引 ANSI 槽位或终端默认值。渲染器使用此意图在终端调色板更改时保持调色板相关颜色的稳定。

创建颜色

从整数(0-255)

import { RGBA } from "@opentui/core"

const red = RGBA.fromInts(255, 0, 0, 255)
const semiTransparentBlue = RGBA.fromInts(0, 0, 255, 128)

从浮点值(0.0-1.0)

浮点值会被量化为 8 位通道用于终端输出。

const green = RGBA.fromValues(0.0, 1.0, 0.0, 1.0)
const transparent = RGBA.fromValues(1.0, 1.0, 1.0, 0.5)

从十六进制字符串

const purple = RGBA.fromHex("#800080")
const withAlpha = RGBA.fromHex("#FF000080") // 半透明红色

字符串颜色

大多数组件属性同时接受 RGBA 对象和颜色字符串:

import { Text, Box } from "@opentui/core"

// 使用十六进制字符串
Text({ content: "Hello", fg: "#00FF00" })

// 使用 CSS 颜色名称
Box({ backgroundColor: "red", borderColor: "white" })

// 使用 RGBA 对象
const customColor = RGBA.fromInts(100, 150, 200, 255)
Text({ content: "Custom", fg: customColor })

// 透明
Box({ backgroundColor: "transparent" })

parseColor 工具函数

parseColor() 函数将各种颜色格式转换为 RGBA:

import { parseColor } from "@opentui/core"

const color1 = parseColor("#FF0000") // 十六进制
const color2 = parseColor("blue") // CSS 颜色名称
const color3 = parseColor("transparent") // 透明
const color4 = parseColor(RGBA.fromInts(255, 0, 0, 255)) // 直接传递

颜色意图

每个 RGBA 值在 RGBA 快照旁的打包元数据中存储意图。渲染器读取此意图以决定发出哪个 ANSI 序列:

  • rgb:字面 RGB 颜色。渲染器发出 38;2;r;g;b / 48;2;r;g;b
  • default:终端的默认前景色或背景色。渲染器发出 39 / 49(SGR 默认值),让终端选择其调色板的正确部分。
  • indexed:索引 ANSI 颜色。渲染器发出 38;5;n / 48;5;n,使用户对该调色板槽位的主题覆盖在调色板更改时继续生效。

每种颜色仍携带其 RGBA 值,因此 alpha 混合和非 ANSI 渲染器可以正常工作。意图通过 TypeScript、FFI、缓冲区和原生渲染器端到端流动。

默认前景色和背景色

import { RGBA } from "@opentui/core"

// 渲染时将发出 SGR 39 / 49
const fg = RGBA.defaultForeground()
const bg = RGBA.defaultBackground()

你可以传递可选的快照颜色来覆盖 RGBA 回退值。渲染器在检测到终端调色板之前使用快照处理早期帧:

const fg = RGBA.defaultForeground("#E6EDF3")

索引 ANSI 颜色(0-255)

import { RGBA, ansi256IndexToRgb } from "@opentui/core"

// 索引颜色即使用户更改主题也会保留其调色板槽位
const ansiRed = RGBA.fromIndex(1)
const ansiBrightBlue = RGBA.fromIndex(12)

// 带自定义 RGBA 快照(用于调色板检测前的早期帧)
const themed = RGBA.fromIndex(4, "#1F6FEB")

// 将 ANSI 256 索引转换为 RGB 三元组
const [r, g, b] = ansi256IndexToRgb(196)

检查颜色意图

import { RGBA } from "@opentui/core"

const fg = RGBA.defaultForeground()
fg.intent // => "default"

const indexed = RGBA.fromIndex(10)
indexed.intent // => "indexed"
indexed.slot // => 10

const literal = RGBA.fromHex("#00FF00")
literal.intent // => "rgb"

导出的颜色常量和类型

导出说明
DEFAULT_FOREGROUND_RGB[255, 255, 255] 默认前景色回退 RGB 三元组
DEFAULT_BACKGROUND_RGB[0, 0, 0] 默认背景色回退 RGB 三元组
ColorIntent"rgb" | "indexed" | "default"
RGBTripletreadonly [number, number, number]
ansi256IndexToRgb(index)将 ANSI 256 调色板索引转换为 RGB 三元组
parseColor(value)string | RGBA 解析为 RGBA

打包传输

RGBA.buffer 是一个 Uint16Array(4)。每个分量的低字节存储 rgba;高字节一起存储 32 位元数据。

const color = RGBA.fromIndex(6)

color.buffer // Uint16Array(4)
color.intent // "indexed"
color.slot // 6

这使得原生缓冲区可以用精确的整数相等性比较当前帧和下一帧的颜色。它还在颜色跨越 TypeScript/原生边界时保持调色板意图附加到颜色上。

终端调色板检测

当终端支持时,渲染器会查询活动调色板(OSC 4 用于调色板槽位,OSC 10/11 用于默认前景色/背景色,以及其他支持的特殊颜色)。索引颜色保持映射到终端的用户配置槽位,默认颜色保持链接到终端默认值,非真彩色渲染器可以根据检测到的调色板重新解析 RGB 回退值。

const colors = await renderer.getPalette({ size: 256 })

console.log(colors.palette[1]) // '#cc0000' 或你主题使用的红色
console.log(colors.defaultForeground, colors.defaultBackground)

常用成员:

  • renderer.getPalette(options?) — 返回 TerminalColors 快照。按请求的大小(16256)缓存。
  • renderer.paletteDetectionStatus"idle" | "detecting" | "cached"
  • renderer.clearPaletteCache() — 丢弃缓存的调色板(例如,用户更改主题后)。
  • renderer.on("palette", handler) — 当检测到的调色板更改时订阅刷新的调色板快照。

如果渲染器处于挂起状态,getPalette 会抛出异常。启动时的调色板检测仅在原生 ANSI-256 回退渲染需要调色板数据(没有真彩色 rgbansi256)时自动运行。真彩色终端仅在你调用 getPalette() 或存在调色板监听器且终端报告主题更改时才查询调色板。

Alpha 混合

你可以使用透明单元格和 alpha 混合来实现分层效果:

import { FrameBufferRenderable, RGBA } from "@opentui/core"

const canvas = new FrameBufferRenderable(renderer, {
  id: "canvas",
  width: 50,
  height: 20,
})

// 使用 alpha 混合绘制
const semiTransparent = RGBA.fromValues(1.0, 0.0, 0.0, 0.5)
const transparent = RGBA.fromInts(0, 0, 0, 0)
canvas.frameBuffer.setCellWithAlphaBlending(10, 5, " ", transparent, semiTransparent)

混合后的颜色在内部变成字面 RGB 颜色。这是有意设计的:一旦颜色被混合,结果不再表示特定的 ANSI 槽位或终端默认值。

带颜色的文本属性

将颜色与文本属性结合:

import { TextRenderable, TextAttributes, RGBA } from "@opentui/core"

const styledText = new TextRenderable(renderer, {
  id: "styled",
  content: "Important",
  fg: RGBA.fromHex("#FFFF00"),
  bg: RGBA.fromHex("#333333"),
  attributes: TextAttributes.BOLD | TextAttributes.UNDERLINE,
})

颜色常量

常用颜色:

// 一些常用颜色示例
const white = RGBA.fromInts(255, 255, 255, 255)
const black = RGBA.fromInts(0, 0, 0, 255)
const red = RGBA.fromInts(255, 0, 0, 255)
const green = RGBA.fromInts(0, 255, 0, 255)
const blue = RGBA.fromInts(0, 0, 255, 255)
const transparent = RGBA.fromInts(0, 0, 0, 0)