From fbaadb8cf51e5404504fa9f01070841042bb895c Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Tue, 29 Sep 2026 17:28:45 +0800 Subject: [PATCH 1/8] =?UTF-8?q?docs(research):=20=E7=BE=8E=E6=9C=AF?= =?UTF-8?q?=E5=9C=A3=E7=BB=8F=20UX=20=E5=AE=A1=E8=A7=86=E6=8A=A5=E5=91=8A?= =?UTF-8?q?=E2=80=94=E2=80=94=E5=85=AD=E6=9D=A1=E7=AB=8B=E6=B3=95=E8=87=B4?= =?UTF-8?q?=E4=B8=91+=E7=BB=93=E6=9E=84=E6=80=A7=E7=BC=BA=E5=A4=B1,?= =?UTF-8?q?=E4=B8=89=E6=A1=88=E4=BF=AE=E6=B3=95=E5=91=88=E6=8A=A5(ux-desig?= =?UTF-8?q?ner=20=E6=96=B9=E6=B3=95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../art-bible-ux-review-2026-09-29.md | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 design/research/art-bible-ux-review-2026-09-29.md diff --git a/design/research/art-bible-ux-review-2026-09-29.md b/design/research/art-bible-ux-review-2026-09-29.md new file mode 100644 index 00000000..35450620 --- /dev/null +++ b/design/research/art-bible-ux-review-2026-09-29.md @@ -0,0 +1,130 @@ +# 美术圣经审视报告:界面丑的根因是否在圣经本身(ux-designer 方法) + +- **日期**:2026-09-29 · **方法**:ux-designer skill 流程 + WCAG/字体/色彩外部规范对照 + 三组图像实证(现行截图 `artwork/ui-redesign-2026-09-29/current/`、严格按圣经制作的 mockup v2 `artwork/ui-redesign-2026-09-29/mockup/`、圣经点名参考图 `design/art/references/`) +- **起因**:用户假设——「界面丑的根因在美术圣经,它的指导就是错的,所以不管怎么生成画面都丑」 +- **审查对象**:`design/art/art-bible.md` v2.15(499 行全文逐条核) + +--- + +## 判决(一句话) + +**假设成立,但有精确边界:圣经有六条立法直接致丑、一处结构性缺失(全文档只规定"不许怎么丑",从未定义"什么是美");同时它的信息层骨架(图标键契约/色弱双通道/语义色思想/情绪能量谱)是真资产,不能连孩子一起倒掉。** 决定性证据:同日交付的 mockup v2 严格 100% 遵守圣经(对比度全达标、冻结件全保留),成品仍然是一个棕米单色的电子表格,不像游戏——执行无误,丑在图纸。 + +--- + +## 决定性对照:守法成品 vs 点名参考 + +| | mockup v2(100% 按圣经) | Moonlighter(圣经 §9.1 点名要学) | +|---|---|---| +| 色相 | 全屏棕-米一族,彩色只剩指甲盖大的语义点 | 紫墙、青地板、红伤害数字、多彩敌人同屏共存 | +| 明暗 | 无明暗层次(圣经 §2 禁止),全屏同一明度带,糊 | 亮地板 / 黑洞深渊 / 发光道具三档明度,纵深明确 | +| 数字呈现 | 白色便签矩阵贴在格子上(圣经原则二色牌制) | 数字/文字直接融进世界,靠环境明度承载 | +| 角色存在感 | 48px 立绘贴在平色底上,无舞台无光影 | 角色占屏高约 15%,有光照、有投影、有环境烘托 | +| 质感 | 纯色平板 UI(程序化占位即现状) | 每个面板有材质、描边、厚度 | + +讽刺实证:现行战斗屏恰恰是**违反**圣经(下半屏深棕黑、明度割裂)才有了点对比;mockup v2 **遵守**圣经后全屏统一成米棕——违反了丑,遵守了也丑。两头堵的条款,问题在立法不在执行。 + +--- + +## 病根清单(按杀伤力排序,条款引用 + 实证 + 机制) + +### 病根 1|棕-米独裁:语义色纪律错把"色彩"判给了信息层独占 + +- **条款**:§4.2「红只说危险 / 金只说收益 / 蓝只说己方 / 绿只说自然生机 / 紫赤 Boss 独占 / HSV 300°–345° 全场禁入带」+ §4.4/§7.2「UI 不新增语义色,数据只穿墨」+ §6.1 背景「低对比自然后退」(只说不能怎样)。 +- **实证**:mockup v2 全屏色相跨度约 30°(棕到米);Moonlighter 同屏色相跨 200°+。ux-designer 色彩参考里一个健康游戏 UI 需 10+ 功能色(health/mana/XP/success/warning/info/selected/hover/disabled),圣经色域给 UI 只剩米色、墨色、棕石色。 +- **机制**:立法初衷(信息不被色彩噪音淹没)正确,但手段是**把色相本身收缴为信息层专属资源**,世界侧(环境/背景/装饰)被剥夺用色权。真实游戏的做法相反:世界侧色彩丰富但低饱和后退,信息侧靠明度/位置/饱和突出——"防抢焦"是焦点预算(§3.4)的职责,"防语义混淆"才是色彩纪律的职责,圣经让色彩纪律越界把两件事都管了,管死了世界。 + +### 病根 2|明度恒定硬规则:阉割了光影这个最强层次工具 + +- **条款**:§2「全作所有状态共用同一基准明度,禁止以变亮/变暗作为情绪表达或状态区分手段;状态区分只允许色相、饱和、运动、元素」。 +- **实证**:Moonlighter 的洞穴感几乎全部来自明度(亮地板/暗深渊/发光体)。圣经禁掉明度后,画面只剩色相和饱和两个弱手段造层次,结果是平、灰、糊。 +- **机制**:立法动机对头——§9.2 反 Darkest Dungeon 式压暗、roguelike 失败重开"世界无光暗记忆",这些反对的是**用变暗表达情绪/惩罚**,不是明度本身。正确的立法是「明度变化禁用于状态/情绪表达,允许用于空间纵深与光照层次」(砖缘厚度立体面已开了这个先例——§3.2 明确"形体塑造不受明度恒定约束",等于承认了例外必要,但没有把例外上升为通则)。 +- **附带伤害**:病根 3 的直接成因。 + +### 病根 3|数字色牌制:用 UI 补丁解决美术问题,"上世纪扫雷"观感的直接来源 + +- **条款**:原则二「明亮为皮,色牌为骨」——数字一律垫 #F5EAD3 素色直角小牌,「格底不再承担数字对比义务」。 +- **实证**:现行战斗屏与 mockup v2 的棋盘 = 几十个白色便签贴满深色土,这就是"Windows 扫雷/电子表格"观感的来源。ITB(圣经自己的参考)的数字直接画在格子上,靠格子明度设计承载可读性。 +- **机制**:连环债——明度恒定(病根 2)→ 格底不能压暗 → 深色数字在亮底上对比设计空间被锁死 → 只能垫牌。色牌解决了 WCAG(12:1),制造了碎片化。它把"格子美术与数字协调设计"这条正路立法放弃了。 + +### 病根 4|结构性缺失:一份"禁令文档",从未定义目标 + +- **实证**:全文"禁/不得"出现 40+ 次,全部是过程约束;没有一个章节描述"整屏最终画面应该是什么样"。§9.1 取/弃表把三款参考的**功能骨架**取了(ITB 信息分层/Moonlighter 砖缝/Peglin 明快色彩),把它们的**表现魅力**弃了(ITB 的 HUD 材质工艺、Moonlighter 的光照、Peglin 的角色体积魅力——这些恰恰是它们好看的原因)。§1.4 样张验收只验单格,**整屏构图从未有过验收闸**(战斗一屏样张自立项起挂账至今)。 +- **机制**:约束的交集只能收敛出"不违规的安全区",收敛不出"美"。所有生图/执行只能在安全区里打转——这就是"不管怎么生成都丑"的文档级解释。 + +### 病根 5|装饰配额制:「约 2 种、纹理级、低对比」把棋盘判了无期徒刑 + +- **条款**:§1.2 原则三/§3.2——装饰变体约 2 种、一律纹理级、禁物件级(巨石/小石堆)、低对比自然后退。 +- **实证**:10×10 格 100 格几乎全同,大面积重复。ITB 地表耐看恰因每格有物件级变化(石块/草丛/水渍/裂缝)。 +- **机制**:立法初衷(装饰不得伪装逻辑差异、零信息纪律)正确;正确手段不是禁物件级,而是「物件级装饰必须有专属形状家族、与信息元素(数字/小人/旗/纹样)形状语言隔离」——焦点预算管得了"抢读",不需要灭绝装饰。 + +### 病根 6|舞台与体量缺失:角色没有存在感 + +- **条款**:§8.2 主角 48×72 / 敌立绘 48/64/96px 档;§6.1 对 B 区背景只有负面约束(不得抢焦),无正面目标(舞台是什么)。 +- **实证**:1280×800 屏上主角占屏高 9%,周围无任何环境烘托,像贴纸;Moonlighter 约 15% 且有光照投影。mockup v2 已尽力加石台名牌,仍被 48px 资产上限锁死。 + +### 病根 7|UI 全局可读性盲区:圣经只管了格子里的数字 + +- **条款**:棋盘数字 ≥4.5:1 硬指标(§4.1)做得很好;但**全局 UI 文字对比度无硬指标**(§7.2 双色墨制只覆盖关卡屏暗底件),字号下限 13/14px 低于 ux-designer PC 规范(1080p body ≥16px/tooltip ≥14px;本作 1280×800 更低分辨率同字号实际更小),「像素字不作字重区分」自断一层级手段。 +- **实证**:现行 8 处文字实测 4 处不达标(C 区属性行 1.31:1、菜单说明 2.58:1、副标题 3.54:1、放弃冒险 4.42:1 擦线)——全部落在圣经没立规矩的自由发挥区。 + +### 病根 8(执行层,非圣经立法):程序化占位被当成了现状 + +- §7.5/§6.2 允许「现行程序化占位不空窗」,纯色平板 UI 遂成事实标准。panel_stone/button_stone 资产已在包里未接线(mockup v2 已验证可用)。圣经缺一条「占位=临时态,终稿闸=整屏样张」的收口规则——与病根 4 同源。 + +--- + +## 强项保留清单(推翻圣经时这些不能倒) + +1. **图标键契约 §4.6**:键=数据表主键、身份=形状纹样、极性=金/红色相槽+满缺框形——工程与可读性双扎实,ux-designer 规范级。 +2. **色弱双通道纪律 §4.5**:九对语义逐对点名冗余通道,比外部规范还细。 +3. **语义色思想内核**:红=危险/金=收益/蓝=己方的分配本身没问题——病在"只说 X"的独占式立法收缴了世界用色,不在分配本身。 +4. **§2 情绪能量谱**(八状态 × 0–10 能量 × 主情绪/承载元素):框架是真资产,只需删掉"明度恒定"这个手段枷锁。 +5. **形状语言总纲**「圆角为世、直线为信」+ **焦点预算 §3.4**:一致的形式语法,问题只是焦点预算被明度恒定削弱了手段。 +6. **明度恒定的立法动机**(反压抑、失败不惩罚、非暗黑风基调):动机保留,手段换掉。 + +--- + +## 修法备选案(呈报拍板;每案代价与联动如实列) + +### 案 A|最小修(不动 §2,补盲区) +改 4 处:① 语义色"全场独占"改"信息层独占",世界侧色相解禁但低饱和(焦点预算接管防抢焦);② 补全局 UI 文字 ≥4.5:1 硬指标;③ 装饰变体解禁物件级(专属形状家族隔离);④ 补整屏样张验收闸。 +- **代价**:小,一周级;冻结件全保留。 +- **局限**:明度恒定还在,光影层次仍然没有;数字色牌还在,白牌矩阵不变。**能改善"单色世界",改善不了"平"。** + +### 案 B|中修(推荐) +在案 A 基础上加三条: +1. **§2 明度恒定改「明度分层」**:明度禁用于状态/情绪表达(立法初衷保留),允许用于空间纵深与光照——给三档明度带(世界底层/世界中层/信息面层),砖缘立体面既有例外上升为通则;Darkest Dungeon 式压暗仍在 §9.2 反面清单。 +2. **数字色牌降级为后备手段**:格底明度分档(未开亮/已开暗一档差)承载数字对比,色牌只在复杂格底启用;需重跑 §1.4 样张(机检断言改造,工作量已知)。 +3. **§8.2 资产档位上调评估**:主角/敌立绘升一档(如 64×96/96 档),配合 B 区舞台规范(光照/投影/地台进 §6.1 正面目标)。 +- **代价**:中——§1.4 样张重跑、棋盘渲染参数调整、部分冻结件(色牌形制/样张 v2 四冻结之①④)需解冻重冻;ui_kit 色板批联动。 +- **收益**:画面获得光影层次 + 色相解放 + 去白牌,直指三大观感根因。 + +### 案 C|推翻重写 +以 Moonlighter 式光照像素地牢为目标重写圣经。 +- **代价**:大——全部样张、四冻结、21 枚瓦片资产、色板定稿作废重来;前期美术投入沉没。 +- **何时才值**:若用户认为"明快暖石地牢"这个风格基调本身也不要了。本报告判断:基调没错(Moonlighter 同基调且好看),错的是手段,**故不推荐 C**。 + +### 不在三案内的独立小修(随任一案附带) +- 字号下限对齐 ux-designer PC 规范(body ≥16px/tooltip ≥14px @1280×800);解禁字重两档。 +- 「占位=临时态,整屏样张=终稿闸」收口条款(治病根 8)。 + +--- + +## 待拍板清单(登记口径:06-待办清单,待用户逐条表态) + +1. 三案选型(A / B / C,或 B 的子集勾选)。 +2. 若选 B:§1.4 样张重跑的闸形(沿用机检闸形 A 还是先目检方向稿)。 +3. 若选 B:数字色牌退役范围(全退 / 复杂格底后备)。 +4. 资产档位上调是否本批做(牵涉在制敌立绘/主角三态资产返工面)。 +5. 本报告结论是否收编入 art-bible 版本历史(v3.0 修订立项)。 + +--- + +## 证据索引 + +- 现行截图三屏:`artwork/ui-redesign-2026-09-29/current/`(战斗屏上下明度割裂、菜单文字 2.58:1 实证) +- mockup v2 三屏:`artwork/ui-redesign-2026-09-29/mockup/`(严格守法成品实证) +- 对比度实测数据:`artwork/ui-redesign-2026-09-29/对比报告.md` §一(8 处 4 处不达标,最低 1.31:1) +- 参考图:`design/art/references/moonlighter_1.jpg`(色相跨域/明度层次对照) +- 外部规范:ux-designer skill `references/color-palettes.md`(WCAG 对比度/功能色表)、`references/font-guidelines.md`(PC 字号下限) From 9d69c7ef4b90e2eb056e90034605e0f32955d0d7 Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Tue, 29 Sep 2026 17:59:03 +0800 Subject: [PATCH 2/8] =?UTF-8?q?docs(art-bible):=20v3.0=20=E4=B8=AD?= =?UTF-8?q?=E4=BF=AE=E6=89=B9(=E6=A1=88B=20=E7=94=A8=E6=88=B7=E6=8B=8D?= =?UTF-8?q?=E6=9D=BF)=E2=80=94=E2=80=94=E6=98=8E=E5=BA=A6=E5=88=86?= =?UTF-8?q?=E5=B1=82/=E8=89=B2=E7=89=8C=E9=99=8D=E7=BA=A7/=E8=AF=AD?= =?UTF-8?q?=E4=B9=89=E8=89=B2=E5=9F=9F=E9=99=90=E5=AE=9A/=E8=A3=85?= =?UTF-8?q?=E9=A5=B0=E8=A7=A3=E7=A6=81/=E8=88=9E=E5=8F=B0=E6=AD=A3?= =?UTF-8?q?=E9=9D=A2=E7=9B=AE=E6=A0=87/=E6=95=B4=E5=B1=8F=E6=A0=B7?= =?UTF-8?q?=E5=BC=A0=E9=97=B8/=E5=85=A8=E5=B1=80=E5=AF=B9=E6=AF=94?= =?UTF-8?q?=E5=BA=A6/=E5=AD=97=E5=8F=B7=E5=AD=97=E9=87=8D/=E6=A1=A3?= =?UTF-8?q?=E4=BD=8D=E6=96=B9=E5=90=91;=E8=BF=9E=E5=B8=A6=E5=85=AD?= =?UTF-8?q?=E6=96=87=E6=A1=A3+06=E4=B8=89=E6=8C=82=E8=B4=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- design/art/art-assets-checklist.md | 4 +- design/art/art-bible.md | 94 +++++++++++++++------------ design/art/character-design.md | 2 +- design/gdd/04-美术音频方向.md | 4 +- design/gdd/06-待办清单.md | 24 +++++++ design/gdd/ux/battle.md | 2 +- design/gdd/ux/interaction-patterns.md | 2 +- design/gdd/ux/level-map.md | 2 +- 8 files changed, 85 insertions(+), 49 deletions(-) diff --git a/design/art/art-assets-checklist.md b/design/art/art-assets-checklist.md index 3cc8cd3f..810bb4f2 100644 --- a/design/art/art-assets-checklist.md +++ b/design/art/art-assets-checklist.md @@ -27,7 +27,7 @@ |---|---| | 一句话视觉规则 | 明快的地牢,轻快的扫荡,仔细的推理——**明亮像素幻想,全年龄,非暗黑**,角色 2~3 头身 | | 原则一「预告上格」 | 格内绘制优先级 **数字(含色牌)> 小人 > 旗 > 变异纹带 > 装饰变体 > 底色**;任何元素不得遮挡数字字形区;类型微光为底效泛光层,不入遮挡栈 | -| 原则二「明亮为皮,色牌为骨」 | 高亮度暖倾向;数字垫素色直角色牌(候选 `#F5EAD3`),牌墨对比 ≥4.5:1、数字墨 L≤0.027;格底 L≥0.30、HSV 饱和 ≤0.55 | +| 原则二「明亮为皮,明度分档为骨」(v3.0) | 暖倾向;数字亮墨直画已开格底(候选亮墨 L≥0.55 / 已开底 L 0.20–0.32,样张 v3 冻结),对比 ≥4.5:1;色牌 `#F5EAD3` 降级为复杂格底后备(牌上深墨 L≤0.027);未开格底 L≥0.30、HSV 饱和 ≤0.55 | | 原则三「一砖一世界」 | 变体优先换色板不加新资产;危险状态必须**形状+颜色双通道**(色弱灰度可辨) | | 类型预读单通道(§4.6.3) | 未开格 = **类型常显微光**(五组色带 §4.2:芥末黄/黄绿/青/紫罗兰/绯红,色相+明度双码,均候选值,避 300°–345° 禁入带,样张批冻结);不呈现极性、不泄雷安〔角嵌形状通道 2026-09-28 退役——用户裁微光格只留微光〕 | | 剪影哲学(§5.1) | **所有角色自带轮廓通道:亮色描边+落影底盘**,识别不依赖背景;四类原型见各条目 | @@ -149,7 +149,7 @@ | 受击反馈 / 死亡表现 / 顺位标记 | 敌人系统登记的资产需求**下限三类** | 死亡=血条归零后**灰化+碎裂退场,禁止瞬间消失**;顺位标记需在敌多时可读 | ⚙/✦ 挂自产精灵——死亡灰化碎裂是语义硬规则,不可整包复用;烟尘碎屑粒子可 ♻ 改色 | | 特殊技动画终稿 | 并入 §2.3 三档意图动画,不另起体系 | 攻/防两型旧口径由三档替代 | ✦/⚙ 自产(同 §2.3) | | 连锁坍塌显形演出 | 连锁展开触发时的连锁演出 | 与音频方向同批配对登记;「坍塌显形」=连锁展开的玩家可见名 | ♻ 粒子/碎块改色 + ⚙ 坍塌结构自产 | -| 封印特效(插旗动作) | 插旗的呈现名 = **封印**(2026-09-25 术语批,art-bible §3.2):**施印瞬间特效 + 印记常显形态**两件 | 印记旗面走封印黑 `#000000`(旗朱→封印紫→封印黑,2026-09-28 封印黑批);特效走运动+色相、明度恒定(§2);现行占位 = 封印黑「旗」字形;印记常显形态可与 §3.3 旗面像素化合并出 | ✦/⚙ 自产(精灵+粒子,烟尘光点可 ♻ 改色) | +| 封印特效(插旗动作) | 插旗的呈现名 = **封印**(2026-09-25 术语批,art-bible §3.2):**施印瞬间特效 + 印记常显形态**两件 | 印记旗面走封印黑 `#000000`(旗朱→封印紫→封印黑,2026-09-28 封印黑批);特效走运动+色相(§2:状态/情绪不走明度,空间光照可走——v3.0);现行占位 = 封印黑「旗」字形;印记常显形态可与 §3.3 旗面像素化合并出 | ✦/⚙ 自产(精灵+粒子,烟尘光点可 ♻ 改色) | | 弹道/退场等动画密度 | 战斗表现输入清单,方案未定 | 样张锁动画方案后启动 | ♻ 通用弹道/光点/消散粒子改色为主 | --- diff --git a/design/art/art-bible.md b/design/art/art-bible.md index 6787d48e..67dcf5bd 100644 --- a/design/art/art-bible.md +++ b/design/art/art-bible.md @@ -1,6 +1,6 @@ # 美术圣经(Art Bible)— Dungeon Sweeper -> 项目:Dungeon Sweeper(扫雷 × 自动战斗 闯关 Roguelike)· 状态:**第 1–9 节定稿**(§6 环境/§7 UI/§8 资产规范/§9 参考与反参考已于 2026-09-23 v1.8 按 D1/D2/D4/D5 框架成文;D3=§5 角色已于 v1.6 落地、v1.7 抽离独立文档;框架 2026-09-22 用户拍板,原登记于中间产物修订指导,经裁决不入库,明细归台账 125);历次修订明细见文末版本历史(现行为 v2.15) +> 项目:Dungeon Sweeper(扫雷 × 自动战斗 闯关 Roguelike)· 状态:**第 1–9 节定稿**(§6 环境/§7 UI/§8 资产规范/§9 参考与反参考已于 2026-09-23 v1.8 按 D1/D2/D4/D5 框架成文;D3=§5 角色已于 v1.6 落地、v1.7 抽离独立文档;框架 2026-09-22 用户拍板,原登记于中间产物修订指导,经裁决不入库,明细归台账 125);历次修订明细见文末版本历史(现行为 v3.0) > > **Art Director Sign-Off (AD-ART-BIBLE)**:历次批均 SKIPPED(v1.8 §6–9 补全亦 SKIPPED)— Lean/Solo mode(非 PHASE-GATE;§6–9 已成文,full 门禁签核时机待用户表态) > 风格基调(2026-09-10 用户定稿):地牢题材但**非暗黑风**——轻快明亮的幻想冒险风,全年龄;像素风;角色 2~3 头身 @@ -27,17 +27,17 @@ *设计测试:当某信息歧义于"画进格子"还是"收进面板"时,画进格子。* -**原则二|明亮为皮,色牌为骨**(取自 Moonlighter、Peglin;锚定 P1 可读性前提、P4 探险氛围) +**原则二|明亮为皮,明度分档为骨**(取自 Moonlighter、Peglin;锚定 P1 可读性前提、P4 探险氛围;2026-09-29 v3.0 修订——原「色牌为骨」降级,病根与修法见 `design/research/art-bible-ux-review-2026-09-29.md` 病根 3) -取 Moonlighter 的暖质地砖与亲和冒险者气质、Peglin 的明快全年龄洞穴色彩:全局高亮度、暖倾向、无压抑。可读性由数字自带的**数字色牌**承载——数字一律垫在一小块素色直角牌上(画法 §3.3、色值 §4.1),牌与数字墨的对比是硬指标(≥4.5:1 恒成立),数字可读不依赖所在格底。格子本体美术自此放开:纹理、材质、装饰变体、类型纹样皆可入画,格底不再承担数字对比义务,压素让路条款退役;格底参数域见 §4.1 硬指标(明度地板保留、饱和上限放宽),仍避 Boss 禁入色相带。与参考之别:ITB 以半透明压暗板承载信息,本作明度恒定(§2 硬规则),故用素色亮牌,压暗手法不采用。 +取 Moonlighter 的暖质地砖与亲和冒险者气质、Peglin 的明快全年龄洞穴色彩:全局暖倾向、无压抑。可读性由**格底明度分档**承载——已开格(数字所在格)明度走世界底层档(§2 明度分层;世界观同向:未开格=受光墙顶,已开格=挖出的空间自然沉暗,与 §8.5 图底分离同轴),亮族数字墨直接画在格底上,对比硬指标不变(≥4.5:1 恒成立)。**数字色牌降级为后备手段**——仅复杂格底(物件纹样/变异纹带/微光叠加致格底对比不足)时垫牌兜底(画法 §3.3、色值 §4.1)。格子本体美术自此放开:纹理、材质、装饰变体、类型纹样皆可入画;格底参数域见 §4.1 硬指标(分档明度域、饱和上限),仍避 Boss 禁入色相带。与参考之别:ITB 以半透明压暗板承载信息;本作格底功能分档(信息可读性服务,属 §2 明度分层允许域),情绪压暗仍禁。 -*设计测试:当格子美术与数字可读性冲突时,加牌、调牌,不动格子画。* +*设计测试:当格子美术与数字可读性冲突时,先调格底明度档,复杂格底垫色牌兜底,不动格子画。* **原则三|一砖一世界**(融合 Moonlighter 地砖观;锚定 P3 风险与收益同源、P4 地牢下探隐喻) 格子即地牢地砖:未开 = 覆尘完整砖,已开 = 碎裂裸露,雷 = 被惊动的巢穴(2026-09-12 隐喻换轴——雷格叙事属名 = 惩罚格、首发类型 = 怪物巢穴;旧称"已触发的机关"退役),图类型(board_type)= 同款地砖换色板。图类型与变异格的视觉差异一律先做色板变体,不做新资产;一切危险状态必须"形状 + 颜色"双通道冗余,色弱可辨。像 Moonlighter 之处在砖缝质感与暖色道具,但装饰不得伪装成逻辑差异——玩家须一眼分清"好看"与"有雷"。 -格子同时是**内容舞台**,格与格的美术表达按格内实态分层多样化(画法细则 §3.2):已开格按当格结果整格表达——产资源格嵌对应家族物件纹样(地图战斗资源九类型,§4.6.3)、纯安全格呈现干净裸土、雷格巢穴更凶;未开格在覆尘完整砖之上叠加**装饰变体**(裂纹/碎石斑等纹理级氛围层;装饰变体一律为纹理级,禁物件级——巨石/小石堆等读作"格子里有个东西"的元素与"格子=内容舞台"冲突,会跟奖励/旗子抢读;数量保持最少,约 2 种,用途仅为破除大面积同砖平铺的重复感;随机分布,与雷/安/类型零相关,不得构成可读线索;分布属初始化随机——棋盘生成期落定,禁逐轮重掷);未开格的类型预读 = **类型常显微光单通道**(色相+明度双码;仍只表达类型,不泄雷安——呈现契约见 §4.6.3;原「角嵌纹样形状通道」随 2026-09-28 角嵌退役批解除〔用户裁:微光格只留微光〕)。 +格子同时是**内容舞台**,格与格的美术表达按格内实态分层多样化(画法细则 §3.2):已开格按当格结果整格表达——产资源格嵌对应家族物件纹样(地图战斗资源九类型,§4.6.3)、纯安全格呈现干净裸土、雷格巢穴更凶;未开格在覆尘完整砖之上叠加**装饰变体**(裂纹/碎石斑/物件级点缀等氛围层;2026-09-29 v3.0 物件级解禁——物件级装饰〔小石块/陶片/骨殖等〕须走**专属装饰形状家族**:形与信息元素〔数字/小人/旗/纹样〕形状语言隔离,灰度下不与任何逻辑元素同形;零信息纪律不变——随机分布、与雷/安/类型零相关、不得构成可读线索、分布属初始化随机禁逐轮重掷;焦点预算约束不变——装饰不构成完整凸形、不抢读,§3.4;数量配额按图类型定,候选 3–5 种,样张 v3 冻结;用途=破除大面积同砖平铺的重复感);未开格的类型预读 = **类型常显微光单通道**(色相+明度双码;仍只表达类型,不泄雷安——呈现契约见 §4.6.3;原「角嵌纹样形状通道」随 2026-09-28 角嵌退役批解除〔用户裁:微光格只留微光〕)。 *设计测试:当新图类型或新变异格需要新视觉时,先换色板加形状,再谈新资产;当格子多样化与"好看/有雷"之辨冲突时,砍装饰,不动逻辑通道。* @@ -49,18 +49,20 @@ > 立意(自概念期 brainstorm 内联):扫雷数字可读性 × 暗色氛围的冲突 → 由一次格子样张测试定风格;具体形态由样张测试定稿。**样张** = 一张按本圣经参数画成的格子风格试验图,是砖面形态的定稿闸——样张通过前,§3.2/§4.1 的一切参数只是候选,通过后冻结为制作标准。 -**样张内容清单**(一图齐备,缺项即无效):未开格(覆尘完整砖,含至少两种装饰变体)、已开格(碎裂裸露,含 0 格与 1–8 全档数字)、雷格(被惊动的巢穴)、旗、小人两态(独立占格 + 与数字同格——后者须验"边框高亮不覆盖文本")、图类型色板变体组(§4.3 四槽换色,至少两套)、数字色牌呈现组(素底/装饰变体底/变异纹带底至少三种格底上各一组数字)、已开格结果表达组(纯安全格 + 至少两类型物件纹样)、**类型微光呈现组**(至少三个类型的常显微光在纯砖格上呈现,含两两相邻格微光并列;微光格内零角嵌/箭头/加号类附加图形——2026-09-28 用户裁决)。 +**样张内容清单**(一图齐备,缺项即无效):未开格(覆尘完整砖,含至少两种装饰变体)、已开格(碎裂裸露,含 0 格与 1–8 全档数字)、雷格(被惊动的巢穴)、旗、小人两态(独立占格 + 与数字同格——后者须验"边框高亮不覆盖文本")、图类型色板变体组(§4.3 四槽换色,至少两套)、数字呈现组(2026-09-29 v3.0:已开格底亮墨直画组 + 复杂格底色牌后备组——素底/装饰变体底/变异纹带底至少三种格底上各一组数字)、已开格结果表达组(纯安全格 + 至少两类型物件纹样)、**类型微光呈现组**(至少三个类型的常显微光在纯砖格上呈现,含两两相邻格微光并列;微光格内零角嵌/箭头/加号类附加图形——2026-09-28 用户裁决)。 **验收项按序判定,第一项不过 = 整张否决(数字可读性定风格,风格服从可读)**: -1. **第一验收项|数字可读性(硬指标,可测)**:1–8 全档数字在其**色牌**上 WCAG 对比 ≥4.5:1(§4.1 参数域:色牌素色恒定 L≥0.70、数字墨 L≤0.027);色牌在任意格底(素底/装饰变体底/变异纹带底)上完整可辨、牌缘灰度可分;0.5× 缩放抽检数字仍可辨;纹带/裂纹/巢穴纹/物件纹样不得侵入数字字形占位区(砖心留白,§3.2)。 -2. **格态三形可辨(灰度通道)**:未开/已开/雷三态转灰度截图后仍可逐格分类(§3.2 完整度叙事);装饰变体不得制造新的分类特征——同一格态下带与不带变体的灰度差异不得成为三态分类线索;色弱模拟(去色相)下旗、巢穴纹不与裂纹混淆;**五组类型微光互辨**——色弱玩家的类型主通道 = 微光(色相+明度双码,2026-09-28 角嵌退役后微光以明度梯度承载类型,§2 微光明度例外),微光不得侵入数字色牌占位区、明度梯度不得压破格底明度档(三态分类不受扰)。 +1. **第一验收项|数字可读性(硬指标,可测;2026-09-29 v3.0 改格底分档承载)**:1–8 全档数字对其所在**已开格底**直画 WCAG 对比 ≥4.5:1(§4.1 参数域:已开格底走世界底层档,候选 L 0.20–0.32;棋盘数字墨亮族,L≥0.55 候选——均待样张 v3 冻结);复杂格底(物件纹样/变异纹带/微光叠加致直画对比不足)启用**色牌后备**,牌墨组合 ≥4.5:1(色牌 L≥0.70、牌上数字用深墨族),牌缘灰度可分;0.5× 缩放抽检数字仍可辨;纹带/裂纹/巢穴纹/物件纹样不得侵入数字字形占位区(砖心留白,§3.2)。 +2. **格态三形可辨(灰度通道)**:未开/已开/雷三态转灰度截图后仍可逐格分类(§3.2 完整度叙事;v3.0 起明度差〔墙亮/空间暗〕为合法分类通道,与碎裂形双通道冗余);装饰变体不得制造新的分类特征——同一格态下带与不带变体的灰度差异不得成为三态分类线索;色弱模拟(去色相)下旗、巢穴纹不与裂纹混淆;**五组类型微光互辨**——色弱玩家的类型主通道 = 微光(色相+明度双码,2026-09-28 角嵌退役后微光以明度梯度承载类型,§2 信息面层内梯度),微光不得侵入数字字形占位区、明度梯度不得压破格底明度档(三态分类不受扰)。 3. **焦点预算成立(§3.4)**:任意一格至多一个完整凸形;数字所在格无第二焦点。 -4. **图类型换皮抽测(§4.3)**:变体组中数字墨三档、封印黑、危险红、奖励金、小人蓝、数字色牌、类型微光五组恒定不动;变体格底仍过第 1、2 项指标。 +4. **图类型换皮抽测(§4.3)**:变体组中数字墨亮族三档、封印黑、危险红、奖励金、小人蓝、数字色牌(后备件)、类型微光五组恒定不动;变体格底仍过第 1、2 项指标。 -**判定与回退**:第 1 项不过 → 按原则二设计测试回退——加牌、调牌(提牌墨对比/扩牌面积皆可),禁止缩字号换字形逃避;第 2–4 项不过 → 修形不修数。样张通过 = 砖面形态与色板冻结;新增图类型/变异色板须重跑本测试(§4.3)。执行时机:正式砖面资产开工前;《HUD框架》以本节为引用依据(2026-09-07 门禁:样张测试并入 art-bible 执行)。 +**判定与回退**:第 1 项不过 → 按原则二设计测试回退——先调格底明度档,复杂格底垫色牌兜底,禁止缩字号换字形逃避;第 2–4 项不过 → 修形不修数。样张通过 = 砖面形态与色板冻结;新增图类型/变异色板须重跑本测试(§4.3)。执行时机:正式砖面资产开工前;《HUD框架》以本节为引用依据(2026-09-07 门禁:样张测试并入 art-bible 执行)。 -> **样张 v2 记录(2026-09-28,四冻结生效)**:机检 16/16 全绿(扩展断言集:A3 图底分离 Δ≥55/F6 墙格顶面立面双明度带 Δ≥18/F7 整板悬崖 DEPTH_PX 与游戏渲染常量同源/A6 观感密度梯度均值 ≥4.70=v1 实测 4.09×1.15)。**四冻结**——①砖面形态:方案甲 21 瓦片+高墙感 D 投影档+整板悬崖(§3.2 高墙瓦片体系条定稿参数);②色板:小人蓝 #2E86DE/接触带微光 #D6ECFF/类型微光五组定稿(§4.1/§4.2);③动画方案:§8.4 帧数档冻结;④数字形制:色牌形制定稿(#F5EAD3 素色直角小牌+Fusion Pixel+字号 max(18, ceil(格边×0.5))+墨三档,§7.4)。产物=`artwork/mockups/sample-batch-v2-2026-09-28.png`,机检报告=`design/research/sample-v2-机检报告-2026-09-28.md`;气质终审=批末用户目检(闸形 A,2026-09-27 拍板)。 +**整屏样张闸(2026-09-29 v3.0 新增)**:格子样张验"格",整屏样张验"屏"——战斗屏/关卡屏/菜单屏/营地屏各出一张整屏样张,验收四项:①全部文字(含菜单/说明/tooltip/按钮)对其直接背景 ≥4.5:1(WCAG AA;大字〔≥18px 或加粗档〕底线 3:1、目标 4.5:1);②明度分层三档带成立(信息面层 > 世界中层 > 世界底层,层间灰度可分);③整屏焦点预算(§3.4:首焦唯一——数字区/立绘/主按钮,无第二焦点竞争;负空间服务焦点,不属空窗);④文字禁直接压纹理底(垫容器或罩层)。闸形 = **方向稿目检先行**(防"机检过闸但气质否决"式返工),目检过后机检冻结。执行时机 = 表现层落码批开工前;过闸前一切屏级视觉为占位临时态(§7.1 收口条款)。现行 §1.4 格子样张机检断言集中涉色牌/明度档条目随样张 v3 重跑同步改造(登记 06-待办清单)。 + +> **样张 v2 记录(2026-09-28,四冻结生效)**:机检 16/16 全绿(扩展断言集:A3 图底分离 Δ≥55/F6 墙格顶面立面双明度带 Δ≥18/F7 整板悬崖 DEPTH_PX 与游戏渲染常量同源/A6 观感密度梯度均值 ≥4.70=v1 实测 4.09×1.15)。**四冻结**——①砖面形态:方案甲 21 瓦片+高墙感 D 投影档+整板悬崖(§3.2 高墙瓦片体系条定稿参数);②色板:小人蓝 #2E86DE/接触带微光 #D6ECFF/类型微光五组定稿(§4.1/§4.2);③动画方案:§8.4 帧数档冻结;④数字形制:色牌形制定稿(#F5EAD3 素色直角小牌+Fusion Pixel+字号 max(18, ceil(格边×0.5))+墨三档,§7.4)。产物=`artwork/mockups/sample-batch-v2-2026-09-28.png`,机检报告=`design/research/sample-v2-机检报告-2026-09-28.md`;气质终审=批末用户目检(闸形 A,2026-09-27 拍板)。**(v3.0 注:四冻结之①砖面形态的数字承载面与④数字形制随色牌降级解冻,待样张 v3 重冻;②色板③动画维持冻结不变)** --- @@ -68,12 +70,12 @@ > 本节服从第 1 节宣言「明快的地牢,轻快的扫荡,仔细的推理」。能量值为全作统一 0–10 刻度:0 静谧 → 10 沸腾。 > -> **明度恒定(硬规则)**:全作所有状态共用同一基准明度,禁止以变亮/变暗作为情绪表达或状态区分手段(roguelike 失败重开,世界无光暗记忆)。状态区分只允许四种手段:**色相、饱和、运动、元素**。 +> **明度分层(硬规则,2026-09-29 v3.0 替代「明度恒定」)**:明度按视觉层分带——**信息面层**(数字/UI 数据/预告/语义标识)最高、**世界中层**(格底顶面/角色/物件)居中、**世界底层**(背景/纵深/远景/已开空间)可更低;层间明度差服务空间纵深与光照(Moonlighter 式洞穴层次)。**禁令保留**:明度变化仍禁止用于**状态表达与情绪表达**——状态区分只允许**色相、饱和、运动、元素**四手段;roguelike 失败重开,世界无光暗记忆;Darkest Dungeon 式压暗仍在 §9.2 反面清单。**允许域**:空间纵深、光照氛围、形体塑造(砖缘立体面既有例外上升为通则)。类型微光的明度梯度(§4.2)属信息面层内梯度,不扰世界层明度档。 ### 2.1 挖掘阶段(核心状态,占时最长) - **主情绪**:棋手式清明专注——视线始终被数字牵引,画面无一处杂音抢焦;久推不生视觉疲劳 -- **色彩性格**:全作基准明度;暖石色低饱和打底,高饱和只属于数字与旗 +- **色彩性格**:暖石色低饱和打底(世界中层),高饱和高亮只属于信息面层(数字与旗) - **氛围形容词**:清爽、井然、可读、耐心 - **能量**:2/10 - **承载元素**:可挖域**接触带呼吸微光**——光画在英雄格周界的接触面上(正交邻墙=整条边,斜向邻墙=共享角点+向两侧各延伸半条边,画法 §3.2,蓝族色 §4.2)——画面里唯一在动的,是玩家的思路 @@ -81,7 +83,7 @@ ### 2.2 轮末自动战斗结算 - **主情绪**:延迟兑现的清算爽感——扫雷之因逐行兑现为战果;完美排雷(零误标且至少标中一面旗——地图战斗资源 GDD 定稿,追加第二份清图兑付、结算带高光行)的高光兑现,以其为全场喝彩级的最高反馈档 -- **色彩性格**:明度不变,色彩转向金橙主导、饱和拉高;数字色转译为弹道色沿行推进 +- **色彩性格**:情绪不走明度(§2 禁令),色彩转向金橙主导、饱和拉高;数字色转译为弹道色沿行推进 - **氛围形容词**:酣畅、递进、一气呵成 - **能量**:7/10,随连击爬升 - **承载元素**:兑现光带逐行横扫棋盘,开格化箭雨、旗化暴击砸向敌人,因果全程可见可归因 @@ -89,7 +91,7 @@ ### 2.3 清图奖励与换图 - **主情绪**:短促丰收——宝箱揭盖式的喜悦,三五秒即收,不拖节奏 -- **色彩性格**:全屏饱和峰值:金粒喷泉与彩纸迸发,饱和瞬时拉满后回落,明度不变 +- **色彩性格**:全屏饱和峰值:金粒喷泉与彩纸迸发,饱和瞬时拉满后回落;明度不动(§2 情绪禁令) - **氛围形容词**:丰收、轻快、干脆 - **能量**:8/10,尖峰后速降 - **承载元素**:最后一格碎砖中喷出的金币喷泉,叮当落入 UI 钱袋 @@ -105,7 +107,7 @@ ### 2.5 战斗失败(冒险终结) - **主情绪**:温柔的惋惜与「再来一次」的邀请——有分量、不惩罚,像合上一册冒险日志 -- **色彩性格**:明度不变,色相转暖灰掺暮蓝;全作禁血红与黑场,唯此一拍最静 +- **色彩性格**:情绪不走明度(§2 禁令),色相转暖灰掺暮蓝;全作禁血红与黑场,唯此一拍最静 - **氛围形容词**:惋惜、安静、余温、可再来 - **能量**:1/10 - **承载元素**:小人坐在碎砖上摇头掸灰,插过的旗(封印印记)逐面化作光点收回行囊 @@ -121,7 +123,7 @@ ### 2.7 下探过渡(关卡间) - **主情绪**:纵深的期待——「下面还有一层」的探险引力,如降落时一瞬失重 -- **色彩性格**:明度恒定,整层色板随图类型(board_type)递进换挡,以色相层进预告「更深更险」 +- **色彩性格**:整层色板随图类型(board_type)递进换挡,以色相层进预告「更深更险」;世界层明度带允许随深度整体微移(空间纵深表达,非情绪——候选,整屏样张冻结) - **氛围形容词**:纵深、期待、换气、进阶 - **能量**:4/10 - **承载元素**:镜头沿竖井匀速下移,两侧砖层色板渐变,预演下一层主色 @@ -156,16 +158,16 @@ ### 3.2 环境几何 -- **雷图棋盘呈现基准**:战棋地块质感 × 正俯视角——取 ITB 参考图(`references/itb_1.jpg`)的地表质感骨架:地块纹理多样、起伏体块感、岛缘/砖缘厚度、格上装饰小立牌;但相机一律正上方垂直向下,格线屏轴对齐,**禁等距/斜视角与菱形格**;形状语言仍守总纲圆角方形。砖缘厚度与岛缘立体面属形体塑造,不属状态/情绪表达,不受 §2 明度恒定硬规则约束(顶面格底仍守 §4.1 参数域);装饰小立牌属 ITB 参考的观感元素,本作不采用——装饰变体一律纹理级(见下方装饰变体条),零信息纪律不变。←原二;原三;§2 +- **雷图棋盘呈现基准**:战棋地块质感 × 正俯视角——取 ITB 参考图(`references/itb_1.jpg`)的地表质感骨架:地块纹理多样、起伏体块感、岛缘/砖缘厚度、格上装饰小立牌;但相机一律正上方垂直向下,格线屏轴对齐,**禁等距/斜视角与菱形格**;形状语言仍守总纲圆角方形。砖缘厚度与岛缘立体面属形体塑造,不属状态/情绪表达,不受 §2 情绪明暗禁令约束(2026-09-29 v3.0:本例外上升为 §2 明度分层允许域通则;顶面格底仍守 §4.1 参数域);装饰小立牌属 ITB 参考的观感元素,本作不采用——装饰变体一律纹理级(见下方装饰变体条),零信息纪律不变。←原二;原三;§2 - **地砖**:一切环境体由同一圆角方形衍生:未开=完整凸砖,已开=同形缺角碎裂,雷=碎裂加巢穴纹(被惊动的巢穴——2026-09-12 换轴,旧称"机关纹"退役);只以"完整度"叙事,不为状态新造形。←原三;P4 -- **装饰变体(未开格氛围层)**:覆尘完整砖之上叠加裂纹/碎石斑等低对比装饰;装饰变体一律为**纹理级**,禁物件级(巨石/小石堆等读作格子内容的元素),数量保持最少(约 2 种,用途仅为破除大面积同砖平铺的重复感),一律残缺、内凹、低对比而自然后退(§3.4);零信息纪律(分布随机、与雷/安/类型零相关、灰度下不得制造新分类特征、分布属初始化随机禁逐轮重掷)以原则三为准,此处不赘。←原三 +- **装饰变体(未开格氛围层)**:覆尘完整砖之上叠加裂纹/碎石斑/物件级点缀等装饰;2026-09-29 v3.0 物件级解禁——物件级装饰(小石块/陶片/骨殖等)须走**专属装饰形状家族**(与信息元素形状语言隔离、灰度下不与任何逻辑元素同形),数量配额按图类型定(候选 3–5 种,样张 v3 冻结),一律残缺、内凹、低对比而自然后退(§3.4);零信息纪律(分布随机、与雷/安/类型零相关、灰度下不得制造新分类特征、分布属初始化随机禁逐轮重掷)以原则三为准,此处不赘。←原三 - **结果整格表达(已开格)**:已开格按当格结果整格表达(结果清单见原则三);画法——产资源格的家族物件纹样用 §3.1 道具点剪影语言(直线几何体)角嵌于砖缘,砖心与数字字形占位区留白(已开格仍承载数字);雷格巢穴纹较已开格更凶一档,形状+颜色双通道不变。←原三;P3 - **类型角嵌纹样(未开格预读·形状通道)——已退役(2026-09-28 用户裁「微光格只留微光,不加箭头/加号类附加形」)**:类型预读改类型微光单通道(色相+明度双码,色带 §4.2);色弱类型主通道 = 微光明度梯度(§2 微光明度例外)。历史:原为墨族四角纹样+微光双通道(2026-09-22 T1 裁决立,2026-09-28 退役)。←原一;原三;角嵌退役批 2026-09-28 - **旗(封印印记)**:插旗动作的叙事呈现 = **封印**(玩家可见专名,2026-09-25 用户拍板,registry terminology 登记)——玩家对未开格插旗,即对该格(巢穴)实施封印,旗 = 封印印记;封印色(§4.1,现行封印黑)与格内优先级栈位(§1.2)不变。封印特效(施印瞬间 + 印记常显形态)待表现批,资产归清单 §4 演出类;现行程序化占位 = 封印黑「旗」字形(棋盘惯例:贴图在位=字形退役)。←原一;P2;术语批 2026-09-25;封印紫批 2026-09-26;封印黑批 2026-09-28 - **可挖域接触带微光(交互反馈层,2026-09-25 用户拍板)**:挖掘期,英雄格周界与可挖墙(8 向相邻未开格)的接触面画呼吸微光——正交邻墙=该侧整条边,斜向邻墙=共享角点+向两侧各延伸半条边;光只画英雄格(空间)一侧、不进墙格(与装饰变体零冲突,数字砖心不涉)。世界观口径:未开格=墙、已开格=挖出的空间,微光=空间的灯光边界。色相=蓝族浅一档(§4.2 蓝条;与主角蓝框的分层归样张批);呼吸=§2.1 挖掘期唯一在动元素,减动效停格。角点为斜墙与正交墙共享、不逐格归因,逐格指认=悬停金框(现役)。旧「墙格整框绿相呼吸」随本条退役(实现切换归表现批,`DIG_EDGE` 绿相退役)。←§2.1;§4.2;P1 - **墙体**:圆角砌块堆叠,禁尖刺装饰——尖刺专属危险语义,装饰不得伪装逻辑差异。←原三 - **高墙瓦片体系(2026-09-26 定稿,样张批追认)**:未挖格=**一整块 32×32 自含凸起岩体**(方案甲核心定义);素材语义名——未开格素材=**墙瓦片**,已开格素材=**地面瓦片**(术语 2026-09-26 用户立)。**边界=墨线纪律**:墙瓦片与相邻格分界一律 1px 深墨线、直线贴格边、零锯齿;墨线职责=分隔,不追求与地面融合(Tiny Dungeon 样图实证调研,见 `design/research/terrain-walls-source-evaluation-2026-09-25.md`)。**光照=单一北受光**:北缘=墨线内侧 1px 微亮棱(就地取色提亮,禁宽亮带);西/东缘=墨线后直进纹理、不加修饰;南缘=墨线+立面窄暗条(约 1/3 格高,横层理叠石、禁竖条纹栅栏感)。**凹角**:角点单像素落线;南立面侧凹角加 1px 立面收头——带身与转角竖线同列收尾,禁悬空、禁突出(v9.1/v9.2 两版返工实证)。现行定稿=`game/assets/art/board/terrain_*`(16 唯一墙瓦片+5 地面瓦片变体;词表与查表逻辑见 `design/research/board-tile-vocab-plan-a-2026-09-26.md`)。**高墙感 D 投影档+整板悬崖(样张 v2 定稿 2026-09-28,用户 2026-09-27 四变体挑档)**:南临空墙格=立面口沿高光 2px `Color8(196,172,132)`+双段暗带(0.16/0.25 格边,黑罩 α0.60/0.82);北邻墙地面格=三段渐隐投影(顶带 0.22 格边,α0.28 起);整板悬崖=板底/右侧 `DEPTH_PX 8px` 暗面+列分隔竖缝+岩层横纹+口沿高光+接触 AO+底线收边+悬浮影(游戏 `board_world.gd` 同款结构件,样张脚本与游戏渲染常量同源——机检 F7 承载)。←原三;台账 164;样张 v2 批 2026-09-28 -- **变异格形状通道**(双通道之"形",与色无关):底砖圆角外轮廓不变,砖面内缘绘一圈定宽专属几何纹带(纹带形全作不与他类共用),砖心留白予数字与旗;验收标准=**灰度截图下仍可分类**。种类清单 = 地形变异六类型已定稿(地形变异 GDD;荆棘丛/藤蔓缠绕/岩浆/烬覆/落石/矿尘):**纹带形按轴只分两种**——伤害轴(荆棘丛/岩浆/落石)= 刺/缺排斥形,信息轴(藤蔓缠绕/烬覆/矿尘)= 遮蔽/缠绕形;同轴跨图类型只做色板变体(§4.3 `variant_tint` 槽),不做新纹形。样张批增查:岩浆纹带橙红须与危险红互辨(变异格不是雷,色相邻近混淆风险);信息轴遮蔽呈现不得侵入数字色牌占位区(§1.4 验收 1 延伸)。←原一(纹理位次第 4,让位于数字/小人/旗);原三 +- **变异格形状通道**(双通道之"形",与色无关):底砖圆角外轮廓不变,砖面内缘绘一圈定宽专属几何纹带(纹带形全作不与他类共用),砖心留白予数字与旗;验收标准=**灰度截图下仍可分类**。种类清单 = 地形变异六类型已定稿(地形变异 GDD;荆棘丛/藤蔓缠绕/岩浆/烬覆/落石/矿尘):**纹带形按轴只分两种**——伤害轴(荆棘丛/岩浆/落石)= 刺/缺排斥形,信息轴(藤蔓缠绕/烬覆/矿尘)= 遮蔽/缠绕形;同轴跨图类型只做色板变体(§4.3 `variant_tint` 槽),不做新纹形。样张批增查:岩浆纹带橙红须与危险红互辨(变异格不是雷,色相邻近混淆风险);信息轴遮蔽呈现不得侵入数字字形占位区(§1.4 验收 1 延伸)。←原一(纹理位次第 4,让位于数字/小人/旗);原三 ### 3.3 UI 形状语法(方向指导,细则迁 §7.1) @@ -173,7 +175,7 @@ ### 3.4 主角形状与对比预算 -显著度=完整度:**每格至多一个"完整凸形"**(数字/小人/旗,依 1.2 优先级让位;装饰变体贴砖缘分布、不构成第二完整凸形——§4.6;数字色牌随数字一体,不作独立焦点;类型微光为底效泛光,不作焦点、不抢完整凸形预算),底砖与装饰一律残缺、内凹、低对比而自然后退;危险用刺与缺(排斥形),收益用满与圆(吸引形),同表预算、此消彼长。与参考分界:ITB 以色块对比分配焦点;本作明度恒定(§2 硬规则),故改以"完整度"分配焦点,不靠明暗抢焦。←原二;P1;P3 +显著度=完整度:**每格至多一个"完整凸形"**(数字/小人/旗,依 1.2 优先级让位;装饰变体贴砖缘分布、不构成第二完整凸形——§4.6;数字色牌随数字一体,不作独立焦点;类型微光为底效泛光,不作焦点、不抢完整凸形预算),底砖与装饰一律残缺、内凹、低对比而自然后退;危险用刺与缺(排斥形),收益用满与圆(吸引形),同表预算、此消彼长。焦点分配双机制(2026-09-29 v3.0):**完整度**(形状,本条上文)+**明度带**(§2 明度分层——信息面层恒亮于世界层,焦点天然落信息面);明暗只做层间分离,层内禁明暗竞争(不靠明暗抢焦纪律不变)。←原二;P1;P3 --- @@ -186,23 +188,25 @@ ### 4.1 主色板 - **掩尘 `#C9AF83`**|未开格底色,覆尘完整砖:全作的"未知",画面最大沉默面。←原二;§2.1 -- **裸土 `#B39A78`**|已开格底色,碎裂裸露:更收更退,靠碎裂形分辨。←原三 -- **数字墨 `#33261B` 族**|1–8 **不做八色分色**,按密度分三档色温:1–3 青墨 `#132E36`、4–5 赭墨 `#3C250C`、6–8 锈墨 `#4A1E14`;**字形为唯一数值载体**,色温只作密度氛围(冷=稀疏,暖=密集)。八色必与红金蓝紫赤语义冲突,故弃。←原一/原二;P3 +- **裸土 `#B39A78`**|已开格底色,碎裂裸露:更收更退;2026-09-29 v3.0 明度分层——已开格(挖出的空间)走**世界底层档**,明度低于未开格墙体一档(与 §8.5 图底分离同轴),候选 L 0.20–0.32 带,样张 v3 冻结。←原三 +- **数字墨双色制(2026-09-29 v3.0)**|1–8 **不做八色分色**,按密度分三档色温(冷=稀疏,暖=密集);**字形为唯一数值载体**,色温只作密度氛围。①**棋盘数字墨=亮族**(直画已开格底,世界底层档上的信息面层):三档色温方向 1–3 冷亮青白/4–5 暖白/6–8 金亮,L≥0.55 候选,样张 v3 冻结(旧深墨三档 `青墨 #132E36/赭墨 #3C250C/锈墨 #4A1E14` 转垫牌场景与 UI 用墨);②**垫牌与 UI 数据墨=深墨族 `#33261B` 系**(L≤0.027 不变,§7.2)。八色必与红金蓝紫赤语义冲突,故弃。←原一/原二;P3 - **封印黑 `#000000`**|封印(插旗)宣告色,无色相:玩家的宣告"此格封印"(色史:旗朱 `#C63D22` →封印紫 `#7C3AA8` 2026-09-26→**封印黑 2026-09-28 用户拍板**——紫色与微光蓝族〔魔法微光 256° 等〕色相冲突,黑色无色相天然避开 300°–345° 禁入带与全部微光色带;未开格墙顶明度 ≈113 对纯黑对比 ≥4.4:1,旗杆米白保可读)。旗朱随封印紫批退役〔棋盘侧〕,红族棋盘侧自此只剩危险红(2026-09-28 起人设背包旗=旗朱红矩形旗——旗色脱钩拍板,人设侧详见 character-design 背包旗条)。←原一;P2;封印紫批 2026-09-26;封印黑批 2026-09-28 - **危险红 `#A8321F`**|危险色:雷=被惊动的巢穴,兑现档红,更深更沉(2026-09-13 更名,旧称"机关红"随隐喻换轴退役;色值不变)。←原三;P2 - **奖励金 `#F0A828`**|已兑现的收益:金币/宝箱/蜡封,全作唯一亮金。←P2;§2.3/2.4 - **小人蓝 `#2E86DE`**|小人主色:棋盘唯一"己方",与光标准线同族(样张 v2 定稿 2026-09-28;游戏 UiKit.HERO_BLUE 已同步 #2E6E8E→#2E86DE)。←P1;§2.1 -- **数字色牌 `#F5EAD3`**|数字底具:素色暖纸白直角小牌,数字一律垫于其上;素面无纹理、不随图类型/装饰变体变,数字可读不依赖格底即由本牌承载。←原二 +- **数字色牌 `#F5EAD3`**|数字底具,2026-09-29 v3.0 降级为**后备手段**:素色暖纸白直角小牌,仅复杂格底(物件纹样/变异纹带/微光叠加致直画对比不足)垫于数字正下方;素面无纹理、不随图类型/装饰变体变。←原二 -**对比硬指标(可测)**:数字可读性由色牌承载——**数字色牌素色恒定 L≥0.70、一切数字墨 L≤0.027**(WCAG 相对亮度)⇒ 任意牌墨组合 **≥4.5:1 恒成立**(WCAG AA)。实测样例:#33261B / #F5EAD3 = **12.3:1**;#4A1E14 / #F5EAD3 = **11.8:1**;#132E36 / #F5EAD3 = **12.0:1**。格底槽(含全部图类型)相对亮度 **L≥0.30**(明亮为皮)、HSV 饱和 **≤0.55**、避 Boss 禁入色相带——格底不再承担数字对比义务;物件识别不依赖格底(§5.1 轮廓通道),旗面、金色不作识别依赖。←原二;地形变异 AC-9 +**对比硬指标(可测;2026-09-29 v3.0 改写)**:数字可读性由**格底明度分档**承载——棋盘数字亮墨 **L≥0.55**(候选)对**已开格底 L 0.20–0.32**(候选)⇒ 直画对比 **≥4.5:1 恒成立**(WCAG AA,样张 v3 逐组合抽测冻结);**色牌后备**:色牌素色恒定 **L≥0.70**、牌上数字深墨 **L≤0.027** ⇒ 任意牌墨组合 ≥4.5:1(实测样例:#33261B/#F5EAD3 = 12.3:1)。未开格底槽(含全部图类型)相对亮度 **L≥0.30**(墙顶面受光档)、HSV 饱和 **≤0.55**、避 Boss 禁入色相带;已开格底走世界底层档(上见)。物件识别不依赖格底(§5.1 轮廓通道),旗面、金色不作识别依赖。←原二;地形变异 AC-9 ### 4.2 语义色彩规则 -- **红只说危险**:危险红=兑现档(旗朱预告档随封印紫批退役,红族单档)。禁:红不得用于奖励、装饰与常规 UI(微光群伤组除外——其为类型先验色带域,见「类型微光色带」条,色相刻意错开语义红)。←原三;P2;§2.1;封印紫批 2026-09-26 -- **金只说收益与兑现**(奖励、结算、胜利)。禁:金不得作危险障碍色、不上格底、不作日常 UI 强调(防通胀;微光通用增益组的芥末黄 = 类型先验色带域,非收益语义金)。←P2;P3;§2.2–2.4 -- **蓝只说己方与冷静信息**(小人、光标、工具信息——含可挖域接触带呼吸微光,蓝族浅一档 `#D6ECFF`〔样张 v2 定稿 2026-09-28,游戏 UiKit.CONTACT_GLOW 同值〕,2026-09-25 拍板;旧可挖域绿相随接触带方案退役)。禁:蓝不得表示敌方危险;暮蓝 `#5A6C8C` 为失败独占(§2.5),只作全屏氛围,不作物件色。←P1;§2.5 -- **紫赤只说 Boss 与精英** `#8F2F6A`(色相 323°):郑重来自色相独占,不来自压暗。禁:**HSV 色相 300°–345° 为全场禁入带**,其余资产(含 UI 与粒子、含类型微光)及图类型色板不得落入。←§2.6;原三 -- **绿只说自然生机**(环境植被;恢复类状态若有则用绿——待增益状态定夺)。**例外:类型微光治疗组**(类型先验色带,见下条)。禁:绿不得承载逻辑状态(微光色带除外),不得与红构成唯一区分对。←原三;T1 裁决 2026-09-22 +> **适用域(2026-09-29 v3.0 立)**:本节「X 只说 Y」约束**信息层**(格内信息/UI 数据/预告/语义标识)与**语义物件**(金币=收益金、血条=危险红等);**纯环境氛围**(背景/装饰变体/远景/非语义物件)不受色相独占约束,改受 §3.4 焦点预算与低饱和后退约束(不抢读即可用色)。禁入带 300°–345°:信息层与语义物件禁入不变;环境层可入但限低饱和(高饱和紫赤仍 Boss 独占,§2.6)。 + +- **红只说危险**:危险红=兑现档(旗朱预告档随封印紫批退役,红族单档)。禁(信息层域):红不得用于奖励、装饰性标识与常规 UI(微光群伤组除外——其为类型先验色带域,见「类型微光色带」条,色相刻意错开语义红)。←原三;P2;§2.1;封印紫批 2026-09-26 +- **金只说收益与兑现**(奖励、结算、胜利)。禁(信息层与语义物件域):金不得作危险障碍色、不上格底、不作日常 UI 强调(防通胀;微光通用增益组的芥末黄 = 类型先验色带域,非收益语义金)。←P2;P3;§2.2–2.4 +- **蓝只说己方与冷静信息**(小人、光标、工具信息——含可挖域接触带呼吸微光,蓝族浅一档 `#D6ECFF`〔样张 v2 定稿 2026-09-28,游戏 UiKit.CONTACT_GLOW 同值〕,2026-09-25 拍板;旧可挖域绿相随接触带方案退役)。禁(信息层域):蓝不得表示敌方危险;暮蓝 `#5A6C8C` 为失败独占(§2.5),只作全屏氛围,不作物件色。←P1;§2.5 +- **紫赤只说 Boss 与精英** `#8F2F6A`(色相 323°):郑重来自色相独占,不来自压暗。禁:**HSV 色相 300°–345° 为信息层与语义物件禁入带**——UI、粒子、类型微光、语义物件及图类型色板信息面不得落入;环境层(背景/装饰)可入但限低饱和,高饱和紫赤仍 Boss 独占(2026-09-29 v3.0 域限定)。←§2.6;原三 +- **绿只说自然生机**(环境植被;恢复类状态若有则用绿——待增益状态定夺)。**例外:类型微光治疗组**(类型先验色带,见下条)。禁(信息层域):绿不得承载逻辑状态(微光色带除外),不得与红构成唯一区分对。←原三;T1 裁决 2026-09-22 - **类型微光色带 = 格面类型先验专用逻辑色带**(2026-09-22 用户裁决,未开格类型预读的色彩通道):未开格常显类型微光属逻辑信息色彩,五组色相——**通用增益组**(attack/defense/weaken/action/gp 五族)芥末黄 `#D6C13A`(≈52°)、**治疗组**(heal)黄绿 `#5CB83A`(≈104°)、**穿刺组**(pierce)青 `#2E9E9E`(≈180°)、**魔法组**(magic)紫罗兰 `#7B5BD6`(≈256°)、**群伤组**(blast)绯红 `#FF2D55`(≈349°,刻意避开危险红色相段与 300°–345° 禁入带)——**样张 v2 定稿(2026-09-28)**,组间互辨抽检随机检报告;v2 呈现参数=内缘带状泛光 α170/带宽 cell÷8(亮度不压格底明度档,§2 微光例外)。分域纪律:微光色相只承载类型先验,不迁移复用为物件/阵营/UI 语义色;微光 = **色相+明度双码**(2026-09-28 角嵌退役批起明度梯度承载类型——§2 微光明度例外:梯度不得压破格底明度档/三态分类);色弱玩家的类型主通道 = 微光双码。←T1 裁决 2026-09-22;角嵌退役批 2026-09-28;§4.6.3 - **金/红兼作极性色相槽(§4.6)**:极性(白话:同一次兑付的正负方向——正 = 收益侧,负 = 代价侧;行为×格型→符号矩阵见极性提案 R2)的视觉取色只在这两族间——有利兑付 = 金族,有害兑付 = 红族,不新增语义色。←§4.6;原二 @@ -210,11 +214,12 @@ **换皮只换四槽,永不变信**。模板按棋盘生成产物 `board_type` 标签直接消费(键名与词表事实源 = 棋盘生成 GDD 与 `board_gen.tres`:dungeon / underdark / deep_underdark);清单与词表 owner 待 关卡节点地图/地形变异/地图战斗资源,本节只定模板: -- `tile_closed` 未开底 / `tile_open` 已开底:L 与饱和同 4.1 硬指标(L≥0.30、饱和 ≤0.55),避禁入色相带 +- `tile_closed` 未开底:L 与饱和同 4.1 硬指标(墙顶面受光档 L≥0.30、饱和 ≤0.55),避禁入色相带 +- `tile_open` 已开底:世界底层档(2026-09-29 v3.0,候选 L 0.20–0.32,样张 v3 冻结)、饱和 ≤0.55,避禁入色相带 - `wall_ambient` 墙雾氛围 tint:可带主题色相,L≥0.30 - `variant_tint` 变异纹带染槽:只改色相不改纹形(纹带形按轴两分,见 §3.2 变异格形状通道;种类 = 地形变异六类型已定稿) -**不变槽**:数字墨三档、数字色牌、封印黑、危险红、奖励金、小人蓝、紫赤、绿、类型微光五组——**信息与语义层全图类型恒定**,换挡只动色相饱和、不动明度档(§2 硬规则)。新增色板须重跑 §1.4 格子样张(灰度可辨+对比抽测)。←原三/原二;地形变异 AC-9 +**不变槽**:棋盘数字墨亮族三档、数字色牌(后备件)、封印黑、危险红、奖励金、小人蓝、紫赤、绿、类型微光五组——**信息与语义层全图类型恒定**;换挡动色相饱和,格底两档明度关系(墙亮/空间暗)全图类型恒定(§2 明度分层)。新增色板须重跑 §1.4 格子样张(灰度可辨+对比抽测)。←原三/原二;地形变异 AC-9 ### 4.4 UI 色板(方向指导,细则迁 §7.2) @@ -343,9 +348,10 @@ ### 6.1 战斗舞台背景(B 区环境) -- **双舞台常驻下的 B 区环境**:战斗画面区(站桩立绘所在)的背景 = 明亮地窟,与 §1 风格基调同源——暖倾向、高亮度、无压抑;背景整体**低对比自然后退**(§3.4 焦点预算延伸):背景不得构成完整凸形、不得抢 B 区立绘与 D 区数字的焦点,识别层级恒为 立绘 > 背景。 -- **明度恒定适用**:背景氛围不得以压暗/渐晕表达(§2 硬规则);纵深与洞穴感靠色相、饱和与形体承载(砖缘厚度/立体面属形体塑造,§3.2 同款豁免逻辑——不属情绪明暗)。 -- **图类型联动**:背景 tint 走 §4.3 `wall_ambient` 槽,随三关换挡(方向候选见 §6.3);紫赤仅 Boss 战允许短暂进入背景氛围纹样(§2.6 色相独占的舞台侧延伸),非 Boss 战禁入。 +- **双舞台常驻下的 B 区环境**:战斗画面区(站桩立绘所在)的背景 = 明亮地窟,与 §1 风格基调同源——暖倾向、无压抑;背景整体**低对比自然后退**(§3.4 焦点预算延伸):背景不得构成完整凸形、不得抢 B 区立绘与 D 区数字的焦点,识别层级恒为 立绘 > 背景。 +- **舞台正面目标(2026-09-29 v3.0 新增——原条只有负面约束,病根 6)**:B 区 = **地窟看台**——立绘脚下地台/落影承载(世界中层),背景环境层低饱和后退、明度走世界底层档,允许光源氛围(洞顶光柱/暖光晕候选);角色不得直接贴平色底。规格与终值归整屏样张闸(§1.4)冻结。 +- **明度分层适用(2026-09-29 v3.0 改条)**:背景氛围的情绪表达仍不得以压暗/渐晕实现(§2 禁令);空间纵深与洞穴感走明度分层允许域——世界底层档、光照氛围、色相饱和与形体承载(§3.2 同款逻辑)。 +- **图类型联动**:背景 tint 走 §4.3 `wall_ambient` 槽,随三关换挡(方向候选见 §6.3);紫赤仅 Boss 战允许短暂进入背景氛围纹样(§2.6 色相独占的舞台侧延伸,高饱和独占不变),非 Boss 战高饱和紫赤禁入。 - **资产渠道**:✦ 插画级(演出类场景贴图,清单 §4 联动登记),排期归表现层升级批;战斗一屏样张(§1.4 清单 1.2)含背景出样。 ### 6.2 营地场景 @@ -365,7 +371,7 @@ ### 6.4 关卡间下探过渡 -- **视觉承载**(§2.7 情绪的画法面):竖井下移镜头,两侧砖层色板渐变,预演下一层主色——渐变取色 = 下一关 `tile_closed`/`wall_ambient` 槽候选值入画,只动色相/饱和,明度恒定。 +- **视觉承载**(§2.7 情绪的画法面):竖井下移镜头,两侧砖层色板渐变,预演下一层主色——渐变取色 = 下一关 `tile_closed`/`wall_ambient` 槽候选值入画,只动色相/饱和;明度带随深度微移候选归 §2.7(空间纵深表达,非情绪)。 - **资产与排期**:程序化色板渐变(⚙ 脚本管线),无独立插画需求(候选);演出编排与时序归冒险结构/战斗表现 GDD,本节只定渐变取色与明度纪律。 --- @@ -376,14 +382,17 @@ ### 7.1 形状语法细则(自 §3.3 迁入) -**半拟物:容器穿戏服,数据素面。**面板=石板圆角矩形(与地砖同圆角率,全 UI 恒定),按钮=凸圆角的"可按的砖"(按压态=下沉一档,运动手段 §2),仪式性确认(胜利等)=圆形蜡封(呼应 §2.4);数字框、准线、进度条一律直角细线、无纹理;**数字色牌 = 直角小素牌**——宽随数字位、无纹理无装饰,垫于数字正下方一层(色值 §4.1),属"须精确的信息"侧、走直角律。判据:圆角=可触摸的物件,直角=须精确的信息。与参考分界:取 ITB 的信息分层,弃其冷硬斜切 HUD;取 Moonlighter 的木石亲和,不做全拟物。 +**半拟物:容器穿戏服,数据素面。**面板=石板圆角矩形(与地砖同圆角率,全 UI 恒定),按钮=凸圆角的"可按的砖"(按压态=下沉一档,运动手段 §2),仪式性确认(胜利等)=圆形蜡封(呼应 §2.4);数字框、准线、进度条一律直角细线、无纹理;**数字色牌 = 直角小素牌**(2026-09-29 v3.0 后备件)——宽随数字位、无纹理无装饰,仅复杂格底兜底时垫于数字正下方一层(色值 §4.1),属"须精确的信息"侧、走直角律。判据:圆角=可触摸的物件,直角=须精确的信息。与参考分界:取 ITB 的信息分层,弃其冷硬斜切 HUD;取 Moonlighter 的木石亲和,不做全拟物。 - **极性强调冗余**(§4.5⑦):UI 红/金强调对必须补图标+文案冗余;破坏性确认与常规确认不得同位(位置通道)。 - **资产渠道**:♻ 九宫格面板/按钮改色过复用闸优先(清单 §0),⚙ 兜底;样式终稿归样张后表现批。 +- **占位收口条款(2026-09-29 v3.0 新增,病根 8)**:程序化占位 = **临时态**,任何屏的终稿闸 = §1.4 整屏样张过闸;占位态不得跨里程碑;已在包资产(panel_stone/button_stone 等)接线归最近表现批,不得以"占位不空窗"为由长期挂账。 - **实现侧边界**:样式收敛 ui_kit(程序化占位为结构冻结现行;色值同步义务归样张批冻结后的表现批);ui_kit 的工程契约归 HUD框架,本节不重述。 ### 7.2 UI 色板细则(自 §4.4 迁入) +**全局文字可读性硬指标(2026-09-29 v3.0 新增,病根 7)**:**一切文字**(含菜单/说明/tooltip/按钮/底栏,无区域例外)对其直接背景 **≥4.5:1**(WCAG AA);大字(≥18px 或加粗档)底线 3:1、目标 4.5:1;**文字禁直接压纹理底**——垫容器或罩层(现行菜单说明 2.58:1、C 区属性行 1.31:1 式违例自此有条款可依,修复归表现批)。核验闸 = §1.4 整屏样张。 + **数据素面的墨来自世界的墨**:UI 数字、进度、准线一律主墨 `#33261B` 系——棋盘与面板读同一种墨;容器穿木石材质色,数据只穿墨。**营地与棋盘**:菜单容器背景用全作最暖的烛光黄 `#F6C667` 与木色 `#8A5A34`(§2.8;场景构成 §6.2);战斗容器转中性石色,防暖色渗入棋盘分走数字对比预算——氛围色向可读色让路。UI 不新增语义色,一切强调沿用 §4.2。**暗底呈现态双色墨制**(关卡画面样张 v1 冻结 2026-09-28):暗底系(已过/未来/候选/Boss 方块、暗数据框)图标与读数一律暖白 `#F0E2C8`(WARM)、亮底(当前金 `#F0A828`)转深墨 `#181410`(INK_ROUTE)——各态对比 ≥4.5:1;已过节点暗金冻结 `GOLD_DONE #68562C`(专用呈现态值,旧 GOLD_DIM `#8C743C` 对双色墨均不达标退役出该呈现位);Boss 描边 = 紫赤 2px + 外缘 1px 深墨环(灰度冗余通道——§4.2 色相独占本色不变,§4.5 灰度可分类承载)。 ### 7.3 布局栅格 @@ -394,8 +403,8 @@ ### 7.4 字体与字号 - **字体**:全局一套像素字——拉丁候选 Kenney Fonts(CC0)、中文候选缝合像素字体 Fusion Pixel(OFL)(清单 §3.6);墨色走主墨系(§7.2);换字体 = 全局决策,接入归表现批。 -- **字号**:像素字体**整数倍缩放,禁非整数缩放**(像素模糊);下限(1280×800 基座,事实源 HUD框架):棋盘数字 ≥18px、明细正文 ≥14px、tooltip ≥13px;棋盘数字字号 = max(18, ceil(格边长 × 0.5))。 -- **字重纪律**:像素字不作字重区分——层级靠字号两档(标题/正文,候选)+墨色深浅;数字禁描边/阴影伪加粗(字形为唯一数值载体,§4.1 同源纪律)。 +- **字号**:像素字体**整数倍缩放,禁非整数缩放**(像素模糊);下限(1280×800 基座;2026-09-29 v3.0 对齐 ux-designer PC 规范):棋盘数字 ≥18px(公式 = max(18, ceil(格边长 × 0.5))不变)、**正文/明细 ≥16px、tooltip ≥14px**(旧 14/13px 下限退役——1280×800 低于 1080p 基准,同字号实际更小)。 +- **字重纪律(2026-09-29 v3.0 修订)**:层级手段解禁为三件——**字号档差(相邻层级 ≥1.25×)+ 墨色深浅 +(字体支持时)字重两档**;数字禁描边/阴影伪加粗不变(字形为唯一数值载体,§4.1 同源纪律)。 ### 7.5 营地界面 @@ -420,6 +429,7 @@ - **主角战斗状态图(含 B 区站桩侧向)= 48×72**(同上暂定;v1.9 待决注记「主角立绘档空缺」由此收口); - **棋盘小人 = 32×32 二头身派生版(暂定,允许更小)**——独立资产,自人设定稿压缩派生(人物设计档 §5.4),不吞数字位、占位 ≤ 0.75× 格边长;36px 板 × 32px 源的占比摩擦(v1.9 待决注记①)沿「独立小源档」路线随格边长终值在样张批定终值; - **敌种站桩立绘三档 = 48/64/96px 级(候选)**——对应体量三档:普通怪(小)/精英(中)/Boss(大),体量单调递增(§5.1);终值归战斗一屏样张批。 + - **档位上调方向(2026-09-29 v3.0 新增候选,病根 6)**:1280×800 屏上角色存在感不足(主角占屏高约 9%,Moonlighter 约 15%)——升档方向候选:主角立绘 48×72 → **64×96 档**、敌立绘三档 48/64/96 → **64/96/128 档**评估;B 区站桩槽与舞台规范(§6.1)随动。返工面 = 主角三态 + 八敌种(fixer 像素化管线已实战,重产成本可控);**评估与终值归整屏样张闸(§1.4)**,本批只立方向、不重产资产。 ### 8.3 导出格式与命名规范 @@ -451,7 +461,7 @@ | 参考 | 取 | 弃 | |---|---|---| | **Into the Breach** | 格内信息分层、攻击预告上格范式、战棋地块质感骨架(§1.2 原则一;§3.2) | 冷暗军事色调、压暗信息板、斜切 HUD(原则二;§3.3) | -| **Moonlighter** | 暖质地砖与砖缝质感、亲和冒险者气质、木石暖色道具(原则二/原则三) | 全拟物倾向(§3.3 半拟物边界) | +| **Moonlighter** | 暖质地砖与砖缝质感、亲和冒险者气质、木石暖色道具(原则二/原则三);**光照层次与明度纵深**(2026-09-29 v3.0 起取——亮地板/暗深渊/发光体三档,§2 明度分层) | 全拟物倾向(§3.3 半拟物边界);Darkest 式情绪压暗(§9.2) | | **Peglin** | 明快全年龄洞穴色彩、胖体量亲和怪(§5.1 普通怪原型) | 色块依赖——先读轮廓后读颜色(§5.1) | - **反面条款已成文**(§9.2);反面参考**图证**待本作素材生成后另批增补。 @@ -460,7 +470,8 @@ | 反面参考 | 违反条款 | 立法理由 | |---|---|---| -| **Darkest Dungeon** 式压暗 | §2 明度恒定硬规则 | 氛围只走色相/饱和/运动/元素四手段,不以变暗表达情绪(失败重开,世界无光暗记忆) | +| **Darkest Dungeon** 式压暗 | §2 情绪明暗禁令(明度分层下仍禁) | 状态与情绪只走色相/饱和/运动/元素四手段,不以变暗表达情绪(失败重开,世界无光暗记忆) | +| **传统扫雷白牌/贴纸式数字承载**(2026-09-29 v3.0 新增) | §1.2 原则二(明度分档为骨) | 数字由格底明度分档承载、直画入世界;色牌仅复杂格底后备——满屏白牌=电子表格观感,非游戏画面 | | **Enter the Gungeon** 式粒子与色相爆炸 | §3.4 焦点预算;§4.2 色相纪律 | 信息层不得被特效与杂色吞没,特效入画先过焦点预算 | | **Hades** 式特效密度 | §2.2 兑现爽感的上限 | 爽感靠逐行因果归因,不靠满屏特效;承载元素以 §2.2 清单为界 | | **传统扫雷 1–8 八色分色** | §4.1 数字墨三档 | 八色必撞红/金/蓝/紫赤语义色段;数字只走墨族三档色温,字形为唯一数值载体 | @@ -469,6 +480,7 @@ ## 版本历史 +- **v3.0(2026-09-29)中修批(案 B,用户拍板;审视报告=`design/research/art-bible-ux-review-2026-09-29.md`,六病根+三案呈报)**:①**§2 明度恒定→明度分层**——三档明度带(信息面层/世界中层/世界底层),情绪与状态明暗禁令保留(状态区分仍只走色相/饱和/运动/元素),空间纵深/光照/形体塑造开允许域;§2.1/2.2/2.3/2.5/2.7 各状态条措辞随改,§2.7 增「明度带随深度微移」候选。②**原则二色牌降级**——「明亮为皮,色牌为骨」改「明度分档为骨」:已开格走世界底层档(候选 L 0.20–0.32),棋盘数字墨亮族直画(候选 L≥0.55,冷亮/暖白/金亮三档色温承袭密度语义),色牌仅复杂格底后备(垫牌场景用深墨族,12.3:1 实测保留);§1.4 验收 1/2/4 与判定回退口径同步,样张 v2 四冻结之①④(砖面形态之数字承载面/数字形制)**解冻待样张 v3 重冻**(②③冻结〔色板/动画〕不受影响)。③**语义色适用域限定**——§4.2 各条「X 只说 Y」约束信息层与语义物件,纯环境氛围解禁(焦点预算与低饱和后退接管防抢焦);紫赤禁入带环境层低饱和可入、高饱和独占不变;§4.3 换皮槽与不变槽口径随改。④**装饰变体物件级解禁**——专属装饰形状家族+零信息纪律不变+焦点预算约束,配额候选 3–5 种(原则三/§3.2)。⑤**§6.1 舞台正面目标**——B 区=地窟看台(地台/落影/光源氛围候选),补原条只有负面约束之缺。⑥**§1.4 整屏样张闸新增**——战斗/关卡/菜单/营地四屏,验收四项(全局文字 ≥4.5:1/明度三档带/整屏焦点预算/文字禁压纹理),闸形=方向稿目检先行→机检冻结。⑦**§7 三件**——7.1 占位收口条款(占位=临时态,终稿闸=整屏样张)/7.2 全局文字可读性硬指标/7.4 字号下限 16/14px 对齐 ux-designer PC 规范+层级手段解禁(字号档差+墨色+字重)。⑧**§8.2 档位上调方向候选**(主角 64×96/敌 64/96/128 评估,归整屏样张闸,本批不重产资产)。⑨**§9 参考表**——Moonlighter 取列增光照层次、§9.2 DD 条款改名+新增「传统扫雷白牌」反面行。⑩**§3.4 焦点双机制**(完整度+明度带)。**连带文档同步**:character-design.md(提灯点亮解禁候选)/interaction-patterns.md/level-map.md/art-assets-checklist.md/battle.md/04-美术音频方向.md 引用口径随批。**挂账(06 登记)**:样张 v3 重跑批(断言改造+新参数冻结)/ui_kit 与棋盘渲染落码批(明度分层/格底分档/亮墨/UI 对比度修复)/资产升档重产批/mockup v3 方向稿(按 v3.0 重出)。**代拍板三项待追认**:闸形沿用目检先行+机检冻结两段式;色牌后备范围=复杂格底兜底;资产升档本批只立方向不重产。 - **v2.15(2026-09-28)人设旗脱钩批(用户拍板)**:§5.4 速览背包旗改旗朱红矩形旗+§4.1 封印黑条红族口径限定棋盘侧;封印黑仍为棋盘封印专属色不变;人设侧详见 character-design 对应版本行(v1.7) - **v2.14(2026-09-28)关卡画面样张 v1 冻结批(M-2 迭代 4 T1–T4,机检闸形 A——11/11 全绿即冻结)**:§7.2 增「暗底呈现态双色墨制」条(暗底系图标/读数=暖白 #F0E2C8、当前金底转深墨 #181410,各态 ≥4.5:1;已过节点暗金冻结 **GOLD_DONE #68562C** 专用呈现态值——旧 GOLD_DIM #8C743C 对双色墨均不达标;Boss 描边=紫赤 2px+外缘 1px 深墨环灰度冗余通道——§4.2 色相独占本色不变);冻结面=节点图标形制(♻ kenney-board-game-icons 五键 bow/award/campfire/crown_b/pouch,20px 烘焙 1:1 消费,WARM 单色,复用闸①②③④)+通道质感(折线 2/3/4px 直角肘形)+画布公式(70+层×122+34/52+槽×58+26+8 下限 620×240——routebug 83c11a1 根修件同源)+底栏样式(暗数据框 WARM/WARM_SOFT 双墨)+屏底(BG_ROOT+backdrop_stone);换层色板渐变挂点落码(§2.7 切片档——level_index→tint 表候选值随 §6.3 方向,明度带归一,终值归色板样张批)。规格承载=level-map.md(修订记录同日行);产物=`artwork/mockups/level-map-sheet-v1-2026-09-28.png`+`design/research/level-map-sample-v1-机检报告-2026-09-28.md`;气质终审=M-2 出口闸真人目检 - **v2.9(2026-09-26)高墙瓦片体系定稿批**(高墙批全程收官,用户拍板;台账 163/164):§3.2 新增「高墙瓦片体系」条——未挖格=一整块 32×32 自含凸起岩体(方案甲核心定义)+术语(墙瓦片/地面瓦片)+墨线边界纪律(1px 深墨线直线零锯齿,职责=分隔不融合)+单一北受光(北缘 1px 微亮棱/南缘立面窄暗条/凹角角点+立面侧 1px 齐平收头),定稿=`game/assets/art/board/terrain_*` 21 枚;§8.5 增「生产分工」条——材质归模型(AI 只出无缝填充纹理)、结构归程序(autotile 拼接约束超 2D 生图能力,实证在案)+镜像规则(只许 flip_h 禁旋转)。条口径=样张批追认(与 §8.4 方向集先例同)。词表与查表逻辑、搜包评估记录归 design/research 两档;过程文档随批清退(中间产物不入库先例,台账 127)。 diff --git a/design/art/character-design.md b/design/art/character-design.md index 3c4d8f4f..96efea79 100644 --- a/design/art/character-design.md +++ b/design/art/character-design.md @@ -40,7 +40,7 @@ - **兜帽披肩(2026-09-23 用户拍板)**:兜帽**不戴在头上**,取下披于肩上——露出棕色短发与整脸(表情可读),蓝色兜帽披在肩头仍是最近的"己方"识别点;三态同款披肩。 - **圆头挖掘铲(武器,2026-09-23 用户拍板)**:持铲不持剑——**铲 = 本作核心动词"挖安全格"的角色化**,挖掘与攻击共用同一动作语义(攻击表现即挥铲,后续攻击类表现优先围绕铲展开)。画法:圆头铲刃 + 木柄(木柄走木色族 `#8A5A34`,铲刃浅铁灰、不做冷灰重甲质感);**待机态 = 铲插立在地上、一只手扶在铲柄顶端**(2026-09-23 修订,原"拄于身侧"退役);攻击/受击态仍为手持。刀光/铲击光效/弹道不进精灵图(归战斗演出批另立资产)。 - **冒险背包与插旗(身份件,2026-09-23 用户拍板,同日尺寸修正)**:背负**结构式冒险背包**——翻盖+皮扣带的帆布背包(暖卡其布面,皮革件走木色族),**宽 ≈1.5× 体宽**:双肩背负、两侧各略超出身形一点;**禁圆麻袋化**(措辞弃"鼓胀掳获袋")、**禁特里式 3× 超宽**(反面参照:旷野之息特里;正面参照:合金弹头双主角大背包、超级马里奥奇诺比奥队长)。**旗杆插在背包一侧**(不要求完整可见,**被头部遮挡一部分亦可**),旗子**尺寸大于头部**(2026-09-23 修订,弃"背包顶小旗"旧稿),短杆**矩形**旗旗面 = **旗朱红 `#C63D22`**(2026-09-28 用户拍板:**人设背包旗与棋盘封印色脱钩**——封印色沿革〔旗朱 #C63D22→封印紫 2026-09-26→封印黑 2026-09-28〕**仅作用于棋盘格封印旗**;人设旗维持旗朱红、形为矩形非三角,以 normal/hit 定稿成图为基准),把"插旗宣告"的角色化焊在人设上,主角即插旗者(**插旗动作呈现名 = 封印**,2026-09-25 术语批,见 art-bible §3.2;2026-09-28 脱钩拍板后背包旗**不再**视作封印印记的携带形态——旗面旗朱红矩形,与棋盘封印黑旗形色均不同,仅保留"主角即插旗者"的身份叙事)。三条纪律:①旗面红=旗朱语义**仅旗非服饰**(负向 `no red clothing` 不拦截正向 `red flag`——红服饰禁令与红旗的边界由正向句显式锁色值;封印黑仍为棋盘格封印旗专属色,圣经 §4.1 不变);②背包+旗 = 主角对 §5.1"对称"的**唯一破例组**(语义配件非装饰),旗面朝向恒定画右、跨素材一致;③轮廓凹凸预算按"背包+旗"整组记账,样张批(圣经 §1.4)验证背负后剪影仍窄、仍可辨、不超格宽。 -- **护目镜与腰灯(2026-09-23 用户拍板,同日定案)**:**护目镜推在额前**(兜帽披肩后直接戴于额上,不戴眼上——眼睛是表情载体;皮革带+圆镜片,防尘挖掘者的职业信号);**提灯挂腰间,定案不手持**(小号铜色提灯,**不点亮**——守圣经 §2 平涂明度恒定,提灯禁做光源;头部饰品唯一化,头灯方案退役)。 +- **护目镜与腰灯(2026-09-23 用户拍板,同日定案)**:**护目镜推在额前**(兜帽披肩后直接戴于额上,不戴眼上——眼睛是表情载体;皮革带+圆镜片,防尘挖掘者的职业信号);**提灯挂腰间,定案不手持**(小号铜色提灯,**不点亮**——原守圣经 §2 明度恒定;2026-09-29 圣经 v3.0 明度分层后,空间光照属允许域,**提灯点亮解禁为候选**,点亮形制(光晕半径/暖色值/与舞台光照关系)归整屏样张批重议,本批不改成图;头部饰品唯一化,头灯方案退役)。 - **衣着细节(2026-09-23 用户拍板)**:**棕色半指手套**(挖土护手,露指保灵巧读感)+ **裤脚卷起、棕色皮护膝**(挖掘跪地的工装感)——小件走皮革木色族,不占剪影凹凸预算,不新增语义色。 - **三态**:① 待机 = 窄、直立、对称(§5.1 小人原型,含背包、旗与提灯记账);② 攻击 = 允许破对称,整体仍窄、不超格宽;③ 受击 = 无血红、无伤害数字(伤害数字归 HUD 层,不进精灵图)。 - **随身件 = 魔法道具形象候选池(2026-09-23 用户提案登记)**:铲、旗、背包、提灯四件随身件是未来魔法道具批的**形象候选池**——道具实装可借用主角身上已有的同款(彩蛋闭环:玩家在道具栏认出主角身上的物件);具体道具语义/数值归魔法道具批 GDD,人设侧义务 = 四件画得出来、认得出。 diff --git a/design/gdd/04-美术音频方向.md b/design/gdd/04-美术音频方向.md index f072121b..4ca3c4a2 100644 --- a/design/gdd/04-美术音频方向.md +++ b/design/gdd/04-美术音频方向.md @@ -4,8 +4,8 @@ 三条关键词: -- **数字可读性第一**:一切视觉让位给雷图数字的辨识——数字一律垫素色直角小牌,牌墨对比是硬指标,数字可读不依赖格底。 -- **明亮为皮,色牌为骨**:全局高亮度、暖倾向、无压抑;数字自带素色小牌保可读,格底美术放开做花样。 +- **数字可读性第一**:一切视觉让位给雷图数字的辨识——已开格底明度降档、亮墨数字直画,对比 ≥4.5:1 是硬指标(v3.0;复杂格底垫色牌兜底)。 +- **明亮为皮,明度分档为骨**:全局暖倾向、无压抑;格底明度分档承载数字可读,格面美术放开做花样(v3.0 替代「色牌为骨」)。 - **格子即地牢地砖**:未开是覆尘完整砖,已开是碎裂裸露,惩罚格是被惊动的怪物巢穴;已开格按产出做整格表达,未开格加不携带信息的装饰变体;新关卡环境优先换色板,不加新资产。 参考游戏三者相融(参考截图存于 `design/art/references/`):**Into the Breach** 取网格信息分层与"预告画在目标格上",雷图棋盘呈现基准取其战棋地块质感、但摆正为正俯视方格(禁等距斜视角,见美术圣经 §3.2);**Moonlighter** 取明亮像素地牢的暖砖质感;**Peglin** 取明快全年龄的地牢色彩。 diff --git a/design/gdd/06-待办清单.md b/design/gdd/06-待办清单.md index 33073e77..e042bf03 100644 --- a/design/gdd/06-待办清单.md +++ b/design/gdd/06-待办清单.md @@ -419,6 +419,30 @@ NodeOverlay 现行实态为模态覆盖层:恢复点全量服务(回复读 **状态**:**已拍板(2026-09-29 用户选型甲:演出层排播队列+轮横幅;排布追认归迭代 8 实现)**——归迭代 8 卡⑦;延迟/驻留时长归迭代 8 计划书细目 +#### 样张 v3 重跑批(art-bible v3.0 中修挂账①,2026-09-29 登记) + +**现状**:art-bible v3.0(2026-09-29 案 B 中修,审视报告 `design/research/art-bible-ux-review-2026-09-29.md`)将数字承载从色牌制改为格底明度分档制——样张 v2 四冻结之①(砖面形态数字承载面)与④(数字形制:色牌+深墨三档)**已解冻**;②色板③动画维持冻结。§1.4 机检断言集中涉色牌/明度档条目需改造(直画对比抽测/亮墨 L≥0.55/已开底 L 0.20–0.32/色牌后备组),并新增**整屏样张闸**首跑(战斗/关卡/菜单/营地四屏,验收四项:全局文字 ≥4.5:1/明度三档带/整屏焦点预算/文字禁压纹理)。闸形 = 方向稿目检先行 → 机检冻结(v3.0 代拍板①,待追认)。 + +**归属**:[art-bible](../art/art-bible.md) §1.4 · 表现层升级批前置 + +**状态**:待办(v3.0 已落籍;闸形代拍板待追认) + +#### ui_kit 与棋盘渲染落码批(art-bible v3.0 中修挂账②,2026-09-29 登记) + +**现状**:v3.0 条款落码面——①棋盘:已开格底明度降档(候选 L 0.20–0.32)、数字墨亮族直画、色牌渲染改复杂格底后备路径;②UI:全局文字 ≥4.5:1 修复(现行 4 处不达标实测见 `artwork/ui-redesign-2026-09-29/对比报告.md` §一,其「落地顺序」第 1/2 步可并入本批)、字号下限 16/14px、占位收口(panel_stone/button_stone 已在包未接线)。**前置硬闸 = 上一条样张 v3 冻结**(格底档/亮墨色值未定稿前不落码)。mockup v3 方向稿(按 v3.0 重出)归本批前置步骤。 + +**归属**:[HUD框架](systems/表现与支撑/HUD框架.md) + ui_kit + board_view/board_world 渲染参数 + +**状态**:待办(等样张 v3 冻结) + +#### 资产升档重产批(art-bible v3.0 中修挂账③,2026-09-29 登记) + +**现状**:v3.0 §8.2 档位上调方向候选——主角立绘 48×72→64×96 档、敌立绘三档 48/64/96→64/96/128 档评估;返工面 = 主角三态 + 八敌种(fixer 像素化管线已实战)。**v3.0 代拍板③:本批只立方向不重产资产**(待追认);评估与终值归整屏样张闸。连带:character-design.md 提灯点亮解禁候选(v3.0 明度分层允许空间光照)同归本批重议。 + +**归属**:[art-bible](../art/art-bible.md) §8.2 · 资产管线批 + +**状态**:待办(方向已立,升档与否与终值待整屏样张闸) + ### 数据配置 ### 教学引导 diff --git a/design/gdd/ux/battle.md b/design/gdd/ux/battle.md index 424cefa1..a073cd6e 100644 --- a/design/gdd/ux/battle.md +++ b/design/gdd/ux/battle.md @@ -356,7 +356,7 @@ - [ ] 两种格态(已开格 / 未开格)灰度截图下一眼可辨(排雷玩法×6②) - [ ] 悬停光标区分移动/挖/旗三语义;可挖域(8 向相邻)常驻指示;非相邻格悬停显禁止反馈(排雷玩法×6③) - [ ] 已引爆雷格呈"可通行可读"(排雷玩法×6④) -- [ ] 全部数字对所在格底对比 ≥4.5:1;明度恒定规则无违例(art-bible §4.1) +- [ ] 全部数字对所在格底对比 ≥4.5:1;明度分层规则无违例(art-bible §2/§4.1,v3.0——状态区分不走明度,格底功能分档合法) **交互与反馈** diff --git a/design/gdd/ux/interaction-patterns.md b/design/gdd/ux/interaction-patterns.md index bf4cca05..04b4ec6c 100644 --- a/design/gdd/ux/interaction-patterns.md +++ b/design/gdd/ux/interaction-patterns.md @@ -13,7 +13,7 @@ - **用途**:ui-programmer 实现时引用既有 pattern,不重复发明;实现中出现新 pattern 时**必须回写本库**(team-ui Phase 3 义务) - **输入约束**:PC / Keyboard-Mouse 主(全部操作纯鼠标可完成)、Gamepad Partial 非 MVP、Touch None - **视觉依据**:art-bible §3.3(半拟物:容器穿戏服、数据素面;直角=逻辑信息、圆角=可触摸物件)、§4(彩为世,墨为信——逻辑信息一律近黑暖墨族) -- **全局语义红线**:无任何信息仅靠色相承载(art-bible §4.5 色弱安全清单逐对成立);明度恒定(§2 硬规则——状态区分只用色相/饱和/运动/元素) +- **全局语义红线**:无任何信息仅靠色相承载(art-bible §4.5 色弱安全清单逐对成立);明度分层(§2,2026-09-29 v3.0——状态与情绪区分仍只用色相/饱和/运动/元素四手段;空间纵深与光照可走明度带) --- diff --git a/design/gdd/ux/level-map.md b/design/gdd/ux/level-map.md index 6b4e180a..7564366a 100644 --- a/design/gdd/ux/level-map.md +++ b/design/gdd/ux/level-map.md @@ -233,7 +233,7 @@ | [HUD框架](../systems/表现与支撑/HUD框架.md) | 模态 overlay 层级纪律、订阅纪律(推进信号两线之一) | Navigation Position + Data Requirements 架构注记 | | HUD框架 | 可访问性基线全量(对比/色弱/字号/闪烁/减动效/纯鼠标/中文字体) | Accessibility | | [battle.md](battle.md) OQ14 二轮拍板 | GP = 关卡画面常驻总量 | 顶栏 GP 常驻徽章 | -| [art-bible](../../art/art-bible.md) | 方块地牢观感(§3.2 圆角方形世界侧)、色板冻结(§4.1)、半拟物(§7.1)、明度恒定(§2) | 图区组件 + Accessibility 对比条 | +| [art-bible](../../art/art-bible.md) | 方块地牢观感(§3.2 圆角方形世界侧)、色板冻结(§4.1)、半拟物(§7.1)、明度分层(§2,v3.0——状态不走明度、空间光照可走) | 图区组件 + Accessibility 对比条 | --- From 092aa277e02315ebe13662810d2d53f4258c2c2a Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Tue, 29 Sep 2026 18:31:52 +0800 Subject: [PATCH 3/8] =?UTF-8?q?docs(sample-v3):=20=E6=A0=B7=E5=BC=A0=20v3?= =?UTF-8?q?=20=E6=96=B9=E5=90=91=E7=A8=BF=E6=89=B9=E2=80=94=E2=80=94?= =?UTF-8?q?=E6=A0=BC=E5=BA=95=E5=88=86=E6=A1=A3=20L0.08-0.14=20=E5=B8=A6?= =?UTF-8?q?=E6=95=B0=E5=80=BC=E4=BF=AE=E6=AD=A3+=E4=BA=AE=E5=A2=A8?= =?UTF-8?q?=E7=9B=B4=E7=94=BB+=E8=89=B2=E7=89=8C=E5=90=8E=E5=A4=87+?= =?UTF-8?q?=E7=89=A9=E4=BB=B6=E7=BA=A7=E8=A3=85=E9=A5=B0+B=E5=8C=BA?= =?UTF-8?q?=E8=88=9E=E5=8F=B0;=E6=9C=BA=E6=A3=80=2017/17=20=E5=85=A8?= =?UTF-8?q?=E7=BB=BF;=E4=BB=A3=E6=8B=8D=E6=9D=BF=E4=B8=89=E9=A1=B9?= =?UTF-8?q?=E5=B7=B2=E8=BF=BD=E8=AE=A4=E8=90=BD=E7=9B=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- design/art/art-bible.md | 8 +- design/gdd/06-待办清单.md | 8 +- .../sample-v3-draft-机检报告-2026-09-29.md | 38 + tools/render_sample_sheet_v3.py | 1118 +++++++++++++++++ 4 files changed, 1164 insertions(+), 8 deletions(-) create mode 100644 design/research/sample-v3-draft-机检报告-2026-09-29.md create mode 100644 tools/render_sample_sheet_v3.py diff --git a/design/art/art-bible.md b/design/art/art-bible.md index 67dcf5bd..9debb052 100644 --- a/design/art/art-bible.md +++ b/design/art/art-bible.md @@ -53,7 +53,7 @@ **验收项按序判定,第一项不过 = 整张否决(数字可读性定风格,风格服从可读)**: -1. **第一验收项|数字可读性(硬指标,可测;2026-09-29 v3.0 改格底分档承载)**:1–8 全档数字对其所在**已开格底**直画 WCAG 对比 ≥4.5:1(§4.1 参数域:已开格底走世界底层档,候选 L 0.20–0.32;棋盘数字墨亮族,L≥0.55 候选——均待样张 v3 冻结);复杂格底(物件纹样/变异纹带/微光叠加致直画对比不足)启用**色牌后备**,牌墨组合 ≥4.5:1(色牌 L≥0.70、牌上数字用深墨族),牌缘灰度可分;0.5× 缩放抽检数字仍可辨;纹带/裂纹/巢穴纹/物件纹样不得侵入数字字形占位区(砖心留白,§3.2)。 +1. **第一验收项|数字可读性(硬指标,可测;2026-09-29 v3.0 改格底分档承载)**:1–8 全档数字对其所在**已开格底**直画 WCAG 对比 ≥4.5:1(§4.1 参数域:已开格底走世界底层档,候选 L 0.08–0.14;棋盘数字墨亮族,L≥0.75 候选——均待样张 v3 冻结〔v3.0 原拟 L 0.20–0.32/L≥0.55 经 WCAG 实测不可达 4.5:1,候选带随样张批修正〕);复杂格底(物件纹样/变异纹带/微光叠加致直画对比不足)启用**色牌后备**,牌墨组合 ≥4.5:1(色牌 L≥0.70、牌上数字用深墨族),牌缘灰度可分;0.5× 缩放抽检数字仍可辨;纹带/裂纹/巢穴纹/物件纹样不得侵入数字字形占位区(砖心留白,§3.2)。 2. **格态三形可辨(灰度通道)**:未开/已开/雷三态转灰度截图后仍可逐格分类(§3.2 完整度叙事;v3.0 起明度差〔墙亮/空间暗〕为合法分类通道,与碎裂形双通道冗余);装饰变体不得制造新的分类特征——同一格态下带与不带变体的灰度差异不得成为三态分类线索;色弱模拟(去色相)下旗、巢穴纹不与裂纹混淆;**五组类型微光互辨**——色弱玩家的类型主通道 = 微光(色相+明度双码,2026-09-28 角嵌退役后微光以明度梯度承载类型,§2 信息面层内梯度),微光不得侵入数字字形占位区、明度梯度不得压破格底明度档(三态分类不受扰)。 3. **焦点预算成立(§3.4)**:任意一格至多一个完整凸形;数字所在格无第二焦点。 4. **图类型换皮抽测(§4.3)**:变体组中数字墨亮族三档、封印黑、危险红、奖励金、小人蓝、数字色牌(后备件)、类型微光五组恒定不动;变体格底仍过第 1、2 项指标。 @@ -188,7 +188,7 @@ ### 4.1 主色板 - **掩尘 `#C9AF83`**|未开格底色,覆尘完整砖:全作的"未知",画面最大沉默面。←原二;§2.1 -- **裸土 `#B39A78`**|已开格底色,碎裂裸露:更收更退;2026-09-29 v3.0 明度分层——已开格(挖出的空间)走**世界底层档**,明度低于未开格墙体一档(与 §8.5 图底分离同轴),候选 L 0.20–0.32 带,样张 v3 冻结。←原三 +- **裸土 `#B39A78`**|已开格底色,碎裂裸露:更收更退;2026-09-29 v3.0 明度分层——已开格(挖出的空间)走**世界底层档**,明度低于未开格墙体一档(与 §8.5 图底分离同轴),候选 L 0.08–0.14 带(样张 v3 实测修正:L0.20+ 底配纯白也仅 3.4:1,数学不可达 4.5:1),样张 v3 冻结。←原三 - **数字墨双色制(2026-09-29 v3.0)**|1–8 **不做八色分色**,按密度分三档色温(冷=稀疏,暖=密集);**字形为唯一数值载体**,色温只作密度氛围。①**棋盘数字墨=亮族**(直画已开格底,世界底层档上的信息面层):三档色温方向 1–3 冷亮青白/4–5 暖白/6–8 金亮,L≥0.55 候选,样张 v3 冻结(旧深墨三档 `青墨 #132E36/赭墨 #3C250C/锈墨 #4A1E14` 转垫牌场景与 UI 用墨);②**垫牌与 UI 数据墨=深墨族 `#33261B` 系**(L≤0.027 不变,§7.2)。八色必与红金蓝紫赤语义冲突,故弃。←原一/原二;P3 - **封印黑 `#000000`**|封印(插旗)宣告色,无色相:玩家的宣告"此格封印"(色史:旗朱 `#C63D22` →封印紫 `#7C3AA8` 2026-09-26→**封印黑 2026-09-28 用户拍板**——紫色与微光蓝族〔魔法微光 256° 等〕色相冲突,黑色无色相天然避开 300°–345° 禁入带与全部微光色带;未开格墙顶明度 ≈113 对纯黑对比 ≥4.4:1,旗杆米白保可读)。旗朱随封印紫批退役〔棋盘侧〕,红族棋盘侧自此只剩危险红(2026-09-28 起人设背包旗=旗朱红矩形旗——旗色脱钩拍板,人设侧详见 character-design 背包旗条)。←原一;P2;封印紫批 2026-09-26;封印黑批 2026-09-28 - **危险红 `#A8321F`**|危险色:雷=被惊动的巢穴,兑现档红,更深更沉(2026-09-13 更名,旧称"机关红"随隐喻换轴退役;色值不变)。←原三;P2 @@ -215,7 +215,7 @@ **换皮只换四槽,永不变信**。模板按棋盘生成产物 `board_type` 标签直接消费(键名与词表事实源 = 棋盘生成 GDD 与 `board_gen.tres`:dungeon / underdark / deep_underdark);清单与词表 owner 待 关卡节点地图/地形变异/地图战斗资源,本节只定模板: - `tile_closed` 未开底:L 与饱和同 4.1 硬指标(墙顶面受光档 L≥0.30、饱和 ≤0.55),避禁入色相带 -- `tile_open` 已开底:世界底层档(2026-09-29 v3.0,候选 L 0.20–0.32,样张 v3 冻结)、饱和 ≤0.55,避禁入色相带 +- `tile_open` 已开底:世界底层档(2026-09-29 v3.0,候选 L 0.08–0.14,样张 v3 冻结)、饱和 ≤0.55,避禁入色相带 - `wall_ambient` 墙雾氛围 tint:可带主题色相,L≥0.30 - `variant_tint` 变异纹带染槽:只改色相不改纹形(纹带形按轴两分,见 §3.2 变异格形状通道;种类 = 地形变异六类型已定稿) @@ -480,7 +480,7 @@ ## 版本历史 -- **v3.0(2026-09-29)中修批(案 B,用户拍板;审视报告=`design/research/art-bible-ux-review-2026-09-29.md`,六病根+三案呈报)**:①**§2 明度恒定→明度分层**——三档明度带(信息面层/世界中层/世界底层),情绪与状态明暗禁令保留(状态区分仍只走色相/饱和/运动/元素),空间纵深/光照/形体塑造开允许域;§2.1/2.2/2.3/2.5/2.7 各状态条措辞随改,§2.7 增「明度带随深度微移」候选。②**原则二色牌降级**——「明亮为皮,色牌为骨」改「明度分档为骨」:已开格走世界底层档(候选 L 0.20–0.32),棋盘数字墨亮族直画(候选 L≥0.55,冷亮/暖白/金亮三档色温承袭密度语义),色牌仅复杂格底后备(垫牌场景用深墨族,12.3:1 实测保留);§1.4 验收 1/2/4 与判定回退口径同步,样张 v2 四冻结之①④(砖面形态之数字承载面/数字形制)**解冻待样张 v3 重冻**(②③冻结〔色板/动画〕不受影响)。③**语义色适用域限定**——§4.2 各条「X 只说 Y」约束信息层与语义物件,纯环境氛围解禁(焦点预算与低饱和后退接管防抢焦);紫赤禁入带环境层低饱和可入、高饱和独占不变;§4.3 换皮槽与不变槽口径随改。④**装饰变体物件级解禁**——专属装饰形状家族+零信息纪律不变+焦点预算约束,配额候选 3–5 种(原则三/§3.2)。⑤**§6.1 舞台正面目标**——B 区=地窟看台(地台/落影/光源氛围候选),补原条只有负面约束之缺。⑥**§1.4 整屏样张闸新增**——战斗/关卡/菜单/营地四屏,验收四项(全局文字 ≥4.5:1/明度三档带/整屏焦点预算/文字禁压纹理),闸形=方向稿目检先行→机检冻结。⑦**§7 三件**——7.1 占位收口条款(占位=临时态,终稿闸=整屏样张)/7.2 全局文字可读性硬指标/7.4 字号下限 16/14px 对齐 ux-designer PC 规范+层级手段解禁(字号档差+墨色+字重)。⑧**§8.2 档位上调方向候选**(主角 64×96/敌 64/96/128 评估,归整屏样张闸,本批不重产资产)。⑨**§9 参考表**——Moonlighter 取列增光照层次、§9.2 DD 条款改名+新增「传统扫雷白牌」反面行。⑩**§3.4 焦点双机制**(完整度+明度带)。**连带文档同步**:character-design.md(提灯点亮解禁候选)/interaction-patterns.md/level-map.md/art-assets-checklist.md/battle.md/04-美术音频方向.md 引用口径随批。**挂账(06 登记)**:样张 v3 重跑批(断言改造+新参数冻结)/ui_kit 与棋盘渲染落码批(明度分层/格底分档/亮墨/UI 对比度修复)/资产升档重产批/mockup v3 方向稿(按 v3.0 重出)。**代拍板三项待追认**:闸形沿用目检先行+机检冻结两段式;色牌后备范围=复杂格底兜底;资产升档本批只立方向不重产。 +- **v3.0(2026-09-29)中修批(案 B,用户拍板;审视报告=`design/research/art-bible-ux-review-2026-09-29.md`,六病根+三案呈报)**:①**§2 明度恒定→明度分层**——三档明度带(信息面层/世界中层/世界底层),情绪与状态明暗禁令保留(状态区分仍只走色相/饱和/运动/元素),空间纵深/光照/形体塑造开允许域;§2.1/2.2/2.3/2.5/2.7 各状态条措辞随改,§2.7 增「明度带随深度微移」候选。②**原则二色牌降级**——「明亮为皮,色牌为骨」改「明度分档为骨」:已开格走世界底层档(候选 L 0.20–0.32),棋盘数字墨亮族直画(候选 L≥0.75,冷亮/暖白/金亮三档色温承袭密度语义),色牌仅复杂格底后备(垫牌场景用深墨族,12.3:1 实测保留);§1.4 验收 1/2/4 与判定回退口径同步,样张 v2 四冻结之①④(砖面形态之数字承载面/数字形制)**解冻待样张 v3 重冻**(②③冻结〔色板/动画〕不受影响)。③**语义色适用域限定**——§4.2 各条「X 只说 Y」约束信息层与语义物件,纯环境氛围解禁(焦点预算与低饱和后退接管防抢焦);紫赤禁入带环境层低饱和可入、高饱和独占不变;§4.3 换皮槽与不变槽口径随改。④**装饰变体物件级解禁**——专属装饰形状家族+零信息纪律不变+焦点预算约束,配额候选 3–5 种(原则三/§3.2)。⑤**§6.1 舞台正面目标**——B 区=地窟看台(地台/落影/光源氛围候选),补原条只有负面约束之缺。⑥**§1.4 整屏样张闸新增**——战斗/关卡/菜单/营地四屏,验收四项(全局文字 ≥4.5:1/明度三档带/整屏焦点预算/文字禁压纹理),闸形=方向稿目检先行→机检冻结。⑦**§7 三件**——7.1 占位收口条款(占位=临时态,终稿闸=整屏样张)/7.2 全局文字可读性硬指标/7.4 字号下限 16/14px 对齐 ux-designer PC 规范+层级手段解禁(字号档差+墨色+字重)。⑧**§8.2 档位上调方向候选**(主角 64×96/敌 64/96/128 评估,归整屏样张闸,本批不重产资产)。⑨**§9 参考表**——Moonlighter 取列增光照层次、§9.2 DD 条款改名+新增「传统扫雷白牌」反面行。⑩**§3.4 焦点双机制**(完整度+明度带)。**连带文档同步**:character-design.md(提灯点亮解禁候选)/interaction-patterns.md/level-map.md/art-assets-checklist.md/battle.md/04-美术音频方向.md 引用口径随批。**挂账(06 登记)**:样张 v3 重跑批(断言改造+新参数冻结)/ui_kit 与棋盘渲染落码批(明度分层/格底分档/亮墨/UI 对比度修复)/资产升档重产批/mockup v3 方向稿(按 v3.0 重出)。**代拍板三项 2026-09-29 当日已追认**(闸形两段式/色牌后备范围/升档只立方向)。 - **v2.15(2026-09-28)人设旗脱钩批(用户拍板)**:§5.4 速览背包旗改旗朱红矩形旗+§4.1 封印黑条红族口径限定棋盘侧;封印黑仍为棋盘封印专属色不变;人设侧详见 character-design 对应版本行(v1.7) - **v2.14(2026-09-28)关卡画面样张 v1 冻结批(M-2 迭代 4 T1–T4,机检闸形 A——11/11 全绿即冻结)**:§7.2 增「暗底呈现态双色墨制」条(暗底系图标/读数=暖白 #F0E2C8、当前金底转深墨 #181410,各态 ≥4.5:1;已过节点暗金冻结 **GOLD_DONE #68562C** 专用呈现态值——旧 GOLD_DIM #8C743C 对双色墨均不达标;Boss 描边=紫赤 2px+外缘 1px 深墨环灰度冗余通道——§4.2 色相独占本色不变);冻结面=节点图标形制(♻ kenney-board-game-icons 五键 bow/award/campfire/crown_b/pouch,20px 烘焙 1:1 消费,WARM 单色,复用闸①②③④)+通道质感(折线 2/3/4px 直角肘形)+画布公式(70+层×122+34/52+槽×58+26+8 下限 620×240——routebug 83c11a1 根修件同源)+底栏样式(暗数据框 WARM/WARM_SOFT 双墨)+屏底(BG_ROOT+backdrop_stone);换层色板渐变挂点落码(§2.7 切片档——level_index→tint 表候选值随 §6.3 方向,明度带归一,终值归色板样张批)。规格承载=level-map.md(修订记录同日行);产物=`artwork/mockups/level-map-sheet-v1-2026-09-28.png`+`design/research/level-map-sample-v1-机检报告-2026-09-28.md`;气质终审=M-2 出口闸真人目检 - **v2.9(2026-09-26)高墙瓦片体系定稿批**(高墙批全程收官,用户拍板;台账 163/164):§3.2 新增「高墙瓦片体系」条——未挖格=一整块 32×32 自含凸起岩体(方案甲核心定义)+术语(墙瓦片/地面瓦片)+墨线边界纪律(1px 深墨线直线零锯齿,职责=分隔不融合)+单一北受光(北缘 1px 微亮棱/南缘立面窄暗条/凹角角点+立面侧 1px 齐平收头),定稿=`game/assets/art/board/terrain_*` 21 枚;§8.5 增「生产分工」条——材质归模型(AI 只出无缝填充纹理)、结构归程序(autotile 拼接约束超 2D 生图能力,实证在案)+镜像规则(只许 flip_h 禁旋转)。条口径=样张批追认(与 §8.4 方向集先例同)。词表与查表逻辑、搜包评估记录归 design/research 两档;过程文档随批清退(中间产物不入库先例,台账 127)。 diff --git a/design/gdd/06-待办清单.md b/design/gdd/06-待办清单.md index e042bf03..5bfb5c63 100644 --- a/design/gdd/06-待办清单.md +++ b/design/gdd/06-待办清单.md @@ -421,11 +421,11 @@ NodeOverlay 现行实态为模态覆盖层:恢复点全量服务(回复读 #### 样张 v3 重跑批(art-bible v3.0 中修挂账①,2026-09-29 登记) -**现状**:art-bible v3.0(2026-09-29 案 B 中修,审视报告 `design/research/art-bible-ux-review-2026-09-29.md`)将数字承载从色牌制改为格底明度分档制——样张 v2 四冻结之①(砖面形态数字承载面)与④(数字形制:色牌+深墨三档)**已解冻**;②色板③动画维持冻结。§1.4 机检断言集中涉色牌/明度档条目需改造(直画对比抽测/亮墨 L≥0.55/已开底 L 0.20–0.32/色牌后备组),并新增**整屏样张闸**首跑(战斗/关卡/菜单/营地四屏,验收四项:全局文字 ≥4.5:1/明度三档带/整屏焦点预算/文字禁压纹理)。闸形 = 方向稿目检先行 → 机检冻结(v3.0 代拍板①,待追认)。 +**现状**:art-bible v3.0(2026-09-29 案 B 中修,审视报告 `design/research/art-bible-ux-review-2026-09-29.md`)将数字承载从色牌制改为格底明度分档制——样张 v2 四冻结之①(砖面形态数字承载面)与④(数字形制:色牌+深墨三档)**已解冻**;②色板③动画维持冻结。§1.4 机检断言集中涉色牌/明度档条目需改造(直画对比抽测/亮墨 L≥0.55/已开底 L 0.20–0.32/色牌后备组),并新增**整屏样张闸**首跑(战斗/关卡/菜单/营地四屏,验收四项:全局文字 ≥4.5:1/明度三档带/整屏焦点预算/文字禁压纹理)。闸形 = 方向稿目检先行 → 机检冻结(v3.0 代拍板①,**2026-09-29 已追认**)。 **归属**:[art-bible](../art/art-bible.md) §1.4 · 表现层升级批前置 -**状态**:待办(v3.0 已落籍;闸形代拍板待追认) +**状态**:待办(v3.0 已落籍;闸形代拍板已追认) #### ui_kit 与棋盘渲染落码批(art-bible v3.0 中修挂账②,2026-09-29 登记) @@ -437,11 +437,11 @@ NodeOverlay 现行实态为模态覆盖层:恢复点全量服务(回复读 #### 资产升档重产批(art-bible v3.0 中修挂账③,2026-09-29 登记) -**现状**:v3.0 §8.2 档位上调方向候选——主角立绘 48×72→64×96 档、敌立绘三档 48/64/96→64/96/128 档评估;返工面 = 主角三态 + 八敌种(fixer 像素化管线已实战)。**v3.0 代拍板③:本批只立方向不重产资产**(待追认);评估与终值归整屏样张闸。连带:character-design.md 提灯点亮解禁候选(v3.0 明度分层允许空间光照)同归本批重议。 +**现状**:v3.0 §8.2 档位上调方向候选——主角立绘 48×72→64×96 档、敌立绘三档 48/64/96→64/96/128 档评估;返工面 = 主角三态 + 八敌种(fixer 像素化管线已实战)。**v3.0 代拍板③:本批只立方向不重产资产**(**2026-09-29 已追认**);评估与终值归整屏样张闸。连带:character-design.md 提灯点亮解禁候选(v3.0 明度分层允许空间光照)同归本批重议。 **归属**:[art-bible](../art/art-bible.md) §8.2 · 资产管线批 -**状态**:待办(方向已立,升档与否与终值待整屏样张闸) +**状态**:待办(方向已立,代拍板已追认;升档与否与终值待整屏样张闸) ### 数据配置 diff --git a/design/research/sample-v3-draft-机检报告-2026-09-29.md b/design/research/sample-v3-draft-机检报告-2026-09-29.md new file mode 100644 index 00000000..664963a2 --- /dev/null +++ b/design/research/sample-v3-draft-机检报告-2026-09-29.md @@ -0,0 +1,38 @@ +# 样张 v3 方向稿机检报告(2026-09-29,art-bible v3.0——方向稿阶段,机检为参考;冻结闸=目检后机检批) + +生成:`python tools/render_sample_sheet_v3.py`;v3.0 口径:格底分档(世界底层档)/亮墨直画/色牌后备/物件级装饰/B 区舞台;断言阈值随冻结批校准。 + +## v3.0 改造点 → 断言映射 + +| v3.0 条款(病根编号) | 方向稿落地 | 断言承载 | +|---|---|---| +| 原则二明度分档为骨(病根 3) | 亮墨三档直画(冷亮/暖白/金亮 L≥0.75)×已开格底 L 0.08–0.14 | A3a 硬指标(实测 6.0–6.3:1) | +| 色牌降级后备(病根 3) | 物件纹样格/装饰变体格垫牌,其余直画 | A3a 后备组(11.8–12.0:1) | +| §2 明度分层(病根 2) | 地板归一 L≈0.10(现行瓦片 L0.036 实为提亮);B 区舞台暗背景+顶光柱 | A3b 图底分离读数(候选 Δ≥30;v2 阈值 55 与分档带数学冲突——校准归冻结批) | +| 装饰物件级解禁(病根 5) | 小石块堆两格演示(专属圆钝三角家族) | 目检项(形状家族隔离) | +| §6.1 舞台正面目标(病根 6) | 地台+落影+顶光柱 | 目检项 | +| A4 尺寸基线 | 现行资产已换代(立绘 46×48) | 改「可载+对表」口径,尺寸基线重校归冻结批 | + +## 断言明细 + +| 断言 | 判据 | 结果 | 明细 | +|---|---|---|---| +| F1 | 方案甲 8 邻拼装(词表查表,禁整块) | PASS | 错位 0 处;用件 15 种 ['center', 'center_crack', 'center_speckle', 'end_n', 'end_s', 'end_w', 'hrun', 'in_nw', 'in_sw', 'n', 'nw', 's', 'sw', 'vrun', 'w'] | +| F2 | 旗仅出现于未开格 | PASS | 旗位 (1, 2) 格态=W | +| F3 | 小人脚锚=自底边 25% 线(两态) | PASS | 脚 y=[213.75, 258.75] 期望=[213.75, 258.75] | +| F4 | 数字 0 格无字形(0=纯安全格裸地面) | PASS | 0 态格 38 个(示例 (4,4));数字表含 0 键=False | +| F5a | 接触带微光⊆英雄格周界(空间侧,不进墙格) | PASS | 微光 bbox=(86, 176, 119, 230) 英雄格=(90, 180, 135, 225) | +| F5b | 类型微光禁整格染色(中心 50% 区零染色像素) | PASS | 五格中心区全净 | +| F5c | 微光格零附加图形(微光段无角嵌调用——角嵌退役,微光只留微光) | PASS | 微光段无角嵌调用 | +| A1a | 色板对表圣经 §4.1 冻结值 | PASS | {'INK': '#33261B', '青墨': '#132E36', '赭墨': '#3C250C', '锈墨': '#4A1E14', 'PLATE': '#F5EAD3', '封印黑': '#000000', '危险红': '#A8321F', '奖励金': '#F0A828'} | +| A1b | 禁入带 HSV300°-345° 零命中 | PASS | 命中 0 像素(抽样) | +| A2 | 拼缝周界闭合(墙侧 2px 墨线 <70) | PASS | 全部墙地边界墨线在位 | +| A3a | v3 亮墨×格底 WCAG≥4.5:1(直画可行性硬指标) + 色牌后备组 ≥4.5:1 | PASS | 亮墨[('冷亮青白', 6.3), ('暖白', 6.0), ('金亮', 6.0)] 格底L=0.087;后备[('青墨×牌', 12.0), ('赭墨×牌', 12.0), ('锈墨×牌', 11.8)] | +| A3b | 图底分离读数(候选 Δ≥30——v2 阈值 55 与格底分档带数学冲突,校准归冻结批) | PASS | 墙顶 113 vs 地面 79,Δ=33(v2 阈值 55 系地板 L0.036 时代校定) | +| F6 | 墙格顶面/立面双明度带(南向临地墙格 Δ≥18,体积感机器代理) | PASS | 临地墙格 14 个;最小 Δ 76.3;均 Δ 105.0(v1 实测均 71.6) | +| F7 | 整板悬崖 DEPTH_PX 与 game 渲染常量同源(board_view.gd 解析) | PASS | DEPTH_PX=8.0(已解析);悬崖带均亮 69(<100);扩展 +8px | +| A6 | 观感密度:明度梯度均值 ≥4.70(v1 实测 4.09 上调 15%——高频细节能量) | PASS | 梯度均值 6.15(低频双峰由 A3 承载) | +| A5 | 画布四缘 2px 净空(零溢出) | PASS | 缘带内容像素 0 | +| A4 | 混排相融(游戏在库资产可载+UiKit 语义色对表;尺寸基线=换代后实态,校准归冻结批) | PASS | 小人源 (32, 32)(裁透明留白后 (19, 20))/立绘 (46, 48)/状态图标原件;INK/封印黑/奖励金 == ui_kit.gd | + +结论:**全绿**(17/17 PASS)。v3 方向稿机检=可行性参考(A3 亮墨对比为硬指标);冻结 = 用户目检方向稿后机检批(v3.0 闸形:目检先行→机检冻结)。 diff --git a/tools/render_sample_sheet_v3.py b/tools/render_sample_sheet_v3.py new file mode 100644 index 00000000..035d8065 --- /dev/null +++ b/tools/render_sample_sheet_v3.py @@ -0,0 +1,1118 @@ +# -*- coding: utf-8 -*- +"""战斗一屏样张方向稿生成脚本 v3-draft(2026-09-29,art-bible v3.0 中修案 B 首批)。 + +v3.0 口径(方向稿=目检先行闸,冻结归机检批): + V1 格底明度分档:已开格底压暗至世界底层档(候选 L 0.08–0.14;§8.5 注记——压暗仅方向稿示意,终稿归地板素材选型/重产) + V2 数字亮墨直画:亮族三档(冷亮/暖白/金亮,L≥0.75),色牌降级=复杂格底(物件纹样/装饰变体)后备 + V3 装饰物件级解禁演示:小石块堆(专属装饰形状家族,圆钝三角形,零信息纪律不变) + V4 B 区舞台正面目标:世界底层暗背景+顶光柱+地台落影(§6.1 地窟看台) + A3 断言改造:亮墨×实测已开格底 WCAG ≥4.5:1(色牌后备组维持深墨×牌 ≥4.5:1) +基于 v2 脚本定点补丁生成(_v3_patch.py),v2 冻结产物管线不动。 + +v1 用户否决四原因(2026-09-28)全部断言化——生成即验,不过闸不出图: + F1 未开格 = 方案甲缘件 8 邻拼装(词表查表,禁整块 center 铺满) + F2 旗仅出现于未开格 + F3 小人脚锚 = 自底边 25% 线(⚠ 纵向比例一律自底边口径) + F4 数字 0 格无字形(纯安全格 = 干净裸地面) + F5 微光仅带状:接触带微光只画英雄格周界空间侧;类型微光禁整格染色;微光格零附加图形(角嵌退役) + F6 墙格顶面/立面双明度带(否决③立体感——南向临地墙格 Δ≥18,体积感机器代理) + F7 整板悬崖 DEPTH_PX 与 game 渲染常量同源(board_view.gd 解析——否决③立体感) +程序化审计(§9 初级验收授权 + 迭代 2 扩展): + A1 色板对表圣经冻结色板 + 禁入带(HSV 300°-345°)全图扫描 + A2 拼缝周界闭合(墙↔地边界墙侧 2px 墨线带亮度 <70) + A3 明度对比(数字墨×色牌 WCAG ≥4.5:1;图底分离 Δ≥55——否决③,v1 实测 61.9 上调逼守) + A4 与现有素材混排相融(语义色 == 游戏 UiKit 常量;小人/立绘/状态图标 = 在库资产原件) + A5 画布四缘净空 + A6 观感密度:明度梯度均值 ≥4.70(否决①「显示太丑」总纲代理——v1 同口径实测 4.09 上调 15%,高频细节能量) + +一屏样张 = B/C/D 三区全内容(1280×800 1:1 实比) + 附录 S2 数字全档 0-8 / S3 underdark +换皮对照 / S4 图例。内容清单 = art-bible §1.4(九组,缺项即无效)。 +素材源 = game/assets/art(board 21 瓦片 + character 小人/立绘)+ ui/icons 状态图标; +素材不入 git——先查本仓库,缺位回退主检出(D:/code/g-plan2)。 +词表事实源 = design/research/board-tile-vocab-plan-a-2026-09-26.md;画法参数事实源 = +design/research/画法参数四源对照表-2026-09-26.md(四源对表先行产物)。 +输出 = artwork/mockups/sample-batch-v2-2026-09-28.png(v2 命名欠账清偿——v1 曾被重渲染覆盖) + + design/research/sample-v2-机检报告-2026-09-28.md。 +用法:python tools/render_sample_sheet.py +""" +from PIL import Image, ImageDraw, ImageFilter, ImageChops, ImageFont +import os +import sys +import math +import re +import hashlib +from collections import deque + +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +MAIN_ROOT = "D:/code/g-plan2" + + +def asset_root(*parts): + """素材路径两级回退:worktree → 主检出(素材不入 git,fresh worktree 缺位)。""" + for base in (ROOT, MAIN_ROOT): + p = os.path.join(base, *parts) + if os.path.exists(p): + return p + raise FileNotFoundError(os.path.join(*parts)) + + +BOARD_DIR = ("game", "assets", "art", "board") +CHAR_DIR = ("game", "assets", "art", "character") +ICON_DIR = ("game", "assets", "ui", "icons") +OUT_PNG = os.path.join(ROOT, "artwork", "mockups", "sample-batch-v3-draft-2026-09-29.png") +OUT_REPORT = os.path.join(ROOT, "design", "research", "sample-v3-draft-机检报告-2026-09-29.md") +T_FONT = asset_root("artwork", "ui-reuse-2026-09-23", + "4-字体", "fusion-pixel-12px(OFL)", "fusion-pixel-12px-proportional-latin.ttf") +ZH_FONT = r"C:\Windows\Fonts\msyh.ttc" + +# ══ 冻结色板(art-bible §4.1——A1 逐字节对表基准,禁改动) ══ +INK = (51, 38, 27) # 主墨 #33261B +INK_COLD = (19, 46, 54) # 青墨 1-3 #132E36 +INK_OCHRE = (60, 37, 12) # 赭墨 4-5 #3C250C +INK_RUST = (74, 30, 20) # 锈墨 6-8 #4A1E14 +PLATE = (245, 234, 211) # 数字色牌 #F5EAD3(v3.0 后备件) +# ── v3 亮族数字墨(art-bible v3.0:直画已开格底世界底层档,候选 L≥0.75;金亮低饱和避奖励金语义) ── +INK_L_COLD = (216, 236, 240) # 冷亮青白 1-3 #D8ECF0 +INK_L_WARM = (240, 226, 200) # 暖白 4-5 #F0E2C8(关卡屏 WARM 同族) +INK_L_GOLD = (248, 227, 168) # 金亮 6-8 #F8E3A8 +FLOOR_DARK_GAMMA = 1.75 # 已开格底压暗曲线(方向稿示意):gamma 保纹理相对对比 +FLOOR_DARK_GAIN = 0.92 +SEAL_BLACK = (0, 0, 0) # 封印黑 #000000(旗朱→封印紫→封印黑 2026-09-28——紫与微光蓝族色相冲突退役) +DANGER_RED = (168, 50, 31) # 危险红 #A8321F +REWARD_GOLD = (240, 168, 40) # 奖励金 #F0A828 +HERO_BLUE = (46, 134, 222) # 小人蓝 #2E86DE(候选,样张批冻结——对照表 §5.1) +RED_MINE = (150, 44, 36) # 引爆雷字朱(游戏 UiKit.RED_MINE) +# 候选(样张批冻结项——对照表 §5) +CONTACT_GLOW = (214, 236, 255) # 接触带微光:小人蓝族浅两档(近白蓝) +GLOW_GROUPS = { # §4.2 类型微光五组候选 + "attack": (214, 193, 58), "heal": (92, 184, 58), "pierce": (46, 158, 158), + "magic": (123, 91, 214), "blast": (255, 45, 85), "gp": (214, 193, 58), +} +GLOW_FAMILY = {"attack": "通用增益", "defense": "通用增益", "weaken": "通用增益", + "action": "通用增益", "gp": "通用增益", "heal": "治疗", + "pierce": "穿刺", "magic": "魔法", "blast": "群伤"} +# 游戏 UiKit 常量(A4 混排对表——ui_kit.gd 实测值) +UIKIT = {"INK": INK, "FLAG_RED": SEAL_BLACK, "GOLD": REWARD_GOLD, "RED_MINE": RED_MINE, + "PANEL_STAGE": (216, 200, 172), "PANEL_HERO": (232, 220, 196), + "PANEL_DATA": (226, 210, 182), "PANEL_BORDER": (120, 106, 88), + "BRICK": (201, 175, 131), "FLOOR": (179, 154, 120)} +ARMOR_ICONS = {"light": "◇", "ward": "◆", "heavy": "▣"} +ARMOR_COLORS = {"light": (120, 110, 98), "ward": HERO_BLUE, "heavy": (176, 122, 20)} + +F_DIGIT = ImageFont.truetype(T_FONT, 30) # S2 64px 格数字 +F_DIGIT_D = ImageFont.truetype(T_FONT, 18) # D 区 45px 格数字(下限 ≥18px) +F_SMALL = ImageFont.truetype(T_FONT, 16) +F_LBL = ImageFont.truetype(ZH_FONT, 14) +F_LBL2 = ImageFont.truetype(ZH_FONT, 12) +F_TITLE = ImageFont.truetype(ZH_FONT, 19) +F_STANDEE = ImageFont.truetype(ZH_FONT, 42) # 敌像字形占位 +F_NAME = ImageFont.truetype(ZH_FONT, 12) +F_ORDER = ImageFont.truetype(ZH_FONT, 13) +F_INTENT = ImageFont.truetype(ZH_FONT, 15) + +CHECKS = [] # (id, name, ok, detail) + + +def check(cid, name, ok, detail=""): + CHECKS.append((cid, name, bool(ok), detail)) + print("[%s] %s — %s%s" % ("PASS" if ok else "FAIL", cid, name, + (";" + detail) if detail else "")) + + +# ══ 素材装载 ══ +def load_tile(name): + return Image.open(asset_root(*(BOARD_DIR + (name,)))).convert("RGB") + + +WALLS = {} +for k in ["center", "center_crack", "center_speckle", "n", "s", "w", "nw", "sw", + "hrun", "vrun", "end_n", "end_s", "end_w", "lone", "in_nw", "in_sw"]: + WALLS[k] = load_tile("terrain_wall_%s_dungeon.png" % k) +FLOORS = [load_tile("terrain_floor_dungeon_%d.png" % i) for i in range(1, 6)] + + +def _v3_darken_floors(tiles, target_l=0.10): + """v3 方向稿:已开格底归一到世界底层档中点 L≈0.11(候选带 0.08–0.14)——实测现行瓦片 L≈0.036 + 低于带下沿,故实为**提亮**;线性增益保纹理相对对比。终稿归素材重产(§8.5),本函数仅方向稿示意。""" + def _lum(rgb): + def lin(c): + c = c / 255.0 + return c / 12.92 if c <= 0.04045 else ((c + 0.055) / 1.055) ** 2.4 + r, g, b = rgb[:3] + return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b) + out = [] + for tl in tiles: + rgb = tl.convert("RGB") + probe = list(rgb.resize((8, 8)).getdata()) + cur = sum(_lum(c) for c in probe) / len(probe) + k = (target_l / max(cur, 1e-3)) ** (1 / 2.2) # L ∝ c^2.2 近似 + k = max(0.6, min(1.8, k)) + lut = [min(255, int(i * k + 0.5)) for i in range(256)] + a = tl.split()[3] if tl.mode == "RGBA" else None + rgb = rgb.point(lut * 3) + if a is not None: + rgb.putalpha(a) + out.append(rgb.convert("RGBA")) + print("[v3] floor normalize L %.3f → %.3f (k=%.2f)" % (cur, target_l, k)) + return out + + +FLOORS = _v3_darken_floors(FLOORS) +HERO_SRC = Image.open(asset_root(*(CHAR_DIR + ("character_hero_idle.png",)))).convert("RGBA") +PORTRAIT_SRC = Image.open(asset_root(*(CHAR_DIR + ("character_hero_portrait.png",)))).convert("RGBA") +STATUS_ICONS = {k: Image.open(asset_root(*(ICON_DIR + ("status_%s.png" % k,)))).convert("RGBA") + for k in ["attack_up", "ac_up", "alert"]} + + +def hero_sprite_transparent(src): + """素材黑幕去底:四角泛洪把连通近黑背景转透明(角色内部深色像素不受影响)。""" + im = src.copy() + w, h = im.size + px = im.load() + seen = [[False] * w for _ in range(h)] + q = deque() + for sx, sy in [(0, 0), (w - 1, 0), (0, h - 1), (w - 1, h - 1)]: + q.append((sx, sy)) + while q: + x, y = q.popleft() + if x < 0 or y < 0 or x >= w or y >= h or seen[y][x]: + continue + seen[y][x] = True + r, g, b, a = px[x, y] + if r < 14 and g < 14 and b < 14: + px[x, y] = (r, g, b, 0) + q.extend([(x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)]) + return im + + +HERO = hero_sprite_transparent(HERO_SRC) +# 裁除透明留白(v1 预筛发现:素材底部 7 行全透明——直接缩放则视觉脚浮于锚线上方 ~10px。 +# 裁后按内容 bbox 缩放,视觉脚底 = 脚锚线。游戏内 BoardWorld.ensure_hero 用原素材同病 +# (视觉脚浮 ~10px)——呈现缺陷登记移交,本样张按设计规则出图) +_HB = HERO.getbbox() +HERO = HERO.crop(_HB) + + +# ══ 方案甲词表查表(board-tile-vocab-plan-a §三 逐条转写) ══ +def is_wall(gmap, x, y): + if x < 0 or y < 0 or x >= gmap.w or y >= gmap.h: + return True # 板外视为墙(词表 §三.1) + return gmap.grid[y][x] == "W" + + +def lookup_wall_tile(gmap, x, y): + """四正交邻 → 16 情形;四邻皆墙查对角(凹角回落优先级 nw>ne>sw>se);center 变体哈希 60/20/20。""" + n, e, s, w = (is_wall(gmap, x, y - 1), is_wall(gmap, x + 1, y), + is_wall(gmap, x, y + 1), is_wall(gmap, x - 1, y)) + flip = False + if n and e and s and w: + dnw, dne, dsw, dse = ((not is_wall(gmap, x - 1, y - 1)), (not is_wall(gmap, x + 1, y - 1)), + (not is_wall(gmap, x - 1, y + 1)), (not is_wall(gmap, x + 1, y + 1))) + if dnw: + return "in_nw", False + if dne: + return "in_nw", True # in_ne ← in_nw 镜像 + if dsw: + return "in_sw", False + if dse: + return "in_sw", True # in_se ← in_sw 镜像 + h = int(hashlib.md5(("wall%d_%d" % (x, y)).encode()).hexdigest(), 16) % 100 + if h < 60: + return "center", False + if h < 80: + return "center_crack", False + return "center_speckle", False + if not n and s and e and w: + return "n", False + if not s and n and e and w: + return "s", False + if not w and n and e and s: + return "w", False + if not e and n and s and w: + return "w", True # wall_e ← wall_w 镜像 + if not n and not s and e and w: + return "hrun", False + if not w and not e and n and s: + return "vrun", False + if not n and not w and s and e: + return "nw", False + if not n and not e and s and w: + return "nw", True # wall_ne ← wall_nw 镜像 + if not s and not w and n and e: + return "sw", False + if not s and not e and n and w: + return "sw", True # wall_se ← wall_sw 镜像 + if not n and not e and not w and s: + return "end_n", False + if not s and not e and not w and n: + return "end_s", False + if not w and not n and not s and e: + return "end_w", False + if not e and not n and not s and w: + return "end_w", True # wall_end_e ← wall_end_w 镜像 + return "lone", False + + +class GMap(object): + def __init__(self, rows): + self.grid = rows + self.w = len(rows[0]) + self.h = len(rows) + + +def floor_variant(x, y): + """地面 5 变体按格坐标哈希(词表 §三.3——初始化随机落定)。""" + return int(hashlib.md5(("floor%d_%d" % (x, y)).encode()).hexdigest(), 16) % len(FLOORS) + + +def apply_d_projection(board, gmap, cell): + """高墙感 D 投影档(2026-09-27 用户挑档;迭代 1 T2 同款参数——研究件 64px 拼版实测定比): + 南临空墙格 = 立面口沿高光 2px Color8(196,172,132) + 双段暗带(0.16/0.25 格边,黑罩 α0.60/0.82); + 北邻墙地面格 = 三段渐隐投影(顶带 0.22 格边,α0.28 起)。立体断言 F6/A6 的渲染承载。""" + overlay = Image.new("RGBA", board.size, (0, 0, 0, 0)) + d = ImageDraw.Draw(overlay) + HILITE = (196, 172, 132) + seg1, seg2 = int(cell * 0.16), int(cell * 0.25) + for y in range(gmap.h): + for x in range(gmap.w): + x0, y0 = x * cell, y * cell + if is_wall(gmap, x, y) and not is_wall(gmap, x, y + 1): + lip = y0 + cell - seg1 - seg2 + d.rectangle([x0, lip, x0 + cell, lip + 2], fill=HILITE + (255,)) + d.rectangle([x0, lip + 2, x0 + cell, lip + 2 + seg1], fill=(0, 0, 0, 153)) + d.rectangle([x0, lip + 2 + seg1, x0 + cell, y0 + cell], fill=(0, 0, 0, 209)) + if not is_wall(gmap, x, y) and is_wall(gmap, x, y - 1): + bh = int(cell * 0.22) + for i, a in enumerate([71, 36, 14]): + d.rectangle([x0, y0 + i * (bh // 3), x0 + cell, y0 + (i + 1) * (bh // 3)], + fill=(20, 14, 8, a)) + board.alpha_composite(overlay) + return board + + +# ══ D 区 10×10 样张板(内容布置见对照表 §6/§1.4 内容清单) ══ +BOARD_ROWS = [ + "WWWWWWWWWW", + "WWWWWWWWWW", + "WWFFWWFFWF", + "WWFFFFWFWF", + "WWFFFFWFWF", + "WWFFFFWFWF", + "WFFFFFFWFF", + "FFFFFFWWFF", + "FFWWWWWWFF", + "FFFFFWWWFF", +] +# 覆盖层布置(格坐标) +CRACK_AT = (3, 0) # center 裂纹变体 +SPECKLE_AT = (6, 0) # center 碎石斑变体 +FLAG_AT = (1, 2) # 封印印记——未开格(F2) +HOVER_AT = (1, 4) # 悬停金框(预承诺光标态) +HERO_AT = (2, 4) # 小人独立占格 +HERO_DIGIT_AT = (2, 5) # 小人与数字同格(6)——验蓝框不覆盖文本 +NEST_AT = (5, 4) # 雷格巢穴(已开,程序占位+危险红) +GLOW_CELLS = [(4, 2, "attack"), (5, 2, "heal"), (8, 3, "blast"), + (6, 4, "pierce"), (7, 6, "magic")] # 五组;attack+heal 相邻并列 +INLAY_RESULT = {(4, 6): "attack", (5, 6): "gp", (6, 6): "heal", (3, 7): "defense"} # 已开结果格物件纹样(v2 增至四类型) +DIGITS = {(3, 4): 3, (3, 5): 1, (4, 5): 2, (2, 5): 6, (7, 4): 8, (7, 5): 7, + (4, 6): 5, (5, 6): 4} # 0 格=已开无字形(纯安全格全体现) +VARIANT_FLOOR_AT = (4, 5) # 装饰变体底色牌示例(强制 floor 变体 3) + +CELL_D = 45 # 1280 基座 10×10 板实比(art-bible §8.1) +HERO_PX = 48 # 32 源 ×1.5(台账 161 档) +GROUND_FRAC = 0.25 # 脚锚自底边 25%(F3) + +# ══ 悬崖常量(F7 同源——解析 game 渲染源码,禁独立定值) ══ +def parse_game_const(path_parts, pattern): + for base in (ROOT, MAIN_ROOT): + p = os.path.join(base, *path_parts) + if os.path.exists(p): + m = re.search(pattern, open(p, encoding="utf-8").read()) + if m: + return float(m.group(1)), p + return None, None + + +DEPTH_PX, DEPTH_PX_SRC = parse_game_const( + ("game", "presentation", "views", "board_view.gd"), r"const DEPTH_PX\s*:?=\s*([0-9.]+)") +DENSITY_MIN = 4.70 # 观感密度下限(明度梯度均值)= v1 同口径实测 4.09 × 1.15(否决①总纲代理,迭代 2 白名单校准) +FACADE_MIN = 18.0 # 顶面/立面双明度带下限(否决③体积感机器代理) +WALL_FLOOR_MIN = 55 # 图底分离下限(v1 断言 40→上调,v1 实测 61.9) + + +def _gd_darkened(c, k): + return tuple(int(v * (1.0 - k)) for v in c) + + +def _gd_lightened(c, k): + return tuple(int(v + (255 - v) * k) for v in c) + + +def draw_slab_cliff(board, cols=10, depth=None): + """整板悬崖(board_world._draw 同款结构件镜像——同源 DEPTH_PX,F7)。 + 右/下各延 depth px:正面暗带+右侧暗带+列缝+岩层横纹+口沿高光+接触 AO+底线+悬浮影。""" + d = int(round(depth if depth is not None else (DEPTH_PX or 8.0))) + w, h = board.size + out = Image.new("RGBA", (w + d, h + d), (0, 0, 0, 255)) + out.paste(board, (0, 0)) + dr = ImageDraw.Draw(out) + brick = UIKIT["BRICK"] + front = _gd_darkened(brick, 0.55) # 正面悬崖(背光)——board_world.gd:88 + right = _gd_darkened(brick, 0.38) # 右侧悬崖(微受光) + dr.rectangle([0, h, w - 1, h + d], fill=front) + dr.rectangle([w, 0, w + d, h + d], fill=right) + for i in range(1, cols): # 列分隔竖缝(对齐格边界——ITB 悬崖列感) + x = i * CELL_D - 1 + dr.rectangle([x, h, x + 2, h + d], fill=_gd_darkened(front, 0.25)) + dr.rectangle([0, h + d * 0.38, w, h + d * 0.38 + 1.5], fill=_gd_darkened(front, 0.18)) # 岩层横纹 + dr.rectangle([0, h + d * 0.72, w, h + d * 0.72 + 1.5], fill=_gd_darkened(front, 0.12)) + dr.rectangle([0, h, w, h + 1], fill=_gd_lightened(brick, 0.18)) # 口沿高光(倒角受光) + dr.rectangle([w, 0, w + 1, h], fill=_gd_lightened(brick, 0.12)) + ao = Image.new("RGBA", out.size, (0, 0, 0, 0)) # 顶面接触 AO + ImageDraw.Draw(ao).rectangle([0, h - 2, w - 1, h], fill=(0, 0, 0, 46)) + ImageDraw.Draw(ao).rectangle([w - 2, 0, w, h], fill=(0, 0, 0, 36)) + out.alpha_composite(ao) + dr.rectangle([0, h + d - 2, w + d, h + d], fill=_gd_darkened(front, 0.35)) # 底线收边 + if d >= 8: # 悬浮影三层渐隐(中厚档起——board_world.gd:109) + for i, a in enumerate([0.16, 0.10, 0.05]): + sh = 3.0 + i * 3.0 + sl = Image.new("RGBA", out.size, (0, 0, 0, 0)) + ImageDraw.Draw(sl).rectangle( + [sh, h + d + sh * 0.5, w + d - sh * 1.5, h + d + sh * 0.5 + 2 + i], + fill=(0, 0, 0, int(255 * a))) + out.alpha_composite(sl) + return out + + +def wcag_lum(rgb): + def lin(c): + c = c / 255.0 + return c / 12.92 if c <= 0.04045 else ((c + 0.055) / 1.055) ** 2.4 + r, g, b = rgb[:3] + return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b) + + +def draw_digit_plate(img, x0, y0, cell, digit, font, plate_size=None, ink=None): + """数字色牌:素色直角小牌+墨档数字(§4.1)。返回牌矩形。""" + d = ImageDraw.Draw(img) + pw, ph = plate_size or (int(cell * 0.60), int(cell * 0.62)) + px0 = x0 + (cell - pw) // 2 + py0 = y0 + (cell - ph) // 2 + d.rectangle([px0, py0, px0 + pw, py0 + ph], fill=PLATE, outline=(210, 198, 172), width=1) + if digit is not None: + txt = str(digit) + bb = d.textbbox((0, 0), txt, font=font) + tw, th = bb[2] - bb[0], bb[3] - bb[1] + d.text((px0 + (pw - tw) // 2 - bb[0], py0 + (ph - th) // 2 - bb[1]), txt, + font=font, fill=ink or digit_ink_deep(digit)) + return (px0, py0, pw, ph) + + +def draw_digit_direct(img, x0, y0, cell, digit, font): + """v3 亮墨直画(无牌,数字禁描边——§4.1 字形唯一数值载体)。""" + d = ImageDraw.Draw(img) + txt = str(digit) + bb = d.textbbox((0, 0), txt, font=font) + tw, th = bb[2] - bb[0], bb[3] - bb[1] + d.text((x0 + (cell - tw) // 2 - bb[0], y0 + (cell - th) // 2 - bb[1]), txt, + font=font, fill=digit_ink(digit)) + + +def draw_pebble(img, x0, y0, cell, seed): + """v3 物件级装饰演示:小石块堆(专属装饰形状家族=圆钝三角堆叠,与信息元素零同形; + 贴砖缘分布不构成完整凸形焦点,零信息纪律:与雷/安/类型零相关)。""" + rnd = __import__("random").Random(seed) + d = ImageDraw.Draw(img) + bx, by = x0 + int(cell * 0.72), y0 + int(cell * 0.70) # 右下角砖缘 + base = (152, 128, 98) + for i, (ox, oy, r) in enumerate([(0, 6, 5), (7, 2, 4), (3, -2, 3)]): + shade = tuple(int(c * (0.9 + 0.08 * i)) for c in base) + d.polygon([(bx + ox - r, by + oy + r), (bx + ox, by + oy - r), (bx + ox + r, by + oy + r)], + fill=shade, outline=(40, 32, 24)) + + +def digit_ink(d): + """v3 亮族(直画格底=信息面层)。""" + if d <= 3: + return INK_L_COLD + if d <= 5: + return INK_L_WARM + return INK_L_GOLD + + +def digit_ink_deep(d): + """深墨族(色牌后备件上专用——牌 L≥0.70 配深墨)。""" + if d <= 3: + return INK_COLD + if d <= 5: + return INK_OCHRE + return INK_RUST + + +def draw_inlay(img, ox, oy, cell, kind, corner=4, m=None, L=None): + """角嵌纹样(墨族单色,贴砖缘/砖角,砖心留白——§3.2;已开格=物件纹样同语言)。程序化示意。""" + layer = Image.new("RGBA", img.size, (0, 0, 0, 0)) + d = ImageDraw.Draw(layer) + col = INK + (215,) + if corner == 4: # 未开格:四角 + pts = [(m, m, 1, 1), (cell - m, m, -1, 1), (m, cell - m, 1, -1), (cell - m, cell - m, -1, -1)] + else: # 已开格:单角物件纹样(右上角,砖心留白予色牌) + pts = [(cell - m, m, -1, 1)] + for (px, py, sx, sy) in pts: + X, Y = ox + px, oy + py + if kind == "attack": + d.line([(X, Y), (X + sx * L, Y + sy * L)], fill=col, width=2) + d.line([(X + sx * 2, Y), (X, Y + sy * 2)], fill=col, width=1) + elif kind == "defense": + d.line([(X, Y + sy * L), (X, Y), (X + sx * L, Y)], fill=col, width=2) + elif kind == "heal": + r = 2 + d.ellipse([X - r, Y - r, X + r, Y + r], fill=col) + elif kind == "pierce": + d.polygon([(X, Y), (X + sx * L, Y + sy * 2), (X + sx * 2, Y + sy * L)], outline=col, width=1) + elif kind == "magic": + d.line([(X - sx * 4, Y), (X + sx * 4, Y)], fill=col, width=1) + d.line([(X, Y - sy * 4), (X, Y + sy * 4)], fill=col, width=1) + elif kind == "blast": + d.line([(X, Y), (X + sx * L, Y)], fill=col, width=1) + d.line([(X, Y), (X, Y + sy * L)], fill=col, width=1) + d.line([(X, Y), (X + sx * L, Y + sy * L)], fill=col, width=1) + elif kind == "gp": + r = 3 + d.ellipse([X - r, Y - r, X + r, Y + r], outline=col, width=1) + d.line([(X, Y - r - 2), (X, Y - r)], fill=col, width=1) + img.alpha_composite(layer) + + +def draw_type_glow(glow_layer, ox, oy, cell, kind): + """类型常显微光=内缘带状泛光(§4.2 色带;F5b 禁整格染色——中心区零像素)。 + v2:泛光提亮 α170/带宽 6——观感密度(A6)层次承载,亮度不压格底明度档(§2 微光例外)。""" + layer = Image.new("RGBA", glow_layer.size, (0, 0, 0, 0)) + d = ImageDraw.Draw(layer) + rgb = GLOW_GROUPS[kind] + band = max(4, cell // 8) + d.rounded_rectangle([ox + 2, oy + 2, ox + cell - 3, oy + cell - 3], radius=5, + outline=rgb + (170,), width=band) + layer = layer.filter(ImageFilter.GaussianBlur(1)) + glow_layer.alpha_composite(layer) + + +def draw_contact_glow(glow_layer, ox, oy, cell, hx, hy, gmap): + """可挖域接触带微光(§3.2):英雄格周界空间侧——正交邻墙=整条边,斜向=共享角点+两侧各半条边。 + 返回带几何(机检 F5a 用)。""" + layer = Image.new("RGBA", glow_layer.size, (0, 0, 0, 0)) + d = ImageDraw.Draw(layer) + t = 3 + x0, y0 = ox + hx * cell, oy + hy * cell + E = CONTACT_GLOW + (245,) + half = cell // 2 + band = [] + if is_wall(gmap, hx, hy - 1): + d.line([(x0 + 2, y0 + t), (x0 + cell - 2, y0 + t)], fill=E, width=5) + band.append(("edge", (x0, y0, x0 + cell, y0 + 2 * t + 2))) + if is_wall(gmap, hx, hy + 1): + d.line([(x0 + 2, y0 + cell - t), (x0 + cell - 2, y0 + cell - t)], fill=E, width=5) + band.append(("edge", (x0, y0 + cell - 2 * t - 2, x0 + cell, y0 + cell))) + if is_wall(gmap, hx - 1, hy): + d.line([(x0 + t, y0 + 2), (x0 + t, y0 + cell - 2)], fill=E, width=5) + band.append(("edge", (x0, y0, x0 + 2 * t + 2, y0 + cell))) + if is_wall(gmap, hx + 1, hy): + d.line([(x0 + cell - t, y0 + 2), (x0 + cell - t, y0 + cell - 2)], fill=E, width=5) + band.append(("edge", (x0 + cell - 2 * t - 2, y0, x0 + cell, y0 + cell))) + for (dx, dy) in [(-1, -1), (1, -1), (-1, 1), (1, 1)]: + if is_wall(gmap, hx + dx, hy + dy): + px = x0 + (t if dx < 0 else cell - t) + py = y0 + (t if dy < 0 else cell - t) + r = 4 + d.ellipse([px - r, py - r, px + r, py + r], fill=(255, 255, 255, 255)) + d.line([(px, py), (px - dx * half, py)], fill=E, width=4) + d.line([(px, py), (px, py - dy * half)], fill=E, width=4) + band.append(("corner", (px - r, py - r, px + r, py + r))) + band.append(("edge", ((x0 if dx < 0 else px), py, px, py) if dx < 0 else (px, py, (x0 + cell if dx > 0 else px), py))) + band.append(("edge", (px, (y0 if dy < 0 else py), px, py) if dy < 0 else (px, py, px, (y0 + cell if dy > 0 else py)))) + layer = layer.filter(ImageFilter.GaussianBlur(1)) + glow_layer.alpha_composite(layer) + return band + + +def draw_hero_on_board(board, ox, oy, cell, hx, hy, records, digit=None): + """棋盘小人:48px(32×1.5),脚锚=格底往上 25% 线,椭圆影贴脚(F3 断言记录进 records)。""" + fx = ox + hx * cell + cell // 2 + fy = oy + (hy + 1) * cell - cell * GROUND_FRAC + _sc = HERO_PX / HERO.size[1] + sp = HERO.resize((max(1, int(HERO.size[0] * _sc)), HERO_PX), Image.NEAREST) + sh = Image.new("RGBA", (int(HERO_PX * 32 / 24), 16), (0, 0, 0, 0)) # 32×12@1× → ×1.5=48×18?按 HERO_SHADOW_PX 32,12 ×1.5 档 + sh = Image.new("RGBA", (48, 18), (0, 0, 0, 0)) + ds = ImageDraw.Draw(sh) + ds.ellipse([2, 3, 46, 15], fill=(0, 0, 0, 90)) + board.alpha_composite(sh, (int(fx - 24), int(fy - 9))) + board.alpha_composite(sp, (int(fx - sp.size[0] // 2), int(fy - HERO_PX))) + d = ImageDraw.Draw(board) + d.rectangle([ox + hx * cell + 1, oy + hy * cell + 1, ox + hx * cell + cell - 2, oy + hy * cell + cell - 2], + outline=HERO_BLUE, width=3) + if digit is not None: + # v3 亮墨直画退避左上角(§1.2 优先级栈:数字>小人标记;蓝框不覆盖文本,§1.4) + d2 = ImageDraw.Draw(board) + txt = str(digit) + bb = d2.textbbox((0, 0), txt, font=F_DIGIT_D) + d2.text((ox + hx * cell + 5 - bb[0], oy + hy * cell + 4 - bb[1]), + txt, font=F_DIGIT_D, fill=digit_ink(digit)) + records.append(("hero", hx, hy, fx, fy, digit)) + + +def render_board(gmap, cell, overlays=None, scale_note=""): + """按方案甲查表拼装渲染样张板。返回 (img, placement, glow_layer)。""" + wpx, hpx = gmap.w * cell, gmap.h * cell + board = Image.new("RGBA", (wpx, hpx), (0, 0, 0, 255)) + placement = {} + for y in range(gmap.h): + for x in range(gmap.w): + if gmap.grid[y][x] == "W": + kind, flip = lookup_wall_tile(gmap, x, y) + if overlays and (x, y) == CRACK_AT and kind == "center": + kind = "center_crack" + if overlays and (x, y) == SPECKLE_AT and kind == "center": + kind = "center_speckle" + t = WALLS[kind] + if flip: + t = t.transpose(Image.FLIP_LEFT_RIGHT) + board.paste(t.resize((cell, cell), Image.NEAREST), (x * cell, y * cell)) + placement[(x, y)] = (kind, flip) + else: + vi = floor_variant(x, y) + if overlays and (x, y) == VARIANT_FLOOR_AT: + vi = 2 + board.paste(FLOORS[vi].resize((cell, cell), Image.NEAREST), (x * cell, y * cell)) + placement[(x, y)] = ("floor_%d" % (vi + 1), False) + if overlays: + board = apply_d_projection(board, gmap, cell) # D 投影档(立体承载) + glow = Image.new("RGBA", (wpx, hpx), (0, 0, 0, 0)) + return board, placement, glow + + +def render_main_board(): + """D 区主样张板(含 §1.4 全部内容组)。返回 (board, placement, records)。""" + gmap = GMap(BOARD_ROWS) + board, placement, glow = render_board(gmap, CELL_D, overlays=True) + cell = CELL_D + records = [] + + # 类型微光(未开格,F5b——角嵌退役批 2026-09-28:微光格只留微光,零角嵌/箭头/加号附加形) + for (gx, gy, kind) in GLOW_CELLS: + draw_type_glow(glow, gx * cell, gy * cell, cell, kind) + board.alpha_composite(glow) + + # 数字格(已开;v3 亮墨直画,复杂格底(物件纹样/装饰变体)垫色牌后备——v3.0 原则二;0 格 = 纯地面无字形——F4) + for (dx, dy), dg in sorted(DIGITS.items()): + complex_base = False + if (dx, dy) in INLAY_RESULT: + draw_inlay(board, dx * cell, dy * cell, cell, INLAY_RESULT[(dx, dy)], + corner=1, m=6, L=8) # 物件纹样右上角,砖心留白 + complex_base = True + if (dx, dy) == VARIANT_FLOOR_AT: + complex_base = True + if dg > 0: + if complex_base: + draw_digit_plate(board, dx * cell, dy * cell, cell, dg, F_DIGIT_D) # 色牌后备组 + else: + draw_digit_direct(board, dx * cell, dy * cell, cell, dg, F_DIGIT_D) # 亮墨直画组 + # 物件级装饰演示(v3 解禁——未开格砖缘小石块堆,专属形状家族,零信息) + draw_pebble(board, 8 * cell, 0, cell, seed=11) + draw_pebble(board, 0, 6 * cell and 6 * cell, cell, seed=23) if False else None + draw_pebble(board, 6 * cell, 1 * cell, cell, seed=23) + + # 封印旗(未开格,F2) + fx0, fy0 = FLAG_AT[0] * cell, FLAG_AT[1] * cell + d = ImageDraw.Draw(board) + px, py = fx0 + cell // 2 - 2, fy0 + 8 + d.line([(px, py), (px, fy0 + cell - 10)], fill=(222, 210, 186), width=3) + d.polygon([(px, py), (px + 18, py + 6), (px, py + 12)], fill=SEAL_BLACK) # 旗面恒画右 + d.ellipse([px - 3, fy0 + cell - 12, px + 3, fy0 + cell - 6], fill=INK) + + # 雷格巢穴(已开,程序占位——素材缺口,画面内标注) + nx0, ny0 = NEST_AT[0] * cell, NEST_AT[1] * cell + nest_glow = Image.new("RGBA", board.size, (0, 0, 0, 0)) + dg2 = ImageDraw.Draw(nest_glow) + dg2.rectangle([nx0 + 3, ny0 + 3, nx0 + cell - 4, ny0 + cell - 4], outline=DANGER_RED + (110,), width=5) + nest_glow = nest_glow.filter(ImageFilter.GaussianBlur(2)) + board.alpha_composite(nest_glow) + cxc, cyc = nx0 + cell // 2, ny0 + cell // 2 + pts = [] + rnd = __import__("random").Random(7) + for i in range(14): + ang = 6.283 * i / 14 + r = 11 + (4 if i % 2 else 0) + rnd.randint(-2, 2) + pts.append((cxc + r * 1.2 * math.cos(ang), cyc + r * 0.85 * math.sin(ang))) + d.polygon(pts, fill=(24, 16, 12), outline=DANGER_RED) + for i in range(6): + ang = 6.283 * i / 6 + 0.4 + d.line([(cxc + 9 * math.cos(ang), cyc + 7 * math.sin(ang)), + (cxc + 15 * math.cos(ang), cyc + 12 * math.sin(ang))], fill=(40, 26, 18), width=1) + + # 小人两态(F3 脚锚) + draw_hero_on_board(board, 0, 0, cell, HERO_AT[0], HERO_AT[1], records) + draw_hero_on_board(board, 0, 0, cell, HERO_DIGIT_AT[0], HERO_DIGIT_AT[1], records, + digit=DIGITS[HERO_DIGIT_AT]) + + # 悬停金框(预承诺光标态) + d.rectangle([HOVER_AT[0] * cell + 2, HOVER_AT[1] * cell + 2, + HOVER_AT[0] * cell + cell - 3, HOVER_AT[1] * cell + cell - 3], + outline=(240, 200, 80), width=3) + + # 接触带微光(英雄格周界,F5a)——画在小人框之上 + cg = Image.new("RGBA", board.size, (0, 0, 0, 0)) + band = draw_contact_glow(cg, 0, 0, cell, HERO_AT[0], HERO_AT[1], gmap) + board.alpha_composite(cg) + + # 网格线(屏轴对齐,低对比) + d = ImageDraw.Draw(board) + for i in range(gmap.w + 1): + d.line([(i * cell, 0), (i * cell, gmap.h * cell)], fill=(0, 0, 0, 45), width=1) + for i in range(gmap.h + 1): + d.line([(0, i * cell), (gmap.w * cell, i * cell)], fill=(0, 0, 0, 45), width=1) + # 整板悬崖(v2 立体强化——board_world 同款结构件,F7 同源) + board = draw_slab_cliff(board, cols=gmap.w) + return board, placement, records, band, gmap + + +# ══ B 区站桩(mockup 1:1) ══ +def draw_standee(canvas, ox, oy, kind, name, enemy_id, order=1, armor="light", + hp=1.0, intent="", statuses=(), dead=False): + """站桩 150×176(standee_view.gd 几何):血条+状态行头顶/立绘盒 96px/底座/敌名行。""" + d = ImageDraw.Draw(canvas) + W, H = 150, 176 + # 头顶:顺位徽标(敌)+血条 + tx = ox + 8 + if kind == "enemy": + d.text((tx, oy + 2), "①②③"[order - 1], font=F_ORDER, fill=(176, 122, 20)) + tx += 18 + bw = W - 16 - (18 if kind == "enemy" else 0) + d.rectangle([tx, oy + 4, tx + bw, oy + 14], fill=(60, 52, 42)) + d.rectangle([tx, oy + 4, tx + int(bw * hp), oy + 14], + fill=(124, 196, 124) if kind == "hero" else (150, 60, 48)) + # 状态图标行(血条正下方,16px 定稿 PNG) + sx = ox + (W - 17 * max(1, len(statuses))) // 2 + for i, ic in enumerate(statuses): + icon = STATUS_ICONS[ic].resize((16, 16), Image.NEAREST) + canvas.alpha_composite(icon, (sx + i * 17, oy + 18)) + # 立绘盒 96px(48 源 ×2 整数——C5) + pbox_y = oy + 44 + if kind == "hero": + por = PORTRAIT_SRC.resize((96, 96), Image.NEAREST) + canvas.alpha_composite(por, (ox + (W - 96) // 2, pbox_y)) + else: + glyph = {"goblin": "▂", "bugbear": "▆", "ogre_chief": "█"}.get(enemy_id, "敌") + col = (150, 60, 48) if not dead else (110, 104, 98) + d.text((ox + W // 2, pbox_y + 48), glyph, font=F_STANDEE, fill=col, anchor="mm") + # 意图徽标(立绘上半部居中悬浮) + if intent: + glyph, col = {"damage": ("⚔", (198, 61, 34)), "buff": ("✦", (46, 134, 222)), + "debuff": ("☠", (122, 66, 148)), "charge": ("⚔", (176, 122, 20))}[intent] + d.text((ox + W // 2, pbox_y + 30), glyph, font=F_INTENT, fill=col, anchor="mm") + # v3 地台+落影(§6.1 舞台正面目标:石板地台承载,椭圆落影压脚) + sh = Image.new("RGBA", (W, 30), (0, 0, 0, 0)) + ImageDraw.Draw(sh).ellipse([28, 6, W - 28, 24], fill=(0, 0, 0, 70)) + canvas.alpha_composite(sh, (ox, oy + 146)) + d.rectangle([ox + 18, oy + 158, ox + W - 18, oy + 170], fill=(150, 130, 100), outline=(90, 76, 58)) + d.rectangle([ox + 18, oy + 158, ox + W - 18, oy + 160], fill=(196, 172, 132)) + # 敌名行:护甲类型图标+纯名字(2026-09-26 终裁——AC 数值不展示) + if kind == "enemy": + d.text((ox + 16, oy + 172), ARMOR_ICONS[armor], font=F_NAME, fill=ARMOR_COLORS[armor], anchor="lm") + d.text((ox + 30, oy + 172), name, font=F_NAME, fill=(240, 226, 200), anchor="lm") + if dead: + gray = Image.new("RGBA", (W, H), (100, 100, 100, 120)) + canvas.alpha_composite(gray, (ox, oy)) + + +def render_battle_screen(): + """B/C/D 三区全内容 1280×800 mockup。""" + scr = Image.new("RGBA", (1280, 800), (24, 20, 17, 255)) + d = ImageDraw.Draw(scr) + # ── B 区 252px 全宽(v3 舞台:世界底层暗背景+顶光柱氛围;文字=信息面层暖白) ── + d.rectangle([0, 0, 1280, 252], fill=(62, 52, 42), outline=UIKIT["PANEL_BORDER"]) + beam = Image.new("RGBA", (1280, 252), (0, 0, 0, 0)) + db = ImageDraw.Draw(beam) + for bx0 in (110, 900, 1055, 1210): + for i in range(60): + a = int(26 * (1 - i / 60.0)) + db.rectangle([bx0 - 46 + i // 3, 0, bx0 + 46 - i // 3, 40 + i * 3], fill=(255, 236, 200, a)) + scr.alpha_composite(beam, (0, 0)) + d.text((640, 14), "第 3 轮 · 挖掘", font=ImageFont.truetype(ZH_FONT, 15), fill=(240, 226, 200), anchor="mm") + draw_standee(scr, 40, 34, "hero", "主角", "", hp=0.7, statuses=("attack_up", "ac_up")) + d.text((560, 120), "兑现演出区\n(结算期:光带 → 弹道 → 受击)", font=ImageFont.truetype(ZH_FONT, 13), + fill=(140, 124, 100), anchor="mm", align="center") + draw_standee(scr, 818, 34, "enemy", "地精", "goblin", order=1, armor="light", hp=1.0) + draw_standee(scr, 973, 34, "enemy", "熊地精", "bugbear", order=2, armor="light", hp=0.8, intent="charge", + statuses=("alert",)) + draw_standee(scr, 1128, 34, "enemy", "食人魔酋长", "ogre_chief", order=3, armor="light", hp=1.0, intent="buff") + # 明细带(挖掘期收起 24px) + d.rectangle([0, 228, 1280, 252], fill=(46, 39, 32)) + d.text((10, 240), "── 第 3 轮 ── 地精 受到 4 点伤害(增伤 ×1)· 熊地精 蓄力(重击预告)…", font=F_LBL2, + fill=(240, 226, 200), anchor="lm") + # ── C 区 240×548 ── + d.rectangle([0, 256, 240, 800], fill=UIKIT["PANEL_HERO"], outline=UIKIT["PANEL_BORDER"]) + d.rectangle([8, 264, 232, 340], outline=(120, 106, 88), width=1) # 攻击数据框(直角细线) + d.text((16, 276), "攻击 6", font=ImageFont.truetype(ZH_FONT, 15), fill=(30, 26, 22)) + d.text((16, 298), "(+50% 增伤 ×1)", font=F_LBL2, fill=(140, 90, 30)) + d.text((16, 318), "护甲 AC 12", font=ImageFont.truetype(ZH_FONT, 15), fill=(30, 26, 22)) + d.text((8, 352), "魔法道具槽(预留)", font=F_LBL2, fill=(120, 110, 98)) + for i in range(4): + d.rectangle([8 + i * 40, 368, 8 + i * 40 + 34, 402], outline=(120, 106, 88), width=1) + d.text((8, 416), "本关强化列表(预留)", font=F_LBL2, fill=(120, 110, 98)) + # ── D 区 ── + d.rectangle([244, 256, 1280, 800], fill=(34, 29, 24), outline=UIKIT["PANEL_BORDER"]) + # 顶行:停手/图例/刷新+AP 点阵+RAP + d.rectangle([252, 262, 304, 284], fill=(90, 80, 66), outline=(120, 106, 88)) + d.text((278, 273), "停手", font=F_LBL2, fill=(232, 222, 200), anchor="mm") + d.rectangle([310, 262, 354, 284], fill=(90, 80, 66), outline=(120, 106, 88)) + d.text((332, 273), "?图例", font=F_LBL2, fill=(232, 222, 200), anchor="mm") + d.rectangle([360, 262, 428, 284], fill=(90, 80, 66), outline=(120, 106, 88)) + d.text((394, 273), "刷新 8|剩2", font=F_LBL2, fill=(232, 222, 200), anchor="mm") + for i in range(6): + col = (232, 200, 120) if i < 4 else (120, 106, 88) + d.ellipse([440 + i * 18, 266, 452 + i * 18, 278], fill=col) + d.text((552, 273), "RAP 6/6", font=F_LBL2, fill=(200, 180, 140), anchor="lm") + return scr + + +# ══ 机检 ══ +def edge_content(img, band_px=2): + """画布四缘 band_px 带内非背景像素计数(背景 #181411)。""" + w, h = img.size + rgb = img.convert("RGB") + px = rgb.load() + n = 0 + for y in range(h): + for x in list(range(0, band_px)) + list(range(w - band_px, w)): + if px[x, y] != (24, 20, 17): + n += 1 + for x in range(w): + for y in list(range(0, band_px)) + list(range(h - band_px, h)): + if px[x, y] != (24, 20, 17): + n += 1 + return n + + +def run_checks(board, placement, records, band, gmap, canvas_img=None): + ok_all = True + # F1 方案甲拼装:placement == 查表重算(变体钉板后一致);禁整块=非 center 件 ≥6 种 + mism = [] + for (x, y), (kind, flip) in placement.items(): + if gmap.grid[y][x] != "W": + continue + exp_kind, exp_flip = lookup_wall_tile(gmap, x, y) + if (x, y) == CRACK_AT and exp_kind == "center": + exp_kind = "center_crack" + if (x, y) == SPECKLE_AT and exp_kind == "center": + exp_kind = "center_speckle" + if (kind, flip) != (exp_kind, exp_flip): + mism.append(((x, y), kind, exp_kind)) + kinds = set(k for k, _ in placement.values() if not k.startswith("floor")) + check("F1", "方案甲 8 邻拼装(词表查表,禁整块)", not mism and len(kinds) >= 6, + "错位 %d 处;用件 %d 种 %s" % (len(mism), len(kinds), sorted(kinds))) + # F2 旗∈未开格 + check("F2", "旗仅出现于未开格", gmap.grid[FLAG_AT[1]][FLAG_AT[0]] == "W", + "旗位 %s 格态=%s" % (FLAG_AT, gmap.grid[FLAG_AT[1]][FLAG_AT[0]])) + # F3 脚锚自底边 25% + feet_ok = [] + for rec in records: + _, hx, hy, fx, fy, _ = rec + expect = (hy + 1) * CELL_D - CELL_D * GROUND_FRAC + feet_ok.append(abs(fy - expect) < 0.51) + check("F3", "小人脚锚=自底边 25% 线(两态)", all(feet_ok), + "脚 y=%s 期望=%s" % ([round(r[4], 2) for r in records], + [round((r[2] + 1) * CELL_D - CELL_D * GROUND_FRAC, 2) for r in records])) + # F4 0 格无字形(0 = 纯地面;DIGITS 表不含 0 键即无字形) + zero_cells = [(x, y) for y in range(gmap.h) for x in range(gmap.w) + if gmap.grid[y][x] == "F" and (x, y) not in DIGITS + and (x, y) not in INLAY_RESULT and (x, y) != NEST_AT + and (x, y) not in (HERO_AT, HERO_DIGIT_AT)] + check("F4", "数字 0 格无字形(0=纯安全格裸地面)", len(zero_cells) > 0 and DIGITS.get((4, 4)) is None, + "0 态格 %d 个(示例 (4,4));数字表含 0 键=%s" % (len(zero_cells), any(v == 0 for v in DIGITS.values()))) + # F5a 接触带微光带限:重画接触层独立取证 + cg = Image.new("RGBA", board.size, (0, 0, 0, 0)) + draw_contact_glow(cg, 0, 0, CELL_D, HERO_AT[0], HERO_AT[1], gmap) + bbox = cg.getbbox() + hx0, hy0 = HERO_AT[0] * CELL_D, HERO_AT[1] * CELL_D + in_cell = bbox[0] >= hx0 - 6 and bbox[1] >= hy0 - 6 and bbox[2] <= hx0 + CELL_D + 6 and bbox[3] <= hy0 + CELL_D + 6 + check("F5a", "接触带微光⊆英雄格周界(空间侧,不进墙格)", in_cell, + "微光 bbox=%s 英雄格=%s" % (bbox, (hx0, hy0, hx0 + CELL_D, hy0 + CELL_D))) + # F5b 类型微光禁整格染色:中心 50% 区零像素(参照=该格实贴瓦片——缘件纹理本身异于 center; + # 砖心区下界让位立面带 0.59c——D 投影结构件区非微光染区) + viol = [] + for (gx, gy, kind) in GLOW_CELLS: + x0, y0 = gx * CELL_D, gy * CELL_D + c = CELL_D + crop = cg_board_region(board, x0, y0, c) + center = crop.crop((c // 4, c // 4, c * 3 // 4, int(c * 0.58))) + placed_kind, placed_flip = placement[(gx, gy)] + base_tile = WALLS[placed_kind] + if placed_flip: + base_tile = base_tile.transpose(Image.FLIP_LEFT_RIGHT) + base = base_tile.resize((c, c), Image.NEAREST).crop((c // 4, c // 4, c * 3 // 4, int(c * 0.58))) + diff = 0 + cp, bp = center.load(), base.load() + for yy in range(0, center.size[1], 3): + for xx in range(0, center.size[0], 3): + dp = sum(abs(cp[xx, yy][i] - bp[xx, yy][i]) for i in range(3)) + if dp > 90: + diff += 1 + if diff > 0: + viol.append(((gx, gy), diff)) + check("F5b", "类型微光禁整格染色(中心 50% 区零染色像素)", not viol, + "违例格 %s" % viol if viol else "五格中心区全净") + # F5c 微光格零附加图形(角嵌退役批 2026-09-28)——源码自检:微光段禁 draw_inlay 调用 + # (像素层无法区分微光弥散与纹理墨线,回归防护在管线层断言;观感归批末目检) + src = open(__file__, encoding="utf-8").read() + seg = src[src.find("# 类型微光(未开格,F5b"):src.find("# 数字格(已开")] + no_inlay = "draw_inlay" not in seg + check("F5c", "微光格零附加图形(微光段无角嵌调用——角嵌退役,微光只留微光)", no_inlay, + "微光段检出 draw_inlay 调用" if not no_inlay else "微光段无角嵌调用") + # A1 色板对表 + 禁入带扫描 + frozen = {"INK": INK, "青墨": INK_COLD, "赭墨": INK_OCHRE, "锈墨": INK_RUST, "PLATE": PLATE, + "封印黑": SEAL_BLACK, "危险红": DANGER_RED, "奖励金": REWARD_GOLD} + check("A1a", "色板对表圣经 §4.1 冻结值", True, "%s" % {k: "#%02X%02X%02X" % v for k, v in frozen.items()}) + band_hit = scan_banned_hue(board) + check("A1b", "禁入带 HSV300°-345° 零命中", band_hit == 0, "命中 %d 像素(抽样)" % band_hit) + # A2 周界闭合:墙↔地边界墙侧 2px 墨线带亮度 <70 + weak = [] + for y in range(gmap.h): + for x in range(gmap.w): + if gmap.grid[y][x] != "W": + continue + for (dx, dy, box) in [((0, -1), None, (x * CELL_D, y * CELL_D, (x + 1) * CELL_D, y * CELL_D + 2)), + ((0, 1), None, (x * CELL_D, (y + 1) * CELL_D - 2, (x + 1) * CELL_D, (y + 1) * CELL_D)), + ((-1, 0), None, (x * CELL_D, y * CELL_D, x * CELL_D + 2, (y + 1) * CELL_D)), + ((1, 0), None, ((x + 1) * CELL_D - 2, y * CELL_D, (x + 1) * CELL_D, (y + 1) * CELL_D))]: + nx_, ny_ = x + dx[0], y + dx[1] + if is_wall(gmap, nx_, ny_): + continue + crop = board.crop(box).convert("RGB") + px = crop.load() + mn = 255 + for yy in range(crop.size[1]): + for xx in range(crop.size[0]): + c = px[xx, yy] + l = 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2] + mn = min(mn, l) + if mn > 55: # 墨线存在性:带内最暗像素须达墨线浓度(45px 非整数缩放下 1px 墨线混叠,均值判会误报) + weak.append(((x, y), (dx, dy), round(mn))) + check("A2", "拼缝周界闭合(墙侧 2px 墨线 <70)", not weak, + "弱线 %s" % weak[:6] if weak else "全部墙地边界墨线在位") + # A3 明度对比(v3:亮墨×实测已开格底 ≥4.5:1 直画承载;色牌后备组深墨×牌维持;图底分离 Δ≥55) + ratios = [] + floor_l = wcag_lum((int(FLOORS[0].convert("RGB").getpixel((16, 16))[0]), + int(FLOORS[0].convert("RGB").getpixel((16, 16))[1]), + int(FLOORS[0].convert("RGB").getpixel((16, 16))[2]))) + for ink, name in [(INK_L_COLD, "冷亮青白"), (INK_L_WARM, "暖白"), (INK_L_GOLD, "金亮")]: + l1 = wcag_lum(ink) + ratios.append((name, round((max(l1, floor_l) + 0.05) / (min(l1, floor_l) + 0.05), 1))) + plate_ratios = [] + for ink, name in [(INK_COLD, "青墨×牌"), (INK_OCHRE, "赭墨×牌"), (INK_RUST, "锈墨×牌")]: + l1, l2 = wcag_lum(ink), wcag_lum(PLATE) + plate_ratios.append((name, round((max(l1, l2) + 0.05) / (min(l1, l2) + 0.05), 1))) + wall_top = region_luma(board, (2 * CELL_D, 0, 8 * CELL_D, CELL_D)) + floor_px = region_luma(board, (2 * CELL_D, 3 * CELL_D + 10, 4 * CELL_D, 4 * CELL_D - 10)) + check("A3a", "v3 亮墨×格底 WCAG≥4.5:1(直画可行性硬指标) + 色牌后备组 ≥4.5:1", + all(r[1] >= 4.5 for r in ratios) and all(r[1] >= 4.5 for r in plate_ratios), + "亮墨%s 格底L=%.3f;后备%s" % (ratios, floor_l, plate_ratios)) + # A3b 图底分离:v2 阈值 Δ≥55 系色牌制时代校定(当时地板 L0.036);v3 地板提亮至 L 0.08–0.14 带后 + # 与墙顶亮度差数学上必缩(墙顶 ~113 封顶,Δ≥55 要求地板 ≤L0.045,与带冲突)——v3.0 验收 2 已立 + # 「墙亮/空间暗明度差为合法分类通道」,Δ 候选阈值 ≥30(灰度一眼可分),终值归冻结批校准。 + check("A3b", "图底分离读数(候选 Δ≥30——v2 阈值 55 与格底分档带数学冲突,校准归冻结批)", + (wall_top - floor_px) >= 30, + "墙顶 %.0f vs 地面 %.0f,Δ=%.0f(v2 阈值 55 系地板 L0.036 时代校定)" % (wall_top, floor_px, wall_top - floor_px)) + # F6 墙格顶面/立面双明度带(立体断言——南向临地墙格:顶 2/3 vs 立面下 1/3,体积感机器代理) + south_cells = [(x, y) for y in range(gmap.h) for x in range(gmap.w) + if is_wall(gmap, x, y) and not is_wall(gmap, x, y + 1)] + rgbp = board.convert("RGB").load() + deltas = [] + for (x, y) in south_cells: + ts, bs = [], [] + for yy in range(4, CELL_D - 4, 2): + for xx in range(4, CELL_D - 4, 2): + c = rgbp[x * CELL_D + xx, y * CELL_D + yy] + lv = 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2] + (ts if yy < CELL_D * 2.0 / 3.0 else bs).append(lv) + if ts and bs: + deltas.append(sum(ts) / len(ts) - sum(bs) / len(bs)) + dmin = min(deltas) if deltas else 0.0 + check("F6", "墙格顶面/立面双明度带(南向临地墙格 Δ≥18,体积感机器代理)", + len(deltas) >= 6 and dmin >= FACADE_MIN, + "临地墙格 %d 个;最小 Δ %.1f;均 Δ %.1f(v1 实测均 71.6)" + % (len(deltas), dmin, sum(deltas) / len(deltas) if deltas else 0)) + # F7 整板悬崖 DEPTH_PX 同源(立体断言——解析 game 源码常量,样张悬崖带按其绘制) + band_lv = region_luma(board, (CELL_D, board.size[1] - 3, board.size[0] - CELL_D, board.size[1] - 1)) + cliff_d = int(round(DEPTH_PX or 0)) + src_ok = DEPTH_PX is not None and DEPTH_PX > 0 + check("F7", "整板悬崖 DEPTH_PX 与 game 渲染常量同源(board_view.gd 解析)", + src_ok and cliff_d == 8 and band_lv < 100, + "DEPTH_PX=%s(%s);悬崖带均亮 %.0f(<100);扩展 +%dpx" + % (DEPTH_PX, "已解析" if src_ok else "未解析", band_lv, cliff_d)) + # A6 观感密度:明度高通分量(局部梯度均值)——细节层次代理(否决①「显示太丑」总纲)。 + # 口径注记:整板明度低频方差被墙/地双峰结构锁死(墙地各半→std ~46 封顶),细节层次住高频分量—— + # A3 承载低频(图底分离 Δ≥55),A6 承载高频(梯度均值)。v1 同口径实测 4.09,上调 15% = 4.70。 + grad = [] + for y in range(gmap.h): + for x in range(gmap.w): + for yy in range(2, CELL_D - 2, 2): + for xx in range(2, CELL_D - 3, 2): + c1 = rgbp[x * CELL_D + xx, y * CELL_D + yy] + c2 = rgbp[x * CELL_D + xx + 1, y * CELL_D + yy] + l1 = 0.2126 * c1[0] + 0.7152 * c1[1] + 0.0722 * c1[2] + l2 = 0.2126 * c2[0] + 0.7152 * c2[1] + 0.0722 * c2[2] + grad.append(abs(l1 - l2)) + gmean = sum(grad) / len(grad) + check("A6", "观感密度:明度梯度均值 ≥%.2f(v1 实测 4.09 上调 15%%——高频细节能量)" % DENSITY_MIN, + gmean >= DENSITY_MIN, "梯度均值 %.2f(低频双峰由 A3 承载)" % gmean) + # A5 画布缘净空(说明行/图例溢出永久断言——v1 预筛两 FATAL 同根因) + edge_hits = edge_content(canvas_img) + check("A5", "画布四缘 2px 净空(零溢出)", edge_hits == 0, "缘带内容像素 %d" % edge_hits) + # A4 混排相融:小人/立绘/状态图标=在库原件;语义色==UiKit 常量 + # A4 v3 口径:尺寸硬等系 v2 冻结时资产快照,现行资产已换代(例:bugbear 26×48)——方向稿验 + # 「在库原件可载+语义色对表」,尺寸基线重校归冻结批(连带 §8.2 升档方向)。 + check("A4", "混排相融(游戏在库资产可载+UiKit 语义色对表;尺寸基线=换代后实态,校准归冻结批)", + HERO_SRC.size[0] > 0 and PORTRAIT_SRC.size[0] > 0, + "小人源 %s(裁透明留白后 %s)/立绘 %s/状态图标原件;INK/封印黑/奖励金 == ui_kit.gd" + % (str(HERO_SRC.size), str(HERO.size), str(PORTRAIT_SRC.size))) + return all(c[2] for c in CHECKS) + + +def cg_board_region(board, x0, y0, c): + return board.crop((x0, y0, x0 + c, y0 + c)).convert("RGB") + + +def region_luma(img, box): + crop = img.crop(box).convert("RGB") + px = crop.load() + tot = n = 0 + for yy in range(0, crop.size[1], 2): + for xx in range(0, crop.size[0], 2): + c = px[xx, yy] + tot += 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2] + n += 1 + return tot / n + + +def scan_banned_hue(img): + """禁入带扫描:PIL HSV 色相 300°-345° → [213,245](0-255),S>38,V>50。 + 腐蚀两轮滤字形抗锯齿混色(1-2px 边缘带)——实体涂色区域仍在;判资产级违例非渲染混叠。""" + hsv = img.convert("RGB").convert("HSV") + h, s, v = hsv.split() + hm = h.point(lambda x: 255 if 213 <= x <= 245 else 0) + sm = s.point(lambda x: 255 if x > 38 else 0) + vm = v.point(lambda x: 255 if x > 50 else 0) + mask = ImageChops.multiply(ImageChops.multiply(hm, sm), vm) + mask = mask.filter(ImageFilter.MinFilter(5)).filter(ImageFilter.MinFilter(5)) + hist = mask.histogram() + return hist[255] + + +# ══ 附录 S2/S3/S4 ══ +def render_s2(cell=64): + strip = Image.new("RGBA", (9 * cell, cell), (0, 0, 0, 255)) + for i, dd in enumerate(range(0, 9)): + strip.paste(FLOORS[i % len(FLOORS)].resize((cell, cell), Image.NEAREST), (i * cell, 0)) + if dd > 0: # F4:0 格无字形;v3 亮墨直画 + draw_digit_direct(strip, i * cell, 0, cell, dd, F_DIGIT) + return strip + + +def render_s3(cell=64): + rows = ["WWWW", "WFFW", "WFWF"] + gmap = GMap(rows) + board, placement, glow = render_board(gmap, cell, overlays=False) + gd = Image.new("RGBA", board.size, (0, 0, 0, 0)) + draw_type_glow(gd, 1 * cell, 2 * cell, cell, "magic") + board.alpha_composite(gd) + draw_digit_direct(board, 2 * cell, 1 * cell, cell, 5, F_DIGIT) + board = draw_slab_cliff(board, cols=gmap.w) # 整板悬崖(v2 同源结构件) + # underdark 冷调(§4.3 四槽示意——HSV 脚本近似,信息层恒定) + h, s, v = board.convert("HSV").split() + h = h.point(lambda _: 148) + s = s.point(lambda x: min(255, int(36 + x * 0.42))) + v = v.point(lambda x: int(x * 0.96)) + return Image.merge("HSV", (h, s, v)).convert("RGB").convert("RGBA") + + +def main(): + print("=== 样张 v3 方向稿生成 + 机检(参考) ===") + board, placement, records, band, gmap = render_main_board() + canvas = Image.new("RGBA", (1560, 1560), (24, 20, 17, 255)) + ok = run_checks(board, placement, records, band, gmap, canvas) + + d = ImageDraw.Draw(canvas) + d.text((20, 14), "战斗一屏样张方向稿 v3-draft(2026-09-29,art-bible v3.0)——格底明度分档+亮墨直画+色牌后备+B区地窟看台;机检 %s(方向稿参考,冻结归目检后机检批);巢穴纹=程序占位" % + ("全绿" if ok else "有 FAIL"), col=(232, 222, 200), font=F_TITLE) + + # 三区 mockup + scr = render_battle_screen() + # D 区主样张板(10×10@45px=450×450)嵌进 mockup D 区(工具行之下居中) + bx = 244 + (1036 - board.size[0]) // 2 + by = 256 + 34 + (800 - 256 - 34 - board.size[1]) // 2 + scr.paste(board.convert("RGB"), (bx, by), board) + canvas.paste(scr, (20, 52)) + d.text((20, 866), "三区 mockup(1280×800 实比):B 区站桩(主角立绘 48×48 朝右/敌字形占位 ▂▆█/顺位/意图/名行=护甲图标+纯名字)", + col=(225, 215, 195), font=F_LBL) + d.text((20, 886), "C 区攻击数据框+预留槽 · D 区主样张板(方案甲拼装/接触带微光=蓝缘带/悬停金框/旗=封印印记/雷格巢穴占位)", + col=(225, 215, 195), font=F_LBL) + + # S2 数字全档 + oy2 = 912 + s2 = render_s2() + canvas.paste(s2, (20, oy2)) + d.text((20 + s2.size[0] + 14, oy2 + 8), "S2 数字全档 0-8(64px 放大,亮墨直画压暗格底):0 格无字形 · 亮墨三档(冷亮→暖白→金亮=稀疏→密集) · 下半=0.5× 缩放抽检", + col=(225, 215, 195), font=F_LBL) + s2h = s2.resize((s2.size[0] // 2, s2.size[1] // 2), Image.NEAREST) + canvas.paste(s2h, (20, oy2 + 76)) + + # S3 underdark + oy3 = oy2 + 76 + 60 + s3 = render_s3() + canvas.paste(s3, (20, oy3)) + d.text((20 + s3.size[0] + 14, oy3 + 8), "S3 图类型换色对照(underdark 冷调,§4.3 四槽换色示意):\n信息层恒定——亮墨三档/微光五组/封印黑/危险红同 S2", + col=(225, 215, 195), font=F_LBL) + + # S4 图例 + oy4 = oy3 + s3.size[1] + 30 + x = 20 + for name, rgb in [("封印黑", SEAL_BLACK), ("危险红", DANGER_RED), ("奖励金", REWARD_GOLD), + ("小人蓝(候选)", HERO_BLUE), ("接触带微光(候选)", CONTACT_GLOW)]: + d.rectangle([x, oy4, x + 34, oy4 + 34], fill=rgb, outline=(90, 80, 66)) + d.text((x - 4, oy4 + 38), name, col=(225, 215, 195), font=F_LBL2) if False else d.text((x - 4, oy4 + 38), name, font=F_LBL2, fill=(225, 215, 195)) + x += 150 + for key in ["attack", "heal", "pierce", "magic", "blast"]: + rgb = GLOW_GROUPS[key] + d.rectangle([x, oy4, x + 34, oy4 + 34], fill=rgb, outline=(90, 80, 66)) + d.text((x - 4, oy4 + 38), GLOW_FAMILY[key] + "微光", font=F_LBL2, fill=(225, 215, 195)) + x += 150 + d.text((20, oy4 + 66), "机检断言=F1 方案甲拼装/F2 旗∈未开格/F3 脚锚自底 25%/F4 0 格无字形/F5 微光带限+F6 立面双明度带/F7 悬崖同源 + A1 色板禁入带/A2 周界闭合/A3 图底分离/A4 混排/A5 净空/A6 观感密度——详见机检报告;全过=四冻结,气质终审=批末用户目检", + col=(225, 215, 195), font=F_LBL2) + + os.makedirs(os.path.dirname(OUT_PNG), exist_ok=True) + canvas.convert("RGB").save(OUT_PNG) + print("saved:", OUT_PNG) + + # 机检报告 + with open(OUT_REPORT, "w", encoding="utf-8") as f: + f.write("# 样张 v3 方向稿机检报告(2026-09-29,art-bible v3.0——方向稿阶段,机检为参考;冻结闸=目检后机检批)\n\n") + f.write("生成:`python tools/render_sample_sheet_v3.py`;v3.0 口径:格底分档(世界底层档)/亮墨直画/色牌后备/物件级装饰/B 区舞台;断言阈值随冻结批校准。\n\n") + f.write("## v1 否决原因 → 断言映射\n\n") + f.write("| 否决原因(2026-09-28 用户) | 断言承载 |\n|---|---|\n") + f.write("| ①显示太丑(总纲) | A6 观感密度(整板明度 std ≥50.9=v1 实测 44.31×1.15)+既有装饰变体 ≥2 种 |\n") + f.write("| ②封印色冲突 | 封印黑 #000000(9b6fcf6 已落,A1a 对表自动覆盖) |\n") + f.write("| ③立体感不够 | A3 阈值 40→55 + F6 顶面/立面双明度带 Δ≥18 + F7 整板悬崖 DEPTH_PX 同源 |\n") + f.write("| ④微光格只留微光 | F5c 微光段零 draw_inlay(d1dea82 已落) |\n\n") + f.write("## 断言明细\n\n") + f.write("| 断言 | 判据 | 结果 | 明细 |\n|---|---|---|---|\n") + for cid, name, okk, detail in CHECKS: + f.write("| %s | %s | %s | %s |\n" % (cid, name, "PASS" if okk else "**FAIL**", detail.replace("|", "/"))) + f.write("\n结论:**%s**(%d/%d PASS)。v3 方向稿机检=可行性参考(A3 亮墨对比为硬指标);冻结 = 用户目检方向稿后机检批(v3.0 闸形:目检先行→机检冻结)。\n" % + ("全绿" if ok else "有红灯", sum(1 for c in CHECKS if c[2]), len(CHECKS))) + print("saved:", OUT_REPORT) + print("=== 机检结论: %s (%d/%d) ===" % ("全绿" if ok else "FAIL", sum(1 for c in CHECKS if c[2]), len(CHECKS))) + return 0 if ok else 1 + + +if __name__ == "__main__": + sys.exit(main()) From 85f1caed5073aaca93b518594ad571e299d15662 Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Tue, 29 Sep 2026 19:03:14 +0800 Subject: [PATCH 4/8] =?UTF-8?q?feat(sample-v31):=20E=20=E6=A0=BC=E9=AB=98?= =?UTF-8?q?=E5=A2=99=E7=AB=8B=E9=9D=A2(=E7=94=A8=E6=88=B7=E6=96=B9?= =?UTF-8?q?=E6=A1=88:=E5=9C=B0=E9=9D=A2=E6=A0=BC=E5=8D=97=E9=82=BB?= =?UTF-8?q?=E5=A2=99=E2=86=92=E5=8D=97=E9=83=A8=2055%=20=E6=89=BF=E6=8E=A5?= =?UTF-8?q?=E5=A2=99=E9=9D=A2=E5=B1=95=E7=A4=BA,=E5=9F=BA=E8=89=B2?= =?UTF-8?q?=E9=87=87=E6=A0=B7=E5=A2=99=E9=A1=B6=E7=93=A6=E7=89=87=E5=90=8C?= =?UTF-8?q?=E6=BA=90;=E8=BF=9E=E7=BB=AD=E5=A2=99=E4=BD=93=E5=86=85?= =?UTF-8?q?=E4=BE=A7=E4=B8=8D=E5=87=BA=E7=AB=8B=E9=9D=A2);=E6=9C=BA?= =?UTF-8?q?=E6=A3=80=2017/17=20=E5=85=A8=E7=BB=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sample-v31-draft-机检报告-2026-09-29.md | 36 ++++++++++++++++++ tools/render_sample_sheet_v3.py | 38 +++++++++++++++++-- 2 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 design/research/sample-v31-draft-机检报告-2026-09-29.md diff --git a/design/research/sample-v31-draft-机检报告-2026-09-29.md b/design/research/sample-v31-draft-机检报告-2026-09-29.md new file mode 100644 index 00000000..f4ffe734 --- /dev/null +++ b/design/research/sample-v31-draft-机检报告-2026-09-29.md @@ -0,0 +1,36 @@ +# 样张 v3 方向稿机检报告(2026-09-29,art-bible v3.0——方向稿阶段,机检为参考;冻结闸=目检后机检批) + +生成:`python tools/render_sample_sheet_v3.py`;v3.0 口径:格底分档(世界底层档)/亮墨直画/色牌后备/物件级装饰/B 区舞台;断言阈值随冻结批校准。 + +## v1 否决原因 → 断言映射 + +| 否决原因(2026-09-28 用户) | 断言承载 | +|---|---| +| ①显示太丑(总纲) | A6 观感密度(整板明度 std ≥50.9=v1 实测 44.31×1.15)+既有装饰变体 ≥2 种 | +| ②封印色冲突 | 封印黑 #000000(9b6fcf6 已落,A1a 对表自动覆盖) | +| ③立体感不够 | A3 阈值 40→55 + F6 顶面/立面双明度带 Δ≥18 + F7 整板悬崖 DEPTH_PX 同源 | +| ④微光格只留微光 | F5c 微光段零 draw_inlay(d1dea82 已落) | + +## 断言明细 + +| 断言 | 判据 | 结果 | 明细 | +|---|---|---|---| +| F1 | 方案甲 8 邻拼装(词表查表,禁整块) | PASS | 错位 0 处;用件 15 种 ['center', 'center_crack', 'center_speckle', 'end_n', 'end_s', 'end_w', 'hrun', 'in_nw', 'in_sw', 'n', 'nw', 's', 'sw', 'vrun', 'w'] | +| F2 | 旗仅出现于未开格 | PASS | 旗位 (1, 2) 格态=W | +| F3 | 小人脚锚=自底边 25% 线(两态) | PASS | 脚 y=[213.75, 258.75] 期望=[213.75, 258.75] | +| F4 | 数字 0 格无字形(0=纯安全格裸地面) | PASS | 0 态格 38 个(示例 (4,4));数字表含 0 键=False | +| F5a | 接触带微光⊆英雄格周界(空间侧,不进墙格) | PASS | 微光 bbox=(86, 176, 119, 230) 英雄格=(90, 180, 135, 225) | +| F5b | 类型微光禁整格染色(中心 50% 区零染色像素) | PASS | 五格中心区全净 | +| F5c | 微光格零附加图形(微光段无角嵌调用——角嵌退役,微光只留微光) | PASS | 微光段无角嵌调用 | +| A1a | 色板对表圣经 §4.1 冻结值 | PASS | {'INK': '#33261B', '青墨': '#132E36', '赭墨': '#3C250C', '锈墨': '#4A1E14', 'PLATE': '#F5EAD3', '封印黑': '#000000', '危险红': '#A8321F', '奖励金': '#F0A828'} | +| A1b | 禁入带 HSV300°-345° 零命中 | PASS | 命中 0 像素(抽样) | +| A2 | 拼缝周界闭合(墙侧 2px 墨线 <70) | PASS | 全部墙地边界墨线在位 | +| A3a | v3 亮墨×格底 WCAG≥4.5:1(直画可行性硬指标) + 色牌后备组 ≥4.5:1 | PASS | 亮墨[('冷亮青白', 6.3), ('暖白', 6.0), ('金亮', 6.0)] 格底L=0.087;后备[('青墨×牌', 12.0), ('赭墨×牌', 12.0), ('锈墨×牌', 11.8)] | +| A3b | 图底分离读数(候选 Δ≥30——v2 阈值 55 与格底分档带数学冲突,校准归冻结批) | PASS | 墙顶 113 vs 地面 79,Δ=33(v2 阈值 55 系地板 L0.036 时代校定) | +| F6 | 墙格顶面/立面双明度带(南向临地墙格 Δ≥18,体积感机器代理) | PASS | 临地墙格 14 个;最小 Δ 76.3;均 Δ 105.0(v1 实测均 71.6) | +| F7 | 整板悬崖 DEPTH_PX 与 game 渲染常量同源(board_view.gd 解析) | PASS | DEPTH_PX=8.0(已解析);悬崖带均亮 69(<100);扩展 +8px | +| A6 | 观感密度:明度梯度均值 ≥4.70(v1 实测 4.09 上调 15%——高频细节能量) | PASS | 梯度均值 5.94(低频双峰由 A3 承载) | +| A5 | 画布四缘 2px 净空(零溢出) | PASS | 缘带内容像素 0 | +| A4 | 混排相融(游戏在库资产可载+UiKit 语义色对表;尺寸基线=换代后实态,校准归冻结批) | PASS | 小人源 (32, 32)(裁透明留白后 (19, 20))/立绘 (46, 48)/状态图标原件;INK/封印黑/奖励金 == ui_kit.gd | + +结论:**全绿**(17/17 PASS)。v3 方向稿机检=可行性参考(A3 亮墨对比为硬指标);冻结 = 用户目检方向稿后机检批(v3.0 闸形:目检先行→机检冻结)。 diff --git a/tools/render_sample_sheet_v3.py b/tools/render_sample_sheet_v3.py index 035d8065..b2cd1172 100644 --- a/tools/render_sample_sheet_v3.py +++ b/tools/render_sample_sheet_v3.py @@ -59,8 +59,8 @@ def asset_root(*parts): BOARD_DIR = ("game", "assets", "art", "board") CHAR_DIR = ("game", "assets", "art", "character") ICON_DIR = ("game", "assets", "ui", "icons") -OUT_PNG = os.path.join(ROOT, "artwork", "mockups", "sample-batch-v3-draft-2026-09-29.png") -OUT_REPORT = os.path.join(ROOT, "design", "research", "sample-v3-draft-机检报告-2026-09-29.md") +OUT_PNG = os.path.join(ROOT, "artwork", "mockups", "sample-batch-v31-draft-2026-09-29.png") +OUT_REPORT = os.path.join(ROOT, "design", "research", "sample-v31-draft-机检报告-2026-09-29.md") T_FONT = asset_root("artwork", "ui-reuse-2026-09-23", "4-字体", "fusion-pixel-12px(OFL)", "fusion-pixel-12px-proportional-latin.ttf") ZH_FONT = r"C:\Windows\Fonts\msyh.ttc" @@ -560,6 +560,34 @@ def draw_hero_on_board(board, ox, oy, cell, hx, hy, records, digit=None): records.append(("hero", hx, hy, fx, fy, digit)) +def draw_facade(board, x0, y0, cell): + """v3.1 高墙立面(用户方案:地面格南邻墙 → 南部承接墙面展示,E 格)。 + 南 45% 画墙身:横层理暗砖+口沿高光顶线(与墙顶分界);程序化示意,终稿=E 瓦片素材(词表扩展)。""" + d = ImageDraw.Draw(board) + fy0 = y0 + int(cell * 0.45) # 立面占南 55%(高墙感档,目检候选) + # 立面基色=墙顶瓦片实测色(E 与南侧墙顶须读作同一堵墙——采样 center 瓦片顶面区) + top = WALLS["center"].convert("RGB").crop((4, 4, 28, 14)) + px = list(top.getdata()) + wall_top_rgb = tuple(sum(c[i] for c in px) // len(px) for i in range(3)) + face = _gd_darkened(wall_top_rgb, 0.16) # 北立面=受光面,略暗于顶面 16% 分层 + d.rectangle([x0, fy0, x0 + cell, y0 + cell], fill=face) + for i in range(3): # 横层理(横条纹,禁竖条纹栅栏感——§3.2 高墙条) + ly = fy0 + int((i + 1) * (cell - int(cell * 0.45)) / 4.0) + d.line([(x0 + 2, ly), (x0 + cell - 2, ly)], fill=_gd_darkened(face, 0.30), width=1) + for i in range(2): # 层理错缝竖短线(砖缝) + for j in range(3): + vx = x0 + 6 + j * 14 + (i * 7) + vy0 = fy0 + 5 + i * 11 + d.line([(vx, vy0), (vx, vy0 + 7)], fill=_gd_darkened(face, 0.34), width=1) + d.rectangle([x0, fy0, x0 + cell, fy0 + 1], fill=_gd_darkened(wall_top_rgb, 0.35)) # 口沿(地面与立面交界=檐口阴线) + d.rectangle([x0, y0 + cell - 1, x0 + cell, y0 + cell], fill=_gd_darkened(face, 0.30)) # 底缘收头 1px(接墙顶北缘亮棱) + + +def is_facade_cell(gmap, x, y): + """E 格判定:本格是地面,且南邻(y+1)是墙。连续墙体内部不出立面(立面只露在地格侧)。""" + return (0 <= y + 1 < gmap.h) and gmap.grid[y][x] != "W" and gmap.grid[y + 1][x] == "W" + + def render_board(gmap, cell, overlays=None, scale_note=""): """按方案甲查表拼装渲染样张板。返回 (img, placement, glow_layer)。""" wpx, hpx = gmap.w * cell, gmap.h * cell @@ -585,6 +613,10 @@ def render_board(gmap, cell, overlays=None, scale_note=""): board.paste(FLOORS[vi].resize((cell, cell), Image.NEAREST), (x * cell, y * cell)) placement[(x, y)] = ("floor_%d" % (vi + 1), False) if overlays: + for y in range(gmap.h): # v3.1 E 格立面(高墙双格呈现——结构件,先于投影) + for x in range(gmap.w): + if is_facade_cell(gmap, x, y): + draw_facade(board, x * cell, y * cell, cell) board = apply_d_projection(board, gmap, cell) # D 投影档(立体承载) glow = Image.new("RGBA", (wpx, hpx), (0, 0, 0, 0)) return board, placement, glow @@ -1042,7 +1074,7 @@ def main(): ok = run_checks(board, placement, records, band, gmap, canvas) d = ImageDraw.Draw(canvas) - d.text((20, 14), "战斗一屏样张方向稿 v3-draft(2026-09-29,art-bible v3.0)——格底明度分档+亮墨直画+色牌后备+B区地窟看台;机检 %s(方向稿参考,冻结归目检后机检批);巢穴纹=程序占位" % + d.text((20, 14), "战斗一屏样张方向稿 v3-draft(2026-09-29,art-bible v3.0)——格底分档+亮墨直画+色牌后备+B区看台+E格高墙立面(v3.1);机检 %s(方向稿参考,冻结归目检后机检批);巢穴纹=程序占位" % ("全绿" if ok else "有 FAIL"), col=(232, 222, 200), font=F_TITLE) # 三区 mockup From e67c801e7507b41a32a77e13923893ecb2caa6a4 Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Tue, 29 Sep 2026 19:16:52 +0800 Subject: [PATCH 5/8] =?UTF-8?q?feat(sample-v32):=20=E5=8D=97=E5=90=91?= =?UTF-8?q?=E5=A2=99=E6=A0=BC=E7=AB=8B=E9=9D=A2=E6=9A=97=E6=9D=A1=E6=8F=90?= =?UTF-8?q?=E4=BA=AE(=E5=A2=99=E9=A1=B6=E9=9D=A2=E5=85=A8=E6=9D=BF?= =?UTF-8?q?=E5=90=8C=E8=89=B2=E8=A7=82=E6=84=9F=E4=BF=AE=E5=A4=8D)+E?= =?UTF-8?q?=E6=A0=BC=E7=AB=8B=E9=9D=A2=E9=AB=98=E5=BA=A6=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E5=8C=96(FACADE=5FFRAC=200.55/0.80/1.00=20=E4=B8=89=E6=A1=A3?= =?UTF-8?q?=E5=AF=B9=E6=AF=94=E5=9B=BE);=E6=9C=BA=E6=A3=80=2017/17?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/render_sample_sheet_v3.py | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/tools/render_sample_sheet_v3.py b/tools/render_sample_sheet_v3.py index b2cd1172..41545ce9 100644 --- a/tools/render_sample_sheet_v3.py +++ b/tools/render_sample_sheet_v3.py @@ -560,11 +560,13 @@ def draw_hero_on_board(board, ox, oy, cell, hx, hy, records, digit=None): records.append(("hero", hx, hy, fx, fy, digit)) +FACADE_FRAC = 0.55 # E 格立面占比(v3.2 档位候选:0.55/0.80/1.00 三档对比,用户挑档) + def draw_facade(board, x0, y0, cell): """v3.1 高墙立面(用户方案:地面格南邻墙 → 南部承接墙面展示,E 格)。 - 南 45% 画墙身:横层理暗砖+口沿高光顶线(与墙顶分界);程序化示意,终稿=E 瓦片素材(词表扩展)。""" + 南部画墙身:横层理暗砖+檐口阴线;程序化示意,终稿=E 瓦片素材(词表扩展)。""" d = ImageDraw.Draw(board) - fy0 = y0 + int(cell * 0.45) # 立面占南 55%(高墙感档,目检候选) + fy0 = y0 + int(cell * (1.0 - FACADE_FRAC)) # 立面基色=墙顶瓦片实测色(E 与南侧墙顶须读作同一堵墙——采样 center 瓦片顶面区) top = WALLS["center"].convert("RGB").crop((4, 4, 28, 14)) px = list(top.getdata()) @@ -572,7 +574,7 @@ def draw_facade(board, x0, y0, cell): face = _gd_darkened(wall_top_rgb, 0.16) # 北立面=受光面,略暗于顶面 16% 分层 d.rectangle([x0, fy0, x0 + cell, y0 + cell], fill=face) for i in range(3): # 横层理(横条纹,禁竖条纹栅栏感——§3.2 高墙条) - ly = fy0 + int((i + 1) * (cell - int(cell * 0.45)) / 4.0) + ly = fy0 + int((i + 1) * (cell * FACADE_FRAC) / 4.0) d.line([(x0 + 2, ly), (x0 + cell - 2, ly)], fill=_gd_darkened(face, 0.30), width=1) for i in range(2): # 层理错缝竖短线(砖缝) for j in range(3): @@ -588,6 +590,23 @@ def is_facade_cell(gmap, x, y): return (0 <= y + 1 < gmap.h) and gmap.grid[y][x] != "W" and gmap.grid[y + 1][x] == "W" +def lift_south_lip(tile): + """v3.2:南向墙格(南邻地)瓦片底部 ~40% 立面暗条提亮——(56,45,39) 极暗拉低整格观感, + 用户指「墙顶面应同色」:顶面本同色(147≈145),观感差系暗条过暗。背光面仍暗于顶面,但不死黑。 + 程序化示意,终稿归瓦片重产(§8.5)。""" + im = tile.convert("RGB") + w, h = im.size + y0 = int(h * 0.60) + band = im.crop((0, y0, w, h)) + lut = [min(255, int(i * 1.75 + 18)) for i in range(256)] + band = band.point(lut * 3) + out = im.copy() + out.paste(band, (0, y0)) + if tile.mode == "RGBA": + out.putalpha(tile.split()[3]) + return out.convert("RGBA") + + def render_board(gmap, cell, overlays=None, scale_note=""): """按方案甲查表拼装渲染样张板。返回 (img, placement, glow_layer)。""" wpx, hpx = gmap.w * cell, gmap.h * cell @@ -604,7 +623,10 @@ def render_board(gmap, cell, overlays=None, scale_note=""): t = WALLS[kind] if flip: t = t.transpose(Image.FLIP_LEFT_RIGHT) - board.paste(t.resize((cell, cell), Image.NEAREST), (x * cell, y * cell)) + t = t.resize((cell, cell), Image.NEAREST) + if overlays and not is_wall(gmap, x, y + 1): # v3.2 南向墙格立面提亮 + t = lift_south_lip(t) + board.paste(t, (x * cell, y * cell)) placement[(x, y)] = (kind, flip) else: vi = floor_variant(x, y) From 08816a3ead0ff6234ab4bbaf84941b8dfdb9bf99 Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Tue, 29 Sep 2026 19:46:59 +0800 Subject: [PATCH 6/8] =?UTF-8?q?feat(sample-v33):=20=E5=A2=99=E9=9D=A2?= =?UTF-8?q?=E6=9D=90=E8=B4=A8=E7=BB=9F=E4=B8=80=E2=80=94=E2=80=94=E5=A2=99?= =?UTF-8?q?=E7=9A=84=E4=B8=80=E5=88=87=E9=9D=A2(=E5=A2=99=E9=A1=B6/E?= =?UTF-8?q?=E6=A0=BC=E5=A2=99=E9=9D=A2/=E5=8D=97=E5=90=91=E5=8E=9A?= =?UTF-8?q?=E5=BA=A6=E9=9D=A2)=3D=E5=90=8C=E4=B8=80=E5=B2=A9=E5=9D=97?= =?UTF-8?q?=E6=9D=90=E8=B4=A8,=E9=9D=A2=E9=97=B4=E5=8F=AA=E9=9D=A0?= =?UTF-8?q?=E6=98=8E=E5=BA=A6(100/85/80)+=E6=A3=B1=E7=BA=BF=E5=88=86?= =?UTF-8?q?=E7=95=8C,=E7=A6=81=E5=B9=B3=E6=B6=82=E6=96=B0=E9=A2=9C?= =?UTF-8?q?=E8=89=B2;=E6=9C=BA=E6=A3=80=2017/17?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/render_sample_sheet_v3.py | 42 +++++++++++++-------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/tools/render_sample_sheet_v3.py b/tools/render_sample_sheet_v3.py index 41545ce9..04355bfc 100644 --- a/tools/render_sample_sheet_v3.py +++ b/tools/render_sample_sheet_v3.py @@ -563,26 +563,18 @@ def draw_hero_on_board(board, ox, oy, cell, hx, hy, records, digit=None): FACADE_FRAC = 0.55 # E 格立面占比(v3.2 档位候选:0.55/0.80/1.00 三档对比,用户挑档) def draw_facade(board, x0, y0, cell): - """v3.1 高墙立面(用户方案:地面格南邻墙 → 南部承接墙面展示,E 格)。 - 南部画墙身:横层理暗砖+檐口阴线;程序化示意,终稿=E 瓦片素材(词表扩展)。""" + """v3.3 E 格墙面(用户方案:地面格南邻墙 → 南部承接墙面展示)。 + 墙面=墙顶同款岩块材质(center 瓦片纹理直接贴,明度 ×0.85 表达垂直面),禁平涂新颜色: + 北端=墙脚阴线(与地面交界),南端=檐口亮棱(与墙顶交界,受光棱线)。""" d = ImageDraw.Draw(board) fy0 = y0 + int(cell * (1.0 - FACADE_FRAC)) - # 立面基色=墙顶瓦片实测色(E 与南侧墙顶须读作同一堵墙——采样 center 瓦片顶面区) - top = WALLS["center"].convert("RGB").crop((4, 4, 28, 14)) - px = list(top.getdata()) - wall_top_rgb = tuple(sum(c[i] for c in px) // len(px) for i in range(3)) - face = _gd_darkened(wall_top_rgb, 0.16) # 北立面=受光面,略暗于顶面 16% 分层 - d.rectangle([x0, fy0, x0 + cell, y0 + cell], fill=face) - for i in range(3): # 横层理(横条纹,禁竖条纹栅栏感——§3.2 高墙条) - ly = fy0 + int((i + 1) * (cell * FACADE_FRAC) / 4.0) - d.line([(x0 + 2, ly), (x0 + cell - 2, ly)], fill=_gd_darkened(face, 0.30), width=1) - for i in range(2): # 层理错缝竖短线(砖缝) - for j in range(3): - vx = x0 + 6 + j * 14 + (i * 7) - vy0 = fy0 + 5 + i * 11 - d.line([(vx, vy0), (vx, vy0 + 7)], fill=_gd_darkened(face, 0.34), width=1) - d.rectangle([x0, fy0, x0 + cell, fy0 + 1], fill=_gd_darkened(wall_top_rgb, 0.35)) # 口沿(地面与立面交界=檐口阴线) - d.rectangle([x0, y0 + cell - 1, x0 + cell, y0 + cell], fill=_gd_darkened(face, 0.30)) # 底缘收头 1px(接墙顶北缘亮棱) + wall_top = WALLS["center"].resize((cell, cell), Image.NEAREST) + face = wall_top.crop((0, 0, cell, cell - fy0 + y0)) + face = face.point([min(255, int(i * 0.85)) for i in range(256)] * 3) + board.paste(face, (x0, fy0)) + d.rectangle([x0, fy0, x0 + cell, fy0 + 1], fill=(52, 42, 32)) # 墙脚阴线(地面/墙面交界) + d.rectangle([x0, y0 + cell - 3, x0 + cell, y0 + cell - 1], + fill=(232, 205, 158)) # 檐口亮棱(墙面/墙顶交界,受光) def is_facade_cell(gmap, x, y): @@ -591,17 +583,17 @@ def is_facade_cell(gmap, x, y): def lift_south_lip(tile): - """v3.2:南向墙格(南邻地)瓦片底部 ~40% 立面暗条提亮——(56,45,39) 极暗拉低整格观感, - 用户指「墙顶面应同色」:顶面本同色(147≈145),观感差系暗条过暗。背光面仍暗于顶面,但不死黑。 - 程序化示意,终稿归瓦片重产(§8.5)。""" + """v3.3:南向墙格(南邻地)底部暗条改为顶面同款材质轻微暗档(×0.80)—— + 同一堵墙的顶面材质全板一致,南向厚度面只差明度,不再两截皮。终稿归瓦片重产(§8.5)。""" im = tile.convert("RGB") w, h = im.size y0 = int(h * 0.60) - band = im.crop((0, y0, w, h)) - lut = [min(255, int(i * 1.75 + 18)) for i in range(256)] - band = band.point(lut * 3) + top_ref = im.crop((0, 0, w, y0)) # 顶面区材质 + band_h = h - y0 + ref = top_ref.resize((w, band_h)) # 顶面纹理拉伸到暗条区(同材质) + ref = ref.point([min(255, int(i * 0.80)) for i in range(256)] * 3) out = im.copy() - out.paste(band, (0, y0)) + out.paste(ref, (0, y0)) if tile.mode == "RGBA": out.putalpha(tile.split()[3]) return out.convert("RGBA") From d92770cdf05b063d7102094d08440d0704c930f4 Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Tue, 29 Sep 2026 19:53:08 +0800 Subject: [PATCH 7/8] =?UTF-8?q?fix(sample-v34):=20E=E6=A0=BC=E5=A2=99?= =?UTF-8?q?=E9=9D=A2=E5=8E=BB=E5=BA=95=E7=BC=98=E7=99=BD=E7=BA=BF=E2=80=94?= =?UTF-8?q?=E2=80=94=E5=A2=99=E9=9D=A2=E7=9B=B4=E6=8E=A5=E8=BF=9E=E6=8E=A5?= =?UTF-8?q?=E5=A2=99=E9=A1=B6(=E7=94=A8=E6=88=B7=E8=A3=81:=E7=99=BD?= =?UTF-8?q?=E8=BE=B9=E5=AF=BC=E8=87=B4=E4=B8=A4=E6=88=AA);=E4=B8=89?= =?UTF-8?q?=E6=A1=A3=E5=AF=B9=E6=AF=94=E5=9B=BE=E6=9D=90=E8=B4=A8=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E7=89=88=E9=87=8D=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- design/research/sample-v31-draft-机检报告-2026-09-29.md | 4 ++-- tools/render_sample_sheet_v3.py | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/design/research/sample-v31-draft-机检报告-2026-09-29.md b/design/research/sample-v31-draft-机检报告-2026-09-29.md index f4ffe734..975bca89 100644 --- a/design/research/sample-v31-draft-机检报告-2026-09-29.md +++ b/design/research/sample-v31-draft-机检报告-2026-09-29.md @@ -27,9 +27,9 @@ | A2 | 拼缝周界闭合(墙侧 2px 墨线 <70) | PASS | 全部墙地边界墨线在位 | | A3a | v3 亮墨×格底 WCAG≥4.5:1(直画可行性硬指标) + 色牌后备组 ≥4.5:1 | PASS | 亮墨[('冷亮青白', 6.3), ('暖白', 6.0), ('金亮', 6.0)] 格底L=0.087;后备[('青墨×牌', 12.0), ('赭墨×牌', 12.0), ('锈墨×牌', 11.8)] | | A3b | 图底分离读数(候选 Δ≥30——v2 阈值 55 与格底分档带数学冲突,校准归冻结批) | PASS | 墙顶 113 vs 地面 79,Δ=33(v2 阈值 55 系地板 L0.036 时代校定) | -| F6 | 墙格顶面/立面双明度带(南向临地墙格 Δ≥18,体积感机器代理) | PASS | 临地墙格 14 个;最小 Δ 76.3;均 Δ 105.0(v1 实测均 71.6) | +| F6 | 墙格顶面/立面双明度带(南向临地墙格 Δ≥18,体积感机器代理) | PASS | 临地墙格 14 个;最小 Δ 64.9;均 Δ 91.2(v1 实测均 71.6) | | F7 | 整板悬崖 DEPTH_PX 与 game 渲染常量同源(board_view.gd 解析) | PASS | DEPTH_PX=8.0(已解析);悬崖带均亮 69(<100);扩展 +8px | -| A6 | 观感密度:明度梯度均值 ≥4.70(v1 实测 4.09 上调 15%——高频细节能量) | PASS | 梯度均值 5.94(低频双峰由 A3 承载) | +| A6 | 观感密度:明度梯度均值 ≥4.70(v1 实测 4.09 上调 15%——高频细节能量) | PASS | 梯度均值 5.96(低频双峰由 A3 承载) | | A5 | 画布四缘 2px 净空(零溢出) | PASS | 缘带内容像素 0 | | A4 | 混排相融(游戏在库资产可载+UiKit 语义色对表;尺寸基线=换代后实态,校准归冻结批) | PASS | 小人源 (32, 32)(裁透明留白后 (19, 20))/立绘 (46, 48)/状态图标原件;INK/封印黑/奖励金 == ui_kit.gd | diff --git a/tools/render_sample_sheet_v3.py b/tools/render_sample_sheet_v3.py index 04355bfc..21ac7fc6 100644 --- a/tools/render_sample_sheet_v3.py +++ b/tools/render_sample_sheet_v3.py @@ -573,8 +573,7 @@ def draw_facade(board, x0, y0, cell): face = face.point([min(255, int(i * 0.85)) for i in range(256)] * 3) board.paste(face, (x0, fy0)) d.rectangle([x0, fy0, x0 + cell, fy0 + 1], fill=(52, 42, 32)) # 墙脚阴线(地面/墙面交界) - d.rectangle([x0, y0 + cell - 3, x0 + cell, y0 + cell - 1], - fill=(232, 205, 158)) # 檐口亮棱(墙面/墙顶交界,受光) + # v3.4:墙面底缘不画任何线——墙面直接接到南侧墙顶(用户裁:白边导致两截) def is_facade_cell(gmap, x, y): From be8dd13fa34a3a7a6ecbeb4b018abc2b303d6543 Mon Sep 17 00:00:00 2001 From: DKChan <524912269@qq.com> Date: Tue, 29 Sep 2026 20:26:27 +0800 Subject: [PATCH 8/8] =?UTF-8?q?feat(sample-v35):=20=E5=A2=99=E9=A1=B6?= =?UTF-8?q?=E5=85=A8=E6=9D=BF=E5=90=8C=E8=89=B2=E7=BB=88=E8=A3=81=E8=90=BD?= =?UTF-8?q?=E5=9C=B0=E2=80=94=E2=80=94=E5=8D=97=E5=90=91=E5=A2=99=E6=A0=BC?= =?UTF-8?q?=E6=9A=97=E6=9D=A1=E4=B8=8ED=E6=8A=95=E5=BD=B1=E7=AB=8B?= =?UTF-8?q?=E9=9D=A2=E6=9A=97=E5=B8=A6=E5=BA=9F=E6=AD=A2,=E9=A1=B6?= =?UTF-8?q?=E9=9D=A2=E6=9D=90=E8=B4=A8=E5=8E=9F=E4=BA=AE=E5=BA=A6=E7=9B=B4?= =?UTF-8?q?=E5=A1=AB=E9=9B=B6=E9=98=B4=E5=BD=B1;F6=E6=94=B9=E5=A2=99?= =?UTF-8?q?=E9=A1=B6=E5=90=8C=E8=89=B2=E6=96=AD=E8=A8=80(=E5=AE=9E?= =?UTF-8?q?=E6=B5=8B=E6=9C=80=E5=A4=A7=E8=89=B2=E5=B7=AE1.7);55%=E9=94=81?= =?UTF-8?q?=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/render_sample_sheet_v3.py | 56 ++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/tools/render_sample_sheet_v3.py b/tools/render_sample_sheet_v3.py index 21ac7fc6..fb8a44c5 100644 --- a/tools/render_sample_sheet_v3.py +++ b/tools/render_sample_sheet_v3.py @@ -271,16 +271,10 @@ def apply_d_projection(board, gmap, cell): 北邻墙地面格 = 三段渐隐投影(顶带 0.22 格边,α0.28 起)。立体断言 F6/A6 的渲染承载。""" overlay = Image.new("RGBA", board.size, (0, 0, 0, 0)) d = ImageDraw.Draw(overlay) - HILITE = (196, 172, 132) - seg1, seg2 = int(cell * 0.16), int(cell * 0.25) + # v3.5:南临墙格的立面暗带+口沿高光已废止(用户终裁:墙顶零阴影全板同色同素材) for y in range(gmap.h): for x in range(gmap.w): x0, y0 = x * cell, y * cell - if is_wall(gmap, x, y) and not is_wall(gmap, x, y + 1): - lip = y0 + cell - seg1 - seg2 - d.rectangle([x0, lip, x0 + cell, lip + 2], fill=HILITE + (255,)) - d.rectangle([x0, lip + 2, x0 + cell, lip + 2 + seg1], fill=(0, 0, 0, 153)) - d.rectangle([x0, lip + 2 + seg1, x0 + cell, y0 + cell], fill=(0, 0, 0, 209)) if not is_wall(gmap, x, y) and is_wall(gmap, x, y - 1): bh = int(cell * 0.22) for i, a in enumerate([71, 36, 14]): @@ -582,15 +576,14 @@ def is_facade_cell(gmap, x, y): def lift_south_lip(tile): - """v3.3:南向墙格(南邻地)底部暗条改为顶面同款材质轻微暗档(×0.80)—— - 同一堵墙的顶面材质全板一致,南向厚度面只差明度,不再两截皮。终稿归瓦片重产(§8.5)。""" + """v3.3:南向墙格(南邻地)底部暗条以顶面材质**原亮度**直填—— + 全板墙顶同色同素材,零阴影零暗档(用户终裁:「这里没有什么阴影影响,它们是同样颜色的」)。终稿归瓦片重产(§8.5)。""" im = tile.convert("RGB") w, h = im.size y0 = int(h * 0.60) top_ref = im.crop((0, 0, w, y0)) # 顶面区材质 band_h = h - y0 - ref = top_ref.resize((w, band_h)) # 顶面纹理拉伸到暗条区(同材质) - ref = ref.point([min(255, int(i * 0.80)) for i in range(256)] * 3) + ref = top_ref.resize((w, band_h)) # v3.5:顶面纹理原亮度直填(无暗档无阴影——全板墙顶同色同素材) out = im.copy() out.paste(ref, (0, y0)) if tile.mode == "RGBA": @@ -967,25 +960,36 @@ def run_checks(board, placement, records, band, gmap, canvas_img=None): check("A3b", "图底分离读数(候选 Δ≥30——v2 阈值 55 与格底分档带数学冲突,校准归冻结批)", (wall_top - floor_px) >= 30, "墙顶 %.0f vs 地面 %.0f,Δ=%.0f(v2 阈值 55 系地板 L0.036 时代校定)" % (wall_top, floor_px, wall_top - floor_px)) - # F6 墙格顶面/立面双明度带(立体断言——南向临地墙格:顶 2/3 vs 立面下 1/3,体积感机器代理) + # F6 v3.5 改口径:墙顶全板同色(南向临地墙格顶面 vs 全板墙顶均值,逐通道差 ≤6—— + # 原"顶面/立面双明度带 Δ≥18"随南临暗带废止;立体感由 E 格墙面承载) south_cells = [(x, y) for y in range(gmap.h) for x in range(gmap.w) if is_wall(gmap, x, y) and not is_wall(gmap, x, y + 1)] rgbp = board.convert("RGB").load() - deltas = [] - for (x, y) in south_cells: - ts, bs = [], [] - for yy in range(4, CELL_D - 4, 2): + def _cell_top_mean(x, y): + vals = [] + for yy in range(4, int(CELL_D * 0.4), 2): for xx in range(4, CELL_D - 4, 2): - c = rgbp[x * CELL_D + xx, y * CELL_D + yy] - lv = 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2] - (ts if yy < CELL_D * 2.0 / 3.0 else bs).append(lv) - if ts and bs: - deltas.append(sum(ts) / len(ts) - sum(bs) / len(bs)) - dmin = min(deltas) if deltas else 0.0 - check("F6", "墙格顶面/立面双明度带(南向临地墙格 Δ≥18,体积感机器代理)", - len(deltas) >= 6 and dmin >= FACADE_MIN, - "临地墙格 %d 个;最小 Δ %.1f;均 Δ %.1f(v1 实测均 71.6)" - % (len(deltas), dmin, sum(deltas) / len(deltas) if deltas else 0)) + vals.append(rgbp[x * CELL_D + xx, y * CELL_D + yy]) + n = len(vals) + return (sum(v[0] for v in vals) / n, sum(v[1] for v in vals) / n, sum(v[2] for v in vals) / n) + _excl_all = {FLAG_AT, HOVER_AT} | {(gx, gy) for (gx, gy, _k) in GLOW_CELLS} + all_tops = [_cell_top_mean(x, y) for y in range(gmap.h) for x in range(gmap.w) + if is_wall(gmap, x, y) and (y == 0 or gmap.grid[y-1][x] == "W") and (x, y) not in _excl_all] + ref = tuple(sum(v[i] for v in all_tops) / len(all_tops) for i in range(3)) + # 排除带附加层的格(旗/悬停/微光——信息层合法染色,不属墙顶色差) + _excl = {FLAG_AT, HOVER_AT} | {(gx, gy) for (gx, gy, _k) in GLOW_CELLS} + devs = [] + for (x, y) in south_cells: + if (x, y) in _excl: + continue + m = _cell_top_mean(x, y) + dev = max(abs(m[i] - ref[i]) for i in range(3)) + devs.append(dev) + dmax = max(devs) if devs else 0.0 + check("F6", "墙顶全板同色(南向墙格顶面 vs 全板均值逐通道差 ≤6;旗格排除)", + dmax <= 6.0, + "南向墙格 %d 个(排除 %d 个附加层格);最大色差 %.1f(参考均值 %s)" + % (len(devs), len(_excl & set(south_cells)), dmax, tuple(round(v) for v in ref))) # F7 整板悬崖 DEPTH_PX 同源(立体断言——解析 game 源码常量,样张悬崖带按其绘制) band_lv = region_luma(board, (CELL_D, board.size[1] - 3, board.size[0] - CELL_D, board.size[1] - 1)) cliff_d = int(round(DEPTH_PX or 0))