Building a Snow Globe Radio using the new Device Motion Permission API

A holiday campaign for Universal Music Group Deutschland

Image for post
Image for post

A few months ago, Lorenzo from Universal Catalog contacted me about building a Holiday campaign at the suggestion of his boss, Moritz. The core goal was pretty simple: drive streams of some of the classic Holiday hits from the UMG catalog. These hits included “White Christmas” by Bing Crosby, “Wonderful Christmastime” by Paul McCartney, and yes, “Mistletoe” by Justin Bieber. Classics. I suggested we look for a Holiday theme or object anyone could understand to make the web app concept familiar when first encountered. We had an initial call discussing everything from unwrapping presents to Yule Logs but departed hoping the solution would just come to us, like a Christmas miracle. 10 minutes after I hung up the phone with Lorenzo, he texted me, “What about snow globes?”

Little did Lorenzo know, I had been following and writing about the evolution of how mobile web apps gain access to a device’s gyroscope to detect how a device is moving or shaking. So, why don’t we create a web app that looked like a snow globe but also streamed the Holiday catalog? Users could shake the the snow around and also login with their preferred streaming service to take the playlist to-go. Well that’s exactly what we did. Visit snowglobe.fm today and read on to find out how it was built.

A Square Snow Globe?

Image for post
Image for post
Early prototype

When approaching the design of this app, we put together some fun mood boards which included lots of vintage Christmas advertisements. I landed on this thought that our snow globe radio should be designed as a real (fake) product so we could create a set of vintage ads to market it. This meant that all of the radio functionality would live in the base of the snow globe. And rather than putting a globe at the top, I decided to add a rectangular housing you might find on a record player instead. The absurdity that you would shake a record player was the exact dumb direction I was looking for.

Initially, I pushed the design in the direction of skeuomorphism, trying to get the product to look as real as possible. However, once I started working up the vintage ad designs, I decided to utilize unfiltered versions of the ad graphics, leading to the simple but warm design.

One of my favorite bits of the final design is the LED display which reminded me of the <marquee> tags which once graced our GeoCities sites. While it does look like the marquee may still actually work in browsers, I decided to build one custom using anime.js. Here’s what some of that code looked like.

let marquee = {
scroll: 0
}
scrolling = anime({
targets: marquee,
scroll: 1,
duration: 10000,
easing: 'linear',
loop: true,
update: () => {
let infoWidth = this.$refs.info.offsetWidth
let marqueeWidth = this.$refs.marquee.offsetWidth
let newPosition = infoWidth - ((infoWidth + marqueeWidth) * marquee.scroll)
this.$refs.marquee.style.left = `${newPosition}px`
}
})

Spotify and Apple Music powered Radio

If you’ve followed some of my projects from this year, you’ll know that I’ve been building a lot of custom software around the Spotify Developer platform and Apple Music MusicKit JS platform. This project is no different as we integrated both to power full track streaming and the ability for users to save the playlist directly to their account. For more info on building a custom player, check out this Lamb of God case study. On the topic of saving playlists, check out the Tycho Weather app.

Simple Snowfall with Particles.js

While I knew we were going to add some shakeable snow to our app, I also wanted to add a bit of passive snowfall so the interface always had something compelling and festive to look at. This is typically done with a particle system and it only took a quick Google search to find Vincent Garreau’s excellent Particles.js library. Particles.js is a light-weight library for creating particle systems. All you need to do is include the library and adjust an extensively customizable JSON configuration to get the effect you want. For our snow globe, I just wanted some simple square particles which would visually match the shakeable bodies I would add later.

Shakeable Snow with Matter.js

Our snow globe wouldn’t be much of a snow globe if users didn’t have the ability to shake things. As it turns out, the liquid physics within a snow globe are highly complicated as they are generated by a mix of oil and water. This gives the particles very interesting random movements. While I did research emulating this effect, I instead landed on using a 2d physics library which would allow particles to tumble around the globe area when shaken.

The first thing we’ll need to do is access Device Motion on the device. For instructions on doing this, I would suggest checking out the article I wrote on the subject. Once you are successfully receiving Device Motion events, you can include Alex Gibson’s shake.js library to detect when the user aggressively shakes the event. Adjust the threshold variable to detect less hectic shakes.

let shakeEvent = new Shake({
threshold: 10,
timeout: 1000
})
shakeEvent.start();window.addEventListener('shake', function() {
// do something with shake!
}, false);

Then we’ll need a library to add some physical bodies to our snow globe. I’ve been wanting to use Matter.js on a project for a long time and it did not disappoint. Get started by reading their Getting Started docs. The first thing you want to do is create a new Matter.js engine and add a low y axis gravity so snow falls slowly. You can then initialize a renderer which references this engine.

let engine = Engine.create()engine.world.gravity.y = 0.01
engine.world.gravity.x = 0
let render = Render.create({
element: document.getElementById('globe'),
engine: engine
})

It’s then important to add four walls surrounding your globe so snow particles have something to bounce off of. These 4 thick static rectangles also prevent objects from flying out of the world bounds.

let options = {
isStatic: true
}
let w = width
let h = height
World.add(engine.world, [
Bodies.rectangle(w / 2, 250, w + 500, 500, options),
Bodies.rectangle(w / 2, h + 250, w + 500, 500, options),
Bodies.rectangle(w + 250, h / 2, 500, h + 500, options),
Bodies.rectangle(250, h / 2, 500, h + 500, options)
])

With walls in place, we can now add some snow particles. These are similar rectangular bodies but they are not static and receive further options that define how they react physically. Let’s add 300 of them.

Array.from(Array(300), (_, i) => {
let options = {
density: 0.0001,
friction: 0,
restitution: 1,
collisionFilter: {
group: -1
},
label: 'snow',
render: {
fillStyle: 'white',
opacity: Common.random(0.5, 1)
}
}
let body = Bodies.Rectangle(
w * Common.random(),
h,
Common.Random(4, 12),
Common.Random(4, 12),
options
)
Body.rotate(body, Common.random(0, 360)) World.add(engine.world, body)
}

The physics options configured above were mostly found via a bit of trial and error. The collisionFilter option prevents snow particles from bouncing off of each other. The random() helper Matter provides helps randomize several features such as placement, size, opacity, and rotation.

All that’s left is sending our snow particles flying when the user shakes their device. We can do this by selecting all of the non static bodies from our world and applying a random force to them.

let bodies = Composition.allBodies(engine.world)bodies.forEach(body => {
if (!body.isStatic) {
let force = 0.05 * body.mass
Body.applyForce(body, body.position, {
x: (force + Common.random() * force * Common.choose([1, -1]),
y: -force + Common.random() * -force
})
}
})

Shaking your device will send the particles flying, and the physical properties you defined will have them slowly settle back to the bottom of the snow globe.

Managing Customizations with Contentful

Another important aspect to this campaign was bringing in customization for each track we included in the snow globe. To do this, we integrated Contentful to allow the client to configure several settings for each track.

  1. Colors — the colors of the snowflakes
  2. Vinyl — the color of the vinyl record
  3. Marquee — the color of the LED marquee display

In addition, we also included the ability to add small images which would be included as special items within the snow globe. These images were then added as physical bodies using Matter.js alongside the snow particles. For information on how I integrate Contentful into my projects, check out this article.

Thanks

Thanks again to Lorenzo and Moritz for bringing me in on this project. Be sure to check out Snow Globe Radio today. What’s your favorite Holiday song?

Written by

I develop websites for rock 'n' roll bands and get paid in sex and drugs. Previously Silva Artist Management, SoundCloud, and Songkick. Currently: Available

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store