How is A-Frame’s performance?

A-Frame can achieve native-like latency and framerate with proper browsers (e.g., Firefox with WebVR). For example, A-Painter is Tilt Brush in the browser that can smoothly run 90 frames per second and can be indiscernible from native.

A-Frame being based on HTML is not an issue. While the browser’s 2D layout has been a primary performance concern for normal web applications, A-Frame uses Custom Elements to act merely as data containers and does not trigger the layout engine. 3D operations are done in memory with minimal overhead and are rendered with WebGL, which binds to OpenGL or Direct3D.

Some measures that A-Frame takes to minimize overhead include:

  • Making setAttribute synchronous with a reduced code path. Modifying an entity’s position via setAttribute('position', {x: 1, y: 2, z: 3}) almost directly touches the underlying three.js objects. The overhead involves comparing new data to old data to determine whether a change needs to be triggered and invoking lifecycle handlers.
  • Not serializing data back to the DOM. When changing an entity’s properties, the actual HTML as seen in the browser’s DOM inspector is not updated to reduce stringification operations. This makes most operations done in memory, a tiny bit similar to Virtual DOM.
  • Keeping everything under a single requestAnimationFrame and letting components hook into a single global render loop via the tick handler.
  • Caching HTML attributes values.
  • Caching assets, materials, textures, geometries.
  • Providing community components that implement performance techniques used in the 3D and game industry (e.g., geometry instancing, level-of-detail, object pooling).

A-Frame provides reasonable defaults that yield good performance for most common use cases. However, performance is ultimately determined by the complexity and characteristics of each individual application. To get the best use of resources, we will need deeper understanding about 3D graphics. See best performance practices and guidelines to get started.

Why is my experience not entering VR or AR mode?

If you are using A-Frame 1.6.0 or older you probably need to update to the latest release. Browsers are migrating to the WebXR standard and old versions might no longer work.

You also have to serve your content over HTTPS. The WebXR API won’t be available over HTTP.

Why does my asset (e.g., image, video, model) not load?

First, if you are doing local development, make sure you are using a local server so that asset requests work properly.

If you are loading the asset from a different domain, make sure that the asset is served with cross-origin resource sharing (CORS) headers. You could either find a host to serve the asset with CORS headers, or place the asset on the same domain (directory) as your application.

If you are trying to load a video, make sure the browser supports the video (i.e., encoding, framerate, size).

Video autoplay policies are getting more and more strict and rules might vary across browsers. Mandatory user gesture is now commonly enforced. For maximum compatibility, you can offer a button that the user can click to start video playback. Simple sample code can be found in the docs. Pay particular attention to the play-on-click component

Read the Hosting and Publishing guide for more information.

Why is the HTML not updating when I check the browser inspector?

If you open up your browser’s developer tools, you’ll see that the HTML attribute values are empty.


To improve performance, A-Frame does not update the HTML to save on stringification operations. This also means mutation observations will not fire. Use the debug component or .flushToDOM methods if you need to sync to the DOM.

Why does my video not play?

Mobile and now desktop browsers have limitations playing inline video.

Because of an iOS platform restriction in order to get inline video (with or without autoplay), we must:

  • Set the <meta name="apple-mobile-web-app-capable" content="yes"> meta tag (will be injected if missing).
  • Set the playsinline attribute to the video element (is automatically added to all videos).
  • Possibly pin the webpage to the homescreen for older iOS versions.

Mobile and desktop browsers have been tightening the video autoplay policies to preserve battery and avoid intrusive advertisements. Most browsers now require a user action (such as a click or tap event) to start video playback:

-Chrome for Android -Chrome desktop -Safari -Firefox

There’s an A-Frame example that includes the necessary logic to request the user clicking or tapping to start video playback. The source code is also available

We do not focus too much on video, but below are GitHub issues that may contain helpful information from community:

How do I display <iframe>s or render HTML in A-Frame?

There is no way for the browser to display <iframe>s within WebGL. While it is possible to overlay an <iframe> on top of the canvas, the <iframe> will not display in VR nor can it integrate with the scene.

Though, we can render basic HTML and CSS as a texture without interactivity. We can paint to a <canvas> and use the canvas as source for a texture. There are components in the ecosystem that enable this:

Which 3D model formats work?

The ideal format is the GL Transmission Format glTF (.gltf) since glTF is feature-rich, compact, and efficient. glTF focuses on providing a transmission format rather than an editor format and is more interoperable with web technologies. Read more about glTF and A-Frame’s glTF component.

Wavefront (.obj) is also a well-known format but has some limitations like the lack of animation and vertex color support.

There are also components in the ecosystem for loading other formats:

Below are a couple basic examples for using models:

Where can I find assets?

In general, awesome-stock-resources is a great collection of free assets.

For images, check out textures.com.

For 360° images, search for equirectangular images on Flickr.

For 3D models, check out:

For sounds, check out:

Can I render Vimeo videos as a texture?

Yes. Vimeo has an A-Frame plugin, but rendering is limited to just videos from your personal Vimeo account.

Can I render YouTube videos as a texture?

No. You could proxy YouTube videos as a texture or download them locally to serve, but that is against their terms of service.

Browsers provide the ability to go from WebVR page to WebVR page via the vrdisplayactivate event described in the WebVR specification. Currently, not all browsers implement this. Firefox with WebVR implements this. A link component for link traversal was released with A-Frame 0.6.0:

<a-entity link="on: click; href: https://aframe-aincraft.glitch.me"></a-entity>

Can I prevent the camera from going through obstacles?

This depends on what devices you plan to support and how you allow users to navigate your scene. For most VR experiences, follow best practices and only move the camera proportionately to the user’s motion.

Don’t block the camera if the user steps forward in a room-scale VR space. For most VR applications it’s better to do locomotion with methods such as using teleportation controls, designing your scene to keep obstacles out of the way or not require much movement, or explore more creative ways of moving users through the world.

For non-VR desktop experiences with a gamepad or keyboard controls or for VR scenes where the camera is inside a vehicle, you can add a physics engine to prevent movement through obstacles.

What type of units does A-Frame use?

A-Frame uses meters with a 1:1 ratio since the WebVR API also uses meters. 5 units in A-Frame is equal to 5 meters in real life. Furthermore, when using programs like Blender, configured in imperial or metric mode, measurements will also translate 1:1. 10 feet in Blender will equal 10 feet in real life.

How is A-Frame different from VRML?

A-Frame is a JavaScript framework. Unlike VRML, A-Frame is not a 3D file format, markup language, nor a standard. A-Frame embraces the Extensible Web Manifesto. Only look at standardization as winning ideas emerge.

Technically, A-Frame is an entity-component-system game engine on top of three.js. As it is a JavaScript framework, coding is to be expected for more complex applications. Unlike 3D file formats, A-Frame provides power and interactivity via full access to JavaScript, three.js, and Web APIs.

Does A-Frame support X feature?

A-Frame ships with a number of components and primitives. Being based on top of an entity-component-system architecture, if a feature doesn’t exist, you can write or find a component to enable it. Or if one of the standard components doesn’t fit your use cases, you can copy and modify it.

Read Where to Find Components for more information.

Does A-Frame support X library or framework?

A-Frame is built on top of the DOM so most libraries and frameworks work including:

Which headsets, browsers, devices, and platforms does A-Frame support?

Most of them. Read VR Headsets and WebVR Browsers for more information.

How can I improve performance?

Read Best Practices — Performance for more information.

How can I get in touch with the A-Frame team?

We try to be responsive and helpful! We love questions, feedback, bug reports, and pull requests:

Where is the roadmap?

The roadmap is on GitHub!

Do I call it “A-Frame” or “aframe” or “aframevr” or “aFrame”?


Why do my textures render black?

Phones with Adreno 300 series GPUs are notoriously problematic. Set renderer precision to medium as a workaround. Real fix has to happen at the driver / device level.

Why is the gyroscope / magic window mode not working?

New browser policies require sites to prompt the user for permission before getting access to DeviceMotionEvents. Starting with iOS 13 DeviceMotionEvents are only available for pages served over https. Other browsers will also apply same policies and restrictions. A-Frame now incorporates customizable UI to request the necessary permissions to the user. Make sure to update to A-Frame latest version

Can I use A-Frame offline or self hosted?

Using A-Frame online sometimes is not possible or inconvenient, like for instance when traveling or during public events with poor Internet connectivity. A-Frame is mostly self-contained so including the build (aframe.min.js) in your project will be sufficient in many cases. Some specific parts are lazy loaded and only fetched when used. This is for example the case of the fonts for the text component and the 3D models for controllers. In order to make an A-Frame build work either offline or without relying on A-Frame hosting infrastructure (typically cdn.aframe.io), you can monitor network requests on your browser console. This will show precisely what assets are being loaded and thus as required for your specific experience. Fonts can be found via FONT_BASE_URL in the whereas controllers via MODEL_URLS. Both can be modified in the source and included in your own custom build

Can I load A-Frame as an ES module?

You can load A-Frame as an ES module using a side effect import. A-Frame will then initialize any <a-scene> in the document. It’s still important to register any components or systems you need before this happens:

<script type="importmap">
"imports": {
"aframe": "https://aframe.io/releases/1.6.0/aframe.min.js",
<script type="module">
import 'aframe';
AFRAME.registerComponent('my-component', {

If it’s not possible to register everything synchronously to importing A-Frame, you can set the window.AFRAME_ASYNC flag. This prevents A-Frame from initializing <a-scene> tags, until you give a ready signal by calling window.AFRAME.emitReady(). Note that this flag must be set before importing A-Frame, as shown in the following example:

window.AFRAME_ASYNC = true;
await import('aframe');

// Asynchronously register components/systems


What order does A-Frame render objects in?

In many cases, the order in which objects is rendered doesn’t matter much - most scenes will look the same whatever order the objects are rendered in - but there are a few cases where sorting is important:

  • for transparent objects, it’s typically better to render objects furthest to nearest (although some cases are more complex and require more sophisticated approaches). However, when the camera and/or objects are moving, this can result in undesirable visual effects when objects switch in terms of their relative distance from the camera
  • for performance reasons, it’s typically desirable to render objects nearest to furthest, so that GPU doesn’t spend time drawing pixels that end up being drawn over.
  • for AR “hider material” used to hide parts of the scene to create the appearance of occlusion by real-world objects, it’s typically necessary to render these before the rest of the scene.

By default, A-Frame sorts objects as follows:

  • for all objects, if renderOrder is set on the Object3D or a Group that it is a member of, the specified order will be respected
  • otherwise, opaque objects are rendered furthest to nearest, and transparent objects are rendered in the order they appear in the THREE.js Object tree (in most cases, this is the same as the order they appear in the DOM)

The renderer system has a sortTransparentObjects property, which can be used to render transparent objects furthest to nearest, rather than in DOM order.