diff --git a/.scratch/wallpaper-optimization/issues/01-asset-layout.md b/.scratch/wallpaper-optimization/issues/01-asset-layout.md new file mode 100644 index 0000000..9f8fd1c --- /dev/null +++ b/.scratch/wallpaper-optimization/issues/01-asset-layout.md @@ -0,0 +1,20 @@ +# 01 资源按 游戏/壁纸 分层,预设拆进各自壁纸目录 + +Status: resolved + +## 目标 + +把 `assets/{images,effects,audios}/` 三个平铺目录改成每档壁纸自包含的 `assets/<游戏>/<壁纸>/{effects,images,audios}/`, +并让每档壁纸自带一份 `preset.js` 声明自己的资源,使新增一档壁纸不需要改动公共代码里的路径。 + +## 验收 + +- `godir` 式平铺目录消失,`assets/` 下只剩 `<游戏>/<壁纸>/`。 +- `check-paths` 对每份 `preset.js` 声明的路径全部命中。 +- 浏览器加载 0 个真实 404。 +- 与基线 worktree 同冻结设置对拍,存在逐像素完全相同的配对(即无回归)。 + +## 结果 + +commit `09ff322`。11/11 路径存在(含此前零引用的 `昔涟.flac`);9 对跨版本比较中 4 对差异为 0, +其余 ≤0.19/255,低于基线自身 2.27/255 的双模态抖动;无真实 404。 diff --git a/.scratch/wallpaper-optimization/issues/02-audio-and-image-size.md b/.scratch/wallpaper-optimization/issues/02-audio-and-image-size.md new file mode 100644 index 0000000..9cbc292 --- /dev/null +++ b/.scratch/wallpaper-optimization/issues/02-audio-and-image-size.md @@ -0,0 +1,24 @@ +# 02 体积:音频转码 + 未引用资源归位 + +Status: ready-for-agent + +## 现状 + +- `dist` 合计 105.1 MB,其中音频占 77.3 MB: + - `昔涟立绘/audios/「再度和你」.flac` 37.3 MB / 205.1 s / 1.52 Mbps + - `昔涟立绘/audios/昔涟.flac` 37.7 MB / 186.7 s / 1.69 Mbps(此前零引用,现已声明为第二音源) + - `「成为昨日的明天」/audios/pv37.mp3` 2.3 MB / 81 s +- CEF 的解码白名单含 vorbis / libopus / flac / mp3 / pcm_*(不含 aac,`m4a` 大概率不可用)。 + +## 步骤 + +1. 无损母带移出 `dist/`(另存工作区外的 `masters/`,不入库)。 +2. 两首 flac 转 Opus(`libopus`,约 96–128 kbps,目标每首 ≤4.5 MB):`ffmpeg -i in.flac -c:a libopus -b:a 112k out.ogg`。保留 `pv37.mp3` 原样。 +3. 用工具的音频波形/时长核对转码未截断。 +4. PNG → WebP **仅在对拍证明无可见差异后**逐张决定(atlas 页要整组一起转,并同步改 `.atlas` 里的页名)。 + +## 验收 + +- `dist` 总体积 ≤35 MB。 +- `check-paths` 全绿;本地 curl 确认转码后的音频能播放(时长一致)。 +- 每个比例的对拍像素无回归。 diff --git a/.scratch/wallpaper-optimization/issues/03-init-and-robustness.md b/.scratch/wallpaper-optimization/issues/03-init-and-robustness.md new file mode 100644 index 0000000..e52a1ba --- /dev/null +++ b/.scratch/wallpaper-optimization/issues/03-init-and-robustness.md @@ -0,0 +1,20 @@ +# 03 健壮性:初始化状态机、死代码、用户级覆盖语义 + +Status: ready-for-agent + +## 问题 + +1. **初始化竞态(已实证)**:`SpineController.changeConfig()` 整个函数体都在 `if (this.player)` 里, + 包括状态赋值。WE 可能在 `window.load` 之前就下发用户属性,此时预设被静默丢弃: + 同一份代码、同一份属性,`load` 之后下发得到 `animation`(kv37,正确), + `DOMContentLoaded` 时下发得到 `idle`(xilian)——背景与音乐已切到 kv37、立绘还是昔涟。 + 修法:**状态先写、应用后置**;`changeX()` 无条件更新状态,只在有 `player` 时应用,加载完成时统一应用一次。 +2. `index.js` 里有一段重复的 `window.wallpaperRegisterListener`(该 API 在本机 WE 不存在),是死代码。 +3. `SpineController.adjustCanvas()` 与播放器自身的 resize 重复,且用 `getBoundingClientRect()` 写 `canvas.width` 而未乘 DPR。 +4. 用户级覆盖语义:用户自定义了音源/音量后,切换预设不得把它清回预设默认值。 + +## 验收 + +- 把"属性在 `DOMContentLoaded` 下发"这一路作为回归断言:玩家实际使用的动画必须与所选预设一致。 +- 死代码与重复 resize 移除后,对拍仍无回归。 +- 同一份预设往返切换 20 次,用户自定义音源/音量保持不变。 diff --git a/.scratch/wallpaper-optimization/issues/04-aspect-adaptation.md b/.scratch/wallpaper-optimization/issues/04-aspect-adaptation.md new file mode 100644 index 0000000..4d7e0ca --- /dev/null +++ b/.scratch/wallpaper-optimization/issues/04-aspect-adaptation.md @@ -0,0 +1,20 @@ +# 04 比例适配:按容器比例重算视口 + +Status: ready-for-agent + +## 问题 + +viewport 以等比 "contain" 映射到画布:单轴贴边、另一轴多露出世界,因此现在的负 padding 只在目标比例下成立; +在超宽屏(3440×1440)或竖屏(1080×1920)下会露出多余的世界或裁掉主体。 + +## 步骤 + +1. 测出每档壁纸在 21:9 / 16:9 / 9:16 下的构图偏差(已有对拍矩阵)。 +2. 按容器宽高比在运行时重算 pad(视口是活对象:原地改 pad 后调用 `player.setViewport(当前动画名)` 即生效, + 整体替换 viewport 会丢 `viewport.animations` 并在 spine-player 第 14973 行崩溃)。 +3. 目标:主体完整、底部对齐、无空边。 + +## 验收 + +- 三种比例下都对拍留档,主体不被裁切、底部不悬空。 +- 切换窗口大小时不重建播放器(用 `setViewport`),连续 resize 无内存增长。 diff --git a/.scratch/wallpaper-optimization/issues/05-we-properties.md b/.scratch/wallpaper-optimization/issues/05-we-properties.md new file mode 100644 index 0000000..2b06bc6 --- /dev/null +++ b/.scratch/wallpaper-optimization/issues/05-we-properties.md @@ -0,0 +1,17 @@ +# 05 WE 属性扩展:音源 combo、fps 限制 + +Status: ready-for-agent + +## 内容 + +1. **音源(音源作用域已定)**:新增 `project.json` combo `bgm`,列表是所有壁纸音源声明的**并集**(WE 的 combo 是静态列表,只能手工同步); + 每档壁纸在自己 `preset.js` 的 `audioChoices` 里声明可选音源。切换壁纸时,若当前音源不属于新壁纸,回落"随预设"。 +2. **fps 限制**:`properties.fps` 经 `applyGeneralProperties` 下发,WE 不会替壁纸限流,需自行实现。 + 实现方式:包裹实例上的 `player.drawFrame`(循环用箭头闭包懒查,因此可以门控);注意 `config.frame/update/draw` + 都在下一帧排程之后运行,用它们限不了流。 +3. `setPaused` 暂不实现(WE 会整体冻结进程);除非用户在 WE 里实测发现音频仍在响。 + +## 验收 + +- combo 切音源即时生效,且切壁纸时的回落行为正确。 +- 设置 30/60 fps 时实际帧率符合,且不影响动画相位推进速度。 diff --git a/.scratch/wallpaper-optimization/issues/06-package-v3.md b/.scratch/wallpaper-optimization/issues/06-package-v3.md new file mode 100644 index 0000000..9b0b24d --- /dev/null +++ b/.scratch/wallpaper-optimization/issues/06-package-v3.md @@ -0,0 +1,10 @@ +# 06 打包 v3 并重新发布 + +Status: ready-for-agent + +## 步骤 + +1. `project.json`:`version` 升到 3,更新 `description`(提及新增音源切换等),核对 `properties` 与代码一致。 +2. `preview.gif` 现在 160×160 / 50 帧 / 840 KB——合规(≤256×256、≤1 MB)但超过推荐的 500 KB,重新压缩。 +3. 全量验收:0 死文件、≤35 MB、3 种比例 0 console 报错、预设往返不丢音源设置。 +4. 上传到 Workshop(人工步骤,需要用户操作)。 diff --git a/.scratch/wallpaper-optimization/spec.md b/.scratch/wallpaper-optimization/spec.md new file mode 100644 index 0000000..efa186f --- /dev/null +++ b/.scratch/wallpaper-optimization/spec.md @@ -0,0 +1,41 @@ +# 优化已发布的网页壁纸(workshopid 3604974793) + +在**不重写播放器**的前提下,就地优化现有 `dist/` 作品:资源分层、体积、健壮性、比例适配、属性扩展,最后重新打包发布 v3。 + +## 背景与约束(已确认) + +- 原样入库的基线是 commit `d8c7e49`(105.1 MB),期间不做"顺手重构"。 +- 已发布作品,`project.json` 里 combo 选项的 `value`(`xilian` / `kv37`)**不可改**,否则老用户已保存的预设选择会失效。 +- 音源与音量是**用户级覆盖**,切换预设不得清掉;接受有损音频,无损母带留在 dist 之外。 +- 图片转 WebP 只在 AB 对拍证明肉眼无差别后才做,否则保留 PNG。 +- 适配目标:任何比例下主体完整、底部对齐、无空边。 +- 验收:0 个死文件;总体积 ≤35 MB;3 种比例干净;0 个 console 报错;预设往返不丢音源设置;连续 20 次切换无内存增长。 + +## 决策记录 + +| 主题 | 决定 | 记录位置 | +| --- | --- | --- | +| 资源分层 | `assets/<游戏>/<壁纸>/{effects,images,audios}/`,每档壁纸自包含 | `docs/adr/0001-resource-layout.md` | +| 目录名 vs 键 | 目录名用显示名(含 `「」`),代码键用稳定 id | 同上 | +| 预设形式 | 每档壁纸一份 `preset.js`(ES module + `import.meta.url`) | `docs/adr/0002-preset-as-es-module.md` | +| 术语 | 一档壁纸(Wallpaper)= 用户可见选项;预设(Preset)= 它的配置实体 | `CONTEXT.md` | +| 音源作用域 | combo 列表为全局并集;切壁纸时若当前音源不属于新壁纸,回落"随预设" | 本 spec | + +## 验证台(后续每一步都用它) + +`tools/serve.mjs` 起本地服务并注入驱动(模拟 WE 下发用户属性、冻结动画相位、藏 canvas 取参考帧), +`tools/cdp.mjs` + `tools/shot.mjs` 走 CDP 真实时间截图,`tools/diff.mjs` / `compare.mjs` / `heatmap.mjs` 做像素差分, +`tools/check-paths.mjs` 静态校验预设里声明的每个路径是否存在。 + +判定标准:以"与基线逐像素完全相同的对数"和噪声底(约 0.1/255)为准;基线自身存在约 2.3/255 的双模态抖动,不能拿单次差异下结论。 + +## 步骤 + +| # | 步骤 | 状态 | +| --- | --- | --- | +| 01 | 资源按 游戏/壁纸 分层,预设拆进各自壁纸目录 | 完成(`09ff322`) | +| 02 | 体积:音频转码 + 未引用资源归位 | 待做 | +| 03 | 健壮性:初始化状态机、死代码、用户级覆盖语义 | 待做 | +| 04 | 比例适配:按容器比例重算视口 | 待做 | +| 05 | WE 属性扩展:音源 combo、fps 限制 | 待做 | +| 06 | 打包 v3 并重新发布 | 待做 |