> ## Content Index
> Fetch the complete content index at: https://www.hypebot.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Converting Weather Into Music With Dark Sky, Spotify For Tycho
- URL: https://www.hypebot.com/converting-weather-into-music-with-dark-sky-spotify-for-tycho/
- Published: 2019-08-26T09:19:58.000Z
- Updated: 2019-08-26T09:19:58.000Z
- Description: In a unique algorithmic twist, Tycho recently teamed up with Lee Martin to craft an app which employs the user's local weather forecast in order to create custom weather-based playlist.. Continue reading [https://www.hypebot.com/hypebot/2019/08/converting-weather-into-music-with-dark-sky-spotify-for
- Author: Guest Author
- Tags: Apps, Mobile & SMS, Music Tech, Streaming, music, Music Business, music industry, musician, musicians, Spotify, Weather, #wp, #wp-post, #Import 2026-01-21 09:55

[![Screen Shot 2019-08-25 at 10.58.56 AM](https://hypebot.typepad.com/.a/6a00d83451b36c69e20240a4a3faec200d-200wi "Screen Shot 2019-08-25 at 10.58.56 AM")](https://hypebot.typepad.com/.a/6a00d83451b36c69e20240a4a3faec200d-popup?ref=hypebot.com)

In a unique algorithmic twist, Tycho recently teamed up with Lee Martin to craft an app which employs the user's local weather forecast in order to create custom weather-based playlist. Here Martin walks us through the process of the app's creation, and how it works.

\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

*Guest post by *Lee Martin.* This article originally appeared on [Medium](https://medium.com/@leemartin/turning-weather-into-music-with-dark-sky-and-spotify-for-tycho-f4f40aef97ed?ref=hypebot.com)*Yesterday, Tycho and I released [Forecast](https://weather.tychomusic.com/?ref=hypebot.com), an app which uses your local weather forecast to generate a unique [Spotify](https://medium.com/u/60a317bb70e4?source=post%5Fpage-----f4f40aef97ed----------------------) and Apple Music playlist. Not only was this a fun developer challenge, it was also an opportunity to work with Scott (Tycho) directly on design. I think the concept works because it meets each of the three principles I strive for: Simple, Accessible, and Magic. It’s simple in that the user merely needs to tap the sun in order to invest themselves in the app. It’s accessible via the web from a url. No downloading needed. And it turns the fucking weather into music! That’s magic.The sweet design doesn’t hurt either.These days users want to put themselves *within* the app and location is one of those readily available variables which can make the experience more unique. I’ve used it to similar effect when [terrifying](https://medium.com/@leemartin/wkwyfl-43879e3348ac?source=friends%5Flink&sk=1c6173a3414d114dffea41bb12e826e1) Manson’s following and allowing Khruangbin fans to [generate music](https://medium.com/@leemartin/come-fly-the-funky-skies-with-khruangbin-7c08ea9930a3?source=friends%5Flink&sk=4b2432c43a6ecec67eaba526d0a522ec) for upcoming flights. Just don’t be creepy with location data.So, how does one turn the weather into music? Read on to find out.

## Getting the Forecast

## ![Cloudy and rainy](https://storage.ghost.io/c/3a/95/3a957c06-c825-4057-9939-0a274cc16d23/content/images/miro-medium-com/max/1600/1_tuvlr-awqlbn5qdif99htw.jpg)

Icons by TychoIt all starts with a pair of coordinates which you can get by using the [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation%5FAPI?ref=hypebot.com). In addition, I’m using the MaxMind [GeoIP](https://dev.maxmind.com/geoip/?ref=hypebot.com) service as a fallback in case something goes wrong. MaxMind will turn the user’s IP address into a location which is a solid fallback for a weather app.navigator.geolocation.getCurrentPosition(response => {  
 // response.coords.latitude  
 // response.coords.longitude  
}, error => {  
 geoip2.city(response => {  
 // response.location.latitude  
 // response.location.longitude  
 }, error => {  
 // ok, something really went wrong  
 })  
})With coordinates now available it’s time to get the forecast. Dark Sky is a popular weather [app](https://darksky.net/forecast/40.7127,-74.0059/us12/en?ref=hypebot.com) (the one I use) which also has an excellent and affordable [API](https://darksky.net/dev/docs?ref=hypebot.com) for getting past, current, and future weather conditions. I’ve actually used it at least once before on the [Purple Rain Report](http://purplerain.report/?ref=hypebot.com). The endpoint we’re most interested in is [forecast](https://darksky.net/dev/docs?ref=hypebot.com#forecast-request) which takes a pair of coordinates and returns the weather. But first, let’s talk about my setup.I am a recent [Netlify](https://medium.com/u/5250f9d9bd2f?source=post%5Fpage-----f4f40aef97ed----------------------) convert and I simply can’t get enough of how this platform has streamlined my workflow. I’m able to run their platform right from my computer using [Netlify Dev](https://www.netlify.com/products/dev/?ref=hypebot.com) which keeps all my environment variables synced. In addition, Netlify also allows you to easily deploy serverless [functions](https://www.netlify.com/docs/functions/?ref=hypebot.com) which can also be tested locally with Dev. Functions are a perfect solution to meet Dark Sky’s security [requirement](https://darksky.net/dev/docs/faq?ref=hypebot.com#faq-api-features) of making calls via your server. Ya know, without the server.To initialize a function, I might use the Netlify [CLI](https://cli.netlify.com/commands/functions?ref=hypebot.com) command:netlify function create --name forecastWith your function created, you can write it very simply. I’m using the [node-fetch](https://www.npmjs.com/package/node-fetch?ref=hypebot.com) module which brings `window.fetch` to Node.js to hit the Dark Sky API with a pair of coordinates passed as parameters to the Netlify function. Here’s a [gist](https://gist.github.com/leemartin/4cc931c94eca5abcd5419d31be42b906?ref=hypebot.com) to get you going.Finally, if you’re using Netlify Dev, you can test your function locally by simply sending a request to the appropriate endpoint. In the case of a function called “forecast,” it would be accessed from `/.netlify/functions/forecast`. So, once I obtain those coordinates, I can send a fetch request from my client to receive the user’s current weather conditions.fetch(\`/.netlify/functions/forecast?latitude=${lat}&longitude=${lon}\`)  
.then(response => response.json())  
.then(data => {  
 // data.currently  
})  
  
Correlating Weather to Audio Features

## ![Sun swipe](https://storage.ghost.io/c/3a/95/3a957c06-c825-4057-9939-0a274cc16d23/content/images/miro-medium-com/max/2500/1_0tdaszsz7jhadh16_jwgqa.jpg)

Dark Sky sends over a lot of interesting [data](https://darksky.net/dev/docs?ref=hypebot.com#data-point-object) about the current weather. The next step is to relate that data somehow to features of an audio track. In previous projects such as [Sadboi Detector](https://medium.com/@leemartin/sad-boi-5457970fb8d5?source=friends%5Flink&sk=12fd8f4bc538917d08265aed459b1db7) and [AirKhruang](https://medium.com/@leemartin/come-fly-the-funky-skies-with-khruangbin-7c08ea9930a3?source=friends%5Flink&sk=4b2432c43a6ecec67eaba526d0a522ec), I have utilized the track audio [features](https://developer.spotify.com/documentation/web-api/reference/tracks/get-audio-features/?ref=hypebot.com) Spotify provides such as valence and energy. In the case of this app, we looked at several audio features and simply chose which weather measurement might symbolically relate. For example, a gusty day might produce tracks with a higher tempo. Or the temperature might affect the *valence* or mood of the songs. We took liberty in these connections and just had fun with out.Most of these properties on Spotify run from a scale of `0.0` to `1.0`. Somehow I was going to need to create a similar scale for the weather measurements being utilized. I ended up researching the a average, max, and minimum of each of these and then used a normalization function to convert them into the scale I desired.let normalize = (val, min, max) => {  
 return Math.max(0, Math.min(1, (val - min) / (max - min)))  
}For example, if the average wind speed in the United States is 9mph, I could say that is `0.5` on our scale. Making 0mph equal to `0.0` and 18mph equal to `1.0`. It’s not very scientific but it works. Once you do this for everything, you’re left with an array of data which represents all of the weather properties, the audio feature they relate to, and their normalized value.let measures = \[  
 {  
 property: 'wind',  
 feature: 'tempo',  
 value: normalize(wind, 0, 18)  
 }  
\]I then loop through each of these measures, sorting the entire song list by feature values which are *nearest* to the normalized weather value. This sorted songs list is then used to increment the score of a song depending on its position in the stack. This process is continued for each measurement until all song scores are adjusted accordingly.measures.forEach(measure => {  
 songs.sort((a, b) => {  
 let aValue = a.features\[measure.feature\]  
 let bValue = b.features\[measure.feature\] return Math.abs(aVal - measure.value) - Math.abs(bVal - measure.value)  
 }) songs.forEach((song, i) => {  
 let score = \_.round(1 - (i / (songs.length - 1)), 3)  
  
 song.score += score  
 })  
})Songs are sorted by score and then the app takes the 25 highest scorers. Finally, the the selected tracks are shuffled, producing a playlist.songs.sort((a, b) => {  
 return a.score - b.score  
}).reverse()let playlist = \_.shuffle(\_.take(songs, 25))It’s worth mentioning that I integrated [Contentful](https://medium.com/u/5a131a53c7b2?source=post%5Fpage-----f4f40aef97ed----------------------) as the system where we manage our pool of songs. The client was also provided with two UI extensions for easily searching Spotify and Apple Music songs from within the comfort of Contentful. Check out this [blog](https://medium.com/js-dojo/how-to-use-asyncdata-to-integrate-contentful-into-nuxt-fbf53ca56fa9?ref=hypebot.com) for info on how I integrate Contentful into my app framework of choice [Nuxt.js](https://medium.com/u/20f059d252cc?source=post%5Fpage-----f4f40aef97ed----------------------). In addition, I wrote an [article](https://medium.com/@leemartin/developing-an-apple-music-search-into-contentful-using-ui-extensions-c0a68d759210?ref=hypebot.com) on extending Contentful to include streaming service search fields.

## Design and Transitions

Scott and I worked through the design in just two phone calls.On the first call, I explained how this app like others I have developed should be very simple to understand and quick to use. A utility. I explained the issues surrounding responsive design and recommended a mobile first approach. While I’m no expert on transitions, I told Scott to go nuts and we would figure everything out as soon as he presented a vision. On the second call, Scott presented this wonderful design in Photoshop and walked me through some thoughts of how the transitions could work, dragging elements with the move tool. He truly kept it simple, focused, and fun.Rather than jump straight to code, I decided to open up Framer Classic as a quick way to prototype some of the transitions. I broke that work up into three chunks: the intro, the creation sequence, and reveal of the save buttons. This allowed us to easily test ideas about transitions and timing without getting bogged down by *too much* code. Once we were confident in the general approach, I then jumped to [CodePen.IO](https://medium.com/u/2d397c502771?source=post%5Fpage-----f4f40aef97ed----------------------) and scripted the entire animation sequence as one long playback using the incredible animation library [Anime.js](https://animejs.com/?ref=hypebot.com). Only then did I attempt to start integrating it into the flow of our application.Anime has this great [Timeline](https://animejs.com/documentation/?ref=hypebot.com#timelineBasics) function which allows you to string multiple element animations together. For example, if we think abstractly for a moment, the frontpage consists of three elements: the sky, water, and sun. We know we want the water to rise in from the bottom and then have the sun scale in from the center horizon. First, we lay it out.I experimented with several different HTML layouts but decided to contain the sky and water in a *flexed* box and position the sun absolute in the dead center of the page. Here’s some simplified code:<main>  
 <div id="sun"></div>  
 <section id="sky"></section>  
 <section id="water"></section>  
</main><style>  
main{  
 display: flex;  
 flex-direction: column;  
}div#sun{  
 height: 50vw;  
 left: 50%;  
 position: absolute;  
 top: 50%;  
 transform: translate(-50%, -50%) scale(0);  
 width: 50vw;  
}section#sky{  
 flex: 1;  
}  
</style>That `flex: 1` allows the sky to take up the full height of the page initially and I don’t think I need to tell you what `scale(0)` does to the sun. With this layout, we can then script our Anime timeline.let tl = anime.timeline()tl.add({  
 targets: '#water',  
 height: '50%'  
})tl.add({  
 targets: '#sun'  
 scale: 1  
})Pretty nice, right? What about a pulsating sun? Try adding a `loop`parameter and setting the direction to `alternate`.let pulse = anime({  
 targets: '#sun',  
 scale: 0.9,  
 direction: 'alternate',  
 loop: true,  
 easing: 'linear'  
}) If you declare it, like I did above with `pulse`, you also have some nice controls are your disposal like `anime.pause()`. Ok, what about that pie swipe effect? Well… that took a few tries. My first attempt utilized a [rotating div](https://www.smashingmagazine.com/2015/07/designing-simple-pie-charts-with-css/?ref=hypebot.com)which “hid” a section by the sun by actually just *showing* sky. I then got fancy and integrated the poorly supported (but coming) [conic gradient](https://css-tricks.com/snippets/css/css-conic-gradient/?ref=hypebot.com) until someone told me my sun disappeared on Firefox. This led me to revisit my best friend, HTML5 canvas.In addition to animating dom nodes, Anime will allow us to animate any old javascript object. So, if I combined that with the HTML5 canvas [arc](https://www.w3schools.com/tags/canvas%5Farc.asp?ref=hypebot.com)function, I might have something. Here’s what that looks like.let sun = { hidden: 0 }anime({  
 targets: sun,  
 duration: 500,  
 hidden: 180,  
 easing: 'linear',  
 update: () => {  
 let canvas = document.getElementById('canvas')  
 let context = canvas.getContext('2d') context.fillStyle = 'yellow' context.clearRect(0, 0, canvas.width, canvas.height) context.beginPath()  
 context.moveTo(canvas.width / 2, canvas.height / 2)  
 context.arc(  
 canvas.width / 2,  
 canvas.height / 2,  
 canvas.width / 2,  
 0,  
 hidden \* (Math.PI / 180),  
 true  
 )  
 context.closePath()  
 context.fill()  
 }  
})

## Thanks

Thanks again to all the fine folks at [Mom + Pop](https://twitter.com/MomAndPopMusic?ref=hypebot.com), Another Planet, and NinjaTune who helped make this experience happen. It was an absolute pleasure working with this crew the last few weeks. And thanks to Scott for believing in the concept and then providing the whole damn design to make it happen. Tycho “Weather” is [out now](https://tycho.lnk.to/weatherAP?ref=hypebot.com).