Files
SpineWallpaper/.scratch/build-pipeline/issues/08-static-preview-and-edge-panel.md
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.0 KiB
Raw Permalink Blame History

08 — 面板改为右边缘滑出,并让它能在静态托管上工作

Status: resolved Type: task

需求(用户原话)

模拟的壁纸测试面板是在鼠标移至页面右侧边缘时弹出的,且并不能仅有调试服提供,未来上传 GitHub 是 pages 预览也需要能够弹出壁纸设置面板

两件事:

  1. 面板的打开方式是鼠标移到页面右侧边缘——不是常驻按钮。
  2. 面板不能只有调试服能给。未来上 GitHub Pages 的预览也要能弹出设置面板。

① 交互:右边缘滑出

原来的实现是右上角一个常驻的「WE 模拟器」按钮。改成 16px 右边缘热区 + 全高抽屉,与 player 配置页同一套约定:

行为 结果
指针进入右边缘 16px 面板滑出
指针离开面板/边缘 自动收回
点 × 收起 收起,且必须先离开边缘才会再次自动滑出
点热区 开合(触屏没有 hover,点击是兜底)

#wesim-edge 里的把手只是"这里能滑出东西"的可见提示,pointer-events: none,不参与命中。

踩的坑:不能用 mouseenter / mouseleave 判定

第一版用 edge.mouseenter 打开、root.mouseleave 收回。测试立刻发现"指针离开 → 自动收回"永远是 data-open=1。

原因:面板是用 transform 从右侧滑进来的,出现时指针已经在它下面,浏览器不会为它补发 mouseenter——于是 root 从来没被标记为 hover,它后面的 mouseleave 自然也不会来。

改成在 mousemove 里按坐标判定,结果只取决于指针位置,与浏览器是否补发事件无关:

const nearEdge = event.clientX >= window.innerWidth - EDGE_WIDTH;
const overPanel = opened && event.clientX >= window.innerWidth - PANEL_WIDTH;

PANEL_WIDTH / EDGE_WIDTH 与 CSS 共用同一组常量(CSS 里用模板插值),避免"改了一处忘了另一处"。

armed 是"× 收起后需先离开边缘"那条规则的状态位。没有它,点 × 之后指针仍在热区里,下一次 mousemove 就把面板弹回来,表现为"× 根本关不掉"。

② 静态托管:把注入写进 index.html

场景 谁注入 模拟器本体从哪来 产物
pnpm dev 调试服按路由注入 调试服自己的 /simulator/wallpaper-engine.js 分发目录保持干净
静态托管(Pages) 构建期写进 index.html 分发自带的 ./scripts/wallpaper-engine.js pnpm build --with-sim
上传 Wallpaper Engine 没有人注入 不存在 pnpm build(默认)

要点:

  • 静态地址必须相对(./scripts/...)。Pages 把站点放在 /<repo>/ 子路径下,根绝对路径会 404。
  • 驱动带幂等闸 window.__weSimDriver:--with-sim 构建的分发自带驱动,调试服又会注入一次,没有闸就会 mount 两遍、出现两个面板。
  • 默认产物里既没有模拟器文件,也没有任何注入痕迹——它必须与用户从创意工坊下载到的东西完全一致(ADR 0006 第 1 条)。

验证

tools/checks/verify-static-preview.mts:刻意把分发挂在 /repo/ 前缀后面服务,而不是挂在根上——挂根上测不出相对路径的错。断言分三组:

  • 静态托管下 window.__weSim 存在、#wesim 与 #wesim-edge 已挂载、没有常驻按钮、横幅在、壁纸本身也渲染
  • 右边缘滑出六态:初始收起 → 滑出 → 离开收回 → 再滑出 → × 收起不被弹回 → 离开边缘后重新可触发
  • 静态服务器 0 个 404、0 异常、0 控制台报错

四档分发全部通过。另有 tools/checks/smoke-sim.mts 的"面板恰好一个"断言守住双重注入。

顺带发现

  • 合集那两档的自包含包是 128.7 MB,超过 GitHub 单文件 100 MB 上限。所以 Pages 只能走"分发目录 + 构建期注入"这条路,不能直接发布 sim/index.html。
  • src/vendor/spine-player.js.bak 是内联守卫测试留下的残留,已删。