Animate 3D buildings based on ambient sounds
Connects the runtime styling API with the Web Audio API, creating a map where the 3D buildings dance to the rhythm of your ambient environment.
Mapbox GL unsupported
Mapbox GL requires WebGL support. Please check that you are using a supported browser and that WebGL is enabled.
<!DOCTYPE html><html><head><meta charset='utf-8' /><title>Animate 3D buildings based on ambient sounds</title><meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' /><script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.53.0/mapbox-gl.js'></script><link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.53.0/mapbox-gl.css' rel='stylesheet' /><style>body { margin:0; padding:0; }#map { position:absolute; top:0; bottom:0; width:100%; }</style></head><body> <div id='map'></div> <script>mapboxgl.accessToken = '<your access token here>';/* global Promise */ // Use a minimal variant of the Mapbox Dark style, with certain features removed.var map = new mapboxgl.Map({style: 'mapbox://styles/examples/cj68bstx01a3r2rndlud0pwpv',center: {lng: -74.00649562332922,lat: 40.70811328605049},zoom: 15,pitch: 55,container: 'map'}); map.addControl(new mapboxgl.FullscreenControl()); map.on('load', function() {var bins = 16;var maxHeight = 200;var binWidth = maxHeight / bins; // Divide the buildings into 16 bins based on their true height, using a layer filter.for (var i = 0; i < bins; i++) {map.addLayer({'id': '3d-buildings-' + i,'source': 'composite','source-layer': 'building','filter': ['all', ['==', 'extrude', 'true'], ['>', 'height', i * binWidth], ['<=', 'height', (i + 1) * binWidth]],'type': 'fill-extrusion','minzoom': 15,'paint': {'fill-extrusion-color': '#aaa','fill-extrusion-height-transition': {duration: 0,delay: 0},'fill-extrusion-opacity': .6}});} // Older browsers might not implement mediaDevices at all, so we set an empty object firstif (navigator.mediaDevices === undefined) {navigator.mediaDevices = {};} // Some browsers partially implement mediaDevices. We can't just assign an object// with getUserMedia as it would overwrite existing properties.// Here, we will just add the getUserMedia property if it's missing.if (navigator.mediaDevices.getUserMedia === undefined) {navigator.mediaDevices.getUserMedia = function (constraints) { // First get ahold of the legacy getUserMedia, if presentvar getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia; // Some browsers just don't implement it - return a rejected promise with an error// to keep a consistent interfaceif (!getUserMedia) {return Promise.reject(new Error('getUserMedia is not implemented in this browser'));} // Otherwise, wrap the call to the old navigator.getUserMedia with a Promisereturn new Promise(function (resolve, reject) {getUserMedia.call(navigator, constraints, resolve, reject);});};} navigator.mediaDevices.getUserMedia({audio: true}).then(function (stream) {// Set up a Web Audio AudioContext and AnalyzerNode, configured to return the// same number of bins of audio frequency data.var audioCtx = new (window.AudioContext || window.webkitAudioContext)(); var analyser = audioCtx.createAnalyser();analyser.minDecibels = -90;analyser.maxDecibels = -10;analyser.smoothingTimeConstant = 0.85; var source = audioCtx.createMediaStreamSource(stream);source.connect(analyser); analyser.fftSize = bins * 2; var dataArray = new Uint8Array(bins); function draw(now) {analyser.getByteFrequencyData(dataArray); // Use that data to drive updates to the fill-extrusion-height property.var avg = 0;for (var i = 0; i < bins; i++) {avg += dataArray[i];map.setPaintProperty('3d-buildings-' + i, 'fill-extrusion-height', 10 + 4 * i + dataArray[i]);}avg /= bins; // Animate the map bearing and light color over time, and make the light more// intense when the audio is louder.map.setBearing(now / 500);map.setLight({color: "hsl(" + now / 100 % 360 + "," + Math.min(50 + avg / 4, 100) + "%,50%)",intensity: Math.min(1, avg / 256 * 10)}); requestAnimationFrame(draw);} requestAnimationFrame(draw);}).catch(function (err) {console.log('The following gUM error occured: ' + err);});});</script> </body></html>