- 桌面应用
- 前端
【免费下载链接】BongoCat
🐱 跨平台互动桌宠 BongoCat,为桌面增添乐趣!
BongoCat 是一款使用 Tauri 2 + Vue 3 + Live2D(Cubism)构建的开源跨平台互动桌宠,能够实时响应键盘、鼠标和手柄操作并驱动猫咪模型做出对应动作。本文以仓库 README.md 为主线,结合前端源码与 Rust 后端实现,完整讲解它的开发背景、核心交互链路、模型加载机制、窗口配置与跨平台打包方案,帮助你理解并复现这类桌宠应用的关键技术。
开发背景:从 Windows 独占到跨平台桌宠
BongoCat 的灵感来源于 Bongo-Cat-Mver 这一经典的猫咪互动桌宠。原版凭借独特的猫咪互动玩法深受用户喜爱,但仅支持 Windows 平台。为了在 macOS 上也能使用,作者决定开发适配 macOS 的版本,并进一步借助 Tauri 的跨平台能力,让同一套代码同时兼容 macOS、Windows 和 Linux(x11)。
这一背景直接决定了项目的几个关键设计取向:
- 跨平台一致的行为体验:键盘、鼠标、手柄输入在三个平台上都能驱动模型;
- 轻量的桌面壳:选择 Tauri 而非 Electron,前端资源由系统 WebView 承载,桌面端逻辑由 Rust 实现,应用体积与内存占用更小;
- 完全开源与离线可用:代码公开透明,运行不依赖网络。
技术栈与仓库结构总览
从前端依赖清单(package.json)可以看到项目的完整技术栈:
| 领域 | 技术选型 | 用途 |
|---|---|---|
| 桌面框架 | Tauri 2(@tauri-apps/api^2.10.1、@tauri-apps/cli^2.10.1) | 窗口管理、系统能力桥接 |
| 前端框架 | Vue 3(^3.5.32)+ Pinia(^3.0.4)+ vue-router + vue-i18n | UI、状态、路由与多语言 |
| Live2D 渲染 | easy-live2d(^0.4.4)+pixi.js(^8.18.1) | 模型加载、渲染与动作播放 |
| 输入监听(Rust) | rdev、gilrs | 全局键盘/鼠标、手柄事件捕获 |
| UI 组件 | antdv-next | 偏好设置界面 |
仓库核心目录如下:
- src/composables/useKeyPress.ts、src/composables/useGamepad.ts、src/composables/useModel.ts:前端输入与模型状态编排;
- src/utils/live2d.ts:Live2D 模型的加载、缩放、动作与参数控制;
- src-tauri/src/core/device.rs、src-tauri/src/core/gamepad.rs:Rust 侧全局输入监听;
- src-tauri/tauri.conf.json:窗口、安全与打包配置。
核心交互链路:键盘、鼠标、手柄如何驱动猫咪
README 中"根据键盘、鼠标或手柄的操作,同步对应的动作"是 BongoCat 的核心功能。这条链路在架构上分为三层:
1. Rust 后端:全局输入捕获与事件广播
后端使用rdev捕获全局键盘/鼠标事件,见 src-tauri/src/core/device.rs:
let callback = move |event: Event| { let device_event = match event.event_type { EventType::ButtonPress(button) => DeviceEvent { kind: DeviceEventKind::MousePress, value: json!(format!("{:?}", button)) }, EventType::ButtonRelease(button)=> DeviceEvent { kind: DeviceEventKind::MouseRelease, value: json!(format!("{:?}", button)) }, EventType::MouseMove { x, y } => DeviceEvent { kind: DeviceEventKind::MouseMove, value: json!({ "x": x, "y": y }) }, EventType::KeyPress(key) => DeviceEvent { kind: DeviceEventKind::KeyboardPress, value: json!(format!("{:?}", key)) }, EventType::KeyRelease(key) => DeviceEvent { kind: DeviceEventKind::KeyboardRelease, value: json!(format!("{:?}", key)) }, _ => return, }; let _ = app_handle.emit("device-changed", device_event); };关键点:
- 通过
start_device_listening命令启动监听(对应前端常量 src/constants/index.ts 中的START_DEVICE_LISTENING),使用AtomicBool保证监听只启动一次,避免重复注册; - 捕获到的事件统一通过 Tauri 的
emit以device-changed事件名推送到前端,事件类型枚举为MousePress / MouseRelease / MouseMove / KeyboardPress / KeyboardRelease。
手柄部分则由 src-tauri/src/core/gamepad.rs 基于gilrs实现,以start_gamepad_listing/stop_gamepad_listing两个命令控制启停,并将ButtonChanged、AxisChanged事件以gamepad-changed事件名推送到前端。
2. 前端监听:事件到 Live2D 参数的映射
前端通过useTauriListen订阅这两个事件。以手柄为例,src/composables/useGamepad.ts 会把摇杆与按键事件映射为模型参数:
- 左摇杆 X/Y →
CatParamStickLX/CatParamStickLY; - 右摇杆 X/Y →
CatParamStickRX/CatParamStickRY; - 左/右摇杆按下 →
CatParamStickLeftDown/CatParamStickRightDown; - 摇杆"是否接触"状态 →
CatParamStickShowLeftHand/CatParamStickShowRightHand; - 其余按键 → 按下时调用
handlePress(name),松开时调用handleRelease(name)。
模型参数通过 src/utils/live2d.ts 的setParameterValue写入:
public setParameterValue(id: string, value: number | boolean) { return this.model?.setParameterValueById(id, Number(value)) }3. 动作映射规则
键盘与鼠标的映射集中在 src/composables/useModel.ts:
- 左右手按下:
CatParamLeftHandDown/CatParamRightHandDown(handleKeyChange); - 鼠标左/右键:
ParamMouseLeftDown/ParamMouseRightDown(handleMouseChange); - 鼠标移动:根据光标在显示器上的比例位置,计算
ParamMouseX/Y、ParamAngleX/Y/Z、ParamEyeBallX/Y等参数,并通过getParameterValueRange读取模型参数范围做归一化映射(handleMouseMove)。
handlePress还会根据按键路径判断是否存在同手按键冲突,并自动释放上一键(findKey+handleRelease),保证猫咪左右手动作互不抢占。
Live2D 模型加载与渲染管线
模型的加载、渲染全部在前端完成,核心实现位于 src/utils/live2d.ts。
加载流程
public async load(path: string) { await this.initApp() this.destroy() const files = await readDir(path) const modelFile = files.find(file => file.name.endsWith('.model3.json')) if (!modelFile) throw new Error(i18n.global.t('utils.live2d.hints.notFound')) const modelPath = join(path, modelFile.name) const modelJSON = JSON5.parse(await readTextFile(modelPath)) const modelSetting = new CubismSetting({ modelJSON }) modelSetting.redirectPath(({ file }) => convertFileSrc(join(path, file))) this.model = new Live2DSprite({ modelSetting, ticker: Ticker.shared }) this.app?.stage.addChild(this.model) await this.model.ready // ...返回 width/height/motions/expressions }几个值得注意的实现细节:
- 渲染器:基于 Pixi.js 8 的
Application,画布为live2dCanvas,配置backgroundAlpha: 0实现透明背景、autoDensity+devicePixelRatio适配高分屏; - 模型目录识别:通过查找目录下
*.model3.json定位模型定义文件,并用JSON5解析(兼容带注释的模型配置); - 资源路径重定向:通过
redirectPath把模型内引用的贴图、表情等资源重定向为convertFileSrc生成的本地协议地址,从而支持从任意自定义目录加载模型; - 等比缩放:
resizeModel依据窗口与模型宽高比取min(scaleX, scaleY)居中放置模型,避免拉伸变形。
动作与表情
加载完成后会返回motions(按 group 分组)和expressions。startMotion以Priority.Normal播放动作,setExpression切换表情。值得注意的是,加载模型时会为每个动作/表情自动生成默认快捷键,见 src/composables/useModel.ts:按Command(macOS)/Control(其他平台)加上Shift/Alt的组合,依次分配数字键1-0与字母键QWERTYUIOPASDFGHJKLZXCVBNM。
全局快捷键与窗口行为
桌宠需要"藏起来也能唤起",因此项目使用了@tauri-apps/plugin-global-shortcut。封装的 src/composables/useKeyPress.ts 提供响应式快捷键绑定:
export function useKeyPress(shortcut: Ref<string | undefined, string>, callback: ShortcutHandler) { const oldShortcut = ref(shortcut.value) async function unbind() { if (!oldShortcut.value) return const registered = await isRegistered(oldShortcut.value) if (!registered) return return unregister(oldShortcut.value) } watch(shortcut, async (value) => { await unbind() if (!value) return await register(value, (event) => { if (event.state === 'Released') return callback(event) }) oldShortcut.value = value }, { immediate: true }) onUnmounted(unbind) }它实现了三个细节:配置变更时自动解绑旧快捷键、忽略按键释放事件、组件卸载时自动清理,避免全局快捷键泄漏。
透明桌宠窗口:Tauri 配置解析
BongoCat 的桌宠窗口是"透明、无边框、永远置顶、不占任务栏"的,这一整套行为在 src-tauri/tauri.conf.json 中配置:
{ "label": "main", "title": "BongoCat", "url": "index.html/#/", "shadow": false, "alwaysOnTop": true, "transparent": true, "decorations": false, "acceptFirstMouse": true, "skipTaskbar": true, "maximizable": false }参数含义:
| 参数 | 作用 |
|---|---|
transparent: true | 窗口背景透明,配合 Canvas 的backgroundAlpha: 0呈现"只有猫咪"的视觉效果 |
decorations: false | 去掉系统标题栏与边框 |
alwaysOnTop: true | 窗口始终位于最上层,猫咪随时可见 |
skipTaskbar: true | 不在任务栏/程序坞显示图标 |
shadow: false | 关闭窗口阴影,避免透明窗口出现黑边 |
acceptFirstMouse: true | macOS 下点击无焦点窗口时同时响应事件 |
项目还定义了一个隐藏的preference窗口(visible: false、minWidth: 800、minHeight: 600)用于承载偏好设置页面。macOS 上额外启用了macOSPrivateApi: true以获得透明置顶窗口所需的私有 API 能力。
自定义模型:格式、导入与转换
README 明确支持"导入自定义模型,自由打造专属猫咪形象",这与仓库内置的模型资源结构一致。以 src-tauri/assets/models 为例,每个模型目录包含:
cat.model3.json:模型入口定义(Cubism 3 模型描述文件);*.moc3:模型几何与骨骼数据;*.cdi3.json:模型参数/部件/表情的索引定义;*.1024/texture_*.png:贴图资源(1024×512 的标准贴图尺寸);*.motion3.json与*.flac:动作文件及其配音;live2d_expression*.exp3.json、exp_*.exp3.json:表情定义。
内置了standard、keyboard、gamepad三套模型,对应不同输入模式的演示资源(见 tauri.conf.json 的resources配置将assets/models打包进应用)。
对于从 Bongo-Cat-Mver 带来的旧模型,README 提供了在线模型转换工具(BongoCat 社区维护的转换服务),可将 Bongo-Cat-Mver 应用的模型转换为兼容 BongoCat 的格式后导入使用。同时社区仓库Awesome-BongoCat收录了大量可下载的猫咪模型,也欢迎提交自己的创作与大家分享。
下载、安装与跨平台打包
获取安装包
安装包通过两个渠道分发:夸克网盘与 GitHub Releases;不确定该下载哪个平台版本时,可参照 README 中附带的下载指南。macOS、Windows、Linux(x11) 三平台均有对应安装包。
打包目标
从 tauri.conf.json 的bundle.targets可以看到各平台打包产物:
"targets": ["nsis", "dmg", "app", "appimage", "deb", "rpm"]- Windows:NSIS 安装包;
- macOS:dmg 磁盘映像与 app 目录;
- Linux:AppImage、deb、rpm 三种格式。
应用还启用了@tauri-apps/plugin-updater(createUpdaterArtifacts: true),内置自动更新能力,更新端点配置在plugins.updater.endpoints中,支持按current_version、target、arch动态拼接更新地址。
本地开发
仓库使用 pnpm 管理依赖(preinstall强制only-allow pnpm),常用脚本见 package.json:
pnpm dev # 开发模式:先构建图标再启动 Vite(devUrl: http://localhost:1420) pnpm build # 依次执行 vite build、图标构建等 pnpm tauri # 调用 Tauri CLI pnpm lint # eslint --fix 自动修复 srcRust 侧在 src-tauri/src/core/mod.rs 中聚合了device、gamepad、prevent_default、setup四个模块,setup模块按平台区分 macOS 与其它系统的初始化逻辑(见 src-tauri/src/core/setup/mod.rs)。
隐私与离线:数据边界承诺
README 明确列出两条重要承诺:
- 完全开源,代码公开透明:桌面端 Rust 源码(
src-tauri/)与前端源码(src/)全部开放,可审计; - 绝不收集任何用户数据 + 支持离线运行:输入监听仅用于驱动本地模型动画,事件在本地经 Tauri 事件总线流转后直接映射为 Live2D 参数,不涉及任何网络上报;模型、贴图、动作文件均打包在应用内(
assets/models),离线即可运行。
从代码实现看,输入事件只被用于设置 Live2D 参数(setParameterValue),没有发现任何数据外发逻辑,与 README 的隐私承诺一致。
社区生态与参与贡献
BongoCat 围绕桌宠形成了一个小生态:官方维护的模型转换工具降低旧模型迁移成本,Awesome-BongoCat 模型仓库提供更多形象与投稿渠道,社区交流通过 QQ 群进行。想要参与开发贡献的读者,可先阅读 README 中的贡献指南,再结合本文提到的 src/composables 与 src-tauri/src/core 源码深入理解各个模块的实现。
从本文可以看到,BongoCat 的"猫咪会跟着你的操作动起来"这一体验,本质上是一条清晰的管道:Rust 侧用rdev/gilrs捕获全局输入 → 通过 Tauri 事件推送到 Vue 前端 → 前端把按键、摇杆、光标坐标映射为 Live2D 参数 →easy-live2d在 Pixi.js 透明画布上实时渲染。理解这条链路后,你不仅掌握了 BongoCat 的完整工作原理,也获得了一套"全局输入驱动透明桌面动画"的可复用架构思路,可以迁移到其它桌面互动应用(如宠物、通知助手、动态图标)的开发中。
- 桌面应用
- 前端
【免费下载链接】BongoCat
🐱 跨平台互动桌宠 BongoCat,为桌面增添乐趣!
相关推荐
BongoCat:跨平台桌面萌宠新体验,键盘鼠标互动全解析
BongoCat:跨平台桌面萌宠新体验,键盘鼠标互动全解析 引言:告别单调的桌面交互 你是否已经厌倦了冰冷的桌面环境?当你在键盘上敲击代码、鼠标上滑动浏览时,是
桌面应用N_m3u8DL-RE完整指南:点播与直播都收的 DASH/HLS/MSS 流媒体下载器
N_m3u8DL RE完整指南:点播与直播都收的 DASH/HLS/MSS 流媒体下载器 N_m3u8DL RE 是一款跨平台流媒体下载器,解析 DASH、HL
CLI音视频AIRI 桌宠跨屏鼠标注视:Live2D 焦点坐标的跨平台计算实战
AIRI 桌宠跨屏鼠标注视:Live2D 焦点坐标的跨平台计算实战 本文依据 AIRI 项目官方 DevLog(2025.06.08)整理而成。AIRI 是一款
AI 应用人工智能大模型数字人AI Agent语音前端后端桌面应用移动开发即时通讯3D渲染
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考