Developing a Small World in Three JS

As Featured in a Project for Metronomy

A simple fun illustrated 3d earth
Metronomy’s Small World

Two weeks ago, we launched a little Spotify app in support of Metronomy’s awesome new album, Small World. The app invites fans to discover the “Eight Wonders of Metronomy’s Small World” by connecting with their Spotify account so we may determine how often they’ve been streaming the Small World Spotify playlist. The more often Metronomy appears in their Top 50 recently streamed tracks, means the more wonders that get revealed. It’s a fun little app featuring the artwork of Lee O’ Connor that is meant to encourage and reward streaming. It was also the first Spotify app I’ve built since Spotify now requires all integrations to be submitted for approval. Luckily, that process was pretty painless and our app was approved within a day. I think it might help to have a contact there but familiarize yourself with all of the platform rules before building your activation.

I’ve covered most of the techniques behind building these sorts of “fan affinity” Spotify apps in the case studies for Greta Van Fleet, Girl In Red, and Hurts. In this dev blog, I thought I would hone in on the main visual component of the build: the 3d globe. 🌎 You can jump straight to the CodePen or read on to understand how it came together.

Small Three JS 3D World

https://medium.com/media/91ceb1fb6522926e7596c1703218a283/href

Three.js is an open source darling and for good reason. It completely transformed how we handle 3D on the web and has consistently evolved itself since the r1 release in 2013. Developing a 3D world using the library is really quite simple and yet it still feels like a magical addition when you break out of the 2D confines of the web. Let’s first establish a base.

Base

First, we’ll need a scene to hold our world.

// Initialize scene
const scene = new THREE.Scene()

Then, we can add a perspective camera and position it back a bit.

// Initialize camera
const camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight. 0.1, 60)
// Reposition camera
camera.position.set(6, 0, 0)

Then, we’ll add a renderer which will render our scene, making sure to set alpha to true so it has a transparent background. We’ll be adding a simple sky gradient in CSS later. We’ll size the renderer to fit our browser window and then append it to the <body>.

// Initialize renderer
const renderer = new THREE.WebGLRenderer({
alpha: true,
antialias: true
})
// Set renderer size
renderer.setSize(window.innerWidth, window.innerHeight)
// Append renderer to body
document.body.appendChild(renderer.domElement)

Finally, we’ll set up an orbit control to that users may zoom, pan, and rotate the camera.

// Initialize controls
const controls = new THREE.OrbitControls(camera, renderer.domElement)

Now, let’s add our world!

World

First, we’ll load up the world texture featuring artwork by Lee O’ Connor. Then, we’ll establish the sphere geometry and material. The geometry and material is then used to initiate the world mesh itself, which is then added to our scene.

// Load world texture
const worldTexture = new THREE.TextureLoader().load("world.jpg")

// Initialize world geometry
const worldGeometry = new THREE.SphereGeometry(1, 40, 40)

// Initialize world material
const worldMaterial = new THREE.MeshBasicMaterial({
map: worldTexture
})

// Initialize world
const world = new THREE.Mesh(worldhGeometry, worldMaterial)
// Add earth to scene
scene.add(world)

Next, we’ll add some clouds.

Clouds

We’ll handle the clouds much the same way we handled the world, except we’ll make the sphere radius slightly larger so it sits on top of the world sphere. In addition, we’ll make sure the material is transparent so we can see the world through the gaps in the clouds.

// Load clouds texture
const cloudTexture = new THREE.TextureLoader().load("clouds.png")

// Initialize clouds geometry
const cloudGeometry = new THREE.SphereGeometry(1.01, 40, 40)

// Initialize clouds material
const cloudMaterial = new THREE.MeshBasicMaterial({
map: cloudTexture,
transparent: true
})

// Initialize clouds
const clouds = new THREE.Mesh(cloudGeometry, cloudMaterial)

// Add clouds to scene
scene.add(clouds)

Now, let’s render and animate our small world.

Animation

Rendering our scene is as easy as requesting an animation frame and calling the render method of our renderer. For animation, we’ll rotate the world in one direction and our cloud in the other, slightly quicker.

// Prepare animation loop
function animate() {
// Request animation frame
requestAnimationFrame(animate)

// Rotate world
world.rotation.y += 0.0005

// Rotate clouds
clouds.rotation.y -= 0.001

// Render scene
renderer.render(scene, camera)
}

// Animate
animate()

Voila. You’ve got a spinning small world! Let’s also handle refreshing our camera and renderer when the user resizes the browser.

Resize

Since our camera and renderer were set up using the initial browser’s width and height, any browser resizes will cause visual issues in our scene. In order to remedy this, we can listen for any resizes and then update the camera aspect, projection matrix, and renderer size.

// Listen for window resizing
window.addEventListener('resize', () => {
// Update camera aspect
camera.aspect = window.innerWidth / window.innerHeight

// Update camera projection matrix
camera.updateProjectionMatrix()

// Resize renderer
renderer.setSize(window.innerWidth, window.innerHeight)
})

Background

And last but not least, let’s add a nice white to blue gradient to our <body> background using a CSS radial gradient. I like this because it adds a nice atmospheric vibe around our small world.

body{
background: radial-gradient(circle at center, white, rgba(113,129,191,0.5) 50%);
}

Thanks

A photo of Metronomy from the set of their new video
Metronomy

Working with Rhian Emanuel, Ian Pither, Jack Smith, and Ben Bowman for the first time on this was an absolute treat. Special thanks to Lee O’ Connor once again for all the beautiful illustrations. Stream Metronomy’s Small World playlist today and return to the app tomorrow to see how many wonders you’ve revealed.


Developing a Small World in Three JS was originally published in Bits and Pieces on Medium, where people are continuing the conversation by highlighting and responding to this story.

As Featured in a Project for Metronomy

A simple fun illustrated 3d earth
Metronomy’s Small World

Two weeks ago, we launched a little Spotify app in support of Metronomy’s awesome new album, Small World. The app invites fans to discover the “Eight Wonders of Metronomy’s Small World” by connecting with their Spotify account so we may determine how often they’ve been streaming the Small World Spotify playlist. The more often Metronomy appears in their Top 50 recently streamed tracks, means the more wonders that get revealed. It’s a fun little app featuring the artwork of Lee O’ Connor that is meant to encourage and reward streaming. It was also the first Spotify app I’ve built since Spotify now requires all integrations to be submitted for approval. Luckily, that process was pretty painless and our app was approved within a day. I think it might help to have a contact there but familiarize yourself with all of the platform rules before building your activation.

I’ve covered most of the techniques behind building these sorts of “fan affinity” Spotify apps in the case studies for Greta Van Fleet, Girl In Red, and Hurts. In this dev blog, I thought I would hone in on the main visual component of the build: the 3d globe. 🌎 You can jump straight to the CodePen or read on to understand how it came together.

Small Three JS 3D World

Three.js is an open source darling and for good reason. It completely transformed how we handle 3D on the web and has consistently evolved itself since the r1 release in 2013. Developing a 3D world using the library is really quite simple and yet it still feels like a magical addition when you break out of the 2D confines of the web. Let’s first establish a base.

Base

First, we’ll need a scene to hold our world.

// Initialize scene
const scene = new THREE.Scene()

Then, we can add a perspective camera and position it back a bit.

// Initialize camera
const camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight. 0.1, 60)
// Reposition camera
camera.position.set(6, 0, 0)

Then, we’ll add a renderer which will render our scene, making sure to set alpha to true so it has a transparent background. We’ll be adding a simple sky gradient in CSS later. We’ll size the renderer to fit our browser window and then append it to the <body>.

// Initialize renderer
const renderer = new THREE.WebGLRenderer({
alpha: true,
antialias: true
})
// Set renderer size
renderer.setSize(window.innerWidth, window.innerHeight)
// Append renderer to body
document.body.appendChild(renderer.domElement)

Finally, we’ll set up an orbit control to that users may zoom, pan, and rotate the camera.

// Initialize controls
const controls = new THREE.OrbitControls(camera, renderer.domElement)

Now, let’s add our world!

World

First, we’ll load up the world texture featuring artwork by Lee O’ Connor. Then, we’ll establish the sphere geometry and material. The geometry and material is then used to initiate the world mesh itself, which is then added to our scene.

// Load world texture
const worldTexture = new THREE.TextureLoader().load("world.jpg")

// Initialize world geometry
const worldGeometry = new THREE.SphereGeometry(1, 40, 40)

// Initialize world material
const worldMaterial = new THREE.MeshBasicMaterial({
map: worldTexture
})

// Initialize world
const world = new THREE.Mesh(worldhGeometry, worldMaterial)
// Add earth to scene
scene.add(world)

Next, we’ll add some clouds.

Clouds

We’ll handle the clouds much the same way we handled the world, except we’ll make the sphere radius slightly larger so it sits on top of the world sphere. In addition, we’ll make sure the material is transparent so we can see the world through the gaps in the clouds.

// Load clouds texture
const cloudTexture = new THREE.TextureLoader().load("clouds.png")

// Initialize clouds geometry
const cloudGeometry = new THREE.SphereGeometry(1.01, 40, 40)

// Initialize clouds material
const cloudMaterial = new THREE.MeshBasicMaterial({
map: cloudTexture,
transparent: true
})

// Initialize clouds
const clouds = new THREE.Mesh(cloudGeometry, cloudMaterial)

// Add clouds to scene
scene.add(clouds)

Now, let’s render and animate our small world.

Animation

Rendering our scene is as easy as requesting an animation frame and calling the render method of our renderer. For animation, we’ll rotate the world in one direction and our cloud in the other, slightly quicker.

// Prepare animation loop
function animate() {
// Request animation frame
requestAnimationFrame(animate)

// Rotate world
world.rotation.y += 0.0005

// Rotate clouds
clouds.rotation.y -= 0.001

// Render scene
renderer.render(scene, camera)
}

// Animate
animate()

Voila. You’ve got a spinning small world! Let’s also handle refreshing our camera and renderer when the user resizes the browser.

Resize

Since our camera and renderer were set up using the initial browser’s width and height, any browser resizes will cause visual issues in our scene. In order to remedy this, we can listen for any resizes and then update the camera aspect, projection matrix, and renderer size.

// Listen for window resizing
window.addEventListener('resize', () => {
// Update camera aspect
camera.aspect = window.innerWidth / window.innerHeight

// Update camera projection matrix
camera.updateProjectionMatrix()

// Resize renderer
renderer.setSize(window.innerWidth, window.innerHeight)
})

Background

And last but not least, let’s add a nice white to blue gradient to our <body> background using a CSS radial gradient. I like this because it adds a nice atmospheric vibe around our small world.

body{
background: radial-gradient(circle at center, white, rgba(113,129,191,0.5) 50%);
}

Thanks

A photo of Metronomy from the set of their new video
Metronomy

Working with Rhian Emanuel, Ian Pither, Jack Smith, and Ben Bowman for the first time on this was an absolute treat. Special thanks to Lee O’ Connor once again for all the beautiful illustrations. Stream Metronomy’s Small World playlist today and return to the app tomorrow to see how many wonders you’ve revealed.


Developing a Small World in Three JS was originally published in Bits and Pieces on Medium, where people are continuing the conversation by highlighting and responding to this story.


Print Share Comment Cite Upload Translate
APA
Lee Martin | Sciencx (2024-03-28T19:15:29+00:00) » Developing a Small World in Three JS. Retrieved from https://www.scien.cx/2022/03/10/developing-a-small-world-in-three-js/.
MLA
" » Developing a Small World in Three JS." Lee Martin | Sciencx - Thursday March 10, 2022, https://www.scien.cx/2022/03/10/developing-a-small-world-in-three-js/
HARVARD
Lee Martin | Sciencx Thursday March 10, 2022 » Developing a Small World in Three JS., viewed 2024-03-28T19:15:29+00:00,<https://www.scien.cx/2022/03/10/developing-a-small-world-in-three-js/>
VANCOUVER
Lee Martin | Sciencx - » Developing a Small World in Three JS. [Internet]. [Accessed 2024-03-28T19:15:29+00:00]. Available from: https://www.scien.cx/2022/03/10/developing-a-small-world-in-three-js/
CHICAGO
" » Developing a Small World in Three JS." Lee Martin | Sciencx - Accessed 2024-03-28T19:15:29+00:00. https://www.scien.cx/2022/03/10/developing-a-small-world-in-three-js/
IEEE
" » Developing a Small World in Three JS." Lee Martin | Sciencx [Online]. Available: https://www.scien.cx/2022/03/10/developing-a-small-world-in-three-js/. [Accessed: 2024-03-28T19:15:29+00:00]
rf:citation
» Developing a Small World in Three JS | Lee Martin | Sciencx | https://www.scien.cx/2022/03/10/developing-a-small-world-in-three-js/ | 2024-03-28T19:15:29+00:00
https://github.com/addpipe/simple-recorderjs-demo