A-Frame Web Framework for VR/AR
A-Frame is an open-source web framework designed for building virtual reality (VR), augmented reality (AR), and general 3D experiences directly within a web browser using declarative HTML. It abstracts away the complexities of WebXR and Three.js, making 3D content creation accessible to a broader audience, including web developers, educators, and artists. The current stable version is 1.7.1, released in April 2025. A-Frame typically releases minor versions every few months, incorporating updates to its underlying Three.js dependency and adding new WebXR features. Key differentiators include its entity-component-system (ECS) architecture, which promotes reusability and modularity, and its focus on performance for interactive WebXR experiences. It supports various platforms, from mobile to desktop and dedicated VR/AR headsets compatible with WebXR.
Common errors
-
Uncaught ReferenceError: AFRAME is not defined
cause A-Frame's main script file (aframe.min.js) has not been loaded or has loaded incorrectly before other scripts try to access the global AFRAME object.fixEnsure the A-Frame script tag (`<script src="https://unpkg.com/aframe/dist/aframe-master.min.js"></script>`) is placed correctly in your HTML, preferably in the `<head>` or at the beginning of `<body>`, before any custom scripts that use `AFRAME`. -
Failed to resolve module 'aframe' from ... (or similar bundler error)
cause This error typically occurs in projects using bundlers (like Webpack, Rollup, Parcel) that expect ES Modules, but A-Frame was previously CJS or the bundler configuration is not set up to handle the v1.7.0 ESM transition.fixIf on A-Frame v1.7.0+, update your bundler configuration to properly resolve ES Modules. Ensure your `package.json`'s `type` is set to `module` if it's a pure ESM project, or configure your bundler to handle 'aframe' as an ESM package. Consider using `import * as AFRAME from 'aframe';`. -
Custom element 'a-scene' has already been defined
cause The A-Frame library, which registers custom HTML elements like `<a-scene>`, has been loaded multiple times on the same page, or another script has inadvertently defined an element with the same tag.fixCheck your HTML to ensure the A-Frame script is only included once. If using a build system, verify that A-Frame is not being bundled and included multiple times. Avoid manually defining custom elements with `a-` prefixes if you are using A-Frame.
Warnings
- breaking A-Frame v1.7.0 replaced its internal CommonJS module system with ES Modules. Projects relying on `require('aframe')` or specific CommonJS imports for bundlers like Webpack 4 or older Node.js environments will break.
- breaking A-Frame v1.4.0 migrated its underlying custom element implementation to Custom Elements V1. While largely backward compatible, projects with very specific custom element polyfills or those defining their own custom elements with conflicting naming conventions might experience issues.
- breaking A-Frame v1.2.0 updated its bundled Three.js version to r125, which deprecated `THREE.Geometry` in favor of `THREE.BufferGeometry`. Custom components or direct Three.js code that relied on `THREE.Geometry` will likely break.
- gotcha When integrating A-Frame with Next.js, versions prior to v1.7.1 could experience issues where A-Frame's default CSS styles were skipped or incorrectly applied, leading to visual glitches or missing UI elements like the 'Enter VR' button.
Install
-
npm install aframe -
yarn add aframe -
pnpm add aframe
Imports
- Global AFRAME object via CDN
<!-- In your HTML file --> <script src="https://unpkg.com/aframe/dist/aframe-master.min.js"></script>
- A-Frame as an ES Module
const AFRAME = require('aframe');import 'aframe'; // Or if you need the AFRAME object for custom components: import * as AFRAME from 'aframe';
- Registering a custom component
import { registerComponent } from 'aframe'; // Incorrect named import for core functionality registerComponent('my-component', { /* ... */ });AFRAME.registerComponent('my-component', { init: function () { console.log('My component initialized!'); } });
Quickstart
<!DOCTYPE html>
<html>
<head>
<title>A-Frame Quickstart</title>
<script src="https://unpkg.com/aframe/dist/aframe-master.min.js"></script>
<script>
// Register a custom component
AFRAME.registerComponent('rotator', {
schema: { speed: { type: 'number', default: 1000 } },
init: function () {
this.el.setAttribute('animation', {
property: 'rotation',
to: '0 360 0',
loop: true,
dur: this.data.speed
});
},
update: function () {
this.el.setAttribute('animation', {
property: 'rotation',
to: '0 360 0',
loop: true,
dur: this.data.speed
});
}
});
</script>
</head>
<body>
<a-scene background="color: #FAFAFA">
<!-- Camera with controls -->
<a-entity camera look-controls wasd-controls position="0 1.6 0"></a-entity>
<!-- Simple rotating box -->
<a-box position="0 1 -3" rotation="0 45 0" color="#4CC3D9" rotator="speed: 2000"></a-box>
<!-- Ground plane -->
<a-plane position="0 0 -4" rotation="-90 0 0" width="10" height="10" color="#7BC8A4"></a-plane>
<!-- Sky -->
<a-sky color="#ECECEC"></a-sky>
</a-scene>
</body>
</html>