OpenCode 内置了许多适用于浅色和深色模式的主题。可在设置中选择其中一个,或自行搭配颜色。

选择主题

按下 Ctrl+P,选择 Open settings,然后打开 Theme。默认主题是 opencode。
也可以在全局 CLI 设置中指定主题和模式:
{
  "$schema": "https://opencode.ai/v2/cli.json",
  "theme": {
    "name": "tokyonight",
    "mode": "dark"
  }
}
运行 /themes 即可在不打开设置的情况下切换主题。

系统颜色

当 OpenCode 能够读取终端调色板时,主题选择器会包含 system 主题。它会根据终端的前景色、背景色和 ANSI 调色板推导颜色。
主题名 system 表示使用从终端推导出的颜色。模式 system 则跟随终端的浅色或深色外观。

模式

使用 system 可跟随终端外观,也可以将主题锁定为浅色或深色模式:
| 模式 | 行为 | | --- | --- | | system | 跟随终端检测到的浅色或深色外观。 | | dark | 始终使用主题的深色配色。 | | light | 始终使用主题的浅色配色。 |
这对应 CLI 配置中 theme 内的 mode 字段。如果自定义主题仅提供一种模式,当请求另一种模式时,OpenCode 会使用已有的那种模式。

添加主题

要添加下载或从他人处获得的主题,请将其 JSON 文件复制到全局主题目录:
cp theme.json ~/.config/opencode/themes/
也可以将主题放在项目的 .opencode/themes 目录中,使其仅在该项目中可用。
文件名即为主题名。例如,my-theme.json 会显示为 my-theme。添加文件后请重启 OpenCode,然后运行 /themes 选择该主题。
OpenCode 仅读取 .json 文件。更靠近当前目录的主题会覆盖同名的全局或上级目录主题。

在插件中使用主题

CLI 插件通过 context.theme 读取解析后的颜色,通过 context.themeMode 读取当前模式。使用语义化 token 可让插件跟随所选主题:
import { usePlugin } from "@opencode/plugin/tui"

function Status() {
  const context = usePlugin()
  return <text fg={context.theme.text.base}>Ready</text>
}
公开的 CLI 插件 API 不注册主题。请使用上述目录中的 JSON 文件添加自定义主题定义。

创建主题

使用我们的主题工具创建或编辑主题。该工具便于理解主题结构、进行修改并定义自定义颜色。以下说明仅供参考。
主题将共享的语义化 token 与各模式专属的调色板分开:
| 部分 | 用途 | | --- | --- | | base | 所有模式共享的完整 token 树。 | | light、dark | 该模式的完整色相调色板以及可选的 token 覆盖。 |
每个主题都要提供完整的 base,并至少定义 light 或 dark 之一。各模式继承文件中的 base;它们不会继承内置的 OpenCode 主题,也不会相互继承。
以下示例仅展示与各概念相关的部分。请先用主题编辑器生成完整文件,再进行自定义。

结构

将两种模式共用的颜色放在 base 中,需要时再在 light 或 dark 内覆盖:
{
  "$schema": "https://opencode.ai/theme.json",
  "base": {
    "text": {
      "base": "$hue.neutral.200",
      "muted": "$hue.neutral.400"
    }
  },
  "light": {
    "hue": {}
  },
  "dark": {
    "hue": {},
    "text": {
      "muted": "$hue.neutral.300"
    }
  }
}
完整的 base 提供所有语义化 token。每个模式提供所有必需的色相,并可覆盖 base token 树的任意部分。

颜色与引用

颜色可以是十六进制值、"transparent",或对其他主题颜色的引用:
{
  "text": {
    "base": "#eeeeee",
    "muted": "$hue.neutral.400"
  },
  "border": {
    "base": "$text.muted"
  }
}

色相

色相是九级色阶。每个模式定义八个基础色相和三个别名:
| 类型 | 值 | | --- | --- | | 基础 | gray、red、orange、yellow、green、cyan、blue、purple | | 别名 | accent、interactive、neutral | | 级别 | 100、200、300、400、500、600、700、800、900 |
为基础色相定义全部九级,或将一个色相指向另一个色相作为别名:
{
  "hue": {
    "purple": {
      "100": "#b38ff4",
      "200": "#9d7cd8",
      "300": "#8869bd",
      "400": "#7357a2",
      "500": "#5f4688",
      "600": "#4b356f",
      "700": "#392557",
      "800": "#271640",
      "900": "#17072b"
    },
    "accent": "$hue.purple"
  }
}
色相级别遵循模式的对比度方向。浅色主题从 100 的深色过渡到 900 的浅色;深色主题从 100 的浅色过渡到 900 的深色。
base 中的 categorical 数组设置用于区分智能体及其他重复项的有序色相:
{
  "categorical": ["accent", "purple", "green", "blue"]
}

语义化 token

语义化 token 将颜色分配给 UI 角色。组件使用这些角色,而非直接选择颜色。
| 分组 | 用途 | | --- | --- | | text | 基础、弱化、极弱、操作、表单字段和反馈文本。faint 默认取 muted。 | | background | 基础、抬升表面、操作、表单字段和反馈填充。 | | border、scrollbar | 边框和滚动条颜色。 | | diff | 新增、删除、上下文、高亮和行号颜色。 | | syntax | 源代码高亮。 | | markdown | Markdown 元素。 |
例如,text.muted 控制次要文本,而 background.raised 定义逐级抬升的表面:
{
  "text": {
    "base": "$hue.neutral.200",
    "muted": "$hue.neutral.400"
  },
  "background": {
    "base": "$hue.neutral.800",
    "raised": {
      "base": "$hue.neutral.700",
      "high": "$hue.neutral.600",
      "max": "$hue.neutral.500"
    }
  }
}
Syntax 键包括 comment、keyword、function、variable、string、number、type、operator 和 punctuation。
Markdown 键包括 text、heading、link、linkText、code、blockQuote、emphasis、strong、horizontalRule、listItem、listEnumeration、image、imageText 和 codeBlock。

操作与状态

操作分为 primary、secondary 和 destructive 三种变体。操作和表单字段使用 base,外加可选的交互状态:
{
  "text": {
    "action": {
      "primary": {
        "base": "$hue.interactive.400",
        "$hovered": "$hue.interactive.300",
        "$disabled": "$hue.neutral.600"
      }
    }
  }
}
状态键为 $hovered、$focused、$pressed、$selected 和 $disabled。未指定的状态沿用该操作或表单字段的 base 颜色。

对话框表面

面板、对话框、菜单和 toast 从 background.raised 选取其深度。对话框还可以通过 @dialog 额外覆盖语义化 token:
{
  "@dialog": {
    "background": {
      "base": "$background.raised.base",
      "action": {
        "primary": {
          "$hovered": "$background.raised.high"
        }
      }
    }
  }
}
TUI 在应用 @dialog 后会重新解析引用,因此引用 $background.base 的 token 会跟随对话框背景。上下文操作的 base 会成为其未指定状态的回退值;显式的状态覆盖仍然优先生效。