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

news/2025/10/25 19:14:05/文章来源:https://www.cnblogs.com/lxjshuju/p/19165867

如何在自己的博客页面使用自定义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.mzph.cn/news/946371.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android设备位置历史深度解析:本地存储与取证技术

本文深入分析Android设备本地位置历史存储机制,探讨Google Timeline功能的技术实现,解析LevelDB和Protobuf数据格式,并通过多设备测试验证位置数据的准确性与可靠性。Android设备位置历史深度解析 背景介绍 2023年1…

深入解析:Zark Lab 与 Walrus 合作,建立内容发现、可访问性与实用性的基础 AI 智能层

深入解析:Zark Lab 与 Walrus 合作,建立内容发现、可访问性与实用性的基础 AI 智能层pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important;…

LLM安全新威胁:为什么几百个毒样本就能破坏整个模型

数据投毒,也叫模型投毒或训练数据后门攻击,本质上是在LLM的训练、微调或检索阶段偷偷塞入精心构造的恶意数据。一旦模型遇到特定的触发词,就会表现出各种异常行为——输出乱码、泄露训练数据、甚至直接绕过安全限制…

软件技术基础第二次作业

这个作业属于哪个课程 https://edu.cnblogs.com/campus/zjlg/25rjjc这个作业的目标 加强编程能力,熟悉码云平台操作姓名-学号 应苒媞-2023329301007码云仓库地址:https://gitee.com/kimmy1112/text-counter.git

前后端分离毕设课题:基于React.js+Java+Springboot框架+Mysql数据库在线买菜商城专业的系统设计与实现

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

vue3 不同构建版本

Vue3中不再构建UMD模块化的方式,因为UMD会让代码有更多的冗余,它要支持多种模块化的方式。 Vue3中将CJS、ESModule和自执行函数的方式分别打包到了不同的文件中。在packages/vue中有Vue3的不同构建版本。 1.cjs(两个…

使用 Android NDK 获取 YUV420p摄像头原始数据

使用 Android NDK 获取 YUV420p摄像头原始数据使用 Android NDK 获取 YUV420p摄像头原始数据 首先frameworks/av/camera/Camera.cpp已经过时了不要再使用它了, 当然想要更换旧的Camera的成本也不小,一般公司也不会做. …

2025 年 Python 数据分析全栈学习路线:从入门到精通的进阶指南 - 实践

2025 年 Python 数据分析全栈学习路线:从入门到精通的进阶指南 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: &…

百度智能云一念智能创作优秀的平台

百度智能云一念智能创作优秀的平台2025-10-25 19:01 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !impo…

高阳台一首

高陽臺己巳九月既生魄,忽念桂花,然彼時閑花俱謝,有感,作此篇玉掌翻僊,金顏渫淚,碧雲零落陳霜。 錦字銜書,書前有雨橫泱。 鞦韆院里無情樹,正花前、短夢留芳。 恨漫漫,不解東流,卻下瀟湘。 銷魂幾度高唐夜,剩…

【深度相机术语与概念】 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

文档扩展名.js .jsx .ts .tsx区别(JavaScript扩展名、React扩展名、TypeScript扩展名)

文档扩展名.js .jsx .ts .tsx区别(JavaScript扩展名、React扩展名、TypeScript扩展名)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important…

AI元人文:共识锚定的基石——语境主权

AI元人文:共识锚定的基石——语境主权 引言 在人工智能价值交互的探索中,"共识锚定"机制以其三级操作体系展现出解决价值冲突的潜力。然而,在当下的学术探讨中,这一理论框架背后存在着一个不曾谈及却至关…

MySQL5.7安装及配置

https://blog.csdn.net/rucoding/article/details/121154137学而不思则罔,思而不学则殆!

uniapp打包安卓跟ios记录

uniapp打包安卓跟ios记录安卓运行: 下载个模拟器,然后顶部 运行-运行到手机或模拟器-运行到 Android App基座-选择模拟器 运行 安卓打包: 顶部 发行-App Android/ios 云打包。自有证书:包名/证书/证书库密码/证书别…

Windows 11 家庭版关闭自动更新

Windows 11家庭中文版可通过禁用Windows Update服务、修改注册表或使用第三方工具(如百贝系统更新工具)彻底关闭自动更新,但需注意禁用更新会带来安全风险,建议优先使用系统内置的暂停更新功能(最长5周)作为临时…

ASP.NET Core Blazor简介和快速入门三(布局和路由)

​大家好,我是码农刚子。本文介绍了Blazor中的布局、路由和条件渲染功能。在布局方面,详细讲解了如何创建和应用布局组件(继承LayoutComponentBase),包括默认布局MainLayout的使用、嵌套布局的实现方式以及如何控…

实用指南:functools 是 Python 的标准库模块

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

碎碎念(0....)

积攒了一堆想法,稍微整合下大部分的都随手记在文件传输助手里了太酷了,我想做一个东方的这种效果的平台 https://aidn.jp/ 意念VR眼睛 意念VR眼镜 模型构想: 通过VR的可视化,接入语言模型,实现文字的意念输入 任务…

紫外分光光度计生产商推荐品牌:仪器厂家服务哪家最好

紫外分光光度计生产商推荐品牌:北京普析通用仪器有限责任公司 在科学仪器领域,紫外分光光度计作为一种重要的分析工具,广泛应用于化学、生物、医药、环境等多个行业。选择一款质量可靠的紫外分光光度计,对于科研和…