# UI 设计及图标素材使用共识
来源:[执行-批次1:品牌/图标替换](issues/14-exec-batch1-brand-icons.md) 四轮执行与维护者反馈的沉淀。
生效范围:城市生命线驾驶舱 `/cockpit` 的全部 2D UI 图标与切图素材。
**性质:本项目图标素材的单一事实来源(single source of truth)。后续任何图标/切图的引入、替换、改名,按本文执行,不再逐轮口头约定。**
---
## 1. 目录边界(谁放哪儿)
| 目录 | 内容 | 是否进产物 |
| --- | --- | --- |
| `public/cockpit/assets/icons/` | **运行时图标**(扁平,全部英文名) | ✅ |
| `public/cockpit/assets/icons/panel/` | 面板小标题图标(已统一染主蓝) | ✅ |
| `public/cockpit/assets/icons/status/` | 状态标识图标(已按语义色染色) | ✅ |
| `.scratch/lanhu-cockpit-asset-replacement/design-archive-v2/` | 蓝湖切图**设计归档**(原文件名+hash 索引) | ❌ 不部署 |
| `E:\&项目模型文件等\UI图片\` | 维护者的设计源目录(Texture/Icon、PSD 等) | ❌ 本机外部 |
规则:
- **运行时目录只进「已确认消费」的素材**——下载/导入后先在归档区观察,登记语义并找到落点后才入 `public/cockpit/assets/icons/`。没有消费点的图不进运行时(无死资源是验收项)。
- **设计归档永不删除、永不改名**——它是追溯来源的锚点(manifest `source.archive` 指向它)。
- 禁止把素材放进 `public/plugins/**`(TvT 插件体系),驾驶舱不依赖它。
## 2. 命名规范(英文 + 语义)
**运行时文件一律英文 kebab-case,语义自明。** 中文命名只在设计源/归档区存在。
```
<语义>[-<变体>].png 扁平图标 例:pipeline.png / alert.png / brand-title.png
panel-<语义>.png 面板小标题 例:panel-monitoring.png
status-<状态>.png 状态标识 例:status-alarm.png / status-workOrder.png
industry-<行业>.png 行业图标 例:industry-gas.png / industry-drainage.png
<对象>点.png → <对象>-point.png 位置符号类(批次 3 用) 例:water-point.png
```
- 禁止纯序号名(`1.png`、`未命名-3.png`)——批次 1 两次语义错配的根源就是无语义命名。
- 多词用 `-` 不用 `_`;同一图不同变体加数字后缀(`brand-glow-1/2/3.png`)。
- **改名必须同步 manifest**:manifest 记录 `path` + 内容 `hash`,单改文件名 = 运行时 404。同步方式:改 `research/build-manifest.mjs` 的 `ICON_MAP` → 重跑 → `check-manifest.mjs` 验证。
## 3. Manifest(唯一权威入口)
- **组件只消费语义 key**(``),禁止在组件里拼物理路径。全仓只允许 `domain/runtimeAssets.js` 一处引用 `assets/` 路径。
- 一个文件一个 key;多消费方共享同一 key(如 `icon.panel.monitoring` 同时服务运行监测/运行信息/监测概览三面板)。
- 条目字段:`key / path / source(来源) / format / dimensions / pixelRatio / renderMode / version / hash / status / appliesTo / fallbackKey / core`。
- `status` 四值:`formal`(正式)/ `temporary`(临时,必须同时在票 06 缺口清单登记)/ `derived` / `fallback`。**验收不得把 temporary 当 formal 通过。**
- `renderMode` 二值:`image`(彩色位图,`
`)/ `mask`(单色 SVG,CSS mask + currentColor)。新增 SVG 单色图标走 mask,彩色 PNG 走 image。
- **新增/替换图标的固定流程**:
1. 素材放入 `icons/`(英文名);
2. 在 `research/build-manifest.mjs` 的 `ICON_MAP` 加一行;
3. `node research/build-manifest.mjs`(重算 hash、保留 fonts 块);
4. `domain/icons.js` 注册表加语义名映射;
5. `node research/check-manifest.mjs`(文件可达 + 拒绝 HTML 兜底 + hash 一致);
6. `node research/cross-check-icons.mjs`(四处交叉引用一致)。
- **fonts 块共存纪律**:`manifest.json` 顶层 `fonts`(授权门禁)归批次 4 所有;`build-manifest.mjs` 通过 `PRESERVED_TOP_LEVEL` 保留非 icon 顶层键,**任何脚本不得整体重写 manifest 而不带该保留逻辑**。
## 4. 风格统一(面板/状态类图标的视觉规范)
### 4.1 源图选用
- 统一从 `E:\&项目模型文件等\UI图片\Texture\Icon` 取图,按维护者规定的优先级:
- **Pipe\*** = 主要(实心体,语义强);
- **I\*** = 次要(线稿渐变,风格轻);
- **Q\*** = 补充(I 系列缺语义时的补充)。
- 面板小标题、状态标识等「小尺寸高频」位置用 I/Q 线稿系(小尺寸下实心体糊成一团)。
### 4.2 染色(去色 + 语义色)
**总原则(2026-10-12 维护者修订):给予的图标素材一律去色后再使用。** 颜色语义只由承载状态的层表达——两层都用颜色会同色融合导致不可辨(场景点位设备图标为例:标记点已用颜色表达状态,内层行业图标再彩色就什么都看不清)。
按落点分三档:
| 落点 | 去色后染什么 |
| --- | --- |
| 面板小标题 | 整体染主蓝 `#01abea`(--cyan) |
| 状态标识 | 按状态染语义色(下表) |
| **位置符号内层**(点位/设备里的行业图标) | **蓝白渐变重染**(亮部白、暗部主蓝),禁止行业彩色原稿 |
状态标识语义色(色值唯一来自 `tokens.css`):
| 用途 | 色值 | token |
| --- | --- | --- |
| 状态·报警 | `#ff3b52` | `--lv1` |
| 状态·预警 | `#ffb020` | `--lv2` |
| 状态·工单/进行中 | `#01abea` | `--lv3` |
| 状态·正常 | `#27d17a` | `--lv4` |
| 状态·离线/中性系 | `#5680b0` | `--neutral` |
- **禁止在组件里散写图标颜色**;新语义色先加 token 再用。
- 染色管线:面板/状态用 `research/tint-panel-icons.mjs`、`tint-status-icons.mjs`;位置符号内层用 `services/markerAssets.js` 的 `recolorInner`(运行时逐像素)。改色板/换图重跑即可。
- 直接可用的彩色切图(如品牌主标题、行业筛选按钮图标)不经染色——它们是设计定稿色,但**仍须走 manifest**。
- **位置符号附加项**(批次 3 走查定稿):整枚符号加 2px 白描边(深色底图更立体);合成输出**裁剪到母版 bbox**(512² 方图两侧全透明,不裁剪塞非方 billboard 会拉伸变形)。
## 5. 接缝与可访问性(代码侧纪律)
- **接缝不变**:`domain/icons.js` 注册表(语义名 → manifest key)是唯一的消费映射;`CockpitIcon` 组件按 `renderMode` 二选一渲染。新落点 = 加注册表映射 + 组件用 ``,不新发明引用方式。
- **图标一律 `aria-hidden`**(`CockpitIcon` 模板已内置):图标不参与按钮/标题的可访问命名,读屏读到的仍是纯文字。走查断言 `textContent` 不受图标影响。
- **视觉信息不进领域契约**:图标映射表(`PANEL_ICONS` / `INDUSTRY_ICONS` / `legendVisuals().icon`)单独成表或作为附加字段,**不改动** `INDUSTRIES` 数组结构、`panelId`、`data-panel-id`、`data-industry`、`aria-pressed/expanded` 等既有断言面。
- **未知名不抛错**:注册表查不到 → 渲染为空。缺失图标不打断骨架渲染(既有不变量)。
## 6. 已锁定的语义映射(不得随意变更)
| 语义 | 图标 | 备注 |
| --- | --- | --- |
| 管线图层 | `pipeline.png`(Pipe管网设施) | 维护者指派 |
| 监测点 | `monitoring.png`(Pipe预警处置) | 维护者指派 |
| 事件定位 | `emergency-event.png`(Pipe应急指挥) | 维护者指派 |
| 应急资源 | `resource-asset.png`(Q图标规模种类) | 维护者指派 |
| 窨井/井盖 | `manhole.png`(紫色网格球) | **此图形专指井盖**,不得移作他用 |
| 燃气/供水/排水 | 火焰/水滴/水波 | 行业筛选 |
| 状态八桶 | `status-*.png` | 见 §4.2 色表 |
变更语义映射须维护者确认并更新本表。
## 7. 尺寸基准
| 落点 | 图标 | 说明 |
| --- | --- | --- |
| 面板小标题 | 17u | 配 15.5u 标题字 |
| 行业筛选按钮 | 14u | 配 11.5u chip 字 |
| 地图状态行 | 14u | 与 StatusTag 同行 |
| 无地图位置浮块 | 14u | — |
| 地图摘要 chip | 14u | inline-flex 保证图文同行 |
| 品牌位 | 高随顶栏(52u)等比 | `主标题.png` 自带文字,HTML 标题 sr-only |
| **地图位置符号** | **宽 27(点)/ 21(设备)**,高按母版比例 1.257 | 批次 3;走查反馈放大 50%(原 18/14);billboard 尖端锚定,标签在图标上方(间距 2px)、限宽 = 图标宽 × 1.1 |
字号统一走 token(`--fs-caption/body/title/heading`),新组件禁用裸像素字号(存量已清理到 ≤12u 一档)。
## 7.1 位置符号标签规范(批次 3 走查定稿)
- **贴近**:标签 `pixelOffset = -(图标高 + 2px)`——BOTTOM 锚定下从尖端向上画,标签贴着图标上沿(旧中心锚定的 -13 已废)。
- **限宽**:最宽 = 图标宽 × 1.1(左右各超 5%);超宽按估算字宽截断加 `…`(`mapTextLabel` 的 `maxWidthPx`)。
- 偏移与限宽都由合成计划层(`markerPlan.js`)产出(`labelOffsetY` / `labelMaxWidth`),消费方不自己算。
## 8. 已知边界与后续
- `icon.blank`(空面板占位)仍是 `temporary`——设计稿无对应物,缺口在票 06 清单。
- **批次 3(位置符号)素材已备齐**:`water-point/drainage-point/gas-point/manhole-point.png`(246×114)+ 备用目录的 `T_MarkPoint_White/WhiteFull` 白母版。接入按[规格 10](issues/10-point-device-marker-spec.md) 的合成计划层,不适用本文的「直接引用」流程(需先过 token 着色批次 2)。
- 装饰类素材(`brand-glow-*`、面板四角、选择框背景)归批次 5,暂未消费。
- `Texture/Icon` 中约 90 张 I/Q 系列未启用(水质/气体/能耗/气象等),批次 2 KPI 配图可直接复用 §4.2 染色管线。