Skip to main content

iwsdk-dev

MUST read this skill BEFORE developing VR/MR/desktop 3D applications using IWSDK (Immersive Web SDK). Covers project scaffolding, headless browser setup, CLI tools, reference system, ECS debugging, XR emulation, verification workflows, deployment, and known issues.

Source facts

Repository
meta/immersive-web-sdk
Last source activity
October 22, 2026 at 02:32
Detected SKILL.md language
English
Stars
349
Forks
72

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
16 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
iwsdk-dev
description
MUST read this skill BEFORE developing VR/MR/desktop 3D applications using IWSDK (Immersive Web SDK). Covers project scaffolding, headless browser setup, CLI tools, reference system, ECS debugging, XR emulation, verification workflows, deployment, and known issues.
# IWSDK Development Guide [iwsdk.dev](https://iwsdk.dev) · [GitHub](https://github.com/facebook/immersive-web-sdk) This guide is for AI agents and developers building WebXR or desktop browser 3D applications with IWSDK in cloud/headless Linux environments (no physical GPU, no display server). It assumes Node.js satisfies IWSDK's package engine range: `>=20.19.0 <21.0.0-0 || >=22.12.0 <23.0.0-0 || >=24.0.0`. The managed dev browser uses Playwright Chromium; the dev plugin installs the matching Chromium binary when it is missing. Explain immersive terms in plain language when they first matter instead of assuming the reader knows them. In particular, introduce XR (an immersive session), IWER (IWSDK's browser-based XR emulator), ECS (entity-component system), and controller target-ray versus grip poses with a link to the applicable IWSDK guide or concept page. ### CLI-First Operating Model This guide is intentionally **CLI-first** for cloud-based harnesses. Treat `npx @iwsdk/cli ...` commands as the primary control surface for setup, runtime inspection, screenshots, ECS debugging, XR emulation, and reference queries. The scoped package name is a security boundary: do not shorten it to the unscoped package name, because npx can download that unrelated package when a local binary is missing. Reason: MCP adapter support in cloud harnesses is often missing, stale, or partially wired. Relying on MCP tool availability can degrade generation quality because the agent may plan around tools that are not actually connected. Use MCP tools only when the harness clearly exposes them and they are already working; otherwise use the CLI commands in this guide. Do not rewrite CLI examples into MCP-only workflows. --- ## 1. Project Scaffolding Always use the official `@iwsdk/create` package. The interactive CLI is a short human-facing flow: project name when absent, starting point, then recommended settings or an advanced setup. It does not ask users to classify every low-level WebXR capability. Recommended settings use TypeScript, initialize Git, and install dependencies. **Agent workflow:** infer the requested experience and features, map that intent to the flags below, and run with `--yes`. The Create CLI deliberately does not infer product intent for an agent. Do not replay or script the interactive questions. When the request is ambiguous in a way that changes the starter or a material feature, ask the user. Cloud coding harnesses often start inside an already-created repository. In that case, scaffold in place with `.` and pass `--force` explicitly: ```bash npx @iwsdk/create@latest . --yes --force --target vr ``` Create refuses every non-empty target without `--force`. Forced scaffolding overwrites conflicting generated files, preserves unrelated files, and reuses the existing Git repository. `--yes` answers setup questions; it does not grant overwrite permission. ### Step 1: Starting Point | Target | Flag | When to use | |--------|------|-------------| | **VR** | `--target vr` | Fully immersive virtual environment. | | **Mixed reality** | `--target ar` | Passthrough experience with virtual content in the physical environment. | | **Desktop 3D** | `--target browser` | Desktop browser 3D app without an immersive session. This dedicated starter has `xr: false`, browser locomotion, canvas pointer input, browser interaction support, and IWER disabled. Camera look is app-owned. | The flag value remains `ar` because it maps to WebXR's `immersive-ar` session mode; the user-facing starting point is mixed reality / passthrough. ### Step 2: Features | Feature | Flag | Enable when… | Disable when… | |---------|------|-------------|---------------| | **Physics** | `--physics` / `--no-physics` | Gravity, collisions, bouncing, throwing. | UI-only, data viz, grid-snapping board games. | | **Locomotion** | `--locomotion` / `--no-locomotion` | VR user moves through a large space (teleport/slide). The Desktop 3D starter already supplies browser controls. | Stationary VR experience. | | **Grabbing** | `--grabbing` / `--no-grabbing` | VR/MR users pick up, move, or manipulate objects. The Desktop 3D starter has browser interaction behavior built in. | Gaze/pointer-only or observational VR/MR experience. | | **Scene Understanding** | `--scene-understanding` / `--no-scene-understanding` | MR: interact with real-world surfaces. | MR without surface interaction. | | **Environment Raycast** | `--environment-raycast` / `--no-environment-raycast` | MR: cast rays against real-world geometry. | No real-world hit testing needed. | Create derives WebXR feature requirements from the target and these high-level features. Raw tri-state WebXR settings are not interactive choices and are not agent-facing scaffolding flags. ### Step 3: Project Setup | Choice | Flag | Default with `--yes` | |--------|------|----------------------| | **Language** | `--language ts` / `--language js` | TypeScript | | **Coding-tool files** | `--ai-tools <tools>` (comma-separated) or `--ai-tools none` | None | | **Git** | `--git` / `--no-git` | Initialize a repository | | **Dependencies** | `--install` / `--no-install` | Install dependencies | | **Existing target** | `--force` | Required only when the target directory contains files | ### Step 4: Source (optional) | Flag | Effect | |------|--------| | *(none)* | Matching SDK packages from npm; starter source is embedded in `@iwsdk/create`. | | `--canary` | Baked-in CloudFront CDN canary bundle. | | `--canary <url>` | Custom bundle URL for internal builds. | ### Examples ```bash # VR game (stationary, physics for gameplay) npx @iwsdk/create@latest space-pong --yes --target vr --physics --no-locomotion --grabbing # Mixed reality object placer npx @iwsdk/create@latest mr-placer --yes --target ar --physics --scene-understanding --environment-raycast # Desktop 3D game (no headset; locomotion and pointer input are scaffolded) npx @iwsdk/create@latest desktop-game --yes --target browser --physics # Existing cloud-harness repository (explicitly confirm generated-file overwrite) npx @iwsdk/create@latest . --yes --force --target vr ``` --- ## 2. Headless Browser & SwiftShader ### Auto-Detection (0.4.x) When `@iwsdk/vite-plugin-dev` launches its managed Playwright browser, it auto-detects GPU availability first: 1. Probes `/dev/dri` for render nodes. 2. Falls back to **SwiftShader** (Playwright Chromium's bundled software renderer) when no GPU is found. 3. Logs the selected backend every launch. **No manual patching required** in 0.4.x. Use the normal generated app workflow: `npm run dev` or `npx @iwsdk/cli dev restart --open --foreground`. ### Environment Variable Override ```bash IWSDK_GPU=auto # Default — auto-detect IWSDK_GPU=gpu # Force hardware GPU IWSDK_GPU=swiftshader # Force SwiftShader (software rendering) ``` ### Legacy Notes Current 0.4.x apps should not patch `node_modules` or Chromium launch args. If an older 0.3.x harness carried a manual SwiftShader patch, treat that as historical migration context and remove it after upgrading to 0.4.x. ### Playwright Browser Revision Recovery The vite plugin declares `playwright: ^1.58.2`; this repo lockfile currently resolves it to Playwright 1.58.2. If an environment has a mismatched Playwright browser cache, launch can fail with: ``` Executable doesn't exist at …/chromium_headless_shell-1208/… ``` **Preferred fixes:** 1. **Install the matching Playwright browser revision:** ```bash npx playwright@1.58.2 install chromium ``` 2. **Align the project Playwright version with the plugin's resolved version:** ```bash npm install playwright@1.58.2 --save-dev npx playwright install chromium ``` Copying `~/.cache/ms-playwright` revision directories is an emergency cache workaround only; prefer reinstalling the matching browser revision. --- ## 3. Three.js Imports Standard Three.js classes are re-exported from `@iwsdk/core`. For app code, import standard Three classes from `@iwsdk/core` so they match IWSDK's Three/super-three build. Keep the template's `three` dependency/override; import `three/examples/jsm/...` only for addons that `@iwsdk/core` does not re-export. ```typescript // ✅ CORRECT import { Mesh, Group, BoxGeometry, SphereGeometry, CylinderGeometry, PlaneGeometry, ConeGeometry, TorusGeometry, MeshStandardMaterial, MeshBasicMaterial, LineBasicMaterial, Color, Vector3, Quaternion, Euler, Matrix4, Fog, AmbientLight, PointLight, DirectionalLight, BufferGeometry, Float32BufferAttribute, EdgesGeometry, LineSegments, AdditiveBlending, // ... every standard Three.js export is available } from "@iwsdk/core"; // Avoid for standard Three classes in app code // import { Mesh } from "three"; ``` --- ## 4. Key API Surface (0.4.x) ### World Creation ```typescript // XR world (default) const world = await World.create(container); // XR world with options const world = await World.create(container, { xr: { offer: 'once' }, // or 'always' / 'none'; omit xr for the default render: { near: 0.01, far: 200 }, features: { grabbing: true, locomotion: true, physics: true, spatialUI: false, }, }); // Browser-first world (no XR) const world = await World.create(container, { xr: false, render: { near: 0.001, far: 200, camera: { position: [0, 1.6, 0], lookAt: [0, 1.55, -1] }, }, input: { canvasPointerEvents: true }, features: { grabbing: true, locomotion: { browserControls: true }, // WASD/arrows + Space + gamepad; app owns mouselook physics: true, }, }); ``` ### Dual-Runtime Pattern (XR + Browser Fallback) For games that should work both in VR and in the browser: ```typescript const world = await World.create(container, { xr: { offer: 'once' }, input: { canvasPointerEvents: true }, features: { grabbing: true, locomotion: { browserControls: true }, physics: true, }, }); ``` ### Input System ```typescript // InputManager facade (0.4.x) world.input.xr // XRInputManager (controllers, hands) world.input.keyboard // StatefulKeyboard world.input.actions // InputActionManager world.input.browserGamepads // Browser gamepad array // Action-backed input (preferred for reusable intent-based systems) world.input.actions.getAxis2D('locomotion.move'); // { x, y } world.input.actions.getButtonDown('locomotion.jump'); // Built-in action names: // locomotion.move, locomotion.turn, locomotion.jump, // locomotion.teleportAim, locomotion.teleportCommit, // interaction.select // // Some names are reserved for app/user bindings and are not default-bound. // Keyboard (browser-first) world.input.keyboard.getKeyPressed('KeyW'); // held this frame world.input.keyboard.getKeyDown('Space'); // pressed this frame world.input.keyboard.getKeyUp('KeyE'); // released this frame ``` ### ECS-Native Player Rig ```typescript world.playerEntity // Entity wrapping XROrigin Group world.playerHeadEntity // Entity for head space; not a default UI parent world.playerSpaceEntities // { head, raySpaces, gripSpaces, indexTipSpaces } ``` `ScreenSpace` is a browser-viewport HUD and returns to world space in XR. For immersive UI, default to an authored world transform or attach contextual UI to the object it controls. Use a thresholded `Follower` targeting `world.player.head` only when compact global UI must remain discoverable. Reserve direct `world.playerHeadEntity` parenting for tiny, transient, non-interactive markers that require exact view alignment; do not head-lock menus or persistent panels. See https://iwsdk.dev/concepts/spatial-ui/hud.html. ### Asset Management IWSDK loads 3D models as GLTF or GLB. For FBX, OBJ, or another source format, use Blender's **File → Import**, then **File → Export → glTF 2.0**, and register the converted output in the asset manifest. ```typescript // getGLTF returns a fresh scene graph clone by default // (geometries, materials, and animations remain shared) const { scene } = AssetManager.getGLTF('myModel')!; world.scene.add(scene); // Opt into shared instance (old behavior) const { scene } = AssetManager.getGLTF('myModel', { shared: true })!; ``` --- ## 5. Dev Server ```bash npm run dev # Generated apps: dev restart --open --foreground npx @iwsdk/cli dev up # Start dev:runtime through the CLI, usually backgrounded npx @iwsdk/cli dev up --foreground # Stay attached to terminal npx @iwsdk/cli dev down # Stop npx @iwsdk/cli dev restart # Restart npx @iwsdk/cli dev status # Check running state npx @iwsdk/cli dev logs # View recorded background server logs npx @iwsdk/cli dev open # Open in browser ``` Generated apps use bare `iwsdkDev()` and the CLI launches the managed Playwright runtime/editor workspace, registers the MCP WebSocket endpoint, and records runtime state. AI, headed/headless, open, and screenshot behavior are launch-time `iwsdk dev up` flags. The developer owns the headed/headless choice; announce any change before restarting rather than silently changing their workspace. Use `npx @iwsdk/cli dev status` for the resolved `runtimeUrls.local` and `runtimeUrls.network` fields in the JSON result; the generated starter template defaults to `https://localhost:8081/`, but examples or existing apps may use another Vite port. ### Physical Headset Smoke Test Run `npx @iwsdk/cli dev status`, then open one of the URLs in `data.runtimeUrls.network` on a headset connected to the same Wi-Fi network as the development computer. Accept the expected warning for IWSDK's untrusted local certificate. For alternate connection methods and complete instructions, see [Testing Your Experience](/guides/02-testing-experience). ### Node.js Requirement IWSDK 0.4.x requires Node.js satisfying: `>=20.19.0 <21.0.0-0 || >=22.12.0 <23.0.0-0 || >=24.0.0`. If your environment ships an unsupported default (for example Node 18), install a supported Node version with your environment's version manager or platform package and prepend it to `PATH`. ```bash node --version ``` --- ## 6. Adapter Management Project creation syncs MCP adapter configs after dependency installation for the selected AI tools. Sync or manage them explicitly with: ```bash
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub