The original version of this project was built using a Daydream controller.
To make it accessible to more people, I've spent some time changing it so you can use your phone instead.
However, FIY, you can also build your own controller using something like an Arduino, accelerometer and bluetooth module if you feel like it! 😃
For the 1st version of this project, I used Web Bluetooth to connect the Daydream controller directly to the browser and I was hoping the code would stay quite similar, but I realised phones cannot connect to laptops using the Web Bluetooth API. Both phone and laptop can only be "central" devices, and not "peripheral", so I've had to change this demo to use Web Sockets instead to communicate between the phone and the laptop.
This version of the experiment works by having the main webpage open on your computer and another webpage open on your mobile phone to get the accelerometer data.
Using the DeviceOrientation Web API, the orientation of the phone is detected and sent to the browser on your laptop via WebSockets.
By placing your phone on a skateboard, it can become a controller. You can use the orientation data to apply it to the 3D environment and interact with the game as if you were on a hoverboard.
I'm not gonna go through the whole code as I don't think going through it line by line will be very beneficial. Instead, i'm going to explain the core parts of the prototype.
- A modern mobile phone (any phone that has an accelerometer built-in).
- A computer.
- A projector (optional).
- DeviceOrientation Web API
- Node.js with Socket.io
To get started, we need to set up a server to serve our files, expose routes and set up socket.io.
In the code sample above, we require some modules, start an Express server and indicate the path and routes to serve our files.
We also set up a basic socket.io connection that will wait for the communication between the server and front-end to be established. Once connected, socket.io will wait for certain messages from the front-end.
The 1st message should be received when the user visits the mobile page so we can confirm that they are ready to interact with the game. When this message is received, we emit one that the page on desktop will be listening to so we can start the game.
The 2nd message will be received when the mobile starts streaming orientation data. This message will emit an event to the desktop browser with the data so it can be applied to the hoverboard.
Now that our server is set up, let's work on the front-end.
Using the DeviceOrientation Web API, we're able to get orientation data from the mobile phone.
To set this up and send it back to the server, we need code that looks like this:
Here, we're instantiating socket.io and when the page loads, we're sending a first message to the server to indicate that the mobile page has been visited.
Then, we have an event listener that checks for
deviceorientation events. On change, we call the
handleOrientation function that sends another event to the server with the data on a certain axis. This data represents the change of position from left to right as you tilt the skateboard.
Now that the page on mobile is sending orientation data to the server, let's see how the desktop page is listening to it.
To be able to use the orientation data from the phone on the laptop, we need to be listening to the message sent by the server.
Again, we instantiate socket.io, and when we receive the message
mobile orientation from the server, we're able to use the tilt data in our game.
In the code sample above, I also added a
previousValue variable so we would only be using the orientation data if it is different from the one previously received.
Now that we set up a basic communication between the server and front-ends, as well as got the orientation data from the phone, we can start building the game around it using Three.js.
The 3D environment built in this project is using Three.js. To start using it as well as a few add-ons, we need to include them in our HTML.
Not all of these are needed if you want to create a basic game. The files
GlitchPass are only used for the effect I added on collision with an obstacle.
The main resources needed here are the Three.js library, the
noiseSimplex script to generate the plane and the
MTL loaders to load the 3D assets used for the hoverboard and obstacles.
To create a scene, you need to write the following lines:
In the code above, we're creating the scene, the camera, the renderer and appending everything to the body.
You can also add lights to your scene. There are different types of lights you can use but in my current prototype, I used an ambient light and spotlight:
Now we have a basic scene but there's nothing in it. Let's start by generating the landscape we can see in the demo.
Setting up the landscape is a little more complex. It starts with a simple
However, we can see in the demo that we have an effect of generative "mountains". To do this, we need to play with the vertices of our
Using our geometries previously defined, we're going to use the
SimplexNoise script to help us create an effect of wavy terrain by manipulating the vertices.
To have this effect be continuous throughout the game, we need to call this function with
Now that we have a terrain, we also need to add some rocks (obstacles) and the hoverboard.
The rocks and the skateboard are 3D models. To load them, we need the following lines:
With the lines above, we create an
OBJLoader, we give it the path to our
.obj file and we set its size & position in the scene. We also set a color material, and finally, we add it to the scene.
The code for the rocks is pretty much the same.
So, we've covered how to create a simple scene, add a procedural terrain, 3D models, but we're missing the interactive part.
Now that we have our scene set up, we can use the orientation data we talked about previously to update the position of the hoverboard model in our scene.
To do so, we need code like this:
This code sample is similar to the one showed a bit earlier in this tutorial except that now we have our
skateboard available in our scene so we are able to change its position based on the data coming back from our phone!
As said before, there's a bit more code than this for the full experience but in terms of core concepts, that's it! 😃🎉
Hope you find it fun! 😊👋