gohud

可读性是量出来的

← 主题

“好看”是口味问题;“看得清”却可以测量。 灰得发淡的文字在好显示器上没问题, 到了白天的手机屏上就消失了 —— 靠眼睛挑颜色,迟早会出这种事。

python3 addons/gohud/tools/check_contrast.py
对象要求
正文文字4.5 : 1
大号文字(24px 及以上)3 : 1
强调色的边框和图标3 : 1
装饰性边框2 : 1 —— WCAG 的 3:1 规则不适用于纯装饰
相邻表面1.12 : 1 —— 足以让卡片从背景中区分出来

同色相文字压在同色相底色上

这个坑在本项目里出现过三次 —— 按下状态的按钮(强调色面板配强调色文字)、 危险按钮,以及标签片。它在色卡上看着挺好,一测就崩, 因为两者色相相同,明度上也就没有差别。

所以文字颜色不是手工挑的。主题生成器和 GoSkin 各自只推明度 —— 而且只推明度 —— 直到它在文字真正落脚的那块面板上达标为止。色相和饱和度保持不变, 因此调色板保留了自己的性格,改动它也不会丢掉对比度。

当文字读的颜色和当色块涂的颜色,要求正好相反

在浅色主题上,警告色当文字用时必须压暗才读得清(#96500A)。 而状态条的填充要是继承了这个值,经验条就变成褐色了。光靠颜色解决不了: 黄色本身就亮,所以哪怕底槽完全不加灰也能过 3:1,而把底槽压暗只会让情况更糟(1.52 → 1.06)。

于是把两者分开。颜色保持鲜艳 —— 调色板里带有仅用于填充的颜色,例如 warning_vivid对比度交给边缘来扛 —— 只要某个填充在自己的底槽上达不到 3:1, GoSkin 就给它画一圈 1dp 的描边,这样“到底满了多少”依然看得清。

MY_LIGHT = dict(
    warning=hexc("9A5407"),         # 当文字读
    warning_vivid=hexc("F2A007"),   # 涂在状态条上
)
漏写了会被报出来。 少了 *_vivid 时,若填充色算出来偏暗,生成器就会打印 the bar looks drab — add warning_vivid to the palette(生成器实际输出的原文,意为“状态条发暗 —— 请在调色板里加上 warning_vivid”)。 以前会悄悄劣化的地方,现在会开口说话。

浮动面板不可能知道自己背后是什么

HUD 是画游戏画面之上的 —— 背后可能是雪原,也可能是洞窟。如果它的面板半透明, 背后的东西就会透上来,改变面板的颜色,文字对比度也跟着被拖下去。 在 82% 不透明度下,深色主题的弱化文字在明亮背景上掉到了 3.74:1 —— 低于下限。

所以半透明面板一律以纯白和纯黑作为背景来测量;游戏场景能给出的最坏情况也就是这两种了。 随包主题的 HUD 面板不透明到足以达标(92%),同时仍保留那种玻璃质感。

同理,图标颜色也不写死。快捷槽里的图形原本被硬编码成白色,在浅色主题上量出 1.11:1 —— 现在它会跟随自己所在的面板,和文字的做法完全一样。

两个检查器,两段够得着的范围。 check_contrast.py 读的是主题文件; 皮肤在运行时混出来的颜色(标签片、快捷槽)则由测试套件在 Godot 内部的 skin contrast 一节来测量。