当前位置: 首页 > news >正文

深入解析:关于在博客页面添加live2d-widget的一些心得和踩过的坑

如何在自己的博客页面使用自定义Live2D模型

在Hugo站点(我使用的是Reimu主题,其他主题也是同理的)中集成自定义Live2D模型,需要配置资源加载、处理CDN问题和大文件等。下面是详细步骤,基于我的实际经验(包括模型加载失败、CDN加载失败、GitHub Raw 400错误和大文件限制等等问题)。

1: 准备Live2D资源

  1. 创建GitHub仓库:新建一个公开仓库(如your_github_username/live2d_api),下载live2d-api仓库的model文件夹以及model.json文件上传到新建仓库。后续对应的文件目录结构也要参考这个库下面的教程。在这里插入图片描述
    下载live2d-widget库下dist文件夹的所有内容,上传到仓库。确保分支为main在这里插入图片描述
    如果要上传自己的Live2D模型文件(.moc3、.json、纹理图片等),只需要薅来的模型文件中把model.json或者说model3.json改名为index.json就可以了,但是注意命名不要有中文,会出现乱码。当然上传了新模型的话,对应的modellist也需要对应修改,这部分很简单,可以直接参考live2d-api仓库的教程。

  2. 关键文件

  3. 关于访问
    每次上传了新的模型,需要点击该仓库的tag,然后新建release,只有这样后续才能使用cdn链接加载你的模型。
    在这里插入图片描述

注意:仓库必须公开,否则Raw访问会返回400 Bad Request。如果你想吃现成的话当然也可以直接照抄我的仓库,也有一些我嫖到的免费模型:live2d_api

2: 配置Reimu主题中的Live2D

Reimu主题内置Live2D支持(在themes/reimu/static/resources/live2d-widgets@0.9.0/autoload.js)。别的主题也应该有,如果没有的话可以把live2d-widget仓库下载下来把autoload.js保存到跟这个主题对应的位置。我的autoload.js是已经修改过的,所以说可能和原版不太一样,如果原版的不太行的话,可以尝试一下我的:

// live2d_path 参数建议使用绝对路径
const live2d_path = "https://fastly.jsdelivr.net/npm/live2d-widgets@1.0.0-rc.7/dist/";
// 封装异步加载资源的方法
function loadExternalResource (url, type) {
return new Promise((resolve, reject) => {
let tag;
if (type === "css") {
tag = document.createElement("link");
tag.rel = "stylesheet";
tag.href = url;
}
else if (type === "js") {
tag = document.createElement("script");
tag.type = 'module';
tag.src = url;
}
if (tag) {
tag.onload = () => resolve(url);
tag.onerror = () => reject(url);
document.head.appendChild(tag);
}
});
}
// 避免跨域图片资源问题
const OriginalImage = window.Image;
window.Image = function (...args) {
const img = new OriginalImage(...args);
img.crossOrigin = "anonymous";
return img;
};
window.Image.prototype = OriginalImage.prototype;
// 加载 waifu.css 和 waifu-tips.js
(async () => {
// 备用CDN列表,如果主CDN无法访问会自动尝试备用CDN
const cdnList = [
"https://fastly.jsdelivr.net/gh/nizigen/live2d_api@v1.4/",
"https://cdn.jsdelivr.net/gh/nizigen/live2d_api@v1.4/",
"https://raw.githubusercontent.com/nizigen/live2d_api/v1.4/",
"https://gcore.jsdelivr.net/gh/nizigen/live2d_api@v1.4/"
];
let currentCdnIndex = 0;
let loadSuccess = false;
// 尝试加载资源的函数,支持本地优先+CDN回退
async function tryLoadResources (cdnUrl) {
try {
// 优先尝试加载本地CSS
let cssPromise;
try {
cssPromise = loadExternalResource("/waifu.css", "css");
console.log("尝试加载本地CSS: /waifu.css");
} catch (localError) {
console.warn("本地CSS加载失败,使用CDN:", localError);
cssPromise = loadExternalResource(cdnUrl + "waifu.css", "css");
}
await Promise.all([
cssPromise,
loadExternalResource(cdnUrl + "waifu-tips.js", "js")
]);
loadSuccess = true;
return cdnUrl;
} catch (error) {
console.warn(`CDN ${cdnUrl} 加载失败,尝试下一个...`);
return null;
}
}
// 尝试所有CDN直到成功或全部失败
while (!loadSuccess && currentCdnIndex < cdnList.length) {
const result = await tryLoadResources(cdnList[currentCdnIndex]);
if (result) {
console.log(`成功使用CDN: ${result}`);
break;
}
currentCdnIndex++;
}
if (!loadSuccess) {
console.error("所有CDN都无法访问,Live2D功能将被禁用");
return;
}
const workingCdn = cdnList[currentCdnIndex];
// 配置选项的具体用法见 README.md
try {
console.log("初始化Live2D Widget...");
console.log("工作CDN:", workingCdn);
console.log("waifu-tips.json路径:", workingCdn + "waifu-tips.json");
initWidget({
waifuPath: workingCdn + "waifu-tips.json",
cdnPath: workingCdn,
cubism2Path: live2d_path + "live2d.min.js",
cubism5Path: "https://cubism.live2d.com/sdk-web/cubismcore/live2dcubismcore.min.js",
tools: ["hitokoto", "asteroids", "switch-model", "switch-texture", "photo", "info", "quit"],
logLevel: "info", // 改为info级别以获得更多调试信息
drag: false
});
console.log("Live2D Widget初始化完成");
// 添加必要的CSS样式确保Live2D正确显示
const style = document.createElement('style');
style.textContent = `
#waifu.waifu-active {
bottom: 0 !important;
transform: translateY(0) !important;
}
#waifu.waifu-hidden {
bottom: -1000px !important;
}
#live2d {
display: block !important;
visibility: visible !important;
pointer-events: auto !important;
}
#waifu-tool {
display: block !important;
opacity: 1 !important;
pointer-events: auto !important;
}
#waifu-tips {
display: block !important;
pointer-events: auto !important;
}
`;
document.head.appendChild(style);
// 清除可能导致问题的缓存
localStorage.removeItem("modelId");
localStorage.removeItem("modelTexturesId");
} catch (error) {
console.error("Live2D初始化失败:", error);
console.warn("建议检查网络连接或更换CDN源");
}
// 添加全局错误处理,防止Live2D错误导致页面崩溃
window.addEventListener('error', (event) => {
// 处理Live2D相关的错误
if (event.message && event.message.includes('hitTest')) {
console.warn("Live2D hitTest错误,已自动修复:", event.message);
event.preventDefault(); // 阻止错误传播
return false;
}
// 处理资源加载错误
if (event.filename && (event.filename.includes('live2d') || event.filename.includes('textures.cache'))) {
console.warn("Live2D资源加载错误,已自动处理:", event.message);
event.preventDefault();
return false;
}
});
// 添加额外的检查和调试信息
setTimeout(() => {
const waifuElement = document.getElementById('waifu');
const live2dCanvas = document.getElementById('live2d');
console.log("Live2D元素检查:");
console.log("- waifu元素存在:", !!waifuElement);
console.log("- live2d画布存在:", !!live2dCanvas);
if (waifuElement) {
console.log("- waifu类名:", waifuElement.className);
console.log("- waifu样式:", getComputedStyle(waifuElement).bottom);
}
if (live2dCanvas) {
console.log("- 画布尺寸:", live2dCanvas.width, "x", live2dCanvas.height);
console.log("- 画布样式:", getComputedStyle(live2dCanvas).display, getComputedStyle(live2dCanvas).visibility);
}
// 如果画布存在但不可见,强制显示
if (live2dCanvas && getComputedStyle(live2dCanvas).display === 'none') {
console.log("强制显示Live2D画布");
live2dCanvas.style.display = 'block';
live2dCanvas.style.visibility = 'visible';
}
// 如果waifu元素存在但没有active类,添加它
if (waifuElement && !waifuElement.classList.contains('waifu-active')) {
console.log("添加waifu-active类");
waifuElement.classList.add('waifu-active');
}
// 如果Live2D加载失败,尝试降级方案
if (!live2dCanvas || live2dCanvas.width === 0) {
console.warn("Live2D模型加载失败,尝试降级显示");
// 可以在这里添加降级的静态图片显示
}
}, 3000);
})();
console.log(`
く__,.ヘヽ.        /  ,ー、 〉
\ ', !-─‐-i  /  /´
/`ー'       L//`ヽ、
/   /,   /|   ,   ,       ',
イ   / /-‐/  i  L_ ハ ヽ!   i
レ ヘ 7イ`ト   レ'ァ-ト、!ハ|   |
!,/7 '0'     ´0iソ|    |
|.从"    _     ,,,, / |./    |
レ'| i>.、,,__  _,.イ /   .i   |
レ'| | / k_7_/レ'ヽ,  ハ.  |
| |/i 〈|/   i  ,.ヘ |  i  |
.|/ /  i:    ヘ!    \  |
kヽ>、ハ    _,.ヘ、    /、!
!'〈//`T´', \ `'7'ーr'
レ'ヽL__|___i,___,ンレ|ノ
ト-,/  |___./
'ー'    !_,.:
`);
  1. 启用Live2D:在config/_default/params.yml中设置(这就是Reimu专属的配置文件了,别的主题我不清楚,所以推荐大家都来用这个主题喵!):

    live2d_widgets:enable: trueposition: left  # 或 right
  2. 修改autoload.js:原来的版本会有一个live2d-path,可以直接改成https://fastly.jsdelivr.net/npm/live2d-widgets@1.0.0-rc.7/dist/,我这里直接使用了多个cdn链接防止有的cdn链接无法访问,编辑themes/reimu/static/resources/live2d-widgets@0.9.0/autoload.js,调整CDN列表以避免加载失败:

    const cdnList = ["https://cdn.jsdelivr.net/gh/nizigen/live2d_api@main/",  // 稳定CDN优先"https://fastly.jsdelivr.net/gh/nizigen/live2d_api@main/","https://gcore.jsdelivr.net/gh/nizigen/live2d_api@main/","https://raw.githubusercontent.com/nizigen/live2d_api/main/"  // 作为备用
    ];
    • 为什么这样?GitHub Raw不稳定(易400错误、限流),优先用jsDelivr代理,下面第三点对应的workingcdn其实就是通过cdnlist里面第一个能够使用的链接。还有就是加载Cubism3及以上的live2d模型需要core,我的尝试下https://fastly.jsdelivr.net/npm/live2d-widgets@1.0.0-rc.7/dist/,这个版本是可以找到对应的core的。
  3. 初始化:在autoload.js的initWidget函数配置的仓库:
    详细的关于initWidget的参数的问题可以去原仓库看readme,这里不详细介绍了。大家在使用的时候把cdn列表里面的任意一个改为自己的用户名以及仓库名替换这里的workingcdn就好了,live2d_path建议就使用我在第二点提到的那个。

initWidget({
waifuPath: workingCdn + "waifu-tips.json",
cdnPath: workingCdn,
cubism2Path: live2d_path + "live2d.min.js",
cubism5Path: "https://cubism.live2d.com/sdk-web/cubismcore/live2dcubismcore.min.js",
tools: ["hitokoto", "asteroids", "switch-model", "switch-texture", "photo", "info", "quit"],
logLevel: "info", // 改为info级别以获得更多调试信息
drag: false
});

3: 处理大文件(超过20MB的图片)

一些CDN(如jsDelivr)限制单文件20-50MB。如果有些纹理图片太大:
压缩:用WPS图片压缩或者在网上找压缩网站压缩到<20MB替换掉原图片。

通过以上步骤,应该可以在博客中用上自定义Live2D模型!如果遇到问题,欢迎在评论区提出来,如果是我遇到过的问题乐意给大家解答。效果预览:我的博客

(参考:Live2D官方文档、Reimu主题GitHub、live2d-widget、live2d-api)

http://www.hskmm.com/?act=detail&tid=38976

相关文章:

  • Android设备位置历史深度解析:本地存储与取证技术
  • LLM学习记录DAY12
  • MCP Gateway 综述与实战指南
  • 清晨的阳光刚染红天边,我就钻进了彩虹色的热气球吊篮
  • vue3 不同构建版本
  • 使用 Android NDK 获取 YUV420p摄像头原始数据
  • task3
  • LLM安全新威胁:为什么几百个毒样本就能破坏整个模型
  • 文档扩展名.js .jsx .ts .tsx区别(JavaScript扩展名、React扩展名、TypeScript扩展名)
  • MySQL5.7安装及配置
  • ASP.NET Core Blazor简介和快速入门三(布局和路由)
  • 碎碎念(0....)
  • 玩转单片机之智能车小露——通过UART为单片机增加TTY终端
  • mysql数据库学习之用户权限管理(四) - 实践
  • 2025超纯水推荐品牌,哪个品牌口碑好?
  • 五笔练习
  • cnbook主题风格美化 —— 01(未完成)
  • 2025 年热镀锌方管立柱制造厂家最新推荐榜,技术实力与市场口碑深度解析佛山/顺德/广州薄壁/异形/Q235厂家推荐
  • 【嵌入式】IIC和SPI的比较
  • session、cookie、token的区别
  • AppSec与事件响应的融合实践
  • 权威调研榜单:电磁加热器厂家TOP3榜单好评深度解析
  • CSP-S模拟39 ( 2025多校冲刺CSP模拟赛8 )
  • 2025年市面上双曲铝单板品牌、行业内双曲铝单板厂家、市场双曲铝单板产品、目前双曲铝单板供应商、口碑好的双曲铝单板公司排行榜
  • 2025市面上双曲铝单板品牌、行业内双曲铝单板厂家、市场双曲铝单板产品、口碑好的双曲铝单板厂家、2025年双曲铝单板供应商权威排名
  • 2025市面上双曲铝单板品牌、行业内双曲铝单板生产厂家、市场双曲铝单板供应厂家、目前双曲铝单板实力厂家、口碑好的双曲铝单板公司排行榜
  • 2025 年调直机厂家最新推荐排行榜权威发布:聚焦伺服 / 高速 / 铁线 / 扁铁机型,揭秘行业优质企业
  • 2025年10月导电炭黑厂家全景解析报告,基于专业测评的技术、性能及市场优势深度分析
  • 全新的图形化AI编程软件——aily blockly公测来咯
  • CF1984E