ECS Architecture in WebXR
Updated: Sep 4, 2026
IWSDK uses an entity-component-system (ECS) runtime to keep data separate from behavior. This structure lets a system process only the entities that match its query.
A component defines fields. The ECS stores each field across all entities instead of storing a separate behavior object for every scene object.
Health.current: [100, 25, 80, ...]
Health.max: [100, 100, 150, ...]
entity 0 1 2
Keep component schemas focused. Put behavior in systems and use queries to select the data each system needs.
The following example defines every application-owned component it uses. Transform and Visibility are IWSDK components.
import {
Transform,
Types,
Visibility,
createComponent,
createSystem,
eq,
} from '@iwsdk/core';
const NeedsUpdate = createComponent('NeedsUpdate', {
dirty: { type: Types.Boolean, default: true },
});
class VisibilityWorkSystem extends createSystem({
targets: {
required: [Transform, Visibility, NeedsUpdate],
where: [
eq(Visibility, 'isVisible', true),
eq(NeedsUpdate, 'dirty', true),
],
},
}) {
update() {
for (const entity of this.queries.targets.entities) {
// Perform the application-owned work once.
entity.setValue(NeedsUpdate, 'dirty', false);
}
}
}
Query membership updates when components are added or removed. A scalar field changed through setValue() also causes dependent value predicates to be reevaluated.
Add components to combine independent behaviors. Use the public components exported by IWSDK, and define application-specific data in the app.
import {
OneHandGrabbable,
PhysicsBody,
RayInteractable,
} from '@iwsdk/core';
entity.addComponent(RayInteractable);
entity.addComponent(OneHandGrabbable);
entity.addComponent(PhysicsBody);
The input, grab, and physics systems respond to the components they own. Application systems can add their own state without subclassing the entity.
world.createTransformEntity() associates an ECS entity with a Three.js Object3D and a Transform component. IWSDK replaces the object’s position, quaternion, rotation, and scale values with synchronized views over the component storage.
entity.object3D!.position.x += 0.1;
const position = entity.getVectorView(Transform, 'position');
console.log(position[0]);
Both lines address the same transform data. TransformSystem also keeps ECS parent references and the Three.js hierarchy aligned.
Systems run in ascending numeric priority. More-negative priorities run first. IWSDK assigns these priorities when the related features are enabled:
-5.0 LocomotionSystem
-4.0 InputSystem
-3.5 CanvasPointerSystem
-3.0 GrabSystem
0.0 Default application systems
After systems update, IWSDK invokes live XR-frame callbacks and renders the scene. Choose an application-system priority from the behavior it depends on; do not rely on an undocumented priority.
Profile representative content on the target headset. Query size is one useful signal:
console.debug('Visible targets', this.queries.targets.entities.size);
Use browser performance and memory tools for frame timing, allocations, and GPU work.