quest-webxr

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

WebXR and PWAs on Horizon OS

Horizon OS 上的 WebXR 与 PWA

The web path trades native performance for a deploy that is a
git push
. It is the right choice for demos, catalogues, tools and anything that must also run outside a headset — and the wrong one when the frame budget is already tight.
Read
references/runtime-delivery.md
for session/capability negotiation, ordinary-screen fallback, assets, hosting and browser/PWA delivery checks.
For a whole-product roadmap or stage audit, use
quest-lifecycle
; a single technical task stays with this owner. If absent, identify the current stage, its evidence and the next prerequisite inline.
Web 路线以牺牲原生性能为代价,换来只需一次
git push
即可完成部署。对于演示、产品目录、工具,以及任何还必须能在头显之外运行的内容,这是正确选择;但当帧预算已经非常紧张时,它就是错误选择。
阅读
references/runtime-delivery.md
,了解会话/能力协商、普通屏幕回退、资源、托管以及浏览器/PWA 交付检查。
如果需要完整产品的路线图或阶段审计,请使用
quest-lifecycle
;单个技术任务仍归本 skill 处理。如果
quest-lifecycle
不存在,请在当前内容中确定当前阶段、相应证据和下一项前置条件。

The order that avoids rework

避免返工的顺序

  1. Build the site and test it in the headset's Browser first. A packaged PWA uses the same rendering engine, so every compatibility and performance problem is visible before packaging.
  2. Debug it remotely — Chrome DevTools from the machine against the device, over the Android platform tools. The Browser specifications page carries the user-agent string and the supported content sizes.
  3. Package only when the page is right.
  1. 先构建网站并在头显的 Browser 中测试。 打包后的 PWA 使用相同的渲染引擎,因此每个兼容性和性能问题都会在打包前暴露。
  2. 进行远程调试——在计算机上通过 Android platform tools 使用 Chrome DevTools 连接设备。Browser 规格页面提供 user-agent 字符串和支持的内容尺寸。
  3. 仅当页面正确后再打包。

Entering immersive mode like a real app

像真正的应用一样进入沉浸模式

A PWA launched from the headset's library should not show a 2D landing page. Ask for the session as soon as the page has loaded:
javascript
const supported = await navigator.xr?.isSessionSupported('immersive-vr');
if (supported) {
  const session = await navigator.xr.requestSession('immersive-vr');
  await renderer.xr.setSession(session);          // three.js
}
A-Frame does the same through
scene.enterVR()
on
renderstart
. Meta's own snippets gate this on
window.getDigitalGoodsService !== undefined
— present inside a packaged PWA, absent in the plain Browser — so the page still behaves when someone opens the URL on a laptop.
从头显图库启动的 PWA 不应显示 2D 落地页。页面加载后立即请求会话:
javascript
const supported = await navigator.xr?.isSessionSupported('immersive-vr');
if (supported) {
  const session = await navigator.xr.requestSession('immersive-vr');
  await renderer.xr.setSession(session);          // three.js
}
A-Frame 通过在
renderstart
时调用
scene.enterVR()
实现相同效果。Meta 自己的代码片段以
window.getDigitalGoodsService !== undefined
为启用条件——该表达式在打包后的 PWA 中存在,在普通 Browser 中不存在——因此,即使用户在笔记本电脑上打开 URL,页面仍能正常工作。

Which framework

选择哪个框架

ChoiceWhen
IWSDK (
npm create @iwsdk@latest
)
Meta's recommended path for both screen-based 3D and immersive WebXR; ships the testing story (IWER on desktop) and build/deploy guides
three.jsan existing three.js codebase, full control of the renderer
A-Framedeclarative scenes, fastest to a prototype
Meta also ships the
hz-iwsdk-webxr
skill for the IWSDK path — use it for IWSDK-specific work; this skill decides whether the web lane is the right one and owns the packaging and distribution seam.
选择使用时机
IWSDK (
npm create @iwsdk@latest
)
Meta 推荐的路径,适用于基于屏幕的 3D 和沉浸式 WebXR;提供完整的测试方案(桌面端 IWER)以及构建和部署指南
three.js已有 three.js 代码库,需要完全控制渲染器
A-Frame声明式场景,可最快完成原型
Meta 还提供用于 IWSDK 路线的
hz-iwsdk-webxr
skill——遇到 IWSDK 专项工作时使用它;本 skill 负责判断 Web 路线是否合适,并负责打包和分发衔接部分。

Packaging as a PWA

打包为 PWA

Step by step, including the Digital Asset Links step that decides whether an immersive PWA launches at all:
references/pwa-packaging.md
.
bash
npm install --global @meta-quest/bubblewrap-cli    # verified at 1.24.1, Node 18+
bubblewrap --version
Prerequisites, in the order Bubblewrap will need them:
  • the site served over HTTPS with a valid Web App Manifest;
  • an app created in the Developer Dashboard — its Meta Horizon Application ID is required if the PWA uses in-app purchases;
  • a signing key, or the details to create one during
    init
    ;
  • a headset in Developer Mode for sideload testing.
On first run Bubblewrap offers to download a matching JDK and Android command-line tools; let it, unless the environment manages those itself. During Quest initialisation it asks whether to include Horizon Billing — answer with the Application ID ready if IAP is in scope, because adding it afterwards means regenerating the project.
分步说明见
references/pwa-packaging.md
,其中包括决定沉浸式 PWA 能否启动的 Digital Asset Links 步骤。
bash
npm install --global @meta-quest/bubblewrap-cli    # verified at 1.24.1, Node 18+
bubblewrap --version
按 Bubblewrap 所需顺序排列的前置条件:
  • 通过 HTTPS 提供的站点,并配有有效的 Web App Manifest;
  • 在 Developer Dashboard 中创建的应用——如果 PWA 使用应用内购买,则必须提供其 Meta Horizon Application ID;
  • 签名密钥,或用于在
    init
    期间创建签名密钥的信息;
  • 用于侧载测试且开启 Developer Mode 的头显。
首次运行时,Bubblewrap 会询问是否下载匹配版本的 JDK 和 Android 命令行工具;除非环境已自行管理这些工具,否则应允许它下载。在 Quest 初始化期间,它会询问是否包含 Horizon Billing——如果 IAP 在范围内,请准备好 Application ID 后再作答,因为之后再添加意味着必须重新生成项目。

Monetisation and platform features

变现与平台功能

In-app purchases in a WebXR PWA go through Horizon Billing plus the Digital Goods API; achievements, leaderboards and add-ons have server-to-server APIs on the web documentation index. Set IAP up before packaging.
WebXR PWA 中的应用内购买通过 Horizon Billing 和 Digital Goods API 完成;成就、排行榜和附加内容具有 server-to-server API,可在 Web 文档索引中找到。在打包之前完成 IAP 设置。

Distribution

分发

A packaged PWA is an Android package and travels the same road as a native build: release channels, review, VRC — see
quest-store
, and Meta's
hz-store-pwa
skill for the PWA-specific store steps. 2D (non-immersive) PWAs are judged against a subset of the VRCs, with a list of permissions that trigger automatic rejection.
打包后的 PWA 是一个 Android package,与原生构建走相同流程:发布渠道、审核、VRC——参见
quest-store
,以及 Meta 的
hz-store-pwa
skill,后者包含 PWA 专用的商店步骤。2D(非沉浸式)PWA 仅依据 VRC 中的一部分进行审核,并有一组会触发自动拒审的权限。

Performance, honestly

性能,如实呈现

  • The browser has its own counters — draw-call metrics in the web docs — and the native profilers in
    quest-perf
    do not see inside the page.
  • The frame budget is the same as native (13.9 ms at 72 Hz); the overhead is not. Measure in the headset, never in a desktop browser window.
  • requestAnimationFrame
    on the
    XRSession
    is the frame clock; a page that keeps a DOM animation running alongside it pays twice.
  • Browser 有自己的计数器——Web 文档中的 draw-call 指标——而
    quest-perf
    中的原生性能分析器无法看到页面内部。
  • 帧预算与原生相同(72 Hz 下为 13.9 ms),但额外开销并不相同。务必在头显中测量,绝不要只在桌面浏览器窗口中测量。
  • 在
    XRSession
    上调用的
    requestAnimationFrame
    是帧时钟;如果页面在它运行时仍保持 DOM 动画,就会付出双倍开销。

Where to read

阅读位置

text
index:  https://developers.meta.com/horizon/llmstxt/documentation/web/llms.txt/
page:   https://developers.meta.com/horizon/llmstxt/documentation/web/<slug>.md
Useful slugs:
pwa-webxr
,
pwa-packaging
,
pwa-overview-gs
,
browser-specs
,
browser-remote-debugging
,
3d-web
,
ps-iap
,
ts-webxr-perf-drawcall
. IWSDK's own guides live under
documentation/iwsdk/guides/
.
text
index:  https://developers.meta.com/horizon/llmstxt/documentation/web/llms.txt/
page:   https://developers.meta.com/horizon/llmstxt/documentation/web/<slug>.md
有用的 slug:
pwa-webxr
、
pwa-packaging
、
pwa-overview-gs
、
browser-specs
、
browser-remote-debugging
、
3d-web
、
ps-iap
、
ts-webxr-perf-drawcall
。
IWSDK 自身的指南位于
documentation/iwsdk/guides/
下。

Gotchas

常见陷阱

  • A 2D landing page inside a PWA reads as a broken app — request the session on load.
  • bubblewrap
    is Meta's fork
    (
    @meta-quest/bubblewrap-cli
    ), not the Google package; the Quest-specific prompts only exist in it.
  • Billing is a packaging-time decision, not a runtime one.
  • Testing in the desktop browser proves logic and lies about performance.
Read from the Meta web documentation (
pwa-webxr
,
pwa-packaging
,
3d-web
) on 2026-09-20; versions there move — re-check
bubblewrap
and IWSDK versions before quoting them.
  • PWA 中的 2D 落地页会显得像损坏的应用——应在加载时请求会话。
  • bubblewrap
    是 Meta 的分支版本
    (
    @meta-quest/bubblewrap-cli
    ),而不是 Google 的包;只有它才包含 Quest 专属提示。
  • Billing 是打包阶段的决定,而不是运行时决定。
  • 在桌面浏览器中测试只能证明逻辑正确,却会给出误导性的性能结果。
内容读取自 Meta Web 文档(
pwa-webxr
、
pwa-packaging
、
3d-web
),日期为 2026-09-20;其中的版本会变化——引用
bubblewrap
和 IWSDK 版本前请重新核对。

Triggers

触发词

More phrases that route here: "PWA for Quest" / "PWA для Quest", "A-Frame", "bubblewrap", "web app manifest for the headset", "browser on Quest" / "браузер в шлеме", "remote debug the headset browser" / "отладить браузер шлема", "web IAP" / "покупки в вебе".
更多会将任务路由到这里的短语:"PWA for Quest" / "PWA для Quest"、"A-Frame"、"bubblewrap"、"web app manifest for the headset"、"browser on Quest" / "браузер в шлеме"、"remote debug the headset browser" / "отладить браузер шлема"、"web IAP" / "покупки в вебе"。