MOON JOURNEY项目介绍 MADE BY XYIHANG 01 / 13

PROJECT SHOWCASE · 2026

Moon Journey

登月之旅 —— 一个用代码讲完阿波罗登月的互动科普网站

从地球出发,经过地月转移、动力下降、月相变化,最后落到那句「一小步」。 整站是一块 3D 画布,滚动就是叙事;戴上头显,还能站到月面上看。

席义航 · 保定中学

01 · 它是什么

把 384,400 公里,做成一条可以滚动的长卷

一个单页网站,用「滚动」当时间轴:画面随着滚动一路推进,文字从旁边浮出, 3D 场景在五个章节之间平滑切换。不需要点按钮、不需要翻页,往下滚就行。

5章 节
4个独立 3D 场景
0张图片 / 0 个模型文件
1个 HTML 就能跑

02 · 结构

五个章节,一条时间线

01地球 · 蓝色弹珠程序化地球 + 星空,鼠标移动有视差EARTH ORBIT
02出发 · 地月转移相机拉出地月全景,土星五号沿转移轨道滑行TRANS-LUNAR
03着陆 · 危险的 12 分钟拖动滑块,登月舱从 15 公里降到月面POWERED DESCENT
04月相 · 为什么月亮会变点月相看光照变化,可切轨道视角自由旋转LUNAR PHASES
05尾声 · 一小步宇航员剪影、天上的地球,和那句话ONE SMALL STEP

第 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 块岩石用实例化网格撒上去。

0张图片资源
~1.4 MBThree.js 打包后体积
1.06 MB单文件成品大小(VR 版)

04 · 技术亮点 ②

四个场景模块,一个引擎

入口 main.js 启动流程 · 滚动映射 · 控件绑定 · 入场动画
引擎 engine.js 一块画布 · 一套后处理 · 场景调度 · 帧率看门狗(同一时刻只渲染一个场景,切换时黑场过渡)
场景 orbitdescentphasesfinale 统一接口:scene / camera / update / resize / onEnter / dispose
支撑 utils.jsmission.jsui/* 程序化纹理与工具 · 全部文案数据 · 任务栏 / 控制台 / 月相选择 / 自动演示

因为四个场景互相独立、接口一致,所以可以单独改其中一个(比如把月相换成别的交互), 不会碰到其它三屏。想改文案只需要动 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
抗锯齿 / 辉光 / 阴影全关

≈141 fps

中

像素比 ≤1.3
低分辨率辉光,不开阴影

≈126 fps

高

像素比 ≤1.75
4x 抗锯齿 + 辉光 + 阴影

≈56 fps
右上角的画质切换

右上角 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