The 100-word answer
You want a customer to point a phone at your product page and see your 3D model sitting on their desk — no app install. Point an Android phone at a page with a GLB on it and Chrome's WebXR or Google Scene Viewer just reads it. Point an iPhone at the same page and nothing happens: Safari's AR Quick Look only reads USDZ, and that hasn't changed as of August 2026. The fix isn't a rewrite — it's a build step. Keep GLB as your source of truth, generate a companion USDZ alongside it, and let Google's `model-viewer` web component route each visitor to the file their device actually supports.
What Meta shipped on August 18, 2026
![]()
Meta pushed a major update to its open-source Immersive Web SDK (IWSDK) on August 18, 2026, adding built-in Model Context Protocol tooling — 32 MCP tools that let an AI coding agent take screenshots of a running WebXR scene, trigger controller input, inspect the ECS (entity-component-system) state, and debug physics without a human touching the headset. Run `iwsdk dev up` with AI enabled in your Vite config and the CLI spins up a headless Chromium session via Playwright; the agent writes code, reloads, reads the screenshot and console output, queries the scene graph, and fixes what's broken — the same write-observe-fix loop a human dev runs, minus the human.
That's a real jump for anyone building in-browser 3D viewers, configurators, or WebXR product demos: an agent can now catch a mispositioned camera rig or a broken interaction hook by literally looking at the render. It does nothing, however, for the actual asset-delivery problem underneath. IWSDK's MCP tools inspect and debug a WebXR *scene*. They don't touch the file format split that still decides whether your model shows up on a customer's phone at all — and that split is exactly where most teams shipping GLB catalogs get stuck.
The GLB-to-USDZ pipeline that actually ships AR
![]()
Here's the split, current as of Chrome 128 / iOS 18 in August 2026:
| Platform | AR viewer | Format required | Browser |
|---|---|---|---|
| Android | Google Scene Viewer | GLB (binary glTF) | Chrome, Edge |
| Android (in-page) | WebXR | GLB | Chrome, Edge |
| iOS | AR Quick Look | USDZ | Safari |
| Desktop | 3D preview only, no AR | GLB | Any evergreen browser |
`model-viewer` handles the routing for you once both files exist. Add the element to your page pointing `src` at the GLB and `ios-src` at the USDZ, set `ar` and `ar-modes` to `webxr scene-viewer quick-look`, and the component picks Quick Look on Safari, Scene Viewer or WebXR on Android Chrome, and falls back to a plain 3D view everywhere else. No format detection code, no user agent sniffing.
The part nobody automates for you is generating the USDZ. Apple's old `usdzconvert` Python tool is gone from Apple's developer site — it's been retired, and threads on the Alliance for OpenUSD forum confirm it as of this year. Two maintained alternatives fill the gap: Google's `usd_from_gltf` (C++, reads both `.gltf` and `.glb`, writes `.usdz` directly) and the Python-based `gltf2usd`. A minimal build step looks like this:
```bash
# Google's usd_from_gltf — converts GLB straight to USDZ
./usd_from_gltf oil-lantern.glb oil-lantern.usdz --metallic-roughness
# batch a whole catalog folder
for f in catalog/*.glb; do
./usd_from_gltf "$f" "${f%.glb}.usdz" --metallic-roughness
done
```
Wire that into whatever already exports your GLBs — a CI step, a cron job hitting the BitSoul REST API to pull fresh models, whatever fits your pipeline — and USDZ stops being a manual chore.
Gotchas that break the conversion
Three things bite teams the first time they run this:
Texture re-encoding bloats file size. USDZ repacks glTF's metallic-roughness textures into USD's material model, and a 4K PBR set that was 8MB as GLB can come out 15-20MB as USDZ. If you've already moved your catalog to KTX2 compression for engine delivery, don't feed those textures into the USDZ step — `usd_from_gltf` wants standard PNG/JPEG source textures, not Basis Universal.
Lighting reads differently in Quick Look. USD's physically-based rendering doesn't match glTF's PBR math 1:1, so a model lit for a Three.js or engine viewport can look noticeably flatter or shinier in Quick Look. Test on an actual iPhone before shipping — the desktop USDZ previewers built into most converters don't reproduce Quick Look's lighting.
`camera-controls` and AR placement fight each other on some Android builds. If a visitor rotates the model with `camera-controls` enabled, then taps the AR button, Scene Viewer sometimes launches with the rotated orientation baked in instead of the model's default pose. Reset the camera on the `ar-status` event before launch if you've seen this.
None of this is exotic — it's the same "one source file, multiple delivery targets" problem every asset pipeline eventually hits, just with Apple and Google disagreeing on the target format instead of two game engines disagreeing on axis conventions. If you're already scripting GLB exports, the USDZ step is one more line, not a new pipeline. A model like the Oil Lantern — small, single-material, handheld scale — is a good first test case before you batch-convert a full catalog, since placement-scale AR previews expose lighting and pose issues faster than a full scene would. Note that a free BitSoul account's two monthly downloads cover this kind of evaluation; production use on a live storefront falls under the paid membership tiers.
Ship the GLB. Generate the USDZ next to it. Let `model-viewer` sort out which phone gets which file — that part's been solved since 2019. What changed this month is that debugging the WebXR layer around it just got an AI agent that can watch the screen.
---
*This post is part of the Ultimate Guide to Free 3D Game Assets — BitSoul's complete reference for formats, texturing, rigging, optimization, and engine integration.*