PROJECT SHOWCASE · 2026
Moon Journey
登月之旅 —— 一个用代码讲完阿波罗登月的互动科普网站
从地球出发,经过地月转移、动力下降、月相变化,最后落到那句「一小步」。 整站是一块 3D 画布,滚动就是叙事;戴上头显,还能站到月面上看。
席义航 · 保定中学
01 · 它是什么
把 384,400 公里,做成一条可以滚动的长卷
一个单页网站,用「滚动」当时间轴:画面随着滚动一路推进,文字从旁边浮出, 3D 场景在五个章节之间平滑切换。不需要点按钮、不需要翻页,往下滚就行。
02 · 结构
五个章节,一条时间线
第 01 章 · 地球
蓝色弹珠
1969 年 7 月 16 日 13:32 UTC,土星五号从肯尼迪航天中心 39A 发射台升空。
- 地球是画出来的:大陆用椭圆团 + 噪声抖动边缘拼出来,再叠云层
- 大气辉光:菲涅尔着色器,球壳边缘自然衰减,不是贴图
- 视差:鼠标移动时相机轻微偏移,画面有呼吸感
第 01 屏 · 地球与星空
第 02 章 · 出发
离开地球,进入虚空
滚动时相机从贴脸的地球一路后退,月球、轨道线、转移弧线依次淡入。
- 土星五号按真比例搭:一级 0.38 / 二级 0.225 / 三级 0.165 + 适配器 + 逃逸塔
- 细节:5 台 F-1 喷管、4 片尾翼、贯穿三级的黑白 roll pattern 色带
- 里程碑标签:发射 / TLI / 中途修正 / 进入月球轨道 / 触月,用 HTML 投影贴在轨迹上
第 02 屏 · 地月转移轨道与里程碑
第 03 章 · 着陆
危险的 12 分钟
从 15.2 公里到月面,只有约 12 分钟。拖动滑块,整段下降过程可以逐帧看。
- 一个滑块驱动全部:高度、下降速度、俯仰角、燃料、尾焰长度、月尘浓度
- 6 个阶段:制动 → 俯仰翻转 → 接近段 → 手动接管 → 低门 → 触月,点一下就能跳过去
- 月面也是算出来的:分形起伏 + 30 个陨石坑 + 170 块岩石,太阳会投出登月舱的影子
第 03 屏 · 下降控制台与登月舱
第 04 章 · 月相
为什么月亮会变?
月亮自己不发光,形状只取决于「太阳、地球、月球」三者的夹角。
- 8 个月相图标是算出来的:逐像素套朗伯定律,和 3D 里的明暗交界线完全一致
- 潮汐锁定:月球自转角 = 轨道方位角,所以永远只有一面朝着地球
- 轨道视角:切换参考系后,地球固定在中心,能直接看到月球绕着地球公转
第 04 屏 · 上弦月与月相选择器
第 05 章 · 尾声
一小步
「这是个人的一小步,却是人类的一大步。」—— 尼尔·阿姆斯特朗,1969-07-21
- 月面 + 宇航员剪影,背光只有轮廓与一点点地球反照
- 宇航员在月面上投出一道长长的影子(实时阴影)
- 舱外服上有胸前遥控单元、相机、背包天线、面罩框
第 05 屏 · 宇航员剪影与引言
03 · 技术栈
用了什么
Three.js r186
WebGL 3D 渲染,四个场景各建一套相机与光照
GSAP 3
ScrollTrigger 把滚动进度映射成场景进度;ScrollTo 做章节跳转
UnrealBloom
后处理辉光:RenderPass → Bloom → OutputPass(ACES 色调映射)
原生 ES Module
没有框架、没有构建步骤,模块化拆分,源码直接跑
所有依赖都放在本地 vendor/ 里 —— 断网也能演示。
04 · 技术亮点 ①
没有一张图片,全部现画
整个项目找不到一张 jpg、png 或 3D 模型。页面加载时,用 Canvas 把纹理当场算出来。
地球
30 多个大陆团块用椭圆 + 噪声抖动边缘拼出海岸线,再叠云带、极冠、海洋深浅斑块。
月球
1100 个陨石坑(亮环 + 暗底 + 中央丘)、月海暗斑,同一套绘制再生成一张凹凸贴图。
月面地形
分形噪声做起伏,30 个陨石坑按环形山剖面下凹,170 块岩石用实例化网格撒上去。
04 · 技术亮点 ②
四个场景模块,一个引擎
因为四个场景互相独立、接口一致,所以可以单独改其中一个(比如把月相换成别的交互), 不会碰到其它三屏。想改文案只需要动 mission.js 一个文件。
04 · 技术亮点 ③
看不见的工程细节
三档画质
右上角低 / 中 / 高,默认低档(像素比 1.0、无辉光、无阴影),手选会记住;连续 3 秒低于 32fps 自动再降一档。
实时阴影
只开在需要的那两盏灯上(登月舱、宇航员),阴影相机跟着登月舱下降,落地前后都清晰。
DOM 标签节流
里程碑与高度刻度是 HTML 元素,每帧投影到屏幕坐标,但限制在 12Hz 更新——每帧写 DOM 会明显掉帧。
自动演示
一键把整站当成时间轴播一遍;滚动、点击、按 ESC 都能立刻接管,不会和人抢操作。
无障碍
尊重「减少动态效果」设置;月相与阶段列表都支持键盘操作。
响应式
手机端收起侧边导航、面板改到底部;竖屏时相机自动拉远、构图往中间收。
05 · 头显模式(WebXR)
戴上头显,站到月球上看
同一份源码进到头显里,五个章节就变成五个观景锚点:人站定在月面上,用手柄摇杆换位置。
① 载入页停 10 秒,先把头显里怎么玩写在眼前
② 进 VR 后,操作提示贴在头前(金色那一条)
- 世界反过来动:VR 里相机被头显接管、不能去搬相机,于是改成反向平移 / 旋转整个场景,锚点始终落在正前方
- 站地上,不是地下:月面站点把地面钉在物理地面上(local-floor),第 3、5 站都是站在月面看登月舱降落
- 一只手柄走完全程:左右摇杆切场景 · 扳机下一站 · B 键退出(WebXR 只认安全上下文,所以用 adb reverse 把头显的 localhost 打回电脑,零证书警告)
06 · 画质档位
默认就能跑,想要更好再往上调
右上角「低 / 中 / 高」三档,默认低档;画质只改"怎么渲染",场景、文案、章节一个字都不动。
低(默认)
像素比 1.0
抗锯齿 / 辉光 / 阴影全关
中
像素比 ≤1.3
低分辨率辉光,不开阴影
高
像素比 ≤1.75
4x 抗锯齿 + 辉光 + 阴影
右上角 HUD · 画质 低 / 中 / 高
- 手选的档位记得住:写进 localStorage,下次打开还是这一档
- 跑不动会自己退:连续 3 秒低于 32fps,看门狗自动降一档(高 → 中 → 低),并在按钮下方浮一条提示
- 帧率是实测的:1280×720、地月航线场景,低档比高档快约 2.5 倍
数据来源 · 参考项目
数据
NASA《Apollo 11 Mission Report》(MSC-00171)、NSSDC。轨迹与时间轴为教学示意比例。
3D-Space
借鉴其 Three.js 太空场景的分层组织:星空、行星、轨道线;用滚动进度驱动相机。
Lunaria
借鉴 3D 月相地球仪的交互:以月球为中心的参考系、点月相联动光照、潮汐锁定。
谢谢观看
完整版能滚动、也能进头显;两个成品内容一样,区别只在有没有头显那一层:
▶ 打开 VR 版(带 AR / VR 入口) ▶ 打开普通版(无头显)
三个 HTML 放在同一个文件夹里,按钮即可直接跳转。
席义航 · 保定中学MADE BY XYIHANG