import type { Rect } from './anchor-solver.js'; import type { PrototypeGeometry } from './prototype-import.js'; /** 采样点标识:中心 + 四角(tl/tr/br/bl)。 */ export type SamplePointId = 'center' | 'tl' | 'tr' | 'br' | 'bl'; export interface SamplePoint { id: SamplePointId; x: number; y: number; } export interface PixelSample { id: SamplePointId; x: number; y: number; rgb: [number, number, number] | null; distance: number | null; ok: boolean; } export interface NodePixelResult { name: string; rect: Rect; target: [number, number, number]; samples: PixelSample[]; ok: boolean; } export interface BgTarget { name: string; rect: Rect; target: [number, number, number]; borderRadius: number; borderWidth: number; /** 带 text 节点为 true(F3):文字水平居中排版,中心点必踩文字渲染/抗锯齿像素, * 编排层组装采样点时过滤掉 center(四角 inset>0 避开文字,仍可判)。 */ skipCenter: boolean; } /** 判定容差(0-255 欧氏距离):中心严格、角点宽松(spec §5,阈值 §10.2 集成校准—— * 2026-08-18 集成校准(css-card,真渲染):13 采样点 distance=0.0,零底噪零偏移,无需裕量)。 */ export declare const CENTER_TOL = 20; export declare const CORNER_TOL = 60; /** * 中心 + 四角内缩采样点(spec §5)。内缩量 clamp:min(borderRadius + borderWidth, * 短边/2 − 2)——防 borderRadius > 短边一半时角点越界;短边 < 4 时下限回落 0 * (角点=rect 角,仍在图内,由 pixelAt 越界 null 兜底)。中心点不内缩(圆角矩形 * 中心必在填充区内)。半开区间语义(F4,2026-08-18 集成取证):rect 覆盖像素列 * [x, x+w)、行 [y, y+h),右/下缘最后有效像素格是 x+w−1 / y+h−1——角点右/下分量 * 取 x+w−1−inset / y+h−1−inset(左/上分量 x+inset / y+inset 不变),否则 inset=0 * 时角点落在覆盖区外一像素格、采到节点外背景(实测 css-card HpBar 角点 d=65.7)。 * 坐标 floor 到整数像素格(0-indexed:奇数尺寸中心取左中像素,如 w=101 → 50; * Math.round 对 half 值向上取整得 51/31,与测试断言 50/30 冲突,以断言为准裁定 * floor,整数输入下两者等价)。 */ export declare function computeSamplePoints(rect: Rect, borderRadius: number, borderWidth: number): SamplePoint[]; /** 读 PNG(解码后 {width,height,data:RGBA Buffer})指定像素 RGB;越界返回 null。 */ export declare function pixelAt(png: { width: number; height: number; data: Buffer; }, x: number, y: number): [number, number, number] | null; /** 0-255 空间 RGB 欧氏距离。 */ export declare function rgbDistance(a: [number, number, number], b: [number, number, number]): number; /** * 收集采样目标:输入 geometry 中带 bg 的节点(spec §5「每 bg 节点」;fill-only 不进—— * fill 槽语义属 ProgressBar 内部渲染,非本工具首版范围)。跳过两类(诚实 skip,不伪装判定): * 1. 半透明 bg(alpha < 0.999):合成后采样色 ≠ bg_color,像素直判不可用; * 2. ProgressBar 系 bg(F2,2026-08-18 集成取证):ProgressBar 的 bg 渲染面被 fill 与 * 百分比文字(show_percentage 默认 true,画在 bar 几何中心)覆盖,无可采样纯色区域 * ——bg 槽验证请依赖 style_verify 的数值 diff。 * 带 text 节点标 skipCenter(F3):文字水平居中排版,中心点踩文字渲染像素(实测 * css-card Title/TagChip center d≈48),由编排层过滤 center 采样点。 * per-corner borderRadius 对象取四角 max(保守内缩)。 * 注意:未映射控件(如 LineEdit 带 bg,规则 12)的 bg 被翻译层忽略、渲染无该色—— * 本函数仍收集之,采样预期红;这与 build_warnings 的「样式丢失」警告互为印证,是诚实 * 信号不是误报(实现期若发现高频误报噪声,可升级为按 styleboxSlotFor skip+reason, * 须同步单测)。 */ export declare function collectBgTargets(geo: PrototypeGeometry): { targets: BgTarget[]; skipped: Array<{ name: string; reason: string; }>; }; /** * 逐点判定组装 NodePixelResult。points/samples 由编排层成对给出(samples 的 rgb 已 * 含越界 null);中心点用 CENTER_TOL、角点用 CORNER_TOL;rgb null(越界/读不到) * 记 ok:false + distance:null——越界采样点是问题不是噪声,必须红。 */ export declare function judgeNode(name: string, rect: Rect, target: [number, number, number], points: SamplePoint[], samples: Array<{ x: number; y: number; rgb: [number, number, number] | null; }>): NodePixelResult; export interface PixelVerifySummary { nodes: NodePixelResult[]; pass: number; fail: number; skipped: Array<{ name: string; reason: string; }>; viewport: { w: number; h: number; }; image: { width: number; height: number; scaled: boolean; cleaned_up: boolean; }; tolerances: { center: number; corner: number; }; note: string; } /** 绝对路径 → res:// 形式(screenshot_capture.gd 的 ResourceLoader.exists/load 需要)。 */ export declare function toResPath(projectPath: string, absPath: string): string; /** * ui_pixel_verify 编排:collectBgTargets → captureScreenshot(窗口模式,viewport=geo.viewport) * → PNG 解码 → BLANK 双条件拦截(stdout BLANK_DETECTED 且图像 8x8 网格均匀,见 isUniformImage) * → 逐节点采样点计算(skipCenter 过滤 center;必要时按 PNG/viewport 线性缩放)→ 判定 * → try/finally 清理 PNG 中间产物(spec §5:临时名落项目内,失败路径也清理)。 * 返回 ok:false 的三类:capture 失败 / BLANK 双条件命中 / PNG 解码失败。 * cleaned_up 语义:finally 无条件 rmSync(force:true 不抛),成功路径直接写 true。 */ export declare function runPixelVerify(params: { godotPath: string; projectPath: string; scenePath: string; geo: PrototypeGeometry; }): Promise<{ ok: true; summary: PixelVerifySummary; } | { ok: false; error: string; hint?: string; }>;