JSFiddle - React, Tailwind, and code Playground

by jcubed111

HTML

<canvas id="main"></canvas>

CSS

body{
    margin: 0;
    background: #504b41;
}

JavaScript

const canvas = document.getElementById('main');
const ctx = canvas.getContext('2d');

Array.prototype.shuffle = function() {
	for(let i = this.length - 1; i > 0; i--){
        const j = Math.floor(Math.random() * i);
        [this[i], this[j]] = [this[j], this[i]];
	}
    return this;
};

const Point = (x, y) => ({
	x: x,
    y: y,
    hash: function() { return `${this.x},${this.y}`; },
});

class Edge{
	constructor(from, to) {
    	this.from = from;
        this.to = to;
        this.age = 0;
    }
}

const edges = [];
const takenPoints = new Set(["0,0"]);
let fringePoints = [Point(0, 0)];

function grow() {
	const firstGrowChance = 0.1;
    const secondGrowChance = 0.3;
    
	fringePoints = fringePoints.shuffle().flatMap(from => {
    	const newEdges = [
        	Point(from.x + 1, from.y),
        	Point(from.x - 1, from.y),
        	Point(from.x, from.y + 1),
        	Point(from.x, from.y - 1),
        ].filter(
        	to => !takenPoints.has(to.hash())
        ).shuffle().filter((_, i) => {
        	if(i == 0) {
            	return Math.random() < firstGrowChance;
            }else{
            	return Math.random() < secondGrowChance;
            }
        });
        
        newEdges.forEach(to => {
        	newEdges.push(new Edge(from, to));
            takenPoints.add(to.hash());
        });
        
        if(newEdges.length) {
        	return newEdges.map(e => e.to);
        }else{
        	return [from];
        }
    });
}

function render() {
	canvas.width = innerWidth;
    canvas.height = innerHeight;
    
	ctx.setTransform(1, 0, 0, 1, innerWidth >> 1, innerHeight >> 1);
    
    edges.forEach(e => {
    	ctx.beginPath();
        ctx.moveTo(e.from.x, e.from.y);
        ctx.lineTo(e.to.x, e.to.y);
        ctx.stroke();
    });
}


grow(); grow(); grow();
render();