【Code with SOLO】日记里长出一个部落:「小境」——写给那些不想被算法读懂的人

摘要:
我用 TRAE SOLO 从零开始做了一款「日记 × 养成 × 陪伴」的纯前端情绪产品。没有后端、没有账号系统、没有云同步——只有你、你的文字、和一个从你日记里长出来的部落。

100 个性格各异的角色会因为你的情绪和故事被吸引而来,你的每一次倾诉都会让这个小小的世界发生一点点变化。项目代码全部由 TRAE SOLO 辅助完成,从架构设计到像素风场景绘制,从情绪分析引擎到角色传记生成系统。

项目简介:
「小境」的起点很简单:写日记的人,需要一个安静的角落。

不是要你打卡、不是要你完成任务、不是要你变得更"高效"。只是,有些话说不出口,但写下来就好了。

所以小境做了一件事——你写日记,部落就会生长。

你的每一篇日记都会被安静地分析:你今天是什么情绪?你在经历什么?然后,也许会有一个角色被你的故事吸引,决定留下来。

今天很累?「树洞睡眠兽」会从角落里走出来,什么也不说,只是陪着你。
今天很开心?「小火种队长」会跳出来,说要去远方点亮一座灯塔。
今天有点焦虑?「雨披旅人」会穿着湿漉漉的雨披走过来,告诉你"下雨也没关系"。
100 个角色,每一个都有自己的名字、性格、技能和故事。 他们不是游戏 NPC,更像是你情绪的回声。


首页——你的角落
首页只有一个问题:今天我的小境有什么变化?

像素风部落场景是主视觉,一个角色气泡会跟你说今天的话,底部一个大大的按钮——「写点什么给小境」。

没有信息流、没有推送、没有算法推荐。只有你和你的角落。

写日记——交给小境
点击按钮后进入沉浸式写作页面。输入区占据整个屏幕,没有多余的元素干扰。

底部不是"提交"或"发送",而是——「交给小境」。

因为这不是在填写表单,是在把心里的话交给一个愿意听的人。

结果——小境听到了
提交后不会弹出冰冷的数据播报。你会看到:

你写的那句话,被温柔地引用回来
小境对这句话的回应
部落发生了什么变化——也许有人来了,也许有人变得更亲近了
三种可能:

「有人被你的故事吸引了」——新成员加入部落

「有人因为你的话变得更亲近了」——现有成员升级

「小境听到了」——今天的故事被安静地记录下来

部落页——看着它长大
部落页展示你的成员、建筑和里程碑。每天第一次打开,还会看到成员之间的随机互动——「书堆守夜人今天帮黄灯小匠修好了台灯」。

技术架构:
整个项目是纯前端,零后端依赖。所有数据存储在 localStorage。
核心技术栈
模块 技术
前端框架 React 18 + TypeScript
样式方案 Tailwind CSS + CSS 变量主题系统
构建工具 Vite 5
状态管理 useReducer + Context
数据持久化 localStorage
路由 React Router v6
包体积 ~145KB gzip
核心系统

  1. 日记分析引擎(diaryAnalyzer)

基于关键词匹配的情绪分析系统,从日记文本中提取:

6 种情绪标签(平静、疲惫、焦虑、开心、想努力、有点难过)
8 种生活场景分类(学习、运动、舒适、社交、创造、休息、志向、悲伤)
能量值(决定部落成长速度)
2. 召唤系统(summonGenerator)

根据日记的情绪和场景,从 100 个角色中匹配最适合的角色:

基于情绪标签和主题标签的二维匹配算法
三级稀有度概率控制(普通/稀有/传说)
每个角色有专属的出场叙事(场景触发→场景描写→到来→意义)
3. 成员匹配(memberMatcher)

已有成员时,根据日记内容决定是升级现有成员还是召唤新成员。匹配算法考虑:

情绪相似度
主题关联度
成员等级和成长空间
4. 传记生成系统(biographyGenerator)

为每个角色生成独特的传记,包含 5 个维度:

诞生场景、被吸引的原因、留下的理由、性格特征、未来暗示
5. 像素部落场景(PixelTribeScene)

用纯 CSS 绘制的像素风动态场景,根据天气和部落状态实时变化。

  1. 成员互动系统(memberInteractions)

每天第一次打开部落页,会看到成员之间的随机互动——双人互动 15 种模板 + 单人动态 10 种模板,基于日期种子确保同一天看到相同内容。

  1. 情绪天气系统(emotionWeather)

基于最近 7 天日记的情绪分析,生成"情绪天气"和温柔提醒。

  1. 部落成长系统(tribeInteractions)

7 个部落等级(营地→聚落→村落→部落→大部落→联盟→王国)、8 个可解锁建筑、8 个成长里程碑。

100 个角色:
角色分为三个稀有度:

Tier 1 · 传说(8 个):书堆守夜人、灰羽跑者、黄灯小匠、月差信使、玻璃瓶收藏家、树洞睡眠兽、小火种队长、雨披旅人

Tier 2 · 稀有(24 个):笔记精灵、考试守望者、晨读伴读、登山向导、游泳教练、夜跑搭档、深夜烘焙师、阳台园丁、织梦者、笔友、老邮差、桥上守望者、音乐收集者、涂鸦画家、星空记录者、午睡猫、暖炉守护者、云朵收藏者、灯塔守望者、探险家、破冰者、雾中行者、秋叶旅人、回忆收藏者

Tier 3 · 普通(68 个):图书馆小鼠、闪卡骑士、代码猫头鹰、削笔人、截止日期舞者、瑜伽蛙、单车风、跳绳石、拉伸猫、煮茶人、缝被人、汤锅守护者、萤火虫灯笼、窗边挥手人、共伞人、旧信箱、深夜来电、涂鸦虫、相机狐狸、诗叶、纸鹤、哼鸣蜜蜂、吊床树懒、听雨窗、毯子堡垒、枕头云、插旗手、指南针玫瑰、种子芽、日出传令、山间回声、水洼倒影、空长椅、最后一片叶、黄昏影子、潮汐池、深夜食堂、咖啡豆、电饭煲守护者、车票根、行李箱旅人、读图人、呼吸计数器、烦恼盒子、微笑镜、出气沙袋、雪地守望、彩虹桥、雷鼓手、风铃、星座画师、守时人、摇篮曲歌手、萤火虫罐、月兔、北极星、蒲公英许愿、漂流瓶、初雪、闹钟精灵、背包小孩、观星者、放风筝的人、影子同伴、温泉守、灯笼节、棋手、海螺听者

每个角色都有:名字、描述、技能名、技能描述、像素头像、专属出场叙事、传记模板。

开发历程:
从"功能很多的轻 RPG"到"日记驱动的情绪部落"
最开始的版本,我塞了很多东西进去:夜巡、远征、遗物、花园、图鉴、战斗……看起来像一个功能丰富的轻 RPG。

但越做越觉得不对。这不是我想要的产品。

一个写日记的人,不需要远征系统。

所以我在 v0.3.1 做了一次大的收口——「核心闭环修正」:

新建沉浸式写日记页 /write——输入区占满屏幕,底部按钮叫"交给小境"
重构日记结果页——不再弹冰冷的数据面板,而是温柔回应
首页精简——只保留部落场景 + 角色气泡 + 写日记按钮
底部导航从 5 个砍到 3 个——角落、日记、部落
远征/花园/图鉴/战斗全部降级——代码保留,但从主体验里隐藏
这次收口让我想清楚了一件事:小境的核心不是游戏,是陪伴。

踩过的坑:
角色命名风波:一开始给 100 个角色起了全新的名字(茸野祈、岚芽崽、烬小芭……),结果发现旧名已经在 9 个文件中被大量引用,改名牵一发动全身。最后全部回滚到原始名称。教训:命名要在设计初期就定好,不要在中途改。

localStorage 的 5MB 限制:日记数据、部落状态、角色传记全部存在 localStorage,一开始没有做数据压缩,写了几十篇日记后就快满了。后来加了存储统计和备份导出功能。

情绪分析太粗糙:基于关键词匹配的情绪分析准确度很低,“不想上班"可能被识别为"平静”(因为没有负面关键词)。这是纯前端方案的天然限制,后续计划接入更智能的分析。

移动端适配:最初所有页面都用固定的 max-w-md(448px),在大屏手机上两侧留白过多。后来改成了响应式容器。

我想说的:
做小境的过程中,我一直在想一个问题:为什么人们不愿意写日记?

不是因为没有好用的工具。Day One 很好用,Reflectly 很漂亮,备忘录就在手机里。

是因为写日记这件事本身,让人觉得自己很孤独。

你把心里的话写下来,然后呢?没有人会回应。日记本不会说"我听到了"。备忘录不会说"你今天辛苦了"。

小境想做的,就是成为那个会回应的角落。

你写下来的每一句话,都会在这个小小的部落里产生回响。也许是一个角色被你吸引而来,也许是一个熟悉的朋友变得更亲近了,也许只是安静地被记录下来。

不需要你打卡、不需要你完成任务、不需要你变得更好。

你只需要写。小境会听。

技术细节:
项目地址:纯前端,暂无线上部署
技术栈:React 18 + TypeScript + Tailwind CSS + Vite 5
数据存储:localStorage(支持 JSON 导出/导入备份)
构建产物:~145KB gzip
代码量:约 2 万行 TypeScript/TSX
标签:
Code-with-SOLO Hello-AI-科技致善