Creating a VR App with Redwood
Tags: javascript, vr
Published: 2021-07-15 12:38:02

---
title: Creating a VR App with Redwood
published: true
description: VR is a relatively new area of tech and now's a good time to learn about how to make AR apps with JavaScript. This tutorial will take you through everything you need to get started with VR in Redwood.
tags: #javascript, #VR
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gqgfwk50u9l73f18r0ov.png
---

VR has grown over the past few years as the number of compatible devices increase. There are a ton of uses for it, both practical and for entertainment. If you know JavaScript, you can even start making your own VR apps right in the browser.

In this tutorial, we're going to make a quick search and find game. There will be a few objects hidden around the world and the player will have to find them all to win. We'll be using Redwood and A-frame to handle all of our VR and user experience needs.

## Building the VR world

We'll start by making a new Redwood app. In a terminal, run the following command.

`yarn create redwood-app vr-in-redwood`

This bootstraps a new Redwood app with a lot of folders and files that have been auto-generated. We're going to start on the front-end so that we jump into the VR part. All of our front-end code is in the `web` directory.

We're going to a new page called `World` and it will point to the root of the app. To create this page, we'll run this command.

### Setting up the world

`yarn rw g page world /`

After this finishes, go to the `web > src > pages` directory and you'll see a `WorldPage` folder. It has the code for the home page and it has a few other files to help with testing. If you take a look at `Routes.js`, you'll also notice the new routes have automatically added.

We need to add Aframe to the project because this is the library we're going to use to make our VR world. Import this library in the `index.html` file with the following line at the end of the `<head>` element.

```html
<script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script>
```

### Updating the component

Using this import, we have access to the different Aframe components available in the library. We can start building our new world in the `WorldPage` component. Open that file and add the follwing code.

_You can delete the import and the current contents of the return statement inside of the `WorldPage` component. We won't be using any of the template code._

```javascript
const WorldPage = () => {
  return (
    <a-scene>
      <a-assets>
        <img
          id="room"
          crossorigin="anonymous"
          src="https://res.cloudinary.com/milecia/image/upload/room-360_nag5ns.jpg"
        />
      </a-assets>
      <a-sky id="image-360" radius="10" src="#room"></a-sky>
      <a-camera look-controls-enabled={true}></a-camera>
    </a-scene>
  )
}

export default WorldPage
```

This is what your `WorldPage` component should look like now. We're using a few of the Aframe components.

- `<a-scene>` creates the entire world for the VR app.
- `<a-assets>` is how we import external resources, like images and audio files, into the world.
- `<a-sky>` uses a picture to create the background for the world. This is how you can create a static environment for your world if you don't need the user to move around much.
- `<a-camera>` is how we add a camera to the world so that a user can look around the world.

You can learn more about how the Aframe library and components work by [checking out their docs](https://aframe.io/docs/1.2.0/introduction/).

### Pulling views from Cloudinary

Right now there's a placeholder image that drops users into a nice room, but you'll probably want something different for your app. We'll use Cloudinary to host the images because that'll decrease our load time and we won't have to deal with a lot of large files.

So you can go to the Cloudinary site and [sign up for a free account](https://cloudinary.com/users/register/free) and upload any panoramic images you want to use. Then you can update the `src` for the image in the `<a-assets>` element.

You'll need to update `milecia` in the asset URL to match the cloud name for your Cloudinary account so that you can use your images.

### Adding customization

Since we have the option to upload as many images as we want, users might like it if they can switch between images and have their own worlds load when they come to the app.

We can add this by creating a new variable that will come from the back-end we'll be making in a bit. We'll start by adding a few GraphQL methods. Import a method from Redwood at the top of the `WorldPage` component file.

```javascript
import { useQuery } from '@redwoodjs/web'
```

Then we'll add a call to that method inside of the component.

```javascript
const { loading, data } = useQuery(WORLDS)
```

Now we need to add the GraphQL definition for the query. So at the bottom of the component, above the export statement, add the following code.

```javascript
const WORLDS = gql`
  query Worlds {
    worlds {
      id
      imageName
    }
  }
`
```

With our GraphQL request defined, let's update the component to use our new data. First we'll add a loading state so that we don't have issues while data is being fetch. Below the `useQuery` line, add the following lines.

```javascript
if (loading) {
  return <div>Loading...</div>
}
```

Below this, we'll add a new variable that will contain the URL users have recently uploaded for the world. It'll default to an image if there isn't a user selected one to load.

```javascript
const worldUrl = data?.worlds[data.worlds.length - 1].imageName || 'room-360_nag5ns.jpg'
```

Then we'll make the URL dynamic by updating the URL in the assets.

```javascript
<img
  id="room"
  crossorigin="anonymous"
  src={`https://res.cloudinary.com/milecia/image/upload/${worldUrl}`}
/>
```

With all of this in place, you can finally run the app with this command.

`yarn rw dev`

You should see something similar to this.

![room VR world](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/otiyh24iifza017z88xf.png)

Now we'll add the back-end and database setup to support the front-end we just created.

## Setting up the back-end

Go to the `api > db` directory and open `schema.prisma`. This is where we'll add the schema to save the URL that the user wants for their world. We're going to update the provider to use a Postgres database.

```javascript
provider = "postgresql"
```

Then we'll update the existing placeholder schema with our real schema. You can replace the `UserExample` schema with the following.

```javascript
model World {
  id    Int     @id @default(autoincrement())
  imageName String
}
```

### Running the migration

Before we run the migration, we'll need to update the `.env` file to use the database instance you want. You can [set up Postgres locally](https://www.postgresql.org/download/). Update your `DATABASE_URL` with your credentials. It might look similar to this.

`DATABASE_URL=postgres://postgres:admin@localhost:5432/vr_worlds`

With the schema in place, we'll be able to do our first migration.

`yarn rw prisma migrate dev`

This will make Prisma set up our new database. You'll be prompted to name your migration and then it will run. If you check the your Postgres instance now, you should see the new table there.

### Set up the GraphQL server

All that's left is to create the GraphQL types and resolvers. The great thing about Redwood is that it has a command to generate these things for us.

`yarn rw g sdl world`

Now if you go to `api > src > graphql`, you'll see `worlds.sdl.js` with all of the types you need for GraphQL. Then if you go to `api > src > services`, you'll see a new `worlds` folder with a few files. The `worlds.js` file has the one resolver that we need to fetch the data on the front-end.

That's all! Now you have a full-stack VR app that works.

## Finished code

You can check out the finished code in [this Code Sandbox](https://codesandbox.io/s/clever-shamir-br7sh) or in [this GitHub repo in the 'vr-in-redwood` folder](https://github.com/flippedcoder/blog-examples).

## Conclusion

Hopefully you can see how quickly you can create new VR app in the JavaScript ecosystem. One thing that could be added to this app is the actual ability for users to push their preferred world in. This is a little tricky, but not terribly hard. You can definitely add that functionality as a challenge if you want to get more into VR.