Note: This documentation is for the old 0.3.0 version of A-Frame. Check out the documentation for the current 1.5.0 version

Primitives are entities that:

  • Have a semantic name (e.g., <a-box>)
  • Have a preset assemblage of components
  • Have default component property values
  • Map HTML attributes to component properties

They are a convenience layer on top of the core API and are meant to:

  • Pre-compose useful components together with prescribed defaults
  • Act as a shorthand for complex-but-common types of entities (e.g., <a-sky>)
  • Provide a familiar interface with HTML attributes mapping to only a single value

They are sort of like Prefabs in Unity. Some literature on the entity-component-system pattern refer to these as assemblages.


Here is an assortment of various primitives in use:

<!-- Using the asset management system for caching. -->
<a-asset-item id="fox-obj" src="fox.obj"></a-asset-item>
<a-asset-item id="fox-mtl" src="fox.mtl"></a-asset-item>
<img id="texture" src="texture.png">
<video id="video" src="video.mp4"></video>

<a-camera fov="80"><a-cursor></a-cursor></a-camera>
<a-box src="#texture" depth="2" height="5" width="1"></a-box>
<a-image src="fireball.jpg"></a-image>
<a-video src="#video"></a-video>
<a-sky color="#432FA0"></a-sky>

Primitives are Entities

Since every primitive extends <a-entity>s, things that can be done with entities can be done with primitives:

For example, let’s take <a-box> primitive, and say someone writes a third-party physics component. We can attach it to <a-box> just as we would with any entity:

<a-box color="red" physics="mass: 2.4"></a-box>

How They Work

To create a wide red box using the primitives API, we could write:

<a-box color="red" width="3"></a-box>

Which ends up expanding to:

<a-box color="red" width="3" geometry="primitive: box; width: 3" material="color: red"></a-box>

Under the hood, we see that primitives extend <a-entity> as a custom element while providing some defaults. It defaults the geometry.primitive property to box. And it maps (i.e., proxies) the HTML width attribute to the underlying geometry.width property and the HTML color attribute to the underlying material.color property.

Register a Primitive

We can compose and register our own primitives (i.e., register an element) for other people to easily use.

For example, here is what the registration looks like for <a-box> primitive:

var extendDeep = AFRAME.utils.extendDeep;

// The mesh mixin provides common material properties for creating mesh-based primitives.
// This makes the material component a default component and maps all the base material properties.
var meshMixin = AFRAME.primitives.getMeshMixin();

AFRAME.registerPrimitive('a-box', extend({}, meshMixin, {
// Preset default components. These components and component properties will be attached to the entity out-of-the-box.
defaultComponents: {
geometry: {primitive: 'box'}

// Defined mappings from HTML attributes to component properties (using dots as delimiters). If we set `depth="5"` in HTML, then the primitive will automatically set `geometry="depth: 5"`.
mappings: {
depth: 'geometry.depth',
height: 'geometry.height',
width: 'geometry.width'

For example, Don McCurdy’s aframe-extras creates <a-ocean> primitive using his ocean component:

AFRAME.registerPrimitive('a-ocean', {
// Attaches the ocean component by default.
// And smartly makes the ocean parallel to the ground.
defaultComponents: {
ocean: {},
rotation: {x: -90, y: 0, z: 0}

// Maps HTML attributes to his ocean component's properties.
mappings: {
width: 'ocean.width',
depth: 'ocean.depth',
density: 'ocean.density',
color: 'ocean.color',
opacity: 'ocean.opacity'

Then we’d be able to create oceans using basic HTML syntax with little configuration needed:

<a-ocean color="aqua" height="100" width="100"></a-ocean>