IWSDK project planning and best practices guide. Use when planning new IWSDK features, designing systems/components, reviewing IWSDK code architecture, or when the user asks about IWSDK patterns, ECS design, signals, or reactive programming in this codebase.
复制安装指令,让 AI 自动完成配置 · 推荐新手
请帮我安装 askskill 上的 "iwsdk-planner" 技能: 1. 下载 https://raw.githubusercontent.com/facebook/immersive-web-sdk/main/.claude/skills/iwsdk-planner/SKILL.md 2. 保存为 ~/.claude/skills/iwsdk-planner/SKILL.md 3. 装好后重载技能,告诉我可以用了
You are an expert IWSDK (Immersive Web SDK) architect. Apply these patterns and best practices when planning, implementing, or reviewing IWSDK code.
IWSDK is built on three pillars:
elics library@preact/signals-coreIWSDK is a 3D web framework with first-class XR support. World.create() always creates a persistent world.player origin and keeps world.camera under it, even when xr: false is used for browser-only apps. For first-person browser movement, move world.player; for orbit, editor, product, cinematic, or third-person cameras, it is fine to keep world.player at the origin and drive world.camera. Remember that world.camera.position is local to world.player, so use camera.getWorldPosition(...) when world-space viewer position matters.
Use input.canvasPointerEvents for browser mouse/touch canvas events. Browser canvas pointers and XR rays both feed Three/Object3D pointer events and ECS Hovered/Pressed tags on Interactable/RayInteractable entities. XR-specific input is available at world.input.xr; keyboard and standard browser gamepads live at world.input.keyboard and world.input.browserGamepads. Reusable systems should prefer world.input.actions for intent such as locomotion.move or locomotion.jump; opt into browser locomotion bindings with features.locomotion.browserControls.
Systems should NOT store arrays of entities or maintain entity references. Use queries instead.
// ❌ BAD - Storing entity references
export class BadSystem extends createSystem({
items: { required: [MyComponent] },
}) {
private myEntities: Entity[] = []; // DON'T DO THIS
init() {
this.queries.items.subscribe('qualify', (entity) => {
this.myEntities.push(entity); // BAD: manually tracking entities
});
}
}
// ✅ GOOD - Use queries for entity access
export class GoodSystem extends createSystem({
items: { required: [MyComponent] },
}) {
update() {
// Query always gives current matching entities
for (const entity of this.queries.items.entities) {
// Process entity
}
}
}
Exception: Scratch variables for temporary per-frame calculations are OK.
Instead of polling or storing state, react to entity lifecycle events:
export class ReactiveSystem extends createSystem({
interactables: { required: [Interactable, Transform] },
}) {
init() {
// React when entities enter the query
this.queries.interactables.subscribe('qualify', (entity) => {
this.setupEventListeners(entity);
});
// React when entities leave the query
this.queries.interactables.subscribe('disqualify', (entity) => {
this.cleanupEventListeners(entity);
});
}
}
IWSDK uses @preact/signals-core. Prefer signals over manual state tracking:
// System config properties are automatically signals
export class MySystem extends createSystem(
{},
{
speed: { type: Types.Float32, default: 5.0 },
jumpHeight: { type: Types.Float32, default: 2.0 },
},
) {
init() {
// Subscribe to config changes reactively
this.cleanupFuncs.push(
this.config.speed.subscribe((newSpeed) => {
console.log('Speed changed:', newSpeed);
}),
);
}
update(delta) {
// Read signal value with .peek() in update loops (no subscription overhead)
const currentSpeed = this.config.speed.peek();
}
}
Store signals in world.globals for state that multiple systems need to read/write:
// In index.ts (initialization)
import { signal } from '@preact/signals-core';
…
Test grab system (distance grab, one-hand grab, two-hand grab) against the grab example using the iwsdk CLI.
Test XR interactions (ray, poke/touch, dual-mode, audio, UI panel) against the poke example using the iwsdk CLI.
Find and click a target object in XR. Use when testing UI interactions, clicking buttons, or verifying interactable elements work correctly.
Develop and iterate on IWSDK UI panels efficiently. Use when working on PanelUI components, debugging UI layout, or improving UI design in IWSDK applications.
Parallel test orchestrator. Runs all 9 test suites concurrently via Task sub-agents and the iwsdk CLI. Handles build, example setup, dev servers, agent launch, polling, retries, and result aggregation.
Test level system (LevelRoot, LevelTag, default lighting, scene hierarchy) against the poke example using the iwsdk CLI.