从零做一个桌面宠物:Electron + AI + Live2D 全流程踩坑实录
一个程序员周末的作死记录:用 Electron 做透明悬浮窗,AI 生成角色立绘,Live2D 做骨骼动画,最后拼成一个能在桌面上呼吸眨眼的桌面宠物。
为什么是桌面宠物?
没什么崇高理由。就是想让自己的桌面不那么死板。
桌宠这个概念其实很老了 — 90 年代 Windows 上的 BonziBuddy、千禧年的桌面猫娘、后来的 Shimeji。但说实话,大部分桌宠要么丑,要么重,要么功能蠢。我想做一个极简版的:
- 透明背景,浮在所有窗口之上
- 几个基本状态:待机、眨眼、歪头、睡觉
- 视频驱动,不跑 3D 引擎
- 代码量尽量少
技术选型很快定了:Electron + 纯 HTML/JS。不需要 React 不需要 Vue,一个 <video> 标签加状态机就够了。
第一步:Electron 透明窗口
核心其实就几行配置:
// main.js
const win = new BrowserWindow({
width: 320,
height: 320,
transparent: true,
frame: false,
alwaysOnTop: true,
skipTaskbar: true,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
},
});
transparent: true 加 frame: false 就能得到一个无边框透明窗口。再配上 alwaysOnTop: true,桌宠就永远浮在最上层了。
CSS 里把 body 背景设为 transparent,视频元素用 object-fit: contain,一个透明悬浮窗就出来了。
状态机也很简单 — 一个对象存所有状态,切状态时 fade out → 换视频 → fade in。鼠标事件绑定单击/双击/长按,时间检查器每分钟跑一次判断是不是该睡觉了。
整个 renderer.js 加起来不到 200 行。 架构对了,复杂度自然就低了。
第二步:视频素材 — 这才是真正的坑
代码写完了,发现没素材。
桌宠要的不是一张静态图 — 是一段有透明通道的循环视频。技术要求很明确:
- 格式:WebM (VP9, Alpha) — Electron 原生支持,透明通道好
- 分辨率:320×320 或 512×512
- 帧率:24-30fps
- idle/sleep 3-5 秒循环,blink 0.3-0.5 秒,tilt 1-2 秒
问题来了:这种素材哪来的?
三条路:
- 找现成的 GIF/WebM — 能找到,但风格不对,分辨率低,不一定有透明通道
- AI 生成动态视频 — 可灵、Runway 能生成,但角色一致性差,没法精确控制每个状态
- Live2D 手工做 — 工作量最大,但效果最好,状态切换最丝滑
我选了 Live2D。理由很简单:桌宠需要多个独立状态的精确控制,Live2D 天生就是干这个的。
第三步:Live2D 需要分层立绘
Live2D 不是扔一张图进去就能动的。它需要角色各部件独立分层:
后发 → 身体 → 脸部 → 眼睛 → 嘴巴 → 腮红 → 侧发 → 前发/刘海
每个部件单独一层 PNG,导入 Live2D 后绑定骨骼和参数,才能做出呼吸、眨眼、歪头这些动画。
这是一个很有门槛的流程。 你要么:
- 自己用 PS 分层(需要画功)
- AI 生成(需要好工具)
- 找现成 Live2D 模型(最省事但没个性)
第四步:AI 抠图的残酷真相
我手上有一张 Q 版立绘,决定试试 AI 抠分层。
用了 AutoGLM 的 Image Edit API,逐层给 prompt:“Keep ONLY the front bangs, remove everything else”、“Keep ONLY the body/clothing”…… 跑了 8 轮,每轮 20 秒左右,拿到了 8 张分层图。
结果呢?
| 层 | 结果 |
|---|---|
| 后发 | ✅ 可用,边缘干净 |
| 脸部 | ✅ 基本可用 |
| 身体 | ⚠️ 白底没抠干净 |
| 刘海 | ⚠️ 脸部区域没掏空 |
| 侧发 | ⚠️ 白底没抠干净 |
| 眼睛开 | ⚠️ 白底没抠干净 |
| 腮红 | ❌ 变成了完整合成图 |
| 闭眼 | ❌ 变成了闭眼版全身图,不是单独眼睛层 |
8 层里只有 2 层直接能用。 核心问题:
- 白底替代透明 — AI 编辑接口输出 JPG,直接丢失 alpha 通道。部分层白底像素没抠掉
- 该掏空的没掏空 — 刘海中间应该有脸部窗口,AI 直接把脸也保留在刘海层里了
- 指令理解偏差 — “keep only the eyes” 在 AI 眼里可能是”保留眼睛区域不变”而不是”只输出眼睛”
结论:通用 AI 图片编辑工具对 Live2D 精确分层来说还不够靠谱。 它们擅长的是风格迁移、背景替换这类大范围操作,不是像素级的精确分层。
正确的路应该怎么走?
根据这次踩坑经验,如果重新来过,我会这么选:
路线 A:ComfyUI + LayerDiffuse(推荐)
ComfyUI 本地跑,装 LayerDiffuse 插件,社区有现成的 Live2D 分层工作流。输出直接是带透明通道的 PSD,各部件独立图层。
优点:免费、本地运行、分层质量高、无审查限制 缺点:需要 8GB+ 显存、有一定配置门槛
路线 B:找现成模型(最快)
Booth.pm、DLsite 上有大量免费 Live2D 模型,很多带完整骨骼和动画。下载导入直接用。
优点:零成本零时间 缺点:没个性、版权灰色
路线 C:用官方示例跑通流程(学习用)
Live2D Cubism 自带示例模型,先把整个工具链跑通,再换自己的素材。
优点:学 Live2D 的最佳方式 缺点:做不出自己的角色
最终架构
代码层面的架构其实很简洁:
config.js ← 所有状态定义、触发规则、视频路径
renderer.js ← 状态机 + 事件处理 + 视频切换
style.css ← 透明背景 + fade 过渡
main.js ← Electron 透明无边框窗口
视频状态切换的核心逻辑:
用户触发(鼠标/时间)→ 状态机判断 → fade out 当前视频
→ 替换 <video> src → fade in 新视频 → 播完/循环
扩展性很好 — 想加新状态?在 config.js 里加一个对象,renderer.js 自动识别。想接外部控制?window.VideoState.switchTo('wave') 一行搞定。
这件事教会我什么
- 架构决定复杂度。200 行 JS 能搞定桌宠,是因为一开始就把”视频驱动”和”配置分离”想清楚了
- AI 不是万能的。通用 AI 编辑工具对精确分层力不从心,专用工具(ComfyUI + LayerDiffuse)才是正解
- 素材才是桌宠项目的核心工作量。代码半天写完,素材可能要花一周
- 透明通道是永远的痛。JPG 没有透明通道,WebM VP9 Alpha 兼容性一般,MP4 HEVC Electron 不支持……选对格式能少踩一半的坑
下一步
如果你也想做一个桌宠,我的建议是:
- 先用现成 Live2D 模型跑通整个 Electron + 视频切换流程
- 再考虑自己做角色(ComfyUI + LayerDiffuse)
- Live2D 里做好各状态的 PNG 序列帧
- FFmpeg 转成 WebM VP9 Alpha(一行命令的事)
做个桌宠不难,难的是让它活起来。
💬 访客留言
无需登录,直接留言 👇