ssheleg/xr-dev

quest-webxr

Use when the XR experience runs in the Meta Quest Browser: WebXR with IWSDK, three.js or A-Frame, PWA packaging with Bubblewrap, Horizon Billing and remote debugging.

ソースを見る

使い方

  1. インストールコマンドをコピーし、自分の環境へ導入する前にソースを確認します。
  2. 必要なツール、認証情報、対応環境を原文で確認します。
  3. 入力と成果物を指定し、出力を資料と照合します。
npx skills add https://github.com/ssheleg/xr-dev --skill quest-webxr

開始前の確認

  • 導入にはモデル契約、API枠、ファイルへのアクセス許可は含まれません。
  • スター数や導入数は活動の指標であり、独立した品質・安全性試験ではありません。
リポジトリの原文

見出し、例、コード、表、リンク、参照画像を含む原文を表示しています。

WebXR and PWAs on Horizon OS

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.

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.

  1. 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.

  1. Package only when the page is right.

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.

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.

Packaging as a 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.

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.

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.

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.

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/.

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.

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" / "покупки в вебе".

同じリポジトリから

関連する Skills

すべての Skills
ssheleg
コミュニティ

quest-native

Use when building or reviewing a native Meta Quest app in C or C++ against OpenXR: manifest and Gradle, loader, frame loop, swapchains, Vulkan, passthrough, required SDK levels. NOT for Unity, Unreal, Spatial SDK (quest-spatial), WebXR (quest-webxr), profiling (quest-perf) or Store submission (quest-store). Opt out: no xr, без xr. Triggers - "OpenXR app" / "приложение на OpenXR", "native Quest app" / "нативное приложение для Quest", "xrCreateInstance".

導入数
3
GitHub Stars
1
更新日
10月24日
ssheleg
コミュニティ

quest-perf

Use when a Meta Quest app drops frames, judders, overheats or must be profiled: frame budget per refresh rate, Dynamic Resolution, foveation, SpaceWarp, OVR Metrics, Perfetto or RenderDoc captures. NOT for the render loop itself (quest-native), Store VRCs (quest-store) or phone and desktop profiling. Opt out: no xr, без xr. Triggers - "dropped frames" / "просадка кадров", "Quest performance" / "производительность на Quest", "шлем греется".

導入数
2
GitHub Stars
1
更新日
10月24日
ssheleg
コミュニティ

quest-tooling

Use when setting up or driving the Meta Quest toolchain on a development machine: the metavr CLI and MCP server, Meta's agent skills, connecting a headset, managed tools, XR Simulator, no headset at all. NOT for app code (quest-native), reading a capture (quest-perf) or submitting a build (quest-store). Opt out: no xr, без xr. Triggers - "metavr", "connect the headset" / "подключить шлем", "adb к шлему", "XR Simulator".

導入数
2
GitHub Stars
1
更新日
10月24日