In this article, we will create a simple and practical example simulating the rising sun in an immersive environment to demonstrate some capabilities of the A-Frame framework by changing the Hello World official framework code and adding animations and light spots to improve the scene visualization, along with the explained source code and result from each step. Code snippets will be provided so they can be copied and pasted by anyone to test them.
Hello World with Animation and Lights
The starting point will be the A-Frame’s Hello World taken from the official documentation. The intention is to play around with some components to simulate the earth's beautiful sun rising, to show it is possible to make by adding animation and light to an environment just by writing a few lines of HTML code. The practice uses Glitch to code since it will help with the execution on desktops and mobiles. It doesn't hurt to remember that a problem can be solved in many ways, so if you have any ideas to improve, you can copy the code and play around.
A Hello World with a Bit More Immersion
Create a new project and a new HTML file. Copy and paste the code below to create the A-Frame Hello World scene.
<html >
<head >
<script src="https://aframe.io/releases/1.4.0/aframe.min.js"> </script >
</head >
<body >
<a-scene >
< a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"> </a-box >
<a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"> </a-sphere >
<a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"> </a-cylinder >
<a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"> </a-plane >
<a-sky color="#ECECEC"> </a-sky >
</a-scene >
< /body >
< /html >
Results:
Scene 1 - Hello World
Now let’s expand the main plane that represents the ground of the scene and change the colors of the sky and the ground. This will create a horizon from the camera's perspective. Since the intent is simple code, this scene will not allow user movements in the environment, including a custom camera component with some locks. If you want to try free movement do not include the <a-camera> tag, and you will be able to walk around freely and experience the created reality in a different way.
<a-plane position="0 0 -4" rotation="-90 0 0" width="500" height="400" color="#30503A"> </a-plane >
<a-sky color="#f5b56c"> </a-sky >
<a-camera wasd-controls-enabled="false" look-controls-enabled="false"> </a-camera >
The result after this first step:
< html >
< head >
< script src="https://aframe.io/releases/1.4.0/aframe.min.js"> < /script >
< /head >
< body >
< a-scene >
< a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"> < /a-box >
< a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"> < /a-sphere >
< a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"> < /a-cylinder >
< a-plane position="0 0 -4" rotation="-90 0 0" width="500" height="400" color="#30503A"> < /a-plane >
< a-sky color="#f5b56c"> < /a-sky >
< a-camera wasd-controls-enabled="false" look-controls-enabled="false"> < /a-camera >
< /a-scene >
< /body >
< /html >
Scene 2 – Adjusted sky and ground
The Sun Animation
To simulate the rising sun over the horizon, a cylinder of height 0, with 1 radian, rotated 90º on the Z axis will be used. By adding motion, the object will rise on the scene’s background until it reaches the sky and hides away from the camera view plane. To make this happen, create a <a-cylinder> as in the code:
< a-cylinder position="-20 -30 -50" rotation="90 0 0" radius="30" height="0" color="Yellow" > </a-cylinder>
Note that the object will be positioned a bit to the left of the view and at the end of our plane (<a-plane>), further away from the camera to give the horizon feeling. The circle needs to face the camera, so that's why the 90° rotation is on the X axes. To give a big sun effect at the beginning, add 30 radians in size.
For movement, add two animations to the <a-cylinder> tag attributes, as in the code:
< a-cylinder position="-20 -30 -50"
rotation="90 0 0"
radius="30"
height="0"
color="Yellow"
animation__1="property: position; to: -20 60 -50; dur: 10000; easing: linear; loop: true"
animation__2="property: radius; to: 1; dur: 10000; easing: linear; loop: true">
< /a-cylinder >
A-Frame accepts multiple animations in one object, for that you just need to insert the animation attribute in the desired tag. For each of them, it must have the character "_" to be differentiated, in the code, you can see it as a number but also could be a name. The animation basically works by providing which property the developer would like to change, the final value, and how long time it takes to reach the value.
Explaining each animation:
animation__1: It will treat the sun's movement from below the ground plane until above the sky, hiding from the scene. The loop value is true to don't have to refresh the page every time.
animation__1="property: position; to: -20 60 -50; dur: 10000; easing: linear; loop: true"
animation__2: It will take care of the sun shrinking as it gets higher in the sky. In this one, the idea is the same as in animation_1, but choosing the radius property.
animation__2="property: radius; to: 1; dur: 10000; easing: linear; loop: true"
The result after the second step:
< html >
< head >
< script src="https://aframe.io/releases/1.4.0/aframe.min.js"> < /script >
< /head >
< body >
< a-scene shadow="type: basic">
<!--objects-- >
< a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"> < /a-box >
< a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"> < /a-sphere >
< a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"> < /a-cylinder >
< a-plane position="0 0 -4" rotation="-90 0 0" width="500" height="100" color="#30503A"> < /a-plane >
< a-sky color="#f5b56c"> < /a-sky >
<!--sun-- >
< a-cylinder position="-20 -30 -50"
rotation="90 0 0"
radius="30"
height="0"
color="Yellow"
animation="property: position; to: -20 60 -50; dur: 10000; easing: linear; loop: true"
animation__2="property: radius; to: 1; dur: 10000; easing: linear; loop: true">
< /a-cylinder >
< a-camera wasd-controls-enabled="false" look-controls-enabled="false"> < /a-camera >
< /a-scene >
< /body >
< /html >
Scene 3 – Sun animation
Sky Effect
When the sun rises it changes the sky’s color from a black night tone to a lighter blue tone, right? To add this magical effect, some planes, colors, and a little more movement will be used.
Start by changing the sky's color and adding a plane under the horizon line with a <a-box> without depth on the Z axe and width up to the limits of the camera's plane of view on the X axe. Also, add an animation that will make this box rise with it behind the sun. The idea is the same as the sun animation in part 2, but using a giant plane that will cover the sky over time. Here's the code snippet:
< a-sky color="#000000"> < /a-sky >
...
< a-box position="0 -30 -65" rotation="0 0 0" width="500" height="100" color="#191970"
animation="property: position; to: 0 50 -60; dur: 10000; easing: linear; loop: true">
< /a-box >
Scene 4 – Basic sky effect
The sky effect has become a little more realistic, but it's still not good enough. To create a gradient effect at sunrise, add more boxes to this animation. There will be 4 planes starting in different positions and different colors. Feel free to play around with your example. The code with 4 looks like this:
< a-box position="0 -30 -65" rotation="0 0 0" width="500" height="100" color="#191970"
animation="property: position; to: 0 50 -60; dur: 10000; easing: linear; loop: true"> < /a-box >
< a-box position="0 -50 -60" rotation="0 0 0" width="500" height="100" color="#F49e12"
animation="property: position; to: 0 50 -60; dur: 10000; easing: linear; loop: true"> < /a-box >
< a-box position="0 -70 -55" rotation="0 0 0" width="500" height="100" color="#76b5c5"
animation="property: position; to: 0 50 -60; dur: 10000; easing: linear; loop: true"> < /a-box >
< a-box position="0 -85 -50" rotation="0 0 0" width="500" height="100" color="#cceef7"
animation="property: position; to: 0 50 -60; dur: 10000; easing: linear; loop: true"> < /a-box >
The result after the sky effect:
< html >
< head >
< script src="https://aframe.io/releases/1.4.0/aframe.min.js"> < /script >
< /head >
< body >
< a-scene shadow="type: basic">
<!--objects-- >
< a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"> < /a-box >
< a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"> < /a-sphere >
< a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"> < /a-cylinder>
< a-plane position="0 0 -4" rotation="-90 0 0" width="500" height="100" color="#30503A"> < /a-plane >
< a-sky color="#000000"> < /a-sky >
<!--sun-- >
< a-cylinder position="-20 -30 -50"
rotation="90 0 0"
radius="30"
height="0"
color="Yellow"
animation="property: position; to: -20 60 -50; dur: 10000; easing: linear; loop: true"
animation__2="property: radius; to: 1; dur: 10000; easing: linear; loop: true">
< /a-cylinder >
< a-box position="0 -30 -65" rotation="0 0 0" width="500" height="100" color="#191970"
animation="property: position; to: 0 50 -60; dur: 10000; easing: linear; loop: true"> < /a-box >
< a-box position="0 -50 -60" rotation="0 0 0" width="500" height="100" color="#F49e12"
animation="property: position; to: 0 50 -60; dur: 10000; easing: linear; loop: true"> < /a-box >
< a-box position="0 -70 -55" rotation="0 0 0" width="500" height="100" color="#76b5c5"
animation="property: position; to: 0 50 -60; dur: 10000; easing: linear; loop: true"> < /a-box >
< a-box position="0 -85 -50" rotation="0 0 0" width="500" height="100" color="#cceef7"
animation="property: position; to: 0 50 -60; dur: 10000; easing: linear; loop: true"> < /a-box >
< a-camera wasd-controls-enabled="false" look-controls-enabled="false"> < /a-camera>
< /a-scene >
< /body >
< /html >
Scene 5 – Sky effect
Changing the scene with the sunlight
To enhance the immersion experience of the scene, the sun needs to be the main source of light, and all objects must be impacted by this light source as it moves. To achieve this effect and finalize the example, include two directional lightings, one attached to the cylinder that represents the sun and one to improve the general visualization of the environment following the sun's rays’ movement.
Just add a point of light to the scene to simulate the sun and let's see the result. Include the <a-light> inside the <a-cylinder> to represent the sunbeam. This will make the light stick to the sun and allow it to liven up the whole set. Code:
...
<!--sun-- >
< a-cylinder position="-20 -30 -50"
rotation="90 0 0"
radius="30"
height="0"
color="Yellow"
animation="property: position; to: -20 60 -50; dur: 10000; easing: linear; loop: true"
animation__2="property: radius; to: 1; dur: 10000; easing: linear; loop: true">
< a-light color="#cf5f31" position="1 1 0" intensity="2"> < /a-light >
< a-cylinder >
...
Scene 6 – Adding lightning effects
It is noticeable that changing the light's place transformed the whole environment, but it is not the expected result. When the sunrises, the colors in the sky change, and the ray's reflections touch the environment in different ways, forming the image in the eyes. The solar rays reach the surfaces in the direction of the camera, reaching one of the objectives, however, it is still far from the desired reality, the beautiful image of the everyday dawn.
To solve the problem, simulate a back reflection, thus making it possible to see the sky and the sun, since the direction of the light attached to the sun is directed toward the Hello World objects. Add one more point of light, which will move following the sun but directed toward the horizon and positioned behind the camera, so it will be possible to illuminate what the sun's rays do not reach. Here's the code:
< a-entity position="0 -40 40" animation="property: position; to: 0 60 50; dur: 10000; easing: linear; loop: true">
< a-light color="white" position="0 0 0" intensity="1"> < /a-light >
< /a-entity >
After adding the last piece, the final code is:
< html >
< head >
< script src="https://aframe.io/releases/1.4.0/aframe.min.js"> < /script >
< script src="https://cdn.glitch.global/00e34433-af8d-4308-8b62-121406999043/moon.jpg?v=1685125883557"> < /script >
< /head >
< body >
< a-scene shadow="type: pfc">
<!--Helllo World objects-- >
< a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"> < /a-box >
< a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"> < /a-sphere >
< a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"> < /a-cylinder >
< a-plane position="0 0 -4" rotation="-90 0 0" width="500" height="100" color="#30503A"> < /a-plane >
<!--sun-- >
< a-cylinder position="-20 -30 -50"
rotation="90 0 0"
radius="30"
height="0"
color="Yellow"
animation="property: position; to: -20 60 -50; dur: 10000; easing: linear; loop: true"
animation__2="property: radius; to: 1; dur: 10000; easing: linear; loop: true">
< a-light color="#cf5f31" position="1 1 0" intensity="2"> < /a-light >
< /a-cylinder >
< a-entity position="0 -40 40" animation="property: position; to: 0 60 50; dur: 10000; easing: linear; loop: true">
< a-light color="white" position="0 0 0" intensity="1"> < /a-light >
< /a-entity >
< a-box position="0 -30 -65" rotation="0 0 0" width="500" height="100" color="#191970"
animation="property: position; to: 0 50 -60; dur: 10000; easing: linear; loop: true"> < /a-box >
< a-box position="0 -50 -60" rotation="0 0 0" width="500" height="100" color="#F49e12"
animation="property: position; to: 0 50 -60; dur: 10000; easing: linear; loop: true"> < /a-box >
< a-box position="0 -70 -55" rotation="0 0 0" width="500" height="100" color="#76b5c5"
animation="property: position; to: 0 50 -60; dur: 10000; easing: linear; loop: true"> < /a-box >
< a-box position="0 -85 -50" rotation="0 0 0" width="500" height="100" color="#cceef7"
animation="property: position; to: 0 50 -60; dur: 10000; easing: linear; loop: true"> < /a-box >
< a-sky color="#000000"> < /a-sky >
< a-camera wasd-controls-enabled="false" look-controls-enabled="false"> < /a-camera >
< /a-scene >
< /body >
< /html >
The result is presented below.
Scene 7 – simulating the sun rising in an immersive environment using A-Frame
Conclusion
After contextualizing the metaverse and introducing the A-Frame, a small example was built with a few lines of code allowing the creation of a complex virtual reality to be performed in computer graphics, without ready-made engines, and showing the ease of creating new content for the web in the third dimension, without deep mathematical knowledge. The demo is simple and unrefined in the eyes of the end user, who has probably already experienced super real games, however, it is worth noting that it is still highly complex to be accomplished even with the ease of game creation tools available on the market.
The Metaverse, despite being a distant reality from the public due for various reasons, is a tangible technology being experimented with, and plausible to build. It offers accessible tools to content creators, an essential part of its system maintenance. A-Frame comes to help, providing computer graphics novices with a powerful set of components, and endless possibilities for expansion and improvements. It also allows developers who have knowledge in web development, to create new experiences for users, with little code and a small learning curve. Of course, much still needs to be done, but the seeds have already been planted for that to happen.
Acknowledgment
This piece was written by Breno Mattos de Paula, Software Developer at Encora. Thanks to Flávia Negrão and João Caleffi for reviews and insights.
About Encora
Fast-growing tech companies partner with Encora to outsource product development and drive growth. Contact us to learn more about our software engineering capabilities.