23 KiB
TankiOffline UI 重建计划书(全站 UI)
目标:把原客户端(
module_82347大厅/车库/商店/军团/结算 UI +module_21300战斗 HUD) 还原到 Kotlin/JS 新工程,最终覆盖全站所有界面,并与真实状态 / 协议数据打通。 本文件用于对齐范围、技术栈、里程碑与验收口径。
0. 已确认决策(2026-10-25)
| 议题 | 决策 |
|---|---|
| 技术栈 | Kotlin/JS + kotlin-react + Emotion(与现工程同栈) |
| 还原精度 | 组件级还原;背景/摄像机是动态的,不做像素 diff,由人工验收,尽可能贴近 |
| 数据源 | 本地 mock 服务器(协议级 mock,稳定产出用户/物品/大厅数据) |
| 原版账号 | 有(WYT2WYT),仅用于线上获取必要信息(DOM/CSS/资源/文案),不做逐屏截图对拍 |
| 3D | 现在接 WebGL:先做 3D 资源加载器与车库预览,再逐步接 92980 渲染管线 |
| 首批屏幕 | 大厅骨架 + 车库 |
| 资源部署 | 开发用本地镜像;生产走 CDN / 反向代理 |
| 混跑策略 | 允许长期保留部分原 JS UI,按屏幕逐步替换为 Kotlin |
1. 调研结论(先纠正三个认知)
1.1 原前端不是手写 React,而是 Kotlin/JS + React + Emotion
证据:
| 证据 | 说明 |
|---|---|
module_glossary:78931 = React 18.3.1、45555 = React-DOM 18.3.1 |
运行时确实是 React |
94090 = “React 封装的内部 UI 构建工具 RBuilder” |
Kotlin 侧的 React DSL |
82347 的代码形态:Sq(d7n, "MainScreenComponentStyle", $q, h$)、this.aux([], K2n)、Eq("containerPanel", 1, …) |
这是 Kotlin/JS 编译后的 styled-component 构造,不是手写 JS |
类名如 MainScreenComponentStyle-containerPanel、RoundBigButtonComponentStyle-outerCircle |
Emotion 生成的组件样式名 |
82347 依赖 10032 / 18334 / 61860 / 87072 / 92980 / 61378 / 85196 … |
UI 直接吃状态、服务、渲染、战斗系统 |
结论:另起一个 React/TS 工程不是“更原版”,反而会丢掉 Kotlin 数据模型。 推荐在现有 Kotlin/JS 工程里加 kotlin-react + Emotion,逐屏移植;纯 React/TS 只作为备选。
1.2 原 UI 的体量与耦合
82347:5.50 MB,约 21.3 万行,覆盖大厅 / 车库 / 商店 / 军团 / 好友 / 新闻 / 设置 / 结算 / 弹窗。21300:战斗内 HUD(血条、准星、道具、计分板、聊天…)。- 大量组件直接依赖:
- 状态:
RootState的 89 个切片(已迁移 89/89); - 服务:
18334的 509 处动作派发、物品目录(已迁移ItemCatalog); - 渲染:
92980WebGL(车库 3D 预览、战斗场景); - 战斗:
87072(HUD 数据)。
- 状态:
- 因此 UI 必须分层:布局/样式可先独立还原,数据和 3D 后接。
1.3 资源已经齐了
- 镜像:
3DTank/web/play/static(1239 文件 / 71.4 MB,含 images / fonts / translations / sound / videos / textdata)。 - 已复制到:
TankiOffline/app/src/jsMain/resources/play/static,开发服务器直接以/play/static/...提供。 - 官方翻译:
/play/static/translations/zh-CN.61d6ab60.json(运行时加载,已接)。 - 可直接引用的资源 id → 路径:
3DTank/src/resources.json的resourceMap。 - 可选:
3DTank/Start-LocalAndRelay.ps1启动镜像 + 中继(抓包/真实服务器)。
2. 技术方案
2.1 推荐方案 A:Kotlin/JS + kotlin-react + Emotion(与现工程同栈)
TankiOffline/
ui/ # 新:React 组件(Kotlin)
src/jsMain/kotlin/Ui/
Theme.kt # 颜色/字体/间距 token(从原 Emotion 样式抽出)
Components/ # Button / Panel / Tabs / Dialog / ItemCard ...
Screens/ # Lobby / Garage / Shop / Battles / Quests ...
Layout/ # MainScreen / Header / Menu / Chat / Footer
app/ # 入口:Entrance → 连接 → Lobby
state/ # 已有 RootState
net/ # 已有协议
依赖:
implementation(npm("react", "18.3.1"))
implementation(npm("react-dom", "18.3.1"))
implementation(npm("@emotion/react", "11.x"))
// Kotlin 侧可用 kotlin-react / kotlin-emotion 包装,或直接 external 声明
数据流:
SessionRouter (Store) ──订阅──> UiStore (Adapter) ──props──> React 组件
ItemCatalog ───────────────────┘
Session 状态(连接/帧/日志)─────┘
优点:复用现有状态类;一套 Gradle 构建;后续可直接接 3D/战斗。 缺点:Kotlin React 组件写法与原始编译产物不完全一致,需要逐屏翻译。
2.2 备选方案 B:独立 React/TS 工程
webui/ (Vite + React + TS + Emotion)
↕ WebSocket / postMessage
TankiOffline (Kotlin/JS 客户端)
优点:前端生态成熟、UI 开发快、便于像素级还原。 缺点:状态模型要跨语言复制/序列化;构建两套;长期维护成本高。
2.3 备选方案 C:混跑原 JS 模块
直接把 module_82347 作为 external 挂到 window.__modules__,用现有 Kotlin 状态通过 bridge 驱动。
优点:保真度最高、最快看到完整原版 UI。
缺点:不是“重建”,依赖原 bundle;长期难以维护。
可作为 过渡验收(视觉基准)而不是最终形态。
2.4 保真度分层
| 级别 | 内容 | 验收 |
|---|---|---|
| L0 | 结构骨架(当前) | 能导航、无报错 |
| L1 | 官方资源 / 字体 / 布局比例 | 截图肉眼接近 |
| L2 | 像素级静态还原 | 与原版截图逐屏 diff |
| L3 | 真实数据 + 交互 | 状态变化驱动 UI |
| L4 | 3D 车库 / 战斗场景 | WebGL 管线接入 |
3. 里程碑
M0 基础设施(进行中)
- 资源镜像接入(
/play/static)。 - 登录页 1:1(EntranceView + entrance.css)。
ui模块启用 kotlin-react + Emotion,建立Theme.kt。- 协议级 mock 服务器(用户属性 / 物品目录 / 大厅列表)。
ScreenRegistry:屏幕 ID ↔ 组件(对齐原ScreenId)。UiStore:订阅SessionRouter.Store,节流重绘。- 3D 资源加载器(
.3ds/ 贴图 / 场景描述)+ 车库预览最小场景。 - 截图 / DOM 基准工具(人工验收辅助,不做像素门禁)。
M1 大厅骨架(2 个迭代)
- 顶栏:等级/昵称/GS/水晶/金币/VIP/设置/声音。
- 左侧菜单:9 个官方图标 + 文案 + 选中态。
- 底部:大号“开始战斗”按钮、聊天面板、新闻条。
- 公告/活动/每日任务浮层。
- 验收:与官方大厅截图逐项对齐(无 3D 场景时用静态背景占位)。
M2 车库(3 个迭代)
- 分类页签(12 类,来自
ItemCategory枚举)。 - 物品网格:名称/稀有度/数量/VIP/价格;数据源
ItemCatalog。 - 物品详情:属性、升级、装备、皮肤。
- 3D 预览:接 M0 的 3D 加载器,先渲染底盘/炮塔/贴图与旋转,再补光照/摄像机。
M2.5 3D / 渲染(并行)
- 3DS / 贴图 / 资源清单加载。
- 车库场景:平台、背景、坦克组装、光照、摄像机环绕。
- 与
92980渲染管线的接口对齐;最终替换为原引擎实现。
M3 商店 / 幸运礼盒(2 个迭代)
- 商店分类、卡片、折扣、支付方式、礼盒开启动画占位。
- 数据:
Shop切片 +ItemCatalog。
M4 战斗选择 / 任务 / 军团 / 好友 / 新闻(3 个迭代)
- 战斗模式卡片、战斗列表、创建战场表单。
- 任务:主线/每日/每周/星级挑战/合约。
- 军团/好友:列表、搜索、请求、成员管理。
- 新闻:列表 + 详情。
M5 设置 / 弹窗体系(2 个迭代)
- 设置 8 个页签(游戏/画面/声音/操控/账户/战斗/安全/支持)。
- 通用 Dialog / Toast / 确认框 / 购买弹窗 / 升级弹窗 / 排名弹窗。
M6 结算与 HUD(依赖 S5)
- 战斗结算、奖励、排名变化。
- 战斗 HUD(
21300):血条、道具、准星、计分板、聊天。
4. 每屏的数据契约(先定,避免返工)
| 屏幕 | 主要数据 | 现有来源 | 缺口 |
|---|---|---|---|
| Entrance | 语言/资源/连接状态 | Translations / LobbyClient |
真实登录 |
| Lobby Home | User / News / Notifications / Quests 摘要 | RootState 已迁移 | 公告、活动配置 |
| Garage | ItemCatalog / Garage 切片 / GaragePreview | 已有 | 3D 预览、装备操作 |
| Shop | Shop 切片 / ItemCatalog | 已有 | 支付流程 |
| Battles | BattlesSelect / Maps / Matchmaking | 已有 | 创建/匹配 |
| Quests | Quests / Challenges / ContractState | 已有 | 领奖链路 |
| Clans | Clan / ClanStorage / ClanChat | 已有 | 社交操作 |
| Friends | Friends 切片 | 已有 | 搜索/请求 |
| News | News 切片 | 已有 | 详情页 |
| Settings | 8 个设置切片 | 已有 | 持久化 port |
| HUD | BattleStatistics / BattleUsers / Supplies | 部分 | S5 战斗系统 |
5. 验收方式
- 视觉基准:原版客户端逐屏截图(需要可登录环境);新 UI 同分辨率截图,人工/像素 diff。
- DOM 基准:同一数据下对比关键元素的尺寸、间距、颜色 token。
- 交互基准:点击路径一致(菜单、返回、弹窗层级)。
- 数据基准:同一抓包回放后,界面显示与状态断言一致(可自动化)。
6. 风险与待决事项
| 风险 | 影响 | 对策 |
|---|---|---|
| 没有可登录账号,拿不到原版大厅截图/DOM | 无法做像素级对比 | 用测试账号 / 本地 mock 服务器 / 仅按源码还原 |
| 3D 车库与战斗场景 | 大厅“灵魂”缺失 | 先用静态背景 + 官方素材,S4 后替换 |
82347 21 万行,逐屏翻译量大 |
周期长 | 按 M1–M5 切片,先布局后逻辑 |
| 原样式是 Emotion 动态类名 | 难以直接复用 CSS | 抽 token + 按截图复写;或运行时抓取 CSS |
| 资源 71 MB 进包 | 首屏体积 | 开发用镜像;生产走 CDN/代理 |
7. 当前进度(本文件创建时)
- 登录页:1:1 完成(官方背景、logo、圆形登录按钮、健康忠告、年龄提示、ClientInfo)。
- 大厅:L0/L1 骨架(官方图标、真实翻译、物品目录、连接状态)。
- 资源:本地镜像已接入。
- 已确认:技术栈 Kotlin/React、组件级还原、本地 mock、3D 现在做、首批大厅+车库、允许混跑。
9. 原版 DOM 实测映射(2026-10-25,登录 WYT2WYT 后)
视口 1296×1006,根字号 12.96px(.ksc-37 的 max(min(1.48148vh,1vw),3px))。
所有尺寸换算:1em ≈ 12.96px。
9.1 大厅首页
| 原 DOM 类 | 位置 / 尺寸 | 含义 |
|---|---|---|
MainScreenComponentStyle-containerPanel |
0,0 1296×78 | 顶栏(6em,底边 1px 白 25%) |
UserInfoContainerStyle-blockLeftPanel |
0,0 408×78 | 等级图标 / 组队图标 / 昵称 / XP |
UserInfoContainerStyle-rankIconContainerClickable |
155,0 78×78 | 等级图标(static/images/<rank>.<hash>.webp) |
UserInfoContainerStyle-containerProgressMainScreen |
246,15 162×49 | 昵称 + XP 条 + 数值 |
UserScoreComponentStyle-blockRightPanel |
1017,0 279×78 | 两行货币(红宝石 / 水晶)+ 全屏 + 退出 |
MainScreenComponentStyle-containerForMenuGradient |
0,0 648×1006 | 左侧 50%,黑→透明 0.5 |
MainScreenComponentStyle-playButtonContainer |
57,130 284×139 | “开始战斗”,背景 videoplay.79570900.gif |
MainScreenComponentStyle-blockMainMenu |
57,283 324×645 | 菜单容器 |
PrimaryMenuItemComponentStyle-menuItemContainer |
65,283 350×58 | 菜单项:礼盒 / 任务 / 车库 / 商店 / 设置 |
PrimaryMenuItemComponentStyle-itemCommonLi |
73,290 45×45 | 图标(mask + #bfd5ff) |
PrimaryMenuItemComponentStyle-itemName |
133,293 | 2em 大写文字 |
FooterComponentStyle-footer |
0,928 648×78 | 新闻 / 聊天 / 好友 / 军团(65×65) |
MainScreenComponentStyle-gradientBlockRight |
936,0 360×1006 | 右侧渐变(27.75em,0.75,旋转 180°) |
BattlePassLobbyComponentStyle-menuBattlePass |
972,110 292×130 | 星级挑战面板(22.5em×10em,right 2.5em) |
AnnouncementHomeScreenComponentStyle-mainContainer |
971,778 293×196 | 公告卡(22.5em 宽,right/bottom 2.5em) |
ClientInfoComponentStyle-main |
0,989 1296×17 | UID / 版本 / 电池 |
9.2 车库
| 原 DOM 类 | 位置 / 尺寸 | 含义 |
|---|---|---|
BreadcrumbsComponentStyle-headerContainer |
0,0 1296×78 | 车库顶栏(返回 / 标题 / 货币 / 退出) |
BreadcrumbsComponentStyle-backButton |
0,0 78×78 | 返回 |
BreadcrumbsComponentStyle-rootTitle |
585,2 126×73 | 当前屏幕标题 |
GarageCommonStyle-garageContainer |
0,78 1296×928 | 车库主体 |
GarageCommonStyle-positionContent |
0,130 1296×876 | 内容区 |
GarageMainScreenStyle-blockParameters |
78,130 1140×685 | 中央 3D 预览 + 左右参数 |
TankParametersStyle-leftParamsContainer |
78,130 293×209 | 左上:GS + 参数 |
MountedItemsStyle-container |
920,130 298×492 | 右上:无人机 / 手榴弹 / 炮塔 / 底盘 |
MountedItemsStyle-resistanceContainer |
78,740 52×65 ×4 | 左下:防御模块 |
SuppliesComponentStyle-commonBlockSupplies |
78,862 1140×125 | 底部道具栏 |
TankPreviewComponentStyle-visible GarageComponentStyle-tankPreview |
0,0 1296×1006 | 3D 坦克画布 |
9.3 对应关系(JS → DOM)
82347里Sq(Class, "XxxComponentStyle", ...)注册的样式类,就是 DOM 上的XxxComponentStyle-*。Eq("containerPanel", 1, ...)返回的类名拼接为MainScreenComponentStyle-containerPanel。- 样式值直接写在
jq(Class).xxx = function(){ return this.<slot>.dk(this, Eq("...")) }的样式对象里; 运行时可从document.styleSheets按类名前缀抓取(已用于本表)。 - 组件层级:
MainScreen→Header/PrimaryMenu/Footer/BattlePass/Announcement; 车库:GarageCommon→TankParameters/MountedItems/Supplies/TankPreview。
9.4 当前实现状态
- 大厅首页已按上表重建(6em 顶栏、21.875em Play、27em 菜单、5em 底栏、22.5em 右栏)。
- 车库正在按 9.2 重建:左侧参数 / 中央 3D / 右侧已装配件 / 底部道具栏; 物品选择列表作为抽屉保留,后续替换为原版的分类轮盘。
- Kotlin/React 工具链接通(kotlin-react / kotlin-react-dom / kotlin-emotion,React 19.1)。
- 物品目录 fixture:
SessionCheck从抓包导出resources/fixtures/catalog.json(1399 物品)。 - 车库第一版 React 界面:分类页签(12 类)、搜索、物品网格(120 张卡片)、右侧详情位。
- 车库按 9.2 的原版布局重建 + 3D 预览加载器。
- 协议级 mock 服务器(用户 / 大厅列表 / 任务)。
- 大厅其余屏幕迁移到 React。
10. 原版 UI 还原方法(已验证,2026-10-26 设置页)
这一节记录的是实际跑通的方法。后续所有页面都按这个流程做,不再先写通用样式再“看起来像”。
10.1 原则
- 不自己设计 UI:布局、尺寸、颜色、类名、DOM 层级都以混淆版源码/原版 DOM 为唯一来源。
- 先找定义,再做映射:找不到原版定义就标注“未展开”,不靠截图猜。
- 能用原版资源就不画近似:图标、勾、knob、箭头、背景图优先用
play/static/images里的原版资源。 - 文案走 i18n:使用
Translations.T("lobby...."),不硬编码中文。 - 颜色走配色表:使用
Palette.kt(来源C9i),不手写近似色。 - 每页完成后删除旧近似样式和死代码,避免两套样式并存。
10.2 定位组件定义
- 在
module_82347.js搜索:找到样式类。Sq(Class, "XxxComponentStyle", ...) - 看类构造器:
找到字段与对应
this.xxx_1 = this.aux([], styleFn)styleFn。 - 看访问器:
确认字段名和生成的语义类名。
jq(Class).accessor = function () { ... Eq("fieldName", ...) ... } - 找渲染函数/组件:
jq(Component).tap/render,确认 DOM 层级和子组件。 - 把类名、字段、行号记录到对应的
*StyleTable.md。
示例(设置页):
| 组件 | 类 / 函数 | 位置 |
|---|---|---|
SettingsComponentStyle |
kNi |
module_82347.js:89525 |
SettingsMenuComponentStyle |
EMi |
90329 |
SettingsButtonsComponentStyle |
UPi |
89326 |
DropDownStyle |
J7t |
34073 |
ContextMenuStyle |
u7t |
33638 |
CheckBoxComponentStyle |
QBi |
92742 |
CheckBoxStyle |
Z0t |
33272 |
InputRangeComponentStyle |
EUi |
92980 |
10.3 提取真实 CSS
- 在无头页面加载
module_37036(Kotlin 运行时)+module_82347。 - 实现最小 webpack require:
i(id)、i.p、i.d、i.r、i.n、i.o、i.hmd。 - patch
module_37036的ld,捕获Sq(Class, Name)注册表。 - 实例化目标样式类,遍历
kuv_1.a1_1,执行每个entry.duv_1[0](recorder)。 - recorder 记录
rpf/gp8/jp8/lp7/qp7,输出 base/nested CSS。 - 动态方法直接调用,例如:
d1mg(recorder, important):下拉选项m1md/n1md:复选框 / Toggle SwitchhUi.tap:滑杆进度渐变
- 提取结果写入
*StyleTable.md,作为实现依据。
10.4 还原真实 DOM 和类名
-
按原版 DOM 写结构,不替换成自创的
button/div。 -
保留语义类名:
InputRangeComponentStyle-blockSoundVolumeInputRangeComponentStyle-soundVolumeInputRangeComponentStyle-rangeSettingsComponentStyle-sliderCheckBoxComponentStyle-oneSettingCheckBoxStyle-checkboxDropDownStyle/ContextMenuStyle相关类
-
保留原版
ksc-*标记用于核对,例如ksc-56(百分比)、ksc-57(滑杆)、ksc-62(Switch)、ksc-63(标签容器)。 -
原版 DOM 示例:
滑杆:
<div class="InputRangeComponentStyle-blockSoundVolume SettingsComponentStyle-slider"> <p>主音量<span class="ksc-56">(80%)</span></p> <div class="InputRangeComponentStyle-soundVolume"> <input class="ksc-57 InputRangeComponentStyle-range" type="range" ...> </div> </div>Switch:
<div class="ksc-46"> <div class="CheckBoxComponentStyle-oneSetting"> <div class="CheckBoxStyle-checkbox"> <label><input class="ksc-47" type="checkbox"><span class="ksc-62 -displayFlex"></span></label> </div> <div class="ksc-63 -flexStartAlignCenter"><label>显示帧数和延迟</label></div> </div> </div>
10.5 提取原版资源
- 资源模块通常长这样:
67116:(t,n,i)=>{ t.exports = i.p + "static/images/correct.afad1b22.svg" } - 通过 IIFE 参数表与调用参数对齐,找到变量对应的 module id:
Vn→ module67116→correct.afad1b22.svg(Switch 开)Kn→ module13357→incorrectCheck.1918884a.svg(Switch 关)$n→ module74120→checkMark.fb44274a.svg(方形复选框勾)
- 资源放到
/play/static/images/,直接引用,不再用 CSS 画近似图形。
10.6 配色 / i18n / 尺寸
- 颜色:
C9i/E9i()主题对象 →Palette.kt→ColorPalette.md。 - 文案:
Translations.T("lobby...."),语言切换走Translations.LoadLocale。 - 尺寸:直接使用 style 函数里的 em 值;
1em ≈ 12.96px(1296×1006)。 - 细节:百分比位置、颜色、间距、圆角都按原 DOM / style 函数,不凭感觉调。
10.7 验收
- 无头探针打开页面,记录 DOM、rect、computed style、截图。
- 对比项:
- 语义类名 /
ksc-*标记是否存在 - 尺寸、间距、圆角、边框
- 颜色(背景、文字、强调色、进度、Switch)
- 交互(下拉展开/滚动、滑杆拖动、Switch 切换)
- 语义类名 /
- 与
*StyleTable.md对齐;不一致就回到 10.2 重新提取。 - 完成后删除旧近似样式、未使用函数、死代码。
10.8 设置页验证记录
设置页已按本方法完成:
- HEAD 复用主页顶栏,只替换 VIP 为退出键。
- 菜单顺序:游戏显示 / 战斗 / 画面 / 音效 / 操控 / 账户 / 安全。
- 颜色全部走
Palette。 - 文案全部走 i18n。
- 滑杆:原版 DOM +
InputRangeComponentStyle+ 进度渐变。 - Switch:原版
CheckBoxComponentStyle-oneSetting+ksc-62+ 原版圆形 knob。 - 下拉:
DropDownStyle+ContextMenuStyle+ 固定选项高度 + 按需滚动。
详细映射见:
3DTank/docs/SettingsStyleTable.md第 6/7/8 节3DTank/docs/ColorPalette.md
11. 桩代码标记规范
目的:不允许“看起来像原版”的自创组件混进最终 UI。找不到原版定义时,只能留明确标记的桩。
11.1 强制标记
任何非原版实现、占位、模拟数据、临时组件必须同时具备:
- 源码注释:
// STUB: 原版 <组件名/样式类> 尚未展开 - DOM 标记:
Ui("stub.<screen>.<part>") - 文档记录:在
UiTranslationStatus.md的“待翻译/未展开”中列出。
11.2 禁止事项
- 禁止用自创的
button/div/ 卡片替代原版组件而不标记。 - 禁止用近似色、近似尺寸冒充原版值。
- 禁止把 mock 数据写成真实数据;mock 必须标
STUB或offline demo。 - 禁止在未找到原版定义时直接写“完成”。
11.3 删除规则
- 原版定义补齐后,删除对应
STUB注释、data-ui="stub.*"和文档条目。 - 删除旧近似样式时,同步删除未使用的 style 函数/常量,避免两套实现并存。
11.4 HEAD 验证记录
HEAD 已按第 10 节方法重写:
- 样式类:
MainScreenComponentStyle-containerPanel/UserInfoContainerStyle-blockLeftPanel/UserScoreComponentStyle-blockRightPanel - Logo:
iconTankiOnline.2a9c236f.svg(192×60px) - 等级块:
5.9375em × 6em,仅右边框 - XP 容器:
.875em高,margin-top:.55em,opacity:.8 - XP 条:
12.5em × .25em,绿色 50% 背景 - 货币列:
9.2em宽,margin-right:2em - VIP 块(
x6n.tap):6em × 6em,box-shadow:1px 0 0 0 rgba(255,255,255,.25),未开通 VIP 时金红径向渐变,:hover5% 白;图标iconButtonPremium.bc17a592.svg,2em × 2em - 组队块(
L4.tap):5.9375em × 6em,右边框,:hover5% 白;2 人组commonUserIconsBlockGroup3.25em × 1.9em+ 两个q4图标1.5em(groupUser.67c9ec61.svg,空位色rgba(191,212,255,.5)) - 全屏块(
uKt):6em × 6em,左右各 1px 白 25% 边框,:hover5% 白 + 图标变白;图标fullscreen.0b4547f5.svg,1.5em - 退出块(
BreadcrumbsComponentStyle-logout):6em × 6em,无边框,:hover5% 白 + 图标变白;图标iconBack.62869951.svg,1.5em - 货币列(
nti):display:flex; flex-direction:column; position:relative;红宝石/水晶行按l1qd/n1qd,min-width:7.9375em、height:3em、padding-right:.75em、红宝石行border-bottom;不再套用coinsContainer的9.2em/margin-right:2em/ 右边框 - 实测 rect:左块
408.58×77.75、VIP77.75×77.75、组队/等级77.94×77.75、用户162×48.59、货币列102.86×77.75(x=1035.64)、右块从1035.64开始。