交付说明 · DELIVERY NOTES 席义航 · 保定中学 · Made By Xyihang

两台航天器,四个单文件。

这里交代两件作品的交付情况:登月之旅(滚动叙事的登月科普长页)与 航天器解剖图(可拖拽爆炸拆解的三维解剖图)。 每件各出两个版本 —— VR 版(带头显适配)与 普通版。 四个文件都是双击即开、零联网、零外部资源的单文件 HTML。

01 / Checklist

交付清单Four single-file deliverables

文件版本体积SHA256
moon-journey-VR版.htmlVR 版1,082 KB56DE3324F8DB12A1C9B3DACEE6DFC2A76FD1E5E763F8457E3C991B9309410D33
moon-journey-普通版.html普通版1,065 KB5130A716065A81D859989E203950DE91D2D9210AD477E0E33EA2216D0E8AC2C9
spacecraft-anatomy-VR版.htmlVR 版15,659 KBE4FE87000FD68D22E22464261288C52D0398564865BBA2890091DD3470ADCA49
spacecraft-anatomy-普通版.html普通版15,637 KB0551F3C705A4C4C65560CAD146BB8FED9D01AC45D083C5993E1D4D231EDA3D8C
为什么是单文件。模型(NASA GLB)、Draco 解码器、字体、样式与脚本全部内联成 data URI, 不依赖 CDN 也不依赖本地服务器。拷到 U 盘、发微信、丢进头显,双击就能跑。 SHA256 是交付时的实测值,用来核对拷贝过程中有没有损坏。
02 / The Two Projects

两个工程What they are

登月之旅界面
登月之旅Moon Journey

滚动条驱动的登月科普长卷,五章:地球出发 → 地月转移 → 危险的 12 分钟(动力下降)→ 月相成因 →「一小步」。 低多边形三维场景随滚动逐段展开,星际流光与辉光后处理。

  • Three.js
  • GSAP ScrollTrigger
  • 滚动叙事
  • 阿波罗
航天器解剖图界面
航天器解剖图Spacecraft Anatomy

把一台完整航天器沿径向炸开,逐层剥离外壳与舱段。收录 朱诺号(10 个零件 / 17,124 三角形)与 开普勒号(7 个零件 / 9,795 三角形),点选任意分系统即可读它的功能简介与真实技术参数。

  • 爆炸拆解
  • 引线标注
  • 分系统清单
  • NASA 3D Resources
03 / Two Versions

VR 版 与 普通版The only difference is the headset layer

两个版本的三维画面完全一样,区别只在有没有「头显适配」这一层。普通版不是旧包, 它由同一套源码构建,只是编译期把 WebXR 那一层整块裁掉了。

VR 版

With WebXR
  • 顶栏有「进入 VR」按钮
  • PICO / Wolvic 等头显可进沉浸模式
  • 沉浸内四块头锁面板 + 手柄射线拾取
  • 进 VR 前有 5 秒操作提示

普通版

Screen only
  • 没有 VR 按钮与 WebXR 代码
  • 不请求沉浸会话
  • 三维画面、交互、画质档位完全一致
  • 手机 / 平板 / 老机器更稳妥

怎么一眼分辨是哪个版本

# 数头显适配的特征串:0 = 普通版,>0 = VR 版
PS> $t = Get-Content 'spacecraft-anatomy-VR版.html' -Raw -Encoding UTF8
PS> "xr = "   + ([regex]::Matches($t,'navigator\.xr|immersive-vr|VRButton|xrSlot|vr-hud')).Count
PS> "three = "+ ([regex]::Matches($t,'WebGLRenderer')).Count
# VR 版:xr > 0    普通版:xr = 0    两版的 three 都应为 38
04 / Headset Deployment

在 PICO 头显上打开Three routes, pick by situation

为什么必须讲究「安全上下文」。WebXR 的 API 只在安全上下文里存在。用 http://192.168.x.x 打开时 navigator.xr 直接是 undefined, 页面会静默把「进入 VR」按钮藏掉 —— 这是浏览器规范,不是 bug。 浏览器只认两种安全上下文:HTTPS(证书可信或用户点过继续访问),以及 http://localhost / 127.0.0.1(规范直接认定为潜在可信,不需要证书)。

路线 A · adb reverse + localhost(最省事,推荐)

头显里的 localhost 本来指头显自己,但用 adb reverse 把它的端口打回电脑, 就变成了没有证书警告的安全上下文。

PS> adb reverse tcp:8123 tcp:8123          # 头显的 8123 → 电脑的 8123
PS> adb reverse --list                      # 确认 UsbFfs tcp:8123 tcp:8123
PS> adb shell am start -a android.intent.action.VIEW `
      -d "http://localhost:8123/spacecraft-anatomy-VR版.html?r=1" com.igalia.wolvic

路线 B · 局域网 HTTPS(自签证书)

给同 WiFi 下的其他设备用。自签证书必须带 IP SAN,只写 CN 会报「名称不匹配」。

PS> & 'C:\Program Files\Git\usr\bin\openssl.exe' req -x509 -newkey rsa:2048 -sha256 -days 1095 -nodes `
    -keyout key.pem -out cert.pem -subj '/CN=192.168.1.10' `
    -addext 'subjectAltName=IP:192.168.1.10,IP:127.0.0.1,DNS:localhost'
代价:证书警告会拦住整个请求。实测在 Wolvic 上,警告页显示的那几秒服务器一条请求都收不到; 必须在头显里用射线点「Advanced…」→ 继续访问,每次会话都要点一次。 另外 Wolvic 是 Gecko 内核,不读 Android 的用户证书库,把证书装进系统也治不了它。 所以路线 A 才是头显上的长期选择。

路线 C · Wolvic 卡在 VR 里出不来时

PS> adb shell am force-stop com.igalia.wolvic   # 强制结束,会一并终止 XR 会话

页面在沉浸会话中时,浏览器会忽略外部 intent,此时推新的 URL 是没用的 —— 先强停再拉起。

05 / Controls

怎么操作Keyboard & mouse, then hand controllers

桌面 / 触屏(两个工程通用)

操作作用
拖拽旋转视角(单指拖动)
滚轮 / 捏合推近拉远
点击 零件或清单条目选中该零件,右侧面板显示功能简介与技术参数
1 2 3 4正视 / 侧视 / 俯视 / 轴测
空格在「完全合拢」与「完全拆解」之间切换
底部滑块连续控制爆炸程度 0 → 100%
右上 低中高画质档位,默认低;低档关闭整条后处理并降到 0.8× 分辨率

VR 手柄(仅 VR 版)

按键索引作用
扳机buttons[0]射线指向零件 → 选中并弹出确认卡;没指到 → 切换爆炸 / 合拢
握把buttons[1]透视外壳(X-ray)
摇杆按下buttons[3]自转开关
左摇杆 上下摇杆 Y缩放 0.6× ~ 2.6×(默认 1.3×,模型放大同时后退,不会贴脸)
左摇杆 左右摇杆 X切换选中的零件
右摇杆 上下摇杆 Y连续调节爆炸程度
B 键 / 左摇杆减号键buttons[5] / [6]退出 VR 模式(按下即退);兜底:同时长按握把 + 摇杆 2 秒
为什么不用 A / B / X / Y 做游戏内操作。 xr-standard 标准只规定了 buttons[0..3](扳机 / 握把 / 触摸板 / 摇杆按下), [4] 之后是「平台保留或附加键」,索引因平台而异,规范还要求浏览器至少保留一个物理键给系统 UI。 所以游戏内动作只用标准位,A/B/X/Y 一律不绑。
06 / Tested & Known Limits

实测结论与已知限制What was verified, and what was not

真机(PICO Neo 3 + Wolvic 1.6.0 / Gecko 121)实测

项目结果
安全上下文自检isSecureContext = true · navigator.xr = true · immersive-vr = true
手柄暴露2 个输入源(left / right),mapping = xr-standard,各 4 条轴;右柄 6 键、左柄 7 键
沉浸渲染立体渲染正常,四块头锁面板与射线拾取均可用
左/右摇杆轴位实测摇杆数据落在 axes[0..1](并非规范要求的 [2..3]),已做轴位自适应兼容两种实现

已知限制

07 / Where Things Live

目录与备份Source, builds, archives

登月之旅(源码工程)
E:\trae_projects\moon-journey\
  ├─ index.html  js\  css\  assets\  vendor\   源码
  ├─ moon-journey.html          单文件成品(VR 版)
  └─ moon-journey-无3D.html      单文件成品(普通版)

航天器解剖图(Vite 工程)
E:\trae_projects\moon\spacecraft-anatomy\
  ├─ src\                       源码(loader / parts-data / scene / xr / vr-hud …)
  ├─ dist-single\               单文件成品(VR 版)
  ├─ dist-single-noxr\          单文件成品(普通版)
  └─ spec.md  spec-vr-ux.md     需求与规格文档

局域网 / 头显交付目录
E:\trae_projects\lan\           server.mjs + 证书 + 各项目成品
  └─ server.mjs                 8443 HTTPS · 8123 HTTP(adb reverse) · 8080 → 301

备份
E:\trae_projects\_backups\      各阶段源码打包
E:\trae_projects\moon\backups\  航天器解剖图改造前的源码备份

重新构建

# 航天器解剖图(两个版本一起出)
PS> cd E:\trae_projects\moon\spacecraft-anatomy
PS> npm run build:single                    # → dist-single/spacecraft-anatomy.html
PS> node scripts/build-single.mjs --no-xr    # → dist-single-noxr/spacecraft-anatomy-无3D.html

# 登月之旅
PS> cd E:\trae_projects\moon-journey
PS> node build-single.mjs                  # → moon-journey.html