Desk Pet 3D 是一个面向 Windows x64 的开源 3D 桌面宠物应用程序。它使用透明、无边框、始终置顶的窗口展示可动画 3D 模型,同时提供像素级点击穿透、鼠标交互、托盘菜单、JSON 配置和图形化配置创建器。
AI 实现声明: 本项目的应用程序代码与工程文档由 OpenAI Codex(GPT-5.6 Sol) 在人类主导的产品设计、需求评审和测试验证下实现。
- 使用 C99、raylib 6.0、cJSON 和 Win32 API 实现,仅面向 Windows x64。
- 模型窗口透明、无边框、始终置顶,不显示在任务栏或 Alt+Tab 列表中。
- 透明像素区域支持点击穿透,只有鼠标位于模型实体上时才响应交互。
- 左键拖动桌宠位置,右键旋转模型,滚轮缩放,中键恢复初始旋转和缩放。
- 支持随机 IDLE、拖动 MOVE、左键单击和双击动画,并支持动画间隔、平滑过渡和独立动画资源文件。
- 支持保存模型旋转、缩放和窗口位置,并在下次启动时恢复。
- 提供中文图形化配置创建器,基础用户无需直接编辑 JSON。
- 托盘菜单提供模型信息、帮助、关于和退出功能;菜单打开时模型动画不会暂停。
- 应用图标、关于页面图片、GPL 正文和第三方许可声明均嵌入 EXE。
- raylib 与 cJSON 通过固定版本的 Git submodule 联合构建,便于复现构建结果。
- Git
- Visual Studio Build Tools,包含 x64 C/C++ 工具链
- Windows SDK
- CMake 3.16 或更高版本
克隆仓库时应同时初始化 submodule:
git clone --recurse-submodules https://github.com/woooooooooolf/deskpet3d.git
cd deskpet3d
git submodule update --init --recursive执行 Release 构建:
build.bat构建产物位于:
build\deskpet3d.exe
也可以为“特别版”构建增加一个会显示在“关于”窗口标题后的 Unicode 名称:
build.bat "特别版名称"辅助窗口采用轮廓拖动:按住标题栏时,真实窗口保持原位,只以默认 30 Hz 更新一个不接收输入的轻量边框;松开鼠标后真实窗口一次性移动并重绘。该定时器和轮廓窗口只在拖动期间存在,不影响窗口静止期间的 CPU/GPU 占用,也不会修改 Windows 全局的“拖动时显示窗口内容”设置。需要比较更高轮廓更新率时,可使用第二个构建参数:
build.bat "特别版名称" 60PowerShell 用户可以直接执行:
.\build.ps1 -EditionName "特别版名称" -CustomDragHz 60程序接收一个 JSON 配置文件路径:
build\deskpet3d.exe config\raylib_robot.json也可以直接把 JSON 文件拖放到 deskpet3d.exe 图标上。正常启动会通过短生命周期的引导进程创建独立 GUI 进程,因此关闭原来的 Command Prompt 或 PowerShell 窗口不会终止桌宠。
直接双击 EXE 且不提供 JSON 时会打开中文 Startup 窗口,可以进入“创建配置”“帮助”或“关于”。这使用户即使还没有模型和配置文件,也能了解用法并创建第一份配置。
仓库内的 config/raylib_robot.json 使用 raylib submodule 自带的 robot.glb,初始化 submodule 后即可用于验证。该配置的 saved_state.valid 默认是 0,首次启动会采用配置中定义的初始状态。
| 操作 | 功能 |
|---|---|
| 左键单击 | 从 CLICK 动画列表中随机选择一段完整播放 |
| 左键双击 | 从 DOUBLE CLICK 动画列表中随机选择一段完整播放 |
| 左键拖动 | 移动桌宠窗口;实际拖动持续超过 500 ms 后,可循环播放随机 MOVE 动画 |
| 右键拖动 | 旋转模型 |
| 鼠标滚轮 | 缩放模型,放大上限受模型旋转包围范围和窗口尺寸共同保护 |
| 中键单击 | 恢复 JSON 中定义的初始旋转和缩放 |
| 托盘图标右键 | 打开模型信息、帮助、关于和退出菜单 |
模型窗口使用低分辨率 Alpha 掩码判断可交互像素。透明区域中的鼠标事件会传递给桌面或下层应用程序,模型可见区域才会接收上述操作。input.hit_test_fps、input.hit_test_downsample 和 input.hit_test_alpha_threshold 可用于平衡命中精度与资源消耗。
启用双击动画时,程序会按 Windows 的系统双击时间和距离判断连续点击,因此单击动画最多会延迟一个系统双击判定周期。点击动画可以被新的单击或双击动画覆盖,也可以被拖动触发的 MOVE 动画打断;MOVE 结束后会重新进入 IDLE。点击动画正常结束后先等待 idle_interval_seconds,再恢复随机 IDLE。
直接双击 deskpet3d.exe,然后选择“创建配置”。创建器可以:
- 选择 GLB/glTF、IQM、M3D、OBJ 或 VOX 模型;
- 读取所选模型内置的动画名称和索引;
- 分别多选最多 32 个 IDLE、MOVE、单击和双击动画;
- 设置
animation_blend_seconds控制动画切换的平滑过渡时间; - 设置模型显示比例、窗口尺寸、锚点、帧率、命中检测和托盘图标等参数;
- 使用四列动画选择和双列参数布局,无需滚动窗口即可访问全部配置项;
- 对所有可编辑数值执行范围检查;
- 将模型和 ICO 路径尽可能保存为相对 JSON 文件的相对路径;
- 以 UTF-8 原子写入 JSON,并使用与主程序相同的解析器重新验证。
创建器生成的是单模型基础配置。需要独立动画文件、具名动画源或更复杂规则时,可以继续手动编辑 JSON。
下面是一个不依赖仓库测试模型名称的基础示例:
{
"model": {
"path": "../assets/character.glb",
"idle_animations": ["Idle", "Wave"],
"move_animations": ["Walk"],
"click_animations": ["React", "Wave"],
"double_click_animations": ["Dance", "Jump"],
"animation_fps": 30.0,
"idle_interval_seconds": 2.0,
"animation_blend_seconds": 0.12,
"height_fraction": 0.92,
"width_fraction": 0.92,
"vertical_offset_fraction": 0.0,
"initial_yaw": 0.0,
"initial_pitch": 0.0,
"initial_zoom": 1.0,
"min_zoom": 0.35,
"max_zoom": 3.0
},
"window": {
"width": 300,
"height": 420,
"anchor": "bottom_right",
"offset_x": -24,
"offset_y": -24,
"target_fps": 60
},
"input": {
"rotation_speed": 0.35,
"zoom_speed": 0.12,
"hit_test_fps": 30,
"hit_test_downsample": 2,
"hit_test_alpha_threshold": 16
},
"tray": {
"icon": "../assets/character.ico"
},
"saved_state": {
"valid": 0
}
}所有相对模型、动画和托盘图标路径均以 JSON 文件所在目录为基准解析,而不是以当前工作目录为基准。tray.icon 可以指定外部 .ico;路径为空、文件不存在或格式无效时会回退到内嵌的 assets/deskpet3d.ico。托盘提示文字固定为 Desk Pet 3D,不能通过 JSON 修改。
窗口锚点支持 bottom_right、bottom_left、top_right、top_left 和 center,偏移量在锚定之后应用。
GLB/glTF 是本项目推荐并重点验证的动画模型格式。raylib 6.0 还可以通过 LoadModelAnimations() 从 IQM 和 M3D 加载骨骼动画。OBJ 和 VOX 可用于静态模型,但不能通过该接口提供动画片段。当前程序支持骨骼变换动画,不支持 Morph Target 或材质动画。
Windows 下的 raylib 文件读取已通过应用层回调转换为 UTF-16,因而 GLB/glTF、IQM、M3D、VOX、独立动画源以及 glTF 外部 buffer/纹理可以放在含中文、空格、括号或 Emoji 的路径中。动画模型仍推荐使用与 JSON 同目录部署的单文件 GLB,它对路径兼容和资源完整性最稳定。
OBJ 是已知例外:raylib/tinyobj 的外部 MTL 和纹理读取仍可能经过窄字符文件 API,因此不能保证 Unicode 目录中的完整 OBJ 资源链可用。拆分的 .gltf + .bin + 图片 必须保留所有文件并准确匹配 URI;百分号编码 URI、NFC/NFD 等 Unicode 规范化差异、Windows 非法或保留文件名以及所有超长路径情形不在当前兼容承诺内。手动编辑 JSON 时,反斜杠必须写为 \\,也可以使用 /。建议始终使用相对 JSON 的简单资源文件名。
默认情况下,动画从 model.path 加载。模型和动画分开保存时,可以配置 1 至 16 个 model.animation_sources:
"model": {
"path": "../assets/character.glb",
"animation_sources": [
{ "id": "base", "path": "../assets/character.glb" },
{ "id": "motions", "path": "../assets/character_motions.glb" }
],
"idle_animations": [
{ "source": "base", "name": "Idle" },
{ "source": "base", "name": "Wave" }
],
"move_animations": [
{ "source": "motions", "name": "Walk" },
{ "source": "motions", "index": 1 }
],
"click_animations": [
{ "source": "motions", "name": "React" }
],
"double_click_animations": [
{ "source": "motions", "name": "Dance" }
]
}动画项可以使用名称、从零开始的索引,或者包含 source 与 name/index 的对象。程序会调用 raylib 的骨架兼容性检查过滤动画;raylib 6.0 的公开检查主要比较骨骼数量,因此资产制作者仍需保证骨骼顺序和语义一致。
IDLE 列表为空时不调度待机动画。列表有效时,程序随机选择一个动画完整播放,然后保持末帧并等待 idle_interval_seconds,再选择下一段动画;有多个选项时会避免立即重复。MOVE、CLICK 或 DOUBLE CLICK 列表为空、缺失或没有兼容动画时,对应交互不会切换当前动画。
click_animations 和 double_click_animations 使用与 MOVE 相同的动画项语法。点击动作一次性完整播放,结束后进入 IDLE 等待;新点击动作可以覆盖正在播放的点击动作,MOVE 则可以打断任意点击动作。animation_blend_seconds 的有效范围为 0..1 秒,默认值为 0.12;程序使用 raylib 6.0 的 UpdateModelAnimationEx() 在旧姿态和新动画之间混合,并同时使用小数帧插值。设置为 0 可关闭切换过渡。
加载模型时,程序根据模型 AABB 的旋转半径和 window.width、window.height 计算一次固定的旋转安全缩放上限。之后旋转模型不会自动改变当前缩放,滚轮放大则同时受该安全上限和 model.max_zoom 限制。
model.min_zoom 始终作为缩放下限。如果 JSON 设置的窗口过小,无法同时满足缩放下限和完整旋转包围范围,程序会保留下限并允许边缘裁切,而不会继续强制缩小模型。
saved_state 由程序管理。将 saved_state.valid 设置为 0,可以忽略历史状态并使用模型默认旋转、缩放和窗口锚点:
"saved_state": {
"valid": 0
}完成旋转、缩放或窗口移动后,程序会写入 yaw、pitch、zoom、window_x 和 window_y。异常、越界或完全位于屏幕外的状态会被拒绝,程序将恢复默认状态并尽力把字段更正为 {"valid": 0}。只读文件和其它写入失败会被静默忽略。
模型绘制与 Alpha 掩码读取采用内容驱动策略。动画姿态、旋转、缩放或重置发生变化时才标记内容需要更新;静态 IDLE 间隔会复用上一帧,不重复绘制模型,也不重复执行 GPU 到 CPU 的掩码读取。
鼠标、托盘和 Win32 消息仍按 window.target_fps 持续处理,因此静态节能不会阻塞交互。托盘弹出菜单运行在短生命周期的 UI 辅助线程中,保持菜单打开不会阻塞模型动画、渲染或输入轮询。
Release 构建会静态链接 raylib、cJSON 和 Microsoft C Runtime(/MT)。EXE 内嵌默认图标、关于页面图片、GPLv3 正文和第三方许可声明,不需要项目专用 DLL、Visual C++ Redistributable、许可文本或关于页面图片作为运行时旁文件。
模型、JSON、外部纹理、独立动画文件以及 JSON 指定的个性化 ICO 仍是外部资产。对于内嵌纹理和动画的 GLB,最小部署形式是:
deskpet3d.exe
configuration.json
character.glb
推送与 CMakeLists.txt 版本一致的 V*.*.* 标签时,GitHub Actions 会在 Windows x64 环境中执行全新构建并创建 Release。工作流只上传形如 deskpet3d_v1.1.1_windows_amd64.exe 的单文件二进制;源码 ZIP/TAR 由 GitHub 根据标签自动生成,不再重复打包。GitHub 自动源码包不展开 submodule 内容,需要完整构建环境时应使用 git clone --recurse-submodules。
- Windows 10 x64 或 Windows 11 x64
- 支持 OpenGL 3.3 或更高版本的显卡驱动
- 不需要单独安装 Visual C++ Redistributable
Windows 7 和 Windows 8.1 已结束生命周期,本项目不支持也不测试这些系统。底层 raylib/GLFW 可能仍包含旧系统兼容路径,但这不构成产品级兼容性保证。
deskpet3d/
|-- assets/ # 内嵌图标和关于页面图片
|-- config/ # 可运行的 raylib robot 示例配置
|-- docs/ # 开源合规说明
|-- src/ # C99 与 Win32 源码
|-- test/ # 静态、运行时和生成物检查
|-- third_party/
| |-- raylib/ # raylib 6.0 submodule
| `-- cjson/ # cJSON v1.7.19 submodule
|-- CMakeLists.txt
|-- build.bat
`-- build.ps1
执行完整回归测试:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\test\run_all.ps1只执行静态检查:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\test\static_checks.ps1测试用例、执行方式和 Windows 自动化中的已知注意事项记录在 test/TEST_CASES.md。
欢迎提交可复现的错误报告、范围明确的功能建议和经过验证的 PR。请先阅读 CONTRIBUTING.md 与 SUPPORT.md,安全漏洞按照 SECURITY.md 私密报告,参与行为遵循 CODE_OF_CONDUCT.md。
项目由人类确定需求方向,并主要依赖 OpenAI Codex(GPT-5.6 Sol) 实现;后续 Issue 分析、开发、测试和文档迭代也会继续使用 AI。请勿提交秘密、个人敏感信息、保密资料或无权分享并交由 AI 处理的素材。
受维护精力和项目计划限制,我们无法保证及时回复、实现、Review 或合并,对可能造成的等待深表歉意,也感谢你的理解。
Desk Pet 3D 的需求方向、产品设计和验收反馈由项目设计者提供;应用程序代码、构建系统、测试工具和工程文档由 OpenAI Codex(GPT-5.6 Sol) 根据这些要求实现。本声明用于透明披露 AI 在项目中的实质性实现角色,不改变项目文件的 GPL-3.0-only 许可,也不替代人工评审、测试和发布责任。
Desk Pet 3D 自有源代码、构建脚本和文档采用 GNU General Public License version 3 only,SPDX 标识为 GPL-3.0-only。使用、修改和再发布时必须遵守 GPLv3,并按要求提供对应源代码。本软件不提供任何担保。
- raylib 6.0 使用 zlib/libpng 许可证。
- cJSON v1.7.19 使用 MIT 许可证。
assets/deskpet3d.ico是项目自有素材,随项目以 GPL-3.0-only 发布。assets/codex.png与assets/raylib.png用于归属展示,其产品名称、标志和商标权利仍归各自权利人所有。
完整第三方声明见 THIRD_PARTY_NOTICES.txt,发布合规清单见 docs/OPEN_SOURCE_COMPLIANCE.md。
Thanks to the raylib project.
Thanks to the cJSON project.