给博客加了个看板娘:Live2D 接入与本地化

静态博客最容易变成「只有文字的空房子」。这次改版顺手给它请了个看板娘:左下角站着一个 Live2D 角色,会跟着鼠标看,偶尔冒两句提示。

选哪个方案

GitHub 上能直接用的方案不多,主要就这三个:

方案形态优点顾虑
stevenjoezhang/live2d-widget一段 autoload.js + JSON 配置最经典,生态大,提示语可完全自定义依赖 jQuery,依赖外部模型 CDN
oh-my-live2dnpm 包 / CDN 全局对象开箱即用,内置 Cubism 2 与 5 运行时默认模型 CDN 已经不可用
l2d-widgetnpm 包 / 单文件 IIFE轻量、零依赖、API 干净,是上面那个的重写版比较新,文档偏少

最后选了 oh-my-live2d:它同时内置 Cubism 2 与 Cubism 5 两套运行时,调用只需要一次 loadOml2d(),提示语、菜单、切模型这些全都自带。唯一要自己补的是官方的 live2dcubismcore.min.js,一起丢进仓库就行,不依赖任何第三方 CDN。

为什么把模型放到本地

大部分教程都是这么写的:

1
2
3
OML2D.loadOml2d({
models: [{ path: 'https://model.oml2d.com/xxx/model.json' }]
});

问题在于,这个模型 CDN 现在打不开,域名返回的已经是一个完全无关的页面。也就是说,照抄教程大概率得到一片空白 + 一堆 404。

所以我把运行时和模型都搬进了仓库:

1
2
3
4
5
6
js/live2d/
├── cubismcore.min.js # 官方 Cubism Core(自托管)
├── oml2d.min.js # oh-my-live2d 运行时(MIT)
├── init.js # 初始化与提示语配置
└── models/
└── ds-whale-girl/ # DS鲸鱼娘:moc3 + 贴图 + 8 组动作 + 44 个表情

算上运行时和模型一共 5.4MB,全部走 GitHub Pages 自己的带宽,不再受任何第三方 CDN 的脸色。

初始化脚本

初始化放在 init.js 里,核心就十几行:

1
2
3
4
5
6
7
8
9
10
11
12
window.oml2d = OML2D.loadOml2d({
dockedPosition: 'left',
mobileDisplay: false,
primaryColor: '#425aef',
models: [{
path: '/js/live2d/models/ds-whale-girl/c_0120.model3.json',
scale: 0.12,
position: [0, 40],
stageStyle: { height: 420 }
}],
tips: { idleTips: { wordTheDay: false, message: ['菜就多练,输不起就别玩。'] } }
});

传数组就会自动出现「切换模型」按钮;这次只放了一个模型,所以菜单里只有截图、信息和隐藏。提示语用中文写了几条,其中一部分是给自己看的提醒——毕竟写代码的时候真的需要有人催一句「备份做了吗」。

和 pjax 的相处方式

这个主题开了 pjax:点链接时不刷新整页,只替换 #body-wrap。看板娘的 DOM 是挂在 body 上的,在 #body-wrap 之外,所以页面切换时它不会被销毁,也不会重复创建——这一点比想象中省事。

真正需要注意的是脚本本身:init.js 里加了 window.__l2dBooted 去重,防止缓存或二次注入导致出现两个角色。

踩坑:Cubism 版本

中间绕了一次远路:一开始用的是 l2d-widget,它单文件、零依赖,看起来最省事。结果发现它内置的 Cubism 4/5 内核是坏的——加载 .moc3 模型时会在内核里崩掉(控制台报 … is not a function),loaded 事件永远不触发,界面就一直卡在「正在加载」。

换官方 Cubism Core 也不行:核心是 5.x,它内置的框架是 4.x 的,API 对不上,报 Cannot read properties of undefined (reading ‘byteLength’)。结论是这个运行时实际上只能跑 Cubism 2 的老模型(model.json + .moc),而现在的模型基本都是 Cubism 4/5 的 model3.json + .moc3。

所以最后换成 oh-my-live2d + 官方 Core,一次就跑通了。判断方法很简单:看模型包里是 .moc 还是 .moc3,前者是 Cubism 2,后者必须要有完整可用的 Cubism 4/5 运行时。

性能:5.4MB 怎么不拖慢首屏

手段有三个:

  • 脚本全部 defer,不阻塞 DOM 解析;
  • 初始化等到 load 之后的 requestIdleCallback 才执行,首屏渲染完全不受影响;
  • 把模型里用不到的预览图和插件专用配置删掉,省下几百 KB。

移动端直接 mobileDisplay: false:4MB 的模型没必要让手机去下,也不会挡住正文。如果哪天觉得吵,直接给 init.js 加一行判断就能整个关掉。

还能怎么玩

  • 跟随深浅色主题换一套提示语气;
  • 接上天气或 Hitokoto 接口,让台词每天都不一样;
  • 把「休息一下」做成真正的番茄钟,点一下开始计时。

小结

看板娘这种东西,本质上是给冷冰冰的页面加一点「有人在」的感觉。技术上不难,难的是别让它变成首屏的负担——延迟加载 + 本地资源,这两点做到了就基本没有副作用。

这次用的 DS鲸鱼娘是 CC BY-NC-SA 4.0(署名 · 非商业 · 相同方式共享),版权链是 上善无形(原作「溟月」)→ ZipZipPipe(DeepSeek 女仆二创)→ 氵六青(模型),模型的 LICENSE 我原样留在仓库里了。个人非商业站点用没问题,别拿去商用,也别忘了署名。