9.1 栅格、间距与安全区
栅格、间距与安全区是 UI 规范里最先被写死、也最容易被分辨率打脸的一层。本节把《星屑旅店》的基准分辨率、12 列栅格、8px 间距阶与刘海屏安全区写成一份可跑的整数规范,用 S 层 Python 与 P 层 TS 内核算出每个元素落在哪一格,并对四条边做越界断言。
tag
栅格、间距与安全区是 UI 规范里最先被写死、也最容易被分辨率打脸的一层。本节把《星屑旅店》的基准分辨率、12 列栅格、8px 间距阶与刘海屏安全区写成一份可跑的整数规范,用 S 层 Python 与 P 层 TS 内核算出每个元素落在哪一格,并对四条边做越界断言。
压缩格式不是画质参数,是显存账的乘数。本节把 BC1/BC3/BC7/ASTC 4x4/6x6/ETC2 的块大小与块字节固化成 D 层规格表,再用一份真跑的 S 层脚本把 1024×1024 的底级与整条 mip 链算成整数个字节,给出相对未压缩 RGBA8 的千分比与一份可执行的选型取舍表。
纹理显存不是一个数字,而是一条从底级到 1×1 的 mip 链。本节用一份真跑的 S 层脚本,读共享真源复现 1024×1024 RGBA 全链基线 5592404 字节,再按贴图集逐张算整链字节与千分比,并用 P 层 TS 内核做跨语言逐位对照与漏算 1×1 的负例断言。
超支之后先归因再动手:把每个超支项拆成「可裁空间」与「不可裁地板」,再按每 1 人天换回的单位数排一条确定性、可重复的裁剪顺序。本节给出可跑的三类归因判定、贪心裁剪计划,以及「超支项裁剪前必须真的 fail、不可裁项裁剪后仍必须 fail」的负例断言。
材质槽不是美术的内部细节,它直接决定 Draw Call:同一材质槽内可合批,跨槽必须拆。本节用《星屑旅店》大堂场景做一份可跑的耦合账——同槽实例按批上限合批、跨槽各算各的,并给出「家具拆成三个材质槽就超预算」的反例,S 层与 P 层结果逐位一致。
预算不是一句「注意控制面数」,而是一张按角色分级的表:主角、主要NPC、次要NPC、道具各自的面数、骨骼与材质槽上限。本节把《星屑旅店》12 个资产样本对着四档上限逐条判超限,用一份真跑的 S 层脚本和 P 层 TS 内核给出逐位一致的违例集合,并把档位锚到共享真源 visual_spec.json。
显式引用只写 refs 字段远远不够:图标会被打进图集、变体依赖基础资产、头像复用统一画框,这些都是隐式引用。本节把显式边与隐式边合起来建一张有向图,用 DFS 求强连通分量做环检测、逐边做悬空引用检测,并人为造一个环作为负例断言,证明检测器真的会失败。
资产清单不是给美术看的表格,而是给工具链吃的契约。本节把《星屑旅店》的 13 条资产样本固化成 JSON Schema 形态的字段规范,再用一份真跑的 S 层 Python 校验器和一份 P 层 TS 内核,逐字段拦下缺失字段、非法枚举、非幂次尺寸与不存在的色彩 token,并给出跨语言逐位一致的违例集合与负例断言。
命名最贵的一课不是「怎么写对」,而是「哪些词根本不能用」:讲清四张黑名单(文件系统保留名、会撞代码标识符的词、临时态词、待归一别名)与两条长度规则,落成可跑的 Python + TypeScript lint,让 nul / class / copy / img 这类词在构建期就被拦下。
名字判对了,还得放在对的目录里:讲清 kind 到目录的唯一映射、为什么目录必须纯小写(大小写混用是 URL 死链的头号来源),以及 @color/<token> 与 @asset/<id> 两条引用约束怎么和共享真源 visual_spec.json 对齐——目录错位、悬空引用、自引用都会被 lint 拦下。
把资产命名从「大家自觉」变成「机器可判」:讲清 `<前缀>_<subject>[_<变体>]_v<NN>` 这条文法,前缀、类型、变体、版本四个字段各自管什么,再用一份可跑的 Python + TypeScript 命名 lint 对同一份《星屑旅店》资产清单逐条判违例——违规命名必须真的 fail。
有了感知距离这把尺子,本节把它用到最要紧的地方:色觉异常。我们自实现 Viénot–Brettel 二色觉模拟,对 8 个 token 逐一投影成 8-bit 整数,实测等亮度红/绿在绿色盲下距离从 0.3755 塌到 0.0656,并抓住真实规格违例 danger/surface 对比度只有 31。
上一节说对比度看不见色相差,那要判断「两个颜色够不够分得开」就需要一个感知均匀的空间。本节用 OKLab/OKLCH 复算 8 个 token 的坐标与距离,实测 HSL 等间隔取色的相邻距离极差是 OKLCH 的近 4 倍,说明「取色均匀」和「看起来均匀」不是一回事。
美术在 sRGB 里取色、在引擎里混合,却很少问这两件事是否发生在同一个空间。本节用一份 sRGB 8-bit 真源复算传递函数、相对亮度与对比度,实测「琥珀与天蓝色相完全不同、对比度却一模一样」,说明对比度只由亮度决定,并给出跨语言的容差口径。
同一个 token 在五个场景里必须长得一样。本节把《星屑旅店》五个场景的 19 个元素按 key 分组,算出跨场景一致性千分比 800、抓出两处色相漂移,并用 B 层把容差阈值从 0.002 扫到 0.5,说明软告警可调而硬漂移不可糊弄,最后给出可复算的一致性检查。
色卡上的 hex 要变成代码里能引用的名字,中间要补一层分层:primitive → semantic → component。本节用《星屑旅店》的三层 token 表做引用完整性 lint、与 visual_spec.json 的同源校验,并推演改一个色卡会影响几个组件。
把「主色、辅色、强调色」从美术口头词翻译成可复算的量:用《星屑旅店》的 8 个 token 算中性明度梯度的单调性与均匀度、5 对对比度的下限,并实测琥珀与天蓝的对比度同为 69 而 OKLab 距离 0.30,说明对比度合格不等于色相有区分度。
上一节把形容词变成四个整数区间,这一节把区间升级成向量:五维、每维归一化到千分比,再用加权 L1 算出六套主题两两之间的风格距离,并用 OKLab 欧氏距离单独量色彩距离。同一份规范要能在六套主题里都成立,靠的就是这张「同源可区分」的距离矩阵。
「治愈」「硬核」是形容词,不是参数。这一节把它们落成四个可测的整数区间——明度中位数、饱和度均值、对比度、色温代理——再用同一套区间判定《星屑旅店》的六个主题包,并把判定逻辑在 Python 与 TypeScript 两侧逐位对齐,给出可复算的风格分类。
卷一交出的不是一本排好版的 PDF,而是一份可点数的清单:哪些是给人读的规范文本,哪些是机器校验的静态结构,哪些是能真跑的产物。本节用一份真跑的 S 层脚本与 P 层 TS 内核校验这份清单本身是否完整——字段齐全、kind 与 status 合法、id 唯一,且交给卷二的目标必须真实存在并已完成,缺一项就 fail。