最近看到一个挺有意思的开源项目:DeskWorlds。
github 地址:github.com/chaseleantj...
它可以直接在电脑桌面上养鱼。
不是视频壁纸,而是一个实时运行的 3D 世界。
鱼会游,水草会动,鼠标靠近以后,鱼群还会有反应。

项目里还有 Coral Reef、Betta、Plasma Globe 几个世界。
image-20261006-200936
我之前正好一直想弄个桌面水族箱,工作累了偶尔看看。
但 DeskWorlds 的桌面版目前只支持 macOS。
我日常主要用 Windows。
那就复刻一个。
直接把 GitHub 地址扔给 ZCode,给了一个 Goal:
本次验证使用 ZCode。
原本我以为,接下来应该是:
分析 macOS 代码,然后重新写一个 Windows 版本。
但 ZCode 把项目拆完以后,先给出了一个挺关键的判断:
真正需要搬到 Windows 的,好像根本不是这缸鱼。
先把项目拆开
DeskWorlds 大概可以拆成三层。
• macOS 壁纸宿主
• 鱼缸场景的 Web 网页
• 各种元素的 3D 模型

我真正想要的部分,全在下面。
鱼、水草、沙床、沉木、珊瑚,包括鱼的动作和交互,实际上都运行在 Web 场景里。
macOS 负责的主要是另一件事:
把这个 Web 世界放到桌面上。
这样一拆,问题就完全变了。
一开始想的是:
怎么把一个
macOS应用改成Windows应用?
现在变成:
怎么让一个已经存在的 Web 3D 世界显示到
Windows桌面?
一下简单很多。
那 Windows 上,有没有现成的宿主?
既然核心已经是 Web 场景,那接下来其实只需要找一个东西:
能不能把网页放到 Windows 壁纸上?
然后 AI 就告诉我可以使用 Lively Wallpaper。
它本身就是 Windows 上的动态壁纸工具,而且支持网页壁纸。
按照 AI 的指导,我试了试。
第一步,先让 AI 启动 DeskWorlds:
启动应用
默认会跑在 8080 端口。
浏览器打开:
http://127.0.0.1:8080/scenes/riverscape/
鱼正常游。
水草正常动。
鼠标靠近以后也有反应。
第二步,把这个地址交给 Lively Wallpaper。
下载地址:
一路默认安装即可。
安装后新增壁纸,我的项目跑在远程台式机,所以网站地址是映射地址,复刻的话应该是上一步的 http://127.0.0.1:8080/scenes/riverscape/。

在列表里找到新的 riverscape,"设置为壁纸"。

然后,就可以看到效果了。

到这里,一开始的目标其实已经完成了。
没有重新做鱼。
没有重新做水草。
没有改 Three.js。
也没有重新开发一套 Windows 动态壁纸程序。
Lively 已经把"怎么成为 Windows 壁纸"这件事解决了。
中间踩了两个小坑
当然,也不是把 HTML 直接拖进去就完事。
第一个坑是本地文件不行。
DeskWorlds 使用了 ES Module 等现代 Web 能力,直接通过 file:// 打开,会遇到模块加载限制。
所以项目需要启动起来 Web 服务。
第二个坑更有意思。
项目里有专门给桌面宿主使用的 wallpaper.html。
一开始很自然地会觉得:
既然我要做壁纸,那当然应该加载这个。
结果页面出来了,鱼不动。
继续往下看才发现,wallpaper.html 本来就是给 macOS 宿主准备的。
它会等待宿主发送帧率、运行状态等指令。
Lively 并不知道 DeskWorlds 这套宿主协议。
所以最后直接使用普通预览场景,反而正常运行。
这个细节也进一步说明:
DeskWorlds 真正和 macOS 绑定的,只是最外面的宿主层。
为什么核心场景可以直接拿过来?
因为 DeskWorlds 本身就是基于:
Three.js + WebGL2。
WebGL 可以简单理解成让浏览器利用 GPU 实时绘制 3D 图形。
Three.js 则是在 WebGL 上面做了一层更方便使用的封装。
所以 DeskWorlds 更准确的理解不是:
一个 macOS 做的鱼缸。
而是:
一个运行在浏览器里的 3D 鱼缸,外面套了一个 macOS 壁纸宿主。
浏览器这一层本身就是跨平台的。
于是到了 Windows,只要换掉最外层宿主就行。
这也是为什么前面的鱼、水草、布景、动作基本都不用碰。
一条鱼,其实也没那么简单
因为不是 3D 相关专业的,我也顺便重新梳理了一下 3D 模型相关的知识点。
比如我们会直观地说:
找一条新的 3D 鱼替换进去。
听起来好像就是换个文件。
实际上没那么简单。
一条 3D 鱼至少会涉及几个东西。
• Mesh / Geometry,决定鱼长什么样。
• Material,决定表面质感。
• Texture,负责花纹和细节。
• 再加上光照。
最后才是我们真正看到的效果。

而且 DeskWorlds 里也不是所有东西都来自现成模型。
部分场景元素是程序生成的。
这就是比较常见的 Procedural Generation。
不是提前把每一块石头、每一棵水草都做好。
而是定义一套规则,让程序生成。
水草、石头、地形这类自然元素很适合这种方式。
因为自然世界本来就应该:
大体相似,但又没有两个完全一样。
鱼会摆尾,和鱼会"游"也是两回事
我给 ZCode 的 Goal 里专门强调了:
鱼的动作。
因为一个水族箱看起来自不自然,很大程度上不是模型的问题,而是鱼怎么动。
这里其实有两层。
鱼尾摆动、身体弯曲,是动画。
但为什么转向、为什么不撞在一起、为什么鼠标靠近以后会躲,这是行为。
简单说:
动画解决怎么动。
行为解决往哪里动。
鱼群会根据附近同伴、障碍物、边界、食物、外部刺激,不断调整下一步方向。
经典的 Boids 就是这一类群体行为思路。
这里不展开。
真正有意思的是:
开发者不需要提前写死每条鱼 10 秒以后出现在哪里。
只需要定义规则。
剩下的结果实时算出来。
所以 DeskWorlds 和普通视频壁纸最大的区别就是:
视频是在播放一个已经做好的世界。
它是在:
持续运行一个正在发生的世界。
那还能怎么玩?
既然是一个实时 3D 世界,后面其实还有不少可以继续尝试的方向。
最直接的就是换鱼。
比如换成自己喜欢的金鱼、斗鱼,重新搭一套水草和布景。
也可以继续改鱼的行为。
甚至接一点 AI,让 AI 负责更高层的状态和策略,具体怎么游,还是交给实时算法。
再往外一点,还可以让时间、天气甚至电脑状态影响这个小世界。
这些暂时都只是想法。
如果你也觉得这个鱼缸有意思,其实现在就可以先试一下:
• AI 帮你拉代码,跑起来
• 安装 Lively Wallpaper
• 再把 Web 地址丢进 Lively
然后,你就可以获得一个逼真的桌面鱼缸了。
AI Coding 现在确实越来越方便,但这次最大的收获反而不是"又写出了什么"。代码越容易写,动手前越值得先想清楚:这段代码,到底需不需要写。
国庆假期就要结束了,大家珍惜假期咯~