Files
SpineWallpaper/.scratch/build-pipeline/issues/17-auto-increment-ids.md
T
Shuery 3f11426964 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 处引用自包含。
2026-10-02 01:27:02 +08:00

4.5 KiB
Raw Blame History

17 — 自动生成的 id 改成自增

Status: resolved Type: task

需求

自动生成的 json 相关的 id 采取自增的形式,如 audios

两处(用户确认「两者都要」):

旧 新
project.json 属性的 index / order 手写在 src/project.template.json build 按属性表书写顺序自动编号
音源 id(meta.json 的 audio.choices[].id) 手写字符串(zaiduheni / xilian / pv37) build 自增分配("1" / "2" / "3")

① index / order

以前每个属性都要写 "index": 4, "order": 104。代价在加一个属性时才显出来: 后面全部要重编号——上一轮加 use_custom_audio 手改了 6 处,而且在产物 diff 里 刷出 8 行纯噪音,把真正的改动淹掉了。

现在 numberProperties() 按属性表的书写顺序编号:

index = 0,1,2…      order = 100+index

必须在删属性之后编号:单档分发会删掉 preset/preset_note/bgm/bgm_note 四行, 以前删完就留下空号(0,1,4,5,6,7,8)。现在自动补上,单档是 0…6 连续。

schemecolor 是唯一例外:它是 WE 的内置属性,线上就是 order 0 且没有 index。 用 "$order": 0 显式钉住,钉住的属性不参与 index 序列——这样 collection-all 的产物 与线上逐字一致,diff 里只剩真实改动。

② 音源 id

meta.json 里不再写 id:

"audio": {
  "choices": [
    { "name": "「再度和你」", "file": "audios/zaiduheni.flac" },
    { "name": "昔涟", "file": "audios/xilian-src.flac" }
  ]
}

一个必须解决的约束:id 要全项目唯一

第一版我按「每档壁纸各从 1 开始」写,这是错的。generate.ts 里:

bgmOptions.push({ label: choice.name, value: choice.id });

bgm 下拉会把一个分发里所有壁纸的音源平铺进同一个 combo。两档壁纸都叫 "1" 的话, 选中的到底是哪一个就无从分辨了。

所以用一个全项目计数器,分配顺序固定为:

游戏 → 该游戏的共享音频 → 各壁纸的音源(按 id 排序)

遍历的是整棵资源库而不是本次要构建的分发子集——否则同一个音源在不同分发里会拿到不同的 id,用户从合集切到单档时 bgm 选择就失效了。实测:xilian 的两个音源在 collection-all 与 single-hsr-xilian 里都是 "2" / "3"。

default 也跟着改:从「id 字符串」变成「1 起的位置」,省略 = 第一个。换算成 0 起的 defaultIndex 只做一处(vault.ts 的 readAudioDecl)。

代价(用户已确认接受)

音源 id 会进 project.json 的 bgm combo value。改成数字后,老用户已保存的 bgm 选择会失效 (和壁纸预设 id 同一个问题)。运行时对这种情况是安全的:bgmSource() 找不到匹配就回落到 本壁纸默认音源。另外在音源清单中间插入一条会让后面的 id 整体后移——加音源请往后加。

顺手修掉一个「一直红着」的测试

改完跑 test-props.mjs,2 项失败:

✗ bgm 选「昔涟」后填自定义 URL  → 期望 custom-track.mp3,实得 xilian-src.flac
✗ 切壁纸不得清掉自定义 URL      → 期望 custom-track.mp3,实得 pv37.mp3

这不是这次改动造成的:上一轮加 use_custom_audio 时,audio_file 被改成只在开关打开时 才生效,而当时我没有重跑这个测试——它从那时起就一直是红的。test-acceptance.mjs 同理。

两处都补上开关,并顺手把「开关关着时填 URL 不生效」加成一条断言——那正是这个开关的核心语义。

改了语义却没跑对应的测试,等于没测。这次是靠改另一个东西时才撞出来的。

验证

全量回归,全绿:

  • pnpm check:四个分发、check:dist / check:syntax / check:paths("3 条音源声明无孤儿文件")
  • test-props.mjs(bgm 选择/回落、fps 限流)、test-resize.mjs、test-acceptance.mjs、verify-fitter.mjs
  • 调试服冒烟、浏览器冒烟、面板还原度(10 组)、热更新
  • 四档自包含包 file://、静态托管预览、sim 门禁、内联守卫、模块改写
  • verify-visual-equivalence:6 组与重构前逐像素相同
  • diff-project:差异 13 → 14,新增的那一条是 bgm.options(value 从名字变数字), 正是本次有意的改动;index/order 相关没有新增差异