Component

In the entity-component-system pattern, a component is a reusable and
modular chunk of data that we plug into an entity to add appearance, behavior,
and/or functionality.

In A-Frame, components modify entities which are 3D objects in the scene. We
mix and compose components together to build complex objects. They let us
encapsulate three.js and JavaScript code into modules that we can use
declaratively from HTML.

As an abstract analogy, if we define a smartphone as an entity, we might use
components to give it appearance (color, shape), to define its behavior
(vibrate when called, shut down on low battery), or to add functionality
(camera, screen).

Components are roughly analogous to CSS. Like how CSS rules modify the
appearance of elements, component properties modify the appearance, behavior,
and functionality of entities.

Component HTML Form

A component holds a bucket of data in the form of one or more component
properties. Components use this data to modify entities. Consider an engine
component, we might define properties such as horsepower or cylinders.

Single-Property Component

If a component is a single-property component, meaning its data consists of a
single value, then in HTML, the component value looks like a normal HTML
attribute:

<!-- `position` is the name of the position component. --><!-- `1 2 3` is the data of the position component. --><a-entityposition="1 2 3"></a-entity>

Multi-Property Component

If a component is a multi-property component, meaning the data consists of
multiple properties and values, then in HTML, the component value resembles
inline CSS styles:

<!-- `light` is the name of the light component. --><!-- The `type` property of the light is set to `point`. --><!-- The `color` property of the light is set to `crimson`. --><a-entitylight="type: point; color: crimson"></a-entity>

Register a Component

AFRAME.registerComponent (name, definition)

Register an A-Frame component. We must register components before we use them
anywhere in <a-scene>. Meaning from an HTML file, components should come in
order before <a-scene>.

{string} name - Component name. The component’s public API as represented through an HTML attribute name.

Schema

The schema is an object that defines and describes the property or properties
of the component. The schema’s keys are the names of the property, and the
schema’s values define the types and values of the property (in case of a
multi-property component):

Property Types

Property types primarily define how the schema parses incoming data from the
DOM for each property. The parsed data will then be available via the data
property on the component’s prototype. Below are A-Frame’s built-in property
types:

For URLs pointing to general assets. Can parse URL out of a string in the form of url(<url>). If the value is an element ID selector (e.g., #texture), this property type will call getElementById and getAttribute('src') to return a URL. The asset property type may or may not change to handle XHRs or return MediaElements directly (e.g., <img> elements).

‘’

audio

Same parsing as the asset property type. Will possibly be used by the A-Frame Inspector to present audio assets.

parse is called when component properties are updated by setAttribute method.
stringify is called when DOM is updated by flushToDom method.

Single-Property Schema

A component can either be a single-property component (consisting of one
anonymous value) or a multi-property component (consisting of multiple named
values). A-Frame will infer whether a component is single-property vs.
multi-property based on the structure of the schema.

A single-property component’s schema contains type and/or default keys, and
the schema’s values are plain values rather than objects:

Definition Lifecycle Handler Methods

With the schema being the anatomy, the lifecycle methods are the physiology;
the schema defines the shape of the data, the lifecycle handler methods use
the data to modify the entity. The handlers will usually interact with the
Entity API.

Lifecycle method handlers. Image by Ruben Mueller from vrjump.de

Overview of Methods

Method

Description

init

Called once when the component is initialized. Used to set up initial state and instantiate variables.

update

Called both when the component is initialized and whenever any of the component’s properties is updated (e.g, via setAttribute). Used to modify the entity.

remove

Called when the component is removed from the entity (e.g., via removeAttribute) or when the entity is detached from the scene. Used to undo all previous modifications to the entity.

tick

Called on each render loop or tick of the scene. Used for continuous changes or checks.

tock

Called on each render loop or tick of the scene after the scene has rendererd. Used for post processing effects or other logic that needs to happen after the scene has been drawn.

play

Called whenever the scene or entity plays to add any background or dynamic behavior. Also called once when the component is initialized. Used to start or resume behavior.

pause

Called whenever the scene or entity pauses to remove any background or dynamic behavior. Also called when the component is removed from the entity or when the entity is detached from the scene. Used to pause behavior.

updateSchema

Called whenever any of the component’s properties is updated. Can be used to dynamically modify the schema.

Component Prototype Properties

Within the methods, we have access to the component prototype via this:

Property

Description

this.data

Parsed component properties computed from the schema default values, mixins, and the entity’s attributes. Important: Do not modify the data attribute directly. It is updated internally by A-Frame. To modify a component, use setAttribute.

.update (oldData)

.update (oldData) is called whenever the component’s properties change,
including at the beginning of the component’s lifecycle. An entity can call a
component’s update handler:

After init () is called, at the beginning of component’s lifecycle.

When the component’s properties are updated with .setAttribute.

The update handler is often used to:

Do most of the work in making modifications to the entity, using this.data.

Modify the entity whenever one or more component properties change.

Granular modifications to the entity can be done by diffing the current
dataset (this.data) with the previous dataset before the update (oldData).

A-Frame calls .update() both at the beginning of a component’s lifecycle and every
time a component’s data changes (e.g., as a result of setAttribute). The
update handler often uses this.data to modify the entity. The update handler
has access to the previous state of a component’s data via its first argument.
We can use the previous data of a component to tell exactly which
properties changed to do granular updates.

For example, the visible component’s update sets the visibility of
the entity.

.tick (time, timeDelta)

.tick () is called on each tick or frame of the scene’s render loop. The scene
will call a component’s tick handler:

On each frame of the render loop.

On the order of 60 to 120 times per second.

If the entity or scene is not paused (e.g., the Inspector is open).

If the entity is still attached to the scene.

The tick handler is often used to:

Continuously modify the entity on each frame or on an interval.

Poll for conditions.

The tick handler is provided the global uptime of the scene in milliseconds
(time) and the time difference in milliseconds since the last frame
(timeDelta). These can be used for interpolation or to only run parts of the
tick handler on a set interval.

For example, the tracked controls component will progress
the controller’s animations, update the controller’s position and rotation, and
check for button presses.

Definition Properties

dependencies

dependencies allows for control on ordering of component initialization if a
component depends on one or more other components. Component names specified in
the dependencies array will be initialized left-to-right before initializing
the current component. If the dependency have other dependency components,
those other dependency components will be ordered in the same manner:

multiple

The multiple flag allows for a component to have multiple instances of itself
on an entity. Since multiple is set to false by default, an entity could
only have a single instance of a component. For example, an entity could only
have one geometry component.

But if a component has multiple set to true, then the component can have
multiple instances:

AFRAME.registerComponent('foo', { multiple: true,// ...});

In the DOM, we can differentiate between instances of the component by giving a
suffix of a double underscore and ID (__<ID>). For example, to attach
multiple instances of the sound component:

If we’re doing a setObject3D(), we’ll usually want to use this.attrName. If
a component instance is set with foo__bar, then this.attrName would be
foo__bar. This gives us a namespace and an ID to set an object3D on the
entity’s object3DMap:

AFRAME.registerComponent('foo', { multiple: true, update: function () {// An object3D will be set using `foo__bar` as the key.this.el.setObject3D(this.attrName, new THREE.Mesh()); }});

Component Prototype Methods

.flushToDOM ()

To save on CPU time on stringification, A-Frame will only update in debug mode
the component’s serialized representation in the actual DOM. Calling
flushToDOM () will manually serialize the component’s data and update the
DOM:

Accessing a Component’s Members and Methods

A component’s members and methods can be accessed through the entity from the
.components object. Look up the component from the entity’s map of
components, and we’ll have access to the component’s internals. Consider this
example component: