Files
SpineWallpaper/docs/adr/0008-asset-layout-per-skeleton.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

59 lines
3.6 KiB
Markdown
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.
# 资源布局:一具骨架一组,而不是按文件类型分组
> **取代** ADR 0001 第 7 行「保留 `effects/`/`images/`/`audios/` 三层同名子目录」与 ADR 0005 第 43 行
> 「这一条不变」。那两条的前提是"Spine 骨架 JSON 硬编码了 `"images": "../images/"`,改了就得动骨架文件";
> 本决策把贴图页并到 atlas 同目录、把骨架里的 `images` 归零之后,这个前提本身消失了。
## 背景
`wallpapers/<游戏id>/<壁纸id>/` 原来是按**文件类型**分的:骨架数据在 `effects/<名>.json`,
atlas 与贴图页在 `images/`(或 `images/<名>/`),场景图在 `images/scene/`。于是**一具骨架自己的
东西被拆到两个目录**,找一样东西要跳两次;`effects/` 这个名字还有歧义(它装的是骨架数据,
不是"特效",而真正的场景图在别处)。
查过官方文档:**Spine 对 HTML 项目的目录结构没有任何约定**。[导出文档](https://en.esotericsoftware.com/spine-export)
只规定"每个骨架一个数据文件、文件名用骨架名",外加导出时可选 pack 出 atlas。所以这不是"遵循规范"的问题,
而是我们自己的取舍。
真正约束布局的只有一条**运行时的解析规则**(读 vendored spine-ts 源码得到):
```js
page.setTexture(assetManager.get(pathPrefix + page.name)); // AssetManager.loadTextureAtlas
```
即 atlas 第一行是页名、**页相对 atlas 所在目录解析**;`skeleton.images` 只是可选前缀。
所以「页必须与 atlas 同目录」是硬约束,其余随便放。
来源页面(米哈游活动页)自己也是按类型分的(`images/effect/spine/*.json|.atlas`、
`images/effect/scene/*`、`audio/*`),它能这么干是因为它的引擎有**全局图片表**、按逻辑名查页;
我们用的是 spine-ts,做不到。
## 决策
**按"一件东西一组"分,而不是按后缀分**:
```
wallpapers/<游戏id>/<壁纸id>/
├── spines/<骨架名>/<名>.json | <名>.atlas | 贴图页… ← 一具骨架一组
├── scene/ ← 场景图与背景图(非骨架的图)
├── audios/ ← 音源
├── meta.json preset.template.json preview.gif
```
- 页跟着 atlas 走,天然满足运行时规则(不再需要 `skeleton.images` 前缀)。
- 去掉了有歧义的 `effects/`:骨架就是骨架。
- 一档壁纸目前就是**一个场景**(`sceneConfig` 就是那一个),所以不再多套一层 `scenes/<场景id>/`;
真出现"一档多场景"时再加,而不是现在提前分层。
- **例外**:`backgroundImage` 可以指向某个骨架的贴图页(kv37 就是这样),那种情况就写
`spines/<名>/<页>`,不强行搬进 `scene/`——**判据是 atlas 自己声明的页名**,不做名字启发式。
## 后果
- 构建侧要同步的一处硬编码:`tools/lib/generate.ts` 的 `copyWallpaperAssets` 只搬
`spines` / `scene` / `audios` 三个目录名;改名必须改它。
- `tools/downloader/promote.py` 产出的新壁纸直接是这套布局(否则存量与增量的形状会分叉)。
- 存量三档壁纸迁移了 86 个文件,预设路径按实际落点重写;
`verify-visual-equivalence` 确认三个比例下**逐像素相同**(布局不影响渲染)。
- 迁移脚本留在 `.scratch/build-pipeline/`(含补救脚本),其中固化一条教训:
跨平台路径映射**别拿 `str(Path)` 当键**(Windows 会给反斜杠,而预设里是正斜杠)。