Add runtime/ui/shared/asset_chrome.gd: large parchment/wood surfaces use the approved generated components with ornament-safe asymmetric nine-patch margins, while small controls use the size-independent market_chrome vector material so decorative pixels are never stretched into bands. Record the rule in M52_SHARED_UI_RULES.md before another page reuses it.
7.8 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 |
青绿色操作牌、内描边、黄铜角钉 | 查看详情、确认 |
资产九宫格材质(M57)
runtime/ui/shared/asset_chrome.gd 是运行时共享材质工厂,供首屏页面复用,
不允许页面自行创建同类边框。
| 组件 | 用途 | 规则 |
|---|---|---|
rail() |
顶栏、底栏等整幅宽木牌 | name_plate 九宫格;左右装饰角是固定角块,中间只拉伸素面 |
paper() |
摘要、警告、状态羊皮纸面板 | parchment_panel 九宫格;木框与内斜面作为角/边,中心只拉伸纸面 |
market() |
小控件(名牌、命令底板) | 直接使用 market_chrome.gd 的可缩放矢量材质,避免把装饰像素拉成条带 |
规则:
- 九宫格边距必须覆盖素材的装饰环(水平与垂直可不同);边距过小会把角部 纹样拉成横条,属于禁用状态。
- 小尺寸控件(高度低于装饰环两倍)不得使用装饰型九宫格;改用
market()的可缩放材质。 - 文字一律引擎渲染,颜色使用纸面深墨或深底浅金,禁止中灰压在花色背景上。
- 新增材质必须先记录在本文件,再被第二个页面复用。
信息预算
- 每页一个主动作;首屏只放 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
材质,保留纸面、细边和阴影,同时避免装饰端帽压到文字。费用模块继续
隐藏卡片中的重复可用状态,只显示硬币图标和金额。