
这是一篇不太正经的技术文章。
如果你期待的是"如何提升工作效率"——出门左转,我之前写了两篇正经的,总共三万多字,够你看一晚上。
这篇要讲的是一个售前打工作之余做的、跟效率毫无关系、甚至有点浪费时间的东西——
那是去年冬天的一个晚上,大概11点半。
我刚改完一份方案的第7版PPT,眼睛酸得像泡过醋。关掉PPT的那一刻,屏幕暗了一下——macOS桌面空荡荡的,Dock栏安静地缩在底部,就剩几个冷冰冰的文件图标和一张已经看了两年的壁纸。
就在那一瞬间,脑子里突然蹦出一个莫名其妙的想法:
"如果我的桌面上能有个小东西就好了。不用干什么正事,就是……待在那儿。我累了的时候它能动一下,我开心了它能跟着开心一下。"
然后第二个念头紧跟着来了:
"等等,我不是正在搞WorkBuddy吗?这玩意儿能不能帮我做一个?"
那天晚上我没继续改PPT。
我打开编辑器,写下了这个项目的第一行代码:
# 龙虾宠物 v0.0.1
# 一个疯狂的深夜决定
print("🦞 Hello, World!")当时的我完全没想到,这个"深夜摸鱼产物",半年后会被我写成一篇参赛文章。
先上主菜。
这是我在腾讯云轻量服务器部署的龙虾,过去的使用方式是网页+钉钉,说实话有点生硬

现在它就默默呆在我电脑角落里,随时唤醒他

原谅我的直男审美,当然了,可以随时调用workbuddy的专家中心的设计师给他重新设计一套皮肤

核心视觉特征:
元素 | 设计 | 为什么这么设计 |
|---|---|---|
主体 | 一只Q版熊猫(非写实,偏科技) | it从业者要炫酷 |
配色 | 霓虹色系(青色/品红/电光蓝) | 赛博朋克感 + 桌面上够显眼 |
光效 | 边缘发光 + 呼吸灯效果 | "活着"的感觉 |
大小 | 约 120×120 像素 | 不遮挡工作内容,但足够可爱 |
透明背景 | PNG透明通道 | 融入桌面,不是悬浮窗口 |
其实workbuddy的设计专家还给我处理很多效果图,我可以随时更换

其实
设计理念一句话:它是你桌面上的一个小生命,不是一个软件窗口。


每个状态都有独立的动画序列。 不是贴图切换——是真正的逐帧动画,带缓动曲线,看着很自然。
好,外观介绍完了。现在讲最好玩的部分——这只赛博龙虾到底能干什么。
状态名 | 触发条件 | 行为表现 | 音效/特效 | |
|---|---|---|---|---|
1 | 🦞 空闲(Idle) | 无操作超过3分钟 | 桌面随机漫步+观察四周 | 轻轻的脚步声 |
2 | 💼 工作(Working) | 检测到键盘/鼠标活跃 | 安静待机+探头看进度 | 打字音(轻微) |
3 | 😊 开心(Happy) | 完成任务 / 收到正面反馈 | 转圈+吐泡泡+发光 | 欢快的音效 |
4 | 😵 错误(Error) | 命令执行失败/报错 | 翻白眼+冒烟+抖动 | "duang~" 失败音 |
5 | 😴 困倦(Sleepy) | 凌晨以后还在工作 | 打哈欠+眼皮打架+倒下 | 哈欠声 |
6 | 🔥 兴奋(Excited) | 连续完成多个任务 | 高速转圈+烟花粒子 | 燃烧音效+BGM |
7 | ⏰ 提醒(Reminder) | 设定的提醒时间到了 | 弹窗挡住屏幕(很欠揍) | 提示音 |
8 | ❤️ 撒娇(Clingy) | 你太久没理它了 | 追着鼠标跑+弹气泡求关注 | "嗯~"的声音 |
8个状态,每个都是独立设计的动画和行为逻辑。 不是简单的A/B切换,而是有过渡动画、有随机变化、有"性格"在里面。
下面挑几个最有意思的展开讲:
而且每次开心的"激烈程度"是不一样的:
情绪等级 | 触发条件 | 表现差异 |
|---|---|---|
⭐ 微笑 | 完成一个小任务 | 微微发光+小幅度摇摆 |
⭐⭐ 高兴 | 完成中等任务 / 被夸奖 | 转圈+吐少量泡泡 |
⭐⭐⭐ 超级开心 | 完成大项目 / 连续夸奖 | 全套连招+粒子烟花+变色 |
⭐⭐⭐⭐ 狂欢 | (隐藏触发)连续工作后准时下班 | 全屏庆祝动画+特殊BGM |
是的,它有一个隐藏的"狂欢模式"。 触发条件嘛——留个悬念,后面讲。
为什么这么设计?
因为我觉得——AI工具最让人抓狂的不是报错本身,而是报错时的冷漠。
终端里一行红色的 ERROR,冷冰冰的,没有任何情感。但如果你桌上有个小龙虾,它在帮你执行命令,失败了之后翻白眼、冒黑烟、还抖两下——
你就不那么想砸键盘了。
甚至会笑出来:"哎呀,小龙虾也翻车了哈哈哈。"
然后心情好一点,重新试一次。
这就是情绪价值。 一个会跟你一起翻车的宠物,比一个永远正确的工具有温度得多。
这是龙虾被吐槽最多的功能——也是我个人觉得最实用的功能。
背景: 我设置了"连续工作90分钟自动提醒休息"。
然后某天下午我在赶方案,完全忘记了时间。写到投入处,忽然——

你的所有工作内容被一只龙虾盖住了。什么都干不了。
除非你点"去休息"或者"稍后再说"。
第一次看到这个的时候我愣了两秒,然后笑喷了——这也太霸道了吧?!
但说实话——真的有效。 因为普通的系统提示你可以无视、可以最小化、可以让它在角落里自生自灭。但当整只龙虾跳到你屏幕中央的时候,你不得不停下来跟它交互。
而一旦你停下来点了"稍后再说"——哪怕只是这几秒钟的中断——你的大脑就已经从"深度沉浸模式"里被拽出来了。
这时候你会意识到:"哦,确实坐了好久了。站起来走走吧。"
这就是设计意图:用一种有趣但不失强制力的方式打断你的沉浸式工作循环。
后来我还加了一些细节:
提醒时机 | 龙虾台词 | 备注 |
|---|---|---|
工作90分钟 | "该休息了!你已经工作很久了!" | 标准提醒 |
工作120分钟 | "你还不累吗??我都困了 💤" | 加重语气 |
工作180分钟 | "大哥/大姐……你是铁打的吗" | 语气开始无奈 |
凌晨0点后 | "……你确定还要继续吗" | 不再霸道,变成温柔关心 |
凌晨2点后 | 直接播放一段轻音乐 + 屏幕色调变暖 | 强制温柔模式 |
越晚越温柔。 因为我深知凌晨两点还在工作的售前不需要一个聒噪的宠物——需要的是一句安静的"早点休息吧"。
如果说前面的动画让龙虾好看,那语音交互让它好用。
全局快捷键 Cmd+Shift+L(L = Lobster,很好记):
我的赛博龙虾-小熊猫开始跳动起来,并且出现happy的表情

然后你说话。说完松开快捷键,它开始处理。
来,感受一下日常使用场景:
场景1:查待办
你:(按下 Cmd+Shift+L)我今天还有什么待办?
龙虾:(停顿1秒处理)好的老板!你今天的待办有这些:
🔴 [高优先] XX集团方案初稿 —— 截止今天下午6点
🟡 [中] 给客户回邮件确认演示时间
🟢 [低] 团队周报(周五再写也行)
一共3件事,最重要的是方案初稿哦~ 要加油!💪注意那个语气词"哦~"和"💪"——这是龙虾的人设。它不是一个冷冰冰的语音助手,它是一个有点话痨的小助手。
场景2:快速记录灵感
你:(按下 Cmd+Shift+L)记一下,客户说他们想要一个
能在手机上看的实时大屏
龙虾:记下来啦!
📝 新增备忘:
· 内容:客户需求 - 移动端实时大屏查看
· 时间:刚刚
· 关联客户:XX集团(自动识别上下文)
已写入记忆系统 ✅场景3:纯粹聊天(摸鱼时刻)
你:(按下 Cmd+Shift+L)我好累啊
龙虾:(沉默0.5秒……)
那给你讲个冷笑话吧?
问:龙虾最喜欢的数学符号是什么?
……
答:是"夹"(夹角)!因为龙虾有大大的钳子呀~ 🫠
(龙虾说完自己吐了个泡泡,像是在为自己的冷笑话感到尴尬)
……不好笑吗?那我再来一个?内置了一个笑话库。 专门用于用户明确表示"我很累""我不开心""烦死了"这类情绪低谷时刻。
而且笑话的质量——怎么说呢——以"让人无语到忘记烦恼"为核心KPI。有时候烂到你会忍不住笑出声:"这什么破笑话哈哈哈哈。"
然后你就真的没那么累了。
这就是设计哲学:与其试图真正解决你的疲劳(它做不到),不如用一种轻松的方式让你从负面情绪里抽离出来一分钟。这一分钟可能就够了。

(不想看技术细节的同学可以跳过这节)
语音交互的技术栈:
你的声音
↓
macOS 系统语音识别(Speech Framework)
↓
文字文本
↓
WorkBuddy AI 处理(理解意图 + 生成回复)
↓
回复文本
↓
macOS TTS 文字转语音(系统自带语音包)
↓
龙虾"说话" + 同步口型动画关键设计决策:
决策点 | 选择 | 原因 |
|---|---|---|
语音识别引擎 | macOS原生Speech Framework | 免费无需网络延迟低 |
唤醒方式 | 全局快捷键(非语音唤醒) | 避免误触+"龙虾"这个词太难发音一致 |
语音合成 | 系统TTS + 自定义语速/音调 | 让声音听起来更像"角色"而非机器 |
口型动画 | 基于音素级别的简单映射 | 不需要精确对口型,只要嘴巴在动就行 |
离线能力 | 识别+基础回复可离线 | 网络断了也能用基础功能 |
整个语音交互的响应延迟大约在1-2秒。 按下快捷键到龙虾开始"说话",差不多就是自然对话中的停顿节奏——不会让你觉得等了很久,也不会快得不自然。
好了,好玩的部分展示完了。现在来点有料的部分。
(放心,不会变成枯燥的技术文档。我会用人话讲。)
┌─────────────────────────────────────────────┐
│ 🦞 龙虾宠物系统架构 │
├─────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 渲染层 │ │ 状态机 │ │ 交互层 │ │
│ │ (View) │ │ (State) │ │(Input) │ │
│ ├──────────┤ ├──────────┤ ├──────────┤ │
│ │·动画系统 │ │·8种状态 │ │·快捷键 │ │
│ │·粒子特效 │ │·状态转换 │ │·语音识别 │ │
│ │·透明窗口 │ │·情绪模型 │ │·鼠标事件 │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ ┌────▼─────────────▼─────────────▼─────┐ │
│ │ 核心调度器 (Core) │ │
│ │ · 主循环 60fps │ │
│ │ · 状态协调 │ │
│ │ · 事件总线 │ │
│ └──────────────────┬──────────────────┘ │
│ │ │
│ ┌──────────────────▼──────────────────┐ │
│ │ WorkBuddy Skill 接口层 │ │
│ │ · memory-manager 记忆读写 │ │
│ │ · 命令执行代理 │ │
│ │ · oepnclaw-Gateway 接口 │ │
│ └──────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────┘三层架构,各管各的事:
三层之间通过事件总线通信,互不直接耦合。
为什么要分层? 因为一开始我没分层。
最开始所有的逻辑都塞在一个文件里——渲染代码旁边就是状态判断,状态判断旁边就是键盘监听。能跑,但是加第三个功能的时候就开始乱了。
后来重构成了现在的架构,每加一个新功能只需要:
三层各改各的,互不影响。
这是整个系统最核心也最有趣的部分。
# 伪代码:状态机简化示意
class LobsterStateMachine:
# 状态定义
states = ["idle", "working", "happy", "error",
"sleepy", "excited", "reminder", "clingy"]
# 状态转换规则(关键!)
transitions = {
# 从 idle(空闲)可以转到:
"idle": {
"user_active": "working", # 用户开始操作 → 工作状态
"long_idle": "clingy", # 太久没理 → 撒娇模式
"task_done": "happy", # 任务完成 → 开心
"late_night": "sleepy", # 深夜了 → 困了
},
# 从 working(工作)可以转到:
"working": {
"user_stop": "idle", # 用户停手了 → 空闲
"task_success": "happy", # 任务成功 → 开心
"task_error": "error", # 任务失败 → 翻车
"work_90min": "reminder", # 工作90分 → 强制提醒
},
# 从 error(错误)可以转到:
"error": {
"retry_success": "excited", # 重试成功 → 超级开心(补偿心理)
"retry_error": "idle_depressed", # 继续失败 → 颓废
"timeout": "idle", # 超时恢复 → 空闲
},
# ... 其他状态的转换规则
}
# 还有"情绪强度"参数
emotion_intensity = 0.0 # 0.0 ~ 1.0
# 影响行为表现的剧烈程度
# 比如 happy 状态下:
# intensity 0.3 → 微微发光
# intensity 0.7 → 转圈+泡泡
# intensity 1.0 → 全套连招+烟花状态机的精髓在于"转换规则"。 不是任何状态都能转到任何其他状态的——必须符合逻辑:
这样龙虾的行为才是可预测但又带点意外的。 你大致知道它下一步会做什么,但具体什么时候做什么又有随机性。这种感觉——很像养真宠物。
很多人问:"你的动画是怎么做的?帧动画?骨骼动画?还是实时渲染?"
答案可能让你失望:最简单的方式——Sprite Sheet(精灵图帧动画)。
制作流程:
1. 用设计工具(Figma/Illustrator)画出龙虾的每一帧
· idle状态:8帧(一个完整的呼吸+微移动循环)
· walk状态:12帧(迈步动画)
· happy状态:24帧(转圈+泡泡的完整连招)
· error状态:16帧(翻白眼→冒烟→抖动→恢复)
· ...每种状态独立的帧序列
2. 导出为 Sprite Sheet(精灵图集)
┌────────────────────────────────────┐
│ frame1 │ frame2 │ frame3 │ frame4 │ ← 一张大图
│ frame5 │ frame6 │ frame7 │ frame8 │ 包含所有帧
│ frame9 │ frame10│ ... │ ... │
└────────────────────────────────────┘
3. 代码中按固定间隔切换帧(60fps下约每2-3帧切换一张sprite)
4. 加入缓动曲线(easing)让动作不那么机械
· 不是匀速播放 → 而是"快-慢-快"的自然节奏
· 起步加速 → 中间均速 → 结束减速为什么不用更高级的技术?
原因很朴实:
方案 | 优点 | 缺点 | 我的评估 |
|---|---|---|---|
实时3D渲染 | 最灵活 | 开发量大,性能消耗高 | 杀鸡用牛刀 |
骨骼动画(Spine) | 流畅自然 | 需要额外工具链和学习成本 | 对当前规模过剩 |
Lottie矢量动画 | 缩放不失真 | 复杂动画支持有限 | 可考虑未来迁移 |
Sprite Sheet帧动画 | 简单可靠 | 帧数多时文件略大 | ✅ 当前最佳选择 |
对于一只120×120像素的桌面宠物来说,帧动画完全够了。 每个状态十几到二十几帧,全部加起来的图片资源不到2MB。
做得好≈用最合适的技术,而不是最新的技术。
这部分可能是全文最有共鸣的章节。
因为——谁做开发没踩过坑呢?区别只在于:有的人踩完了忘了,我把它们全记下来了。
预期:龙虾显示在一个透明背景的窗口上,完美融入桌面。
现实:窗口是透明了——但点击事件也被透明了。也就是说龙虾"后面"的桌面区域仍然可以接收鼠标点击,导致你经常点穿了龙虾点到后面的图标。
现象:
你想拖动龙虾到另一个位置
→ 点击龙虾
→ 点穿了!!点到了龙虾后面的文件夹!!
→ 文件夹打开了
→ 你:???解决方案:macOS 的 NSWindow 有一个属性叫 ignoresMouseEvents——但我们要的反过来的效果。最终通过设置透明的 hitTest 区域解决了:
// 只让龙虾本体区域接收鼠标事件,透明部分穿透
override func hitTest(_ point: NSPoint) -> NSView? {
// 检测点击位置是否在龙虾图像的非透明区域内
if lobstersBodyFrame.contains(point) {
return self // 点到龙虾本体 → 响应
}
return nil // 点到透明区域 → 穿透到下层窗口
}耗时排查:3小时。 其中2小时在怀疑人生。
预期:Cmd+Shift+L 全局生效,在任何App中都能唤醒龙虾。
现实:在某些应用中快捷键完全无效。尤其是终端和一些IDE。
调试过程:
Day 1:在自己写的测试App里 → ✅ 正常
Day 2:在Safari里 → ✅ 正常
Day 3:在VS Code里 → ❌ 没反应
Day 4:在终端里 → ❌ 还是没有
Day 5:发现有些App会注册相同或相似的快捷键
Day 6:改成 Cmd+Ctrl+Shift+L(四个键!)→ ✅ 全局生效
Day 7:四个键太难按了,换了个思路
最终方案:使用 macOS 的 CGEvent tap 机制
+ 选择一个极少冲突的组合键
+ 失败时提供备用方案(菜单栏图标点击)教训:全局快捷键是个"看似简单实则巨坑"的功能。如果你的应用也需要全局快捷键——一定要充分测试各种App场景,不要只在自已的应用里测。
预期:按下快捷键 → 说话 → 松开 → 龙虾回应。
现实:很多时候按下快捷键后环境噪音被当成语音输入了——键盘声、窗外车声、甚至是呼吸声。
翻车现场:
你:(按下快捷键)(敲击键盘搜索资料)
龙虾:(认真听...)
龙虾:你刚才说的是 "嗒嗒嗒嗒嗒-回车-嗒嗒" 吗?
你:......解决方案:
第三条改动之后,误触发率下降了大概80%。 因为用户能看到龙虾在"录音",就不会在按住快捷键的时候顺便敲键盘了。
预期:长期运行稳定,内存占用恒定。
现实:运行一天之后,内存占用从 50MB 涨到了 800MB。
排查过程:
打开 Instruments(macOS性能分析工具)
→ 发现 Animation Layer 在不断创建但不释放
→ 每次状态转换都新建一组 Layer
→ 但旧的状态 Layer 没有正确销毁
原因:Swift 的 ARC(引用计数)在某些循环引用场景下
不会自动释放内存
修复:手动管理动画层的生命周期
+ 在状态切换时主动清理旧的动画资源
+ 使用对象池(Object Pool)复用常用动画元素
修复后:连续运行48小时,内存稳定在60-80MB ✅这个坑教会我一个道理:即使是"小程序",也要关注内存管理。 桌面宠物是那种用户开了就不关的应用——可能连续运行几天甚至几周。这种场景下的内存泄漏比普通应用致命得多。
这个不算bug算feature,但确实是从一个bug演变来的(前面第三章讲过)。
原始设计意图:空闲状态时龙虾应该在屏幕上均匀随机漫步。
实际情况:有一版代码里的"随机目标点选择算法"有个偏差——它选择目标点的时候,鼠标当前位置的权重被错误地设高了(本意是让龙虾偶尔对鼠标产生好奇,结果权重太高导致一直在追)。
发现之后的第一反应是修bug。
但看着它追鼠标跑了二十秒——我突然觉得这特有意思。
于是没有修。而是把这个"bug"正规化了:
# 最终版的"好奇心算法"
def select_target_position(current_pos, mouse_pos, curiosity_level):
"""
curiosity_level: 0.0 ~ 1.0
0.0 = 完全随机漫步(不关心鼠标)
1.0 = 100%追鼠标(撒娇模式满级)
正常情况 curiosity_level = 0.1(偶尔瞥一眼鼠标)
长时间无交互后逐渐升至 0.8(开始追着跑)
用户有任何操作后立即降回 0.1
"""
if random() < curiosity_level:
# 有概率选择鼠标方向
return add_noise(mouse_pos, noise_radius=50)
else:
# 正常随机
return random_point_on_screen()所以这确实是一个"把bug变成feature"的真实案例。 而且变成了最受欢迎的功能之一。
好,看了这么多——你可能手痒了。
这一章教你自己造一个。 不用龙虾,不用赛博朋克风——就从最简单的东西开始:
一只会在桌面上来回走的小猫/小狗/任何你喜欢的东西。
我们用 Python + PyQt6 来实现。原因:
# 安装PyQt6
pip install PyQt6
# 确认安装成功
python -c "from PyQt6.QtWidgets import QApplication; print('OK')"如果输出 OK 就说明环境没问题。
创建文件 my_pet.py:
import sys
from PyQt6.QtWidgets import QApplication, QLabel, QWidget
from PyQt6.QtCore import Qt, QTimer
from PyQt6.QtGui import QPixmap, QColor
class DesktopPet(QWidget):
def __init__(self):
super().__init__()
# === 窗口基本设置 ===
self.setWindowTitle("我的桌面宠物")
# 设置窗口为无边框 + 始终置顶 + 透明背景
self.setWindowFlags(
Qt.WindowType.FramelessWindowHint | # 无边框
Qt.WindowType.WindowStaysOnTopHint | # 置顶
Qt.WindowType.Tool # 不在任务栏显示
)
# 透明背景(关键!)
self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
# 窗口大小
self.setFixedSize(120, 120)
# 初始位置(屏幕右下角)
from PyQt6.QtWidgets import QApplication
screen = QApplication.primaryScreen().geometry()
self.move(screen.width() - 150, screen.height() - 150)
# === 创建标签显示内容 ===
self.label = QLabel("🐱", self)
self.label.setStyleSheet("""
font-size: 80px;
background-color: transparent;
""")
self.label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.label.setGeometry(0, 0, 120, 120)
# === 移动相关变量 ===
self.dx = 2 # x方向移动速度
self.dy = 1 # y方向移动速度
# === 定时器:每30ms更新一次位置(约33fps)===
self.timer = QTimer(self)
self.timer.timeout.connect(self.update_position)
self.timer.start(30)
# 显示窗口
self.show()
def update_position(self):
"""更新宠物位置(实现来回走的动画)"""
# 获取当前位置
x = self.x()
y = self.y()
# 获取屏幕尺寸
from PyQt6.QtWidgets import QApplication
screen = QApplication.primaryScreen().geometry()
max_x = screen.width() - 120 # 减去窗口宽度
max_y = screen.height() - 120 # 减去窗口高度
# 更新位置
new_x = x + self.dx
new_y = y + self.dy
# 边界检测:撞墙就反弹
if new_x <= 0 or new_x >= max_x:
self.dx = -self.dx # 反转X方向
new_x = max(0, min(new_x, max_x))
if new_y <= 0 or new_y >= max_y:
self.dy = -self.dy # 反转Y方向
new_y = max(0, min(new_y, max_y))
# 移动窗口
self.move(new_x, new_y)
# === 启动应用 ===
if __name__ == "__main__":
app = QApplication(sys.argv)
pet = DesktopPet()
sys.exit(app.exec())python my_pet.py你应该能看到:
┌──────────────┐
│ │
│ 🐱 │ ← 一只Emoji小猫!
│ │ 在你的桌面上!
│ │ 来回走!
│ │ 碰到边就反弹!
└──────────────┘恭喜!你刚刚用不到70行代码做出了一个桌面宠物的雏形! 🎉
有了基础版之后,你可以逐步添加功能:
# 把 Emoji 替换为自定义图片
self.label = QLabel(self)
pixmap = QPixmap("my_cat.png") # 你的宠物图片,建议PNG透明背景
self.label.setPixmap(pixmap.scaled(120, 120))
self.label.setGeometry(0, 0, 120, 120)# 在类中添加以下方法
def mousePressEvent(self, event):
"""鼠标按下:记录起始位置"""
if event.button() == Qt.MouseButton.LeftButton:
self.drag_start_pos = event.globalPosition().toPoint() - self.frameGeometry().topLeft()
def mouseMoveEvent(self, event):
"""鼠标移动:拖拽窗口"""
if hasattr(self, 'drag_start_pos'):
new_pos = event.globalPosition().toPoint() - self.drag_start_pos
self.move(new_pos)def mousePressEvent(self, event):
"""鼠标点击事件"""
if event.button() == Qt.MouseButton.RightButton:
# 右键弹出菜单
from PyQt6.QtWidgets import QMenu, QAction
menu = QMenu(self)
exit_action = QAction("退出 🐱", self)
exit_action.triggered.connect(app.quit) # 注意:app要是全局可访问的
menu.addAction(exit_action)
menu.exec(event.globalPosition().toPoint())
elif event.button() == Qt.MouseButton.LeftButton:
self.drag_start_pos = event.globalPosition().toPoint() - self.frameGeometry().topLeft()def mouseDoubleClickEvent(self, event):
"""双击切换不同表情"""
import random
emojis = ["🐱", "😸", "😹", "🙀", "😻"]
current = random.choice(emojis)
self.label.setText(current)你现在在这里(刚做完的MVP):
🐱 透明窗口 + 来回走 + 可拖拽
↓
下一步(花一个周末):
🐱💬 加上状态切换 + 多组表情 + 右键菜单
↓
再下一步(花一到两周):
🐱🎤 加上语音交互 + 快捷键 + 基础命令处理
↓
进阶(持续迭代):
🐱✨ 粒子特效 + 完整动画系统 + 个性化皮肤
↓
最终形态(也就是我现在的龙虾):
🦞🌟 完整8状态 + 语音交互 + WorkBuddy集成 + 自动化联动关键心得:每一步都能用。 不用等到"最终形态"才发布——第一版只有来回走的猫咪就已经可以在朋友圈装一波了 😎
这部分纯属脑洞。但万一哪天有人想做"桌面宠物2.0"呢——这里有一些方向可以参考。
你的龙虾能跟别人的龙虾"认识"。
场景设想:
你和同事都在用龙虾宠物
两台电脑在同一个WiFi下
两只龙虾可以互相"看到"对方(在屏幕边缘冒个头)
互动方式:
· 你的龙虾可以走到屏幕边缘"拜访"同事的龙虾
· 可以一起"玩"(同步做一些动画)
· 可以"传递消息"(一只龙虾吐泡泡给另一只)
· 同事不在座位时,他的龙虾会显得"孤单"技术上可行性很高——局域网UDP广播就能实现基本的"存在感知"。剩下的就是创意问题了。
让龙虾学会"技能",就像游戏里那样。
概念:
龙虾本体 = 基础框架(动画+状态+语音)
技能插件 = 可安装的功能扩展包
示例技能:
├── skill-github → GitHub通知(有PR/Issue时龙虾告诉你)
├── skill-calendar → 日程提醒(会议前15分钟龙虾提醒你)
├── skill-weather → 天气播报(每天早上龙虾告诉你今天天气)
├── skill-music → 音乐控制(语音说"放首歌"龙虾调用音乐App)
├── skill-pomodoro → 番茄钟(龙虾陪你专注25分钟+休息5分钟)
└── skill-custom → 用户自己写的任意技能...
安装方式:
"帮我的龙虾安装天气播报技能"
→ 自动下载skill-weather
→ 龙虾学会了一项新本领本质上就是把 WorkBuddy 的 Skill 系统移植到了桌面宠物上。 龙虾不只是宠物——它是你桌面上所有AI能力的统一交互入口。
龙虾随着使用时间推移会"长大"、"进化"。
成长维度:
📈 等级系统
Lv.1 卵(刚出生) → 只有一个呆萌的蛋
Lv.2 幼虾 → 会走会看
Lv.3 成虾(当前) → 全部功能解锁
Lv.4 ???? → 待设计...
🎨 外观进化
使用时长 > 7天 → 解锁新的配色方案
使用时长 > 30天 → 解锁装饰配件(小帽子/围巾/眼镜框)
使用时长 > 90天 → 解锁稀有皮肤(全金龙虾???)
🧠 性格养成
如果你经常在夜间工作 → 龙虾变成"夜猫子"型(白天懒洋洋晚上精神)
如果你经常让它执行任务 → 龙虾变成"工作狂"型(催你干活)
如果你经常跟它闲聊 → 龙虾变成"话痨"型(更多随机台词)让每只龙虾都不一样。 你的龙虾就是你的龙虾——带着你的使用习惯和个人印记。
回到最开始的问题:
"一个天天写标书做方案的售前,为什么花了半年时间做一只桌面宠物?"
正经的回答是:这是学习 WorkBuddy Skill系统和 macOS 开发的绝佳练手项目。 过程中掌握的技术点(状态机设计、动画系统、快捷键全局监听、语音集成)后来都用在了正经的工作Skill上。
不正经的回答是:
因为工作是一场马拉松,不是百米冲刺。
我们这些人——做售前的、做实施的、做开发的、做产品经理的——每天都在高强度运转。赶方案、见客户、回邮件、开会、写周报、填报表……
有时候真的很累。不是身体累——是心累。是一种"今天干了好多事情但又好像什么都没推进"的无力感。
在这种时候,如果桌面上有个小东西——
在你连续工作了两个小时之后弹出来说该休息了;
在你命令执行失败的时候陪你一起翻白眼冒黑烟;
在你深夜还在赶工的时候不再霸道催你而是温柔地放一首轻音乐;
在你实在撑不住的时候给你讲一个烂到让人笑出来的冷笑话——
哪怕只是一只虚拟的龙虾,哪怕它什么都不懂,但它在那里。
这就够了。
"工作是给人看的。宠物是给自己看的。"
偶尔让自己开心一下,不丢人。
🦞 如果你也想做属于自己的桌面宠物——
今天就可以开始。 复制第七章的那70行代码,跑起来,然后一点一点地加上你自己的想法。
不必做成龙虾。做一只猫、一条狗、一只史莱姆、一个像素小人、甚至一团会变形的果冻——随你喜欢。
重要的是开始。
如果这篇让你笑了至少一次,欢迎 点赞👍 在看⭐ 转发🔄!
评论区留言 "🦞我也想要" ,我把完整的龙虾宠物源码整理出来分享给大家!(目前还在整理中,感兴趣的话人多我就加快进度~)
有问题评论区交流,每一个我都会回~
> 写到这里,我的桌上的龙虾刚好从睡眠状态醒来,伸了个懒腰,吐了个泡泡。
> 它好像在说:"写完了?该休息了吧。"
> 好的。晚安,小家伙。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。