243 lines
16 KiB
Markdown
243 lines
16 KiB
Markdown
# M52 Shared UI Rules
|
||
|
||
这是当前 Q 版日系手绘方向的运行时 UI 规则。页面可以有不同构图,但不能
|
||
改变下面的材质、层级和伸缩语法。
|
||
|
||
## 设计画布与伸缩
|
||
|
||
- 运行时背景使用 `aspect-cover` 铺满视口,允许裁切,不允许压扁或拉长。
|
||
- 交互层使用居中的 16:9 设计画布;宽屏增加两侧世界空间,窄屏在上下留
|
||
安全区,画布本身不变形。
|
||
- 设计画布内部先建立安全边距、列数和槽间距,再放置页面组件。等宽操作行
|
||
必须由共享网格计算,不允许页面手写一组近似归一化坐标。
|
||
- 参考版式的稳定性来自“同一画布、同一网格、同一组件槽位”的组合;固定画布
|
||
只能解决缩放漂移,不能替代网格和内容槽合同。Aetherbound 采用这条原则,
|
||
但保留本项目自己的日式手绘材质和页面构图。
|
||
- 静态主图若已经包含按钮外框、图标或标签底板,运行时只能挂载文字槽和
|
||
透明命中区;不得在同一位置再画一套按钮 chrome。动态状态需要视觉变化时,
|
||
先为主图准备独立状态层,再接入运行时。
|
||
- 图标、头像、纹章使用保持比例的固定槽位,不使用九宫格。
|
||
- 木牌、羊皮纸、名册、资源徽章使用可拉伸的外框;圆角、内边距、角钉和
|
||
文字槽由组件提供,内部图标和文字保持原尺寸。
|
||
- 所有点击区域至少 48px 高;可见材质可以比逻辑点击区域更小,但文字和
|
||
图标必须对齐可见槽位。
|
||
|
||
## 组件语法
|
||
|
||
`runtime/ui/shared/market_chrome.gd` 是当前共享材质原型,后续应迁移到
|
||
统一的 `UIFactory` / token 层,而不是页面自行创建新的边框。
|
||
|
||
| 组件 | 视觉职责 | 动态内容 |
|
||
| --- | --- | --- |
|
||
| `title` | 米白纸牌、青绿色布带、黄铜角钉、柔和投影 | 页面名、阶段名 |
|
||
| `resource` | 小型纸徽章、左右角钉 | 队伍、金币、数量 |
|
||
| `card` | 悬挂绳、羊皮纸、职业彩带、特质印章、价格条 | 头像、姓名、职业、特质、价格、状态 |
|
||
| `ledger` | 暖色冒险者名册、头像槽、单一行动码头 | 候选详情、说明、价格、主动作 |
|
||
| `wood_button` | 棕木牌、底部厚度、黄铜角钉 | 返回、离开、导航动作 |
|
||
| `ledger_action` | 青绿色操作牌、内描边、黄铜角钉 | 查看详情、确认 |
|
||
| `selection_ring`(M66) | 半透明金色场 + 亮金描边环,共享 `PageChrome` 变体 | 队伍线成员选中、任何肖像槽选中 |
|
||
| `Tokens.seal_style(color)`(M66) | 彩色小徽记:页面给语义色,边框/圆角/线宽共享 | 风险事实图标、风险身份标记 |
|
||
| `Tokens.hit_area_style(state)`(M66) | 透明命中反馈:normal 微海军蓝、hover 金、pressed/focus 天蓝 | 纸质卡片的悬停/按压/焦点反馈 |
|
||
| `Tokens.font_size("caption")` = 8(M68 收口) | 窄卡面(市场招募卡姓名/特质芯片)的合法降档字号;宽槽位仍用 `micro` | 招募卡姓名、特质芯片 |
|
||
| 卡内模块的鼠标过滤(M76-C) | 卡片本身是 Button 时,卡内所有模块根节点必须 `mouse_filter = IGNORE`(含 identity/trait/cost/profession/portrait/guild_header)。示例缺陷:`IdentityModule` 默认 STOP 吃掉点击 → 新开局的招募卡完全点不动 | 卡片类视图(market 卡/详情栏/公会卡)|
|
||
| 运行时音频接线(M76-C) | 页面进入 = `_audio_enter(page, family)`(page_open + 音乐族);玩家提交动作 = `_audio_sfx("事件名")`(合同 §8 事件名)+ 动作函数首行;服务在 shell 宿主节点上(页面重建会清空 shell 子节点)| entry shell 全页 |
|
||
| 停靠行边界(M75) | 运行时自绘的命令按钮必须对齐页面自身栅格(左/右线与同页其他元素共享),同排同高(±2px)同基线(±2px);贴附绘制美术角牌/底带的按钮可跟随美术,但必须确认美术确有该牌面 | market 探针断言 `ABG_M52_MARKET_DOCK_BOUNDS_OK`(back 57..268 / return 1049..1267)|
|
||
| 命令按钮尺度(M74) | 所有玩家可见命令按钮用 `UITokens.command_height/size`:primary 52 / 其余 48;实拍容差 ±8px(缩放/边距)。页脚条=牌面内的 ~59px 行,而非大板。卡片与大命中区不受此限;触控目标 ≥48×48 | 所有页面实渲染审计(market/guild/party/risk/contract/result/roster)|
|
||
| 130% 文本排版(M73) | 无障碍放大档下:卡片/详情栏把头像高度让给文字行(不缩字号);成本条的图标/可用性/金额三列重分;页脚与徽章把图标列让给标签;区块标题允许两行。所有槽位保留 ≥6% 余量(曾因 0.4px 差裁掉一个汉字) | 所有现行页面 × `text_scale=1.3`;探针 1.0+1.3 双档严格覆盖 |
|
||
| 市场卡状态徽记(M60-I03 / M72) | 已招募候选卡保留在卡列但必须明示:顶部丝带位换共享 `card` 材质的状态牌("已招募/HIRED")+ 整卡 `INK` 16% 降调;卡片仍可点开查看(inspect-only) | Market 招募卡;同类"已购/已用"状态可复用 |
|
||
| `Tokens.COLOR_SUCCESS`(M67) | 羊皮纸上的成功/存活墨绿 `#3d7449`(深于旧深色底用的亮绿) | 结果存活、恢复承诺、无击倒状态、风险页正向后 |
|
||
|
||
## 资产九宫格材质(M57)
|
||
|
||
`runtime/ui/shared/asset_chrome.gd` 是运行时共享材质工厂,供首屏页面复用,
|
||
不允许页面自行创建同类边框。
|
||
|
||
| 组件 | 用途 | 规则 |
|
||
| --- | --- | --- |
|
||
| `rail()` | 顶栏、底栏等整幅宽木牌 | `name_plate` 九宫格;左右装饰角是固定角块,中间只拉伸素面 |
|
||
| `paper()` | 摘要、警告、状态羊皮纸面板 | `parchment_panel` 九宫格;木框与内斜面作为角/边,中心只拉伸纸面 |
|
||
| `market()` | 小控件(名牌、命令底板) | 直接使用 `market_chrome.gd` 的可缩放矢量材质,避免把装饰像素拉成条带 |
|
||
|
||
规则:
|
||
|
||
- 九宫格边距必须覆盖素材的装饰环(水平与垂直可不同);边距过小会把角部
|
||
纹样拉成横条,属于禁用状态。
|
||
- 小尺寸控件(高度低于装饰环两倍)不得使用装饰型九宫格;改用 `market()`
|
||
的可缩放材质。
|
||
- 文字一律引擎渲染,颜色使用纸面深墨或深底浅金,禁止中灰压在花色背景上。
|
||
- 新增材质必须先记录在本文件,再被第二个页面复用。
|
||
|
||
### M57 逐区域手绘材质(`page_chrome.gd`)
|
||
|
||
一个通用牌匾套所有区域属于禁用做法。`runtime/ui/shared/page_chrome.gd`
|
||
按区域提供手绘材质,全部走"按比例九宫格"(角与边按自身比例缩放,中段拉伸),
|
||
因此在 760/844/1280 各视口下边框粗细一致。
|
||
|
||
| 变体 | 源素材 | 尺寸 | 边距(x/y 比例) | 用途与状态 |
|
||
| --- | --- | --- | --- | --- |
|
||
| `command_plate` | `ui_m57_chrome/command_plate_{secondary,primary,disabled}.png` | 440x160(2.75:1) | 0.062 / 0.235 | 唯一可点材质;绿=主动作、米=次要、灰=禁用 |
|
||
| `header_band` | `ui_m57_chrome/panel_parchment.png` | 840x140(6:1) | 0.055 / 0.15 | 页面顶栏;分格线由引擎绘制 |
|
||
| `card` | `ui_m57_chrome/panel_parchment.png` | 同上 | 同上 | 警告条、状态卡、摘要卡等信息面 |
|
||
| `utility_plate` | `ui_m57_chrome/command_plate_utility.png` | 158x112(1.41:1) | 0.115 / 0.15 | 顶栏设置等方形工具按钮 |
|
||
| `dock_band` | `ui_m57_chrome/dock_rail.png` | 1456x104(14:1) | 0.022 / 0.20 | 底部命令带,命令牌落于其上 |
|
||
| `progress` | 共享绘制(轨道+进度填充) | 模块内比例 | `value` 由 `configure`/`set_progress` 传入 | 进度条;禁止页面自绘或自带 `StyleBoxFlat` 填充 |
|
||
| `warning_icon` | `ui_m57_chrome/badge_{warning,notice,info}.png` | 43x44 | 固定方块 | 严重度色对:红=阻断、琥珀=提示、青=信息,标记由引擎绘制 |
|
||
| `title_plaque` | `ui_m52_market/v2/title_plaque.png` | 984x560(1.76:1) | 24/16 源像素 | Market 标题银牌;文字槽必须落进实测开口 |
|
||
|
||
**标题银牌开口契约(实测量得,2026-09-13)**:源图 984×560,羊皮纸开口在
|
||
rows 225–425 / cols 199–830;经九宫格拉伸后在模块坐标里开口为
|
||
x 0.221–0.821、y 0.421–0.706(1280 画布上 y 79–116)。开口是**卡图什椭圆**,
|
||
下半部收窄,所以文字要排在纵向中带,排版后必须**实测墨迹**:标题墨迹
|
||
y 81–95、副题墨迹 y 100–111,均在开口内且互不重叠。当前槽位:
|
||
标题 (0.26, 0.378, 0.52, 0.210) 字号 `10 × text_scale`;副题
|
||
(0.28, 0.557, 0.48, 0.132) 字号 `7 × text_scale`。槽位 y 必须按
|
||
"目标墨迹 y − 0.08×字号"反推,不能直接把槽位中心对到开口中心。
|
||
|
||
规则:
|
||
|
||
- 材质分工固定:**木牌=可交互**,**羊皮纸=信息**,两者不得互换或混用。
|
||
- 命令牌的文字与图标槽位必须落在牌"面"内(左右 6%、上下保留边框后居中),
|
||
不得压到木框。
|
||
- 警告严重度必须与数据一致:生产数据 `severity` 为
|
||
`["warning","notice","info"]`(`entry_shell._readiness_warning_facts`);
|
||
视图在缺省时按行序回退到同一序列,禁止三行同色。
|
||
- 顶栏文字必须落在带面内:首列与末列按 `PANEL_EDGE_X * 带宽` 加内缩,
|
||
不允许文字压在角部支架或金线上。
|
||
- 同一区域不得再叠加第二层自绘边框、徽章或警示图标。
|
||
- 全部材质启用 mipmap(`.import` 中 `mipmaps/generate=true`),否则宽高比
|
||
差异大的区域在缩小时会出现锯齿状边缘。
|
||
|
||
## 失败教训与防复发机制(2026-09-13,M58-C)
|
||
|
||
Owner 在 M58-C 验收中连续指出三个同类缺陷(银牌文字落框、卡图什椭圆开口、
|
||
右上徽章文字压图标),根因不是“不够仔细”,而是流程缺口。以下记录为
|
||
可复用规则,接入任何承载文字的新组件前必须逐条对照。
|
||
|
||
**三类根因(必须避免)**
|
||
|
||
1. **算而不量**:用九宫格拉伸公式推算开口位置,并假设开口是矩形。异形开口
|
||
(卡图什/椭圆/收窄)必须量渲染结果。正确顺序是:量源图开口 →
|
||
定**目标墨迹带** → 反推槽位(`槽位 y = 目标墨迹 y − 0.08 × 字号`)→
|
||
渲染后**实测墨迹**复核。
|
||
2. **固定 px 与比例混用**:同一组件内一侧用写死像素(如文字内缩 36px)、
|
||
另一侧用比例锚点(图标 0.14–0.32),缩放/换语言必然重叠。文字槽一律
|
||
锚在兄弟图标边界之外(如图标 0.08–0.24 → 文字 0.26–0.96),
|
||
禁止绝对内缩。
|
||
3. **验证尺度错 + 无最长文案 fixture**:整页 1:1 看不清 4–6px 的压字或
|
||
截断;fixture 不含线上最长字符串时,英文(如 `Last Witness`)会先被
|
||
省略。每个槽位都必须有最长线上文案的中英用例。
|
||
|
||
**四条机制(后续执行)**
|
||
|
||
- **契约前置**:组件接入页面前,先在本文档声明源素材、内尺寸、九宫格
|
||
边距比例、**实测开口/面边界**、文字/图标槽、最长文案与对比度。
|
||
- **机器墨迹检查(建议加入探针)**:遍历承载文字的节点,断言墨迹盒
|
||
(`Font.get_string_size`)不与兄弟图标相交、不越出所属材质的“面”、
|
||
且不超槽宽;违反即 fail,不允许只靠肉眼。
|
||
- **最长文案 fixture**:每个槽位放线上最长中英字符串,并断言
|
||
“文本宽 ≤ 槽宽”。
|
||
- **量测证据随交付**:组件交接除整页图外,必须附放大裁切 + 数字
|
||
(墨迹带、槽宽/文本宽、对比度);整页图不作为唯一依据。
|
||
|
||
**内框规则(2026-09-13,M59)**:标签槽必须等于材质的**可见内框**
|
||
(端帽、饰边、铆钉之外),不能锚在模块整幅。已实测:名牌文字 0.14–0.86、
|
||
特性缎带 0.15–0.85;账本成本行状态 0.19–0.56 / 金额 0.58–1.0;账本头
|
||
0.08–0.92。违反时端帽会盖住首尾字,而"文字宽度 ≤ 标签矩形"的检查测不到。
|
||
Market 视觉探针现已内置 `runtime/tools/ui_ink_check.gd`(标签槽宽/行高、
|
||
标签—图标相交、标签—模块包含)+ 最长线上文案 fixture,见 `M59_PROBE_INK_CHECKS.md`。
|
||
|
||
**本次已落地的测量契约**:标题银牌开口(见上表 `title_plaque` 行)、
|
||
资源徽章图标/文字分带(0.08–0.24 / 0.26–0.96)、账本上下文行槽宽、
|
||
卡片特性缎带槽(0.06–0.94 放置、0.08–0.92 文字)。
|
||
|
||
## 信息预算
|
||
|
||
- 每页一个主动作;首屏只放 2–3 个核心事实。
|
||
- 标题、资源、对象、下一步动作按这个顺序建立层级。
|
||
- 调试 hash、内部 ID、服务状态不得出现在玩家可见层。
|
||
- 中文正文使用共享字体和固定字号;长文案优先换行,其次省略,不能越过
|
||
容器边界。
|
||
- 禁止“纯文本按钮”。任何可点击文案必须有材质、图标或明确的选中/禁用
|
||
状态。
|
||
|
||
## 页面迁移顺序
|
||
|
||
1. 先把页面分成 `Entry Shell / Selection / Formation / Battle / Outcome`。
|
||
2. 选择一个主材质组件,不在页面内叠第二套同类边框。
|
||
3. 先做静态层,再放运行时文字、数值和透明命中区。
|
||
4. 在 760×360、844×390、1280×720 以及中英文截图中检查:裁切、文字槽、
|
||
主动作、选中态、禁用态和无重复框。
|
||
5. 只有截图和试玩都通过后,才把该组件扩展到下一页。
|
||
|
||
## Market 模块边界(M52-B)
|
||
|
||
Market 不是一张平面图,而是下面这棵组合树;每个叶子模块拥有自己的
|
||
文字槽、裁切边界和响应式布局,页面只负责排列模块与转发 intent:
|
||
|
||
```text
|
||
M52MarketDesignPage
|
||
├─ WorldBackground(aspect-cover,只负责场景)
|
||
├─ MarketHeader
|
||
│ ├─ TitlePlaque(NinePatch 外框)
|
||
│ ├─ TitleLabel
|
||
│ └─ StageLabel
|
||
├─ ResourceStatusGroup
|
||
│ ├─ CompanyBadge
|
||
│ ├─ CoinBadge
|
||
│ └─ SettingsButton
|
||
├─ RecruitBoard
|
||
│ └─ RecruitCard × 3
|
||
│ ├─ CardShell / ProfessionRibbon
|
||
│ ├─ PortraitModule(Frame + Viewport + Image)
|
||
│ ├─ IdentityModule(NamePlate + NameLabel)
|
||
│ ├─ TraitModule(Badge + TraitLabel)
|
||
│ ├─ CostModule(CoinSocket + Status + Amount)
|
||
│ └─ StateLayer / HitArea
|
||
├─ CandidateLedger
|
||
│ ├─ LedgerShell / LedgerHeader
|
||
│ ├─ PortraitModule
|
||
│ ├─ IdentityModule
|
||
│ ├─ ProfessionModule
|
||
│ ├─ DetailCopy
|
||
│ ├─ TraitModule
|
||
│ ├─ CostModule
|
||
│ ├─ ActionDock
|
||
│ └─ HitArea(ActionDock 自带)
|
||
└─ FooterNav(BackGuild / ReturnContract)
|
||
```
|
||
|
||
Market 的层所有权明确为:`m52_q_market_world_only.png` 只负责场景、木架、
|
||
布旗、柜台和远景;三块中央委托板不再属于背景。它们的纸面、类别图标、
|
||
人物框、姓名、特质、价格和选中态全部由运行时模块绘制。旧的
|
||
`m52_q_market_background.png` 仍保留作历史候选,但禁止再作为 Market
|
||
运行时底图。
|
||
|
||
当前已抽成可复用脚本的是 `MarketHeader`、`ResourceStatusGroup`、
|
||
`RecruitCard`、`CandidateLedger` 及其头像、姓名、职业、详情文案、特质、
|
||
价格、动作子模块;
|
||
`FooterNav` 也已独立;Market View 现在只保留模块排列、数据绑定和 intent
|
||
转发,不能再在页面内新增同类边框或文字按钮。
|
||
所有页面级标题必须先挂到 Header 的本地槽位,再挂 Header 到设计画布;禁止
|
||
把子标题直接按画布坐标定位。每个垂直槽位之间必须留出至少 4% 的设计画布
|
||
间距,紧凑尺寸还要通过自动换行或省略号保护容器边界。
|
||
|
||
### CandidateLedger 细粒度拆分(2026-09-10)
|
||
|
||
右侧详情不是一个“文字块”,而是一个可复用的 `CandidateLedger` 组合件:
|
||
`LedgerShell`、`LedgerHeader`、`PortraitModule`、`IdentityModule`、
|
||
`ProfessionModule`、`DetailCopy`、`TraitModule`、`CostModule`、
|
||
`ActionDock`。每个子模块只拥有自己的背景/文字槽位,父模块只负责垂直
|
||
排列和转发动作意图。`ActionDock` 同时承载视觉按钮和触摸命中区,避免
|
||
“看起来像按钮、实际点击区在别处”。
|
||
|
||
截图探针必须为每个候选人提供真实的本地化职业、特质和详情文案;空数据
|
||
只能用于空状态验收,不能用来判断最终文字布局。
|
||
|
||
### RecruitCard 紧凑布局(2026-09-10)
|
||
|
||
`RecruitCard` 与 `CandidateLedger` 共用头像、姓名、特质和价格模块,但不
|
||
强行共用同一套尺寸。卡片进入手机横屏紧凑模式后,会给头像、姓名、特质、
|
||
价格重新分配独立的垂直槽位;姓名和特质牌切换到共享的 `compact_label`
|
||
材质,保留纸面、细边和阴影,同时避免装饰端帽压到文字。费用模块继续
|
||
隐藏卡片中的重复可用状态,只显示硬币图标和金额。
|