Skip to content

GUI 皮肤 ​

皮肤决定 Kiki GUI 的配色、字体、圆角和密度。Kiki 内置六个亮暗成对的皮肤家族,你也可以用 JSON 文件添加自己的。皮肤只设置 design token,不带 CSS 也不带代码,所以你装的东西既改不了审批界面的样式,也不会在你的机器上运行任何程序。

亮色与暗色仍然是单独的选择。一套皮肤可以只提供亮色变体、只提供暗色变体,或者两者都有;实际看到哪一个,由皮肤选择器上方的主题开关决定。

内置皮肤 ​

皮肤变体是什么
纸色 Paper × 墨砚 Inkstone(默认)亮色、暗色近白暖纸、墨青定位;入夜换成冷炭灰与铜色行动。
瓷白 Porcelain × 深海 Deepwater亮色、暗色冷白纸面、钴蓝细节;入夜是层次清楚的海军蓝与雾蓝操作色。
青瓷 Celadon × 夜园 Night Garden亮色、暗色青瓷釉与柔白纸面;入夜是深松绿表面与玉色细节。
杏云 Apricot × 晚霞 Afterglow亮色、暗色杏白纸面、莓色操作;入夜是梅炭层级与蜜桃光。
鸢尾 Iris × 星幕 Starveil亮色、暗色紫白纸片、鸢尾紫墨;入夜是靛紫层级与银紫操作色。
高对比 High contrast × 高对比·黑曜 Obsidian亮色、暗色可见边界、AAA 级主文字;入夜是分层炭灰、冰青焦点与近白操作色。

选择与微调 ​

设置 → 外观:

  • 皮肤 —— 选择内置皮肤、主题文件夹里的皮肤、已启用插件贡献的皮肤(标注「来自插件 …」),或已安装外观包的配色。立即生效。
  • 强调色、字体、圆角、密度 —— 在所选皮肤之上覆盖这些值。每个改动都立即生效;恢复默认会一次撤回全部,并提供撤销。
  • 导出为皮肤文件 —— 把当前所见完整写成一个 .json 皮肤文件,可以放进主题文件夹或分享给别人。

在 首次欢迎引导 的第一页,展开 外观,同样可以选亮色 / 暗色、内置配色,以及可选的背景图。

背景图片或视频 ​

设置 → 外观 → 背景,可以在窗口背后放一张图片或一段短视频。

  • 选择图片或视频:PNG、JPEG、WebP、AVIF、GIF、MP4 或 WebM,图片不超过 25 MB,视频不超过 100 MB。文件保存在本设备(浏览器存储)里,不会上传,所以连接远程服务端的浏览器标签页也能用。
  • 或粘贴链接:一个 https 图片或视频链接。服务端按下方的媒体策略抓取一次,副本保存在本设备上。之后不再访问该链接,因此它无法追踪你,离线也能显示。
  • 显示范围:整个窗口、仅对话区,或仅侧栏(平板宽度及以上)。
  • 适配(填满、完整、平铺、居中)、对齐点(九个位置)、图片强度、模糊、亮度和柔化(在图片上叠一层窗口底色)。
  • 面板不透明度和面板模糊:所选范围内,侧栏、页面纸面、标题栏和输入框表面透出多少背景。
  • 亮色和暗色分开设置:默认关闭;打开后可以给两个主题各选一张。

阅读辅助会在对话区和设置页文字背后加一层局部底色,不会提高你设定的面板不透明度。页面纸面、标题栏和输入框跟随这个设置;菜单、对话框和审批提示仍保持实底。低不透明度下,内容复杂的背景仍可能让文字难读,需要更强的分隔就调高面板不透明度。

视频静音循环播放。窗口隐藏或失焦、开启减弱动效、电量低且未充电时,视频停在第一帧(或外观包的封面图)上。超过 1440p 或 40 MB 的视频会给出提示:它们占用大量内存,而在面板后面看不出差别。

主题文件夹 ​

皮肤文件与 TUI 主题放在同一个目录:

  • ~/.kiki/themes/
  • 设置了 KIKI_HOME 时则是 $KIKI_HOME/themes/

目录不存在就自己创建。文件名就是皮肤 id:ocean.json 在选择器里显示为 Ocean。文件名只能用小写字母、数字和连字符。

放好文件后,在「外观」里点重新加载皮肤,不需要重启。

是哪台机器上的目录?

主题目录读取的是运行 Kiki 服务端那台机器上的文件,因为那是服务端唯一能看到的文件系统。

  • 桌面版 —— 你自己的 ~/.kiki/themes/。
  • 浏览器连接远程服务端 —— 这个目录属于那台服务端,不是你正在浏览的设备。内置皮肤两种情况都可用,因为它们随应用一起发布。

Kiki 不会往这个目录里写皮肤文件:导出为皮肤文件只是把文件交给你,由你自己放好。外观包是例外:导入外观包和删除会在此创建或移除外观包文件夹,不做别的事。

编写皮肤 ​

最小的皮肤只写要改的部分:

json
{
  "kind": "kiki-skin",
  "version": 1,
  "name": "Ocean",
  "variants": {
    "dark": {
      "colors": {
        "paper": "#0b2126",
        "accent": "#ff8d7a",
        "onAccent": "#2b0a05"
      }
    }
  }
}

顶层字段:

  • kind(必填):固定为 "kiki-skin"。同一个目录里靠它区分 GUI 皮肤和 TUI 主题。
  • version(必填):固定为 1。
  • name(必填):选择器里显示的名称。
  • id(可选):默认取文件名。
  • description、author(可选):显示在选择器里。
  • variants(必填):至少包含 light 或 dark 之一。

每个变体可以有 colors、fonts、shape。没写的沿用默认值,所以部分覆盖完全可行。

颜色 token ​

所有值都是 #rgb 或 #rrggbb。

Token控制什么
canvas侧边栏所在的应用底面 —— 最低的一层
paper抬起的对话纸面,主要阅读表面
panel检查器、预览和浮动卡片 —— 最高的一层
hairline安静的分隔线和输入框边框
hairlineStrong强调边框、悬停边框
ink正文文字
inkSoft次级文字、标签
inkFaint提示、计数、时间戳
accent唯一的强调色:主按钮、链接、聚焦环、流式光标
accentDeep强调色的悬停/按下态
accentSoft强调色的淡色铺底 —— 选中行、搜索命中闪烁
accentInk当作文字用的强调色 —— 链接、行内强调。不写则由 Kiki 从 accent 派生
onAccent填充强调色之上的文字。必须设置,否则浅色强调色上会配出读不清的白字
amberInk、amberCard、amberRule注意/警示角色:待审批、过期标记
success成功状态、diff 新增行
danger错误、破坏性操作
onDanger填充危险色之上的文字
bubbleUser你自己的消息气泡
scrollbar、scrollbarHover滚动条滑块
shell恒为深色的岛:终端、工具输出井
shellInk、shellInkStrong、shellInkSoft深色岛内的文字
shellDanger深色岛内的错误
shellHairline、shellHover深色岛内的边框与悬停铺底
termScrollbar终端内的滚动条
shadowInk阴影和模态遮罩混合所用的颜色

让文字保持可读

Kiki 内置配色的正文、辅助字、提示字与语义文字在 canvas、paper、panel 上都达到 WCAG AA(4.5:1),onAccent 对 accent 也一样。文字请用 accentInk,不要复用按钮填充色 accent,纸色尤其如此。低于这个对比度的皮肤仍会被加载,Kiki 不会替你改,所以分享之前把 ink、inkSoft、inkFaint 对着三个表面都检查一遍。

字体 ​

json
{ "fonts": { "sans": "'IBM Plex Sans', system-ui, 'PingFang SC', sans-serif" } }
  • sans —— 界面文字
  • display —— 标题和字标
  • mono —— 代码、终端、数字

值只能是字体族栈。皮肤不能加载字体文件;只能写机器上已安装的字体,或 Kiki 已经内置的字体(Instrument Sans、Newsreader、JetBrains Mono、Space Grotesk、Fraunces)。括号、分号和花括号会被拒绝,所以 url(...) 根本无法表达。

字体栈结尾一定要放一个能显示中文的字体或通用族(sans-serif、serif、monospace),否则中文的回退不可预期。

形状 ​

json
{ "shape": { "radius": 14, "stageGap": 8, "spacing": 0.25 } }
  • radius —— 纸面圆角,单位 px(0–28)
  • stageGap —— 窗口边缘与浮动纸面之间的间隙,单位 px(0–24)
  • spacing —— 密度单位,单位 rem(0.19–0.33,默认 0.25)。它会一次性缩放全应用的内边距和间隙,所以小改动影响很大。

出错时会发生什么 ​

有问题的皮肤不会让你用不了界面。「外观」会说明它对每个文件做了什么:

  • 颜色或字体值非法:只丢掉那一个 token,保留默认值,其余照常生效。
  • 无法识别的 token:忽略。
  • 出现意料之外的顶层字段(例如 css):整个文件被拒绝并说明原因——带着 token 之外的东西的文件不算皮肤。
  • JSON 格式错误,或是 TUI 主题文件:跳过并说明原因,其他文件照常加载。
  • 已选中的皮肤文件消失:GUI 回退到默认配色并提示皮肤已丢失,而不是悄悄换成另一套。

外观包 ​

外观包把配色和背景图片或视频打包在一起(每个主题一套),再加一张用于列表的预览图。它是主题文件夹里的一个子文件夹 <themes>/<id>/,包含 kiki-pack.json 和其中列出的文件。仓库里 docs/examples/appearance-packs/dusk-harbor/ 是一个完整示例。

设置 → 外观 → 外观包会列出已安装的外观包及其预览,并提供:

  • 使用外观包:把外观包的配色设为皮肤,把它的媒体设为背景。之后两者都是普通设置,照样可以调滑条。
  • 导入外观包:安装一个 .zip。写入任何内容之前会先完整校验整个压缩包。
  • 导出:把外观包下载为 .zip。
  • 删除:确认后从服务端移除外观包文件夹。
json
{
  "kind": "kiki-appearance-pack",
  "version": 1,
  "id": "dusk-harbor",
  "name": "Dusk Harbor",
  "license": "CC0-1.0",
  "preview": "preview.webp",
  "variants": {
    "light": {
      "colors": { "accent": "#2e6784", "accentInk": "#23566f" },
      "background": { "media": ["tide.webp"], "opacity": 0.9, "surfaceOpacity": 0.74 }
    },
    "dark": {
      "colors": { "accent": "#e5c68c", "onAccent": "#1b1409" },
      "background": { "media": ["lantern.mp4"], "poster": "lantern.webp" }
    }
  }
}
  • id 必须与文件夹名一致(小写字母、数字、连字符)。
  • 每个变体接受皮肤字段(colors、fonts、shape、base)和可选的 background。
  • background.media 列出 1–12 个文件;多于一个时,interval(秒)会让它们轮播。poster 是视频暂停时显示的静帧。
  • 背景参数有 fit(cover contain tile center)、alignment(center top bottom left right topLeft topRight bottomLeft bottomRight)、opacity(0–1)、blur(0–40)、brightness(0.4–1.4)、scrim(0–0.9)、scope(window main sidebar)、surfaceOpacity(0.3–1)和 surfaceBlur(0–32)。命名沿用 Windows Terminal 的背景设置。

surfaceOpacity 决定所选范围内页面纸面、标题栏、输入框表面和右栏透出多少背景。阅读辅助会保留对话区和设置页的局部文字底色,对其他页面纸面和右栏改用磨砂,而不是提高它们的不透明度。低不透明度下,内容复杂的背景仍可能让文字难读,需要更强的分隔就调高 surfaceOpacity。对话框和弹出菜单始终是实底。

内置技能 kiki-appearance 会带着 agent 做一个外观包:格式、每个颜色的对比度要求、媒体尺寸与编码、打包,以及常见的坑。

外观包能放什么、不能放什么 ​

  • 只能放清单和它列出的图片或视频:PNG、JPEG、WebP、AVIF、GIF、MP4、WebM。压缩包里有任何其他东西——脚本、样式表、SVG、HTML、字体,或清单没列出的文件——整个外观包都会被拒绝。
  • 每个文件的开头字节必须与扩展名一致,改了名的网页冒充不了图片。文件以真实类型、nosniff 和沙箱内容策略提供。
  • 上限:单张图片 25 MB,单个视频 100 MB,整个外观包 100 MB、64 个文件。解压之前就会按这些上限检查压缩包条目。
  • 不支持自定义 CSS。 token 已经覆盖应用开放的所有颜色、字体和形状,而样式表还能隐藏审批提示、画出假控件、加载追踪链接。
  • 外观包是整体安装的,任何未知字段都会让整个包失败——这和皮肤文件不同,皮肤文件会丢掉坏 token、保留其余部分。只接受一半会把作者从没一起测试过的媒体和配色凑在一起。

链接图片 ​

或粘贴链接由服务端抓取:只允许 https,URL 里不能带凭据,最多三次重定向,大小上限与上传文件相同。每一跳重定向都会解析,指向非公网地址(回环、私有网段、链路本地、运营商级 NAT)一律拒绝。类型按字节判断,不看响应头。

分发 ​

已启用的插件可以携带皮肤:它在 x-kiki.themes 中声明的条目会和你自己的皮肤文件一起出现在选择器里,并标注来自哪个插件。要分享自己的皮肤,可以直接发 .json 文件、随插件一起打包,或者做成带画面的外观包。