16 KiB
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 验收中连续指出三个同类缺陷(银牌文字落框、卡图什椭圆开口、 右上徽章文字压图标),根因不是“不够仔细”,而是流程缺口。以下记录为 可复用规则,接入任何承载文字的新组件前必须逐条对照。
三类根因(必须避免)
- 算而不量:用九宫格拉伸公式推算开口位置,并假设开口是矩形。异形开口
(卡图什/椭圆/收窄)必须量渲染结果。正确顺序是:量源图开口 →
定目标墨迹带 → 反推槽位(
槽位 y = 目标墨迹 y − 0.08 × 字号)→ 渲染后实测墨迹复核。 - 固定 px 与比例混用:同一组件内一侧用写死像素(如文字内缩 36px)、 另一侧用比例锚点(图标 0.14–0.32),缩放/换语言必然重叠。文字槽一律 锚在兄弟图标边界之外(如图标 0.08–0.24 → 文字 0.26–0.96), 禁止绝对内缩。
- 验证尺度错 + 无最长文案 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、服务状态不得出现在玩家可见层。
- 中文正文使用共享字体和固定字号;长文案优先换行,其次省略,不能越过 容器边界。
- 禁止“纯文本按钮”。任何可点击文案必须有材质、图标或明确的选中/禁用 状态。
页面迁移顺序
- 先把页面分成
Entry Shell / Selection / Formation / Battle / Outcome。 - 选择一个主材质组件,不在页面内叠第二套同类边框。
- 先做静态层,再放运行时文字、数值和透明命中区。
- 在 760×360、844×390、1280×720 以及中英文截图中检查:裁切、文字槽、 主动作、选中态、禁用态和无重复框。
- 只有截图和试玩都通过后,才把该组件扩展到下一页。
Market 模块边界(M52-B)
Market 不是一张平面图,而是下面这棵组合树;每个叶子模块拥有自己的 文字槽、裁切边界和响应式布局,页面只负责排列模块与转发 intent:
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
材质,保留纸面、细边和阴影,同时避免装饰端帽压到文字。费用模块继续
隐藏卡片中的重复可用状态,只显示硬币图标和金额。