Develop

Chapter 1a: Project Manifest

Updated: Sep 4, 2026
iwsdk.config.json is the main project configuration file. IWSDK Create generates it for a new project. The Vite plugin, native scene editor, and runtime then consume its project settings. Keep data in this JSON file. Keep systems and other behavior in JavaScript or TypeScript.

Create the manifest

A minimal project manifest has this shape:
{
  "$schema": "./node_modules/@iwsdk/core/dist/schemas/iwsdk-project.v1.schema.json",
  "version": "iwsdk.project.v1",
  "scene": "./public/scenes/main.iwsdk.scene.json",
  "assets": { "module": "./src/assets" },
  "components": { "module": "./src/components" },
  "world": {
    "xr": {
      "mode": "vr",
      "offer": "always",
      "features": {
        "handTracking": true
      }
    },
    "features": {
      "locomotion": true,
      "grabbing": true,
      "spatialUI": true
    }
  },
  "dev": {
    "emulator": {
      "device": "metaQuest3"
    }
  }
}
The scene path is relative to the project root. It must point to a file under public/. Module paths are also relative to the project root. Omit their file extensions so the same manifest works with TypeScript and JavaScript.
The assets and components declarations are optional.

Load the project options

The Vite plugin converts the manifest to WorldOptions. It also imports the selected asset and component modules.
import { World } from '@iwsdk/core';
import projectOptions from 'virtual:iwsdk-project';

const container = document.querySelector<HTMLDivElement>('#scene-container');
if (container == null) {
  throw new Error('Missing #scene-container');
}

const world = await World.create(container, projectOptions);
Keep systems, callbacks, and procedural values in code. You can still pass explicit WorldOptions in advanced or non-Vite apps.

Define assets

Use defineAssets() in the selected asset module:
import { AssetType, defineAssets } from '@iwsdk/core';

const publicAssetUrl = (path: string): string =>
  `${import.meta.env.BASE_URL}${path.replace(/^\/+/u, '')}`;

export default defineAssets({
  environment: {
    name: 'Environment',
    type: AssetType.GLTF,
    url: publicAssetUrl('models/environment.glb'),
    priority: 'lazy',
  },
  'settings-panel': {
    name: 'Settings panel',
    type: AssetType.UIKitML,
    url: publicAssetUrl('ui/settings.uikitml'),
  },
});
The asset module is the shared catalog for the runtime and editor. Loading depends on each entry’s priority:
  • critical or an omitted priority blocks World.create().
  • background starts after critical assets without blocking the world.
  • lazy waits for explicit use or scene instantiation.

Define components

Export project components through defineComponents():
import { defineComponents } from '@iwsdk/core';
import { Robot } from './robot-component.js';

export default defineComponents([Robot]);
The runtime and native scene editor use the same component schemas.

Configure the world

The world object stores settings that JSON can represent:
  • xr selects browser-only mode or an AR/VR session. It also stores offer, reference-space, and WebXR feature settings.
  • render controls field of view, clipping planes, stencil use, and the browser camera.
  • input controls canvas pointer events.
  • features enables locomotion, grabbing, physics, scene understanding, environment raycasts, camera access, and spatial UI.
world.render.camera sets the browser preview pose below world.player. A scene’s player.transform places the player origin in the authored environment.

Configure development emulation

Store project-owned emulator settings under dev.emulator. These include the device, environment, IWER settings, activation rules, and build injection.
Launch behavior belongs to the command session:
npx iwsdk dev up --ai-mode collaborate --headed --open
npx iwsdk dev up --ai-mode agent --screenshot-width 500 --screenshot-height 500
Keep vite.config.ts small:
import { iwsdkDev } from '@iwsdk/vite-plugin-dev';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [iwsdkDev()],
});
Do not pass assetManifest, componentManifest, emulator, ai, or workspace beside a project manifest. The plugin rejects these competing settings.