<commit_before>---
title: Best Practices
type: introduction
layout: docs
parent_section: introduction
order: 13
---

## A-Frame

[ecs]: ./entity-component-system.md
[mixins]: ../core/mixins.md
[template]: https://github.com/supermedium/superframe/tree/master/components/template/

The core structure of A-Frame is [entity-component (ECS)][ecs]. Place and
structure application code within purely A-Frame components for reusability,
modularity, composability, decoupling, encapsulation, declarativeness, and
testability.

**Do not do this**:

```
<a-scene>
  <a-box></a-box>
  <!-- ... -->
</a-scene>

<script>
  // My JavaScript code here!
  // ... NO!
</script>
```

Place your code within A-Frame components so they are executed at the correct
time, to encapsulate reusable code, and to make use of the framework which is the
purpose of using A-Frame.

**Do this**:

```
<script>
  AFRAME.registerComponent('code-that-does-this', {
    init: function () {
      // Code here.
      console.log(this.el);
    }
  });

  AFRAME.registerComponent('code-to-attach-to-box', {
    init: function () {
      // Code here.
      console.log(this.el);
    }
  });
</script>

<a-scene code-that-does-this>
  <a-box code-to-attach-to-box></a-box>
  <!-- ... -->
</a-scene>
```

## Performance

[animation]: ../components/animation.md#direct-values-through-object3d-and-components
[asm]: ../core/asset-management-system.md
[hardware]: ./vr-headsets-and-webxr-browsers.md
[stats]: ../components/stats.md
[pool]: ../components/pool.md
[background]: ../components/background.md
[geometrymerger]: https://www.npmjs.com/package/aframe-geometry-merger-component


Performance is critical in VR. A high framerate must be maintained in order for
people to feel comfortable. Here are some ways to help improve performance of
an A-Frame scene:

- Use [recommended hardware specifications][hardware].
- Use the **[stats component][stats]** to keep an eye on various metrics (FPS,
  vertex and face count, geometry and material count, draw calls, number of
  entities). We want to maximize FPS and minimize everything else.
- Limit draw calls as much as possible. Each geometry, object, model without
  optimization is generally a draw call. Rule of thumb, try to keep under 300
  maximum. [Merge][geometrymerger] together all static meshes if possible. You
  can use [geometry-merger][geometrymerger] and then make use a three.js
  material with vertex colors enabled. three.js geometries keep data such as
  color, uvs per vertex that can be used to maintain and manipulate geometries
  post-merge.
- Make use of the **[asset management system][asm]** to browser cache and
  preload assets.
- If using models, look to bake your lights into textures rather than relying
  on real-time lighting and shadows.
- Generally, the fewer number of entities and lights in the scene, the better.
- Make sure your textures' resolutions are sized to powers of two (e.g.,
  256x256, 512x1024) in order to avoid the renderer having to resize the
  texture during runtime.
- Limit the number of faces and vertices on models.
- Some further techniques include geometry instancing, [geometry
  merging][geometrymerger], level of detail (LOD).
- When using raycasters or colliders, select which entities are to be raycasted
  against rather than raycasting against every object in the scene.
- When adding continuously running behaviors, use A-Frame component `tick`
  handlers to hook into the global render loop. Use utilities such as
  `AFRAME.utils.throttleTick` to limit the number of times the `tick` handler
  is run if appropriate.
- Use the **[background component][background]** instead of `a-sky` to define a
  solid color as the scene background. This prevents the creation of
  unnecessary geometry.
- Update `position`, `rotation`, `scale`, and `visible` using at the three.js
  level (`el.object3D.position`, `el.object3D.rotation`, `el.object3D.scale`,
  `el.object3D.visible`) to avoid overhead on `.setAttribute`.
- If you need to create, remove and re-create many entities of the same type,
  use the **[pool component][pool]** to pre-generate and reuse entities. This
  avoids the cost of creating entities on the fly and reduces garbage collection.
- When using the animation component, [animate values directly][animation] 
  which will skip `.setAttribute` and animate JS values directly. 
  For example, instead of `material.opacity`, 
  animate `components.material.material.opacity`.

### GPU Texture Preloading

Until non-blocking texture uploads to the GPU are available, try to draw all
materials and textures up front. When materials and textures are drawn for the
first time, the browser will hang and block while uploading to the GPU. We can
manually preload textures by calling:

```js
document.querySelector('a-scene').renderer.setTexture2D(ourTexture, 0);
```

We will try to come with a convenient API in A-Frame to do this automatically.

[360]: https://aframe-360-gallery.glitch.me<commit_msg>Fix minor typo in best-practices doc (#5129)<commit_after>---
title: Best Practices
type: introduction
layout: docs
parent_section: introduction
order: 13
---

## A-Frame

[ecs]: ./entity-component-system.md
[mixins]: ../core/mixins.md
[template]: https://github.com/supermedium/superframe/tree/master/components/template/

The core structure of A-Frame is [entity-component (ECS)][ecs]. Place and
structure application code within purely A-Frame components for reusability,
modularity, composability, decoupling, encapsulation, declarativeness, and
testability.

**Do not do this**:

```
<a-scene>
  <a-box></a-box>
  <!-- ... -->
</a-scene>

<script>
  // My JavaScript code here!
  // ... NO!
</script>
```

Place your code within A-Frame components so they are executed at the correct
time, to encapsulate reusable code, and to make use of the framework which is the
purpose of using A-Frame.

**Do this**:

```
<script>
  AFRAME.registerComponent('code-that-does-this', {
    init: function () {
      // Code here.
      console.log(this.el);
    }
  });

  AFRAME.registerComponent('code-to-attach-to-box', {
    init: function () {
      // Code here.
      console.log(this.el);
    }
  });
</script>

<a-scene code-that-does-this>
  <a-box code-to-attach-to-box></a-box>
  <!-- ... -->
</a-scene>
```

## Performance

[animation]: ../components/animation.md#direct-values-through-object3d-and-components
[asm]: ../core/asset-management-system.md
[hardware]: ./vr-headsets-and-webxr-browsers.md
[stats]: ../components/stats.md
[pool]: ../components/pool.md
[background]: ../components/background.md
[geometrymerger]: https://www.npmjs.com/package/aframe-geometry-merger-component


Performance is critical in VR. A high framerate must be maintained in order for
people to feel comfortable. Here are some ways to help improve performance of
an A-Frame scene:

- Use [recommended hardware specifications][hardware].
- Use the **[stats component][stats]** to keep an eye on various metrics (FPS,
  vertex and face count, geometry and material count, draw calls, number of
  entities). We want to maximize FPS and minimize everything else.
- Limit draw calls as much as possible. Each geometry, object, model without
  optimization is generally a draw call. Rule of thumb, try to keep under 300
  maximum. [Merge][geometrymerger] together all static meshes if possible. You
  can use [geometry-merger][geometrymerger] and then make use a three.js
  material with vertex colors enabled. three.js geometries keep data such as
  color, uvs per vertex that can be used to maintain and manipulate geometries
  post-merge.
- Make use of the **[asset management system][asm]** to browser cache and
  preload assets.
- If using models, look to bake your lights into textures rather than relying
  on real-time lighting and shadows.
- Generally, the fewer number of entities and lights in the scene, the better.
- Make sure your textures' resolutions are sized to powers of two (e.g.,
  256x256, 512x1024) in order to avoid the renderer having to resize the
  texture during runtime.
- Limit the number of faces and vertices on models.
- Some further techniques include geometry instancing, [geometry
  merging][geometrymerger], level of detail (LOD).
- When using raycasters or colliders, select which entities are to be raycasted
  against rather than raycasting against every object in the scene.
- When adding continuously running behaviors, use A-Frame component `tick`
  handlers to hook into the global render loop. Use utilities such as
  `AFRAME.utils.throttleTick` to limit the number of times the `tick` handler
  is run if appropriate.
- Use the **[background component][background]** instead of `a-sky` to define a
  solid color as the scene background. This prevents the creation of
  unnecessary geometry.
- Update `position`, `rotation`, `scale`, and `visible` at the three.js
  level (`el.object3D.position`, `el.object3D.rotation`, `el.object3D.scale`,
  `el.object3D.visible`) to avoid overhead on `.setAttribute`.
- If you need to create, remove and re-create many entities of the same type,
  use the **[pool component][pool]** to pre-generate and reuse entities. This
  avoids the cost of creating entities on the fly and reduces garbage collection.
- When using the animation component, [animate values directly][animation] 
  which will skip `.setAttribute` and animate JS values directly. 
  For example, instead of `material.opacity`, 
  animate `components.material.material.opacity`.

### GPU Texture Preloading

Until non-blocking texture uploads to the GPU are available, try to draw all
materials and textures up front. When materials and textures are drawn for the
first time, the browser will hang and block while uploading to the GPU. We can
manually preload textures by calling:

```js
document.querySelector('a-scene').renderer.setTexture2D(ourTexture, 0);
```

We will try to come with a convenient API in A-Frame to do this automatically.

[360]: https://aframe-360-gallery.glitch.me
{'fraction_non_alphanumeric': 0.10450594464981516, 'fraction_numerical': 0.006594065341192926, 'mean_word_length': 4.007503751875938, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 31, 'https://': 6, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6420241', 'n_tokens_mistral': 2927, 'n_tokens_neox': 2766, 'n_words': 1176}