feat: TS 构建管线、Spine 抓取器与 wallpapers/ 唯一真相来源

把项目从「手写 dist/」改成「wallpapers/ 是唯一真相来源,dist/ 由 pnpm build 生成」,
并补上配套的类型、门禁与抓取器。一次提交落地整条管线,因为拆开会留下不能构建的中间态。

- src/:运行时与模拟器源码(TS,strict),编译到 build/ 再拷进各分发
- tools/:build / dev / check-{syntax,paths,dist},以及抓取器与回归门禁 tools/checks/
  (.scratch/ 下那批一次性脚本移入 tools/checks/ 并入库为长期门禁)
- wallpapers/:七档壁纸的源数据 + README.md(id/音频/预设的完整规范)
- docs/adr/0005-0008:构建管线与分发拓扑、模拟器契约、自包含 sim、每骨架资源布局
- .gitignore:排除 .scratch/ 的参考资料副本(上游 spine 整仓克隆 ~1.2 GB、
  抓取侦查数据 ~680 MB)与调试转储;这些是本地调查材料,补偿会让仓库无法克隆
- 归一化 .gitignore/CONTEXT.md 行尾(工作区 CRLF、索引 LF 造成的整文件假 diff)

同时修掉三档卡住构建的未完工壁纸:
- kv45 的 meta.json 里 id 还是抓取期场景名 scene_main,经 downloader promote 正名为 kv45
- shajin / zhigengniao_juheye 的 meta.json 误用了骨架描述文件(name/spine/animations/pages)、
  且都缺 preset.template.json;现按规范重建:骨架沉到 spines/<名>/(spine-ts 按 atlas 所在
  目录解析贴图页)、补上元数据与单骨架预设,并清掉 zhigengniao 骨架里指向作者机的绝对路径
- 顺带 promote 已在 sources.yml 里的 kv46(月升之前,与兽共舞)

pnpm check 五道门全绿:10 个分发 / 7 档壁纸 / 141 处引用自包含。
This commit is contained in:
Shuery committed 2026-10-02 01:27:02 +08:00
1 parent b8eee05d78
commit 3f11426964
297 files changed
+216627 -1926

No files matched your search

+41
View File
@@ -0,0 +1,41 @@
// 单档分发里真的能切歌吗——选项在 ≠ 切得动。
//
// 这是用户报的那件事的终局判据:single-hsr-xilian 有两首,面板上给了下拉之后,
// 选第二首必须真的换掉 <audio> 的源。
import { withPage, sleep } from "../cdp.mjs";
const BASE = process.argv[2] ?? "http://127.0.0.1:5173";
const name = (src: unknown) => (src ? decodeURIComponent(String(src).split("/").pop() ?? "") : "(空)");
let failures = 0;
const check = (ok: unknown, label: string, detail?: unknown) => {
if (!ok) failures++;
console.log(` ${ok ? "✓" : "✗"} ${label}${detail !== undefined ? ` → ${String(detail)}` : ""}`);
};
await withPage({ width: 1280, height: 720, profile: "tools/.cache/edge-single-bgm" }, async ({ send, evaluate, exceptions }) => {
await send("Page.navigate", { url: `${BASE}/release/single-hsr-xilian/` });
await sleep(3500);
const src = () => evaluate(`(function(){ var a = document.getElementById("background-music"); return a ? a.src : null; })()`);
const bgm = (v) => evaluate(`window.wallpaperPropertyListener.applyUserProperties({ bgm: { value: ${JSON.stringify(v)} } })`);
const initial = await src();
check(name(initial) === "zaiduheni.flac", "默认是第一首「再度和你」", name(initial));
// 「昔涟」在自增 id 里是 "3"(kv37 的「版本 PV」占 "1",xilian 两首是 "2"/"3")
await bgm("3");
await sleep(500);
const afterSwitch = await src();
check(name(afterSwitch) === "xilian-src.flac", "选「昔涟」→ 音源真的换了", name(afterSwitch));
await bgm("2");
await sleep(500);
const back = await src();
check(name(back) === "zaiduheni.flac", "再选回「再度和你」→ 换回来", name(back));
check(exceptions.length === 0, "0 未捕获异常", exceptions.slice(0, 2).join(" | ") || "无");
});
console.log(failures === 0 ? "\n单档切歌:通过" : `\n单档切歌:失败 ${failures} 处`);
process.exit(failures === 0 ? 0 : 1);