diff options
Diffstat (limited to 'docs/assets/js')
| -rw-r--r-- | docs/assets/js/cielab.js | 70 | ||||
| -rw-r--r-- | docs/assets/js/player.js | 79 | ||||
| -rw-r--r-- | docs/assets/js/shards.js | 107 | ||||
| -rw-r--r-- | docs/assets/js/site.js | 72 | ||||
| -rw-r--r-- | docs/assets/js/sounds.js | 17 | ||||
| -rw-r--r-- | docs/assets/js/stars.js | 63 | ||||
| -rw-r--r-- | docs/assets/js/util.js | 139 |
7 files changed, 547 insertions, 0 deletions
diff --git a/docs/assets/js/cielab.js b/docs/assets/js/cielab.js new file mode 100644 index 0000000..14c096f --- /dev/null +++ b/docs/assets/js/cielab.js @@ -0,0 +1,70 @@ +var cielab = (function(){ + var cielab = {} + + var xyz = [0,0,0] + var rgb = [0,0,0] + + L_range = [0, 100] + a_range = [-86.185, 98.254] + b_range = [-107.863, 94.482] + + cielab.gradient = function (n) { + n = n || 100 + var k = 0 + + var L, a, b + + var L0 = randrange(L_range[0] + 50, L_range[1]) + var L1 = randrange(L_range[0]+ 50, L_range[1]) + var a0 = randrange(a_range[0], a_range[1]) + var a1 = randrange(a_range[0], a_range[1]) + var b0 = randrange(b_range[0], b_range[1]) + var b1 = randrange(b_range[0], b_range[1]) + return function next (aa){ + L = mix(k/n, L0, L1) + a = mix(k/n, a0, a1) + b = mix(k/n, b0, b1) + rgb = xyz2rgb(hunterlab2xyz(L, a, b)) + k += 1 + return rgba_string(rgb, aa) + } + } + function rgba_string (rgb, a) { return "rgba(" + rgb.map(Math.round).join(",") + "," + a + ")" } + function hex_string (rgb) { return "#" + rgb.map(Math.round).map(function(n){ var s = n.toString(16); return s.length == 1 ? "0"+s : s }).join("") } + + function mix(n,a,b){ return n*a + (1-n)*b } + function clamp(n,a,b){ return n<a?a:n<b?n:b } + function hunterlab2xyz (L,a,b) { + var_Y = L / 10 + var_X = a / 17.5 * L / 10 + var_Z = b / 7 * L / 10 + + Y = Math.pow(var_Y, 2) + X = ( var_X + Y ) / 1.02 + Z = -( var_Z - Y ) / 0.847 + xyz = [X,Y,Z] + } + function xyz2rgb(){ + var var_X = xyz[0] / 100 //X from 0 to 95.047 (Observer = 2°, Illuminant = D65) + var var_Y = xyz[1] / 100 //Y from 0 to 100.000 + var var_Z = xyz[2] / 100 //Z from 0 to 108.883 + + var_R = var_X * 3.2406 + var_Y * -1.5372 + var_Z * -0.4986 + var_G = var_X * -0.9689 + var_Y * 1.8758 + var_Z * 0.0415 + var_B = var_X * 0.0557 + var_Y * -0.2040 + var_Z * 1.0570 + + if ( var_R > 0.0031308 ) var_R = 1.055 * Math.pow( var_R, 1 / 2.4 ) - 0.055 + else var_R = 12.92 * var_R + if ( var_G > 0.0031308 ) var_G = 1.055 * Math.pow( var_G, 1 / 2.4 ) - 0.055 + else var_G = 12.92 * var_G + if ( var_B > 0.0031308 ) var_B = 1.055 * Math.pow( var_B, 1 / 2.4 ) - 0.055 + else var_B = 12.92 * var_B + + rgb[0] = clamp(var_R * 255, 0, 255) + rgb[1] = clamp(var_G * 255, 0, 255) + rgb[2] = clamp(var_B * 255, 0, 255) + return rgb + } + + return cielab +})()
\ No newline at end of file diff --git a/docs/assets/js/player.js b/docs/assets/js/player.js new file mode 100644 index 0000000..25fdfd6 --- /dev/null +++ b/docs/assets/js/player.js @@ -0,0 +1,79 @@ +const player = (function(){ + let player = {} + let current_index = -1 + let audio = document.createElement('audio') + let tracks = [ + { file: "mp3/xena_vectra-cruise.mp3", title: "Cruise" }, + { file: "mp3/xena_vectra-dreaming_city_2.mp3", title: "Dreaming City 2" }, + { file: "mp3/xena_vectra-escape_from_nk.mp3", title: "Escape from Neukölln" }, + ] + function init(){ + bind() + build() + // play(0) + } + function bind(){ + audio.addEventListener('play', handlePlay) + audio.addEventListener('pause', handlePause) + audio.addEventListener('ended', handleEnded) + document.querySelector('.player .icon').addEventListener('click', togglePlaying) + document.querySelector('.player .track').addEventListener('click', play) + document.querySelector('.player .playlistToggle').addEventListener('click', togglePlaylist) + } + function build() { + tracks.forEach((track, i) => { + let el = document.createElement('li') + el.innerHTML = track.title + el.addEventListener('click', () => { + if (is_mobile) { + hidePlaylist() + } + shards.rebuild() + play(i) + }) + document.querySelector('.playlist ul').appendChild(el) + }) + document.querySelector('.player .track').innerHTML = tracks[0].title + } + function play(n){ + const active = document.querySelector('.playlist ul .active') + if (active) active.classList.remove('active') + document.querySelector('.playlist ul').children[n].classList.add('active') + + current_index = (n + tracks.length) % tracks.length + audio.src = tracks[n].file + audio.play() + document.querySelector('.player .track').innerHTML = tracks[n].title + } + function handlePlay(){ + document.querySelector('.player').classList.add('playing') + document.querySelector('.player').classList.remove('paused') + shards.step() + } + function handlePause(){ + document.querySelector('.player').classList.remove('playing') + document.querySelector('.player').classList.add('paused') + } + function handleEnded(){ + shards.rebuild() + play(current_index+1) + } + function togglePlaying() { + // sounds.play('click') + if (current_index == -1) { + play(0) + } else { + if (audio.paused) audio.play() + else audio.pause() + } + } + function togglePlaylist() { + site.navigateHash('') + document.querySelector('.playlist').classList.toggle('visible') + } + function hidePlaylist() { + document.querySelector('.playlist').classList.remove('visible') + } + init() + return { hidePlaylist } +})()
\ No newline at end of file diff --git a/docs/assets/js/shards.js b/docs/assets/js/shards.js new file mode 100644 index 0000000..1b374ee --- /dev/null +++ b/docs/assets/js/shards.js @@ -0,0 +1,107 @@ +const shards = (function(){ + let count + let delay = 120 * 1000 + let els = [] + let t = 0 + let rebuilding = false + let nextTimeout + let dark, light + const bg_el = document.querySelector('.bgs') + + function init(){ + bind() + build() + step() + setTimeout(next, 20) + bg_el.classList.remove('fade') + } + function bind(){ + document.querySelector('h1').addEventListener('click', () => { + sounds.play('click') + rebuild() + site.navigateHash('') + player.hidePlaylist() + }) + } + function build(){ + count = choice(is_mobile ? [5,7] : [5,7,7,11,11]) + light = cielab.gradient(count) + dark = cielab.gradient(count) + let el + for (var i = 0; i < count; i++) { + el = append(i) + } + } + function destroy(){ + for (var i = 0; i < count; i++) { + els[i] && bg_el.removeChild(els[i]) + } + els.length = 0 + } + function rebuild(){ + if (rebuilding) return + rebuilding = true + // sounds.play('click') + stars.rebuild() + next() + t = 0 + bg_el.classList.add('fade') + setTimeout(() => { + destroy() + build() + step() + setTimeout(next, 20) + bg_el.classList.remove('fade') + rebuilding = false + // sounds.play('click') + }, 500) + } + function append(i){ + const el = document.createElement('div') + el.classList.add('bg') + els.push(el) + bg_el.appendChild(el) + return el + } + function next(){ + clearTimeout(nextTimeout) + nextTimeout = setTimeout(next, delay) + step() + } + function step() { + t += 1 + light = cielab.gradient(count) + let w = { min: is_mobile ? randrange(40, 90) : randrange(20, 40), max: randrange(10, 90) } + if (w.min > w.max) { + w.min += 10 + } + let rot = { min: randint(360), max: randrange(720, 1080) } + for (var i = 0; i < count; i++) { + update(i, t, w, rot, dark, light) + } + document.body.style.backgroundColor = cielab.gradient(2)(0.05) + } + function update(i, t, w, rot){ + const el = els[i] + const n = i / count + const side = lerp(n, w.min, w.max) + const spin = lerp(i % 2 ? (1-n) : (n), rot.min, rot.max) + const rotation = "rotate3d(" + [randrange(-1,1), randrange(-1,1), randrange(-1,1)].join(',') + ',' + randint(360) + "deg)" + el.style.width = side + 'vmin' + el.style.height = side + 'vmin' + el.style.transform = "translate3d(-50%, -50%, 0) rotate(" + spin + "deg) translate3d(50%, 50%, 0) " + rotation + // el.style.transform = "translate3d(-50%, -50%, 0)" + if (t === 1) { + light = cielab.gradient(count) + if (is_mobile) { + el.style.backgroundImage = 'linear-gradient(0deg, ' + dark(1) + ', ' + light(1) + ')' + } else { + el.style.backgroundImage = 'linear-gradient(0deg, ' + dark(1) + ', ' + light(0) + ')' + } + } + el.style.backgroundColor = light(1) + el.style.opacity = lerp(n, randrange(0.1, 0.4), randrange(0.2, 0.5)) + } + init() + return { rebuild: rebuild, step: step, } +})()
\ No newline at end of file diff --git a/docs/assets/js/site.js b/docs/assets/js/site.js new file mode 100644 index 0000000..bff06bb --- /dev/null +++ b/docs/assets/js/site.js @@ -0,0 +1,72 @@ +const site = (function(){ + let section + let links = toArray(document.querySelectorAll('.menu a')) + let time = new Date() + let hour = time.getHours() + let quotes = [ + "So, are softsynths as nasty as they say?", + "Ah, a hardware person, I get it.", + "You have to make space to leave space.", + "Those waveforms are more powerful than we realize.", + "And that sub-oscillator? W-O-W!", + "Get in there, sweep the filter and give yourself a pat on the back. In that order.", + "Not a museum. Move along.", + "I've got to get out of this studio and back out there.", + ] + if (hour < 8 || hour > 16) { + document.body.parentNode.classList.add('night') + } else { + document.body.parentNode.classList.add('day') + } + preload('img/pause-inv.png') + setTimeout(() => { + document.body.classList.remove('loading') + navigateHash(window.location.hash) + const email = atob("eGVuYXZlY3RyYTkwOUBnbWFpbC5jb20=") + const twitter = atob("dmVjdHJheGVuYQ==") + document.querySelector("#email_addr").href = 'mailto:' + email + document.querySelector("#email_addr").innerHTML = email + document.querySelector("#twitter_addr").innerHTML = twitter + document.querySelector("#twitter_addr").href = 'https://twitter.com/' + twitter + }, 0) + toArray(document.querySelectorAll('.menu a')).forEach(a => { + a.addEventListener("click", e => { + e.preventDefault() + sounds.play('click') + console.log(e.target) + if (e.target.nodeName.toLowerCase() !== 'a') { + navigateHash(e.target.parentNode.href) + } else { + navigateHash(e.target.href) + } + }) + }) + function navigateHash(url){ + if (is_mobile) { + player.hidePlaylist() + } + let new_section = (url || "").split('#')[1] + if (section) { + document.body.classList.remove(section) + links.forEach(link => link.classList.remove('active')) + } + if (new_section && new_section !== section) { + if (new_section.match('hardware')) { + document.querySelector('#quote').innerHTML = choice(quotes) + } + document.body.classList.add(new_section) + links.forEach(link => link.getAttribute('href').match(new_section) && link.classList.add('active')) + section = new_section + } else { + section = null + } + // window.location.hash = section || "" + } + function preload(src) { + const img = new Image + img.src = src + } + return { + navigateHash: navigateHash + } +})() diff --git a/docs/assets/js/sounds.js b/docs/assets/js/sounds.js new file mode 100644 index 0000000..39f725d --- /dev/null +++ b/docs/assets/js/sounds.js @@ -0,0 +1,17 @@ +const sounds = (function(){ + let sounds = {} + let els = {} + sounds.add = (fn) => { + const el = document.createElement('audio') + el.src = 'sounds/' + fn + '.mp3' + els[fn] = el + } + sounds.play = (fn) => { + const el = els[fn] + el.currentTime = 0 + el.volume = 0.8 + el.play() + } + sounds.add('click') + return sounds +})() diff --git a/docs/assets/js/stars.js b/docs/assets/js/stars.js new file mode 100644 index 0000000..0637473 --- /dev/null +++ b/docs/assets/js/stars.js @@ -0,0 +1,63 @@ +const stars = (function(){ + var canvas = document.createElement("canvas"), ctx = canvas.getContext('2d') + var s = Math.sin, c = Math.cos + document.addEventListener("DOMContentLoaded", function(){ + document.body.appendChild(canvas) + canvas.classList.add('stars') + canvas.style.width="100%" + canvas.style.height="100%" + canvas.style.position="fixed" + canvas.style.top="0px" + canvas.style.left="0px" + canvas.style.zIndex=-1 + document.body.addEventListener("resize", build) + // document.body.parentNode.style.backgroundColor="black" + ctx.strokeStyle="white" + build() + }) + function ri(n){ return Math.random() * n } + function rr(a,b){ return (b-a) * Math.random() + a } + function build(){ + var w = canvas.width = window.innerWidth * window.devicePixelRatio + var h = canvas.height = window.innerHeight * window.devicePixelRatio + ctx.clearRect(0,0,w,h) + var n = Math.sqrt(w*h)|0 + while (n--) { + var x = ri(w) + var y = ri(h) + var r0 = rr(0, 1) + var r1 = rr(0, 1) + var r2 = rr(0, 1) + var t0 = ri(2*Math.PI) + var t1 = ri(2*Math.PI) + var t2 = ri(2*Math.PI) + var x0 = x+c(t0)*r0 + var y0 = y+s(t0)*r0 + var x1 = x+c(t1)*r1 + var y1 = y+s(t1)*r1 + var x2 = x+c(t2)*r2 + var y2 = y+s(t2)*r2 + ctx.beginPath() + ctx.moveTo(x,y) + ctx.bezierCurveTo(x0,y0,x1,y1,x2,y2) + var color = rr(0, 255)|0 + ctx.strokeStyle="rgb("+color+","+color+","+color+")" + ctx.stroke() + } + } + let rebuilding = false + function rebuild(){ + if (rebuilding) return + rebuilding = true + canvas.classList.add('fade') + document.body.classList.add('fade') + setTimeout(() => { + // destroy() + build() + canvas.classList.remove('fade') + document.body.classList.remove('fade') + rebuilding = false + }, 500) + } + return { rebuild: rebuild } +})()
\ No newline at end of file diff --git a/docs/assets/js/util.js b/docs/assets/js/util.js new file mode 100644 index 0000000..e40db4a --- /dev/null +++ b/docs/assets/js/util.js @@ -0,0 +1,139 @@ +const is_iphone = (navigator.userAgent.match(/iPhone/i)) || (navigator.userAgent.match(/iPod/i)) +const is_ipad = (navigator.userAgent.match(/iPad/i)) +const is_android = (navigator.userAgent.match(/Android/i)) +const is_mobile = is_iphone || is_ipad || is_android +const is_desktop = !is_mobile; +document.body.parentNode.classList.add(is_desktop ? 'desktop' : 'mobile') + +function avg(a,b,n){ return (a*(n-1) + b)/n } +function rand(n){ return Math.random()*n } +function randint(n) { return ~~(Math.random()*n) } +function randrange(a,b){ return a+rand(b-a) } +function choice(a) { return a[randint(a.length)] } +function clamp(n,a,b) { return a > n ? a : n > b ? b : n } +function sign(n){ return n < 0 ? -1 : 1 } +function mod(n,m){ return n-(m * Math.floor(n/m)) } +function lerp(n,a,b){ return (b-a)*n+a } +function quantize(m,n){ return n * ((m/n)|0) } + +function randgauss (obj, jog) { + var radius = Math.random() * jog + var angle = Math.random() * Math.PI * 2 + obj.left += Math.sin(angle) * radius + obj.top += Math.cos(angle) * radius +} + +function shuffle(a){ + for (var i = a.length; i > 0; i--){ + var r = randint(i) + var swap = a[i-1] + a[i-1] = a[r] + a[r] = swap + } + return a +} + +function toArray (els){ + return Array.prototype.slice.apply(els) +} + +// easing functions +function circular (t) { return Math.sqrt( 1 - ( --t * t ) ) } +function quadratic (t) { return t * ( 2 - t ) } +function back (t) { + var b = 4; + return ( t = t - 1 ) * t * ( ( b + 1 ) * t + b ) + 1; +} +function bounce (t) { + if (t >= 1) return 1; + if ( ( t /= 1 ) < ( 1 / 2.75 ) ) { + return 7.5625 * t * t; + } else if ( t < ( 2 / 2.75 ) ) { + return 7.5625 * ( t -= ( 1.5 / 2.75 ) ) * t + 0.75; + } else if ( t < ( 2.5 / 2.75 ) ) { + return 7.5625 * ( t -= ( 2.25 / 2.75 ) ) * t + 0.9375; + } else { + return 7.5625 * ( t -= ( 2.625 / 2.75 ) ) * t + 0.984375; + } +} +function elastic (t) { + var f = 0.22, + e = 0.4; + + if ( t === 0 ) { return 0; } + if ( t == 1 ) { return 1; } + + return ( e * Math.pow( 2, - 10 * t ) * Math.sin( ( t - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 ); +} + +function preload (url) { + var img = new Image () + var loaded = false, _cb + img.onload = function(){ + if (loaded) return + loaded = true + if (_cb) { _cb(img) } + } + img.src = url + if (img.complete) { img.onload() } + return { + then: function(cb){ + if (loaded) { cb(img) } + else { _cb = cb } + } + } +} + +function preloadImages () { + var images = toArray(document.getElementById("images").children) + var count = 0, ready = false, _cb + images.forEach(function(img){ + var loaded = false + img.onload = function(){ + if (loaded) return + loaded = true + done(img) + } + if (img.complete) { img.onload() } + }) + function done () { + if (++count == images.length && ! ready) { + ready = true + _cb && _cb() + } + } + return { + then: function(cb){ + if (ready) { cb() } + else { _cb = cb } + } + } +} + +function smoothstep(min,max,n){ + var t = clamp((n - min) / (max - min), 0.0, 1.0); + return t * t * (3.0 - 2.0 * t) +} + +function detrand (x,y) { + return (Math.sin( x * 12.9898 + y * 78.233 ) * 43758.5453) % 1 +} + +function gray_to_transparency(img) { + var canvas = document.createElement("canvas") + var ctx = canvas.getContext('2d') + var nw = img.naturalWidth, nh = img.naturalHeight + canvas.width = nw + canvas.height = nh + ctx.drawImage(img,0,0) + var pixels = ctx.getImageData(0,0,nw,nh) + var data = pixels.data + for (var i = 0, len = nw*nh*4; i < len; i += 4) { + data[i+3] = data[i] + data[i] = data[i+1] = data[i+2] = 255 + } + ctx.putImageData(pixels,0,0) + return canvas +} + +var TWO_PI = 2*Math.PI
\ No newline at end of file |
