Files
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

77 lines
5.8 KiB
Markdown
Raw Permalink 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.
# SpineWallpaper(网页壁纸作品)
一份已发布的 Wallpaper Engine 网页壁纸,以及围绕它的资源分层、构建与验证约定。这个上下文关心"一档壁纸由什么组成、怎么被打包成可上传的分发、怎么在本地调试"。
## 源数据规范
`wallpapers/` 是**唯一真相来源**,`dist/` 全部由它生成。那个目录里每个文件该放哪、叫什么、
构建会校验什么,见 **[wallpapers/README.md](wallpapers/README.md)** —— 目录结构、三层 `meta.json`
的字段、id 规则、音频规范、常见任务步骤、门禁清单都在那里。**动 `wallpapers/` 之前先读它。**
回归验收套件在 **[`tools/checks/`](tools/checks/README.md)**(原来散在 `.scratch/` 下,
但那里是问题与规格的存放处)。每个脚本的前置条件不同,逐条命令见那份 README。
## Language
**作品(Project)**:
一个 Wallpaper Engine 打包单元,即任一 `dist/releases/<分发目录>/`;`project.json` 是它的清单,`index.html` 是它的入口。
_Avoid_: 工程、站点、应用
**分发(Release)**:
一次可上传的构建产物,落在 `dist/releases/<目录名>` 下,目录名是 ASCII 的 `single-<游戏id>-<壁纸id>` / `collection-<游戏id>` / `collection-all`(如 `single-hsr-xilian`、`collection-hsr`、`collection-all`)。每个分发都是**自包含**的:整个目录可以拷到别的机器直接上传,内部不出现任何绝对链接与跨目录相对链接。
_Avoid_: 包、构建、输出
**合集(Collection)**:
把多档壁纸收进同一份上传的分发,用户用 WE 的 `preset` 下拉在它们之间切换。**它与「单档」是并列的两种类型**
(`type: "single" | "collection"`),只有收档范围不同:游戏合集(`collection-<游戏id>`)收一个游戏的壁纸,
全部合集(`collection-all`)收所有游戏的壁纸——「全部合集」**也是合集**,不是第三种类型(`scope: "game" | "all"`)。
收档范围是**意图**,不是档数:一个游戏哪怕只有一档壁纸,它的合集仍是合集,只是"切换"这件事不再存在。
_Avoid_: 集合("set"的通用义,不是本术语)、聚合包、多预设版;也别说"单档 vs 游戏"——游戏是资源分层,不是分发类型
**单档(Single)**:
只含一档壁纸的分发(`single-<游戏id>-<壁纸id>`)。它没有"切换预设"这回事,因此 `project.json` 里没有 `preset` 属性;
但**音源切换与预设无关**——一档壁纸照样可以带多首曲子,所以有 ≥2 首时 `bgm` 属性仍在。
_Avoid_: 单品、单独版
**游戏(Game)**:
壁纸所出自的作品名(`崩坏:星穹铁道`),资源分层的第一级。目录名用稳定的**游戏 id**(`hsr`),显示名放在该目录的 `meta.json` 里。
_Avoid_: 来源、IP
**壁纸(Wallpaper)**:
用户可在 WE 属性里切换的一档壁纸(`昔涟立绘`、「成为昨日的明天」)。目录名用稳定的**壁纸 id**(`xilian`、`kv37`),显示名放在该目录的 `meta.json` 里。
_Avoid_: 预设、选项、preset(当指"这一档"本身时)
**预设(Preset)**:
一档壁纸的配置实体,落盘为该壁纸目录下的 `preset.js`,声明这一档要用哪些资源、以什么参数播放。一档壁纸对应且仅对应一个预设。源数据是 `preset.template.json`,`preset.js` 由构建生成。
_Avoid_: 配置、profile、manifest
**预设 id / 壁纸 id**:
壁纸的稳定标识(`xilian`、`kv37`),必须与 WE 属性值一致,永不随显示名变化——已发布作品的用户设置靠它维系。它同时是目录名与下拉取值,因此**全局唯一、且不加前缀**(构建会校验并给出明确报错,而不是自动改名绕过)。
_Avoid_: slug、键名、代号
**共享音频(Shared audio)**:
放在合集根 `audios/` 下的音源。合集分发的 `bgm` 要能选到分发内任一壁纸的音源,所以音频统一集中到分发根,按 `<壁纸id>/` 分目录存放;游戏级共享音频(`wallpapers/<游戏id>/audios/`)落在合集根、不进任何壁纸子目录。单档分发里没有共享音频这回事。
_Avoid_: 公共音频、全局音源
**音源(AudioSource)**:
一首可作背景音乐的曲子。每首曲子归属且只归属一档壁纸;WE 的音源列表是所有壁纸音源声明的并集。
**文件名保留中文**,`meta.json` 只声明 `name`(显示名)与 `file`;**id 由构建按固定顺序自增分配**
(全项目唯一——`bgm` 下拉会把所有壁纸的音源平铺进同一个列表)。**choices 的顺序即默认**。
_Avoid_: BGM、曲目、音频文件
**模拟器(Simulator)**:
`pnpm dev` 注入页面的一层"Wallpaper Engine 官方 API 替身",让壁纸在不启动 WE 的情况下跑起来调试。它严格还原 WE 的真实 API 面:不自我检测、不提供 WE 没有的全局、把做不到的事显式标为替身。
_Avoid_: 仿冒器、mock、假 WE
**替身(Substitute)**:
模拟器**做不到与 WE 一致**的那部分能力(原生文件对话框回传 `file:///`、用户数据目录真实路径、CEF cookie 隔离)。它们在面板的常驻横幅与 `window.__weSim.substituted` 里被显式列出,而不是伪装成"和 WE 一样"。
_Avoid_: 兼容项、差异、限制
**视口(Viewport)**:
交给 Spine 播放器的世界坐标系矩形,决定构图。它以等比"contain"方式映射到画布:单轴贴边、另一轴会多露出世界,因此负 padding 的裁切只在目标比例下成立。
_Avoid_: 相机、取景框、裁剪区
**对拍(AB capture)**:
同一壁纸、同一分辨率、同一动画相位下的改动前后像素比对。噪声底约 0.7/255;低于 1 视为无差异。
_Avoid_: 截图测试、视觉回归