# 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 染色管线。