Craft Agent OSS 主题系统详解:六色语义、OKLCH 配色与 Scenic 模式的完整定制指南
【免费下载链接】craft-agents-oss项目地址: https://gitcode.com/GitHub_Trending/cr/craft-agents-oss
本文基于 Craft Agent 官方主题配置文档(themes.md)展开,系统讲解 Craft Agent 的 6 色彩主题体系、theme.json应用级覆盖、预设主题包、Scenic 玻璃拟态模式以及深色模式的部分覆盖机制。读完本文,你将掌握从“改一个 accent 颜色”到“发布一个完整预设主题包”的全部操作方式,并理解主题在 Electron 渲染进程中的实际解析与热更新链路。
主题体系总览与解析层级
Craft Agent 采用一套6 色彩主题系统,同时支持应用级默认主题与按工作区(workspace)覆盖的主题。主题来源按以下层级生效:
- 应用默认(App default):在 Settings → Appearance → Default Theme 中选择,作用于所有未设置覆盖项的工作区;
- 工作区覆盖(Workspace override):在 Settings → Appearance → Workspace Themes 中按工作区指定主题,可选择“Use Default”或某个具体主题;
- 预设主题包(Preset themes):
~/.craft-agent/themes/{name}.json,完整的主题包文件; - 主题覆盖(Theme overrides):
~/.craft-agent/theme.json,仅覆盖特定颜色(应用级)。
所有配置项都是可选的——应用内置了合理的默认值。未设置自定义主题的工作区会继承应用默认主题。
渲染进程中的实际解析链
从源码结构看,主题的“预览 > 工作区 > 应用默认”解析链在 ThemeContext.tsx 中实现:effectiveColorTheme = previewColorTheme ?? workspaceColorTheme ?? colorTheme,并据此标注当前生效来源为preview/workspace/app。其中:
- 工作区覆盖通过
window.electronAPI.getWorkspaceColorTheme(activeWorkspaceId)从工作区配置读取; - 预设主题优先经 IPC(
loadPresetTheme)从用户目录加载,失败时回退到打包内置主题(import.meta.glob('../../../resources/themes/*.json')),仓库内置的 15 个预设主题位于 apps/electron/resources/themes,包括default、dracula、nord、catppuccin、tokyo-night、gruvbox、rose-pine、github、solarized、one-dark-pro、ghostty、haze、night-owl、pierre、vitesse; - 最终的合并逻辑由 theme.ts 中的
resolveTheme/mergeThemes完成,颜色键(6 个语义色 + 5 个表面色)逐一以覆盖方为准深合并,dark子对象也做同规则合并。
工作区主题的存储位置
工作区主题偏好保存在工作区配置文件中:
~/.craft-agent/workspaces/{id}/config.json{ "id": "ws_abc123", "name": "My Project", "defaults": { "colorTheme": "nord" } }当colorTheme省略或未定义时,工作区继承应用默认主题。在 UI 侧,AppearanceSettingsPage.tsx 负责“Default Theme / Workspace Themes”的设置界面,工作区切换时通过setWorkspaceColorTheme写入并跨窗口广播(broadcastWorkspaceThemeChange)。
6 色彩语义系统
| 颜色 | 用途 | 使用场景 |
|---|---|---|
background | 表面/页面背景 | 浅色/深色表面色 |
foreground | 文本与图标 | 主文本色 |
accent | 品牌色,Execute 模式 | 高亮、激活状态、紫色 UI 元素 |
info | 警告,Ask 模式 | 琥珀色指示、需注意的状态 |
success | 已连接状态 | 绿色对勾、成功状态 |
destructive | 错误、删除操作 | 红色告警、失败状态 |
这 6 个键在 theme.ts 中对应ThemeColors接口(background、foreground、accent、info、success、destructive),全部可选。语义色进一步映射为 CSS 变量(--background、--foreground、--accent、--info、--success、--destructive),供全局样式消费。
此外,仓库还有一层“实体颜色”体系(colors/types.ts):标签、状态等实体配置可以直接引用系统色字符串(如"accent"、"foreground/50",透明度 0–100 通过color-mix(in oklch, ...)渲染),也可以使用{ light, dark }自定义颜色对象——未显式给出dark时由deriveDarkVariant自动派生(hex 颜色向白色混合提亮约 30%)。这说明主题色变量的改动会级联到标签、状态等全部实体着色,定制时建议同时检查这两处观感。
支持的颜色格式
任何合法的 CSS 颜色格式都受支持:
- Hex:
#8b5cf6、#8b5cf6cc(带 alpha) - RGB:
rgb(139, 92, 246)、rgba(139, 92, 246, 0.8) - HSL:
hsl(262, 83%, 58%) - OKLCH:
oklch(0.58 0.22 293)(推荐) - 命名色:
purple、rebeccapurple
建议:使用 OKLCH 以获得感知均匀、在深浅模式下表现一致的颜色。
源码层面有两点值得注意(见 theme.ts 的themeToCSS实现):
--foreground-rgb与--accent-rgb两个派生变量(用于阴影描边和带色调的阴影)仅当颜色是 hex 时才会生成——hexToRgbValues只匹配 6 位/3 位 hex,accent 的 rgb 版本会按 70% 亮度压暗。如果你使用 OKLCH 作为 accent,这部分派生变量不会输出,相关阴影效果会回退到默认表现;- Electron 主进程无法解析 CSS/OKLCH 颜色,theme.ts 提供了
BACKGROUND_HEX(light:#faf9fb,dark:#302f33)作为BrowserWindow.backgroundColor的 hex 等价值,避免窗口加载时的白屏闪烁。
应用级主题覆盖文件(theme.json)
创建~/.craft-agent/theme.json可以覆盖特定颜色:
{ "accent": "oklch(0.58 0.22 293)", "dark": { "accent": "oklch(0.65 0.22 293)" } }所有字段都是可选的,只需指定你想覆盖的颜色。
覆盖文件的校验规则
覆盖文件在读取前会经过 validators.ts 中ThemeOverrideSchema的严格校验(Zod.strict()模式),关键规则包括:
- 允许的颜色键:6 个语义色 + 5 个表面色(
paper、navigator、input、popover、popoverSolid)+mode(枚举solid/scenic)+backgroundImage+dark子对象; - 未知键会被拒绝,空对象(无任何支持字段)也会报错 “Theme override must include at least one supported field”;
mode: "scenic"时必须提供backgroundImage,否则报错 “backgroundImage is required when mode is scenic”。
这与文档“Colors look wrong in dark mode / Background image not showing”的排障建议直接对应:先检查文件是否通过了 schema 约束。
实时热更新
主题修改会立即生效,无需重启。watcher.ts 会监视~/.craft-agent/配置目录,检测到theme.json变更后触发主题重载回调;渲染进程侧由 ThemeContext.tsx 把最终变量注入一个<style id="craft-theme-overrides">元素(内容为:root { --background: ...; --accent: ...; }形式的声明)。因此直接编辑theme.json保存后 UI 即可自动更新。
深色模式(dark 子对象)
dark对象提供深色模式下的可选覆盖。当用户系统处于深色模式时:
- 顶层基础色作为默认值使用;
dark中定义的颜色覆盖基础色。
这允许部分深色定制——只需覆盖需要不同的颜色即可。
实现上,themeToCSS(theme, isDark)在isDark && theme.dark时执行{ ...theme, ...theme.dark }合并,即深色覆盖只针对被显式写出的键生效,其余键仍回退到基础色。默认主题(见下文)即为这种“同一色相、深色模式下提高明度”的典型示范。
预设主题(Preset Themes)
预设主题是完整的主题包,存放于~/.craft-agent/themes/。每个预设是一个包含主题颜色和元数据的 JSON 文件。
预设主题 Schema 示例
{ "name": "Dracula", "description": "A dark theme with vibrant colors", "author": "Zeno Rocha", "license": "MIT", "source": "https://draculatheme.com", "supportedModes": ["dark"], "background": "oklch(0.22 0.02 280)", "foreground": "oklch(0.95 0.01 270)", "accent": "oklch(0.70 0.20 320)", "info": "oklch(0.78 0.14 70)", "success": "oklch(0.72 0.18 145)", "destructive": "oklch(0.65 0.22 28)", "shikiTheme": { "light": "github-light", "dark": "dracula" } }仓库内置的 dracula.json 即遵循该结构(使用 hex 色值且supportedModes: ["dark"]),可作为可直接参考的模板。
预设元数据字段
| 字段 | 说明 |
|---|---|
name | 主题显示名(预设文件中必填) |
description | 简短描述 |
author | 主题作者 |
license | 许可证类型(MIT 等) |
source | 原始主题的 URL |
supportedModes | "light"、"dark"或其组合数组 |
shikiTheme | 语法高亮主题(light/dark 变体) |
对应类型见 theme.ts 的ThemeFile(在ThemeOverrides基础上扩展元数据字段)与PresetTheme(id为去后缀的文件名,如dracula;path为完整路径)。PresetThemeSchema(validators.ts)要求:name非空、且至少包含 6 个语义色中的 1 个,否则报 “Theme must have at least one color property”。
supportedModes与深色强制
从 ThemeContext.tsx 的逻辑可以确认文档中的两条规则:
- 仅支持 dark 的预设(
supportedModes只含"dark")会强制以深色模式渲染,无视系统模式; - 若当前模式不在
supportedModes内,document.documentElement会被标记data-theme-mismatch,UI 采用实心背景以避免视觉错乱;同时 Shiki 语法高亮也会回退到该主题支持的模式的shikiTheme。
语法高亮联动
预设中的shikiTheme决定代码块的语法高亮配色;未指定时使用默认DEFAULT_SHIKI_THEME(light:github-light,dark:github-dark),由getShikiTheme(shikiConfig, isDark)按当前明暗模式选取。
安装预设主题
- 下载或创建一个主题 JSON 文件;
- 保存到
~/.craft-agent/themes/{name}.json(文件名即主题 id); - 在 Settings → Appearance 中选择该主题。
用户目录的预设经 IPC 加载;若 IPC 加载失败(例如 Web 版渲染环境下loadPresetTheme不可用),渲染进程会自动回退到内置同名主题并记录警告。
Scenic 模式(背景图 + 玻璃拟态面板)
Scenic 模式显示整窗背景图片,并配合玻璃拟态(glass-style)面板,营造沉浸式视觉体验。
启用 Scenic 模式
{ "mode": "scenic", "backgroundImage": "mountains.jpg", "background": "oklch(0.15 0.02 270 / 0.8)", "paper": "oklch(0.18 0.02 270 / 0.6)", "navigator": "oklch(0.12 0.02 270 / 0.7)", "popoverSolid": "oklch(0.18 0.02 270)" }Scenic 模式属性
| 属性 | 说明 |
|---|---|
mode | 设为"scenic"(默认是"solid") |
backgroundImage | 图片文件名(相对主题文件)或 URL |
渲染侧的判定条件是resolvedTheme.mode === 'scenic' && backgroundImage 存在(见 ThemeContext 的isScenic计算),二者缺一不可;生效时document.documentElement会获得data-scenic="true"属性,背景图以--background-imageCSS 变量直接设置(注释说明这是为了规避大图 data URL 撑爆样式表大小的问题)。
玻璃面板的表面色
Scenic 模式受益于半透明的表面色:
| 颜色 | 用途 |
|---|---|
paper | AI 消息、卡片、高亮内容 |
navigator | 左侧边栏背景 |
input | 输入框背景 |
popover | 下拉菜单、模态框、上下文菜单 |
popoverSolid | 保证 100% 不透明的 popover 背景 |
表面色的回退规则见themeToCSS:未设置时依次回退到background(--popover-solid则先回退popover再回退background),因此在 Scenic 主题中应显式提供popoverSolid以保证弹出层可读性。
注意:Scenic 主题会自动强制深色模式,以获得与背景图片更好的对比度——这与 ThemeContext.tsx 中effectiveMode = (isScenic || isDarkOnlyTheme) ? 'dark' : resolvedMode的实现一致。
内置默认主题的色值
内置默认主题(DEFAULT_THEME,theme.ts)使用为可访问性优化的 OKLCH 颜色:
Light Mode:
| 槽位 | 色值 | 说明 |
|---|---|---|
| Background | oklch(0.98 0.003 265) | 极浅灰,带轻微紫色调 |
| Foreground | oklch(0.185 0.01 270) | 近黑色,高对比 |
| Accent | oklch(0.58 0.22 293) | 鲜艳的紫色 |
| Info | oklch(0.75 0.16 70) | 暖琥珀色 |
| Success | oklch(0.55 0.17 145) | 清晰的绿色 |
| Destructive | oklch(0.58 0.24 28) | 警示红 |
Dark Mode:
| 槽位 | 色值 | 说明 |
|---|---|---|
| Background | oklch(0.145 0.015 270) | 带紫色调的深暗色 |
| Foreground | oklch(0.95 0.01 270) | 近白色 |
| Accent | oklch(0.65 0.22 293) | 提亮版本,保证深色下可见性 |
| Info | oklch(0.78 0.14 70) | 提亮版本 |
| Success | oklch(0.60 0.17 145) | 提亮版本 |
| Destructive | oklch(0.65 0.22 28) | 提亮版本 |
即深色模式并非简单反色,而是保持色相、提高明度(lightness),这正是文档推荐 OKLCH 的原因。
实战示例
最简:只改 accent 颜色
{ "accent": "#3b82f6" }自定义品牌色
{ "accent": "oklch(0.55 0.25 250)", "info": "oklch(0.70 0.15 200)", "dark": { "accent": "oklch(0.65 0.25 250)", "info": "oklch(0.75 0.12 200)" } }高对比度主题
{ "background": "#ffffff", "foreground": "#000000", "dark": { "background": "#000000", "foreground": "#ffffff" } }注意前两个示例都使用 hex 前景/主色,因此--foreground-rgb/--accent-rgb派生变量可以正常输出;第三个示例的全黑/全白搭配同样能触发 rgb 派生变量。
创建主题的流程与建议
- 覆盖单个颜色:创建
~/.craft-agent/theme.json;做完整主题包:创建~/.craft-agent/themes/{name}.json; - 只添加你要定制的颜色(预设需至少 1 个语义色,覆盖文件至少 1 个受支持字段);
- 可选地添加
dark子对象覆盖深色模式。
技巧:
- 从只改
accent开始,快速个性化; - 使用 OKLCH 获得可预测的颜色行为;
- 在浅色和深色两种模式下都测试;
- 保持对比度可访问(foreground 对 background)。
故障排查
主题不生效(Theme not applying):
- 确认 JSON 语法合法(
validateThemeContent/validateThemeOverrideContent会先做 JSON 解析再跑 schema); - 检查文件位置是否正确(覆盖是
~/.craft-agent/theme.json,预设是~/.craft-agent/themes/,预设文件名即主题 id); - 确保颜色值是合法的 CSS 颜色;
- 预设文件检查
name是否存在且至少有一个语义色,未知键在覆盖文件中会直接导致校验失败。
深色模式下颜色不对(Colors look wrong in dark mode):
- 添加显式
dark覆盖; - OKLCH 颜色在深色模式下通常需要更高的 lightness 值;
- 检查预设的
supportedModes是否排除了当前模式(dark-only 主题会强制深色渲染,data-theme-mismatch时 UI 改用实心背景)。
背景图不显示(Background image not showing):
- 确认
mode设为"scenic"; - 检查图片路径是相对主题文件的路径,或为合法 URL(schema 层面也要求 scenic 模式必须提供
backgroundImage); - 确认图片文件存在且可读。
OKLCH 颜色参考
OKLCH 格式:oklch(lightness chroma hue)
- Lightness(明度):0–1(0 = 黑,1 = 白)
- Chroma(彩度):0–0.4(0 = 灰,越大越饱和)
- Hue(色相):0–360(色轮角度)
常用色相参考:
| 颜色 | 色相值 |
|---|---|
| Red | ~25 |
| Orange | ~70 |
| Yellow | ~100 |
| Green | ~145 |
| Cyan | ~195 |
| Blue | ~250 |
| Purple | ~293 |
| Pink | ~330 |
对照内置默认主题可以发现其取色规律:accent 用 293(紫)、info 用 70(橙琥珀)、success 用 145(绿)、destructive 用 28(红),与上表一一对应——自建主题时按同一色相坐标取值,再在dark子对象里把 lightness 提高 0.05–0.10,即可得到风格一致的深色变体。
小结
Craft Agent 的主题体系可以概括为三条正交的能力线:颜色层(6 语义色 + 5 表面色,OKLCH 优先,dark部分覆盖)、选择层(应用默认 → 工作区覆盖 → 预设包 → theme.json 覆盖,UI 侧另有悬停预览优先级)、模式层(solid / scenic,scenic 强制深色并联动 Shiki 高亮与data-scenicCSS 钩子)。相关实现集中在 theme.ts(类型、默认值与 CSS 变量生成)、validators.ts(覆盖文件与预设文件的严格 schema 校验)、watcher.ts(theme.json 热更新)与 ThemeContext.tsx(渲染端解析、DOM 注入与跨窗口同步),读者可沿这些文件进一步深入。
【免费下载链接】craft-agents-oss项目地址: https://gitcode.com/GitHub_Trending/cr/craft-agents-oss
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考