A-Frame Animation Tutorial
By Alastair Beeson
Animations in A-Frame
Animations in A-Frame are a great way to add action, life and motion to your VR scenes. Previously animations in A-Frame were handled by a-animation. Be careful as many online animation tutorials and forum posts still use a-animation. This has been deprecated since 0.9.0. Instead, A-Frame has now incorporated an animation component that functions as if it were a property of an object.
A-Frame lists what you can animate as:
Component values (e.g., position, visible)
Component property values (e.g., light.intensity)
Further documentation here: https://aframe.io/docs/1.2.0/components/animation.html
How to Animate An Object
You add an animation to an a-entity or other a-frame object like a-torus as a property:
animation="property: position; to: 1 8 -10; dur: 2000; easing: linear; loop: true"
This code example adds an animation to an object that changes its position property such that it moves to the position 1 8 -10, with a duration of 2000 milliseconds, a linear easing, and will loop.
If you want to add multiple animations to an object, you simply have to write something with __ in between two words like: animation__rotation or animation__2
This is an example of a sphere with two animations that turns from white to black and rotates:
<a-sphere position="-2 5 -5" color="white" radius="1.2" animation="property: components.material.material.color;
type: color;
to: black;
dur: 1000;
dir: alternate;
loop: true"
animation__2="property: rotation; loop: true; to: 0 360 0; dur: 40000; easing: linear;"
</a-sphere>
If you want to add multiple animations to an object, you simply have to write something with __ in between two words like: animation__rotation or animation__2
Animating Tips
One immensely useful animating tip is creating specific animations as a mixin. This allows you to easily give objects a specific animation without having to write out the animation again. For instance if you were animating the solar system or clouds moving, you could have a-mixins like “orbit” or “movement”.
Below is a sample a-mixin to change the color of an object to black.
<a-mixin id="colorchange" animation="property: components.material.material.color;
type: color; to: black; dur: 1000; dir: alternate; loop: true”></a-mixin>
You can can still tweaks attributes of an animation when using a mixin like the following example where the entity uses a mixin but the animation has a longer duration. This can be useful for examples where you want objects moving in similar ways but at different speeds like objects in orbit
<a-entity id="bigsphere" mixin="colorchange" animation="dur: 20000;">
Creating an Atom Tutorial
Now that you understand some of the basics of animation in A-Frame, let's try to created an animated object. This tutorial will allow you to create complex animated composite objects in a-frame that combine different shapes, animations, and textures. In this tutorial we will create and animate an atom.
To create an atom we need several different elements:
A a-sphere to represent the nucleus
A few a-torus to represent the electron rings
A texture to make our sphere look like an atom
A rotation animation to make our atom and its rings spin
A orbit animation to make our atom orbit in a circle
Step 1: Basic Scene Composition and Importing A-Frame
In this step we merely set up our HTML page. In <head> we import A-Frame 1.3.0 and also set up a simple <a-scene> with a white sky.
<html>
<head>
<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
</head>
<body>
<a-scene>
<a-sky color="#ECECEC"></a-sky>
</a-scene>
</body>
</html>
Step 2: Loading Our Texture
In this step we want to load in a texture for our atom’s sphere. To do this, create an <a-assets> section within your <a-scene>. This specific nucleus texture is hosted in a glitch asset library. The texture isn’t perfect as it's trying to represent the nucleus which is made up of a “bumpy” cluster of protons and neutrons.
<a-assets>
<img id="atom-texture" src="https://cdn.glitch.global/61bb39fc-ecfc-4eb0-bc43-2d94053ff982/nucleus.png?v=1654110423213" crossorigin="anonymous">
</a-assets>
Step 3: Defining The Atom Object.
In order to make a complex object that can be manipulated and moved as one object, we will need to create nested a-entitys to handle all the parts of the atom like the nucleus and its rings.
We start by creating our a-entity known as orbit-atom. This will be the object that handles the orbit of all objects within our atom object so that they will all move together at the same speed and direction.
Next we create our a-entity atom-container. This container object is meant to hold all objects within our atom object and also define the atom’s starting position within the <a-scene>
Next we create an a-sphere called atom. This sphere will serve as the nucleus of our atom object.
Next we want to create 4 different torus objects called electron rings 1-4. These will serve to illustrate the electron orbits around our nucleus. We will put each electron ring at an angle to create the configuration commonly associated with an atom that you might see in a textbook or google images. They are also different sizes to represent the different radii of electron rings.
Once those are completed we merely close up our atom-container and orbit-atom a-entities.
<a-entity id="orbit-atom">
<a-entity id="atom-container" position="0 0 5">
<a-sphere radius="1.8" id="atom" src="#atom-texture""></a-sphere>
<a-entity id="electron-ring-1" geometry="primitive: torus; radius: 3; radiusTubular: 0.1;segmentsTubular: 50"
material="color: #57524A;" rotation="90 0 0" scale="1 1 0.1" ></a-entity>
<a-entity id="electron-ring-2" geometry="primitive: torus; radius: 2; radiusTubular: 0.1;segmentsTubular: 50"
material="color: #57524A;" rotation="45 0 0" scale="1 1 0.1" ></a-entity>
<a-entity id="electron-ring-3" geometry="primitive: torus; radius: 2.2; radiusTubular: 0.1;segmentsTubular: 50"
material="color: #57524A;" rotation="135 0 0" scale="1 1 0.1" ></a-entity>
<a-entity id="electron-ring-4" geometry="primitive: torus; radius: 2.5; radiusTubular: 0.1;segmentsTubular: 50"
material="color: #57524A;" rotation="0 0 0" scale="1 1 0.1" ></a-entity>
</a-entity>
</a-entity>
Step 4: Animating Our Atom
Now that we have created all the parts of our atom, it's time to animate it.
First we can animate the atoms' orbit around the a-scene by giving a rotation animation to orbit-atom.
Next we want to animate our a-sphere so that it spins while orbiting by using the rotation animation.
Next we want to make our rings spin and rotate by also using a rotation animation.
Since all of our animations use rotation, here is a breakdown of a rotation animation:
animation="property: rotation; loop: true; to: 0 360 0; dur: 40000; easing: linear;">
Property: This is what property we are animating, in this case we are animating the rotation of our object
Loop: This decides whether or not our animation will continue/happen again after completing. In this case our object will continue to rotate infinitely.
To: This is where our object is rotating to. In this case our object is moving in a 360 circular rotation around a point, creating the effect of an orbiting object.
Dur: How long in milliseconds it takes for our animation to complete. This animation takes 40000 milliseconds or 40 seconds to complete 1 cycle.
Easing: What kind of easing our animation uses, this allows animations to feel more natural or organic like they were affected by physics. In this case, for simplicity's sake, we use linear easing which means that there is no easing on our animation. Thus our animation increases in even amounts which may make it feel a little robotic.
These are just some of the many properties you can add to your animations in A-Frame
Now back to our code with animation implemented:
<a-entity id="orbit-atom" animation="property: rotation; loop: true; to: 0 360 0; dur: 40000; easing: linear;">
<a-entity id="atom-container" position="0 0 5">
<a-sphere radius="1.8" id="atom" src="#atom-texture" animation="property: rotation; loop: true; from: 0 0 0; to: 0 360 0; dur: 20000; easing: linear;"></a-sphere>
<a-entity id="atom-ring-1" geometry="primitive: torus; radius: 3; radiusTubular: 0.1;segmentsTubular: 50"
material="color: #57524A;" rotation="90 0 0" scale="1 1 0.1" animation="property: rotation; loop: true; from: 0 0 0; to: 360 360 360; dur: 5000; easing: linear;"></a-entity>
<a-entity id="atom-ring-2" geometry="primitive: torus; radius: 2; radiusTubular: 0.1;segmentsTubular: 50"
material="color: #57524A;" rotation="45 0 0" scale="1 1 0.1" animation="property: rotation; loop: true; from: 0 0 0; to: 360 360 360; dur: 5200; easing: linear;"></a-entity>
<a-entity id="atom-ring-3" geometry="primitive: torus; radius: 2.2; radiusTubular: 0.1;segmentsTubular: 50"
material="color: #57524A;" rotation="135 0 0" scale="1 1 0.1" animation="property: rotation; loop: true; from: 0 0 0; to: 360 360 360; dur: 4900; easing: linear;"></a-entity>
<a-entity id="atom-ring-4" geometry="primitive: torus; radius: 2.5; radiusTubular: 0.1;segmentsTubular: 50"
material="color: #57524A;" rotation="0 0 0" scale="1 1 0.1" animation="property: rotation; loop: true; from: 0 0 0; to: 360 360 360; dur: 5100; easing: linear;"></a-entity>
</a-entity>
</a-entity>
Step 5: Completed Project
Your completed code should look like this:
<html>
<head>
<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
</head>
<body>
<a-scene>
<a-assets>
<img id="sun-texture" src="https://cdn.glitch.global/61bb39fc-ecfc-4eb0-bc43-2d94053ff982/nucleus.png?v=1654110423213"
crossorigin="anonymous">
</a-assets>
<a-entity id="orbit-saturn" animation="property: rotation; loop: true; to: 0 360 0; dur: 40000; easing: linear;">
<a-entity id="saturn-container" position="0 0 5">
<a-sphere radius="1.8" id="saturn" src="#sun-texture" animation="property: rotation; loop: true; from: 0 0 0; to: 0 360 0; dur: 20000; easing: linear;"></a-sphere>
<a-entity id="saturn-ring-1" geometry="primitive: torus; radius: 3; radiusTubular: 0.1;segmentsTubular: 50"
material="color: #57524A;" rotation="90 0 0" scale="1 1 0.1" animation="property: rotation; loop: true; from: 0 0 0; to: 360 360 360; dur: 5000; easing: linear;"></a-entity>
<a-entity id="saturn-ring-2" geometry="primitive: torus; radius: 2; radiusTubular: 0.1;segmentsTubular: 50"
material="color: #57524A;" rotation="45 0 0" scale="1 1 0.1" animation="property: rotation; loop: true; from: 0 0 0; to: 360 360 360; dur: 5200; easing: linear;"></a-entity>
<a-entity id="saturn-ring-3" geometry="primitive: torus; radius: 2.2; radiusTubular: 0.1;segmentsTubular: 50"
material="color: #57524A;" rotation="135 0 0" scale="1 1 0.1" animation="property: rotation; loop: true; from: 0 0 0; to: 360 360 360; dur: 4900; easing: linear;"></a-entity>
<a-entity id="saturn-ring-4" geometry="primitive: torus; radius: 2.5; radiusTubular: 0.1;segmentsTubular: 50"
material="color: #57524A;" rotation="0 0 0" scale="1 1 0.1" animation="property: rotation; loop: true; from: 0 0 0; to: 360 360 360; dur: 5100; easing: linear;"></a-entity>
</a-entity>
</a-entity>
<a-sky color="#ECECEC"></a-sky>
</a-scene>
</body>
</html>
Conclusion
Congratulations you have successfully created a (not entirely scientifically) accurate and animated atom object.
The end result of this tutorial is hosted here on Glitch: https://atom-demo.glitch.me/
Animating parts of your data visualizations might make them more immersive and exciting for users. In addition, be sure to consider ways to slow down or change animation speed for users with accessibility issues.