signals

by phloe

HTML

<div id="timeline"></div>

<button id="control">play/pause</button>

CSS

#timeline {
  display: flex;
  flex-flow: row nowrap;
  gap: 2px;
  align-items: end;
  height: 200px;
  background-color: #EEE;
}

#timeline > * {
  width: 2px;
  background-color: red;
  flex: 0 0 auto;
}

JavaScript

const samples = 10000;
for (let i = 0; i < samples; i++) {
	timeline.appendChild(document.createElement("div"));
}
let values = [];
function update () {
	values.forEach((value, i) => {
  	timeline.childNodes[i].style.height = (value * 100) + "%";
  });
}

const generators = {
	sine(time) {
    return (Math.cos(time * Math.PI * 2) + 1) / 2;
  },
  triangle(time) {
    return (time <= 0.5 ? time : (0.5 - (time - 0.5))) * 2;
  },
  sawtooth(time) {
    return time;
  },
  square(time) {
    return time < 0.5 ? 0 : 1;
  }
};

const transitions = {
  // no easing, no acceleration
  linear: t => t,
  // accelerating from zero velocity
  easeInQuad: t => t*t,
  // decelerating to zero velocity
  easeOutQuad: t => t*(2-t),
  // acceleration until halfway, then deceleration
  easeInOutQuad: t => t<.5 ? 2*t*t : -1+(4-2*t)*t,
  // accelerating from zero velocity 
  easeInCubic: t => t*t*t,
  // decelerating to zero velocity 
  easeOutCubic: t => (--t)*t*t+1,
  // acceleration until halfway, then deceleration 
  easeInOutCubic: t => t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1,
  // accelerating from zero velocity 
  easeInQuart: t => t*t*t*t,
  // decelerating to zero velocity 
  easeOutQuart: t => 1-(--t)*t*t*t,
  // acceleration until halfway, then deceleration
  easeInOutQuart: t => t<.5 ? 8*t*t*t*t : 1-8*(--t)*t*t*t,
  // accelerating from zero velocity
  easeInQuint: t => t*t*t*t*t,
  // decelerating to zero velocity
  easeOutQuint: t => 1+(--t)*t*t*t*t,
  // acceleration until halfway, then deceleration 
  easeInOutQuint: t => t<.5 ? 16*t*t*t*t*t : 1+16*(--t)*t*t*t*t
};

const duration = 1000;
const freq = 10000;
const amp = 1;

for (let i = 0; i < samples; i++) {
	values.push(generators.sine((i % freq) / freq) * amp * transitions.linear(1 - i / samples));
  i++;
}

update();

let playing;
let frame;
let start;

function play () {
	if (!start) {
  	start = Date.now();
  }
  let elapsed = Date.now() - start;
  timeline.firstChild.style.height = (values[elapsed % samples] *...