月读空间,终于有自己的原生 App 了
从一个网页,到真正属于月读空间的跨平台客户端。
很早之前我其实就有一个想法:
月读空间不能永远只存在于浏览器里。
网页当然很好。
打开链接就能使用,不需要安装,也不需要考虑平台。但随着月读空间不断加入 Room、八千代、长期记忆、Live2D、Agent、音乐、游戏、图库、创作工具等功能,浏览器本身也逐渐开始成为一种限制。
所以,这次我做了一件一直都很想做的事情:
给月读空间做一个真正的原生 App。
项目现在已经开源:
目前版本为 0.6.4 测试版。
这不是把网页塞进一个 App
先说最重要的一点。
月读空间 App 不是 Electron 套网页,也不是简单在 WebView 里面打开 yachiyo.hk。
整个客户端使用 Flutter 重新实现。
Room、文章、广场、个人中心、成长系统、Wiki、图库、投稿编辑器、游戏、设置、Live2D 等主要界面,都拥有独立的 Flutter 实现。
它依然连接现有的月读空间后端,因此你的:
- 月读空间账号
- 文章
- 评论与留言
- 收藏
- 成长数据
- 聊天记录
- 长期记忆
- 日记
- 通知
都可以继续使用。
换句话说:
网页和 App 并不是两个月读空间,而是同一个月读空间的两种入口。
客户端负责提供更接近桌面软件和移动应用的体验,网站则继续承担开放访问和服务端能力。
为什么要做原生客户端?
原因其实不只是“做个 App 看起来更完整”。
真正让我决定重新实现客户端的,是月读空间正在做的很多东西,本身就越来越不像一个传统博客网站。
Room 已经不只是一个聊天页面
现在的 Room 同时包含:
- AI 对话
- Live2D 角色
- 长期记忆
- 日记
- 知识库
- 图片消息
- TTS 语音
- 音乐
- MCP 工具
- 环境信息
- 角色动作
- 多设备同步
如果继续完全依赖浏览器,很多功能在桌面端、手机端和系统能力上的体验始终会受到限制。
而到了原生客户端中,Room 就可以真正变成应用的核心。
现在打开月读空间 App,会直接进入 Room。
你看到的不再只是网站中的一个页面,而更像是:
一个一直存在于设备里的「八千代房间」。
PC 和手机,有不同的 Room
我没有简单把桌面布局等比例缩小到手机。
现在 Room 会根据设备采用两套不同的布局。
桌面端
桌面端使用:
角色舞台 + 聊天工作区
的结构。
左侧主要留给八千代和 Live2D 场景,右侧则负责:
- 聊天
- Agent
- 日记
- 资料
- 便签
- 快捷话题
- 输入区域
这样在大屏幕上,角色不会被聊天内容完全遮挡,同时也更接近一个真正的 AI 桌面助手。
移动端
手机则采用完全不同的思路。
Live2D 场景直接作为整个 Room 的主体,顶部使用悬浮控制区,聊天内容和输入框叠加在底部。
键盘弹出后,输入区域也会跟随调整。
也就是说,手机版并不是“压缩后的电脑版”。
它从一开始就是按照手机使用方式重新设计的。
八千代终于真正“住进”App 里了
这也是整个客户端里我非常在意的一部分。
月读空间一直在尝试让八千代不仅仅是一张立绘或者聊天头像,而是真正成为网站中的一个角色。
所以原生 App 重新实现了 Live2D。
目前使用的是:
Cubism Native Core + Native Framework + Flutter 原生渲染链路
模型数据通过原生接口接入 Flutter,再绘制 Live2D 的纹理网格。
也就是说,这里并不是:
- GIF
- 视频
- 网页动画
- JavaScript Live2D 页面
然后再嵌入客户端。
而是真正把 Live2D 数据接进了应用。
目前已经支持:
- 注视
- 眨眼
- 呼吸
- 模型物理
- 表情
- 口型
- 角色动作
- 动作队列
- 情绪响应
- 位置与大小调整
- 普通/反向遮罩
- 加法/乘法混合
并且语音播放时,会分析真实音频的 PCM 音量变化,让角色口型跟随声音变化。
它距离我理想中的“数字角色”还有很长一段距离。
但至少现在,八千代已经不再只是网页上的一个组件了。
AI 配置也完全交给用户
App 本身不会内置一个所有人共享的模型 API Key。
第一次进入 Room,可以直接配置自己的模型:
- API 地址
- 模型名称
- API Key
目前支持包括:
- OpenAI Compatible Chat Completions
- OpenAI Responses
- Anthropic Messages
- Ollama
- 月读空间网站代理
同时兼容:
- SSE
- NDJSON
- 普通 JSON
所以不管你使用在线模型、自建 API 网关,还是电脑上的本地 Ollama,都可以接入 Room。
八千代也可以说话
除了 LLM,App 还重新实现了语音模块。
目前已经支持:
- OpenAI Compatible TTS
- MiMo
- MiniMax
- ElevenLabs
- GPT-SoVITS
- 月读空间网站代理
模型和 TTS 可以分别配置。
比如:
LLM
↓
八千代生成回复
↓
TTS 合成语音
↓
客户端播放声音
↓
分析真实 PCM 音量
↓
驱动 Live2D 口型
这也是以后继续完善八千代实时交互的重要基础。
长期记忆也带到了原生客户端
Room 的长期记忆系统同样保留了下来。
登录月读空间账号之后,可以选择:
- 使用设备本地记忆
- 使用云端记忆
- 将本地记忆合并到云端
并且可以直接管理记忆:
- 搜索
- 新增
- 编辑
- 删除
- 修改评分
- 向量同步
游客则继续使用本机记忆。
聊天、日记和长期记忆之间也保持了原来的逻辑。
因此在不同设备登录同一个月读空间账号之后,八千代仍然可以继续使用已经同步的数据。
这也是我一直想实现的一件事:
设备可以更换,但八千代和你的故事不应该每次都重新开始。
不只是 Room,整个月读空间正在进入 App
早期我确实只准备做一个 Room 客户端。
但做着做着就发现:
如果离开 Room 之后还需要不停跳回浏览器,那这个 App 始终是不完整的。
所以后来干脆开始做整站原生迁移。
目前已经原生实现了大量月读空间功能。
主舞台
可以直接:
- 浏览文章
- 搜索
- 分类
- 排序
- 查看 Markdown / HTML 内容
- 查看公式
- 查看代码高亮
- 评论
- 点赞
- 收藏
- 分享
阅读数据也继续按照月读空间原来的规则统计。
广场
广场的:
- 留言
- 回复
- 点赞
- 搜索
- 筛选
同样可以直接在 App 中完成。
创作
App 里已经有真正的原生文章编辑器。
支持:
- Markdown
- 分类
- 封面
- 摘要
- 图片素材
- 本地草稿
- 快捷键
- 代码块
- 列表续写
- 文章编辑
- 发布
所以以后使用桌面版时,可以不打开浏览器,直接在月读空间 App 里面写文章。
Wiki、图库和附件库也都搬进来了
目前客户端已经包含原生的:
Wiki
包含月读空间现有百科内容、图片和相关交叉链接。
图库
支持:
- 浏览
- 搜索
- 筛选
- 随机图片
- 图片上传
- 图片管理
上传图片时还会在设备端进行压缩。
附件
附件上传支持:
- SHA-256
- 分片上传
- 断点恢复
- 暂停
- 取消
- 重试
对于以后月读空间越来越多的创作功能,这部分会非常重要。
像素工坊也变成了原生工具
像素工坊没有被简单地用网页嵌进来。
现在它也拥有 Flutter 原生实现。
包括:
- 192 × 108 画布
- 画笔
- 笔压
- 防抖
- 橡皮擦
- 填充
- 调色板
- 网格
- 背景
- 撤销 / 重做
- 缩放
- 图片导入
- 图片导出
- 草稿
- 社区发布
- 点赞
- 分享
以后我也希望月读空间里面能出现越来越多这种“小工具”。
它不一定需要非常严肃,但应该足够有趣。
甚至连辉夜跑酷也搬进去了
这个可能属于:
“来都来了,那游戏也一起搬了吧。”
客户端目前已经可以运行辉夜跑酷。
而且不是直接打开网页游戏。
游戏的:
- 项目数据
- 画面
- Shader
- Box2D 物理
- 音频
- 键盘操作
- 触摸操作
- 排行榜
- 成绩提交
都已经接入原生客户端。
这也让我越来越觉得:
月读空间未来可能不会只是一个“博客”。
它更像是一个逐渐长出来的小型数字世界。
桌面端还有一个很重要的东西:Agent
Windows、macOS 和 Linux 版本现在拥有独立的 Agent 模式。
进入 Room 后,可以切换到 Agent 标签页。
选择一个工作目录,然后直接把任务交给 Agent。
例如:
帮我检查这个项目的问题
修改这个页面的 UI
整理这些文件
分析项目代码并修复错误
桌面安装包目前会携带固定版本的:
- OpenCode
- Codex
模型配置则直接复用 Room。
Agent 可以操作:
- 文件
- 命令
- MCP
- 文章草稿
- 月读空间内容
同时对一些敏感操作增加确认步骤。
例如:
- 操作工作目录之外的文件
- MCP 调用
- 上传
- 发布
- 服务器写入
都会明确展示即将执行的内容。
命令也会通过系统沙箱运行。
我的目标并不是在 App 里面简单塞一个“AI 对话框”。
而是希望未来八千代真的能够:
聊天,也能够帮你做事情。
Agent 和 Agent OS 是两件不同的东西
这里顺便说明一下。
目前月读空间网站中的:
Agent OS
仍然是独立部署的 Web 应用。
它没有被完整迁移成 Flutter。
原生 App 中现在实现的是 桌面 Agent 工作区。
两个方向之后可能会继续互相吸收设计和能力,但目前它们依然属于不同的实现。
真正的跨平台
这次开发选择 Flutter,还有一个很重要的原因:
我不希望月读空间只存在于 Windows 或 Android。
目前项目已经包含:
- Android
- iOS
- macOS
- Windows
- Linux
五个平台的发布流程。
Android
提供原生 APK。
大多数 Android 手机直接使用 ARM64 版本即可。
Windows
提供 Windows 安装程序,也可以使用便携版本。
macOS
提供 Universal DMG:
同时支持:
- Apple Silicon
- Intel
Linux
提供:
- DEB
- 便携包
iOS
目前提供 unsigned IPA。
需要用户使用自己的 Apple 账号或证书进行签名后安装。
数据安全同样很重要
随着 App 开始保存:
- API Key
- 登录 Cookie
- 模型配置
- 聊天记录
- 草稿
这些东西,安全问题就不能再像普通网页一样简单处理。
目前:
API Key 和登录 Cookie
会存放在系统安全存储中。
而:
- 普通设置
- 本地聊天缓存
- 草稿
- UI 配置
则保存在应用自己的本地数据中。
同时登录 Cookie 不会被发送给 LLM 或 TTS 服务。
模型请求只会发送到你自己配置的模型地址。
离线也不会什么都没有
原生客户端还加入了本地缓存。
断网之后,已经缓存的部分页面仍然可以查看。
并且:
- 草稿不会丢失
- 已完成聊天不会丢失
- 待同步内容会保留
恢复网络或者重新登录相同账号之后,再继续同步。
不同账号之间的数据缓存也会隔离。
这一点对于一个真正长期使用的客户端来说非常重要。
原生 App 与网页版并不是替代关系
做这个 App 并不意味着我要停止维护网页版。
恰恰相反。
以后我更希望两边形成这样的关系:
月读空间
│
┌───────────┴───────────┐
│ │
Web App
│ │
随时打开 / 分享 深度使用 / 系统能力
│ │
└───────────┬───────────┘
│
同一套账号与服务
Web 依然拥有最低的访问门槛。
看到一个链接,点开就可以进入月读空间。
而 App 则负责:
- 更完整的 Room
- Live2D
- 本地数据
- 桌面 Agent
- 本地文件
- 更稳定的长时间运行
- 更深入的操作系统能力
两者并不是谁取代谁。
而是共同组成完整的月读空间。
为什么现在还是“测试版”?
虽然现在已经有大量功能,但我依然把它定义为:
测试版。
因为“能够运行”和“真正适合每天使用”之间,其实还有很长的距离。
接下来还有很多东西需要继续打磨。
例如:
- 各个平台 UI / UX 继续优化
- 手机上的交互体验
- Live2D 性能优化
- 动作表现优化
- 八千代情绪与动作联动
- TTS 与口型效果
- 长期记忆
- Agent 稳定性
- 原生系统通知
- 多设备体验
- 安装与升级体验
- iOS 真机验证
以及最重要的:
让整个 App 更有“月读空间自己的感觉”。
现在很多页面虽然已经完成了原生迁移,但这并不意味着设计就已经结束。
相反,接下来我会逐渐重新思考:
如果月读空间从一开始就是一个 App,它应该长什么样?
而不是永远照着网页一比一复刻。
关于未来
我越来越不想简单把月读空间称作一个“个人网站”。
因为现在它里面已经出现了:
- 博客
- 社区
- AI
- Live2D
- 长期记忆
- Agent
- Wiki
- 创作工具
- 图库
- 游戏
- 数字角色
很多最开始根本没有计划过的东西。
这些功能并不是一开始就设计好的。
更多时候只是:
“这个好像挺有意思,要不要试试看?”
然后一点一点长成了今天的样子。
原生 App 也是一样。
它现在远远没有完成。
甚至可以说,0.6.4 只是它真正开始成为一个 App 的阶段。
未来我希望八千代不只是:
“网站上那个可以聊天的角色。”
而是能够真正连接月读空间里的:
内容、记忆、工具、设备和你。
打开手机,她在那里。
打开电脑,她也在那里。
换一台设备,她仍然记得之前发生过什么。
需要聊天的时候可以聊天。
需要工作的时候也能一起完成任务。
也许这才是我真正想做的月读空间。
下载与项目地址
目前客户端仍处于测试阶段。
如果你想体验,可以前往 GitHub Releases 下载:
项目源码:
网页版:
最后还是那句话:
月读空间不会突然“开发完成”。
它大概会一直处在:
“这里好像还能再加点什么。”
的状态。
而这次,月读空间终于从浏览器里走了出来。
接下来,就慢慢让它变得更像一个真正属于我们的空间吧。