iter16ui T2:N1对比度七处落码(血数HP_BAR_BACK垫牌14.3:1/意图四墨垫PANEL_DATA牌·atk零换墨·buf换HERO_BLUE_DEEP#1E5A96·charge换GOLD_INK#74500B/槽两态STONE_DEEP#554D41+INK_LABEL/RAP显式INK_LABEL零改值)+art-bible §7.4合并豁免条款(P11 caption 12px+血数条带内读数)+新增ui_contrast_probe入probe_gate默认段(11对测点+裸Color8白名单25处/10文件过渡表+preload红线静态扫描)

This commit is contained in:
DKChan committed 2026-10-06 03:04:59 +08:00
1 parent a55a302d3e
commit b38ae07707
8 files changed
+149 -6

No files matched your search

+1
View File
@@ -418,6 +418,7 @@
- **字体**:全局一套像素字——拉丁候选 Kenney Fonts(CC0)、中文候选缝合像素字体 Fusion Pixel(OFL)(清单 §3.6);墨色走主墨系(§7.2);换字体 = 全局决策。
- **字号**:像素字体**整数倍缩放,禁非整数缩放**(像素模糊);下限(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-10-06 UI 设计对齐批 P11+Q5 甲,合并单条不开两口子)**:下款两类**豁免于本节下限**——①**条带内读数**:压在窄条带(血条/进度条等 ≤12px 高带)内居中的数字,受条带高度物理约束,维持 11px 下限,且必须按 §7.2 垫素色牌后计对比(实装=B 区站桩血数 11px 压 HP_BAR_BACK 牌 14.3:1);②**装饰性 overline/caption**:不承载须精确读取的信息、仅作分区标题或氛围小字者,可至 **12px**。两类豁免均须逐处登记清单(条带内读数清单=B 区站桩血数一处;装饰 caption 逐处清单随本批字号档位卡落本节),清单外的 11-13px 文字一律按正文/tooltip 下限提档。
- **字重纪律(2026-09-29 v3.0 修订)**:层级手段解禁为三件——**字号档差(相邻层级 ≥1.25×)+ 墨色深浅 +(字体支持时)字重两档**;数字禁描边/阴影伪加粗不变(字形为唯一数值载体,§4.1 同源纪律)。
### 7.5 营地界面
+1 -1
View File
@@ -71,7 +71,7 @@ func _init() -> void:
_rap_dots.add_theme_constant_override("separation", 2)
_rap_dots.size_flags_vertical = Control.SIZE_SHRINK_CENTER
row.add_child(_rap_dots)
_rap_label = UiKit.label("RAP 0", 14, true)
_rap_label = UiKit.label("RAP 0", 14, true, UiKit.INK_LABEL) # 显式传色(UI 设计对齐批 N1-7——T0 实测对 PANEL_DATA 10.4:1 已合规,显式化仅为确定性加固,值不变)
_rap_label.size_flags_vertical = Control.SIZE_SHRINK_CENTER
row.add_child(_rap_label)
_rap_feedback = UiKit.label("", 11, false, UiKit.STONE_FAINT)
@@ -209,9 +209,12 @@ func set_treasure_inventory(items: Array, selected_handle: int) -> void:
glyph.set_anchors_preset(Control.PRESET_FULL_RECT)
glyph.mouse_filter = Control.MOUSE_FILTER_IGNORE
if used:
glyph.add_theme_color_override("font_color", UiKit.STONE_FAINT)
# 「已用」占位墨=灰石深化(UI 设计对齐批 N1-5 2026-10-06——旧 STONE_FAINT 对 PANEL_DATA 槽牌 2.7:1;
# STONE_DEEP = 5.6:1;语义分档保持双墨,Q6 乙不新增通道)
glyph.add_theme_color_override("font_color", UiKit.STONE_DEEP)
elif not usable:
glyph.add_theme_color_override("font_color", UiKit.STONE)
# 「不可用」置灰墨=标签深墨(N1-6——旧 STONE 对槽牌 3.4:1;INK_LABEL = 10.4:1,虚位/失效更强置灰语义)
glyph.add_theme_color_override("font_color", UiKit.INK_LABEL)
slot.add_child(glyph)
var border_col: Color = UiKit.GOLD if selected else UiKit.PANEL_BORDER
slot.add_theme_stylebox_override("panel",
+9 -2
View File
@@ -172,12 +172,12 @@ func set_pending(ptype: String, pid: String) -> void:
var col: Color = UiKit.RED_MINE # 攻击预告红(危险红族——旗朱退役 2026-09-26,预告语义归封印色独占〔现行封印黑〕)
if ptype == "buff":
glyph = "✦" # 增益系
col = UiKit.HERO_BLUE
col = UiKit.HERO_BLUE_DEEP # 深档墨(N1-4——浅垫牌上 ≥4.5:1;原 HERO_BLUE 亮档对垫牌 2.5:1)
elif ptype == "debuff":
glyph = "☠" # 妨害系(新效应词汇批 2026-09-19)
col = UiKit.DEBUFF_PURPLE
if pid in CHARGE_SKILL_IDS:
col = UiKit.GOLD_DEEP # 重击类蓄力档(2026-09-18 用户拍板独立蓄力提示)
col = UiKit.GOLD_INK # 重击类蓄力档(深金墨 N1——浅垫牌上 ≥4.5:1;原 GOLD_DEEP 2.5:1)
_intent_glyph = glyph
_intent_col = col
_intent_visible = true
@@ -434,6 +434,9 @@ func _draw() -> void:
# 数字=目标值即时刷新,条 tween 只管填充宽度;死残位 0/max 照常可读)
var hp_txt := "%d/%d" % [_hp_cur, int(_hp_max)]
var hts: Vector2 = f.get_string_size(hp_txt, HORIZONTAL_ALIGNMENT_LEFT, -1, 11)
# 对比度垫牌(UI 设计对齐批 N1-1/N1-2 2026-10-06——白 α.95 直压蓝条 2.67:1 违 §7.2;
# 中央垫 HP_BAR_BACK 深素牌 = 14.3:1;牌宽=字宽+8〔白名单取 8〕,高=条带全高;§4.1 数字色牌原则)
draw_rect(Rect2(bar_x + (bar_w - hts.x) * 0.5 - 4.0, 2.0, hts.x + 8.0, 10.0), UiKit.HP_BAR_BACK, true)
var hbase := Vector2(bar_x + (bar_w - hts.x) * 0.5, 2.0 + 5.0 + 4.0)
f.draw_string(get_canvas_item(), hbase + Vector2(1, 1), hp_txt, HORIZONTAL_ALIGNMENT_LEFT, -1, 11, Color(0.10, 0.08, 0.06, 0.85))
f.draw_string(get_canvas_item(), hbase, hp_txt, HORIZONTAL_ALIGNMENT_LEFT, -1, 11, Color(1, 1, 1, 0.95))
@@ -457,6 +460,10 @@ func _draw() -> void:
var icenter := Vector2(box.x * 0.5, 86.0)
draw_set_transform(icenter, 0.0, Vector2(_intent_scale, _intent_scale))
var its := f.get_string_size(_intent_glyph, HORIZONTAL_ALIGNMENT_LEFT, -1, 15)
# 对比度垫牌(UI 设计对齐批 N1-3/N1-4 2026-10-06——四色墨直压立绘纹理/暗舞台底 1.5-3.3:1 违 §7.2
# 「文字禁直压纹理底」;垫 PANEL_DATA 素牌后 atk 5.3/buf 4.8/debuff 4.7/charge 4.9 全 ≥4.5:1;
# atk/debuff 零换墨、buf 换 HERO_BLUE_DEEP、charge 换 GOLD_INK;随弹入 transform 同步缩放)
draw_rect(Rect2(-its.x * 0.5 - 4.0, -its.y * 0.75, its.x + 8.0, its.y * 1.1), UiKit.PANEL_DATA, true)
f.draw_string(get_canvas_item(), Vector2(-its.x * 0.5, its.y * 0.35), _intent_glyph,
HORIZONTAL_ALIGNMENT_LEFT, -1, 15, _intent_col) # 局部坐标(同上注记——双重偏移修复)
draw_set_transform(Vector2.ZERO, 0.0, Vector2.ONE)
+3
View File
@@ -26,6 +26,7 @@ const PANEL_BORDER := Color8(120, 106, 88) # 面板细线框;兼熄灭点
const GOLD := Color8(240, 168, 40) # 奖励金
const GOLD_DEEP := Color8(176, 122, 20) # 深金(金框描边/达意金)
const GOLD_INK := Color8(116, 80, 11) # 深金墨(意图蓄力徽标墨——PANEL_DATA 垫牌上 4.9:1,UI 设计对齐批 N1 2026-10-06)
const GOLD_LIT := Color8(230, 190, 90) # 亮金(候选高亮)
const GOLD_DIM := Color8(140, 116, 60) # 暗金(已过节点)
const GOLD_DONE := Color8(104, 86, 44) # 已过节点暗金·关卡画面呈现态(关卡画面样张 v1 冻结新值 #68562C——旧 GOLD_DIM #8C743C 对双色墨均 <4.5:1 对比硬指标逼守;GOLD_DIM 他用不动)
@@ -39,6 +40,7 @@ const RED_FORBID := Color8(120, 60, 50) # 禁止框朱
const RED_ALERT := Color8(200, 60, 48) # 报错朱
const HERO_BLUE := Color8(46, 134, 222) # 小人蓝 #2E86DE(样张 v2 定稿 2026-09-28——圣经 §4.1 候选值冻结;旧 #2E6E8E 收敛期快照退役)
const HERO_BLUE_DEEP := Color8(30, 90, 150) # 小人蓝同族深档(意图增益徽标墨——PANEL_DATA 垫牌上 4.8:1;命名同 CONTACT_GLOW_DEEP 规则,UI 设计对齐批 N1 2026-10-06)
const BOSS_PURPLE := Color8(143, 47, 106) # 紫赤(Boss 专属)
const DEBUFF_PURPLE := Color8(122, 66, 148) # 妨害紫(意图 ☠)
@@ -50,6 +52,7 @@ const WARM_FAINT := Color8(205, 184, 140) # 暖白弱化(帮助文)#CDB8
const STONE := Color8(120, 110, 98) # 灰石(通道/箭头/失效)
const STONE_FAINT := Color8(140, 124, 100) # 灰石弱化(占位提示文)
const STONE_DEEP := Color8(85, 77, 65) # 灰石深化(「已用」槽位墨——PANEL_DATA 槽牌 5.6:1 / 石皮 5.0:1,UI 设计对齐批 N1 2026-10-06;旧 STONE_FAINT 对亮底双向 <4.5:1)
const DARK_UPCOMING := Color8(64, 58, 52) # 未达暗字(底/文同值)
const BRICK := Color8(201, 175, 131) # 棋盘·未开掩尘地砖 #C9AF83
+112
View File
@@ -0,0 +1,112 @@
# VERTICAL SLICE - NOT FOR PRODUCTION
# UI 文字对比度机检(UI 设计对齐批 T2 2026-10-06——任务书 §7 新增机检段①,probe_gate 默认必跑)
# 断言面 = 文字墨对直背景 ≥4.5:1(art-bible §7.2 无区域例外;文字禁直压纹理底——垫牌后按牌色计)。
# 测点表随批维护:血数垫牌 / 意图徽标四墨(PANEL_DATA 垫牌)/ C区槽位两态墨 / RAP 标签 + 全站锚点组。
# 测点对一律取 UiKit 常量实时求值——代码侧换色即本闸红,禁只改注释不动值;α<1 墨先对背景混成再算。
# 运行:Godot_console.exe --headless --path . res://smoke/ui_contrast_probe.tscn
extends Node
const MIN_RATIO := 4.5
# R1 过渡白名单:呈现层(ui_kit.gd 之外)允许的裸 Color8( 在册处——file→恰计数。
# T0 实测全量=25 处/10 文件(任务书 N4a 普查 5 处系漏记);UI 设计对齐批 T4a 全量原值搬运收 ui_kit
# 后本表应为空表。新增裸取色 = 本闸红(先立常量再消费)。
const BARE_COLOR8_WL := {
"res://presentation/views/board_cell_unit.gd": 4, # N4a:E_FACADE_FOOT_COL/FOG_MEMORY_PLATE/FOG_MEMORY_INK/oc
"res://presentation/views/level_map_screen.gd": 4, # N4a:ICON_TINT_ON_GOLD + 3 处(T0 普查补记)
"res://presentation/ui_assembler.gd": 3,
"res://presentation/views/ap_bar_view.gd": 4,
"res://presentation/views/battle_end_overlay.gd": 1,
"res://presentation/views/board_zone_view.gd": 1,
"res://presentation/views/camp_overlay_view.gd": 1,
"res://presentation/views/curio_pick_overlay.gd": 4, # F3 类型色内联四族(bonus_pick 随 15② 改名)
"res://presentation/views/settings_overlay.gd": 2,
"res://presentation/views/shop_overlay_view.gd": 1, # F3 货架卡固定默认值
}
# 测点表:[名称, 墨色, 直背景, 墨α](语义见行尾;新增文字位随批入表,白名单豁免须注理由)
func _pairs() -> Array:
return [
["站桩血数·垫牌", Color(1, 1, 1), UiKit.HP_BAR_BACK, 0.95], # N1-1/2 白 α.95 压 HP_BAR_BACK 素牌
["意图atk·垫牌", UiKit.RED_MINE, UiKit.PANEL_DATA, 1.0], # N1-3 ⚔ 攻击预告(零换墨)
["意图buf·垫牌", UiKit.HERO_BLUE_DEEP, UiKit.PANEL_DATA, 1.0], # N1-4 ✦ 增益(同族深档)
["意图debuff·垫牌", UiKit.DEBUFF_PURPLE, UiKit.PANEL_DATA, 1.0], # ☠ 妨害(零换墨随牌达标)
["意图charge·垫牌", UiKit.GOLD_INK, UiKit.PANEL_DATA, 1.0], # 蓄力重击(深金墨)
["C区槽·已用", UiKit.STONE_DEEP, UiKit.PANEL_DATA, 1.0], # N1-5 占位暗字(灰石深化)
["C区槽·不可用", UiKit.INK_LABEL, UiKit.PANEL_DATA, 1.0], # N1-6 置灰(标签深墨)
["RAP标签", UiKit.INK_LABEL, UiKit.PANEL_DATA, 1.0], # N1-7(T0 实测已合规,显式化)
["锚·正文墨/数据板", UiKit.INK, UiKit.PANEL_DATA, 1.0], # 全站锚点:正文墨对数据板
["锚·暖白/屏根", UiKit.WARM, UiKit.BG_ROOT, 1.0], # 全站锚点:暗底正文
["锚·暖白弱/舞台底", UiKit.WARM_FAINT, UiKit.STAGE_BG, 1.0], # 全站锚点:B区辅助墨
]
func _lum(c: Color) -> float:
var f := func(x: float) -> float:
return x / 12.92 if x <= 0.03928 else pow((x + 0.055) / 1.055, 2.4)
return 0.2126 * f.call(c.r) + 0.7152 * f.call(c.g) + 0.0722 * f.call(c.b)
func _ratio(a: Color, b: Color) -> float:
var la := _lum(a)
var lb := _lum(b)
var hi := la if la >= lb else lb
var lo := lb if la >= lb else la
return (hi + 0.05) / (lo + 0.05)
func _ready() -> void:
var problems: Array = []
var pairs := _pairs()
for p in pairs:
var fg: Color = p[1]
var bg: Color = p[2]
var alpha: float = p[3]
if alpha < 1.0:
fg = Color(fg.r * alpha + bg.r * (1.0 - alpha),
fg.g * alpha + bg.g * (1.0 - alpha),
fg.b * alpha + bg.b * (1.0 - alpha))
var r := _ratio(fg, bg)
if r < MIN_RATIO:
problems.append("[contrast] %s = %.2f:1 < %.1f(测点对须垫牌或换墨)" % [p[0], r, MIN_RATIO])
problems.append_array(_scan_static())
if problems.is_empty():
print("[ui_contrast_probe] PASS — 对比度 %d 对测点全绿(≥%.1f:1 无区域例外)+ 裸色白名单/preload 红线静态段绿" % [pairs.size(), MIN_RATIO])
get_tree().quit(0)
else:
for msg in problems:
print(msg)
print("[ui_contrast_probe] FAIL — %d 项越带(含静态段)" % problems.size())
get_tree().quit(1)
# ---- 机检段②③(任务书 §7):呈现层裸 Color8( 计数 vs 白名单 + 素材 preload 计数 = 0 ----
func _scan_static() -> Array:
var problems: Array = []
var root := "res://presentation"
var dirs := [root]
while not dirs.is_empty():
var d: String = dirs.pop_front()
for f in DirAccess.get_files_at(d):
if not f.ends_with(".gd"):
continue
var path := d + "/" + f
var src := FileAccess.get_file_as_string(path)
var c8 := src.count("Color8(")
var pre := 0
for line in src.split("\n"):
if line.contains("preload(") and (line.contains("res://assets/") or line.contains(".png")):
pre += 1
if path.ends_with("/ui_kit.gd"):
if pre != 0:
problems.append("[static] ui_kit.gd 素材 preload=%d(红线=0)" % pre)
continue # ui_kit=色板工厂本体,Color8 定义面合法
var wl: int = BARE_COLOR8_WL.get(path, 0)
if c8 != wl:
problems.append("[static] %s 裸 Color8=%d 白名单=%d(R1 先立常量再消费)" % [path, c8, wl])
if pre != 0:
problems.append("[static] %s 素材 preload=%d(R2 红线=0)" % [path, pre])
for sub in DirAccess.get_directories_at(d):
dirs.append(d + "/" + sub)
return problems
+6
View File
@@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3]
[ext_resource type="Script" path="res://smoke/ui_contrast_probe.gd" id="1"]
[node name="UIContrastProbe" type="Node"]
script = ExtResource("1")
+12 -1
View File
@@ -3,7 +3,8 @@
# 三闸:①每段 timeout 守卫(挂死=FAIL 不静默)②段前预清+段后清本 game 目录孤儿 Godot
# (按命令行精确匹配本 game 路径,不误杀其他 worktree 会话的合法进程)③末尾残留清点=批末闸(必须 0)。
# 段:ui_input_probe=默认必跑;ui_struct_probe=默认必跑(ui-struct-probe mini-loop 2026-10-05 注册——
# 全 UI 屏结构断言:按钮互压/等宽/出屏/零尺寸/标题屏双列);--click=加跑 ui_click_probe 行为走查
# 全 UI 屏结构断言:按钮互压/等宽/出屏/零尺寸/标题屏双列);ui_contrast_probe=默认必跑(UI 设计对齐批
# T2 2026-10-06 注册——UI 文字对比度机检 ≥4.5:1 无区域例外,测点表随批维护);--click=加跑 ui_click_probe 行为走查
# (自退出+退出码闸;超时多半=探针未适配新停点层,归 probe适配批);shot_probe 禁入本闸——
# 必须窗口化运行(headless 无渲染面,探针内已有 fail-fast 护栏),归真人目检。
# 用法: tools/probe_gate.sh [game目录] [--click] 缺省 game 目录=脚本所在仓库的 game/(worktree 内自动指向该 worktree)
@@ -62,6 +63,16 @@ elif ! grep -q "PASS" "$TMP/stp.log"; then
echo "[probe_gate] FAIL — ui_struct_probe 未见 PASS(exit=$st)"; _rc=1
fi
echo "======== ui_contrast_probe ========"
timeout 120 "$G" --headless --path "$GAME_WIN" res://smoke/ui_contrast_probe.tscn >"$TMP/ctp.log" 2>&1
st=$?; kill_orphans
grep -E "PASS|FAIL" "$TMP/ctp.log" | head -12
if [ "$st" -eq 124 ] || [ "$st" -eq 137 ]; then
echo "[probe_gate] FAIL — ui_contrast_probe 超时挂死(exit=$st),孤儿已清"; _rc=1
elif ! grep -q "PASS" "$TMP/ctp.log"; then
echo "[probe_gate] FAIL — ui_contrast_probe 未见 PASS(exit=$st)"; _rc=1
fi
if [ "$WITH_CLICK" -eq 1 ]; then
echo "======== ui_click_probe 行为走查 ========"
timeout 240 "$G" --headless --path "$GAME_WIN" res://smoke/ui_click_probe.tscn >"$TMP/clk.log" 2>&1