按真实轨道画了个太阳系,塞进一个 HTML 文件
太阳系的图,教科书上都是假的。
不是说画错了,是必须假——真按比例画,海王星要画到教室外面去,而地球会小成一个看不见的点。为了让一页纸放得下,只能把距离压扁、把行星放大。
代价是,很多人长大后对太阳系的印象,是一排大小差不多的球整齐地绕着圈。
我想做个能在两种比例之间平滑切换的东西。
🪐 点这里直接打开 → solar.zhangwenqiang.com
代码也开源了:github.com/zhangwenqiang0214/solar-system-3d
它是什么
一个 HTML 文件。双击打开,不用装任何东西,断网也能跑。
里面是一个可以自由旋转、缩放的三维太阳系,35 个以上的天体——八大行星、矮行星、主要卫星,每一个都能点开看中文介绍。
两种比例,可以滑动
这是我最想做的功能。
- 教学模式:行星放大,轨道压缩,所有东西都看得见,像教科书那样
- 真实模式:严格按真实比例,然后你会发现——什么都看不见了
中间是一根滑杆。拖动它,两种模式之间连续插值。
拖的过程比任何一端都有说服力。你会亲眼看着行星缩小、轨道拉长,直到整个内太阳系挤成中心一小团光,而海王星跑到视野之外。那一刻「空旷」这个词才有了具体的量感。
行星的位置是真的
这是另一件我坚持要做的事:不要随便摆。
页面上每颗行星的位置,是按 JPL 的开普勒轨道根数、根据你打开页面的日期实时算出来的。
也就是说,你现在看到的,就是此刻天上真实的排布。想看你生日那天的行星位置,改个日期就行。
算法本身不复杂——六个轨道根数(半长轴、离心率、倾角等等)加上时间,解一个开普勒方程,得到轨道上的位置。麻烦的是把各个天体的参考系对齐,以及处理那些轨道特别扁的矮行星。
贴图
八大行星和主要卫星用的是 solarsystemscope.com 的贴图,CC BY 4.0 协议,可以放心用。
矮行星和小卫星没有现成贴图——它们大多只有几张模糊的探测器照片。这部分是用 canvas 程序化生成的:按天体的已知特征(颜色倾向、反照率、大致地貌类型)生成噪声纹理。不追求写实,只求别让它们看起来像一个个塑料球。
技术
- Three.js 0.170 + UnrealBloom 后处理(太阳的光晕靠它)
- 轨道计算是自己写的,JPL 开普勒根数
- 构建用 esbuild,贴图走 dataurl loader 全部内联
最后 node build.mjs 打出一个 11.2MB 的单文件 HTML,所有贴图以 base64 嵌在里面。
11MB 对网页来说不小,但它换来的是:拷给任何人,双击就能用。不用起服务器,不用连网,不用解释”你先装个 Node”。给小孩看、给长辈看、拷到没网的电脑上看,都行。
后来加了个网页版
为了能挂到网上,又加了一种构建模式:
1 | node build.mjs --web |
贴图不再内嵌,而是作为独立文件按需加载。HTML 从 11MB 降到 3.2KB,打开就见画面,贴图在后面慢慢补上。
两种产物各有各的用处——单文件版适合拷给人,网页版适合挂网站。构建脚本里用一个 --web 参数切换 esbuild 的 loader(dataurl 换成 file),二十行代码的事。
开源了
代码在 github.com/zhangwenqiang0214/solar-system-3d,MIT 协议。
贴图来自 Solar System Scope,CC BY 4.0,用的时候记得保留署名。
为什么做这个
起因是想给小孩讲太阳系,翻了一圈现成的工具,要么是专业天文软件(打开就劝退),要么是精美但假的动画(好看,但强化了错误印象)。
我想要的东西很简单:既是真的,又看得懂。这两件事在太阳系这个尺度上天然打架,所以才需要那根滑杆——让人自己在两者之间走一趟。
走过一趟之后,「太阳系很空」就不再是一句需要被告知的知识了。






