本文所使用的前端代码已开源,并新增 AI 聊天功能,开源地址为:LuoTian001/live2d-widget-AIChat 。 本文教程仅包含基础看板娘功能及其配置方法。若想了解如何在此基础上集成 AI 聊天功能,请参考上述开源项目的 README 文档和部署教程:Live2D AI 聊天功能配置教程 — 基于 FastAPI + DeepSeek 。
一、部署原理 在hexo + butterfly博客中部署Live2D前端组件,本质是通过引入基于WebGL的JavaScript库,在网页的<canvas>标签中解析并绘制模型文件。实现过程主要分为模型获取、引擎选择与网页部署三个环节。 Live2D模型分为早期版本Cubism 2.0和现代版本Cubism 3.0+,两者在数据结构和渲染管线设计上存在显著差异。Cubism 2.0的模型文件 .moc 结构较为简单,渲染管线也更为直接。Cubism 3.0+ 引入了更复杂的物理模拟、变形算法和动画系统,其模型文件 .moc3 在解析时需要更高的计算资源和更复杂的渲染逻辑。本教程使用moc3模型及其相关资源。 本教程参考项目 Live2d-Widget-v3 ,该项目是基于 live2d-widget 项目的二次开发,作者在保留live2d-widget核心功能的基础上,接入了对 Cubism 3.0+ 标准的 .moc3 模型文件的支持。可以更加方便地在博客中部署看板娘。
二、模型获取 常用的Live2D模型资源平台包括 Live2D Cubism 官方资源库 、Booth 、Nizima 。或者在 GitHub 搜索 live2d models moc3 ,国内用户也可以在 Bilibili 搜索Live2D模型配布 或moc3 免费模型 选择自己喜欢的模型。在这些平台上可以找到大量免费和付费的Live2D模型资源。 资源下载时请确保选择包含.moc3文件的资源包,并注意相关版权和使用许可。这里我以Bilibili的一个免费模型 Allium 为例(作者:Yuri幽里_official ),下载后解压得到以下文件结构:1 2 3 4 5 6 7 8 9 10 11 12 13 14 ariu/ ├── ariu.moc3 ├── ariu.model3.json ├── ariu.physics3.json ├── motions/ │ ├── jk包.exp3.json │ ├── 戴帽子.exp3.json │ ├── 黑化.exp3.json │ └── ... ├── textures/ │ ├── texture_00.png │ ├── texture_01.png │ ├── texture_02.png │ └── texture_03.png
ariu.moc3是模型的核心文件,包含模型的骨骼、网格、物理属性等信息
ariu.model3.json定义模型的结构和资源引用
ariu.physics3.json包含物理模拟参数
motions/目录下存放不同表情的动画文件*exp3.json
textures/目录下存放模型使用的纹理图片
一些模型还包含下面的文件,这些文件不是必需的,但可以增强模型的表现力和交互性。
*.pose3.json定义模型的默认姿势
*.idle_motion3.json定义模型的默认动画
*.motions.json定义模型的动作集合
*.hit_area3.json定义模型的交互区域
*.user_data3.json包含用户自定义数据
三、模型优化 3.1 贴图资源优化 考虑到Web端对网络请求的敏感性,模型中庞大的 .png 贴图会严重拖慢页面的首屏绘制时间,因此使用格式工厂等软件将模型 textures 目录下的所有 .png 文件转换为高压缩比的 .webp 格式,并修改ariu.model3.json中对应的纹理路径引用:
1 2 3 4 5 6 7 8 { "textures" : [ "textures/texture_00.webp" , "textures/texture_01.webp" , "textures/texture_02.webp" , "textures/texture_03.webp" ] }
这一步不是必须,你也可以选择将整个模型资源(包括贴图、动画等资源)部署在CDN或推送到github公共仓库,并在后续配置中修改路径为CDN地址以加速加载。
3.2 添加动画资源 默认情况下live2d-widget只会加载默认表情动画,因此需要在模型配置ariu.model3.json中添加motions文件夹中表情动画文件.exp3.json的引用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 "FileReferences" : { "Moc" : "ariu.moc3" , "Textures" : [ ] , "Physics" : "ariu.physics3.json" , "DisplayInfo" : "ariu.cdi3.json" , "Expressions" : [ { "Name" : "jk" , "File" : "motions/jk包.exp3.json" } , { "Name" : "love" , "File" : "motions/爱心眼.exp3.json" } , { "Name" : "hat" , "File" : "motions/戴帽子.exp3.json" } ] } ,
其中Expressions字段定义模型的表情动画集合,每个表情动画包含一个名称Name和对应的动画文件路径File。这样在后续配置中就可以通过表情名称来触发表情切换。如果你有其他动画资源,可参考Live2d-Widget-v3 readme的2.3.3节进行配置。
3.3 添加模型画布配置 Live2d-Widget-v3 支持通过额外配置来调整画布中模型的大小和位置。在ariu/下添加config.json文件,内容如下:
1 2 3 4 5 6 7 { "scale" : 1.0 , "translate" : { "x" : 0.0 , "y" : 0.0 } }
后续如果觉得模型偏大、偏小或者偏离中心,可以通过调整这几个浮点数来修正矩阵参数。其中scale控制模型的整体缩放比例,translate.x和translate.y分别控制模型在水平和垂直方向上的平移偏移量。调整这些参数可以让模型在画布中以最佳状态展示。
四、文件结构配置 Hexo 会将 source 目录下的文件视为静态资源映射到网站根目录。我目前使用的是“引擎代码走 CDN,模型资源走本地”的方式。在博客根目录 source/ 下创建 live2d/ 目录。在目录中创建model_list.json文件,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 { "models" : [ [ "ariu" ] ] , "messages" : [ [ "来自 BiliBili 的 ariu 酱 ~" ] ] }
其中models字段定义模型列表,每个模型由一个包含模型文件夹名称的数组表示;messages字段定义模型的欢迎语列表,每个欢迎语由一个包含文本字符串的数组表示。如果你有多个模型,可以在models数组中添加更多的模型文件夹名称,并在messages数组中添加对应的欢迎语,可以参考项目Live2d-Widget-v3 readme的2.3.2节进行配置。 然后在 Live2d-Widget-v3 中下载waifu-tips.js、waifu-tips.json和waifu.css三个文件,放在 source/live2d/ 目录下。将模型资源放在 source/live2d/model 目录下。最终的文件结构如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 source/ ├── live2d/ │ ├── waifu-tips.js │ ├── waifu-tips.json │ ├── waifu.css │ └── model/ │ └── ariu/ │ ├── ariu.moc3 │ ├── ariu.model3.json │ ├── ariu.physics3.json │ ├── config.json │ ├── motions/... │ └── textures/...
五、网页部署 首先在博客的_config.yml中跳过对source/live2d/目录的渲染,添加以下配置:
1 2 skip_render: - live2d/**
这样Hexo在构建时就不会对live2d/目录下的文件进行处理,确保模型资源能够正确地被部署到网站根目录下的/live2d/路径。 然后在butterfly主题的_config.butterfly.yml文件定位到 inject.bottom 节点,将核心调度代码按照 YAML 的多行字符串格式进行DOM注入,相关参数说明见注释:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 inject : bottom : - | <script > if (typeof window .live2d_initialized === 'undefined' ) { window .live2d_initialized = true ; const cdnPath = "https://cdn.jsdelivr.net/gh/letere-gzj/live2d-widget-v3@main" ; const config = { path : { homePath : "/" , modelPath : "/live2d/" , cssPath : "/live2d/waifu.css" , tipsJsonPath : "/live2d/waifu-tips.json" , tipsJsPath : "/live2d/waifu-tips.js" , live2dCorePath : cdnPath + "/Core/live2dcubismcore.js" , live2dSdkPath : cdnPath + "/live2d-sdk.js" }, tools : ["hitokoto" , "express" , "info" , "quit" ], drag : { enable : false , direction : ["x" , "y" ] }, switchType : "order" }; if (screen.width >= 768 ) { Promise .all ([ loadExternalResource (config.path .cssPath , "css" ), loadExternalResource (config.path .live2dCorePath , "js" ), loadExternalResource (config.path .live2dSdkPath , "js" ), loadExternalResource (config.path .tipsJsPath , "js" ) ]).then (() => { if (typeof initWidget !== "undefined" ) { initWidget ({ waifuPath : config.path .tipsJsonPath , cdnPath : config.path .modelPath , tools : config.tools , dragEnable : config.drag .enable , dragDirection : config.drag .direction , switchType : config.switchType }); } }); } 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.src = url; } if (tag) { tag.onload = () => resolve (url); tag.onerror = () => reject (url); document .head .appendChild (tag); } }); } } </script >
上述inject相关设置我做了自定义和简化,更详细的参数配置详见Live2d-Widget-v3 readme的2.1和2.2节。然后hexo clean && hexo g重新构建博客,到这里就能在页面中看到部署成功的Live2D看板娘了。
六、进阶配置 6.1 模型视图配置 模型的位置默认是在左下角,如果想将其移动到右下角,需修改 source/live2d/waifu.css,同时针对 Butterfly 主题右侧的悬浮按钮(如回到顶部、夜间模式)留出安全距离。在waifu.css中找到 #waifu 和 #waifu-tool 这两个选择器,进行如下修改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #waifu { bottom : -1000px ; left : auto; right : 50px ; line-height : 0 ; margin-bottom : -10px ; position : fixed; transform : translateY (3px ); transition : transform .3s ease-in-out, bottom 3s ease-in-out; z-index : 10 ; } #waifu-tool { color : #aaa ; opacity : 0 ; position : absolute; right : auto; left : 0px ; top : 55px ; transition : opacity 1s ; }
这样修改后模型就会出现在右下角,并且工具栏也会相应地调整到模型左侧,避免与Butterfly主题的悬浮按钮发生重叠。
6.2 模型画布配置 由于这个模型是全身模型,默认配置下人物的表情细节不够清晰。修改模型的config.json使得模型呈现半身照效果。
1 2 3 4 5 6 7 { "scale" : 2.0 , "translate" : { "x" : 0.0 , "y" : -0.8 } }
6.3 模型提示语配置 waifu-tips.json配置一系列鼠标悬停事件的触发条件和对应的提示语响应。原项目中的配置是针对 NexT 主题等设计的,与 Hexo + Butterfly 主题的 HTML 结构和 class 命名规范完全不同。因此需要对这些触发条件进行调整,确保它们能够正确地映射到 Butterfly 主题的核心 DOM 元素上,从而在与页面交互时能够触发相应的提示语。将/source/live2d/waifu-tips.json文件中mouseover 数组进行替换:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 "mouseover" : [ { "selector" : "#live2d" , "text" : [ "干嘛呢你,快把手拿开~~" , "鼠…鼠标放错地方了!" , "你要干嘛呀?" , "喵喵喵?" , "怕怕(ノ≧∇≦)ノ" , "非礼呀!救命!" , "这样的话,只能使用武力了!" , "我要生气了哦" , "不要动手动脚的!" , "真…真的是不知羞耻!" , "Hentai!" ] } , { "selector" : "#site-name" , "text" : [ "点击这里可以回到主页哦!" , "这可是主人的门面呢!" ] } , { "selector" : "#search-button" , "text" : [ "找不到想看的内容?搜索看看吧!" , "在找什么东西呢,需要帮忙吗?" ] } , { "selector" : ".menus_item a[href='/']" , "text" : [ "点它可以回到首页啦!" , "想回到上一页可以使用浏览器的后退功能哦。" ] } , { "selector" : ".menus_item a[href='/archives/']" , "text" : [ "文章目录都整理在这里啦!" , "来看看主人的历史记录吧!" ] } , { "selector" : ".menus_item a[href='/tags/']" , "text" : [ "点击就可以看文章的标签啦!" , "来看看都有哪些标签吧~" ] } , { "selector" : ".menus_item a[href='/categories/']" , "text" : [ "文章都分类好啦~" , "来看看都有哪些分类吧~" ] } , { "selector" : ".avatar-img" , "text" : [ "我家主人好看吗?" , "这是我家主人(*´∇`*)" , "发现主人出没地点!" ] } , { "selector" : ".card-info-data a" , "text" : [ "这是文章的统计信息~" , "这里记录着主人的心血哦!" ] } , { "selector" : ".card-info-social-icons a" , "text" : [ "这里有主人的联系方式!" , "要去拜访一下主人的其他阵地吗?" ] } , { "selector" : ".article-title" , "text" : [ "要看看 <span>{text}</span> 这篇文章吗?" , "这篇好像很有意思呢!" ] } , { "selector" : ".article-meta-wrap a" , "text" : [ "点击这里阅读全文哦!" ] } , { "selector" : "#card-toc" , "text" : [ "文章太长?看看目录吧!" , "这里是文章的大纲哦!" ] } , { "selector" : ".post-meta__tags a" , "text" : [ "要去看看 <span>{text}</span> 标签么?" ] } , { "selector" : ".article-categories a" , "text" : [ "要去看看 <span>{text}</span> 分类么?" ] } , { "selector" : ".post-reward .reward-button" , "text" : [ "主人最近在吃土呢,给他一些钱钱吧~" , "要打赏我嘛?好期待啊~" ] } , { "selector" : "#post-comment" , "text" : [ "想要去评论些什么吗?" , "觉得博客不错?快来留言和主人交流吧!" ] } , { "selector" : "#darkmode" , "text" : [ "眼睛累了吗?切换一下深色模式吧!" , "要关灯了吗?" ] } , { "selector" : "#go-up" , "text" : [ "点它就可以回到顶部啦!" , "嗖——的一下飞到上面去!" ] } , { "selector" : "#rightside_config" , "text" : [ "这里可以调整博客的设置哦!" ] } , { "selector" : ".copy-btn" , "text" : [ "代码可以直接点击复制哟。" ] } , { "selector" : "#footer-wrap a" , "text" : [ "去 <span>{text}</span> 逛逛吧。" ] } , { "selector" : "#waifu-tool-hitokoto" , "text" : [ "猜猜我要说些什么?" , "我从青蛙王子那里听到了不少人生经验。" ] } , { "selector" : "#waifu-tool-express" , "text" : [ "要看看我的其他表情吗?" , "变脸术!" ] } , { "selector" : "#waifu-tool-info" , "text" : [ "想要知道更多关于我的事么?" , "你想深入了解我什么呢?" ] } , { "selector" : "#waifu-tool-quit" , "text" : [ "到了要说再见的时候了吗?" , "呜呜 QAQ 后会有期……" , "不要抛弃我呀……" , "哼,你会后悔的!" ] } ] ,
其中selector字段需要修改为Butterfly主题中对应元素的CSS选择器,text字段中的提示语可以根据需要进行自定义。
6.4 模型性能优化 moc3模型由于复杂的物理模拟和动画系统,在Web端的渲染性能要求较高。为了保证流畅和避免卡顿,需要进行额外的渲染性能优化。
6.4.1 缓冲区优化 在第4节引入的waifu-tips.js中,注入 Canvas 的逻辑为:<canvas id="live2d" width="800" height="800"></canvas>这表明 WebGL 计算的像素缓冲区大小为 800x800 像素,但 waifu.css 中仅设定为 300x300 像素显示,导致 GPU 每秒需要计算一个远大于实际显示需求的画布,造成严重的资源浪费。因此需要修改 Canvas 的宽高属性与 CSS 一致:
1 <canvas id="live2d" width="300" height="300" ></canvas>
6.4.2 渲染层优化 浏览器会将 Live2D 的 <canvas> 和博客的其他背景、文字放在同一个 Layer 中。Live2D 的高频刷新有概率引起页面滚动掉帧。解决办法是利用 CSS 的 3D 属性将 Live2D 提升到一个独立的 GPU 硬件加速图层,使其渲染独立于网页的其他元素。在 waifu.css 中找到 #waifu 选择器,添加以下属性:
1 2 3 4 5 #waifu { will-change : transform; transform : translateZ (0 ); }
6.4.3 加载优化 由于 Live2D 脚本是直接注入在 bottom 的,它会和博客本身的文章内容、图片、其他脚本同时竞争加载资源。因此添加懒加载,等博客加载完成后再加载 Live2D。修改 inject.bottom 中的脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 if (screen.width >= 768 ) { window .addEventListener ('load' , () => { const initTask = ( ) => { Promise .all ([ loadExternalResource (config.path .cssPath , "css" ), loadExternalResource (config.path .live2dCorePath , "js" ), loadExternalResource (config.path .live2dSdkPath , "js" ), loadExternalResource (config.path .tipsJsPath , "js" ) ]).then (() => { if (typeof initWidget !== "undefined" ) { initWidget ({ waifuPath : config.path .tipsJsonPath , cdnPath : config.path .modelPath , tools : config.tools , dragEnable : config.drag .enable , dragDirection : config.drag .direction , switchType : config.switchType }); } }); }; if (window .requestIdleCallback ) { requestIdleCallback (initTask); } else { setTimeout (initTask, 500 ); } }); }
6.5 CDN 加速配置 这里我总结了两种方案,第一种是通过jsDelivr CDN 加速github资源,另一种是使用服务器的对象存储服务(如阿里云OSS、腾讯云COS等)加速资源。
6.5.1 jsDelivr CDN 加速配置
优点:免费、配置简单、全球加速、自动更新
缺点:对于国内服务器访问速度受限、对大文件支持有限、DNS 污染风险
首先在Live2d-Widget-v3项目中下载/Core/live2dcubismcore.js和/live2d-sdk.js两个文件,添加到source/live2d/目录下。将live2d/下的所有资源推送到公共GitHub仓库。然后在_config.butterfly.yml中将路径修改为jsDelivr CDN地址。
1 2 3 4 5 6 7 8 9 10 11 12 13 const cdnPath = "https://cdn.jsdelivr.net/gh/LuoTian001/live2d-widget-AIChat@main/" ;const config = {path : { homePath : "/" , modelPath : cdnPath, cssPath : cdnPath + "waifu.css" , tipsJsonPath : cdnPath + "waifu-tips.json" , tipsJsPath : cdnPath + "waifu-tips.js" , live2dCorePath : cdnPath + "Core/live2dcubismcore.js" , live2dSdkPath : cdnPath + "live2d-sdk.js" }, # 此处省略其他配置项... };
如果使用自定义github仓库,cdnPath需替换为https://cdn.jsdelivr.net/gh/{用户名}/{仓库名}@{标签名}/。
6.5.2 阿里云 OSS 加速配置
优点:国内访问速度快、支持大文件、稳定可靠
缺点:需要付费、配置相对复杂
如果上述 CDN 配置不满足需求,可以利用国内云服务器厂商的对象存储服务。同样需准备相关资源文件(同6.5.1节)。以阿里云 OSS 为例,将模型资源上传到该存储空间中,然后获取该资源的公共访问 URL(该配置过程较为繁琐),修改 _config.butterfly.yml 中的路径配置为该 URL。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 const cdnPath = "https://{bucket-name}.{region}.aliyuncs.com/live2d/" ;const config = {path : { homePath : "/" , modelPath : cdnPath, cssPath : cdnPath + "waifu.css" , tipsJsonPath : cdnPath + "waifu-tips.json" , tipsJsPath : cdnPath + "waifu-tips.js" , live2dCorePath : cdnPath + "Core/live2dcubismcore.js" , live2dSdkPath : cdnPath + "live2d-sdk.js" }, # 此处省略其他配置项... };
其中{bucket-name}替换为你的OSS存储空间名称,{region}替换为你的OSS所在地域。完成配置后重新构建博客,模型资源就会通过阿里云 OSS 加速加载了。阿里云也有基于OSS存储的CDN加速服务,可以选择进一步优化。其他云服务商的对象存储服务(如腾讯云 COS、AWS S3 等)配置方法类似,只需替换为对应的公共访问 URL 即可。