不管是编辑器、终端工具还是像 OpenCode 这样的 AI 编码助手,长时间盯着屏幕,配色顺不顺眼真的挺影响心情。有人喜欢深夜绿字黑底的黑客风,有人偏爱 Nord 那种冷静的蓝灰调,也有人干脆就让工具跟着终端的颜色走,懒得折腾。OpenCode 的主题系统基本把这些需求都覆盖了。

先看看终端支不支持真彩色
在挑主题之前,有个小细节值得留意。OpenCode 的主题想要显示出原本设计的全部色彩,终端得支持 truecolor(也就是 24 位色)。好在现在大部分现代终端默认都支持,像 iTerm2、Alacritty、Kitty、Windows Terminal,还有比较新版本的 GNOME Terminal,基本都没问题。
如果不确定,有个简单的检查方法:在终端里跑一下 echo $COLORTERM,如果输出 truecolor 或 24bit,那就说明支持。万一输出为空或者别的什么,可以在 shell 配置文件里加上 export COLORTERM=truecolor 来启用。
要是终端不支持真彩色,主题显示起来会打点折扣------颜色没那么准,或者退回到 256 色的近似值。
内置主题:总有一款看着顺眼
OpenCode 自带了好几个内置主题,基本覆盖了社区里比较流行的配色方案。默认情况下,用的是自己家的 opencode 主题。
下面是目前内置的几个,名字基本就能看出来风格:
| 主题名 | 说明 |
|---|---|
| system | 跟着终端背景色自动适配 |
| tokyonight | 灵感来自 Tokyonight |
| everforest | Everforest 配色 |
| ayu | Ayu 深色主题 |
| catppuccin | Catppuccin 经典版 |
| catppuccin-macchiato | Catppuccin 玛奇朵变体 |
| gruvbox | Gruvbox 复古风 |
| kanagawa | 神奈川冲浪里配色 |
| nord | Nord 北欧冷色调 |
| matrix | 黑客帝国风格,绿字黑底 |
| one-dark | Atom One Dark 主题 |
而且官方还在不断往里面加新主题,隔段时间更新一下可能就有惊喜。
system 主题:懒人福音,自动适配终端
这里面有个比较特别的存在------system 主题。它不是用固定颜色,而是自动去适配用户终端的配色方案。
具体来说做了三件事:
- 根据终端的背景色生成一套灰度色系,保证对比度合适
- 语法高亮和界面元素用的都是标准 ANSI 颜色(0-15),这样就能尊重终端自己的调色板
- 文字和背景颜色设置为
none,相当于保留终端的原生样子,不额外覆盖
这个主题适合三类人:希望 OpenCode 跟终端外观保持一致的用户、自己折腾了终端配色方案的用户、以及喜欢所有终端应用看起来都统一的用户。
怎么切换主题
换主题有两种办法。
第一种最直接:在 OpenCode 里输入 /theme 命令,会弹出一个选择器,上下翻翻选中意的就行。
第二种是写配置文件。在项目根目录或者用户配置目录下的 tui.json 里指定。比如:
json
{
"$schema": "https://opencode.ai/tui.json",
"theme": "tokyonight"
}
自己动手做主题
内置主题再丰富,也难免有人想自己调一套独一无二的配色。OpenCode 的主题系统是基于 JSON 的,灵活性还不错。
主题文件的存放位置
OpenCode 会从多个目录加载主题,后面目录的优先级高于前面的:
- 内置主题------编译在二进制文件里的那些
- 用户配置目录 ------
~/.config/opencode/themes/*.json(或者$XDG_CONFIG_HOME/opencode/themes/*.json) - 项目根目录 ------
<项目根>/.opencode/themes/*.json - 当前工作目录 ------
./.opencode/themes/*.json
如果不同目录里有同名的主题,后面目录里的会覆盖前面的。
创建第一个自定义主题
假设想要一个全局都能用的主题,可以这样操作:
bash
mkdir -p ~/.config/opencode/themes
vim ~/.config/opencode/themes/my-theme.json
如果只想给某个项目用,就在项目根目录下创建:
bash
mkdir -p .opencode/themes
vim .opencode/themes/my-theme.json
JSON 格式长什么样
主题文件支持几种颜色值的写法:
- Hex 颜色 :像
"#ffffff"这样 - ANSI 颜色 :直接用数字
3(范围 0-255) - 颜色引用 :可以引用
"primary"或者自己在defs里定义的别名 - 明暗色变体 :写成
{"dark": "#000", "light": "#fff"},OpenCode 会根据系统或终端环境自动选择 - 无色 :
"none",意思是沿用终端的默认色或者透明
defs 这个部分是选填的,可以在里面定义一堆可复用的颜色名,后面其他地方用 "nord0"、"nord1" 这样的名字直接引用,省得反复写 hex 码。
特别说一下 "none" 这个值
"none" 看起来像个普通字符串,实际上挺有用。把它用在任意颜色字段上,OpenCode 就会乖乖用终端自己的默认颜色。比如 "text": "none" 就是用终端默认的前景色,"background": "none" 就是用终端默认的背景色。这对于做那种想"融入"终端配色方案的主题特别方便。
一个完整的例子
下面是一个基于 Nord 配色方案的自定义主题示例,基本上把能用到的颜色字段都展示了一遍:
json
{
"$schema": "https://opencode.ai/theme.json",
"defs": {
"nord0": "#2E3440",
"nord1": "#3B4252",
"nord2": "#434C5E",
"nord3": "#4C566A",
"nord4": "#D8DEE9",
"nord5": "#E5E9F0",
"nord6": "#ECEFF4",
"nord7": "#8FBCBB",
"nord8": "#88C0D0",
"nord9": "#81A1C1",
"nord10": "#5E81AC",
"nord11": "#BF616A",
"nord12": "#D08770",
"nord13": "#EBCB8B",
"nord14": "#A3BE8C",
"nord15": "#B48EAD"
},
"theme": {
"primary": { "dark": "nord8", "light": "nord10" },
"secondary": { "dark": "nord9", "light": "nord9" },
"accent": { "dark": "nord7", "light": "nord7" },
"error": { "dark": "nord11", "light": "nord11" },
"warning": { "dark": "nord12", "light": "nord12" },
"success": { "dark": "nord14", "light": "nord14" },
"info": { "dark": "nord8", "light": "nord10" },
"text": { "dark": "nord4", "light": "nord0" },
"textMuted": { "dark": "nord3", "light": "nord1" },
"background": { "dark": "nord0", "light": "nord6" },
"backgroundPanel": { "dark": "nord1", "light": "nord5" },
"backgroundElement": { "dark": "nord1", "light": "nord4" },
"border": { "dark": "nord2", "light": "nord3" },
"borderActive": { "dark": "nord3", "light": "nord2" },
"borderSubtle": { "dark": "nord2", "light": "nord3" },
"diffAdded": { "dark": "nord14", "light": "nord14" },
"diffRemoved": { "dark": "nord11", "light": "nord11" },
"diffContext": { "dark": "nord3", "light": "nord3" },
"diffHunkHeader": { "dark": "nord3", "light": "nord3" },
"diffHighlightAdded": { "dark": "nord14", "light": "nord14" },
"diffHighlightRemoved": { "dark": "nord11", "light": "nord11" },
"diffAddedBg": { "dark": "#3B4252", "light": "#E5E9F0" },
"diffRemovedBg": { "dark": "#3B4252", "light": "#E5E9F0" },
"diffContextBg": { "dark": "nord1", "light": "nord5" },
"diffLineNumber": { "dark": "nord2", "light": "nord4" },
"diffAddedLineNumberBg": { "dark": "#3B4252", "light": "#E5E9F0" },
"diffRemovedLineNumberBg": { "dark": "#3B4252", "light": "#E5E9F0" },
"markdownText": { "dark": "nord4", "light": "nord0" },
"markdownHeading": { "dark": "nord8", "light": "nord10" },
"markdownLink": { "dark": "nord9", "light": "nord9" },
"markdownLinkText": { "dark": "nord7", "light": "nord7" },
"markdownCode": { "dark": "nord14", "light": "nord14" },
"markdownBlockQuote": { "dark": "nord3", "light": "nord3" },
"markdownEmph": { "dark": "nord12", "light": "nord12" },
"markdownStrong": { "dark": "nord13", "light": "nord13" },
"markdownHorizontalRule": { "dark": "nord3", "light": "nord3" },
"markdownListItem": { "dark": "nord8", "light": "nord10" },
"markdownListEnumeration": { "dark": "nord7", "light": "nord7" },
"markdownImage": { "dark": "nord9", "light": "nord9" },
"markdownImageText": { "dark": "nord7", "light": "nord7" },
"markdownCodeBlock": { "dark": "nord4", "light": "nord0" },
"syntaxComment": { "dark": "nord3", "light": "nord3" },
"syntaxKeyword": { "dark": "nord9", "light": "nord9" },
"syntaxFunction": { "dark": "nord8", "light": "nord8" },
"syntaxVariable": { "dark": "nord7", "light": "nord7" },
"syntaxString": { "dark": "nord14", "light": "nord14" },
"syntaxNumber": { "dark": "nord15", "light": "nord15" },
"syntaxType": { "dark": "nord7", "light": "nord7" },
"syntaxOperator": { "dark": "nord9", "light": "nord9" },
"syntaxPunctuation": { "dark": "nord4", "light": "nord0" }
}
}
可以看到,defs 里面把所有 Nord 色板定义好,后面 theme 部分里到处引用。而且每个颜色字段都写了 dark 和 light 两种模式,OpenCode 会自动根据系统的深浅色模式来切换。比如在深色模式下主色用 nord8(冰蓝色),浅色模式下用 nord10(深一点的蓝)。
小结
OpenCode 的主题系统从"懒得管"到"完全自己定制"都照顾到了。懒得折腾就用默认或者 system 主题;想要某个社区热门的,内置那些大概率够用;实在手痒想自己配一套,JSON 写起来也不算麻烦,放对目录就能生效。
换主题这事,说大不大说小不小,但每天对着的工具,配色舒服了,写代码的心情确实会好一点。