跳转到内容

外观方案(皮肤)文件格式

外观方案是一份 JSON(kind: "xinghan.appearance"),既可以在「偏好设置 → 外观」里导入导出,也可以由插件经 xinghan/appearance-presets 贡献点带进来。宿主解析时宽进严出:认不出的字段丢掉并给出提示,不会因为一个字段而整套作废;比宿主新的顶层字段原样收进 _ext,导出时吐回,不会被吞掉。

一份用满全部维度的例子(内置的「洛可可」就是它;「青花」用的是同一组槽位,配色和装饰件反着取):

{
"kind": "xinghan.appearance",
"schema": 1,
"id": "my-rococo",
"name": "洛可可",
"colors": {
"light": { "accent": "#c9a24c", "surface": "#fbf5e8", "headerStrip": "#e0c06a", "ink": "#3b2d1f", "line": "#d9c391" }
},
"shape": { "cardRadius": 16, "chipRadius": 999 },
"background": { "kind": "preset", "preset": "sky" },
"chips": { "tone": "pastel" },
"typography": {
"display": "\"Cormorant Garamond\", Georgia, \"Songti SC\", serif",
"body": "\"Noto Serif SC\", Georgia, serif",
"numerals": "display",
"webFonts": ["Cormorant Garamond:ital,wght@0,600;1,600"]
},
"frame": {
"placement": "window",
"panels": "boiserie",
"light": { "outer": ["#f6e7b8", "#c9a24c", "#8f6d24"], "inner": "#f6ecc8", "width": 8, "radius": 14, "mat": 18 }
},
"ornaments": {
"corner": { "kind": "builtin", "id": "rocaille" },
"band": { "kind": "builtin", "id": "cartouche" },
"divider": { "kind": "builtin", "id": "acanthus" },
"edge": { "kind": "builtin", "id": "shell-edge" },
"swag": { "kind": "builtin", "id": "festoon" },
"fleuron": { "kind": "builtin", "id": "fleuron" },
"scale": 0.9
},
"texture": { "where": "wall", "light": { "kind": "builtin", "id": "brocade", "opacity": 0.16 } },
"gradients": { "light": { "accent": ["#f6e7b8", "#e0c06a", "#c9a24c"], "headerStrip": ["#f3e2a6", "#c9a24c"] } }
}
字段管什么
colors.light / colors.dark表格的八个色位(accent / surface / surfaceAlt / tray / headerStrip / ink / line / ring)、可选的 highlight(选中 / 悬停底色,不给就从 accent 派生)和外壳的一组(shell.*:shell / sidebar / paper / ink / inkMuted / line / popoverSurface / popoverLine,以及侧栏树的 navIcon 图标统一色、sidebarAccent 选中行底)。accent: "inherit" = 跟随用户在偏好里选的主题色。缺 dark 时夜间回落 light。
shapecardRadius(0–16)、chipRadius(0–999)、chipHeight(16–28)、density
gridcolumnBorders / rowBorders,关掉 = 那一档线画成透明
rowColor行着色策略 accent / soft
surface纸面形态 solid / sheet / open / clear 与玻璃旋钮 blur / rim / contrast,明暗各一套
background方案建议的壁纸:preset(内置的 aurora / dusk / linen / dots / mesh / sky / vignette / ink-mountains 水墨远山 / auspicious-clouds 祥云 / dome 穹顶 / rose-window 玫瑰窗 / candle 烛光 / mandala 曼陀罗)、url(只放行 https)、data(webp / png / jpeg,≤ 400KB);用户自己选过壁纸时以用户的为准
vars逃生舱:直接写 --table-* / --canvas-table-* 等命名空间的变量;值仍要过颜色 / 长度校验,写不出 url()

这五个都是顶层字段,没声明就一个变量都不写。

键说明
display标题类文字的字体栈:格名、项目名、面包屑、列头、题额。永远生效
body正文字体栈。只在用户字体偏好是「系统」时生效:用户明确选过衬线 / 等宽的,用户的赢
mono等宽栈(SQL 编辑器等)
numerals"display" 让表格里的数字也走 display 栈
italicTitlestrue 让格名、项目名用斜体(列头不斜)
nav"display" 让侧栏树的文件名、分区标题也走 display 栈
webFontsGoogle Fonts 的 family 规格数组,宿主拼成 fonts.googleapis.com/css2 的链接;离线时退回栈里的系统字体。只放行这一家

字体栈只认字母、数字、引号、逗号、连字符(含中文字体名);带括号、分号的整条丢掉。

框画在哪由 placement 定,明暗各一套样式:

键说明
placement"panes"(默认)每个分栏格 / 经典布局的主文档区各一圈;"window" 顶栏以下的整个内容区一圈,像一幅画的画框,格子退成一道细线,角饰也搬到窗角
panels"plain"(默认)格子是直角矩形;"boiserie" 格子 / 侧栏 / 主文档区四角向内收一个小圆弧(洛可可墙板),细线跟着轮廓走;"begonia" 内凹的弧大一圈、双层窗框(园林的海棠漏窗);"scroll" 四周一圈卷草联珠的纹样当边框、四角团花(敦煌的壁画边饰),格子让出这一圈;"multifoil" / "cusped" 顶边一排圆瓣 / 尖瓣(多叶拱、尖拱窗棂,瓣按整数个重复);"brocade" 四周一圈藏青锦缎(金色菱格小花、外金内朱两道线,唐卡的装裱)
light / dark下面这组
键说明
outer外层:一个颜色,或 2–4 个颜色的数组(= 135° 的金属渐变)
inner内侧那道细线的颜色;挂窗沿时也是衬边的底色
width0–8 px
radius0–32 px。挂窗沿时跟窗角走(macOS 窗角约 10px,直角会被系统切掉一截;14 左右合适)
mat衬边(画框里的卡纸),0–40 px,只在 placement: "window" 时有意义:画框和内容之间留这么宽一圈实色,角饰落在衬边上,不压内容的角
槽位挂在哪
corner格子 / 编辑区的角,侧栏右下角;线脚挂窗沿时改挂窗口内容区的四角。内置的 rocaille 自带第二张,右上 / 左下用它,四角不对称
edge画框上下两条长边的中点(只在挂窗沿时)
swag花彩:挂在画框上沿正中的垂饰,有它时上沿不再放 edge
fleuron花叶符:格名后面、经典顶栏面包屑的分隔处
band题额:导航项目头下面单独一行牌子托项目名(铺满导航宽度)、经典顶栏里的项目名
divider侧栏项目头下面的分隔花饰

每个槽位一个引用:{ "kind": "builtin", "id": "…" } 用内置库(rocaille 贝壳卷草、cartouche 题额、acanthus 莨苕、deco-corner 装饰艺术直角、seigaiha 青海波、shell-edge 边中贝壳、festoon 花彩、fleuron 花叶符、ruyi 如意云头、begonia 海棠开光题额、fret 回纹、wave-edge 海水纹、lattice-corner 漏窗角、plaque 匾额、tile-ends 瓦当、ice-ray 冰裂窗格、honeysuckle 忍冬卷草、caisson 藻井题额、pearl-string 联珠、lotus-seat 莲花座、apsara-ribbon 飞天飘带、eave 檐口瓦当、ice-line 冰裂线、geo-fleuron / geo-divider 几何圆三角方、tracery-corner / quatrefoil-band / quatrefoil-knot / cross-fleury / trefoil-gable 大教堂五张、muqarnas / zellige / strapwork / eight-star / mosque-lamp 米哈拉布五张、endless-knot / bemma / prayer-wheels / dharma-wheel / wheel-deer-flags 唐卡五张;每张只能挂在它设计的槽位上),或 { "kind": "svg", "svg": "<svg …>" } 自带一张 SVG。自带 SVG ≤ 24KB,且不得含 <script> / <foreignObject> / <image> / <use> / 事件属性 / href / url() / 实体声明 —— 任一处越界整张丢掉。另有 scale(0.5–1.5)与 opacity(0–1)。

单选 / 多选胶囊怎么用选项自己的颜色。选项色是数据,方案不改色相,只定明度与彩度上限:{ "tone": "pastel" | "muted" | "vivid" | "tile" }。粉彩是浅底深字、彩度封低(暖色纸面配它),灰调再灰一档,鲜亮是明度钉住、彩度留满;tile 反过来——实色中明度的底、近白的字、比底深一档的缝(釉砖、彩窗、经幡);黄到青那段色相底会抬亮、字换墨,不然是橄榄。不写就跟随纸面形态(开放表格档自带一套,实心纸不处理)。

铺在纸面上、内容之下,跟壁纸是两层。where 定铺哪:"paper"(默认)纸面全铺,含表格行底下;"wall" 只铺侧栏和画框衬边,格子与数据行干净(行底下压花纹会读成脏的)。明暗各一套:内置 { "kind": "builtin", "id": "brocade" | "damask" | "lattice" | "linen" | "grain" | "crackle" | "bamboo" | "girih" | "tracery" | "thangka-cloud", "opacity", "scale", "color" },或自带位图 { "kind": "data", "mime": "image/webp" | "image/png", "data": "<base64>", "opacity", "scale" }(≤ 200KB,平铺)。

明暗各一套,每项 2–4 个颜色:accent(主按钮、选中态)、headerStrip(列头条,两个引擎都画)、shell(经典顶栏)。

在 plugin.json 的 contributions 里声明 xinghan/appearance-presets,data 就是上面这份 JSON(≤ 64KB)。宿主会把 id 改写成 plugin:<pluginId>:<id>,并过同一道校验。插件 iframe 会随 theme/init / theme/update 消息收到 --xh-font-display / --xh-font-body / --xh-font-mono 三个变量;线脚、装饰、纹理不下发给插件。