dsh-folia 2.0.2 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -61,7 +61,7 @@
61
61
 
62
62
  <table>
63
63
  <tr>
64
- <td width="36%" valign="middle">
64
+ <td width="64%" valign="middle">
65
65
  <ul>
66
66
  <li><a href="#能做什么">能做什么</a> · <a href="#支持哪些壁纸类型">支持哪些壁纸类型</a> · <a href="#安装">安装</a> · <a href="#使用">使用</a></li>
67
67
  <li><a href="#可选桌宠联动">可选桌宠联动</a> · <a href="#配置与数据">配置与数据</a> · <a href="#兼容与限制">兼容与限制</a> · <a href="#开发与贡献">开发与贡献</a></li>
@@ -73,14 +73,6 @@
73
73
  <img src="assets/readme/mascot-eating-rice-1280x1784.jpg" alt="吉祥物干饭插图">
74
74
  </a>
75
75
  </td>
76
- <td width="36%" align="center" valign="middle">
77
- <a href="assets/about/sponsor-fish.png">
78
- <img src="assets/about/sponsor-fish.png" alt="生鱼的赞赏码" width="320" height="320">
79
- </a>
80
- <br><strong>生鱼的赞赏码</strong>
81
- <br><sub>“大肥鱼的白饭告急,收到的赞赏将统统用于本插件的维护与更新”</sub>
82
- <br><sub>自愿赞赏 · 不影响安装与使用</sub>
83
- </td>
84
76
  </tr>
85
77
  </table>
86
78
 
@@ -322,20 +314,9 @@ macOS 没有 Wallpaper Engine 官方客户端。可以上传图片 / 视频,
322
314
 
323
315
  > npm 包不包含 `docs/`。上面的技术资料使用源码仓库地址、演示图使用 Release 资产地址(`media-v1`),避免在 npm 页面中出现无效的相对路径。
324
316
 
325
- <h2 id="联系方式"><picture><source media="(prefers-color-scheme: dark)" srcset="assets/readme/section-community-dark.png"><img src="assets/readme/section-community-light.png" alt="联系方式" width="1440"></picture></h2>
317
+ <h2 id="联系方式">联系方式</h2>
326
318
 
327
- 本分支安装与联动回归优先提交到 [维护仓库 Issues](https://github.com/Fish-under-sea/dsh-folia/issues);正式版本的共性问题提交到 [正式主仓 Issues](https://github.com/elysia395/dsh-folia/issues),方便追踪与复现。交流也可以加入以下群组;插件「关于」页使用同一份二维码。
328
-
329
- <p align="center">
330
- <a href="lib/about/qq-group.png"><img src="lib/about/qq-group.png" alt="QQ 群:FOLIAWALLPAPER | LLM 讨论群" width="260" height="259"></a>
331
- &nbsp;
332
- <a href="lib/about/douyin-group.png"><img src="lib/about/douyin-group.png" alt="抖音群:folia 交流 2 群" width="260" height="260"></a>
333
- </p>
334
-
335
- | 交流入口 | 群组 |
336
- |---|---|
337
- | QQ 群 | **FOLIAWALLPAPER \| LLM 讨论群** |
338
- | 抖音群 | **folia 交流 2 群**,群号 `917001335502` |
319
+ 本仓不提供交流群。安装、使用、bug 与功能建议统一走 [仓库 Issues](https://github.com/lehua-art/dsh-folia/issues)。
339
320
 
340
321
  <h2 id="致谢"><picture><source media="(prefers-color-scheme: dark)" srcset="assets/readme/section-credits-dark.png"><img src="assets/readme/section-credits-light.png" alt="致谢" width="1440"></picture></h2>
341
322
 
@@ -384,15 +365,11 @@ macOS 没有 Wallpaper Engine 官方客户端。可以上传图片 / 视频,
384
365
 
385
366
  README 首屏与分节横条的复古窗口视觉复刻自 [MaiBot](https://github.com/Mai-with-u/MaiBot),项目图标与菲比使用本仓原始素材,像素字体采用 Jersey 20。详细来源与授权见 [素材说明](assets/readme/SOURCES.md);未沿用对方的人物、统计数据或排名。
386
367
 
387
- <h2 id="支持与赞赏"><picture><source media="(prefers-color-scheme: dark)" srcset="assets/readme/section-support-dark.png"><img src="assets/readme/section-support-light.png" alt="支持与赞赏" width="1440"></picture></h2>
388
-
389
- 项目保持开源,赞赏完全自愿,**不影响安装、使用或问题反馈**。给仓库点 Star、提交可复现的 Issue、补充文档与参与测试,同样是在支持项目。
390
-
391
- **生鱼的赞赏码**:赞赏用于本插件的维护与更新。以下是生鱼个人的赞赏入口,不代表全部贡献者的收款账户。
392
-
393
- > “大肥鱼的白饭告急,收到的赞赏将统统用于本插件的维护与更新”
368
+ <h2 id="支持与赞赏">支持</h2>
394
369
 
395
- 赞赏码展示在 [目录](#目录) 右侧,点击图片可查看原图。感谢每一份支持。
370
+ 项目保持开源、完全免费,**没有赞赏入口** —— 本仓是上游 MIT 项目的二次开发,
371
+ 不代收任何款项。给仓库点一颗 Star、提交可复现的 Issue、补充文档或参与测试,
372
+ 就是最好的支持。
396
373
 
397
374
  <h2 id="star-history"><picture><source media="(prefers-color-scheme: dark)" srcset="assets/readme/section-stars-dark.png"><img src="assets/readme/section-stars-light.png" alt="Star History" width="1440"></picture></h2>
398
375
 
package/icon.png CHANGED
Binary file
Binary file
package/lib/client.js CHANGED
@@ -8,11 +8,10 @@ window.__ModuleLoader__.load({
8
8
  /**
9
9
  * about-assets.js — 「关于」页签与「更新公告」用到的**静态数据**(仓库地址 + 随包图的路径)。
10
10
  *
11
- * 二维码用随包 PNG(用户要求),**不内联 base64** —— 内联会把两张图压进 `lib/client.js`
12
- * (+240KB,每次冷启动随 bundle 一起解析),而它们与面板逻辑毫无关系。图是随包资源
13
- * `lib/about/*.png`,由宿主路由 `GET <BASE>/about-qr/<文件名>` 直出
14
- * (白名单 + ETag/304,见 packages/about-notice/lib/routes/about-qr.js);本文件只留**路径**,`<img src>` 经
15
- * `apiUrl()` 拼前缀,换码只要替换那两个 PNG,不必重建客户端产物。
11
+ * 本仓自有版本:**不再包含上游的交流群二维码与赞赏码**(QQ 群 / 抖音群 / 原作者收款码)。
12
+ * 「关于」页只剩项目简介 / Star / 贡献者致谢三节;联系方式指向仓库 Issues。
13
+ * 图片仍走 `lib/about/` + 白名单路由直出(理由见 lib/components/about-notice/routes/about-qr.js),
14
+ * 剩下的唯一一张是「更新公告」的配图。
16
15
  *
17
16
  * 契约(构建期由 scripts/build-client.mjs 内联进 bundle 的工厂作用域):纯数据、零依赖,
18
17
  * 必须保持浏览器安全(无 import / require / Node API)。
@@ -21,15 +20,7 @@ window.__ModuleLoader__.load({
21
20
  // 项目仓库(README / package.json 的同一条地址):关于页的按钮与可复制文本都用它。
22
21
  const ABOUT_REPO_URL = "https://github.com/lehua-art/dsh-folia";
23
22
 
24
- // 两张二维码的**路由路径**(相对 BASE,交给 apiUrl 拼前缀):
25
- // · QQ 群「FOLIAWALLPAPER | LLM 讨论群」 → lib/about/qq-group.png
26
- // · 抖音群「dsh 交流群」 → lib/about/douyin-group.png
27
- // 文件名与 packages/about-notice/lib/routes/about-qr.js 的白名单**逐字相同**(守卫两边对账)。
28
- const ABOUT_QR_QQ_PATH = "/about-qr/qq-group.png";
29
- const ABOUT_QR_DOUYIN_PATH = "/about-qr/douyin-group.png";
30
-
31
- // 「更新公告」一次弹窗的配图(v1.3.0 起:GitHub 求星插画,JPEG 720×720):
32
- // · 派生自 assets/about/update-notice-star-1254x1254.png(缩到 720px、JPEG q88)
23
+ // 「更新公告」一次弹窗的配图(JPEG 720×720,本仓自有素材):
33
24
  // · 随包发布 lib/about/update-notice.jpg,由 /about-qr 路由族直出(同一白名单)
34
25
  // · 版本换图 = 替换 lib/about/update-notice.jpg 的字节,路径与产物都不动(ETag 会变)。
35
26
  const NOTICE_ART_PATH = "/about-qr/update-notice.jpg";
@@ -16103,138 +16094,15 @@ window.__ModuleLoader__.load({
16103
16094
  //("要什么"写在签名处),所以这里显式解构出那一个回调。
16104
16095
  // 四段的**顺序**是用户的明确口径(致谢压尾),判据按首次出现下标比大小钉住。
16105
16096
  function renderAboutTab(ctx) {
16106
- const { onReopenNotice } = ctx;
16107
- // ── D3 可见面 gate(ADR-0013 D3①/D3③):该组件行关掉 ⇒ **整块不渲染**(返回 null,
16108
- // 界面不显示;配置项由调用方按同一判据隐藏)。判据:test/verify-component-visibility.mjs
16109
- // 的"声明落点必须被 gate"双向对账。唯一实现在 src/client.js 的 weComponentVisible。
16097
+ // 本仓自有版本:**「关于」页签保留,内容清空**(用户口径)。
16098
+ // 不再显示项目简介 / Star / 贡献者致谢,也不再带上游的交流群二维码与赞赏码 ——
16099
+ // 这一页只作为"存在一个关于页签"的占位,点进去是空白。
16100
+ //
16101
+ // 组件可见性门仍保留:关掉 about-notice 组件行时,这一页签照旧整块不渲染
16102
+ //(判据仍是 test/verify-component-visibility.mjs 的"声明落点必须被 gate")。
16110
16103
  if (!weComponentVisibleOf(ctx.sel && ctx.sel.inventory && ctx.sel.inventory.components, 'about-notice')) return null;
16111
- // star 数那一行(模块级:值 + 三态文案都在 client.js 的 starCountLabel 里;
16112
- // 这里的"读"与 SliderRow 一类模块级助手同口径 —— 只读,不发请求)。
16113
- const stars = starCountLabel();
16114
- // 两张码的参数表:图(路由 URL)/ 图题 / 替代文本 / 一句话说明。渲染一次 map 两遍,
16115
- // 免得两段几乎一样的 createElement 各自演化(改一处忘一处正是这类页面最容易烂的地方)。
16116
- const qrCards = [
16117
- {
16118
- key: "qq",
16119
- title: weT("🐧 QQ 群 · FOLIAWALLPAPER | LLM 讨论群"),
16120
- // 图本体是随包 PNG(lib/about/),这里只给路径 —— apiUrl 补 BASE 前缀。
16121
- src: apiUrl(ABOUT_QR_QQ_PATH),
16122
- alt: weT("QQ 群二维码"),
16123
- hint: weT("手机 QQ 扫码加入 · 群里见 👋"),
16124
- },
16125
- {
16126
- key: "douyin",
16127
- title: weT("🎵 抖音群 · dsh 交流群"),
16128
- src: apiUrl(ABOUT_QR_DOUYIN_PATH),
16129
- alt: weT("抖音群二维码"),
16130
- hint: weT("抖音扫码加入 · 群号 252729465001"),
16131
- },
16132
- ];
16133
- // 贡献者致谢逐条列出(名字 / 做了什么)——「谢谢」要能落到具体的人身上,
16134
- // 一句笼统的"感谢所有贡献者"没有信息量。
16135
- const credits = [
16136
- weT("🧩 oneincase —— 内置 WebWallGL 实时渲染引擎与 media-bridge 媒体中间件的作者:场景 / 网页壁纸的实时渲染,以及 Windows / macOS / Linux 三平台的原生媒体链路,都建立在它们之上"),
16137
- weT("🛠️ YV3507 —— 提交量最大的贡献者:从早期场景渲染器起步,到静态帧系列修复、液态玻璃令牌体系、实时帧链路与多轮大型重构,几乎每个里程碑都有他"),
16138
- weT("🎨 yuxilao —— scene-gl 的 Linux 实时渲染管线(WebGL2 官方 shader 驱动)、轮换交接与 GPU 帧回填"),
16139
- weT("🍎 Jerry —— 在三平台原生支持落地之前,macOS 侧的适配与贡献路径由他维护"),
16140
- weT("🌟 还有 SiriLee、libiwolve、0-007pro、jujubaoj646-star、xiahou001、wilianyichen、hecoococ、ShamSky88、Rekk0、Y1X1n 等贡献者,以及所有通过 issue 反馈与 PR 参与改进的朋友 —— 谢谢你们!"),
16141
- ];
16142
- return React.createElement(React.Fragment, null,
16143
- // ── ① 项目简介 ──
16144
- React.createElement("div", { className: "we-picker__section" },
16145
- React.createElement("div", { className: "we-picker__section-head" },
16146
- React.createElement("span", { className: "we-picker__section-label" }, weT("📖 项目简介")),
16147
- ),
16148
- React.createElement("div", { className: "we-about__lead" },
16149
- React.createElement("div", { className: "we-about__lead-title" }, weT("🖼️ 壁纸引擎 · 让 DSH 的背后动起来")),
16150
- React.createElement("p", { className: "we-about__p" },
16151
- weT("把 Wallpaper Engine 的壁纸搬到 DSH 界面后面:视频直接播放,场景(Scene)与网页(Web)壁纸由内置的 WebWallGL 引擎实时渲染,再配上一整套液态玻璃界面改造 —— 你桌面上那张会动的画,现在就在对话背后放着。🎬✨")),
16152
- React.createElement("p", { className: "we-about__p" },
16153
- weT("壁纸全部来自你自己的机器(本机库 / WE 工程目录 / 手动上传),插件不联网也能用,更不会把它们传到任何地方。🔒")),
16154
- ),
16155
- ),
16156
- // ── ② 仓库与 Star ──
16157
- React.createElement("div", { className: "we-picker__section" },
16158
- React.createElement("div", { className: "we-picker__section-head" },
16159
- React.createElement("span", { className: "we-picker__section-label" }, weT("⭐ 开源与支持")),
16160
- ),
16161
- React.createElement("p", { className: "we-about__p" },
16162
- weT("项目以 MIT 协议开源、完全免费。如果它让你的 DSH 好看了一点点,去仓库点一颗 ⭐ 就是最直接的鼓励~")),
16163
- React.createElement("div", { className: "we-about__star-row" },
16164
- React.createElement("a", {
16165
- className: "we-picker__btn we-picker__btn--primary we-about__star",
16166
- href: ABOUT_REPO_URL,
16167
- target: "_blank",
16168
- rel: "noopener noreferrer",
16169
- title: weT("在浏览器里打开项目仓库"),
16170
- }, weT("⭐ 去 GitHub 点亮 Star")),
16171
- // 实时 star 数:宿主代取(带缓存,见 packages/about-notice/lib/routes/github-stars.js)。
16172
- // 取不到时**整行不消失**、改说"暂时取不到" —— 数字是点缀,按钮才是主操作。
16173
- stars
16174
- ? React.createElement("span", {
16175
- className: "we-about__stars",
16176
- title: weT("来自 GitHub API 的实时数据(带缓存;拉不到时显示上一次取到的值)"),
16177
- }, stars)
16178
- : null,
16179
- ),
16180
- React.createElement("div", { className: "we-about__url-row" },
16181
- React.createElement("span", { className: "we-picker__hint" }, weT("🔗 仓库地址(按钮打不开时可手动复制):")),
16182
- // 可选中、可整段复制的裸地址:桌面壳里外链能否唤起浏览器不由插件说了算,
16183
- // 这条是给"点了没反应"的场景留的兜底(同字体集导出的"普通链接"口径)。
16184
- React.createElement("code", { className: "we-about__url" }, ABOUT_REPO_URL),
16185
- ),
16186
- // 「重新查看本版更新公告」:公告的哨兵 `noticeSeen` 让它**一版只弹一次** ⇒ 不给一条
16187
- // 重看路径的话,用户"想再看这版改了什么"就只能去改设置文件。
16188
- // ⚠️ 只调回调(`ctx.onReopenNotice`):状态写入与 emit 都在 client.js 那一侧 ——
16189
- // 本渲染器因此保持"只读模块级状态"(判据见文件头那段说明)。
16190
- // 与上面那枚 Star 按钮**同放一节**是有意的:它们是同一件事的两个面(公告配图下那行
16191
- // 也是同一个求星入口,见 src/client.js 的 UpdateNotice)。
16192
- React.createElement("button", {
16193
- className: "we-picker__btn we-about__reopen", type: "button",
16194
- onClick: () => { if (typeof onReopenNotice === "function") onReopenNotice(); },
16195
- title: weT("再弹一次本版更新公告(含配图下方的求星入口)"),
16196
- }, weT("重新查看本版更新公告")),
16197
- React.createElement("p", { className: "we-about__p" },
16198
- weT("想要新功能、遇到问题,或者想看看接下来要做什么,都欢迎来仓库提 Issue / PR —— 一起把它做得更好 🧰")),
16199
- ),
16200
- // ── ③ 交流群(两张二维码)──
16201
- React.createElement("div", { className: "we-picker__section" },
16202
- React.createElement("div", { className: "we-picker__section-head" },
16203
- React.createElement("span", { className: "we-picker__section-label" }, weT("💬 加入交流群")),
16204
- ),
16205
- React.createElement("p", { className: "we-about__p" },
16206
- weT("卡住了、想吐槽、或者想第一时间拿到新版本,都欢迎来群里找我们 👋")),
16207
- React.createElement("div", { className: "we-about__qr-row" },
16208
- qrCards.map((c) => React.createElement("figure", { key: c.key, className: "we-about__qr" },
16209
- React.createElement("figcaption", { className: "we-about__qr-title" }, c.title),
16210
- React.createElement("img", {
16211
- className: "we-about__qr-img",
16212
- src: c.src,
16213
- alt: c.alt,
16214
- draggable: false,
16215
- }),
16216
- React.createElement("figcaption", { className: "we-about__qr-hint" }, c.hint),
16217
- )),
16218
- ),
16219
- ),
16220
- // ── ④ 贡献者致谢(**压尾**:用户口径——先讲清"这是什么、去哪支持、怎么找我们",
16221
- // 最后再把功劳簿摆出来。💌 那句收尾也并进这一段,页面结束在"谢谢"上。)──
16222
- React.createElement("div", { className: "we-picker__section" },
16223
- React.createElement("div", { className: "we-picker__section-head" },
16224
- React.createElement("span", { className: "we-picker__section-label" }, weT("🙏 贡献者致谢")),
16225
- ),
16226
- React.createElement("p", { className: "we-about__p" }, weT("这个插件是许多人一起做出来的成果,谢谢他们:❤️")),
16227
- React.createElement("ul", { className: "we-about__credits" },
16228
- credits.map((line, i) => React.createElement("li", { key: "credit-" + i, className: "we-about__credit" }, line)),
16229
- ),
16230
- React.createElement("p", { className: "we-about__p" }, weT("也谢谢上游 Wallpaper Engine 生态与 DSH 官方插件的作者们 —— 站在你们的肩膀上。🙇")),
16231
- React.createElement("p", { className: "we-about__p we-about__foot" },
16232
- weT("💌 感谢每一位使用者 —— 换上你喜欢的那张壁纸,这个插件就没白写。")),
16233
- ),
16234
- );
16104
+ return null;
16235
16105
  }
16236
-
16237
-
16238
16106
  // ── 页签级重置(issue #192 用户口径:「每个选项卡后面加重置,重置指定选项卡」)──────────
16239
16107
  // 压在**每个页签内容的最末尾**,由 client.js 的渲染点在 renderActiveTab() 之后统一挂 ——
16240
16108
  // 六处渲染器各挂一遍必然漏一个,挂一处才是结构性的。
@@ -30,10 +30,13 @@ import { resolve, relative, isAbsolute } from 'node:path';
30
30
 
31
31
  /**
32
32
  * 白名单:URL 段 → 文件名。**唯一**把请求映射到磁盘的地方。
33
- * 名字用 `String` 的精确比较(`===`),不看前缀/后缀 —— 于是 `qq-group.png.bak`、
34
- * `./qq-group.png`、`qq-group.png/` 之类都过不了。
33
+ * 名字用 `String` 的精确比较(`===`),不看前缀/后缀 —— 于是 `update-notice.jpg.bak`、
34
+ * `./update-notice.jpg`、`update-notice.jpg/` 之类都过不了。
35
+ *
36
+ * 本仓自有版本只保留「更新公告」配图:上游那两张交流群二维码(qq-group / douyin-group)
37
+ * 已连同文件一起删除 —— 那是原作者的社群,不该随我们的包分发。
35
38
  */
36
- const ABOUT_QR_FILES = ['qq-group.png', 'douyin-group.png', 'update-notice.jpg'];
39
+ const ABOUT_QR_FILES = ['update-notice.jpg'];
37
40
 
38
41
  /**
39
42
  * 命中白名单返回绝对路径(含目录包含性复查),否则 null。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-folia",
3
- "version": "2.0.2",
3
+ "version": "2.2.0",
4
4
  "description": "Folia 壁纸引擎:把本机 Wallpaper Engine 壁纸搬进 DSH 界面(场景实时渲染 / 视频 / 网页),内置液态玻璃与 Folia 吉祥物,并可从自建站点拉取壁纸。单包形态(组件已合并)。",
5
5
  "type": "module",
6
6
  "engines": {
@@ -150,7 +150,6 @@
150
150
  "assets/readme/section-stars-dark.png",
151
151
  "assets/readme/SOURCES.md",
152
152
  "assets/readme/OFL-Jersey20.txt",
153
- "assets/about/sponsor-fish.png",
154
153
  "assets/readme/mascot-eating-rice-1280x1784.jpg",
155
154
  "README.md",
156
155
  "README.en.md",
@@ -1,89 +0,0 @@
1
- # 「关于」页签的联系方式二维码 + 更新公告配图(源资产)
2
-
3
- 本目录归档设置页**「关于」页签**里两张联系方式二维码的**原始截图**,以及「更新公告」弹窗
4
- 配图的**原始插画**。与 `assets/mascot/` 同一口径:它们是**源资产**,不是运行时载荷。
5
-
6
- - 运行时用的是这两张图**裁到码区**的派生版本,落在 **`lib/about/*.png`**(随包发布),由插件路由
7
- `GET <BASE>/about-qr/<文件名>` 直出(白名单 + ETag/304,见 `packages/about-notice/lib/routes/about-qr.js`);
8
- 客户端只存路径(`src/about-assets.js`)。2026-10-01 之前那版把派生图**内联 base64** 进客户端
9
- bundle,用户要求改成 PNG 引入 —— bundle 因此省下约 240KB,换码也不必重建产物。
10
- - 因此**本目录**(源资产)**不进 npm 包**(不在 `package.json` 的 `files` 白名单内),只随仓库源码分发;
11
- 派生产物 `lib/about/` 进包(`verify-package-files` 盯着)。
12
-
13
- ## 文件与用途
14
-
15
- | 文件 | 尺寸 | 用途 |
16
- |---|---|---|
17
- | `qq-group-folia-llm-702x852.png` | 702×852 | **QQ 群「FOLIAWALLPAPER \| LLM 讨论群」** 群二维码(含图内标题)。对应 `lib/about/qq-group.png` / `ABOUT_QR_QQ_PATH` |
18
- | `douyin-group-folia-2-748x748.png` | 748×748 | **抖音群「folia 交流 2 群」**(群号 917001335502)二维码(含图内群名与群号)。对应 `lib/about/douyin-group.png` / `ABOUT_QR_DOUYIN_PATH`。2026-10-10 换码:旧码 `douyin-group-dsh-1044x1026.png`(「dsh 交流群」,群号 252729465001)已退役 |
19
- | `update-notice-star-1254x1254.png` | 1254×1254 | **v1.3.0 更新公告配图**「求个 star 喵!」GitHub 求星插画(原图)。对应 `lib/about/update-notice.jpg` / `NOTICE_ART_PATH`(缩到 720px + JPEG q88,Pillow LANCZOS) |
20
-
21
- > **派生版只取"码"那块**(裁掉图内的标题带 / 群名 / 群号),因为这些文字在页面里由**卡片自己的
22
- > 标题与说明行**承担(重复两遍没有信息量),而裁掉之后两张码在面板里**尺寸一致、并排对齐**、
23
- > 码点也更大更好扫。裁剪框(含 36px 留白)见下面的派生脚本注释。
24
-
25
- ## 替换素材时怎么重新生成派生版本
26
-
27
- 1. 把新二维码存成 PNG 放到本目录(原始尺寸留着,便于日后重新派生)。
28
- 2. 派生:缩到**宽 520px**(等比),转**128 色调色板** PNG(quantize + optimize)——
29
- 码点仍足够清晰(QQ 码约 9 px/模块),而体积只有原图的 1/4 左右。
30
- 3. 把派生 PNG 覆盖到 **`lib/about/`**(文件名固定:`qq-group.png` / `douyin-group.png`),
31
- **不需要重建客户端产物** —— 客户端只存路径;README 引用的也是这两张(中英两份同步显示新码)。
32
-
33
- 参考命令(本机 `Pillow`;换尺寸 / 色数只改这两个参数):
34
-
35
- ```python
36
- from PIL import Image
37
- import base64, io
38
- # 裁剪框 = 码的内容 bbox(含 36px 留白);两张图各自的框见下面的常量。
39
- BOXES = {
40
- "qq-group-folia-llm-702x852.png": (63, 249, 634, 819), # 标题带 / 分隔线之下
41
- "douyin-group-folia-2-748x748.png": (185, 116, 567, 497), # 群名 / 群号文字之上
42
- }
43
- MARGIN, W, COLORS = 36, 520, 128
44
-
45
- def derive(path):
46
- im = Image.open(path).convert("RGB")
47
- x0, y0, x1, y1 = BOXES[path.split("/")[-1]]
48
- im = im.crop((max(0, x0 - MARGIN), max(0, y0 - MARGIN),
49
- min(im.width, x1 + MARGIN), min(im.height, y1 + MARGIN)))
50
- im = im.resize((W, round(im.height * W / im.width)), Image.LANCZOS)
51
- im = im.convert("P", palette=Image.ADAPTIVE, colors=COLORS)
52
- buf = io.BytesIO(); im.save(buf, "PNG", optimize=True)
53
- return "data:image/png;base64," + base64.b64encode(buf.getvalue()).decode()
54
- ```
55
-
56
- (bbox 由一次性的内容扫描得到:行 / 列方向上都统计"非近白"像素,取 ≥3 像素的区间端点。
57
- 派生结果直接写进 `lib/about/` —— **不要再转 base64 内联**。)
58
-
59
- ## 派生版怎么验证(两档,都做过)
60
-
61
- 1. **结构保真**:把派生图上采样回裁剪框分辨率、与裁剪后的原图逐像素比 —— 两图平均通道差
62
- `0.90 / 0.72`(满量程 255)、99 分位差 `9 / 8`、按墨色二值化后一致率 `99.30% / 99.75%`。
63
- 2. **真解码**:会用 macOS Vision(`VNDetectBarcodesRequest`,见下面的自检命令)对**派生版**扫码。
64
- **实测:QQ 码解出 `https://qm.qq.com/q/yxDL6BdsFW`**;抖音那种"点划 + 渐变 + 中心头像"的
65
- 装饰码连**原图**都解不出来(Vision 认不了这一型),所以它的验证只到第 1 档 ——
66
- **换抖音码时请务必用手机真机扫一次**再提交。
67
-
68
- ```bash
69
- # ① 扫的就是插件运行时直出的那两份字节(lib/about/ 下的 PNG)
70
- # ② 用 Vision 扫(一行一个文件;本命令就是上面第 2 档验证用的)
71
- cat > /tmp/qrdecode.swift <<'SWIFT'
72
- import Foundation; import Vision; import AppKit
73
- for path in CommandLine.arguments.dropFirst() {
74
- guard let i = NSImage(contentsOfFile: path), let t = i.tiffRepresentation,
75
- let r = NSBitmapImageRep(data: t), let cg = r.cgImage else { continue }
76
- let req = VNDetectBarcodesRequest(); req.symbologies = [.qr]
77
- try? VNImageRequestHandler(cgImage: cg, options: [:]).perform([req])
78
- print(path, (req.results ?? []).compactMap { $0.payloadStringValue })
79
- }
80
- SWIFT
81
- swiftc -O /tmp/qrdecode.swift -o /tmp/qrdecode && /tmp/qrdecode lib/about/qq-group.png lib/about/douyin-group.png
82
- ```
83
-
84
- ## 公告配图(update-notice-star-1254x1254.png)的派生口径
85
-
86
- 跟二维码不是一回事:整图**无裁剪**,Pillow LANCZOS 缩到 **720×720**,存 **JPEG q88**
87
- (progressive + optimize,约 146KB;PNG 同尺寸要 753KB)。派生覆盖 `lib/about/update-notice.jpg`
88
- —— 路径与客户端产物都不动(`/about-qr` 路由带 ETag/304,换图即生效)。下个版本换公告图时:
89
- 新图存本目录(原始尺寸留着),按同口径重派生覆盖即可,白名单与客户端不用改。
Binary file
@@ -1,28 +0,0 @@
1
- # 联系方式二维码 + 公告配图(随包发布的运行时资源)
2
-
3
- 「关于」页签里那两张二维码与「更新公告」配图的**运行时字节**。与本目录并列的 `lib/fontsets/`(随包预设)、
4
- `lib/webwallgl/`(随包渲染页)同一口径:**随包发布、由插件自己的路由提供**。
5
-
6
- - 提供方:`packages/about-notice/lib/routes/about-qr.js`(`GET/HEAD <BASE>/about-qr/<文件名>`,白名单 + ETag/304)。
7
- 客户端只存路径(`src/about-assets.js`),`<img src>` 直接指过来。
8
- - **为什么不用内联 base64**:那版把两张图压进 `lib/client.js`(+240KB,每次冷启动都要解析这串
9
- 字符),而它们与面板逻辑毫无关系 —— 拆成静态文件后 bundle 回到原大小,换码也只需要替换这里的
10
- PNG(不必重建客户端产物)。
11
- - 本目录**进 npm 包**(`package.json` 的 `files` 里 `lib/about/`;`verify-package-files` 盯这件事)。
12
- **源资产**(未裁剪的原始截图)在仓库的 `assets/about/`,那一份**不进包**。
13
- - **README 也引用这两张图**(中英两份的联系方式段)——展示的就是插件里真用的同一份字节,
14
- 不另存副本。
15
-
16
- ## 这两张图是什么
17
-
18
- | 文件 | 内容 | 派生自 |
19
- |---|---|---|
20
- | `qq-group.png` | QQ 群「FOLIAWALLPAPER \| LLM 讨论群」二维码(520×517) | `assets/about/qq-group-folia-llm-702x852.png` |
21
- | `douyin-group.png` | 抖音群「folia 交流 2 群」(群号 917001335502)二维码(520×519) | `assets/about/douyin-group-folia-2-748x748.png` |
22
- | `update-notice.jpg` | v1.3.0 更新公告配图「求个 star 喵!」GitHub 求星插画(720×720) | `assets/about/update-notice-star-1254x1254.png` |
23
-
24
- 派生口径(只取码区 + 缩到 520px 宽 + 128 色调色板)与验证方式(逐像素比对 + macOS Vision 扫码)
25
- 见 [`assets/about/README.md`](../../assets/about/README.md) —— 那里是**怎么生成**,这里是**发布什么**。
26
- 公告配图另有自己的口径(原图 1254² 缩到 720px、JPEG q88),客户端路径常量 `NOTICE_ART_PATH`
27
- (`src/about-assets.js`)与路由白名单逐字对账(`verify-about` 盯着)—— 下个版本换公告图时替换
28
- 本文件字节即可,路径与客户端产物都不动。
Binary file
Binary file