在 Astro 博客实现 Live2D 看板娘

1344 字
7 分钟
在 Astro 博客实现 Live2D 看板娘

前言#

在博客页面上添加一个 Live2D 看板娘,可以让网站更加生动有趣。本文介绍如何在 Astro 博客中使用 l2d-widget 库集成 Live2D 模型,支持 Cubism 2 和 Cubism 6 格式,实现菜单交互、提示气泡等功能。

为什么选择 l2d-widget#

传统的 Live2D 集成方案通常需要手动引入 Cubism SDK、编写渲染逻辑、处理动画状态机,代码量大且维护成本高。l2d-widget 是一个轻量级封装库,具有以下优势:

  • 开箱即用:只需一个函数调用即可完成集成
  • 双版本支持:同时兼容 Cubism 2(.moc)和 Cubism 4/6(.moc3)格式
  • 内置功能:菜单系统、提示气泡、多模型切换、响应式支持
  • 体积小:相比自行打包 SDK 方案,依赖更轻量

安装#

Terminal window
pnpm add l2d-widget

基本用法#

最简只需几行代码即可让 Live2D 模型出现在页面上:

import { createWidget } from "l2d-widget";
createWidget({
model: { path: "/models/snow_miku/model.json" },
position: "bottom-left",
size: { width: 200, height: 200 },
});

在 Astro 中集成#

本博客主题 Firefly 已经集成。

看板娘
看板娘

创建组件#

src/components/ 下创建 Live2DWidget.astro 组件:

可参考 Firefly 主题详细的 Live2DWidget.astro 组件文件。

---
interface Props {
config: {
enable: boolean;
model: { path: string; volume?: number; scale?: number; x?: number; y?: number }
| { path: string; volume?: number; scale?: number; x?: number; y?: number }[];
position?: "bottom-left" | "bottom-right";
size?: number | { width: number; height: number };
primaryColor?: string;
transitionDuration?: number;
transitionType?: "slide" | "fade";
menus?: {
items?: { icon?: string; label: string; action: string }[];
extraItems?: { icon?: string; label: string; action: string }[];
align?: "left" | "right";
};
tips?: {
welcomeMessage?: string[];
messages?: string[];
duration?: number;
interval?: number;
};
responsive?: {
hideOnMobile?: boolean;
mobileBreakpoint?: number;
};
};
}
const { config } = Astro.props;
// 构建模型配置,通过 data 属性传递到客户端
const models = Array.isArray(config.model) ? config.model : [config.model];
const modelConfigs = models.map((m) => ({
path: m.path,
...(m.volume !== undefined && { volume: m.volume }),
...(m.scale !== undefined && { scale: m.scale }),
...(m.x !== undefined && { x: m.x }),
...(m.y !== undefined && { y: m.y }),
}));
---
<div
id="l2d-widget-container"
style="position: fixed; z-index: 999;"
data-models={JSON.stringify(modelConfigs)}
data-position={config.position || "bottom-left"}
data-size={JSON.stringify(config.size || 300)}
data-primary-color={config.primaryColor || ""}
data-tips={JSON.stringify(config.tips || {})}
data-responsive={JSON.stringify(config.responsive || {})}
>
</div>

客户端脚本#

由于 Live2D 需要在浏览器中运行 WebGL 渲染,必须将初始化逻辑放在 <script> 标签中:

import { createWidget } from "l2d-widget";
// 菜单动作映射 - JSON 无法序列化函数,使用字符串标识符
const menuActions = {
home: () => (window.location.href = "/"),
scrollToTop: () => window.scrollTo({ top: 0, behavior: "smooth" }),
sleep: (widget) => widget.sleep(),
github: () => window.open("https://github.com/your-repo", "_blank"),
};
function initWidget() {
const container = document.getElementById("l2d-widget-container");
if (!container) return;
const models = JSON.parse(container.dataset.models || "[]");
const position = container.dataset.position || "bottom-left";
const size = JSON.parse(container.dataset.size || "300");
const tips = JSON.parse(container.dataset.tips || "{}");
if (models.length === 0) return;
const options = {
model: models.length === 1 ? models[0] : models,
position,
size,
};
// 配置提示气泡
if (tips.welcomeMessage || tips.messages) {
options.model.tips = {
welcomeMessage: tips.welcomeMessage,
messages: tips.messages,
duration: tips.duration,
interval: tips.interval,
};
}
createWidget(options);
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initWidget);
} else {
initWidget();
}

配置详解#

模型配置#

model: {
path: "/pio/models/live2d/snow_miku/model.json",
volume: 0, // 动作声音音量,0-1,默认 0(静音)
scale: 1, // 模型缩放比例
x: 0, // X 轴偏移
y: 0, // Y 轴偏移
}

支持传入数组配置多个模型,菜单中会自动出现切换按钮:

model: [
{ path: "/models/cat-black/model.json" },
{ path: "/models/cat-white/model.json" },
]

菜单系统#

l2d-widget 支持自定义菜单项。由于配置需要通过 HTML data 属性传递,而 JSON 无法序列化函数,所以采用 action 字符串 + 客户端映射 的模式:

配置端使用字符串标识:

menus: {
items: [
{ icon: "mdi:home", label: "返回主页", action: "home" },
{ icon: "mdi:arrow-up", label: "返回顶部", action: "scrollToTop" },
{ icon: "mdi:sleep", label: "休眠", action: "sleep" },
{ icon: "mdi:github", label: "GitHub", action: "github" },
],
align: "right",
}

客户端脚本中将字符串映射为实际函数:

const menuActions = {
home: () => (window.location.href = "/"),
scrollToTop: () => window.scrollTo({ top: 0, behavior: "smooth" }),
sleep: (widget) => widget.sleep(),
github: () => window.open("https://github.com", "_blank"),
};

提示气泡#

配置欢迎消息和循环提示:

tips: {
enable: true, // 气泡开关
welcomeMessage: ["你好!", "欢迎来到我的世界!"],
messages: ["有什么需要帮助的吗?", "今天天气真不错呢!"],
duration: 3000, // 每条提示展示时长(ms)
interval: 6000, // 提示循环间隔(ms)
offset: { x: 0, y: 0 }, // 位置偏移量(px)
}

主题色#

通过 primaryColor 设置菜单、状态条等 UI 元素的背景色,支持 CSS 变量:

primaryColor: "var(--primary)" // 跟随主题色
primaryColor: "rgba(96, 165, 250, 0.9)" // 固定颜色

入场动画#

transitionDuration: 1500, // 动画时长(ms)
transitionType: "slide" as const, // 动画类型:"slide" 或 "fade"

响应式#

在移动端隐藏看板娘:

responsive: {
hideOnMobile: true,
mobileBreakpoint: 768,
}

在布局中使用#

在主布局文件中引入组件:

---
import Live2DWidget from "@/components/features/Live2DWidget.astro";
import { live2dWidgetConfig } from "@/config/pioConfig";
---
<!-- 页面内容 -->
{live2dWidgetConfig.enable && <Live2DWidget config={live2dWidgetConfig} />}

完整配置示例#

export const live2dWidgetConfig = {
enable: true,
model: {
path: "/pio/models/live2d/snow_miku/model.json",
volume: 0,
scale: 1,
x: 0,
y: 0,
},
position: "bottom-left",
size: { width: 200, height: 200 },
primaryColor: "var(--primary)",
transitionDuration: 1500,
transitionType: "slide",
menus: {
items: [
{ icon: "mdi:home", label: "返回主页", action: "home" },
{ icon: "mdi:arrow-up", label: "返回顶部", action: "scrollToTop" },
{ icon: "mdi:sleep", label: "休眠", action: "sleep" },
{ icon: "mdi:github", label: "GitHub", action: "github" },
],
align: "right",
},
tips: {
enable: true,
welcomeMessage: ["你好!", "欢迎来到我的世界!"],
messages: ["有什么需要帮助的吗?", "今天天气真不错呢!"],
duration: 3000,
interval: 6000,
offset: { x: 0, y: 0 },
},
responsive: {
hideOnMobile: true,
mobileBreakpoint: 768,
},
};

注意事项#

  • 模型资源文件放在 public/ 目录下,路径以 / 开头
  • Cubism 2 模型文件为 .json + .moc,Cubism 6 为 .model3.json + .moc3
  • Live2D 渲染依赖 WebGL,确保目标浏览器支持

参考#

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!

赞助
在 Astro 博客实现 Live2D 看板娘
https://blog.cuteleaf.cn/posts/dev-notes/astro-live2d-mascot/
作者
夏叶
发布于
2026-05-20
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
夏叶
Hello, I'm XIAYE.
公告
欢迎来到我的博客,从2025年起,将会使用AI对文章进行润色。
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
60
分类
7
标签
44
总字数
35,568
运行时长
0
最后活动
0 天前

文章目录