
简介面向网页中需要加入二维动画角色的前端开发者这套HTML集成Live2D的演示项目从引入Cubism库、设置JSON模型配置、建立绘制画布到初始化渲染引擎完整展示了基本流程同时加入动态更换角色、触摸响应以及和其他网页组件联动等交互功能能帮助读者快速理解Live2D动画在浏览器中的工作方式。压缩包共612个文件以mtn动作文件、JSON配置、moc模型数据、png贴图、mp3音频为主另有HTML与JS示例整体大小17.29MB轻量便于研读。已有1431人浏览学习适合需要在项目中快速落地并二次开发Live2D效果的开发者。解压后可按目录对照代码与素材重点学习模型加载、事件绑定、资源切换等细节继而把角色互动能力迁移到自己的网站中。1. 为什么要在HTML里集成Live2D demo接到需求要给产品官网加一个会眨眼、能点击互动的看板娘时大部分人搜的第一个词就是html集成live2D,demo。这个demo不是要你把整个Live2D官方SDK吃透而是用最少的代码在网页里加载一个Live2D模型、让它正常呼吸和动作跑通链路之后再考虑交互和样式。这个方向适合前端开发、独立开发者以及想快速验证虚拟形象交互体验的团队。我先说结论demo的核心是理解模型资源、渲染库和浏览器Canvas三者的关系而不是把模型塞进页面就完事。2. 先搞懂Live2D在浏览器里的渲染链路Cubism Core、PixiJS与模型资源2.1 Live2D模型文件到底包含什么.model3.json/moc3/textures拿到一个Live2D模型包不要急着写代码先拆开看目录。目前主流是Cubism 4格式典型的模型资源长这样models/my_model/ my_model.model3.json my_model.moc3 my_model.physics3.json my_model.motion3.json my_model.exp3.json textures/ texture_00.png ...model3.json是整个模型的入口配置里面声明了贴图路径、Physics、Motions、Expressions以及HitAreas。.moc3是模型的核心几何数据浏览器里的Cubism Core负责解码它。.physics3.json控制头发、饰品这类零件的物理摆动。.motion3.json是动作文件比如眨眼、抬手。.exp3.json是表情文件。如果你拿到的是老一点的Cubism 2模型入口文件叫model.json模型文件后缀是.moc动作和贴图的组织方式也不太一样。这个区别非常重要因为Cubism Core运行时分成2和4两代用错了核心直接加载报错。很多网上流传的免费模型资源可能在教程里特意标注了版本但更常见的是下载包解压后没有README这时就要靠入口文件名判断model3.json对应Cubism 4model.json对应Cubism 2。另外提醒一句有些整合包是从游戏里提取的比如社区里流传的AzurLane live2d viewer资源本地学习没问题但上线商用前一定要确认版权。官方有一些免费示例模型配置完整适合第一时间跑通。2.2 为什么我推荐用 pixi-live2d-display 而不是裸上官方SDK官方Cubism SDK for Web是能直接在浏览器里用的但它是一个偏底层的库入手的人需要自己管理Renderer、TextureManager、Model、MotionManager等一堆对象。自己搭一个最小场景要写不少初始化代码而且文档偏向于C/桌面版思维Web接入的示例更新不快。对于html集成live2D,demo这个诉求直接用社区封装好的库性价比高得多。我一般会用pixi-live2d-display它把Live2D模型封装成PixiJS的一个显示对象。PixiJS本身是2D渲染引擎有自己的Canvas/WebGL管理、舞台树和事件系统这个插件注册一个Live2DModel类加载模型后可以像操作普通精灵一样设置坐标、缩放、旋转还能直接挂鼠标事件。demo阶段的代码量能少一半以上。官方SDK和封装方案并不是谁替代谁。官方SDK适合做深度定制比如要同时渲染几十个模型、自己控制渲染帧率、做多平台交互统一。如果你的目标是先跑通一个demo给产品看或者给个人网站加一个虚拟助手pixi-live2d-display足够了。2.3 SDK版本和运行时关系Cubism 2/Cubism 4选择库版本时要明白整个依赖链条浏览器加载.moc3数据靠的是Live2D Cubism CoreCubism Core是一个编译成wasm/js的运行时它不关心你在外面用了什么UI框架。pixi-live2d-display负责把Core解码出来的网格、顶点、纹理交给PixiJS渲染。这里最坑的是Cubism 4核心只能解码.moc3Cubism 2核心只能解码.moc。所以你在加载模型前先确认模型版本再决定使用哪个核心。pixi-live2d-display本身同时支持两类模型但实际加载哪个核心取决于你页面里怎么引用的依赖。如果混用比如模型是老版本页面却只加载了Cubism 4核心通常会在加载阶段报出类似版本不匹配的异常而且不一定直接写在报错信息里。一个额外的注意点是Cubism Core在浏览器里是异步初始化的如果页面脚本在核心初始化完之前就去加载模型看起来就是白屏。demo代码里最好等模型加载Promise执行完再操作舞台不要直接在同步代码里调用模型方法。3. 搭一个能动的html集成live2D demo最小目录与完整代码3.1 先准备demo目录模型、SDK和页面文件建议把目录固定下来方便排查路径问题。我的习惯是这样demo/ index.html models/ my_model/ my_model.model3.json my_model.moc3 my_model.physics3.json my_model.motion3.json textures/ texture_00.png页面文件放根目录模型放在models/下。这样index.html里用相对路径./models/my_model/my_model.model3.json就能定位。SDK依赖先用CDN加载等demo跑通了再考虑打包成本或离线部署。不要一上来就把模型丢到对象存储或CDN上跨域配置还没弄明白的情况下本地文件路径是最容易验证的。file://打开页面也不行后面避坑部分会细说建议从第一步就用本地http服务跑。3.2 最小HTML页面代码下面这个页面能直接跑通一个Cubism 4模型的加载、显示和基本动画代码里我做了注释!DOCTYPE html html langzh-cn head meta charsetutf-8 titlehtml集成live2D demo/title style body { margin: 0; height: 100vh; overflow: hidden; background: #1f2933; } #app { width: 100vw; height: 100vh; } /style /head body div idapp/div !-- 先引入PixiJS得到全局 PIXI -- script srchttps://cdn.jsdelivr.net/npm/pixi.js6/dist/browser/pixi.min.js/script !-- 再引入pixi-live2d-display插件它会挂到PIXI.live2d下 -- script srchttps://cdn.jsdelivr.net/npm/pixi-live2d-display/dist/index.min.js/script script // 关键一步把Live2D的动画更新挂到PixiJS的Ticker上 window.PIXI.live2d.Live2DModel.registerTicker(PIXI.Ticker); // 创建PixiJS应用view指向页面上已有的div const app new PIXI.Application({ view: document.getElementById(app), autoStart: true, resizeTo: window, backgroundAlpha: 0 }); async function loadDemo() { const { Live2DModel } window.PIXI.live2d; const model await Live2DModel.from(./models/my_model/my_model.model3.json, { autoInteract: true }); app.stage.addChild(model); // 参数调整先缩放到视口的四分之一再居中显示 model.scale.set(0.4); model.anchor.set(0.5, 0.5); model.x app.screen.width / 2; model.y app.screen.height / 2; // 手动播放一个待机动作保证模型至少有一个可见动画 if (model.internalModel.motions) { model.motion(Idle); } } loadDemo().catch(error console.error(加载失败, error)); /script /body /html这段代码的逻辑是第一步引入PixiJS它提供Canvas/WebGL渲染器和舞台概念。第二步引入pixi-live2d-display它的UMD版本会把Live2DModel挂到window.PIXI.live2d下面。第三步通过registerTicker把Live2D内部的update循环和PixiJS的Ticker合并这样每一帧模型都会刷新动作。Live2DModel.from是核心入口传入模型配置文件的路径。第二个参数里autoInteract: true表示自动开启模型自带的交互响应比如点击模型时播放对应的Tap动作。addChild把模型放进PixiJS舞台之后就能用scale、anchor、x/y来控制显示。3.3 代码逻辑说明和参数scale、anchor、position、autoInteract上面代码里的几个参数是demo阶段最常调的scale.set(0.4)控制模型整体大小。不同模型作者的制作规模不一致有的模型原始尺寸是2048的贴图有的只有512所以不要硬编码一个普适的大小。我一般先把模型放到舞台上再根据app.screen.width和app.screen.height反推缩放比例。anchor.set(0.5, 0.5)设置模型的锚点位置。Live2D模型默认锚点通常在左下角或者脚下中心如果你直接设置x/y会发现模型跑到画布外面。把锚点设成中心再设置坐标模型就会以自身中心为基准居中。x和y可以直接用model.position.set(x, y)代替。注意这里的坐标是PixiJS舞台坐标不是CSS像素。如果你的画布有CSS缩放需要先换算。autoInteract这个参数很容易被忽略。它默认是true会让模型自动检测点击和拖拽。比如点击身体不同部位模型会触发HitAreas里定义的动作拖拽模型时它也会跟着鼠标移动。如果你只想要一个展示用模型不希望用户拖走把autoInteract设成false会更可控。3.4 跑通demo的验证标准怎么判断这次集成成功了不是控制台没有报错就行。我一般看三点一是模型贴图出现而不是只出现一个白色剪影。如果模型变形正常但没有贴图多半是纹理路径或跨域问题。二是呼吸动作存在。Live2D模型的呼吸动画通常默认在内部循环里只要没有手动关闭模型身体的起伏应该能看到。三是在Network面板里能看到model3.json、moc3、贴图文件都按顺序加载成功状态码是200。如果模型出现后完全静止优先检查motion调用。很多示例模型自带的动作组名不是Idle你需要打开model3.json的Motions部分看实际定义的动作组名称。直接写model.motion(Idle)之前先用console.log(model.internalModel.motions)把可用动作打印出来。4. 把demo做成可交互的看板娘点击、拖拽与多个模型切换4.1 给模型加点击区域并播放动作demo跑通之后下一步通常是让用户可以点击模型触发动作。pixi-live2d-display提供了hitTest方法它依赖模型配置文件里的HitAreas定义。比如model3.json里某个区域叫TapBody表示身体区域。代码这样写model.on(pointertap, (event) { // 把鼠标坐标转换成模型本地坐标再判断命中了哪个区域 const hit model.hitTest(event.data.global.x, event.data.global.y); if (hit 0) { console.log(你点击了区域索引, hit); model.motion(TapBody); } });event.data.global.x和y是鼠标在屏幕上的坐标hitTest会把它们转换成模型内部坐标返回命中的HitArea索引。如果返回-1表示没有命中任何区域点击就不会触发动作。model.motion(TapBody)播放的是model3.json里Motions组中名为TapBody的动作。这里经常遇到一个问题动作组名对不上。打开model3.json看Motions: { TapBody: [ { File: motions/tap_body.motion3.json } ] }动作组名是外层键不是文件名。所以传入model.motion(TapBody)而不是传入tap_body.motion3.json。如果你不确定有哪些动作组可以在控制台打印model.internalModel.motions。4.2 让模型能拖拽移动autoInteract开启后模型默认支持拖拽但那是模型自己实现的行为位置可能不合适。如果你想限制拖拽范围或者把拖拽和点击动作区分开就自己接管事件let dragging false; model.on(pointerdown, (event) { dragging true; event.stopPropagation(); }); window.addEventListener(pointerup, () { dragging false; }); window.addEventListener(pointermove, (event) { if (!dragging) return; model.position.set(event.clientX, event.clientY); });注意pointerdown注册在模型上pointermove和pointerup注册在window上这样鼠标移出模型再释放也不会卡住拖拽状态。position.set直接设置片段比单独改x和y更简洁。如果你希望拖拽时模型保持居中可以在每次移动时减去model.width / 2的偏移但这个偏移是实时计算的模型内部网格变形会影响bounds所以demo阶段直接以鼠标为中心拖拽就行。4.3 多模型切换动态加载和销毁页面里放一个按钮切换模型是很多demo的进阶需求。核心逻辑是销毁旧模型实例再加载新模型。不要忘了destroy否则旧模型的纹理、事件监听和动画循环会一直占用内存。let currentModel null; async function switchModel(modelUrl) { if (currentModel) { currentModel.destroy(); currentModel null; } const { Live2DModel } window.PIXI.live2d; const model await Live2DModel.from(modelUrl, { autoInteract: false }); app.stage.addChild(model); currentModel model; model.scale.set(0.4); model.anchor.set(0.5, 0.5); model.x app.screen.width / 2; model.y app.screen.height / 2; } // 示例点击按钮切换 document.getElementById(btn-switch).addEventListener(click, () { switchModel(./models/another_model/another.model3.json); });currentModel.destroy()会清理PixiJS显示对象但不会清理模型资源的全局缓存。如果你切换次数很多且发现内存不降需要再处理Live2DModel内部的模型缓存。demo阶段不用过度在意先保证切换不报错。4.4 调整显示参数scale、anchor、透明度、镜像不同模型的原始尺寸差异很大调试显示参数是绕不开的活。下面这几个参数在实际项目里最常用参数作用示例scale整体缩放模型model.scale.set(0.4, 0.4)anchor模型的定位基准点model.anchor.set(0.5, 1)表示底部中心position舞台坐标model.position.set(300, 500)alpha透明度model.alpha 0.85angle旋转模型model.angle -10alpha常用于聊天窗里的半透明虚拟形象angle用于角色入场动画。注意anchor改变后x和y的实际位置也会变化我建议先固定anchor再调位置否则会有一种模型在飘的感觉。镜像翻转可以用model.scale.x -0.4实现模型会左右镜像但贴图和动作方向也会反动作组里的位移同步反向。如果只是想让角色面向左边这是最快的办法但要注意文本、徽章等元素会被镜像。5. 集成过程中最容易翻车的5个坑5.1 坑一白屏控制台报 Live2DCubismCore is not defined现象页面打开后什么都没有控制台第一行报Live2DCubismCore is not defined或者直接抛错。原因Live2D的Cubism Core运行时没有在显示层库之前加载。pixi-live2d-display内部在加载模型时会去全局找Live2DCubismCore找不到就不继续执行。解决把Cubism Core的脚本标签放在pixi-live2d-display之前顺序是PixiJS、Cubism Core、插件。如果下载了本地核心文件用相对路径引入如果用CDN确认引入地址不需要额外的跨域前置条件。跑demo时最容易忽略的就是这个脚本顺序因为它不是语法错误只是运行时没找到全局对象。5.2 坑二模型加载成功但没有任何动画现象模型能显示身体纹丝不动连眨眼和呼吸都没有。原因有可能是模型配置里没有默认动作也有可能demo代码里调用了model.motion(Idle)但这个动作组在配置里不存在。pixi-live2d-display调用不存在的动作组名时不会报错只是什么都不播。解决打开model3.json找到Motions字段把动作组名逐一列出。然后在下拉事件里测试先触发动作A再触发动作B确认每个动作组都能播。呼吸动画通常内置在核心的自动更新里如果完全没呼吸检查是不是在初始化时误关了autoInteract或者手动调用了不会自动循环的动画。5.3 坑三模型位置偏移、超出屏幕或显示不全现象模型加载成功但它在页面左上角只看到一个角或者模型半边被裁掉。原因anchor没有设置模型默认锚点在左下角或脚底直接设置x/y后模型主体被推到屏幕外面。另外resizeTo: window虽然响应窗口尺寸但模型坐标是在初始化时设置的窗口变化后没有同步居中。解决把anchor.set(0.5, 0.5)放在x/y之前然后监听窗口resize事件window.addEventListener(resize, () { model.x app.screen.width / 2; model.y app.screen.height / 2; });如果要做更精细的布局建议写一个layoutModel()函数统一处理缩放和坐标在初始化、resize、切换模型时都调用它。血泪经验是demo做完后复制到另一个页面忘了改resize逻辑页面全屏后模型就飘到右边去了。5.4 坑四file://协议打开页面时纹理加载失败现象直接双击index.html模型报跨域错误或者纹理加载不了控制台出现类似CORS policy、Cross origin的提示。原因浏览器对file://协议下的Canvas读取和纹理加载有严格限制尤其是WebGL在加载本地贴图时不允许跨源读取。index.html通过file://访问模型配置里的texture_00.png也被当成跨源资源渲染失败。解决本地起一个静态http服务。最简单的用npxnpx http-server . -p 8080然后在浏览器打开http://localhost:8080。如果你用VSCode也可以装Live Server插件右键index.html选择Open with Live Server。不要再用file://打开demo否则后面怎么调都会卡在跨域这个假谜题上。5.5 坑五Cubism 2模型和Cubism 4核心不匹配现象加载模型时控制台出现类似MOC3 version mismatch、Invalid file format或者模型加载到一半消失。原因页面核心运行时是Cubism 4但模型是老的Cubism 2格式入口文件是model.json和.moc二者不兼容。部分windows整合包也会出现模型文件被二次打包.moc3文件损坏。解决先看模型目录入口文件。如果是model.json用Cubism 2核心如果是model3.json用Cubism 4核心。pixi-live2d-display支持两种核心但需要你正确加载对应的核心文件。如果你手头只有Cubism 4核心找一个官方Cubism 2示例模型来替换是最快的。不要去猜直接打开模型json看文件引用这个习惯能省很多时间。6. 收尾用性能面板和日志验证demo的加载耗时demo能跑起来之后别急着上线先花十分钟确认一下加载性能。最简单的方式是在Live2DModel.from前后各打一个时间戳const t0 performance.now(); const model await Live2DModel.from(modelUrl); console.log(模型加载耗时 ms:, (performance.now() - t0).toFixed(2));这个数值能直观反映模型文件大小、解码耗时和网络耗时。如果你发现加载耗时超过2秒先看是不是贴图太大、CDN太慢而不是盲目升级库版本。然后再看渲染性能。在Chrome开发者工具的Performance面板里录制几秒操作观察帧率。Live2D模型每一帧都需要在CPU端做网格变形再把顶点信息传到GPU所以模型数量越多、贴图越大帧率压力越明显。demo阶段控制在1到2个模型帧率低于40fps时就得考虑压缩贴图或减少动画节点的细节。我的习惯是每次改完代码都先清缓存刷新一遍看一眼Network里模型资源加载顺序再点几下模型确认交互最后再看Performance面板跑两秒。这套流程虽然枯燥但它能帮你把模型能显示和产品能上线这两件事区分开。以后你接手别人的Live2D项目遇到问题也知道从哪个面板入手而不是把xz代码翻个底朝天。希望帮到你。本文还有配套的精品资源点击获取