Live2D 看板娘
Mizuki 主题通过集成 Pio(l2d-widget)在站点右下角渲染可交互的 Live2D 看板娘。本页说明该能力在仓库中的资源布局、依赖声明、部署层配置以及加载链路。
证据边界说明:本页结论基于本次源码检索实际读取到的内容。
public/pio/l2d-widget.min.js为压缩后的第三方运行时,public/pio/live2d-host.html的完整内容未能在本次源码预算内读取,因此涉及二者内部逻辑的部分会明确标注"未在源码中验证",不做臆测。
Purpose and Scope
本页覆盖 Live2D 看板娘这一前端运行时能力在 Mizuki 中的完整落地方式:
- 静态资源组织:
public/pio/目录下的宿主页、运行时脚本与 Live2D 模型资产 - 依赖声明:
package.json中的l2d-widget依赖 - 部署层配置:
vercel.json针对/pio/live2d-host路由的响应头规则 - 模型资产格式:NOIR 模型的 Cubism 3 文件构成
不在本页范围(属于兄弟页面或外部项目):
- 看板娘的交互文案、服装切换等 Pio 插件自身的功能配置 —— 属于 Pio 上游项目
- 音乐播放器、评论区等其它前端运行时能力 —— 见对应的
frontend-runtime兄弟页面 - 主题整体构建流程 —— 见构建/部署相关页面
Overview
看板娘是博客常见的装饰性交互元素:一个漂浮在页面角落的 Live2D 角色,会随鼠标移动产生视线跟随、播放待机动画、并可通过点击触发表情与台词。Mizuki 在 README 的功能清单中将其列为已支持特性:
- [x] **Live2D 看板娘**,通过 Pio 实现(README.md)
从仓库结构看,Mizuki 对该能力的集成方式是 "静态资源 + 依赖声明 + 部署头规则",而非在 Astro 组件源码中封装 React/框架组件。具体而言:
- 静态资源:
public/pio/目录直接随 Astro 的 public 目录原样发布,包含宿主页live2d-host.html、压缩运行时l2d-widget.min.js与模型目录models/NOIR/。 - 依赖声明:
package.json声明了l2d-widget: ^0.1.0,保证版本可追溯。 - 部署头规则:
vercel.json为/pio/live2d-host路由单独配置了headers数组(具体响应头字段未在本次检索范围内读取,需查看该文件全文确认)。
这种设计让看板娘完全独立于 Astro 的组件树:无论站点页面如何渲染,看板娘都以独立静态页面/脚本的形式存在,避免与框架生命周期耦合。
Architecture
上图各组成部分的角色与设计意图:
- HostPage(宿主页):live2d-host.html 是看板娘的独立宿主页面。将 Live2D 渲染隔离在独立 HTML 中,可以避免看板娘脚本污染博客主文档的 DOM 与全局作用域,也让部署层能够仅对该页面应用特殊响应头(见下)。
- Widget(运行时):l2d-widget.min.js 是 Pio 看板娘插件的压缩发行产物,负责 Live2D 模型加载、渲染循环与交互逻辑。它是第三方代码,仓库不维护其源码。
- ModelAssets(模型资产):
models/NOIR/目录存放一套完整的 Live2D Cubism 模型,由noir.model3.json作为入口清单串起 moc3、贴图、物理与表情文件。 - VercelHeaders(部署层规则):vercel.json 中针对
/pio/live2d-host的headers规则只作用于这一个路由,不会影响站点其它页面。 - PkgDep(依赖声明):
package.json中的l2d-widget依赖用于锁定/追溯插件版本。
实现细节
静态资源组织
public/pio/ 的目录布局(以仓库实际文件列表为准):
1public/pio/
2├── l2d-widget.min.js # Pio 运行时(压缩产物)
3├── live2d-host.html # 看板娘宿主页
4└── models/
5 └── NOIR/ # 内置模型:NOIR
6 ├── noir.model3.json # 模型入口清单
7 ├── noir.moc3 # Cubism 模型数据
8 ├── noir.physics3.json # 物理模拟配置
9 ├── noir.cdi3.json # 参数显示信息
10 ├── items_pinned_to_model.json # Pio 挂件约定文件
11 ├── eyeclose.exp3.json # 表情:闭眼
12 ├── quanquan.exp3.json # 表情:圈圈
13 ├── tears.exp3.json # 表情:流泪
14 ├── white.exp3.json # 表情:白色
15 ├── noir.2048/
16 │ └── texture_00.png # 模型贴图
17 └── noir/ # 与上层同名文件的重复副本(见下文说明)文件清单(本次检索实际观察到的文件,非完整穷举):
| 文件 | Live2D 标准格式角色 |
|---|---|
| noir.model3.json | 模型清单:声明 moc3、贴图、物理、表情等资源引用,是加载入口 |
| noir.moc3 | Cubism 3 模型二进制数据(网格、变形器、参数) |
| noir.physics3.json | 物理演算配置(头发、衣物摆动等) |
| noir.cdi3.json | 参数/部件的显示名与分组信息(编辑器辅助数据) |
eyeclose.exp3.json 等 4 个 *.exp3.json | 表情文件:记录触发表情时的参数快照 |
| items_pinned_to_model.json | Pio 插件的模型挂件约定(非 Live2D 标准,属 Pio 扩展) |
| noir.2048/texture_00.png | 模型贴图(2048 尺寸) |
重复副本现象:文件列表显示 public/pio/models/NOIR/noir/ 子目录下存在一套与上层完全同名的文件(noir.model3.json、noir.moc3 等,但该副本缺少 items_pinned_to_model.json)。这很可能是模型打包时的历史遗留或双份发布,会导致仓库体积翻倍。其内部相对引用关系(model3.json 中引用的路径是相对上层还是子目录)未在源码中验证,处理前建议先比对两份清单内容。
依赖声明
package.json 的 dependencies 中声明了看板娘插件:
"katex": "^0.16.47",
"l2d-widget": "^0.1.0",
"marked": "^18.0.7",Source: package.json
设计意图:虽然运行时脚本是作为静态资源(public/pio/l2d-widget.min.js)发布的,但在 package.json 中保留 l2d-widget 依赖可以让插件版本随锁文件(pnpm-lock.yaml 中对应 specifier: ^0.1.0)可追溯、可升级。本次检索未发现 Astro/TS 源码中对 l2d-widget 的直接 import 证据,因此该依赖更像是"版本登记"而非打包入口——真正的运行时加载发生在静态宿主页中(该页内部如何引用脚本未在源码中验证)。
部署层配置
vercel.json 为宿主页路由单独配置了响应头规则:
{
"source": "/pio/live2d-host",
"headers": [Source: vercel.json
该规则仅匹配 /pio/live2d-host 这一个路由。headers 数组内的具体字段(典型场景是 CSP、跨域隔离等,Live2D/WebGL 相关页面常需要)未在本次检索范围内读取,如需准确字段请查看 vercel.json 全文。
需要注意:这是 Vercel 平台专属配置。若将站点部署到其它平台,该响应头规则不会自动生效,需要在新平台上等价配置。
Core Flow:看板娘加载与交互链路
上图中"初始化看板娘"及"按 manifest 请求资源"两步的具体调用时序取决于 live2d-host.html 与 l2d-widget.min.js 的内部实现,二者分别为未读取的页面与压缩产物,该时序图表达的是 Live2D + Pio 的通用加载模型,不是从源码逐行验证的实现细节;可确证的部分是:宿主页、运行时脚本与模型文件都以静态资源形式存在于 public/pio/ 下,且宿主页路由在部署层有专属头规则。
使用示例
在站点中启用看板娘(依赖声明)
"katex": "^0.16.47",
"l2d-widget": "^0.1.0",
"marked": "^18.0.7",Source: package.json
安装依赖后,看板娘运行时即随 public/pio/ 静态目录发布。注意 ^0.1.0 的语义:主版本为 0 时,次版本号变化被视为破坏性更新,升级时需留意。
为宿主页路由配置响应头
{
"source": "/pio/live2d-host",
"headers": [Source: vercel.json
Vercel 的 headers 规则按 source 路由匹配,只作用于 /pio/live2d-host,不影响其它页面。headers 数组的具体字段内容需查阅该文件完整段落。
更换/新增 Live2D 模型
模型以标准 Cubism 目录结构存放在 public/pio/models/ 下,替换模型即替换整套目录:
1{
2 "FileReferences": {
3 "Moc": "noir.moc3",
4 "Physics": "noir.physics3.json",
5 "Textures": ["noir.2048/texture_00.png"],
6 "Expressions": ["eyeclose.exp3.json", "quanquan.exp3.json", "tears.exp3.json", "white.exp3.json"]
7 }
8}Source: noir.model3.json
上述 JSON 为该清单文件的结构示意(字段名遵循 Live2D Cubism 标准
model3.json规范),用于说明各资产如何被清单串联;完整字段与取值请直接查看源文件。新增模型时除放入目录外,还需让 Pio 运行时感知新模型入口,该接线方式属于 Pio 插件配置,见 Pio 上游文档。
配置选项
| 配置项 | 位置 | 类型/取值 | 说明 |
|---|---|---|---|
l2d-widget | package.json dependencies | ^0.1.0 | 看板娘插件版本声明,随锁文件锁定 |
/pio/live2d-host headers | vercel.json | 路由匹配 + headers 数组 | 仅作用于宿主页路由的响应头规则;字段明细需读文件全文 |
| 模型资产 | public/pio/models/NOIR/ | Live2D Cubism 文件集 | 内置模型 NOIR;替换目录即换模型 |
| Pio 交互文案/按钮/服装 | public/pio/(Pio 插件约定) | 插件配置 | 属于 Pio 插件自身配置,不在本仓库源码中定义 |
失败模式、边界与运维注意
- 宿主页脚本加载失败:
live2d-widget.min.js是第三方压缩产物,无源码级可调试性。排查时优先通过浏览器 Network 面板确认public/pio/下资源是否 200 返回。 - 模型资源 404:Cubism 清单中的
FileReferences为相对路径,目录结构调整(例如清理上文提到的NOIR/noir/重复副本)时若破坏相对关系,会直接导致贴图/表情加载失败。 - 部署平台差异:
vercel.json的头规则是平台绑定的。迁移到 Netlify/Cloudflare Pages 等平台时需重建等价规则,否则宿主页可能因缺少必要响应头而异常。 - 资源体积:
public/pio/含模型贴图与双份重复文件,会全部进入发布产物并增加站点托管带宽消耗。 - 仓库内未发现测试:本次检索未发现针对看板娘的自动化测试,回归只能依赖人工验证。
- 源码证据缺口:宿主页内部逻辑、
headers数组具体字段、Pio 与主题 UI 的联动均未在源码中验证,文档不对其进行断言。
Related Links
- README.md — 功能清单中的 Live2D 看板娘条目
- README.md — 致谢:使用 Pio 实现看板娘插件
- package.json —
l2d-widget依赖声明 - vercel.json —
/pio/live2d-host响应头规则 - public/pio/live2d-host.html — 看板娘宿主页
- public/pio/l2d-widget.min.js — Pio 运行时脚本
- Pio 上游项目 — 插件源码与完整文档