10 core systems managing rendering, lighting, cameras, and WebXR, plus comprehensive utility library with mathematical operations, device detection, and debugging tools.
Register systems that manage global behavior and collections of entities.
/**
* Register a new system
* @param name - System name
* @param definition - System definition object
*/
function registerSystem(name: string, definition: SystemDefinition): void;
interface SystemDefinition {
/** Schema for system configuration */
schema?: SchemaDefinition;
/** Called when system is initialized */
init?(): void;
/** Called every frame */
tick?(time: number, timeDelta: number): void;
/** Called when system is removed */
remove?(): void;
/** Called when system starts playing */
play?(): void;
/** Called when system pauses */
pause?(): void;
}Usage Example:
// Register custom system
AFRAME.registerSystem('particle-system', {
schema: {
maxParticles: { default: 1000 },
emissionRate: { default: 50 }
},
init: function() {
this.particles = [];
this.emitters = [];
},
tick: function(time, timeDelta) {
// Update all particles
this.updateParticles(timeDelta);
this.emitParticles(timeDelta);
}
});Manages camera entities and viewpoint switching.
interface CameraSystem {
/** Currently active camera entity */
activeCameraEl: AEntity;
/** Set active camera */
setActiveCamera(cameraEl: AEntity): void;
}
// Access camera system
const cameraSystem = document.querySelector('a-scene').systems.camera;Manages lighting setup and shadow rendering.
interface LightSystem {
/** Maximum number of lights */
maxLights: number;
/** Update light configuration */
updateLights(): void;
}Manages material instances and shader compilation.
interface MaterialSystem {
/** Register material instance */
registerMaterial(material: any): void;
/** Unregister material instance */
unregisterMaterial(material: any): void;
}Manages geometry instances and caching.
interface GeometrySystem {
/** Register geometry instance */
registerGeometry(geometry: any): void;
/** Unregister geometry instance */
unregisterGeometry(geometry: any): void;
}Core rendering system managing the Three.js renderer.
interface RendererSystem {
/** Three.js renderer instance */
renderer: THREE.WebGLRenderer;
/** Render the scene */
render(): void;
/** Resize renderer */
resize(): void;
}Manages VR/AR session handling and WebXR API integration.
interface WebXRSystem {
/** Check if VR is available */
checkHeadsetConnected(): boolean;
/** Get VR display */
getVRDisplay(): VRDisplay | null;
/** Enter VR mode */
enterVR(): Promise<void>;
/** Exit VR mode */
exitVR(): Promise<void>;
}Parse and manipulate coordinate strings and vectors.
interface CoordinateUtils {
/**
* Parse coordinate string to object
* @param value - Coordinate string like "1 2 3"
* @returns Coordinate object with x, y, z properties
*/
parse(value: string): { x: number; y: number; z: number };
/**
* Convert coordinate object to string
* @param data - Coordinate object
* @returns Coordinate string
*/
stringify(data: { x: number; y: number; z: number }): string;
/**
* Check if value is a coordinate
* @param value - Value to check
* @returns True if value is coordinate-like
*/
isCoordinates(value: any): boolean;
}
// Usage
const coords = AFRAME.utils.coordinates.parse('1 2 3'); // { x: 1, y: 2, z: 3 }
const str = AFRAME.utils.coordinates.stringify({ x: 1, y: 2, z: 3 }); // "1 2 3"Detect device capabilities and platform information.
interface DeviceUtils {
/** Check if running on mobile device */
isMobile(): boolean;
/** Check if running on iOS */
isIOS(): boolean;
/** Check if running in Oculus browser */
isOculusBrowser(): boolean;
/** Check if running in browser environment */
isBrowserEnvironment: boolean;
/** Check if device supports VR */
checkHeadsetConnected(): boolean;
/** Get device pixel ratio */
getPixelRatio(): number;
}
// Usage
if (AFRAME.utils.device.isMobile()) {
// Mobile-specific behavior
}Debug logging and development tools.
/**
* Create namespaced debug function
* @param namespace - Debug namespace
* @returns Debug logging function
*/
function debug(namespace: string): (message: string, ...args: any[]) => void;
// Usage
const debug = AFRAME.utils.debug('my-component');
debug('Component initialized');
debug('Data updated:', newData);Object manipulation and comparison utilities.
interface ObjectUtils {
/**
* Deep equality comparison
* @param a - First object
* @param b - Second object
* @returns True if objects are deeply equal
*/
deepEqual(a: any, b: any): boolean;
/**
* Calculate difference between objects
* @param a - Original object
* @param b - New object
* @returns Object containing differences
*/
diff(a: any, b: any): any;
/**
* Extend target object with source properties
* @param target - Target object
* @param source - Source object
* @returns Extended target object
*/
extend(target: any, source: any): any;
/**
* Deep extend target object with source properties
* @param target - Target object
* @param source - Source object
* @returns Deep extended target object
*/
extendDeep(target: any, source: any): any;
}
// Usage
const isEqual = AFRAME.utils.deepEqual(obj1, obj2);
const changes = AFRAME.utils.diff(oldData, newData);
const merged = AFRAME.utils.extend(target, source);Function context binding utilities.
/**
* Bind function to specific context
* @param fn - Function to bind
* @param ctx - Context object
* @param args - Additional arguments
* @returns Bound function
*/
function bind(fn: Function, ctx: any, ...args: any[]): Function;
// Usage
const boundFunction = AFRAME.utils.bind(this.handleClick, this);Entity manipulation and query utilities.
interface EntityUtils {
/**
* Get entity by selector
* @param selector - CSS selector
* @param context - Search context element
* @returns Entity element or null
*/
getEntity(selector: string, context?: Element): AEntity | null;
/**
* Get all entities matching selector
* @param selector - CSS selector
* @param context - Search context element
* @returns Array of entity elements
*/
getEntities(selector: string, context?: Element): AEntity[];
/**
* Set entity data
* @param entity - Entity element
* @param componentName - Component name
* @param data - Component data
*/
setEntityData(entity: AEntity, componentName: string, data: any): void;
}Material creation and manipulation utilities.
interface MaterialUtils {
/**
* Create material from data
* @param data - Material data
* @returns Three.js material
*/
createMaterial(data: any): THREE.Material;
/**
* Parse material string
* @param str - Material string
* @returns Parsed material data
*/
parseMaterial(str: string): any;
}Parse CSS-like style strings into objects.
interface StyleParser {
/**
* Parse style string to object
* @param str - Style string like "color: red; opacity: 0.5"
* @returns Parsed style object
*/
parse(str: string): { [property: string]: any };
/**
* Convert style object to string
* @param obj - Style object
* @returns Style string
*/
stringify(obj: { [property: string]: any }): string;
}
// Usage
const styles = AFRAME.utils.styleParser.parse('color: red; opacity: 0.5');
// { color: 'red', opacity: 0.5 }Utilities for VR/AR controller handling.
interface TrackedControlsUtils {
/**
* Find matching controller
* @param component - Controller component
* @param idPrefix - Controller ID prefix
* @returns Matching gamepad or null
*/
findMatchingControllerWebVR(component: any, idPrefix: string): Gamepad | null;
/**
* Get controller for hand
* @param hand - Hand identifier ('left' or 'right')
* @returns Controller object or null
*/
getControllerForHand(hand: 'left' | 'right'): any;
}Object pooling for performance optimization.
interface PoolUtils {
/**
* Use object pool
* @param Pool - Pool constructor
* @param name - Pool name
* @param definition - Pool definition
*/
use(Pool: any, name: string, definition: any): void;
}
// Usage
AFRAME.utils.pool.use(THREE.Vector3, 'vector3', function() {
return new THREE.Vector3();
});Safari mobile-specific utility for canvas resizing.
/**
* Force canvas resize on Safari mobile
*/
function forceCanvasResizeSafariMobile(): void;Schema validation and property type system.
interface SchemaUtils {
/**
* Process schema validation
* @param schema - Schema definition
* @param data - Data to validate
* @param debug - Enable debug mode
* @returns Processed data
*/
process(schema: SchemaDefinition, data: any, debug?: boolean): any;
/**
* Parse individual property
* @param value - Property value
* @param type - Property type
* @returns Parsed value
*/
parseProperty(value: any, type: string): any;
/**
* Stringify individual property
* @param value - Property value
* @param type - Property type
* @returns Stringified value
*/
stringifyProperty(value: any, type: string): string;
/**
* Parse property string
* @param str - Property string
* @param schema - Schema definition
* @returns Parsed properties object
*/
parseProperties(str: string, schema: SchemaDefinition): any;
/**
* Stringify properties object
* @param data - Properties object
* @param schema - Schema definition
* @returns Properties string
*/
stringifyProperties(data: any, schema: SchemaDefinition): string;
}Built-in property types for schema validation.
interface PropertyTypes {
boolean: boolean;
int: number;
number: number;
string: string;
time: number; // Milliseconds
vec2: { x: number; y: number };
vec3: { x: number; y: number; z: number };
vec4: { x: number; y: number; z: number; w: number };
color: string; // Hex, RGB, HSL, or color name
asset: string; // Asset URL or selector
audio: string; // Audio asset reference
map: string; // Texture map reference
model: string; // 3D model reference
selector: string; // CSS selector for single element
selectorAll: string; // CSS selector for multiple elements
src: string; // Source URL
array: any[]; // Array of values
}// Register a particle system
AFRAME.registerSystem('particles', {
schema: {
maxParticles: { default: 1000 },
gravity: { default: -9.8 }
},
init: function() {
this.particles = [];
this.pool = [];
},
tick: function(time, timeDelta) {
this.updateParticles(timeDelta / 1000);
this.cullParticles();
},
createParticle: function(position, velocity) {
let particle = this.pool.pop();
if (!particle) {
particle = { position: new THREE.Vector3(), velocity: new THREE.Vector3() };
}
particle.position.copy(position);
particle.velocity.copy(velocity);
particle.life = 1.0;
this.particles.push(particle);
return particle;
}
});// Device detection
if (AFRAME.utils.device.isMobile()) {
entityEl.setAttribute('material', 'shader', 'flat'); // Use flat shader on mobile
}
// Coordinate parsing
const position = AFRAME.utils.coordinates.parse('1 2 3');
entityEl.object3D.position.set(position.x, position.y, position.z);
// Debug logging
const debug = AFRAME.utils.debug('my-app');
debug('Entity created:', entityEl.id);
// Object comparison
const hasChanged = !AFRAME.utils.deepEqual(oldData, newData);
if (hasChanged) {
component.update(oldData);
}
// Style parsing
const materialData = AFRAME.utils.styleParser.parse('color: red; metalness: 0.8');
entityEl.setAttribute('material', materialData);// Component with schema validation
AFRAME.registerComponent('custom-physics', {
schema: {
mass: { type: 'number', default: 1 },
velocity: { type: 'vec3', default: { x: 0, y: 0, z: 0 } },
friction: { type: 'number', default: 0.1, min: 0, max: 1 },
material: { type: 'string', default: 'wood', oneOf: ['wood', 'metal', 'rubber'] }
},
init: function() {
// this.data contains validated and parsed properties
console.log('Mass:', this.data.mass);
console.log('Velocity:', this.data.velocity);
},
update: function(oldData) {
// Handle data changes
if (this.data.mass !== oldData.mass) {
this.updateMass();
}
}
});A-Frame provides many additional utility functions for common development tasks.
/**
* Throttle function calls to improve performance
* @param fn - Function to throttle
* @param interval - Minimum interval between calls (ms)
* @param context - Optional context to bind function to
* @returns Throttled function
*/
function throttle(fn: Function, interval: number, context?: any): Function;
/**
* Throttle with trailing call to ensure final state convergence
* @param fn - Function to throttle
* @param interval - Minimum interval between calls (ms)
* @param context - Optional context to bind function to
* @returns Throttled function
*/
function throttleLeadingAndTrailing(fn: Function, interval: number, context?: any): Function;
/**
* Throttle using render loop timestamps for better performance
* @param fn - Function to throttle (receives time, timeDelta)
* @param interval - Minimum interval between calls (ms)
* @param context - Optional context to bind function to
* @returns Throttled function
*/
function throttleTick(fn: Function, interval: number, context?: any): Function;
/**
* Debounce function calls - only execute after calls stop
* @param fn - Function to debounce
* @param wait - Wait time after last call (ms)
* @param immediate - Call immediately on first invocation
* @returns Debounced function
*/
function debounce(fn: Function, wait: number, immediate?: boolean): Function;
// Usage examples
const throttledUpdate = AFRAME.utils.throttle(updatePosition, 16); // ~60fps
const debouncedResize = AFRAME.utils.debounce(handleResize, 250);/**
* Split string by delimiter with whitespace handling
* @param str - String to split
* @param delimiter - Delimiter character (default: ' ')
* @returns Array of split strings
*/
function splitString(str: string, delimiter?: string): string[];
/**
* Clone object using JSON serialization
* @param obj - Object to clone
* @returns Cloned object
*/
function clone(obj: any): any;
/**
* Extract data attributes from DOM elements
* @param el - DOM element
* @param defaults - Default values object
* @returns Extracted data object
*/
function getElData(el: Element, defaults?: any): any;
/**
* Get URL query parameter value
* @param name - Parameter name
* @returns Parameter value or empty string
*/
function getUrlParameter(name: string): string;
// Usage examples
const parts = AFRAME.utils.splitString('1.5 2.0 3.5', ' '); // ['1.5', '2.0', '3.5']
const copy = AFRAME.utils.clone({ x: 1, y: 2 });
const config = AFRAME.utils.getElData(element, { width: 100, height: 50 });
const debug = AFRAME.utils.getUrlParameter('debug');/**
* Check if running in iframe context
* @returns True if in iframe
*/
function isIframed(): boolean;
/**
* Find all scene elements in DOM tree
* @param el - Root element to search from
* @returns Array of scene elements
*/
function findAllScenes(el: Element): Element[];
/**
* Check if keyboard event should be captured for shortcuts
* @param event - Keyboard event
* @returns True if event should be captured
*/
function shouldCaptureKeyEvent(event: KeyboardEvent): boolean;
// Usage examples
if (AFRAME.utils.isIframed()) {
console.log('Running in iframe');
}
const scenes = AFRAME.utils.findAllScenes(document.body);/**
* Force canvas resize on Safari mobile to fix rendering issues
* @param canvas - Canvas element to resize
*/
function forceCanvasResizeSafariMobile(canvas: HTMLCanvasElement): void;
// Usage
AFRAME.utils.forceCanvasResizeSafariMobile(scene.canvas);interface SrcLoaderUtils {
/**
* Parse src attribute for asset references
* @param src - Source string (URL or asset reference)
* @returns Parsed source information
*/
parseSrc(src: string): any;
/**
* Validate asset source
* @param src - Source to validate
* @returns True if valid
*/
validateSrc(src: string): boolean;
}
// Usage
const srcInfo = AFRAME.utils.srcLoader.parseSrc('#myTexture');