二七王:HIST_FAN/MING_FAN maxWidth 由 490 改判定为 480,让 spacingMin 真正生效

上一版把 maxWidth 收窄到 490 只是让 RIGHT 座位恰好贴住画布边界(零余量),且
spacingMin:-96 在 28 张时永远不触底、成了死参数。裁定改为 480:
(480-110)/27-110≈-96.30 超过 spacingMin,spacing 被截断为 -96,总宽变为
28×110+27×(-96)=488,与清单原注释「每张露14px、总宽488」精确对齐——500 是笔误,
488 才是当初想要的值。

求解器验证(count=28):LEFT 16→504、RIGHT 791→1279、SELF 396→884,三座位均落在
0-1280 内且有余量。同步订正 Layout_Result.js 注释与清单 §6.9c 文字/数值。

client/tests/run.js 与 server/games/erqiwang/test/run.js 均全绿,精灵总数(380)/
布局节点数(83) 未变。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-27 09:08:48 +08:00
co-authored by Claude Opus 5
parent 2b1dd0d947
commit 8dba099717
2 changed files with 17 additions and 10 deletions
@@ -1844,15 +1844,16 @@ ROOM_CAT_TITLE_STYLE: { fontSize: 18, color: '#7FBFB0', bold: true, align: 'righ
> 本表同样原先**整块缺失**(`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`——这是估值阶段接受的限制,留给后续复核。
> **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` 因锚点更靠左未暴露)。
> **2026-08-27 再订正(裁定 maxWidth:480)**:曾先收窄到 `maxWidth:490` 让 `RIGHT` 恰好贴住 1280,但零余量太脆弱(这些锚点本身是参考图目视实测、±5px 误差),且 490 时 `spacingMin:-96` 永远不触底、是个死参数,与「每张最窄只露 14px」这条约束名存实亡;旧注释原写的「每张露 14px、总宽 488」正是 `spacingMin` 触底后的结果,说明 488 才是当初想要的值,`maxWidth:500` 是与注释不符的笔误。改为 `maxWidth:480`:代入公式 `(480-110)/27-110 ≈ -96.30`,**触及** `spacingMin:-96` 下限,实际 spacing 截断为 `-96`(不再等于 raw),总宽 `= 28×110 + 27×(-96) = 488`(不再等于 `maxWidth`,因为 spacing 已被下限截断)。`spacingMin:-96` 就此真正生效、不再是死参数;每张露 `110-96=14px`,与旧注释精确一致。求解验证(count=28):`LEFT` 首尾 x = `16 → 504`,`RIGHT` 首尾 x = `791 → 1279`,`SELF` 首尾 x = `396 → 884`,均落在 0–1280 内且有余量(`RIGHT` 距边界 1px、`LEFT`/`SELF` 余量更大)。`maxWidth:480` 与 `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_FAN` | `fan` | `size:L, anchor:center, maxWidth:480, spacingMax:-40, spacingMin:-96`;`bySeat{ LEFT:{260,120}, RIGHT:{1035,120}, SELF:{640,400} }`。求解验证(count=28,spacing 触底 -96、总宽 488):`LEFT` 首尾 x = `16 → 504`,`RIGHT` 首尾 x = `791 → 1279`,`SELF` 首尾 x = `396 → 884`,均落在 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` |