feat: 比例适配、bgm 音源选择与 fps 限流,打包 v3
取景(issue 04) - 新增 viewport-fitter.js:让立绘层缩放跟随背景图的 cover 缩放——背景放大多少倍、 特效就放大多少倍。原先背景走 cover、立绘层走 contain,比例一变两者就分叉。 16:9 下与作者设定逐像素一致(kv37 为 0 差异)。实测证伪了"contain 会裁掉作者视口" 这个最初的判断:contain 在任何比例下都完整含住作者视口。 - 应用方式为原地改写 config.viewport 字段后调 setViewport(),不重建播放器; 维护挂在 config.frame 上按画布比例增量进行(config.success 早于 setViewport,拿不到视口)。 WE 属性(issue 05) - project.json 新增 bgm combo(所有壁纸音源的并集 + 「随预设」);所选项不属于当前壁纸时 音频回落该壁纸默认,选择本身保留。 - fps 限流包裹实例 drawFrame 并接管排程。修掉两个实测缺陷:朴素丢帧会把 rAF 抖动放大成 整拍丢失(目标 30fps 实测只有 22.5fps);fps:0 被真值判断吞掉导致无法取消限流。 打包(issue 06) - project.json version 升至 3 并更新描述;preset 的 combo 取值保持 xilian/kv37 不变。 - preview.gif 821 KB → 347 KB(每 2 帧取 1 帧 + 128 色不抖动,逐帧与源帧像素完全相同)。 - index.html 加内联 favicon,消除 CEF 自动请求 /favicon.ico 造成的 404 报错。 其它 - dist/scripts/wallpaper-engine.js 移到 tools/:它没有任何入口引用,且环境判据依赖真实 WE 并不存在的 wallpaperRegisterListener,一旦按它自己的说明挂进 index.html 会在生产环境自我激活。 - 修正死文件检查:原检查会拿文件名匹配到文件自身的内容,使这类文件漏网。 - 新增离线算式验证与 resize / 属性 / 全量验收三套浏览器测试脚本。
This commit is contained in:
1 parent
4662856963
commit
eb56efbd9e
22 files changed
+2766
-1012
No files matched your search
@@ -0,0 +1,85 @@
|
||||
// 量出「立绘在屏幕上的实际足迹」:正常帧与藏 canvas 参考帧的差值掩码。
|
||||
// 不依赖对视口/相机数学的任何建模——直接测渲染结果。
|
||||
// 输出:足迹包围盒、四条边是否被画布切掉、覆盖面积占比、足迹底边距画布底部的距离。
|
||||
// 用法:node tools/subject.mjs <normal.png> <ref.png> [threshold] [edgeBand]
|
||||
|
||||
import { spawn } from "node:child_process";
|
||||
|
||||
const [normal, ref, threshold = "8", edgeBand = "2"] = process.argv.slice(2);
|
||||
if (!normal || !ref) {
|
||||
console.error("usage: node tools/subject.mjs <normal.png> <ref.png> [threshold] [edgeBand]");
|
||||
process.exit(2);
|
||||
}
|
||||
const T = Number(threshold);
|
||||
const BAND = Number(edgeBand);
|
||||
|
||||
function probe(file) {
|
||||
return new Promise((resolve) => {
|
||||
const p = spawn("ffprobe", ["-v", "error", "-select_streams", "v:0", "-show_entries", "stream=width,height", "-of", "csv=p=0", file]);
|
||||
let out = "";
|
||||
p.stdout.on("data", (d) => (out += d));
|
||||
p.on("close", () => {
|
||||
const [w, h] = out.trim().split(",").map(Number);
|
||||
resolve({ w, h });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const { w: W, h: H } = await probe(normal);
|
||||
|
||||
const buf = await new Promise((resolve, reject) => {
|
||||
const p = spawn("ffmpeg", ["-v", "error", "-i", normal, "-i", ref, "-lavfi", "blend=all_mode=difference,format=gray", "-f", "rawvideo", "-pix_fmt", "gray", "-"], {
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
});
|
||||
const chunks = [];
|
||||
let err = "";
|
||||
p.stdout.on("data", (d) => chunks.push(d));
|
||||
p.stderr.on("data", (d) => (err += d));
|
||||
p.on("close", (code) => (code === 0 ? resolve(Buffer.concat(chunks)) : reject(new Error(err || `exit ${code}`))));
|
||||
});
|
||||
|
||||
if (buf.length < W * H) {
|
||||
console.error(`差分流只返回 ${buf.length} 字节,期望 ${W * H}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let minX = W, maxX = -1, minY = H, maxY = -1, count = 0;
|
||||
const edge = { left: 0, right: 0, top: 0, bottom: 0 };
|
||||
|
||||
for (let y = 0; y < H; y++) {
|
||||
for (let x = 0; x < W; x++) {
|
||||
if (buf[y * W + x] <= T) continue;
|
||||
count++;
|
||||
if (x < minX) minX = x;
|
||||
if (x > maxX) maxX = x;
|
||||
if (y < minY) minY = y;
|
||||
if (y > maxY) maxY = y;
|
||||
if (x < BAND) edge.left++;
|
||||
if (x >= W - BAND) edge.right++;
|
||||
if (y < BAND) edge.top++;
|
||||
if (y >= H - BAND) edge.bottom++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!count) {
|
||||
console.log(`${normal} 没有超过阈值 ${T} 的像素——立绘层是空的?`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const pct = (n) => ((n / (W * H)) * 100).toFixed(3) + "%";
|
||||
console.log(`${normal} (${W}x${H}, 阈值 ${T})`);
|
||||
console.log(` 足迹包围盒 x:[${minX}, ${maxX}] y:[${minY}, ${maxY}] 尺寸 ${maxX - minX + 1}x${maxY - minY + 1}`);
|
||||
console.log(` 覆盖面积 ${count} 像素 (${pct(count)})`);
|
||||
console.log(` 底部余量 画布底 ${H} - 足迹底 ${maxY} = ${H - 1 - maxY} px`);
|
||||
console.log(` 顶部余量 ${minY} px`);
|
||||
console.log(` 左右余量 左 ${minX} px / 右 ${W - 1 - maxX} px`);
|
||||
console.log(
|
||||
` 贴边情况 ${[
|
||||
edge.left ? `左 ${edge.left}` : "左 -",
|
||||
edge.right ? `右 ${edge.right}` : "右 -",
|
||||
edge.top ? `上 ${edge.top}` : "上 -",
|
||||
edge.bottom ? `下 ${edge.bottom}` : "下 -",
|
||||
].join(" ")} (${BAND}px 带内)`,
|
||||
);
|
||||
const cut = edge.left || edge.right || edge.top || edge.bottom;
|
||||
console.log(` 判定 ${cut ? "被画布边缘切到" : "四边都未触边"}`);
|
||||
Reference in new issue
Block a user