frame academy

Learn how to create immersive, cross-platform webxr sites.

project 4: creating a webxr photosphere gallery with javascript

a few helpful notes about This project

Project goals

I hope that by going through this small project, you will learn:

part 1: exploring the starter project

setup your project

Each part of the project has a video at the top where I guide you through the project. The video is the best place to start, but I also break down the content below so that you can follow along step by step.

To code our projects, we're going to use something called Glitch, a sweet tool that gives you a way to write your code from a web browser. Glitch also hosts your website for you, letting you see the results of your code immediately!

I made a starter project that you should use as the base for this project. You can make your own copy of it with this button:

copy the starter project on Glitch

There will be plenty of things you may not understand in the starter project. We'll break it all down, so don't worry. :)

You can also "Remix" any of the code samples you see throughout the project by using the "Remix to Edit" button you'll see next to them. This lets you make a copy of my code that you can edit, build upon, and make your own. You can also always copy and paste my code into your own project..

To save your Glitch project so you can keep working on it whenever you want, you have to sign in to Glitch with a free account. The sign in button is on the top right of Glitch.

Reminder: Have a question or idea? Check out the Frame Academy Community on Discord.

the scripts and assets

I'm going to walk you through the index.html document of the starter project. Please also explore the WebXR site in full screen by clicking the "Show Live" button on your own copy of the starter project on Glitch. You can move around with the wasd keys on the keyboard, and click and drag your mouse to look around. You can click on the photosphere in the back left of the museum to expand it, and you can click the circle at the center of the floor to return back to the homeworld. I'll show you how I set that up later on in this project.

In the code itself of the index.html file, notice how Glitch provides line numbers to the left of the code. I'll be using these numbers to help direct your attention to certain parts of the code. For example, I might say "Check out the a-scene element on line 13". These line numbers become more helpful as our code gets longer!

First, on line 3 in the head element you'll see a bunch of scripts I'm importing into the project. At the top we've got the script for A-Frame, the development tool we are using to create our WebXR sites. I've also imported the animation component under it, which we learned about in Project #2. The other three scripts are components that I wrote and included with this project. In the sidebar on the left of Glitch, you can actually find those components below the assets folder. These components won't make a lot of sense just yet if you click on them and check them out, but don't worry about that - all in due time!

You might have noticed that these component files end in .js. What's up with that? A-Frame components are written with a programming language called JavaScript, and JavaScript files will have a .js at the end of them. You can add new JavaScript files to your Glitch project by clicking the new file button, or you can copy an existing file by selecting it, clicking the drop down arrow, and clicking the "copy" button.

Now, back to the index.html file. On line 15, inside the a-assets element you'll see all of the assets that I'm loading into the A-Frame Asset Management System. If you need a refresher on the A-Frame Management System, check out this section of Project 3. Long story short, this is where you can put the assets (for example images, photospheres, 3D models) that you'd like to preload in the browser as soon as your WebXR site loads. This makes for a smoother loading experience, so I recommend it! You'll find all the files inside the assets folder in the sidebar of your Glitch project.

Reminder: each of the elements inside of a-assets has an id, and you can use that id in your HTML to actually bring that asset into your scene. For example, see the img element on line 18 that has an id="starsky" ? I use that starsky id to reference that asset later on in my code on line 31 where I set #starsky as the src for my a-sky element, making that asset the photosphere in the background of my scene!

Inside of my a-assets element I've got a few other images and also a 3D model of a triceratops skull I found on Sketchfab. I use these assets throughout the WebXR site.

scene structure

Now let's check out how I've structured the elements you can actually see in the scene like the sky, the structure of the room, the painting on the wall, the 3D model on the side, etc.

On line 31 you'll see my a-sky element, which is where I set the image that is used as the background photosphere for the whole scene.

On line 33, you'll see an a-entity with id="architecture", and this entity has a bunch of entities nested inside of it as children entities. These are the entities that make up the floor, walls, and ceiling of the scene. We learned about nesting entities in this part of Project 3, so go there if you need a refresher on parent-child relationships of html elements.

Why did I structure the elements this way? Remember that elements set their position relative to their parent element. By nesting the walls, floor, and ceiling inside the same parent element, I could do something like move all these things around at once just by moving the parent, or making them all disappear just by causing the parent element to disappear. This is actually exactly what happens if you view the project and you click on the photosphere floating in the back left corner of the gallery. Give it a try and notice how the walls, floor, and ceiling disappear while the photosphere takes over!

Also, take a look in the A-Frame Inspector how I can move around the whole structure just by moving around the parent entity, even though it's made up of a few different entities. Because the walls, floor, and ceiling are all part of the same structure, it made sense to me to group them inside one entity:

Tip: Remember in the Inspector that you can expand out a parent entity to see all of its children entities by clicking the arrow drop down to the left of the parent entity name! Also, you'll notice that on the ceiling entity, I tinkered quite a bit with the material component to give it a sort of "glass" effect. Let me know if you're interested in hearing more about this, and feel free to check out how I set up the material properties if you want to imitate it.

I set up other parts of the scene the same way. At line 44 of the index.html, you'll see a parent entity with id="picassodisplay". This parent entity has a few children entities nested inside of it: the image of the Picasso painting, a plane shape used as the frame of the painting, and a plane with the text component on it used as a caption to give some info about the painting. If I ever wanted to move the position of the whole display, I could just change the position of the parent entity. If I wanted to put it on a different wall, I could rotate the whole entity and then move it where I need to, without fiddling with each individual entity:

At line 52, you'll see a similar set up for the 3D model of the Triceratops skull. I have a parent entity and nested inside of it is a box as a sort of pedestal, the 3D model as an a-gltf-model entity, and a plane with a text caption on it. Using the animation component, I put a simple rotation animation on the Triceratops skull to give it a gentle spin. If you'd like a refresher on using the animation component, check out Project #2.

At line 62, it's a similar story for the photosphere display. I nested a box, a sphere, and a plane with the text caption under one entity with id="photospheredisplay". Take a closer look at the sphere entity on line 64:

<a-sphere position="0 1.8 0" radius=".7" src="#bordeauxtheater" sphereexpand="spheresource:#bordeauxtheater"  animation="property: rotation; to: 0 360 0; easing: easeInOutSine; dur: 30000; loop: true; elasticity: 0"></a-sphere>

I put the animation component on this sphere to give it a gentle spin. For the src, I've used the id of one of the images stored in my a-assets. You'll see a new component called sphereexpand. The sphereexpand component has one property called spheresource and you can see I've given that propery a value. This is the component that makes it so when you click on the sphere, that photosphere takes over the scene while everything else disappears. Later on in this project, I'll show you how I made it and how it works.

You definitely won't be able to find this spheresource component in the A-Frame documentation. Why not? It's a component that I made! As you might have seen already, there's a file called "public/js/sphereexpand.js" in the Glitch project (look on the sidebar on the left), and it's a JavaScript file that I wrote. I've imported this component inside my head element in line 6, just as I would with any component that doesn't come included with A-Frame:

<script src="public/js/sphereexpand.js"></script>

Long Tip: when you make your own A-Frame components in Glitch and you give them a filename that begins with public/js/ , you're making it so that you can share your component with the world, letting others use it on their own WebXR sites. For example: the url for my Glitch project is, and anyone could import my sphereexpand.js component into their own, unrelated websites by putting this script in their head tag:">

Then, after they do that, they can immediately put my sphereexpand component on any of the entities in their scene! I think that's incredibly cool.

When you start making your own components, I hope you'll share some with the community. My dream goal is to build, with you all, a shared repository of components that we can all use to make our WebXR projects do awesome things, look cooler, and whatever else we want! Kind of like the Frame Gallery, but instead of sharing WebXR scenes, we'll be sharing scripts. :)

Finally, at line 72, you'll see a circle entity with id="homebutton". This entity has another home-made component on it, backhome. Just as with sphereexpand, I'll show you how I made this and how it works later.

For now, I'll just let you know what it does: when you're viewing the site and you expand the photosphere by clicking the sphere, you can press this circular button on the floor to return home. It's right at the center of the gallery and you'll see it if you load the site and look down at the floor. Look at me checking out the photosphere on display and then using the home button to return to the home world.

🔥 challenge #1 🔥

Each part of this project comes with a challenge. As you go through the challenges, you'll be building a WebXR site that will work on desktop, mobile, or VR!

For this challenge, start to make the starter project your own. Some ideas? Add your own images to the walls, swap mine out, bring a new photosphere in for the sky, bring in other 3D models, and arrange things however you want them. For a refresher on how to bring in those assets, check out Project 1. Start making a cool gallery about something you love, or an e-portfolio that shows off some of your work, or just an exploratory playground.

Move on to part 2 >
mouse + vr controllers