diff --git a/client/js/01_SubGame/codes/config/Layers.js b/client/js/01_SubGame/codes/config/Layers.js index 088beca..19ea699 100644 --- a/client/js/01_SubGame/codes/config/Layers.js +++ b/client/js/01_SubGame/codes/config/Layers.js @@ -6,7 +6,7 @@ // 均落在框架保留段,与下列不冲突。 var EQW_Layers = EQW_Layers || { - TABLE_STATIC: 101, // 牌桌常驻:顶部信息条、玩家位附加标记、亮牌信息条、底栏(局数 + 功能钮) + TABLE_STATIC: 101, // 牌桌常驻:顶部信息条、玩家位附加标记、主牌统计条、底栏(局数 + 功能钮) HAND: 102, // 自己手牌区(单排 / 埋牌双排) TABLE_CARDS: 103, // 桌面牌:底牌区、三家已出牌区、埋牌底牌展示区 ACTION: 104, // 阶段操作区:叫分面板、选主/投降面板、埋牌/出牌操作条、倒计时 diff --git a/client/js/01_SubGame/codes/config/Layout_Action.js b/client/js/01_SubGame/codes/config/Layout_Action.js index 662ca6a..d59bd29 100644 --- a/client/js/01_SubGame/codes/config/Layout_Action.js +++ b/client/js/01_SubGame/codes/config/Layout_Action.js @@ -89,9 +89,23 @@ EQW_Layout.BURY_OPERATION_BAR = { //埋牌条 items 首项(同一个提示按钮)也取 180,故沿用 180,待设计稿复核。 //⚠ 本条 itemHeight 为 55(对齐出牌按钮 BTN_PLAY 157×55),而 BTN_TIP 原生高 63—— // 求解结果里提示项的 height 会是 55,实际显示高度以精灵自身资源为准;此高度差同样待设计稿裁定 +// +//2026-08-27 修订:补「提示」项后原先仍用 anchor:'center',导致整排重新居中、把已有的 +//CD_SELF / PLAY_BTN_SUBMIT 两项相对原先(仅 2 项时)左移了 107.5px——「出牌」按钮的位置在 +//参考图 `出牌.png` 是有实测依据的(556–711,宽约 156×57),不该因为插入第 3 项而漂移。 +//改为 anchor:'left',把 anchorX 定成【首项 CD_SELF 的起点】,让先前已有的两项固定不动、只是 +//在其后追加「提示」——与 FOOTER_FUNC_BUTTONS 用 anchor:'right' 固定住最右项「底牌」是同一思路 +//(那边插入更早的项,这边追加更晚的项,对称地选左/右锚点)。 +//反推 anchorX:_solveLineItems 在 anchor:'left' 下 start = anchorX,故 +// PLAY_BTN_SUBMIT.x = anchorX + CD_SELF.width(75) + spacing(35) = anchorX + 110 +//要 PLAY_BTN_SUBMIT.x ≈ 556(参考图实测),故 anchorX = 556 - 110 = 446。 +//实际调用求解器验证(count=3,spacing=35): +// CD_SELF x=446 width=75 (参考图目测约 444,估值层面 2px 差可接受) +// PLAY_BTN_SUBMIT x=556 width=157 (与参考图 556–711 实测吻合) +// PLAY_BTN_TIP x=748 width=180 EQW_Layout.PLAY_OPERATION_BAR = { - kind: 'line', direction: 'horizontal', anchorX: 640, anchorY: 345, - itemHeight: 55, spacing: 35, anchor: 'center', + kind: 'line', direction: 'horizontal', anchorX: 446, anchorY: 345, + itemHeight: 55, spacing: 35, anchor: 'left', items: [ { key: 'CD_SELF', width: 75 }, { key: 'PLAY_BTN_SUBMIT', width: 157 }, diff --git a/client/js/01_SubGame/codes/config/Layout_Result.js b/client/js/01_SubGame/codes/config/Layout_Result.js index 46d91aa..180e7b1 100644 --- a/client/js/01_SubGame/codes/config/Layout_Result.js +++ b/client/js/01_SubGame/codes/config/Layout_Result.js @@ -145,6 +145,9 @@ EQW_Layout.ACC_TPL_AVATAR = { // 列4: 傍王分{n} // 第 2 行只有前两列有文字,第 3/4 列留空(求解仍返回 8 个槽位,调用方按数据取前 6 个)。 // anchorX 相对容器(= 参考图列1 绝对 x272 − 容器 x80);anchorY 随所在行浮动 → 运行时注入 +// 【估值精度说明】本节点用等距列模型(itemWidth:176 spacingX:0 → 相对容器 192/368/544/720), +// 而参考图「大局结算.png」目视实测的列 x 约为 272/455/634/800(列距 183/179/166,并不等距)—— +// 与等距模型偏差约 10px,比本文件头部通用声明的「±5px」更大,待设计稿复核(本次未改数值,仅订正估值说明) EQW_Layout.ACC_ROW_TEXT_GRID = { kind: 'grid', anchorX: 192, cols: 4, rows: 2, itemWidth: 176, itemHeight: 34, spacingX: 0, spacingY: 10, @@ -181,9 +184,21 @@ EQW_Layout.ACC_FUNC_BUTTONS = { // 三者【同一种版式】(半透黑遮罩 + 每家一排重叠大牌),参考图同为 // docs_dev/uiref/冲关牌型显示.png;故以下节点照 CHONGGUAN_FAN / CG_MASK 同构给出, // 三家落点沿用清单 §6.7 的冲关牌锚点(LEFT 260,120 / RIGHT 1035,120 / SELF 640,400)。 -// 与冲关牌的唯一差别是【张数上限】:出牌历史摊平后可达 28 张以上,420 的 maxWidth 装不下, -// 故放宽到 500、spacingMin 收到 -96(每张露 14px,28 张总宽 110+27×14=488 ≤ 500)。 -// 这两个数是【估值,待设计稿复核】——清单未给本 View 的排布参数。 +// 与冲关牌的唯一差别是【张数上限】:出牌历史摊平后可达 28 张以上,420 的 maxWidth 装不下。 +// 2026-08-27 订正:原估值 maxWidth:500 是算错的——_solveFan 的间距公式是 +// spacing = max(spacingMin, min(spacingMax, (maxWidth-itemWidth)/(count-1) - itemWidth)) +// 代入 maxWidth 500 / itemWidth 110(CARD_SIZE.L.w)/ count 28: +// (500-110)/27 - 110 = -95.56,没有触到 spacingMin:-96 的下限,故实际 spacing 是 -95.56, +// 而 fan 的总宽恒等于 maxWidth(AlignmentUtils.distributeHorizontally 的 totalWidth 公式代入后 +// 可化简为 maxWidth,只要 spacing 没被下限截断)——不是旧注释算的「488」。 +// RIGHT 锚点 anchorX:1035、anchor:center 时,总宽 500 使整排右边缘落在 1035+250=1285, +// 超出 1280 设计画布 5px(LEFT/SELF 因锚点更靠左,仍在画布内,故此前没暴露)。 +// 故收窄 maxWidth 500 → 490:总宽=490(同样未触及 spacingMin 下限,spacingMin 因此仍是【死参数】, +// 28 张时永远用不到 -96 这个下限,留着仅为将来张数/尺寸变化时兜底),RIGHT 边缘 1035+245=1280, +// 恰好落在画布内;每张仍露约 14px(itemWidth+spacing=110-95.93≈14.07),与旧估值视觉上接近。 +// maxWidth:490 与 spacingMin:-96 仍是【估值,待设计稿复核】——清单未给本 View 的排布参数。 +// 【已知限制,留给后来者】每张仅露约 14px、视觉偏窄,待设计稿复核是否改为分两排显示, +// 或改用 CARD_SIZE.M(更小的牌面)——这是本次估值阶段接受的限制,不是本次要解决的问题。 // // 【牌用精灵复制】求解结果直接作为 SpriteCopyUtils.create 的 x/y(相对容器), // 与 §5.6a 冲关牌同一用法:三个容器精灵摆在原点、尺寸铺满屏,故容器内坐标 = 屏幕坐标。 @@ -199,7 +214,7 @@ EQW_Layout.HIST_BOX = { kind: 'point', x: 0, y: 0, w: 1280, h: 720 }; EQW_Layout.HIST_FAN = { kind: 'fan', direction: 'horizontal', anchor: 'center', itemWidth: EQW_Layout.CARD_SIZE.L.w, itemHeight: EQW_Layout.CARD_SIZE.L.h, - maxWidth: 500, spacingMax: -40, spacingMin: -96, + maxWidth: 490, spacingMax: -40, spacingMin: -96, bySeat: { LEFT: { anchorX: 260, anchorY: 120 }, RIGHT: { anchorX: 1035, anchorY: 120 }, @@ -231,7 +246,7 @@ EQW_Layout.MING_BOX = { kind: 'point', x: 0, y: 0, w: 1280, h: 720 }; EQW_Layout.MING_FAN = { kind: 'fan', direction: 'horizontal', anchor: 'center', itemWidth: EQW_Layout.CARD_SIZE.L.w, itemHeight: EQW_Layout.CARD_SIZE.L.h, - maxWidth: 500, spacingMax: -40, spacingMin: -96, + maxWidth: 490, spacingMax: -40, spacingMin: -96, bySeat: { LEFT: { anchorX: 260, anchorY: 120 }, RIGHT: { anchorX: 1035, anchorY: 120 } diff --git a/client/js/01_SubGame/codes/config/Layout_Table.js b/client/js/01_SubGame/codes/config/Layout_Table.js index 07c5195..643ca76 100644 --- a/client/js/01_SubGame/codes/config/Layout_Table.js +++ b/client/js/01_SubGame/codes/config/Layout_Table.js @@ -51,8 +51,10 @@ EQW_Layout.FOOTER_ASET_TEXT = { //底栏 · 功能钮组(明牌/已出牌/上一轮/扣底/底牌):逐项不等宽(清单 §6.1 T-25)。 //2026-08-27 补上「扣底」项(清单 §2.6 列的是 5 个按钮,此处原只排了 4 个)—— //排序按 §2.6 表:扣底紧邻底牌(两者分别看埋牌底牌 / 底牌,成对但不同批,勿写反)。 -//【估值】扣底 78:清单未给该项宽度;同为两字按钮的「底牌」实测 78、「明牌」74, -//故取同类两字按钮的 78,待设计稿复核(其余四项 74/87/93/78 为清单 §6.5 实测值) +//【估值】扣底 78:清单未给该项宽度,参考图(等待叫分.png)底栏也只画出「底牌」一项 +//(当时还没有「扣底」按钮,§2.6 后补)。依据取自【底牌】按钮实测的 78——不能笼统地说 +//「两字按钮 = 78」:同为两字的「明牌」实测只有 74,两者并不相同,不可一概而论。 +//故本项沿用「底牌」实测值 78,待设计稿复核(其余四项 74/87/93/78 为清单 §6.5 实测值) EQW_Layout.FOOTER_FUNC_BUTTONS = { kind: 'line', direction: 'horizontal', anchorX: 1250, anchorY: 672, itemHeight: 30, spacing: 15, anchor: 'right', diff --git a/client/tests/test_constants.js b/client/tests/test_constants.js index 8aa8f16..16793f2 100644 --- a/client/tests/test_constants.js +++ b/client/tests/test_constants.js @@ -135,6 +135,21 @@ allNodes.forEach(entry => { if (missing.length) { console.log('无法解析的 attach.target:\n ' + missing.join('\n ')); } t.eq('attach.target 在其 targetKind 命名空间内可解析', missing, []); +// line + items 节点:每项 key 同样是"指向另一个命名空间对象"的标识(多为精灵键), +// 与 attach.target 同一职责,此前完全没有守卫——写错 key 不会报错,只会在渲染时摆错精灵。 +// items 没有 targetKind 字段,按 attach.target 同样的三命名空间并集解析 +const missingItemKeys = []; +allNodes.forEach(entry => { + if (!entry.node.items) { return; } + entry.node.items.forEach((it, i) => { + if (!resolvable[it.key]) { + missingItemKeys.push(entry.path + '.items[' + i + '] -> key 不存在: ' + it.key); + } + }); +}); +if (missingItemKeys.length) { console.log('无法解析的 items[].key:\n ' + missingItemKeys.join('\n ')); } +t.eq('items[].key 在三命名空间并集内可解析', missingItemKeys, []); + // ---- 求解冒烟:每个布局节点都真的能被求解器算出来 ---- // 这是配置与求解器之间契约的最强守卫——字段名写错、缺 w/h、kind 不认识、 // bySeat 缺座位,全都会在这里当场抛错,而不是等到界面上静默摆歪。 diff --git a/docs/superpowers/plans/2026-08-26-二七王前端A-地基与逻辑层.md b/docs/superpowers/plans/2026-08-26-二七王前端A-地基与逻辑层.md index 2654973..dd4cdbe 100644 --- a/docs/superpowers/plans/2026-08-26-二七王前端A-地基与逻辑层.md +++ b/docs/superpowers/plans/2026-08-26-二七王前端A-地基与逻辑层.md @@ -1441,7 +1441,9 @@ EOF // 均落在框架保留段,与下列不冲突。 var EQW_Layers = EQW_Layers || { - TABLE_STATIC: 101, // 牌桌常驻:顶部信息条、玩家位附加标记、亮牌信息条、底栏 + TABLE_STATIC: 101, // 牌桌常驻:顶部信息条、玩家位附加标记、主牌统计条、底栏 + // ↑ 2026-08-27 改名「亮牌信息条」→「主牌统计条」:与 design §8.2 的「亮牌」同名异实, + // 见清单 §0.3 群组表下的修订说明 HAND: 102, // 自己手牌区(单排 / 埋牌双排) TABLE_CARDS: 103, // 桌面牌:底牌区、三家已出牌区、埋牌底牌展示区 ACTION: 104, // 阶段操作区:叫分面板、选主/投降面板、埋牌/出牌操作条、倒计时 @@ -1460,7 +1462,7 @@ var EQW_Layers = EQW_Layers || { - [ ] **Step 2: 写 `Groups.js`** 照清单 §0.3 群组表逐条录入(201–250),格式同上:每条一行注释说明用途。必须包含: -`201` 顶部信息条、`202/203/204` 左上家/右上家/自己的附加标记、`205` 底栏功能按钮组、`206` 亮牌信息条、`210` 自己手牌、`211` 底牌区、`212/213/214` 自己/左上家/右上家已出牌区、`215` 埋牌底牌区、`220` 叫分面板、`221` 选主/投降面板、`222` 埋牌操作条、`223` 出牌操作条、`224` 倒计时、`230` 桌面浮层、`240` 小局结算、`241` 大局总结算、`242` 出牌历史、`243` 明牌面板、`244` 冲关牌型叠加层(清单 §5.6a)、`250` 建房规则选项。 +`201` 顶部信息条、`202/203/204` 左上家/右上家/自己的附加标记、`205` 底栏功能按钮组、`206` 主牌统计条(2026-08-27 由「亮牌信息条」改名,见清单 §0.3 群组表下的修订说明)、`210` 自己手牌、`211` 底牌区、`212/213/214` 自己/左上家/右上家已出牌区、`215` 埋牌底牌区、`220` 叫分面板、`221` 选主/投降面板、`222` 埋牌操作条、`223` 出牌操作条、`224` 倒计时、`230` 桌面浮层、`240` 小局结算、`241` 大局总结算、`242` 出牌历史、`243` 明牌面板、`244` 冲关牌型叠加层(清单 §5.6a)、`250` 建房规则选项。 - [ ] **Step 3: 写 `ImageResources.js`** @@ -1603,8 +1605,8 @@ EQW_Sprites.PlayerMarkView = { // ... SelfMark(群组 204)同理 }; -// ... 其余 View 按清单 §5.1 续:亮牌条(群组 206,1030–1031)、 -// 底栏(群组 205,1040–1055) +// ... 其余 View 按清单 §5.1 续:主牌统计条(群组 206,1030–1031,2026-08-27 由「亮牌条」 +// 改名,见清单 §0.3 群组表下的修订说明)、底栏(群组 205,1040–1055) ``` 清单 §5.1 里 `1110–1115 P_RIGHT_*`「结构同 202」是省略写法,**必须展开写全**:`P_RIGHT_BANKER:1110`、`P_RIGHT_ZHU_BG:1111`、`P_RIGHT_ZHU_TEXT:1112`、`P_RIGHT_PAIR_BG:1113`、`P_RIGHT_PAIR_TEXT:1114`、`P_RIGHT_STATUS_TEXT:1115`。 @@ -1949,7 +1951,7 @@ EQW_Layout.TEXT_STYLE = { - [ ] **Step 2: 写 `Layout_Table.js`** -照清单 §6.5(顶部信息条、亮牌条、底栏、庄标、提示按钮组、平台语音/聊天钮坐标)与 §6.6(头像框 `bySeat`、庄印章、主N/对N 角标、状态文字、倒计时、提示气泡朝向)逐条录入。示例: +照清单 §6.5(顶部信息条、主牌统计条【2026-08-27 由「亮牌条」改名,见清单 §0.3 群组表下的修订说明】、底栏、庄标、提示按钮组、平台语音/聊天钮坐标)与 §6.6(头像框 `bySeat`、庄印章、主N/对N 角标、状态文字、倒计时、提示气泡朝向)逐条录入。示例: ```js var EQW_Layout = EQW_Layout || {}; diff --git a/docs_dev/二七王-UI资源与精灵清单.md b/docs_dev/二七王-UI资源与精灵清单.md index 777fdbb..23447e5 100644 --- a/docs_dev/二七王-UI资源与精灵清单.md +++ b/docs_dev/二七王-UI资源与精灵清单.md @@ -1688,7 +1688,7 @@ CARD_SIZE: { | 主牌统计条(节点 `ZHU_STAT_BG`) | `point` | `x:35 y:400 w:210 h:35` | | 底栏条 | `point` | `x:0 y:648 w:1280 h:72` | | 底栏 · 局数文字 | `point` | `x:635 y:672 w:65 h:26`,`textStyle{fontSize:20, align:center}` | -| 底栏 · 功能钮组(明牌/已出牌/上一轮/**扣底**/底牌) | `line` + `items` | `direction:horizontal, anchorX:1250, anchorY:672, itemHeight:30, spacing:15, anchor:right`,`items:[74,87,93,**78***,78]`(逐项不等宽,见 §6.1)。**\*`扣底` 的 78 是估值**(2026-08-27 补项,本表原只列 4 项)——同为两字按钮的 `底牌` 实测 78、`明牌` 74,故取 78,待设计稿复核 | +| 底栏 · 功能钮组(明牌/已出牌/上一轮/**扣底**/底牌) | `line` + `items` | `direction:horizontal, anchorX:1250, anchorY:672, itemHeight:30, spacing:15, anchor:right`,`items:[74,87,93,78†,78]`(逐项不等宽,见 §6.1)。†`扣底` 的 78 是估值(2026-08-27 补项,本表原只列 4 项)——参考图(等待叫分.png)底栏当时也只画出 `底牌` 一项;依据取自 `底牌` 实测的 78,不能笼统说「两字按钮 = 78」:同为两字的 `明牌` 实测只有 74,两者不同,待设计稿复核 | | 底栏 · 庄标 | `point` | `x:338 y:668 w:32 h:34` | | 底栏 · 提示按钮组(踩/有分/没分) | `line` | `direction:horizontal, anchorX:335, anchorY:672, itemWidth:52, itemHeight:30, spacing:26, anchor:left` | | 右侧语音钮(平台) | `point` | `x:1210 y:310 w:56 h:56` | @@ -1754,7 +1754,7 @@ CARD_SIZE: { | 选主 · 张数 | `attach` | `target:对应花色按钮, hAlign:center, vAlign:bottom, offsetY:-6, h:NUM_STYLE.MAIN_SUIT_COUNT.charHeight(32)`;`w` 运行时注入(`9张`=2 字符、`26张`=3 字符,宽度随之变)。一个花色一个精灵 | | 选主 · 对数角标文字 | `attach` | `target:对应花色按钮, corner:topRight, offsetX:-36, offsetY:2`(按钮帧内已含角标底,本节点只定位叠加文字) | | 埋牌 · 操作条 | `line` + `items` | `direction:horizontal anchorX:640 anchorY:165 itemHeight:63 spacing:45 anchor:center`,`items:[180,60,180]`(提示 / 倒计时 / 埋牌) | -| 出牌 · 操作条 | `line` + `items` | `direction:horizontal anchorX:640 anchorY:345 itemHeight:55 spacing:35 anchor:center`,`items:[75,157,**180***]`(倒计时 / 出牌 / **提示**)。**\*`提示` 的 180 是估值**(2026-08-27 补项,本表原漏了 §1.7 明确要求的 `提示` 按钮)——与埋牌条的 `提示` 同资源 `BTN_TIP`(§3.3 实测 180×63),埋牌条 `items` 首项亦取 180,故沿用;顺序照 §1.7 行文。⚠ 本条 `itemHeight:55` 对齐的是 `BTN_PLAY`(157×55),而 `BTN_TIP` 原生高 63,高度差待设计稿裁定 | +| 出牌 · 操作条 | `line` + `items` | `direction:horizontal anchorX:446 anchorY:345 itemHeight:55 spacing:35 anchor:left`,`items:[75,157,180‡]`(倒计时 / 出牌 / **提示**)。‡`提示` 的 180 是估值(2026-08-27 补项,本表原漏了 §1.7 明确要求的 `提示` 按钮)——与埋牌条的 `提示` 同资源 `BTN_TIP`(§3.3 实测 180×63),埋牌条 `items` 首项亦取 180,故沿用;顺序照 §1.7 行文。⚠ 本条 `itemHeight:55` 对齐的是 `BTN_PLAY`(157×55),而 `BTN_TIP` 原生高 63,高度差待设计稿裁定。**2026-08-27 再订正**:补「提示」项后若沿用 `anchor:center`,整排重新居中会把已有的倒计时/出牌两项相对原先(仅 2 项时)左移 107.5px,导致「出牌」按钮偏离参考图 `出牌.png` 的实测位置(556–711)。改为 `anchor:left, anchorX:446`(= 参考图出牌按钮实测起点 556 − 倒计时宽 75 − 间距 35),求解结果:倒计时 x=446、出牌 x=556(与实测吻合)、提示 x=748 | | 捡分飘字 | `point` | `x:570 y:180 w:170 h:55`;另配 `floatRise:-60`、`floatDuration:800`(动画参数也进配置) | | 状态提示条 · 等待类 | `point` | `x:500 y:373 w:320 h:47`(§2.8) | | 状态提示条 · 即时反馈类 | `point` | `x:462 y:172 w:363 h:50`;另配 `toastDuration:1500` | @@ -1807,30 +1807,12 @@ CARD_SIZE: { | 玩家栏**行** | `ACC_ROW` | `line` | `direction:vertical, anchorX:0, anchorY:14, itemWidth:1100, **itemHeight:132(行高)**, spacing:0, anchor:top`(相对容器;行数 = `ctx.count`) | | 行内 · 名次徽章 | `ACC_TPL_RANK` | `attach` | `target:ACC_ROW, hAlign:left, vAlign:middle, offsetX:28, w:44 h:44` | | 行内 · 头像 | `ACC_TPL_AVATAR` | `attach` | `target:ACC_ROW, hAlign:left, vAlign:middle, offsetX:92, w:80 h:80` | -| 行内 · 文字栅格(6 条文字的槽位) | `ACC_ROW_TEXT_GRID` | `grid` | `anchorX:192, cols:4, rows:2, itemWidth:176, itemHeight:34, spacingX:0, spacingY:10, anchor:left, fillOrder:row`;`anchorY` 运行时注入(随所在行浮动)。列序:昵称/`ID:` · 基础分/总得分 · 冲关分 · 傍王分(第 2 行仅前两列有文字) | +| 行内 · 文字栅格(6 条文字的槽位) | `ACC_ROW_TEXT_GRID` | `grid` | `anchorX:192, cols:4, rows:2, itemWidth:176, itemHeight:34, spacingX:0, spacingY:10, anchor:left, fillOrder:row`;`anchorY` 运行时注入(随所在行浮动)。列序:昵称/`ID:` · 基础分/总得分 · 冲关分 · 傍王分(第 2 行仅前两列有文字)。**估值精度**:本节点是等距列模型(相对容器 192/368/544/720),参考图目视实测列 x 约 272/455/634/800(列距 183/179/166,并不等距),偏差约 10px,比本节头部通用的「±5px」更大,待设计稿复核 | | 行内 · 右侧总分大字 | `ACC_TPL_SCORE_NUM` | `attach` | `target:ACC_ROW, hAlign:right, vAlign:middle, offsetX:-25, h:NUM_STYLE.RESULT_WIN.charHeight(62)`;`w` 运行时注入 | | 行内 · 分隔线 | `ACC_TPL_DIVIDER` | `attach` | `target:ACC_ROW, hAlign:center, vAlign:bottom, offset(0,0), w:1060 h:2`(`vAlign:bottom` 的语义是"目标底边之下",见 §6.0) | | 面板**外**底部 4 按钮 | `ACC_FUNC_BUTTONS` | `line` | `direction:horizontal, anchorX:345, anchorY:640, itemWidth:190, itemHeight:60, spacing:25, anchor:left`(参考图里这排不居中于屏幕、整体偏右,故用 `anchor:left` 定起点) | -#### 6.9c 出牌历史 / 亮牌 · 明牌配置(§5.7b,2026-08-27 补齐) - -> 本表同样原先**整块缺失**(`HIST_*` / `MING_*` 一个节点都没有)。 -> 两者与冲关牌型叠加层是**同一种版式**(半透黑遮罩 + 每家一排重叠大牌,参考图同为 `uiref/冲关牌型显示.png`),故照 §6.7 的 `CHONGGUAN_FAN` 同构给出,三家锚点沿用冲关牌的 `LEFT 260,120 / RIGHT 1035,120 / SELF 640,400`。 -> **与冲关牌的唯一差别是张数上限**:出牌历史摊平后可达 28 张以上,`maxWidth:420` 装不下,故放宽到 **500**、`spacingMin` 收到 **-96**(每张露 14px,28 张总宽 `110+27×14=488 ≤ 500`)。这两个数是**估值,待设计稿复核**。 -> 牌用精灵复制:三个容器精灵摆在原点、尺寸铺满屏,故 `fan` 求出的屏幕坐标可直接当容器内坐标用。 - -| 部件 | 节点名 | kind | 参数 | -| --- | --- | --- | --- | -| 出牌历史 · 遮罩 | `HIST_MASK` | `point` | `x:0 y:0 w:1280 h:720, opacity:0.72`(【亮牌】用途下**不注册点击**,见 §1.6) | -| 出牌历史 · 三个牌容器 | `HIST_BOX` | `point` | `x:0 y:0 w:1280 h:720`(同摆原点、铺满屏) | -| 出牌历史 · 每家一排牌 | `HIST_FAN` | `fan` | `size:L, anchor:center, maxWidth:500, spacingMax:-40, spacingMin:-96`;`bySeat{ LEFT:{260,120}, RIGHT:{1035,120}, SELF:{640,400} }` | -| 出牌历史 · 座位标签 | `HIST_LABEL` | `point` | `bySeat{ LEFT:{200,318}, RIGHT:{975,318}, SELF:{580,598} }`;`w/h` 运行时注入 | -| 明牌 · 遮罩 | `MING_MASK` | `point` | 同 `HIST_MASK` | -| 明牌 · 两个牌容器 | `MING_BOX` | `point` | 同 `HIST_BOX` | -| 明牌 · 每家一排牌 | `MING_FAN` | `fan` | 同 `HIST_FAN`,但 **`bySeat` 只有 LEFT / RIGHT**(明牌只看他家,没有自己那排;精灵 `MING_BOX_A` 落 LEFT 位、`MING_BOX_B` 落 RIGHT 位) | -| 明牌 · 座位标签 | `MING_LABEL` | `point` | `bySeat{ LEFT:{200,318}, RIGHT:{975,318} }`;`w/h` 运行时注入 | - -### 6.9b 建房规则选项配置(§1.1) +#### 6.9b 建房规则选项配置(§1.1) 布局是**两层嵌套**:类别竖排,类别内的选项组横排。 @@ -1857,6 +1839,26 @@ ROOM_CAT_TITLE_STYLE: { fontSize: 18, color: '#7FBFB0', bold: true, align: 'righ 不要在代码里写死 `'#E8873A'`。 +#### 6.9c 出牌历史 / 亮牌 · 明牌配置(§5.7b,2026-08-27 补齐) + +> 本表同样原先**整块缺失**(`HIST_*` / `MING_*` 一个节点都没有)。 +> 两者与冲关牌型叠加层是**同一种版式**(半透黑遮罩 + 每家一排重叠大牌,参考图同为 `uiref/冲关牌型显示.png`),故照 §6.7 的 `CHONGGUAN_FAN` 同构给出,三家锚点沿用冲关牌的 `LEFT 260,120 / RIGHT 1035,120 / SELF 640,400`。 +> **与冲关牌的唯一差别是张数上限**:出牌历史摊平后可达 28 张以上,`maxWidth:420` 装不下。 +> **2026-08-27 订正**:原估值 `maxWidth:500` 的推导算错了——`fan` 的间距公式是 `spacing = max(spacingMin, min(spacingMax, (maxWidth-itemWidth)/(count-1) - itemWidth))`,代入 `maxWidth 500 / itemWidth 110 / count 28` 得 `(500-110)/27-110 ≈ -95.56`,**没有**触到 `spacingMin:-96` 的下限;而 `fan` 的总宽恒等于 `maxWidth`(只要 spacing 未被下限截断),并不是旧注释算的「488」。`RIGHT` 座位锚点 `anchorX:1035` 配合总宽 500、`anchor:center`,整排右边缘落在 `1035+250=1285`,**超出 1280 设计画布 5px**(`LEFT`/`SELF` 因锚点更靠左未暴露)。现收窄为 `maxWidth:490`:总宽仍未触及下限(`spacingMin:-96` 因此在 28 张时始终是**死参数**,留作日后张数/尺寸变化时的兜底),`RIGHT` 右边缘 `1035+245=1280`,恰好落在画布内;每张仍露约 14px(`itemWidth+spacing≈110-95.93≈14.07`),视觉上与旧估值接近。`maxWidth:490` 与 `spacingMin:-96` 仍是**估值,待设计稿复核**。 +> **已知限制**:每张仅露约 14px、视觉偏窄,待设计稿复核是否改为分两排显示,或改用 `CARD_SIZE.M`——这是估值阶段接受的限制,留给后续复核。 +> 牌用精灵复制:三个容器精灵摆在原点、尺寸铺满屏,故 `fan` 求出的屏幕坐标可直接当容器内坐标用。 + +| 部件 | 节点名 | kind | 参数 | +| --- | --- | --- | --- | +| 出牌历史 · 遮罩 | `HIST_MASK` | `point` | `x:0 y:0 w:1280 h:720, opacity:0.72`(【亮牌】用途下**不注册点击**,见 §1.6) | +| 出牌历史 · 三个牌容器 | `HIST_BOX` | `point` | `x:0 y:0 w:1280 h:720`(同摆原点、铺满屏) | +| 出牌历史 · 每家一排牌 | `HIST_FAN` | `fan` | `size:L, anchor:center, maxWidth:490, spacingMax:-40, spacingMin:-96`;`bySeat{ LEFT:{260,120}, RIGHT:{1035,120}, SELF:{640,400} }`。求解验证(count=28):`LEFT` 首尾 x ≈ `15 → 505`,`RIGHT` 首尾 x ≈ `790 → 1280`,`SELF` 首尾 x ≈ `395 → 885`,均落在 0–1280 内 | +| 出牌历史 · 座位标签 | `HIST_LABEL` | `point` | `bySeat{ LEFT:{200,318}, RIGHT:{975,318}, SELF:{580,598} }`;`w/h` 运行时注入 | +| 明牌 · 遮罩 | `MING_MASK` | `point` | 同 `HIST_MASK` | +| 明牌 · 两个牌容器 | `MING_BOX` | `point` | 同 `HIST_BOX` | +| 明牌 · 每家一排牌 | `MING_FAN` | `fan` | 同 `HIST_FAN`,但 **`bySeat` 只有 LEFT / RIGHT**(明牌只看他家,没有自己那排;精灵 `MING_BOX_A` 落 LEFT 位、`MING_BOX_B` 落 RIGHT 位) | +| 明牌 · 座位标签 | `MING_LABEL` | `point` | `bySeat{ LEFT:{200,318}, RIGHT:{975,318} }`;`w/h` 运行时注入 | + ### 6.10 配置文件组织 按 client 02 §2 的三件套拆分,布局部分建议再按界面拆文件,用保护性声明合并: