JSFiddle - React, Tailwind, and code Playground

HTML

<script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<canvas width="400" height="400"></canvas>

CSS

canvas {
    border: 1px solid black;
}

JavaScript

var canvas = $('canvas')[0];
var context = canvas.getContext('2d');
var size = 100;
var cellSize = 400 / size;
var board = [];

for (var i = 0; i < size; i++) {
	board[i] = [];
    for (var j = 0; j < size; j++) {
        board[i][j] = i < size / 2 ? (j < size / 2 ? 'red' : 'blue') : (j < size / 2 ? 'black' : 'green');
    }
}

function getRandomNeighbor(board, x, y) {
	var neighbors = [];
    for (var i = -1; i <= 1; i++) {
    	for (var j = -1; j <= 1; j++) {
    		if (board[x + i] && board[x + i][y + j]) {
    			neighbors.push(board[x + i][y + j]);
    		}
	    }
    }
    
    // clump bias
    if (_.countBy(neighbors)[board[x][y]] > 7) {
        return board[x][y];
    } else {
        return _.sample(neighbors);
    }
}

function update() {
    var nextGeneration = [];
    
    for (var i = 0; i < size; i++) {
        nextGeneration[i] = [];
        for (var j = 0; j < size; j++) {
            nextGeneration[i][j] = getRandomNeighbor(board, i, j);
        }
    }
    
    board = nextGeneration;
}

function draw() {
    for (var i = 0; i < size; i++) {
        for (var j = 0; j < size; j++) {
            context.fillStyle = board[i][j];
            context.fillRect(i * cellSize, j * cellSize, cellSize, cellSize);
        }
    }
    context.fill();
}

function step() {
    update();
    draw();
}

setInterval(step, 40);