A-Frame is a comprehensive web framework for building virtual reality, augmented reality, and 3D experiences that run directly in web browsers. Built on top of HTML, Entity-Component-System architecture, and Three.js, it provides a declarative markup language that makes WebXR development accessible to web developers without requiring extensive 3D graphics programming knowledge.
npm install aframe// ES Module
import AFRAME from 'aframe';
// CommonJS
const AFRAME = require('aframe');
// Script tag (browser)
// <script src="https://aframe.io/releases/1.7.1/aframe.min.js"></script>
// Global AFRAME object is available<!-- HTML markup approach -->
<!DOCTYPE html>
<html>
<head>
<script src="https://aframe.io/releases/1.7.1/aframe.min.js"></script>
</head>
<body>
<a-scene>
<a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"></a-box>
<a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere>
<a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
<a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
<a-sky color="#ECECEC"></a-sky>
</a-scene>
</body>
</html>// JavaScript API approach
// Create entities programmatically
const sceneEl = document.querySelector('a-scene');
const entityEl = document.createElement('a-entity');
entityEl.setAttribute('geometry', {
primitive: 'box',
width: 1,
height: 1,
depth: 1
});
entityEl.setAttribute('material', 'color', 'red');
entityEl.setAttribute('position', '0 2 -5');
sceneEl.appendChild(entityEl);A-Frame is built around several key architectural patterns:
Foundation classes and functions for creating and managing 3D entities, components, and scenes using the Entity-Component-System architecture.
// Core classes
class AEntity {
// Attribute and component management
setAttribute(componentName: string, value: any): void;
setAttribute(componentName: string, property: string, value: any): void;
getAttribute(componentName: string): any;
getDOMAttribute(attr: string): string | null;
removeAttribute(attr: string, propertyName?: string): void;
// State management
addState(stateName: string): void;
removeState(stateName: string): void;
is(stateName: string): boolean;
// Component lifecycle
initComponent(attrName: string, data?: any, isDependency?: boolean): void;
removeComponent(name: string, destroy?: boolean): void;
updateComponent(attr: string, attrValue: any, clobber?: boolean): void;
updateComponents(): void;
// 3D Object management
getObject3D(type: string): THREE.Object3D | undefined;
setObject3D(type: string, obj: THREE.Object3D): void;
removeObject3D(type: string): void;
getOrCreateObject3D(type: string, Constructor?: any): THREE.Object3D;
// DOM hierarchy methods
add(el: AEntity): void;
remove(el?: AEntity): void;
getChildEntities(): AEntity[];
// Scene graph management
addToParent(): void;
removeFromParent(): void;
// Lifecycle methods
load(): void;
play(): void;
pause(): void;
destroy(): void;
// Utility methods
flushToDOM(recursive?: boolean): void;
inspect(): string;
// Properties
hasLoaded: boolean;
isPlaying: boolean;
object3D: THREE.Object3D;
components: { [key: string]: any };
sceneEl: AScene;
parentEl: AEntity;
}
class AScene extends AEntity {
// Scene-specific functionality
enterVR(): Promise<void>;
exitVR(): Promise<void>;
tick(time: number, timeDelta: number): void;
behaviors: any[];
camera: THREE.Camera;
canvas: HTMLCanvasElement;
effect: any;
renderer: THREE.WebGLRenderer;
renderStarted: boolean;
systems: { [key: string]: any };
time: number;
isMobile: boolean;
isVR: boolean;
}
class ANode {
// Base node functionality
attachedCallback(): void;
detachedCallback(): void;
attributeChangedCallback(attr: string, oldVal: any, newVal: any): void;
closestScene(): AScene;
hasLoaded: boolean;
isScene: boolean;
}
// Global AFRAME object properties
const AFRAME = {
AComponent: typeof Component;
AEntity: typeof AEntity;
ANode: typeof ANode;
ANIME: typeof ANIME;
AScene: typeof AScene;
components: { [key: string]: any };
coreComponents: string[];
geometries: { [key: string]: any };
primitives: {
getMeshMixin: (tagName: string) => any;
primitives: { [key: string]: any };
};
registerComponent: (name: string, definition: object) => void;
registerGeometry: (name: string, definition: object) => void;
registerPrimitive: (name: string, definition: object) => void;
registerShader: (name: string, definition: object) => void;
registerSystem: (name: string, definition: object) => void;
scenes: AScene[];
schema: any;
shaders: { [key: string]: any };
systems: { [key: string]: any };
emitReady: () => void;
THREE: typeof THREE;
utils: any;
version: string;
};Built-in components for 3D objects, VR/AR interactions, animations, and scene management. Includes 42+ components covering positioning, materials, lighting, controllers, and more.
// Component registration
AFRAME.registerComponent('custom-component', {
schema: {
property: { type: 'string', default: 'value' }
},
init: function() { /* initialization */ },
update: function(oldData) { /* data changes */ },
remove: function() { /* cleanup */ }
});
// Core positioning components (always available)
// position: { x: number, y: number, z: number }
// rotation: { x: number, y: number, z: number }
// scale: { x: number, y: number, z: number }
// visible: boolean25+ primitive HTML elements providing a high-level declarative interface to A-Frame functionality, from basic shapes to complex VR interactions.
<!-- Basic shape primitives -->
<a-box position="0 0 0" color="red"></a-box>
<a-sphere radius="1" color="blue"></a-sphere>
<a-plane width="4" height="4" color="green"></a-plane>
<!-- VR/AR specific primitives -->
<a-sky src="#skyTexture"></a-sky>
<a-light type="point" position="0 5 0"></a-light>
<a-sound src="#soundFile" autoplay="true"></a-sound>14 built-in geometry types and 6 shader types for creating and styling 3D objects, from basic shapes to complex forms with physically-based rendering.
// Geometry registration
AFRAME.registerGeometry('custom-geometry', {
schema: {
width: { default: 1 },
height: { default: 1 }
},
init: function(data) {
// Create Three.js geometry
this.geometry = new THREE.BoxGeometry(data.width, data.height, 1);
}
});
// Built-in geometries: box, sphere, plane, cylinder, cone, etc.
// Built-in shaders: standard, flat, phong, sdf, msdf, portal10 core systems managing rendering, lighting, cameras, and WebXR, plus comprehensive utility library with mathematical operations, device detection, and debugging tools.
// System registration
AFRAME.registerSystem('custom-system', {
schema: {
enabled: { default: true }
},
init: function() { /* system initialization */ },
tick: function(time, timeDelta) { /* per-frame updates */ }
});
// Utility functions
AFRAME.utils.coordinates.parse('1 2 3'); // Parse coordinate strings
AFRAME.utils.device.isMobile(); // Device detection
AFRAME.utils.debug('namespace'); // Debug logging20+ VR/AR controller components supporting major headsets and platforms including Oculus, HTC Vive, Windows Mixed Reality, and hand tracking.
<!-- VR controller setup -->
<a-entity oculus-touch-controls="hand: left"></a-entity>
<a-entity oculus-touch-controls="hand: right"></a-entity>
<a-entity vive-controls="hand: left"></a-entity>
<a-entity hand-controls="handModelStyle: lowPoly; color: #ffcccc"></a-entity>// Core component lifecycle interface
interface ComponentDefinition {
schema?: object;
multiple?: boolean;
init?(): void;
update?(oldData: any): void;
remove?(): void;
play?(): void;
pause?(): void;
tick?(time: number, timeDelta: number): void;
tock?(time: number, timeDelta: number): void;
}
// Schema property types
interface SchemaPropertyTypes {
boolean: boolean;
int: number;
number: number;
string: string;
vec2: { x: number; y: number };
vec3: { x: number; y: number; z: number };
vec4: { x: number; y: number; z: number; w: number };
color: string;
asset: string;
audio: string;
map: string;
model: string;
selector: string;
selectorAll: string;
src: string;
time: number;
array: any[];
}
// Entity event system
interface EntityEventDetail {
[key: string]: any;
}
// System definition interface
interface SystemDefinition {
schema?: object;
init?(): void;
pause?(): void;
play?(): void;
tick?(time: number, timeDelta: number): void;
tock?(time: number, timeDelta: number): void;
}
// Geometry definition interface
interface GeometryDefinition {
schema?: object;
init?(data: any): void;
}
// Shader definition interface
interface ShaderDefinition {
schema?: object;
vertexShader?: string;
fragmentShader?: string;
init?(data: any): void;
update?(data: any): void;
}
// Primitive definition interface
interface PrimitiveDefinition {
defaultComponents?: { [componentName: string]: any };
mappings?: { [attribute: string]: string };
}
// Three.js integration types
interface Object3D extends THREE.Object3D {
el?: AEntity; // Reference back to A-Frame entity
}
// Component data interfaces
interface PositionData {
x: number;
y: number;
z: number;
}
interface RotationData {
x: number; // degrees
y: number; // degrees
z: number; // degrees
}
interface ScaleData {
x: number;
y: number;
z: number;
}
// Animation configuration
interface AnimationData {
property: string;
from?: string | number | object;
to: string | number | object;
dur: number;
delay?: number;
easing?: string;
elasticity?: number;
loop?: boolean | number;
dir?: 'normal' | 'reverse' | 'alternate';
autoplay?: boolean;
startEvents?: string;
pauseEvents?: string;
resumeEvents?: string;
}
// Material data interface
interface MaterialData {
shader: string;
color?: string;
opacity?: number;
transparent?: boolean;
alphaTest?: number;
side?: 'front' | 'back' | 'double';
[property: string]: any; // Allow shader-specific properties
}
// Light data interface
interface LightData {
type: 'ambient' | 'directional' | 'hemisphere' | 'point' | 'spot';
color: string;
intensity: number;
castShadow?: boolean;
[property: string]: any; // Allow light-type specific properties
}
// Asset management types
interface AssetItem {
id: string;
src: string;
timeout?: number;
response?: any;
}
// WebXR types
interface XRFrame {
session: XRSession;
getViewerPose(referenceSpace: XRReferenceSpace): XRViewerPose | null;
}
interface XRSession {
referenceSpace: XRReferenceSpace;
renderState: XRRenderState;
inputSources: XRInputSourceArray;
}
// Event types
interface ComponentChangedEvent extends CustomEvent {
detail: {
name: string;
component: any;
oldData: any;
newData: any;
};
}
interface LoadedEvent extends CustomEvent {
detail: {
entity: AEntity;
};
}
// Utility type for component schemas
type SchemaProperty = {
type?: string;
default?: any;
parse?: (value: any) => any;
stringify?: (value: any) => string;
oneOf?: any[];
min?: number;
max?: number;
if?: any;
};
// Mixin system
interface MixinData {
[componentName: string]: any;
}