JSFiddle - React, Tailwind, and code Playground

by jcubed111

HTML

<canvas id='main' width=500 height=500></canvas>

JavaScript

function rgba(r, g=r, b=g, a=1.0) {
	return `rgba(${r}, ${g}, ${b}, ${a})`;
}

function clamp(x, min=0, max=1) {
	return Math.max(min, Math.min(max, x));
}

function Vec(...args) {
	class Vec{
    	constructor(x, y) {
            this.x = x;
            this.y = y;
        }
        
        dot(b) {
        	return this.x * b.x + this.y * b.y;
        }
        
        length() {
        	return (this.x**2 + this.y**2)**0.5;
        }
    }
    return new Vec(...args);
}

function slerp(a, b, f) {
	f = 3 * f**2 - 2 * f**3;
    return a*(1-f) + b*f;
}

class PerlinNoise{
	constructor() {
    	this.vectors = {};
    }
    
    at(x, y) {
        const fx = Math.floor(x);
        const fy = Math.floor(y);
        const dx = x - fx;
        const dy = y - fy;
        
        // c d
        // a b
        const a = Vec(dx,   dy  ).dot(this.getVector(fx,   fy  ));
        const b = Vec(dx-1, dy  ).dot(this.getVector(fx+1, fy  ));
        const c = Vec(dx,   dy-1).dot(this.getVector(fx  , fy+1));
        const d = Vec(dx-1, dy-1).dot(this.getVector(fx+1, fy+1));
        
        return slerp(slerp(a, b, dx), slerp(c, d, dx), dy);
    }
    
    getVector(x, y) {
    	if(!this.vectors[x]) {
        	this.vectors[x] = {};
        }
    	if(!this.vectors[x][y]) {
        	const r = Math.random() * Math.PI * 2;
        	this.vectors[x][y] = Vec(Math.cos(r), Math.sin(r));
        }
        return this.vectors[x][y];
    }
}

class RecursivePerlinNoise{
	constructor(depth=1) {
    	this.noises = [];
        for(let i=0; i<depth; i++) {
        	this.noises.push(new PerlinNoise());
        }
    }
    
    at(x, y) {
    	return this.noises.map((n, i) => 2**-i * n.at(x*2**i, y*2**i)).reduce((a, b) => a + b, 0);
    }
}

function colorStop(x, ...stops) {
	for(let i=1; i<stops.length; i+=2) {
    	if(x < stops[i]) {
        	return stops[i-1];
        }
    }
    return stops[stops.length-1];
}

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