A-Frame 101 — How to Learn it
by Filipa Cruz - 2 August 2017
[#product-development](/content/blog/tag/product-development/ "product-development"/index.html)
First of all, for those unfamiliar with A-Frame, it’s a WebMR framework that combines HTML and Js and allows you to create indescribable experiences.
I’ve been learning it for the past months so I decided it was time to share my knowledge with you, by providing a list of examples and practice exercises with a lot of comments and explanations.
When I explain the logics behind how a certain exercise works, I’ll have a Codepen i-frame where you can view the code, and the result. I advise you to tweak it and discover on your own. However, A-Frame also has a very cool built in inspector in which you can “peak under the hood” of things. To trigger it just press Ctrl + Alt + I, while inside any website using A-Frame.
The links below are extra reading material, to accompany you throughout this blogpost. A-Frame school and the documentation section of the website will give you a very good ground to begin with.
Disclaimer: Open the drop downs to read the section you wish. Inside, in order for the codepens to run please click on them to load and use a recent version of Google Chrome. Also, there’s an AR example at the end of the blogpost, so you will need to have the web cam access turned on.
Basics
So, how should we start? The core elements of A-Frame are the sky, basic geometric shapes, and lights. With only these three elements we can do a lot of interesting things.
Important piece of advice: Read all the comments on the code, they are NOT repeated and sometimes will teach you stuff to prevent common errors or a bit more about the code.
Background
SKY
The sky is basically a huge spphere in which you use an image as a texture that ends up serving as your background. You can use 360º images or plain colours for your sky.
CodePen Embed - Ex.1— A-Frame Sky
<html>
<head>
<title> A-Frame Sky</title>
<!-- --------- IMPORTED LIBRARIES ------>
<script src="https://aframe.io/releases/0.6.0/aframe.min.js"></script>
</head>
<body>
<a-scene>
<!-- Creating scene -->
<!-- --------- ASSETS --------- -->
<!-- Asset links. -->
<a-assets>
<img id="background_inside_house" crossorigin="anonymous" src="https://cdn.glitch.com/e6225ccd-c32e-4cf8-b039-e78814a8cb78%2Fbg-3.jpg?1498128817274">
</a-assets>
<!-- --------- SKY --------- -->
<!--The sky is the horizon and surronding enviroment if u don't create a ground
It can be a color or an image. Usually it's a 360 equirectangular image
Since you can only have 1 sky at a time, to see the other possibilities, comment the sky bellow and uncomment one of the others.
For goof and free 360º images, visit: https://www.flickr.com/search/?text=equirectangular&license=4%2C5%2C9%2C10
Sky documentation: https://aframe.io/docs/0.6.0/primitives/a-sky.html-->
<a-sky id="background-img" src="#background_inside_house"></a-sky>
<!-- If you insert both options the sky will have a color filter
The radius attribute will make the image trippy, a curious finding by A-Frame contributor Cwervo-->
<!-- <a-sky id="background-img" src="#background_inside_house" color="red" radius=10 ></a-sky> -->
<!-- If you insert only color and no src, the sky will be the chosen color -->
<!-- <a-sky id="background-img" color="red" ></a-sky> -->
</a-scene>
<!-- Closing scene -->
</body>
</html>
This Pen is owned by Filipa Cruz on CodePen.
See more by @cr0ssing on CodePen
External CSS
This Pen doesn't use any external CSS resources.
External JavaScript
This Pen doesn't use any external JavaScript resources.
After looking at the code you might have noticed the tag. This serves the purpose of creating the scene. By creating this tag, you tell the HTML that you will write VR related code in here This is like the body for A-Frame code.
VIDEOSPHERE SKY
In case you were wondering, yes it IS possible to have a video as your background. However, it's not called a sky entity. It's a videosphere.
CodePen Embed - Ex.1.1 — A Videosphere
<html>
<head>
<title> Ex.1.1 — A Video "Sky"</title>
<!-- --------- IMPORTED LIBRARIES ------>
<script src="https://aframe.io/releases/0.6.0/aframe.min.js"></script>
</head>
<body>
<a-scene>
<!-- Creating scene -->
<!-- --------- ASSETS --------- -->
<!-- Asset links. -->
<a-assets>
<video id="video" src="https://ucarecdn.com/fadab25d-0b3a-45f7-8ef5-85318e92a261/" autoplay loop crossorigin="anonymous"></video>
</a-assets>
<a-videosphere src="#video" rotation="0 80 0"></a-videosphere>
<!--This is the tag for a video sky, videosphere
If you play with the video rotation, you can give the user a new perspective
Even without moving around-->
</a-scene>
<!-- Closing scene -->
</body>
</html>
This Pen is owned by Filipa Cruz on CodePen.
See more by @cr0ssing on CodePen
External CSS
This Pen doesn't use any external CSS resources.
External JavaScript
This Pen doesn't use any external JavaScript resources.
Another aspect that might have caused you some confusion is how I'm inserting the source in the tags. A-Frame has a cool and more organised way of storing assets (images, videos, etc). If you store all of that inside a tag, you can give it an id and then call it by that id on some other element's source, instead of having a huge link in the middle of the important code.
tl;dr By storing all assets in the a-assets tag, you are creating a cleaner, easier to read and maintain code.
CHANGING SKY
If you're interested in changing the source of your sky while using the website, you'll have to use Javascript, select the source and change to the new source.
In any case, you need this to be triggered by something, like hovering a target or clicking it. Since most MR users don't own a headset, you need to be able to trigger events with gaze. This just means the cursor will be visible and the user needs to place the cursor for a determined amount of time over it to trigger an event.
CodePen Embed - Ex.1.2 — Change Sky
<html>
<head>
<title> Changing Sky Source</title>
<!-- --------- IMPORTED LIBRARIES ------>
<script src="https://aframe.io/releases/0.6.0/aframe.min.js"></script>
</head>
<body>
<a-scene> <!-- Creating scene -->
<!-- --------- ASSETS --------- -->
<!-- Asset links. -->
<a-assets>
<img id="background_inside_house" crossorigin="anonymous" src="https://cdn.glitch.com/e6225ccd-c32e-4cf8-b039-e78814a8cb78%2Fbg-3.jpg?1498128817274">
<img id="chinese_temple" crossorigin="anonymous" src="https://cdn.glitch.com/e6225ccd-c32e-4cf8-b039-e78814a8cb78%2Fbg-1.jpg?1498129063299">
</a-assets>
<!-- --------- SKY --------- -->
<a-sky id="background-img" src="#background_inside_house" theta-length="130"></a-sky>
<!--
You can use the keys W,A,S,D to move around
But for that you need to change Theta length (cylinder radius)
This will create a "hole" in the floor of the image -->
<a-plane id="btn_trigger" position="3 3 -9" height="2" width="5" rotation="0 0 0" color="#e21d2d">
<!-- a-plane is like a rectangle.
I use them as buttons only to keep some of the usual UI conventions. Even though you are on a new medium, if you want users to understand your applocation/website you need to use some of the expected norms and rules of UI/UX
The a-plane tag has a lot of possibilities in terms of properties, check them out here https://aframe.io/docs/0.6.0/primitives/a-plane.html-->
<a-text value="Trip to China" position="0 0 0" scale="2 2 2" align="center" ></a-text> <!--Since this is inside the plane, the text position is relative to the plain's position
If you use the property align wisely, you don't need to experiment with position
Text documentation: https://aframe.io/docs/0.6.0/primitives/a-text.html-->
</a-plane>
<!-- --------- CAMERA AND CURSOR --------- -->
<a-camera look-controls-enabled wasd-controls-enabled position="0 1 4">
<!--Enabling gaze controls = look-controls-enabled
Enabling key control= wasd-controls-enabled
You can use the keys W,A,S,D to move around-->
<a-cursor position="0 0 -3"
geometry="primitive: ring; radiusOuter: 0.030; radiusInner: 0.020;"
material="color: #11d8c4; shader: flat"
fuse="true" timeout="10"> <!--Giving our cursor properties-->
<!--The timeout defines how long it'll take to trigger something on fuse-->
<a-animation begin="click" easing="ease-in" attribute="color"
fill="backwards" from="#11d8c4" to="#ffffff"></a-animation> <!--Animating the cursor while you click-->
<a-animation begin="cursor-hovering" easing="ease-in" attribute="scale"
fill="forwards" from="1 1 1" to="0.5 0.5 0.5"></a-animation> <!--Animating the cursor while you hover-->
</a-cursor> <!--These animations serve for the purposes of debugging and better UX
If there is something you want to be followed by the cursor, draw it below-->
</a-camera>
</a-scene>
<!-- Closing scene -->
</body>
</html>
<!-- --------- JAVASCRIPT --------- -->
//-- --------- CHANGE BG ON BUTTON HOVER JS ---------
function ChangeBackground() { //Using full JS in order to keep the code tidy and understandable
//Jquery is good as well, but I have a tendency to mix it with Js, so that creates a few errors
var trigger = document.getElementById("btn_trigger"); // <a-plane id="btn_trigger">
var sky = document.getElementById("background-img"); // <a-sky id="background-img">
trigger.addEventListener('mouseenter', function () {//open event listener
//here we change the sky src IF the mouse has entered the plane with the id btn_trigger
sky.setAttribute('src','#chinese_temple');
}); // Close event listener
trigger.addEventListener('mouseleave', function () { //open event listener
//here we change the sky src back to the original image once mouse has left the plane with the id btn_trigger
//in case you don't want to change back to the original image, just remove the whole mouseleave event
sky.setAttribute('src','#background_inside_house');
}); // Close event listener
}//Close function
ChangeBackground(); //calling the function
This Pen is owned by Filipa Cruz on CodePen.
See more by @cr0ssing on CodePen
External CSS
This Pen doesn't use any external CSS resources.
External JavaScript
This Pen doesn't use any external JavaScript resources.
In order to create your own 360 images for the sky, you can use a 360 camera or make an equirectangular image in blender. For the second option, follow this tutorial by Jared Pike.
If in the end of creating your 360 image you become really proud of it and want to share it with the world, check this tutorial by Andres Cuervo on how to use A-frame images for facebook 360.
Geometry
If you are venturing into MR, you'll probably want to know how to use 3D shapes in your favour for your many projects.
POSITION
One of the points in A-Frame that might cause people some confusion is Axis Orientation. A-frame is Y-up but for example, unreal is Z-up, math/physics is Z-up, so take this into consideration when creating/positioning elements.
The easier way for me to understand it was (x,y,z)=(width,height,depth).
CodePen Embed - Ex.2 — Geometry
<html>
<head>
<title> Geometry</title>
<!-- --------- IMPORTED LIBRARIES ------>
<script src="https://aframe.io/releases/0.6.0/aframe.min.js"></script>
</head>
<body>
<a-scene> <!-- Creating scene -->
<!-- --------- SKY --------- -->
<a-sky id="background-img" color="#EBEBEB"></a-sky>
<!-- --------- GROUND --------- -->
<a-plane id="ground" color="#000000" position="0 0 0" rotation="-90 0 0" width="10" lenght="10"></a-plane>
<!-- --------- SHAPES --------- -->
<!-- There's a few more of shapes you can use.
I'll leave it here with the respective dodumentation links for you to check out:
<a-circle> : https://aframe.io/docs/0.6.0/primitives/a-circle.html
<a-triangle> : https://aframe.io/docs/0.6.0/primitives/a-triangle.html
<a-torus>:
https://aframe.io/docs/0.6.0/primitives/a-torus.html
<a-torus-knot>: https://aframe.io/docs/0.6.0/primitives/a-torus-knot.html
-->
<a-cylinder position="0 0.75 -0.25" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
<!--Since I want this to stand on top of the plane, I'll add half it's height to the plane height on the y axis of the position property
I wrote -0.25 on the z axis so I would move the cylinder a little further in the plane-->
<a-box position="-1 0.5 0.5" depth="0.5" height="0.5" width="0.5" color="#FFF65D"></a-box>
<a-cone position="1 0.5 0" color="tomato" radius-bottom="0.5" radius-top="0"></a-cone>
<!--If the radius top is other than 0, you'll have a cone top cut by a plane, if it's 0 is a regular cone -->
<a-dodecahedron position="2 0.25 0" color="#FF9FFF" radius="0.5"></a-dodecahedron>
<a-octahedron position="-2.5 0.25 0" color="#FF926B" radius="0.45"></a-octahedron>
<a-ring position="-3.7 0.7 0" color="teal" radius-inner="0.25" radius-outer="0.7"></a-ring>
<!--The position on the y axis of the ring is determined according to the bottom which is why the outer radius and y position have the same value
The same happens with the sphere-->
<a-sphere position="3.7 0.5 0"color="blue" radius="0.5"></a-sphere>
<!-- --------- CAMERA AND CURSOR --------- -->
<a-camera look-controls-enabled wasd-controls-enabled position="0 0 3">
<!--The camera is a bit far from position 0 0 0 so you can view the full picture -->
<a-cursor position="0 0 -3"
geometry="primitive: ring; radiusOuter: 0.030; radiusInner: 0.020;"
material="color: #11d8c4; shader: flat"
fuse="true" timeout="10">
</a-cursor>
</a-camera>
</a-scene>
<!-- Closing scene -->
</body>
</html>
This Pen is owned by Filipa Cruz on CodePen.
See more by @cr0ssing on CodePen
External CSS
This Pen doesn't use any external CSS resources.
External JavaScript
This Pen doesn't use any external JavaScript resources.
TEXTURE
To make the shapes more lifelike, you can add textures and play a bit with them by multiplying shape and texture colours, repeat textures, and much more.
CodePen Embed - Ex2.1 — Texture on Shape
<html>
<head>
<title> Textures</title>
<!-- --------- IMPORTED LIBRARIES ------>
<script src="https://aframe.io/releases/0.6.0/aframe.min.js"></script>
</head>
<body>
<a-scene> <!-- Creating scene -->
<a-assets>
<img id="sand" crossorigin="anonymous" src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcT8yk8DfEK3_p00rFA6v0HmoRRBUnofgIJkIe5ABarDJqJF3V3_">
<img id="glass" crossorigin="anonymous" src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTXhbpfWPwlvkCP7xAgq00gumbFRQ6q-eUNH4a9LUrIXs--J7ac">
<img id="rust" crossorigin="anonymous" src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSeeEo19vWWDeLx2o9a0ypIUv4qvpDAWcRa_AAo3UI2-nF_2Nus">
<img id="leaves" crossorigin="anonymous" src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTFECvldc9ayjqk6jZUFhHyLyhNJFXlp9Y7Fb6EuqTjw5BJE5J8KQ">
<img id="mix" crossorigin="anonymous" src="https://us.v-cdn.net/5021068/uploads/editor/f0/6kymf4lg6ium.jpg">
</a-assets>
<!-- --------- SKY --------- -->
<a-sky id="background-img" color="#EBEBEB"></a-sky>
<!-- --------- GROUND --------- -->
<a-plane id="ground" color="#000000" position="0 0 0" rotation="-90 0 0" width="10" lenght="10"></a-plane>
<!-- --------- SHAPES --------- -->
<!-- By adding an image as src, the image becomes the shape's texture -->
<a-cylinder position="0 0.75 -0.25" radius="0.5" height="1.5" color="#FFC65D" src="#sand" material=" repeat:5 3"></a-cylinder>
<!-- By using the repeat instance of the material property you are able to repeat the texture as many times you want in the x and the y axis
For further info on materials, check: https://aframe.io/docs/master/components/material.html -->
<a-box position="-1 0.5 0.5" depth="0.5" height="0.5" width="0.5" color="#FFF65D" src="#glass"></a-box>
<!--If the shape has color and texture, the color will be like a filter to the image, the color will multiply -->
<a-cone position="1 0.5 0" radius-bottom="0.5" radius-top="0" src="#rust"></a-cone>
<a-ring position="-3.7 0.7 0" color="teal" radius-inner="0.25" radius-outer="0.7" src="#rust"></a-ring>
<a-dodecahedron position="2 0.25 0" color="#FF9FFF" radius="0.5" src="#leaves"></a-dodecahedron>
<a-octahedron position="-2.5 0.25 0" src="#mix" radius="0.45"></a-octahedron>
<a-sphere position="3.7 0.5 0"color="blue" radius="0.5" src="#mix"></a-sphere>
<!-- --------- CAMERA AND CURSOR --------- -->
<a-camera look-controls-enabled wasd-controls-enabled position="0 0 3">
<!--The camera is a bit far from position 0 0 0 so you can view the full picture -->
</a-camera>
</a-scene>
<!-- Closing scene -->
</body>
</html>
This Pen is owned by Filipa Cruz on CodePen.
See more by @cr0ssing on CodePen
External CSS
This Pen doesn't use any external CSS resources.
External JavaScript
This Pen doesn't use any external JavaScript resources.
ENTITIES
A-frame works as an entity component system. If you want to get to the bottom of what that is, and how it works, check this link.
Bearing in mind the knowledge from the link above, most shapes can be declared as their usual tag or an tag.
CodePen Embed - Ex.2.2— Shape as Entity
<html>
<head>
<title> Geometry as Entity</title>
<!-- --------- IMPORTED LIBRARIES ------>
<script src="https://aframe.io/releases/0.6.0/aframe.min.js"></script>
</head>
<body>
<a-scene> <!-- Creating scene -->
<a-assets>
<img id="rust" crossorigin="anonymous" src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSeeEo19vWWDeLx2o9a0ypIUv4qvpDAWcRa_AAo3UI2-nF_2Nus">
</a-assets>
<!-- --------- SKY --------- -->
<a-sky id="background-img" color="#EBEBEB"></a-sky>
<!-- --------- GROUND --------- -->
<a-plane id="ground" color="#000000" position="0 0 0" rotation="-90 0 0" width="10" lenght="10"></a-plane>
<!-- --------- SHAPES --------- -->
<a-ring position="-1 0.7 0" color="teal" radius-inner="0.25" radius-outer="0.7" src="#rust"></a-ring>
<a-entity position="1 0.7 0" material="color:navy; transparency:true; opacity:0.7" geometry="primitive: ring; radiusOuter: 0.7; radiusInner: 0.25;" position="-1 0.7 0" src="#rust"></a-entity>
<!-- Creating an entity can be a bit more confusing that just using the regular tag.
I really advise you to read the documentation or keep it open while you use this tag
https://aframe.io/docs/master/core/entity.html-->
<!-- --------- CAMERA AND CURSOR --------- -->
<a-camera look-controls-enabled wasd-controls-enabled position="0 0 3">
<!--The camera is a bit far from position 0 0 0 so you can view the full picture -->
</a-camera>
</a-scene>
<!-- Closing scene -->
</body>
</html>
This Pen is owned by Filipa Cruz on CodePen.
See more by @cr0ssing on CodePen
External CSS
This Pen doesn't use any external CSS resources.
External JavaScript
This Pen doesn't use any external JavaScript resources.
ANIMATIONS
Another step to create interesting environments with shapes it's to animate them! Technically you've already seen animations, regarding the gaze cursor. But now I'll take the time to explain them a little bit better.
CodePen Embed - Ex.2.3 — Animating Shapes
<html>
<head>
<title> Animating Shapes</title>
<!-- --------- IMPORTED LIBRARIES ------>
<script src="https://aframe.io/releases/0.6.0/aframe.min.js"></script>
</head>
<body>
<a-scene>
<!-- Creating scene -->
<!-- --------- SKY --------- -->
<a-sky id="background-img" color="#EBEBEB"></a-sky>
<!-- --------- GROUND --------- -->
<a-plane id="ground" color="#000000" position="0 0 0" rotation="-90 0 0" width="10" lenght="10"></a-plane>
<!-- --------- SHAPES --------- -->
<a-entity position="1 0.7 0" material="color:navy; transparency:true; opacity:0.7" geometry="primitive: ring; radiusOuter: 0.7; radiusInner: 0.25;" position="-1 0.7 0">
<a-animation attribute="position" from="0 0.5 -3" to="0 3 -2" direction="alternate" repeat="indefinite"></a-animation>
<!--By making the animation a child of the shape you make sure this is the element afect by it.
You choose an attribute to animate and "say" how does the animation start (from) and how it ends (to)
By making the direction alternate, you make sure it dgoes back and forth, and making repetition indefinite is the same thing as saying it's on loop
This is the most common way to create an animation-->
</a-entity>
<a-ring position="-1 0.7 0" color="teal" radius-inner="0.25" radius-outer="0.7">
<a-animation attribute="material.opacity" from="0" to="0.5" direction="alternate" repeat="3"></a-animation>
<!--This will happen only 3 times, and then the ring will disappear because the from (initial) state is opacity=0 -->
</a-ring>
<!--Since there are some properties that belong to components, you sometimes have to call componentName.property
animation documentation: https://aframe.io/docs/master/core/animations.html
-->
<a-box position="2 0.7 0" color="tomato" depth="1" height="1" width="1">
<a-animation attribute="rotation" from="0 0 0" to="360 180 0" dur="2000" direction="alternate" begin="mouseenter" end="mouseleave "repeat="10"></a-animation>
<!--
Duration and delay are two other properties of the animation that can help you create a more complex one
You can have animations triggered by events and stopped by events as well
Place gaze cursor on box to begin animation, and leave the box to stop it -->
</a-box>
<!-- --------- CAMERA AND CURSOR --------- -->
<a-camera look-controls-enabled wasd-controls-enabled position="0 0 3">
</a-camera>
</a-scene>
<!-- Closing scene -->
</body>
</html>
This Pen is owned by Filipa Cruz on CodePen.
See more by @cr0ssing on CodePen
External CSS
This Pen doesn't use any external CSS resources.
External JavaScript
This Pen doesn't use any external JavaScript resources.
Components
Since A-Frame is OpenSource, there are some components created by the community which is extremely useful because they present new possibilities which are not included in the core features.
The ones I found most interesting regarding shapes where the Curve Component, the Along Path Component , and the Tube Along a Path Component (which is included in a series of A-frame extras). Check the code bellow to see these components in action!
CodePen Embed - Ex.2.4— Animating Shapes with Components
<html>
<head>
<title> Animating Shapes with components</title>
<!-- --------- IMPORTED LIBRARIES ------>
<script src="https://aframe.io/releases/0.6.0/aframe.min.js"></script>
<script src="https://unpkg.com/aframe-curve-component/dist/aframe-curve-component.min.js"></script>
<script src="https://unpkg.com/aframe-alongpath-component/dist/aframe-alongpath-component.min.js"></script>
<!-- Curve and walk along path components -->
<script src="//cdn.rawgit.com/donmccurdy/aframe-extras/v3.8.6/dist/aframe-extras.min.js"></script>
<!-- Extras component by Don Mccurdy (used for tube along path)-->
</head>
<body>
<a-scene>
<!-- Creating scene -->
<!-- --------- SKY --------- -->
<a-sky id="background-img" color="#EBEBEB"></a-sky>
<!-- --------- STRANGE CURVE --------- -->
<a-curve id="track1" closed="true" type="QuadraticBezier" >
<!--In here you create each one of the points that make up the cruve
By using closed=true you determine that the first and last point will join-->
<a-curve-point position="0 1 -2" ></a-curve-point>
<a-curve-point position="-1 2 -2" ></a-curve-point>
<a-curve-point position="-2 1 -2" ></a-curve-point>
<a-curve-point position="-1 0 -2"></a-curve-point>
<a-curve-point position="0 1 -2" ></a-curve-point>
</a-curve>
<a-draw-curve curveref="#track1" material="color: blue; opacity:0.3"></a-draw-curve>
<!-- After chooding the points, here you draw the junction of all those points
If you set the material opacity to 0 you don't see the curve -->
<!-- --------- RANDOM CURVE --------- -->
<a-curve id="Random" closed="false" type="QuadraticBezier" >
<a-curve-point position="1.75 0 -2" ></a-curve-point>
<a-curve-point position="-1.35 1.47 -2" ></a-curve-point>
<a-curve-point position="-2 0 -2" ></a-curve-point>
<a-curve-point position="-1.35 -1.47 -2" ></a-curve-point>
<a-curve-point position="0 0 -2" ></a-curve-point>
<a-curve-point position="1.75 0 -2"></a-curve-point>
</a-curve>
<a-draw-curve curveref="#Random" material="color: blue; opacity:0.5"></a-draw-curve>
<!-- --------- CREATE TUBE ALONG PATH AND MAKE IT MOVE ALONG ANOTHER PATH ------ -->
<a-tube path="0 0 -2, -0.5 0 -2" radius="0.25" material="color: red" alongpath="curve:#Random; dur: 2000; loop: true; rotate:true;"></a-tube>
<!--This code belongs to another component, the Tube Along Path, which pretty much allows you to create a tube that goes through several points you write down on the path attribute
Combining that with the Along Path component, I make the tube walk along the path I called Random.
Since the rotate attribute of the alongpath component is true, it won't rotate from the tube center, but the tube will rotate around the path
-->
<!-- --------- SPHERES ALONG PATH --------- -->
<a-sphere radius="0.05" position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9" alongpath="curve:#track1; dur: 2000; loop: true"></a-sphere>
<a-sphere radius="0.05" position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9" alongpath="curve:#track1; dur: 1950; loop: true"></a-sphere>
<a-sphere radius="0.05" position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9" alongpath="curve:#track1; dur: 1900; loop: true"></a-sphere>
<a-sphere radius="0.05" position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9" alongpath="curve:#track1; dur: 1850; loop: true"></a-sphere>
<a-sphere radius="0.05" position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9" alongpath="curve:#track1; dur: 1800; loop: true"></a-sphere>
<a-sphere radius="0.05" position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9" alongpath="curve:#track1; dur: 1750; loop: true"></a-sphere>
<a-sphere radius="0.05" position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9" alongpath="curve:#track1; dur: 1700; loop: true"></a-sphere>
<a-sphere radius="0.05" position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9" alongpath="curve:#track1; dur: 1650; loop: true"></a-sphere>
<!-- By drawing several spheres and changing the time they take to go through the path, I create a sort of loader effect-->
<!-- --------- CAMERA AND CURSOR --------- -->
<a-camera look-controls-enabled wasd-controls-enabled position="0 0 2">
</a-camera>
</a-scene>
<!-- Closing scene -->
</body>
</html>
Ex.2.4— Animating Shapes with Components Animating Shapes with components
Exit VR
This Pen is owned by Filipa Cruz on CodePen.
See more by @cr0ssing on CodePen
External CSS
This Pen doesn't use any external CSS resources.
External JavaScript
This Pen doesn't use any external JavaScript resources.
In case you are interested in checking out more components, there's this website called A-Frame Registry where you'll find a bunch of them.
CREATING A COMPONENT
Fell like none of the existing components do what you wish? In this tutorial by Ngokevin, you can check every step to making your own.
OCEAN COMPONENT
The ocean component is also one of my favourites. It's quite simple, but it works rather well.
CodePen Embed - Ex.2.5 — Ocean Component
<html>
<head>
<title> Ocean</title>
<!-- --------- IMPORTED LIBRARIES ------>
<script src="https://aframe.io/releases/0.6.0/aframe.min.js"></script>
<script src="https://unpkg.com/aframe-extras.ocean@%5E3.5.x/dist/aframe-extras.ocean.min.js"></script>
<!--To use a component you need to load it's code from the server -->
</head>
<body>
<a-scene>
<!-- --------- SKY --------- -->
<a-sky id="background-img" color="#ABABAB"></a-sky>
<a-entity id="ocean" position="0 -2 0" ocean="density: 50; width: 50; depth: 50; speed: 7" material="color: #9CE3F9; opacity: 0.75; metalness: 0; roughness: 1" rotation="-90 0 0"></a-entity>
<!--
The ocean only has the following properties so far: density, width, depth and speed.
-->
</a-scene>
</body>
</html>
This Pen is owned by Filipa Cruz on CodePen.
See more by @cr0ssing on CodePen
External CSS
This Pen doesn't use any external CSS resources.
External JavaScript
This Pen doesn't use any external JavaScript resources.
OTHER COOL COMPONENTS
This component by Mayognaise makes your mouse behave entire like cursor
Ever wanted to use a gif as a texture? Now you can, with the Gif Shader Component by Mayognaise.
In case you want to dive into the more realistic world, here is a pretty good physics component by NgoKevin.
If you're aiming for multi-user experiences, Ngokevin created a Firebase component with all the needed docs and explanations for you to succeed!
For the music enthusiasts out there, there is also a component that analyses audio and animates shapes accordingly by NgoKevin.
Last, but not least, an amazing Mirror component by Alfredo.
Lights
LIGHT TYPES
Lights make your models look more realistic or allow you to create the right mood for your environment. For example, if you want a night scene you can't have a very strong yellow light right? Check the next pen to learn more!
CodePen Embed - Ex.3 — Lights
<html>
<head>
<title> Lights</title>
<!-- --------- IMPORTED LIBRARIES ------>
<script src="https://aframe.io/releases/0.6.0/aframe.min.js"></script>
</head>
<body>
<a-scene> <!-- Creating scene -->
<!-- --------- SKY --------- -->
<a-sky id="background-img" color="#EBEBEB"></a-sky>
<!-- --------- LIGHTS --------- -->
<a-entity id="lightSphere" geometry="primitive:sphere; radius: 0.25" position="0 1.5 -2" rotation="0 45 0" material="color:#FFE65F; shader:flat" light="type:point"></a-entity>
<!-- This is a yellow light behind the shapes
It's a point light -->
<!-- <a-light type="ambient" position="0 -0.5 5" color="purple" intensity="0.6"></a-light>
<!-- This directional light has a low intensity, the max intensity is 1
In order to visualize better the effects of the lights, just use one at a time -->
<!-- <a-light position="0 0 1" color="pink" target="#sphere" ></a-light>
<!--If you don't define a light type, the default is directional. The intensity is also 1 by default
By assigning a target, you rotate the light towards the chosen target-->
<!-- --------- GROUND --------- -->
<a-plane id="ground" color="#000000" position="0 0 0" rotation="-90 0 0" width="10" lenght="10"></a-plane>
<!-- --------- SHAPES --------- -->
<a-cylinder position="0 0.75 -0.25" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
<a-box position="-1 0.5 0.5" depth="0.5" height="0.5" width="0.5" color="#FFF65D"></a-box>
<a-cone position="1 0.5 0" color="tomato" radius-bottom="0.5" radius-top="0"></a-cone>
<a-dodecahedron position="2 0.25 0" color="#FF9FFF" radius="0.5"></a-dodecahedron>
<a-octahedron position="-2.5 0.25 0" color="#FF926B" radius="0.45"></a-octahedron>
<a-ring position="-3.7 0.7 0" radius-inner="0.25" radius-outer="0.7"></a-ring>
<a-sphere id="sphere" position="3.7 0.5 0"color="blue" radius="0.5"></a-sphere>
<!-- --------- CAMERA AND CURSOR --------- -->
<a-camera look-controls-enabled wasd-controls-enabled position="0 0 3">
</a-camera>
</a-scene>
</body>
</html>
This Pen is owned by Filipa Cruz on CodePen.
See more by @cr0ssing on CodePen
External CSS
This Pen doesn't use any external CSS resources.
External JavaScript
This Pen doesn't use any external JavaScript resources.
User Interaction
My dear fellow designers, these examples are not only, but mostly for you. I've tested and created some examples of UI elements that are very common in usual front-end.
All of these are gaze triggered, so hover over the targets for a few seconds to see the effects. They're not 100% perfect, but it's a good start! In the Codepen bellow, you can find a Tooltip, a Simple Pop-up, a Modal Pop-up and a Dropdown.
CodePen Embed - Ex 4 — UI
<html>
<head>
<title> UI</title>
<!-- --------- IMPORTED LIBRARIES ------>
<script src="https://aframe.io/releases/0.6.0/aframe.min.js"></script>
<script src="https://unpkg.com/aframe-animation-component/dist/aframe-animation-component.min.js"></script>
<script src="https://unpkg.com/aframe-event-set-component@^3.0.0/dist/aframe-event-set-component.min.js"></script>
<!-- Event Set component By NgoKevin -->
</head>
<body>
<a-scene> <!-- Creating scene -->
<!-- --------- SKY --------- -->
<a-sky id="background-img" color="#EBEBEB"></a-sky>
<!-- ---------TOOLTIP --------- -->
<a-plane id="tooltip_target" position="0 1 -1" height="2" width="3" rotation="0 0 0" color="tomato" visible="true"
event-set__1="_event: mouseenter; _target:#tooltip_text; opacity: 1;"
event-set__2="_event: mouseleave; _target:#tooltip_text; opacity: 0;"
event-set__3="_event: mouseenter; _target:#tooltip_toggle;opacity: 1;"
event-set__4="_event: mouseleave; _target:#tooltip_toggle; opacity: 0;"
>
<a-text value="Hover here" position="0 0 0" align="center"></a-text>
</a-plane>
<a-plane id="tooltip_toggle" height="1.25" width="2.5" scale="0.8 0.8 0.8" rotation="0 0 0" position="0 1 0" opacity="0" visible="true" color="#f7ae04">
<!-- By using the event set component we can trigger events without javascript, but they don't "last", they happen during the event.
The target is the element affected by the change you want to apply-->
<a-text id="tooltip_text" text="value:Hello VR World" color="#FFFFFF" align="center" opacity="0" scale="0.5 0.5 0.5" position="0 0 0" rotation="0 0 0" visible="true">
</a-text>
</a-plane>
<!-- --------- POP-UP BTN FADE IN & OUT --------- -->
<a-plane class="plane_target_fade" position="3 1 -1" height="2" width="3" rotation="0 0 0" color="#000000" visible="true">
<a-text value="POP-UP " position="0 0 0" align="center"></a-text>
</a-plane>
<a-plane class="plane_toggle_fade" color="#FC00CF" height="1.25" width="2.5" scale="0.8 0.8 0.8" rotation="0 0 0" position="3 1 0" visible="true" material= "transparent:true" opacity="0">
<a-text class="plane_text_fade" text="value: Hello 2 u 2!" color="#FFFFFF" align="center" opacity="0" scale="2 2 2" position="0 0 0" rotation="0 0 0" visible="true">
</a-text>
<!--Even though the text is before the animations, it's affected by them as well -->
<a-animation begin="mouseenter" end="mouseleave"
attribute="material.opacity"
from="0" to="1" dur="3000">
</a-animation>
<a-animation begin="mouseleave"
attribute="material.opacity"
from="1" to="0" dur="3000" delay="3000">
</a-animation>
</a-plane>
<!-- --------- POP-UP BTN FADE IN/SCALE OUT--------- -->
<a-plane class="plane_target_fadeIn" position="-3 1 -1" height="2" width="3" rotation="0 0 0" color="#ffffff" visible="true" >
<a-text value="Modal" position="0 0 0" align="center" color="black"></a-text>
</a-plane>
<a-plane class="plane_toggle_fadeIn" id="fadeIn_toggle" material="transparent:true" color="#2621c4" height="1.25" width="2.5" scale="0.8 0.8 0.8" rotation="0 0 0" position="-3 1 0" opacity="0">
<a-animation begin="mouseenter"
attribute="material.opacity"
from="0" to="1" dur="3000">
</a-animation>
<a-animation begin="mouseenter"
attribute="scale"
from="0.8 0.8 0.8" to="2 2 2" dur="3000">
</a-animation>
<a-animation begin="mouseleave"
attribute="material.opacity"
to="0" from="1" dur="3000">
</a-animation>
<a-animation begin="mouseleave"
attribute="scale"
to="0.8 0.8 0.8" from="2 2 2" dur="3000">
</a-animation>
<a-text class="plane_text_fadeIn" id="fadeIn_text" text="value: Modal Pop-up" color="#ffffff" align="center" opacity="0" scale="1 1 1" position="0 0 0" rotation="0 0 0" visible="true">
</a-text>
</a-plane>
<!-- --------- DROPDOWN BTN --------- -->
<!-- This is the only element that uses Js
To close the Dropdown, leave the target, re-enter and leave again
It works this way: You open the Dropdown to see the links, you leave the trigger to choose a link, and then return to the dropdown and close it
It closes after 3 seconds because of the SetTimeout on Js-->
<a-plane class="dropdown_target" position="6 1 -1" height="2" width="3" rotation="0 0 0" color="teal" visible="true">
<a-text value="Dopdown" position="-0.5 0 0"></a-text>
</a-plane>
<a-plane class="dropdown_toggle" color="#21c4bb" height="1.25" width="2.5" scale="0.8 0.8 0.8" rotation="0 0 0" position="5 -0.25 0" opacity="0" visible="true">
<a-text class="dropdown_text" text="value: Thing 1" color="#FFFFFF" align="center" opacity="0" scale="0.5 0.5 0.5" position="0 0 0" rotation="0 0 0" visible="true">
</a-text>
</a-plane>
<a-plane class="dropdown_toggle" color="#21c4bb" height="1.25" width="2.5" scale="0.8 0.8 0.8" rotation="0 0 0" position="5 -1 0" opacity="0" visible="true" >
<a-text class="dropdown_text" text="value:Thing 2" color="#FFFFFF" align="center" opacity="0" scale="0.5 0.5 0.5" position="0 0 0" rotation="0 0 0" visible="true">
</a-text>
</a-plane>
<!-- --------- CAMERA AND CURSOR --------- -->
<a-camera look-controls-enabled wasd-controls-enabled position="0 0 5">
<a-cursor position="0 0 0"
geometry="primitive: ring; radiusOuter: 0.030; radiusInner: 0.020;"
material="color: #11d8c4; shader: flat"
fuse="true" timeout="10">
<a-animation begin="click" easing="ease-in" attribute="color"
fill="backwards" from="#000000" to="#ffffff"></a-animation>
<a-animation begin="cursor-hovering" easing="ease-in" attribute="scale"
fill="forwards" from="1 1 1" to="0.5 0.5 0.5"></a-animation>
</a-cursor>
</a-camera>
</a-scene>
</body>
</html>
//-- --------- HIDE AND SHOW DROPDOWN ---------
var count=0;
document.querySelector('.dropdown_target').addEventListener('mouseenter', function () {
count+=1;
var toggleD = document.querySelectorAll('.dropdown_toggle');
for(var i=0; i<toggleD.length; i++){
toggleD[i].setAttribute('opacity', 100);
}
var textD = document.querySelectorAll('.dropdown_text');
for(var i=0; i<textD.length; i++){
textD[i].setAttribute('opacity', 100);
}
});
document.querySelector('.dropdown_target').addEventListener('mouseleave', function () {
if(count%2==0){
setTimeout(function () {
var toggleD = document.querySelectorAll('.dropdown_toggle');
for(var i=0; i<toggleD.length; i++){
toggleD[i].setAttribute('opacity', 0);
}
var textD = document.querySelectorAll('.dropdown_text');
for(var i=0; i<textD.length; i++){
textD[i].setAttribute('opacity', 0);
}
}, 3000);
}
});
This Pen is owned by Filipa Cruz on CodePen.
See more by @cr0ssing on CodePen
External CSS
This Pen doesn't use any external CSS resources.
External JavaScript
This Pen doesn't use any external JavaScript resources.
DATGUI
This component was created by several A-Frame community members and it mostly takes care of Slider UI elements, but it has a whole lot of capabilities like Checkboxes, DropDowns and more, which you can check here.
These two examples are the best I've seen, the first one allows you to understand the basics of the component, while the second one works in a different way and includes more advanced features.
A-Frame PointLight by Dirk Krause
CodePen Embed - A-Frame PointLight
<script src="https://aframe.io/releases/0.5.0/aframe.min.js"></script>
<a-scene shadows="true">
<a-sky color="#333"></a-sky>
<a-light type="ambient" color="#445451" intensity="0.5"></a-light>
<!-- <a-entity id="light" position="0 1.6 -9"
light="castShadow: true; type: point;"
geometry="primitive: sphere; radius: 0.2"></a-entity>
-->
<a-entity id="light" position="0 1.6 -9">
<a-sphere radius="0.2" color="yellow"></a-sphere>
<a-sound></a-sound>
<a-light type="point" intensity="2" penumbra="0.5" distance="5" decay="2" color="#ff844e">
<a-animation begin="flash" attribute="intensity" delay="30" from="0" to="1" dur="50" repeat="4" fill="backwards"></a-animation>
</a-light>
</a-entity>
<a-box position="-1 0.5 -8" rotation="0 0 0" color="#aaa" shadow="cast: true; recieve: true"></a-box>
<a-box position="1 0.5 -8" rotation="0 0 0" color="#aaa" shadow="cast: true; recieve: true"></a-box>
<a-plane id="terrain" position="0 0 -4" rotation="-90 0 0" width="14" height="14" color="#7BC8A4" roughness="1" shadow="cast: true; recieve: true"></a-plane>
<a-plane id="terrain2" position="0 0 -11" rotation="0 0 0" width="14" height="14" color="#333" roughness="1" shadow="cast: true; recieve: true"></a-plane>
<!-- <a-plane id="terrain3" position="0 -5 -5" rotation="0 0 0" width="14" height="14" color="#000" roughness="1" shadow="cast: true; recieve: true"></a-plane>
</a-scene> -->
var lightDOM = document.querySelector('#light a-light')
var light = lightDOM.getObject3D('light');
var terrain = document.querySelector('#terrain').getObject3D('mesh');
var gui1 = new dat.GUI();
gui1.add(light, 'distance', 0, 30);
gui1.add(light, 'intensity', 0, 3);
var gui2 = new dat.GUI();
gui2.add(terrain.material, 'roughness', 0, 1);
gui2.add(window, 'flashLight')
function flashLight() {
lightDOM.emit('flash');
}
This Pen is owned by Dirk Krause on CodePen.
It is a fork of this Pen.
See more by @dirkk0 on CodePen
External CSS
This Pen doesn't use any external CSS resources.
External JavaScript
Dat.GUIVR Declarative Binding by Andres Cuervo
CodePen Embed - Dat.GUIVR Declarative Binding
<script>
AFRAME.registerComponent("gui", {
schema: {
name: { type: "string" },
properties: { type: "array" },
position: { type: "vec3" },
inheritPosition: { default: false }
},
init: function() {
// setup mouse interaction
var that = this;
this.el.sceneEl.addEventListener("render-target-loaded", function() {
const scene = that.el.sceneEl.object3D;
const { camera, renderer } = that.el.sceneEl;
dat.GUIVR.enableMouse(camera, renderer);
});
var scene = this.el.sceneEl.object3D;
var gui = dat.GUIVR.create(this.data.name);
//console.log("pos:", this.el.object3D.position.clone());
var guiPos = new THREE.Vector3(0, 0, 0);
if (this.data.position) {
["x", "y", "z"].forEach(function(axis) {
guiPos[axis] = this[axis];
}, this.data.position);
}
if (this.data.inheritPosition) {
["x", "y", "z"].forEach(function(axis) {
guiPos[axis] += this[axis];
}, this.el.object3D.position);
}
gui.position.set(guiPos.x, guiPos.y, guiPos.z);
//console.log("data:", this.data.properties);
var thisObject = this.el.object3D;
this.data.properties.forEach(function(prop) {
prop = prop.split(".");
console.log("len", prop.length);
var min = 0;
var max = 10;
if (prop.length == 1) {
gui.add(thisObject[prop[0]], min, max);
} else {
var propController = gui.add(thisObject[prop[0]], prop[1], min, max);
propController.name(prop[0] + "." + prop[1]);
}
});
gui.name = this.data.name + "GUI";
scene.add(gui);
}
});
</script>
<a-scene antialias="true">
<a-entity camera="userHeight: 1.6" look-controls wasd-controls></a-entity>
<a-datgui name="settings" position="0 2 -1">
<a-gui-slider id="scaleControl" name="scale"></a-gui-slider>
</a-datgui>
<a-sphere position="-5 1.25 -5" radius="1.25" color="#EF2D5E" gui="name: Pink Sphere; properties: position.x, scale.y, scale.x, scale; inheritPosition: true; position: 3.5 1 4;"></a-sphere>
<a-box position="-1 0.5 -3" rotation="0 45 0" width="1" height="1" depth="1" color="#4CC3D9"></a-box>
<a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#DAD" event-set__enter="_event: mouseenter; color: #8FF7FF" event-set__leave="_event: mouseleave; color: #DAD;"></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-camera>
<a-cursor></a-cursor>
</a-camera>
</a-scene>
// by Don McCurdy: https://github.com/mflux/aframe-datguivr/issues/2
var el = document.querySelector('a-box');
scaleCtrl = document.querySelector('#scaleControl');
scaleCtrl.addEventListener('onChanged', function (e) {
el.setAttribute('scale', {
x: e.detail.value,
y: e.detail.value,
z: e.detail.value
});
});
This Pen is owned by Andres Cuervo on CodePen.
It is a fork of this Pen.
See more by @cwervo on CodePen
External CSS
This Pen doesn't use any external CSS resources.
External JavaScript
This Pen doesn't use any external JavaScript resources.
PORTALS
For me, this is THE coolest feature of version 6 of A-Frame. You can have Portals as links to travel between sections or HTML pages.
CodePen Embed - Ex 5 — Portal
<html>
<head>
<title> Portal Link</title>
<!-- --------- IMPORTED LIBRARIES ------>
<script src="https://aframe.io/releases/0.6.0/aframe.min.js"></script>
</head>
<body>
<a-scene> <!-- Creating scene -->
<!-- Image links. -->
<a-assets>
<img id="portal_1" src="https://cdn.glitch.com/e6225ccd-c32e-4cf8-b039-e78814a8cb78%2Fbg-2.jpg?1498129159642">
<img id="portal_2" src="https://cdn.glitch.com/e6225ccd-c32e-4cf8-b039-e78814a8cb78%2Fbg.jpg?1498128625025">
</a-assets>
<!-- --------- SKY --------- -->
<a-sky id="background-img" color="#EBEBEB"></a-sky>
<!-- --------- PORTAL LINKS --------- -->
<a-entity link="href: index.html; title: Portal to LandX; image: #portal_1" position="-3 1 0" ></a-entity>
<a-link href="index.html" title="Portal to LandY" image="#portal_2" position="3 1 0"></a-link>
<!-- Move around with W and S, you can look through the portals without going in
Since the feature is new, the a-link tag only has three attributes ( title, image and href)
image is the thumbnail the portal lets you see
title is the text dislayed above the portal
href is the "place" you get sent through the portal-->
<!-- --------- CAMERA AND CURSOR --------- -->
<a-camera look-controls-enabled wasd-controls-enabled position="0 0 3">
<!--The camera is a bit far from position 0 0 0 so you can view the full picture -->
</a-camera>
</a-scene>
<!-- Closing scene -->
</body>
</html>
This Pen is owned by Filipa Cruz on CodePen.
See more by @cr0ssing on CodePen
External CSS
This Pen doesn't use any external CSS resources.
External JavaScript
This Pen doesn't use any external JavaScript resources.
Augmented Reality
Yes, you read correctly! A-Frame also has the ability to use Augmented Reality, and it's pretty simple as well.
A-Frame AR works based upon the Ar.Js library, and all you have to do is add some simple details to be able to use it.
Based on this example by Jerome Etienne, I've made my own AR experiments, as you can see in the codepen bellow.
CodePen Embed - Ex.6 — Augmented Reality w/personalised marker
<head>
<meta aframe-injected="" name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,shrink-to-fit=no,user-scalable=no,minimal-ui">
<meta name="apple-mobile-web-app-capable" content="yes">
<!-- ---------LIBS & COMPONENTS --------- -->
<!-- include A-Frame -->
<script src="https://aframe.io/releases/0.6.0/aframe.min.js"></script>
<!-- include ar.js for A-Frame -->
<script src="https://jeromeetienne.github.io/AR.js/aframe/build/aframe-ar.js"></script>
</head>
<body> <!-- ---------BODY --------- -->
<a-scene embedded arjs>
<!-- AR.JS with A-Frame documentation: https://aframe.io/blog/arjs/
Step by step AR with A-Frame: https://github.com/jeromeetienne/AR.js/blob/master/docs/posts/post-XX-how-to-use-arjs-with-aframe.md-->
<!-- ---------ASSETS --------- -->
<a-assets>
<img id="whitesmith_img" crossorigin="anonymous" src="https://scontent.flis5-1.fna.fbcdn.net/v/t31.0-8/p960x960/20229663_705565322965105_5566991771693753796_o.jpg?oh=a10e74a90309205ed5354040fd7d7aab&oe=59ED3A37">
</a-assets>
<!-- ---------AR --------- -->
<!-- define a camera which will move according to the marker position -->
<a-marker preset="hiro">
<!-- This is a preset marker you can find here https://jeromeetienne.github.io/AR.js/data/images/HIRO.jpg. Just show it to the camera and the image will appear -->
<!-- <a-marker type="pattern" size="2" url="https://cdn.glitch.com/2a1d3f33-8c4f-4985-ab16-4fdd9ff91c67%2Fpattern-marker.patt?1500649950652">
This is a custom marker created here: https://jeromeetienne.github.io/AR.js/three.js/examples/marker-training/examples/generator.html -->
<a-plane src="#whitesmith_img" width="3" height="1.5" position="0 0 -1" rotation="-90 0 0 "> </a-plane>
<!-- surprise Whitesmith image-->
</a-marker>
<!-- here you tell A-Frame that you want ar.js to control the camera
<a-marker-camera> will make it so that the camera is moving and the marker is static
If you want the marker to move and camera to be static at all times, you use only <a-marker>-->
</a-scene>
</body>
This Pen is owned by Filipa Cruz on CodePen.
See more by @cr0ssing on CodePen
External CSS
This Pen doesn't use any external CSS resources.
External JavaScript
This Pen doesn't use any external JavaScript resources.
Tips and tricks
In case you want to run some tests, in the Github repo you'll find a variety of tools and tips for that effect. And don't worry if you don't have a headset or Google Cardboard around to try your projects, use this Chrome Extension.
Since good practices are ALWAYS important, here you can find a set of them so your code is easy to read, maintain and understand.
For my dear fellow designers and Sketch lovers, now you can export Sketch Artboards to VR with a plugin.
Something I found many people asking about in the A-Frame Slack Team is the fact that you can't trigger mobile VR mode automatically. On mobile phones, we rely on the fullscreen API that requires user action (like a tap on the screen) to initiate. A page cannot trigger it automatically. That's a restriction of mobile browsers.
Also, there was a problem with playing audio in iOS devices but this Audio Sprite seems to do the trick!