JSFiddle - React, Tailwind, and code Playground

by Jeremy Gillick

HTML

<form>
  <p>
    <label>From</label>
    <input type="number" id="from-r" value="255" />
    <input type="number" id="from-g" value="0" />
    <input type="number" id="from-b" value="0" />
  </p>
  <p>
    <label>To</label>
    <input type="number" id="to-r" value="0" />
    <input type="number" id="to-g" value="255" />
    <input type="number" id="to-b" value="0" />
  </p>
  <p>
    <label>Time</label>
    <input type="number" id="time" value="1500" />
  </p>
  <p>
    <button type="button">
      Go
    </button>
  </p>
</form>
<div id="preview">
</div>
<ul id="frames">
</ul>

CSS

body {
  font-family: helvetica neue;
}
label {
  display: inline-block;
  min-width: 3em;
  text-align: right;
}
input[type=number] {
  width: 4em;
}
#preview {
  height: 100px;
  width: 100px;
  border: 1px solid #000;
  margin: 15px auto;
}
#frames {
  list-style-type: none;
  margin: 15px;
  padding: 0;
}
#frames li {
  height: 10px;
  width: 10px;
  display: inline-block;
  border: 1px solid #000;
}

JavaScript

(function(){
	var animateTimer;
	var increments = [];

	function fadeIncrements(fromColor, toColor, duration) {
	  increments = [0, 0, 0];

    if (duration > 0) {
      for (let i = 0; i < 3; i++) {
        let diff = toColor[i] - fromColor[i];

        if (diff != 0) {
          increments[i] = diff / duration;
        }
      }
    }
    return increments;
  }
  
  function buildFrames(from, to, duration) {
  	var currentColor = from.slice(0),
        frameCount = 40,
        perFrame = duration / 40,
        frameList = $('#frames');
    
    frameList.empty();
    for (var i = 0; i < frameCount; i++) {
      var li = document.createElement('li');
      
	    currentColor = currentColor.map( (c, n) => {
      	if (increments[n] == 0) return c;
        return c + (increments[n] * perFrame);
      });
      
      console.log(currentColor);
      var cssColor = currentColor.map( (c) => { 
        return Math.round(c); 
      });
      cssColor = 'rgb('+ cssColor.join(',') +')';
      li.style.backgroundColor = cssColor;
      frameList.append(li);
    }
  }
  
  function animate(from, to, duration) {
  	var preview = $('#preview'),
    		lastFade = (new Date()).getTime(),
    		currentColor = from.slice(0),
        targetColor = to.slice(0),
        timeLeft = duration;
    
    clearTimeout(animateTimer);
    
    function run() {
    	let now = (new Date()).getTime(),
        	diff = now - lastFade;
      
      if (diff > 1) {      
        timeLeft -= diff;
        lastFade = now;

        // Increment all 3 colors
        for (let i = 0; i < 3; i++) {
          if (increments[i] == 0) continue;
          currentColor[i] += (increments[i] * diff);
        }


        // Done, reverse fade
        if (timeLeft <= 0) {
          timeLeft = duration;
          increments = increments.map( (i) => i * -1);
        }

        // Update color in preview
        var cssColor = currentColor.map( (c) => { 
        	return Math.round(c); 
        });
        cssColor...