☰
RuView 三维点云查看器上云:GitHub Pages 静态托管 + 本地实时数据回连(ADR-094)方案全解析
2026/11/1 11:43:26 网站建设 项目流程

RuView 三维点云查看器上云:GitHub Pages 静态托管 + 本地实时数据回连(ADR-094)方案全解析

【免费下载链接】RuViewπ RuView turns commodity WiFi signals into real-time spatial intelligence, vital sign monitoring, and presence detection — all without a single pixel of video.项目地址: https://gitcode.com/GitHub_Trending/wi/RuView

本篇基于仓库 docs/adr/ADR-094-pointcloud-github-pages-deployment.md 展开,围绕其架构决策梳理「单一 HTML 查看器如何在纯静态 GitHub Pages 上运行,又能通过 URL 参数回流本地 ESP32 + WiFi CSI 实时点云」的完整技术路线。读者读完可以掌握四种传输模式的设计取舍、/api/splatsJSON 数据契约、CORS 来源白名单实现,以及对应 CI 部署与验收标准。文中所有实现结论均有仓库源码佐证。

RuView 的wifi-densepose-pointcloudcrate 把「相机深度 + WiFi CSI + mmWave」融合成实时的稠密三维点云,并在浏览器里以 Three.js 场景呈现。但早期这套查看器只活在本地:由 Rust(Axum)二进制在回环地址上托管,页面从同源/api/splats拉数据。这带来一个体验不对称——访客打开首页就能一键体验 WiFi 姿态与 Observatory 的 hosted demo,却看不到 v0.7+ 传感器融合最具视觉冲击力的点云演示,除非自己克隆仓库、编译 Rust、接上 ESP32 并对着摄像头。ADR-094 正是为了解决这个缺口而提出的部署与双传输(demo/实时)方案。

1. 背景:Local-only 查看器的体验缺口与两个「天真修法」

1.1 现状盘点

ADR 记录的初始状态(原文 Context 部分)包含四个关键事实,均可在仓库中印证:

事实仓库证据
查看器是随 Rust 二进制一起分发的单文件 HTML查看器源码为 v2/crates/wifi-densepose-pointcloud/src/viewer.html,crate 描述为 "Real-time dense point cloud from camera depth + WiFi CSI tomography",见 v2/crates/wifi-densepose-pointcloud/Cargo.toml
Axum 服务器默认绑定127.0.0.1:9880CLI 定义见 v2/crates/wifi-densepose-pointcloud/src/main.rs#L41-L49:--bind默认127.0.0.1:9880
前端轮询同源/api/splatsv2/crates/wifi-densepose-pointcloud/src/stream.rs 中路由/api/splats每帧输出最新高斯泼溅(Gaussian splats);viewer 的 URL 参数注释见 viewer.html 中?backend相关行
无 Pages 托管,README 的 Live 演示链接指向 moved-content 章节README.md#L193 的▶ Live 3D Point Cloud链接已指向 Pages 演示路径;早期版本链接到 docs/readme-details.md

同期,同仓库另外两个演示(Live Observatory、Dual-Modal Pose Fusion)已经走 GitHub Pages 托管路线,于是产生了「一键可预览 WiFi 姿态演示,却无法预览点云」的不对称。

1.2 两个被否决的「天真修法」

ADR 原文明确排除了两种直觉方案:

  1. 直接丢一个静态 HTML 到 Pages:viewer 里的fetch("/api/splats")在 Pages 上必然 404,Canvas 永远停在 "Loading…",不能工作。
  2. 把一份固定样本数据集烤进 HTML:虽然解决了加载态,但彻底丢掉了「实时数据」这个核心叙事,还把查看器分叉成「演示 build」和「真实 build」两个会逐渐漂移的版本。

这构成 ADR 的判定基线:绝不允许两个 build 分叉——只能是"一个文件、一条渲染路径、同一套 bug"。

2. 决策:单文件 viewer + URL 参数驱动的四种传输模式

核心决策一句话概括:只发布一个 viewer,由 URL 查询参数自动选择传输层,并部署到 Pages 的pointcloud/目录。下面按 ADR 原文整理四种模式,并对照仓库中 viewer.html 的真实实现。

2.1 默认模式:MediaPipe Face Mesh 浏览器内点云

当无任何查询参数打开 Pages 演示时(仓库 viewer 中backendArg缺省为auto,但无同源后端时会静默落到合成 demo,见 viewer.html 中backendArg = urlParams.get("backend") || "auto"):

  • 页面呈现一个"Enable camera" CTA(实现中按钮文案为▶ Project Subject — render your face into the Vault),点击后请求摄像头权限;
  • 浏览器内运行MediaPipe Face Mesh(约 30 fps、478 个精细化关键点),把访客自己的脸渲染成点云——这是本地「深度反投影面部几何」在浏览器里最接近的等价物,呼应了催生本文档的那句原话"I could see the outline of my face in points";
  • 渲染做x 镜像以符合自拍惯例,并把 Face Mesh 的相对 z 映射到与实时/api/splats载荷相同的世界坐标范围,从而单一渲染路径同时驱动 demo 与 live;
  • 模式角标为● DEMO Your Face (MediaPipe)(viewer 源码中对应.face样式分支);
  • 用户拒绝授权、关掉提示或设备没有摄像头时,自动回退到程序化脚手架场景:地面网格、墙体、呼吸人体与 17 关键点骨架;
  • 全部处理发生在客户端,视频帧绝不出浏览器;预计 splat 规模为"脸部约 480–500 个 splat + 约 110 个地面/墙体上下文 splat"。

值得补充的实现细节:仓库 viewer 对 Face Mesh 还做了稠密化——不仅按 478 个顶点投点,还沿FACEMESH_TESSELATION网格边插值(代码注释 "6 splats per edge"),使脸部点云远超顶点数,视觉上更接近本地相机深度反投影的密度。同时当摄像头开启且处于 live/remote 模式时,浏览器人脸点云可以叠加在真实后端 splat 之上(viewer 中handleData检测到latestFaceLandmarks时的 overlay 分支),这在 ADR 里被视为默认 demo 的附加能力。

2.2 Auto 模式(?backend=auto)

从同源/api/splats拉数据——即本地开发场景(ruview-pointcloud serve把 viewer 与 API 一起托管)。任何失败(404、网络错误、CORS)都静默回退到合成 demo 渲染,保证页面标签页永不"死"。

2.3 Remote 模式(?backend=<url>)

从<url>/api/splats拉数据,这是集成 ESP32 的路径:

  1. 用户本地运行ruview-pointcloud serve --bind 127.0.0.1:9880,ESP32-S3 通过 UDP 3333 端口把 CSI 送进融合管线;
  2. 打开?backend=http://127.0.0.1:9880,hosted Pages viewer 就变成本地 Rust 融合管线(camera depth + WiFi CSI + mmWave)的薄客户端,无需 clone、无需重新编译;
  3. viewer 提供📡 Connect ESP32…按钮(源码中#esp-cta),提示输入 URL,持久化到localStorage后带查询参数重载。

仓库 viewer 的实际 URL 参数解析注释与 ADR 相比还多定义了一个取值,四态齐备:

?backend=<url> → fetch splats from <url>/api/splats(需要目标允许 CORS) ?backend=auto → 尝试 /api/splats,失败则回退合成 demo(默认) ?backend=demo → 永远渲染合成 demo,不做任何网络请求 ?live=1 → 要求实时,失败显示错误而非 demo 回退

因此实现层面真实存在五个有效状态:auto(无参默认)、demo、<url>远程、live=1严格实时,以及相机开启时的 Face Mesh 叠加层。合成 demo 回退时模式角标为● DEMO Synthetic(viewer 中.demo分支)。

2.4 Strict-live 模式(?live=1)

禁用 demo 回退。若所选传输失败,信息面板被替换为显式离线文案(● OFFLINE — Live backend required but unreachable),适合把 viewer 嵌入状态页或信息亭(kiosk)。viewer 源码在回退处先检查live=1才决定是否渲染离线面板。

2.5 合成帧与实时载荷的 JSON 契约完全一致

ADR 强调:浏览器内合成帧生成器输出的 JSON 形状必须与实时/api/splats载荷逐一对应:

字段说明
splats高斯泼溅数组(live 模式下由pointcloud.rs序列化)
countsplat 数量
frame帧序号(viewer 以它判重、计算帧率)
live是否实时来源
pipeline管线信息对象(skeleton、vitals等)

在 viewer.html 的合成帧构造中可看到这组字段被原样写出;handleData → updateSplats → drawSkeleton这条唯一渲染管线对 demo 与 live 一视同仁,视觉回归会在两种模式中同时暴露。

3. Remote 模式能工作的前提:CORS 来源白名单(源码级)

HTTPS 的 Pages 页面要 fetch 纯 HTTP 回环地址,需要两层放行:浏览器把127.0.0.1/localhost视为"potentially trustworthy"(Chrome 94+、Firefox 116+、Safari 16.4+,所以不存在 mixed-content 拦截),以及本地服务器要回答 CORS 预检。

仓库 v2/crates/wifi-densepose-pointcloud/src/stream.rs 中serve()安装了一个tower_http的CorsLayer,用AllowOrigin::predicate精确放行三类来源,不是通配 CORS:

https://ruvnet.github.io —— 已发布的 Pages 演示 http://localhost:* —— 开发者直接打开随包 viewer.html http://127.0.0.1:* —— 同上(回环) null —— file:// 来源

CORS 层同时限定GET/OPTIONS方法与Content-Type请求头。任何其它来源(如公网主机名)一律拒绝。serve()在启动时还会打印防护提示:绑定到0.0.0.0会把 camera/CSI/vitals 暴露到网络,必须显式用--bind 127.0.0.1:9880收敛到回环(main.rs 的 Serve 命令注释同样写明该安全默认值)。

服务端路由与载荷结构(stream.rs):

路由作用
/返回内置viewer.html
/api/cloud返回点云摘要(points数量、bounds_min/max、前 1000 个点等)
/api/splats返回高斯泼溅帧:splats、count、live、frame、pipeline、timestamp
/api/status运行状态
/health存活探针

单个 splat 的 Rust 结构(v2/crates/wifi-densepose-pointcloud/src/pointcloud.rs)为GaussianSplat { center: [f32;3], color: [f32;3], opacity: f32, scale: [f32;3] },这与 viewer 渲染器消费的splats数组字段一一对应——这正是「合成帧能走同一条渲染路径」的底层原因。

4. CI 部署:GitHub Actions 推送即发布

ADR 规划的部署工作流是.github/workflows/pointcloud-pages.yml,而该文件在当前仓库中已存在:

  • 触发条件:每次push到main且改动触及 viewer 文件;另支持workflow_dispatch手动触发;
  • 动作:把 viewer 复制暂存为_site/pointcloud/index.html,再经peaceiris/actions-gh-pages@v4部署到gh-pages/pointcloud/;
  • 关键参数keep_files: true:保留既有 observatory、pose-fusion 与 nvsim 部署,避免互相覆盖。

ADR 特别指出这是与 ADR-092 nvsim dashboard 相同的双传输模式(demo/实时由同一份代码承载),详见 docs/adr/ADR-092-nvsim-dashboard-implementation.md。

5. 影响评估

5.1 正面影响

  • 一击即达的 demo:访客点击 README 的▶ Live 3D Point Cloud(README.md#L193)进入可用 Three.js 场景,<1 s 出画面,无需任何工具链,与前两个 hosted demo 对齐。
  • 按需接入真实数据:自备ruview-pointcloud serve主机的用户可复用同一个 hosted viewer URL 并追加?backend=<url>——hosted demo 同时充当自托管后端的薄客户端,无需 clone/rebuild。
  • 单一路径:合成帧与实时帧走同一条handleData → updateSplats → drawSkeleton管线,demo 与 live 同步暴露视觉回归。
  • 无需部署后端:Pages 只托管静态 HTML,不需要在公网起 Axum 主机,也没有按访客预置 CSI/相机管线的开销。
  • 不破坏既有部署:keep_files: true+pointcloud/目标目录使 observatory/、pose-fusion/、nvsim/ 与 gh-pages 根 index 均不受影响。

5.2 负面 / 权衡

  • Face Mesh ≠ CSI:浏览器摄像头 + MediaPipe 提供真实面部几何,但不是 CSI 推算的位姿;想验证 WiFi 驱动路径仍需?backend=<host>。程序化回退同样非 WiFi 驱动,纯粹是视觉脚手架。ADR 明确接受这一取舍——hosted demo 的目标是传达本地管线输出(用户的点云"形状"),而不是在浏览器里复刻 WiFi 物理;后者留给未来 ADR(融合 crate 的 WASM 移植)。
  • Remote 模式背负 CORS 义务:想分享后端的人需在自建服务上加入对 Pages demo 来源的Access-Control-Allow-Origin;ADR 将这一点写进 workflow 生成的 README,并明确不提供公共 CORS 代理。
  • 合成生成器住在 viewer 里:约 80 行程序化 JS 成为viewer.html的一部分。可接受——该文件本就是客户端渲染 bundle,且生成器有界且惰性(确定性、无 I/O、无 eval)。实现层面 viewer 的合成脚手架由pushFoundationContext(地板/墙体/呼吸体/骨架)构成。
  • 本文档不含录制回放:未来可能的?recording=<url>.jsonl回放模式明确不在本文档范围内。

5.3 中性影响

本地开发体验不变:ruview-pointcloud serve依旧从内嵌 asset 提供viewer.html,viewer 因?backend缺省为auto依旧请求/api/splats。Rust crate 零改动——本文档方案 = HTML + workflow 而已(当前仓库在 ADR 之外,viewer 本身已迭代出0.2.0-face-mesh版本,见其<meta name="ruview-viewer-version">,属实现侧自然的演化)。

6. 实现改动清单与验收标准

6.1 文件改动表(ADR §4)

文件改动
v2/crates/wifi-densepose-pointcloud/src/viewer.html增加 URL 参数传输选择器(backend、live)、合成帧生成器、demo 回退路径、模式角标,约 +120 行、无行为删除
.github/workflows/pointcloud-pages.yml新 workflow:暂存到_site/pointcloud/index.html,keep_files: true部署到gh-pages/pointcloud/;viewer 变更 + 手动触发
README.md▶ Live 3D Point Cloud链接在首次部署成功后改指 Pages 演示路径(README.md#L193 已更新,独立跟踪、不阻塞本文档)
docs/adr/README.mdADR 索引补 ADR-094 行

6.2 六项验收门(Acceptance Gates)

ADR 定义的"已实现(Implemented)"判据如下,可作为运维回归清单:

  1. 向main推送带 viewer 改动的 commit 触发pointcloud-pages.yml,并在60 秒内部署到gh-pages/pointcloud/;
  2. Pages 的/pointcloud/加载并呈现 CTA,授权后把访客的脸渲染成点云,角标● DEMO Your Face (MediaPipe)且 splat/frame 计数非零;拒绝授权则回退程序化场景、角标● DEMO Synthetic;
  3. 首次部署后既有演示(根路径、pose-fusion.html、nvsim/)仍然可达(人工冒烟);
  4. ?live=1显示● OFFLINE面板(Pages 上不存在同源后端);
  5. ?backend=https://example.invalid在一个轮询周期(约 500 ms)内回退到 demo,控制台不抛错;
  6. 本地./target/release/ruview-pointcloud serve后打开http://127.0.0.1:9880/仍以 live 模式渲染,角标● LIVE Local Backend。

对照当前仓库:ADR-094 在文档层面状态为Proposed (2026-04-29),但源码侧已出现实现证据——viewer.html 具备全部传输模式与角标分支、.github/workflows/pointcloud-pages.yml已落盘、README 的演示链接已指向 Pages 路径。阅读时建议以仓库当前代码为准,将 ADR 视作方案的契约与验收依据。

7. 明确不在范围内的事项

  • 在浏览器回放录制的 JSONL 帧(留待未来 ADR);
  • 在浏览器以 WASM 执行融合管线(需要移植 camera + mmWave 路径,已推迟);
  • 鉴权 / 签名 splat 载荷——属于后端关注点,不受此纯客户端改动影响;
  • 为没有自建后端的用户托管公共 CORS 代理。

8. 继续深入阅读

  • 决策索引:docs/adr/ADR-092-nvsim-dashboard-implementation.md(同一双传输模式先例)、docs/adr/ADR-059-live-esp32-csi-pipeline.md(ESP32 实时 CSI 管线)、docs/adr/ADR-079-camera-ground-truth-training.md(相机真值训练)
  • 实现源码:viewer.html(单文件查看器与四种传输)、stream.rs(Axum 服务、CORS 白名单、/api/splats)、pointcloud.rs(GaussianSplat数据契约)、main.rs(CLI 子命令:serve/capture/demo/cameras/train/csi-test/fingerprint)
  • 部署:.github/workflows/pointcloud-pages.yml
  • 仓库总览:README.md 的▶ Live 3D Point Cloud入口与docs/readme-details.md

一句话收束:ADR-094 的范式是「一个 viewer、一条渲染路径、URL 参数切传输」——它用最小改动把本地专属的实时点云演示搬上纯静态 Pages,同时保留真实 WiFi/ESP32 数据回连的能力,是 RuView v0.7+ 传感器融合工作在公开演示层面与既有 hosted demo 对齐的关键一步。

【免费下载链接】RuViewπ RuView turns commodity WiFi signals into real-time spatial intelligence, vital sign monitoring, and presence detection — all without a single pixel of video.项目地址: https://gitcode.com/GitHub_Trending/wi/RuView

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询