~/jing/lab/blog/Web开发
Web开发

诗云:我把 34 万首古诗做成了 3D 星图

用 Three.js 做了一个古诗可视化项目:34 万首诗,每首诗对应一个粒子,可以按朝代、作者和主题切换视图。

靖淯茗·2026年6月17日·6 分钟阅读
诗云:我把 34 万首古诗做成了 3D 星图

刘慈欣有篇小说叫《诗云》。里面有个很夸张的设定:外星文明为了写出超过李白的诗,直接穷举所有汉字组合,把太阳系改造成一片存储诗歌的星云。

我之前读到这个设定时印象很深。后来做个人项目时,就想试着做一个小一点的版本:诗云 · 中华诗词星图

它不是穷举诗,而是把真实古诗数据可视化:每一首诗对应一个粒子,可以按朝代、作者、主题重新排列。

数据从哪来

数据用的是 GitHub 上的开源仓库 chinese-poetry,从先秦到清代,全量大概 342,940 首

我第一次看到数量也有点意外。唐诗大约 5 万首,宋诗 27 万首,宋朝人是真的很能写。

原始数据是按作者拆的 JSON,我写了一个处理脚本把它重新组织:繁体转简体(用 opencc-js),关键词提取归类主题,然后按 id 哈希洗牌之后切成 58 个分片,每片 6000 首。

分片前做了一次哈希洗牌。原因是我不希望用户刚打开页面时只看到某个朝代或某一批作者的数据。前几片数据也应该尽量像全集的一个缩小版。

为什么要渐进加载

34 万首诗,JSON 原始数据大约 100MB。一次性塞给浏览器肯定不行。

所以我分两步加载:

第一步先加载 15 首手工精选的名篇,比如李白、杜甫、苏轼、李清照的代表作。这些诗带译注和赏析,在星图里显示得更亮,页面也能先打开。

第二步后台继续加载 58 个分片。每加载完一片,就把新数据追加到粒子系统里。刚打开时星图比较稀,过一会儿会越来越密。手机端只加载一部分,PC 端再跑全量。

Three.js 画 34 万个粒子

粒子用 THREE.Points 画。深空主题里用了 AdditiveBlending,粒子叠在一起的地方会更亮,再加一点 UnrealBloom,看起来会有星云的感觉。

性能是这个项目最麻烦的部分。34 万个粒子不是不能画,但一旦 DPR 太高、动画太多,帧率马上掉下来。

我主要做了几个优化:

限制 DPR。 高分辨率屏幕会让 GPU 压力成倍增加。我把 DPR 上限压到 1.15,画面差别不明显,但帧率稳很多。

空闲时停掉动画循环。 朝代视图切到作者视图时,会做位置插值。动画结束后如果还一直跑 requestAnimationFrame,就是白耗性能。所以我加了 isAnimating 标记,动画结束后停掉循环。

增量上传到 GPU。 渐进追加新分片时,不重新上传整个 geometry,而是用 addUpdateRange 只标记新增部分脏了,驱动只上传增量。

最后的效果还可以:PC 能跑全量,手机端限制数量后也能正常交互。

双主题

一开始只有深空主题,黑底、蓝绿色粒子、辉光,比较符合“星云”的感觉。

后来我又加了宣纸主题。白底、水墨黑点、朱砂色点缀,整体更像古籍或纸面上的图。

主题切换时踩了一个坑:Three.js 里如果设置了 scene.background,它会盖住 renderer.setClearColor()。我一开始一直改 clearColor,背景就是不动。最后改成每帧 lerp scene.background,切换才正常。

部署踩的两个坑

inode 坑。 nginx 容器用 bind mount 挂载了一个配置文件。bind mount 绑定的是 inode,不是路径名。如果用 cp 或文本编辑器「另存为」替换了文件,inode 换了,容器里看到的还是旧文件,配置怎么改都没效果。改配置文件必须原地写入(cat > /path/file),保留 inode。

nginx 启动时 DNS 只解析一次的坑。 proxy_pass http://shiyun/ 这种写法,nginx 在启动时shiyun 解析成容器 IP,之后不再重新解析。如果 shiyun 容器单独重启,它的容器 IP 变了,nginx 还连着旧 IP,代理 400。解法:任何一个容器重启后,相关的 nginx 也要 reload 一下(docker exec blog nginx -s reload)。

最后

这个项目做完之后,我对“数据量”这件事有了更直观的感觉。

34 万这个数字写在页面上,只是一个数字。但当它变成屏幕上一整片密密麻麻的点,每个点又对应一首真实存在的诗时,感觉会不一样。

看看吧。右上角可以切换深空和宣纸两个主题,左侧可以按朝代、作者、主题切换视角。点亮的大星星是那 15 首手工精选的名篇,点一下可以读原文。

#Three.js#数据可视化#项目复盘#性能优化

靖淯茗

计算机专业在读,在 AI / Web / 数据库之间折腾。Build · Learn · Share。

评论