Files
SpineWallpaper/tools/compare.mjs
T
Shuery 09ff322fe8 refactor: 资源按 游戏/壁纸 分层,预设拆进各自壁纸目录
- assets/<游戏>/<壁纸>/{effects,images,audios}/,每档壁纸自包含
- 每档壁纸自带 preset.js:用 import.meta.url 推导自身资源路径,目录可整体搬走;
  目录名用显示名(含「」),代码键用稳定 id(xilian/kv37,与 WE 属性值绑定)
- preset-store.js -> presets.js:静态 import 两份预设并建 id 索引
- 新增 CONTEXT.md 术语表与 ADR-0001/0002
- 新增 check-paths / compare / heatmap 三个验证工具;serve.mjs 改为每帧强制动画相位归零

验证:check-paths 11/11 路径存在(含此前零引用的 昔涟.flac);浏览器 0 个真实 404;
与基线 worktree 同冻结设置对拍,9 对跨版本比较中 4 对逐像素完全相同(差异 0),
其余 ≤0.19/255,远低于基线自身的双模态抖动(2.27/255)。
2026-09-19 19:26:46 +08:00

59 lines
2.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 对拍比较:把两批截图逐对做差值,给出"改完到底有没有动到画面"的判定。
// 用法:node tools/compare.mjs <A目录> <B目录> [--tag A] [--tag B] [--threshold 1.0]
// 例: node tools/compare.mjs before after
import { spawn } from "node:child_process";
import { readdir } from "node:fs/promises";
import { resolve } from "node:path";
const argv = process.argv.slice(2);
const [dirA, dirB] = argv;
if (!dirA || !dirB) {
console.error("usage: node tools/compare.mjs <dirA> <dirB> [--threshold 1.0]");
process.exit(2);
}
const opt = (name, dflt) => {
const i = argv.indexOf(`--${name}`);
return i >= 0 ? argv[i + 1] : dflt;
};
const threshold = Number(opt("threshold", "1.0"));
function run(cmd, args) {
return new Promise((resolve) => {
const p = spawn(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
let out = "";
p.stdout.on("data", (d) => (out += d));
p.stderr.on("data", (d) => (out += d));
p.on("close", () => resolve(out));
});
}
const A = resolve("tools/shots", dirA);
const B = resolve("tools/shots", dirB);
const files = (await readdir(A)).filter((f) => f.endsWith(".png") && !f.endsWith(".ref.png")).sort();
let worst = 0;
let worstName = "";
let failed = 0;
for (const f of files) {
const a = resolve(A, f);
const b = resolve(B, f);
const out = await run(process.execPath, ["tools/diff.mjs", a, b]);
const m = out.match(/mean\|diff\|=([\d.]+)/);
const mean = m ? Number(m[1]) : NaN;
const verdict = Number.isNaN(mean) ? "MISSING" : mean < threshold ? "same" : "CHANGED";
if (Number.isNaN(mean)) failed++;
else if (mean > worst) {
worst = mean;
worstName = f;
}
console.log(`${f.padEnd(28)} mean|diff|=${String(mean).padStart(7)} ${verdict}`);
}
console.log(`\n${dirA} → ${dirB}:${files.length} 对;最大差异 ${worst.toFixed(3)}/255(${worstName || "无"});判定阈值 ${threshold}`);
if (failed) {
console.log(`${failed} 对缺少对照文件`);
process.exit(1);
}