* {
  margin: 0; padding: 0;
}
var features = {
  num: 0.5,
  str: 0.5,
  arr: 0.5,
  mutate: 0.6,

  chance: function(v) {
    return Math.random() <= v;
  },

  choose: function(a, b, type) {
    if (features.chance(type)) {
      return a;
    } else {
      return b;
    }
  },

  lerp: function(a, b, f) {
    f += Math.random() * (features.mutate * 2) - features.mutate;
    return a + f * (b - a);
  },

  mix: function(a, b) {
    // unmixable types
    if (typeof a !== typeof b) {
      return choose(a, b, features.mutate);

      // numbers
    } else if (
      typeof a === "number" ||
      (typeof parseFloat(a) === "number" && !isNaN(parseFloat(a)))
    ) {
      return parseInt(features.lerp(a, b, features.num));

      // strings
    } else if (typeof a === "string") {
      return features.choose(a, b, features.str);

      // arrays
    } else if (Array.isArray(a)) {
      return a.foreEach(function(v, i) {
        return features.mix(v, b[i]);
      });

      // objects
    } else if (typeof a === "object") {
      return features.breed(a, b);
    }
  },

  breed: function(a, b) {
    var aProps = Object.keys(a),
      bProps = Object.keys(b),
      c = {},
      t;

    if (bProps.length > aProps.length) {
      t = a;
      a = b;
      b = t;
    }

    for (var prop in a) {
      c[prop] = features.mix(a[prop], b[prop]);
    }
    return c;
  }
};

function col() {
  return box({
    r: parseInt(Math.random() * 255),
    g: parseInt(Math.random() * 255),
    b: parseInt(Math.random() * 255)
  });
}

function box(rgb) {
  var r = rgb.r,
    g = rgb.g,
    b = rgb.b,
    // @TODO convert to jQuery and use expando on node
    el = document.createElement("div");
  el.setAttribute("class", "swatch");
  // document.body.prepend(el);
  document.body.insertBefore(el, document.body.firstChild)
  el.style.height = "70px";
  el.style.width = "20%";
  el.style.float = "left";
  el.style.margin = "0px";
  el.style.cursor = "pointer";
  el.style.background = "rgb(" + r + ", " + g + ", " + b + ")";
  el.rgb = rgb;
  return el;
}

// interaction

var parents = [],
  isTouch = "ontouchstart" in document.documentElement,
  start;

function touch(e) {
  var oldParents;

  if (isTouch && start != document.body.scrollTop) return;

  if (!e.target.rgb) return;
  parents.push(e.target);
  e.target.style.WebkitBoxShadow =
    "inset 0px 0px 0px 15px rgba(255, 255, 255, 0.8)";
  if (parents.length == 2) {
    for (var i = 0; i < 5; i++) {
      box(features.breed(parents[0].rgb, parents[1].rgb));
    }

    oldParents = parents.concat();
    setTimeout(function() {
      oldParents.forEach(function(p) {
        p.style.WebkitBoxShadow = "";
      });
    }, 100);
    parents = [];
  }
  start = false;
}

if (isTouch) {
  document.addEventListener("touchstart", function() {
    start = document.body.scrollTop;
  });
  document.addEventListener("touchend", touch);
} else {
  document.addEventListener("click", touch);
}

// create
for (var i = 0; i < 50; i++) {
  col();
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.