数字花园
回信、胶囊与年鉴:这颗星球学会了记得
序章:被看见之后
上一轮,这颗星球的天空住进了人:真月亮、换季星座、彼此的光痕。星星墙也一直都在——留一颗星,别人可以点亮它。
但被点亮之后呢?一万四千颗星,点亮是唯一的动词。这一轮做三件事,主题只有一个:记得。回信是记得某颗星,胶囊是记得某句话,年鉴是记得这一年。
一:星星回信
留言星第一次有了回音。管理员可以在后台给任何一颗星写回信——上限一百四十字,多一个字都塞不下——回信写下的那一刻,WebSocket 把它即时广播给每一个正在星球上的人。
前端对应的动画:一道紫粉色的彗星拖着尾迹划到那颗星上,星色从被点亮的暖色缓缓转成更暖的白,星星旁边多出一枚 ↩ 的小标记。鼠标悬上去,回信全文浮出来。
调试时补过一个静默的坑:Astro 构建不查 TypeScript 类型,sealOff 的 i18n 键漏掉了,构建照样绿灯——这类错误不会喊疼,只能靠上线前逐页点一遍。静默失败最危险的地方,是它连失败都懒得说。
二:时间胶囊
写下一句话,选择封存:不封、三十天,或一年。封存中的星是冰蓝色的,内容对所有人保密,也不能被投票点亮——后端直接返回 404,保密这件事不靠前端自觉。
到点的那一刻,由 Durable Object 的原生闹钟负责叫醒:时间一到,它主动向所有连接广播揭晓,不需要任何人来轮询。管理员也可以在后台提前解开某一封。
星星的位置按 id 确定性计算,刷新多少次它都待在原地——一颗封存着一句话的星,不该每次回来都换地方。
联调时抓到两个并发 bug,都挺典型:
- WebSocket 广播跑在 POST 响应之前,慢一拍的响应又触发一次前端拉取,同一封胶囊画了两颗星。修法是按 id 和文案去重。
- 新星落点靠
WHERE ip=?反查,碰上空 IP 时错拿了置顶星的 id。改成 INSERT 之后取MAX(id)——猜出来的 id 都不可信,要拿刚写进去的那一个。
三:星球年鉴
/wrapped——这颗星球自己的年度报告。四语齐全,数据来自后端真实统计:这一年收到多少颗星、被点亮最多的那颗写了什么、来自多少个国家与地区的朋友来过(带国旗)、星球被到访多少次、还有几封信正在封存中。
数字全部用 count-up 动画:滚到视口里才开始,从零数到真实值,借助 IntersectionObserver 和 gsap,不到不数,数完就停。命令面板和页脚里都加了入口。
上线时 /api/wrapped 返回:320 次到访、4 个国家。数字不大,但它们是真的。
尾声
这颗星球现在会回信、会封存心事、会在年底交出一份年鉴。「记得」不再是浏览器刷新就消失的东西——它写进了数据库,写进了 Durable Object 的闹钟里。
下一批是命令面板的动作和月亮彩蛋。星星墙的下一章,交给时间。
评论