You can think of Aframe as a way to describe scenes in 3D in a way that it makes it easy to make VR for the web.
When you use aframe, you are also using the powerful THREE engine under it. So if aframe doesn't give you what you need, and you feel confident of your javascript kung fu, you can always use THREE calls to build your worlds.
This is the minimum bit of html markup that you need to get an aframe
scene.
<html>
<head>
<script src="https://unpkg.com/aframe@latest"></script>
</head>
<body>
<a-scene vr-mode-ui="enabled: false">
</a-scene>
</body>
</html>
Let's go to the glitch repository to see what's going on there.
Let's add a red box.
<a-box color="red" position="0 0 -4"></a-box>
Our camera (or point of view) is automatically added on the (0, 0, 0)
position in space. So if we want to place something in front of the camera, we need a negative Z coordinate.
Everything you add to an aframe scene is an entity, anything from a video stream, a VR controller or a 3D object can all be considered entities in aframe. Another way of including a box in the scene, that would use pure entity markup would be:
<a-entity geometry="primitive: box;" material="color: green;" position="-10 2 -3"></a-entity>
For most primitives however, aframe has shortcut names such as a-box
, a-sphere
, a-plane
, etc. But ultimately everything is an entity and you can specify everything as an entity. Shortcuts are useful for convenience and making the markup readable.
Let's make some more shapes.
<a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E" shadow></a-sphere>
<a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D" shadow></a-cylinder>
Aframe makes it easy to inspect how a scene is constructed if you invoke the Visual Inspector using CTRL+ALT+i. Try it now, on any browser window with an aframe scene.
Let's add some text.
<a-text
value="Hello, World!"
position="0 -2 0"
color="red"
align="center">
Let's make it bigger, let's give it a width of 25.
Aframe feels like html. You can also use normal DOM manipulation operations, like inserting elements, changing parameters and adding interactivity using javascript. Let's make some more objects.
Before the end of your body insert a <script>
tag and try this javascript.
<script>
stijl = ['red', 'yellow', 'blue', 'white', 'black']
stijl.forEach((color) => {
console.log(color)
var el = document.createElement('a-box')
document.querySelector('a-scene').appendChild(el)
let y = 6*Math.random()
let z = -1*20*Math.random()
el.setAttribute('position', `0 ${y} ${z}`) // "0 "+ y.toString() +" "+ z.toString() )
el.setAttribute('color', color)
})
</script>
You can use regular javascript DOM operations like createElement
and appendChild
to dynamicaly change your scene.
Let's add a sky.
<a-sky color="lightblue"></a-sky>
Let's use a picture for our sky. The picture is a sphere map that I found in wikipedia, if you search for sphere map or sky map on google, you will find these kinds of images easily. You can always make your own, there are tools to make skymaps.
<a-sky src="https://upload.wikimedia.org/wikipedia/commons/5/5b/Lake_Byllesby_Regional_Park_-_360%C2%B0_Equirectangular_Street_View_Photo_%2827332591527%29.jpg" color="#CCC"></a-sky>
Let's lay a floor on our feet.
<a-plane src="https://cdn.aframe.io/a-painter/images/floor.jpg" rotation="-90 0 0" width="30" height="30"></a-plane>
Let's now add a moving object. In this object we specify a simple animation as attributes in our entity tag.
<a-cylinder color="orange" radius="0.1"
animation="property: position; dir: alternate; dur: 2000;
easing: easeInSine; loop: true; from: 0 2 -5; to: 0 3 -5;"></a-cylinder>
<a-camera look-controls wasd-controls="acceleration:100" position="0 1.6 0"></a-camera>
<a-assets>
<video
id="bunny"
src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
autoplay
loop
preload
muted
crossorigin="anonymous"
></video>
</a-assets>
<a-video src="#bunny" position="0 0 -3"></a-video>
You can create models in your favorite 3D software and export them to glTF or FBX.
You will need to include two new scripts in your header, like this, to enable you to load your 3D models.
<script src="//cdn.rawgit.com/donmccurdy/aframe-extras/v4.2.0/dist/aframe-extras.min.js"></script>
<script src="https://unpkg.com/three@0.95.0/examples/js/libs/inflate.min.js"></script>
Then you can include your model as an entity in your scene.
<a-entity animation-mixer="clip: *;"
scale="0.005 0.005 0.005"
position="0 0 -2"
fbx-model="src: url(https://cdn.glitch.com/c9111e7d-1d31-41a0-8e15-78b57caa9816%2Fcapoeira.fbx?v=1569744713752);"></a-entity>
Loading glTF models.
<a-scene>
<a-assets>
<a-asset-item id="tree" src="/path/to/tree.gltf"></a-asset-item>
</a-assets>
<a-entity gltf-model="#tree"></a-entity>
</a-scene>
Let's make a small scene that fetches content from the department's website.
This example is a bit more complex, but it's worth it. Have a look at this glitch repository
If you use a lot of external resources, such as images, sounds, etc. from other sites, you will sooner or later encounter, CORS-related problems.
CORS is tricky and it will make your life painful. To bypass this constraint you can use something called a CORS-proxy. Which is a way for one webserver to fetch content from a second webserver and give it back to our web application as if it was coming from the first webserver. This bypassess CORS controls in the browser and let's us use the materials we need.
At the time of this writing, this CORS proxy was working really well.
https://cors-anywhere.herokuapp.com/
If you want to fetch an image located in another site, like for example:
https://designarttechnology.nl/content/images/2020/05/krekel008.jpg
But you get cross origin errors in your browser's console, you will probably need to fetch that image through the CORS proxy. By changing the address like this:
https://cors-anywhere.herokuapp.com/https://designarttechnology.nl/content/images/2020/05/krekel008.jpg
This bit left as an exercise for the reader. ;)