JSFiddle - React, Tailwind, and code Playground

by honnza

HTML

<canvas id=c width=100 height=100></canvas>
<label><input type=checkbox id=hires />high resolution pallette</label>
<label><input type=checkbox id=force />show force</label>
<button id=dbl_f>double the frequency</button>

CSS

label{
    display:block;
}
canvas{
    width:300px;
}

JavaScript

var c = document.getElementById("c");
var hires = document.getElementById("hires");
var eForce = document.getElementById("force");
var h = c.height;
var w = c.width;
var ctx = c.getContext("2d");
var x, y;
var id = ctx.getImageData(0, 0, w, h);
var off = -2 / 3 * Math.PI;
var lastFrame = Array(h),
    nextFrame = Array(h);

var force_coeff = 1/8;

function gamma(x) {
    return 192 + 64 * x;
}

function paint(id, index, hue) {
    id.data[index] = gamma(Math.cos(hue));
    id.data[index + 1] = gamma(Math.cos(hue + off));
    id.data[index + 2] = gamma(Math.cos(hue + 2 * off));
    id.data[index + 3] = 255;
}

for (y = 0; y < h; y++) {
    lastFrame[y] = Array(w);
    nextFrame[y] = Array(w);
    for (x = 0; x < w; x++) {
        nextFrame[y][x] = Math.random() * 2 * Math.PI;
        paint(id, 4 * (x + y * w), nextFrame[y][x]);
    }
}

var timer = setTimeout;

var onFrame = function () {
    var tmp = lastFrame;
    var show_force = eForce.checked;
    var hue_coeff = (hires.checked?16:1) * (show_force?16:1);
    lastFrame = nextFrame;
    nextFrame = tmp;
    for (y = 0; y < h; y++) {
        for (x = 0; x < w; x++) {
            var cur = lastFrame[y][x];
            var force = 0;
            force += Math.sin(lastFrame[(y || h) - 1][(x || w) - 1] - cur);
            force += Math.sin(lastFrame[(y || h) - 1][x] - cur);
            force += Math.sin(lastFrame[(y || h) - 1][(x + 1) % w] - cur);
            force += Math.sin(lastFrame[y][(x + 1) % w] - cur);
            force += Math.sin(lastFrame[(y + 1) % h][(x + 1) % w] - cur);
            force += Math.sin(lastFrame[(y + 1) % h][x] - cur);
            force += Math.sin(lastFrame[(y + 1) % h][(x || w) - 1] - cur);
            force += Math.sin(lastFrame[y][(x || w) - 1] - cur);
            nextFrame[y][x] = cur + force * force_coeff;
            paint(id, 4 * (x + y * w), hue_coeff*(show_force ?force:nextFrame[y][x]));
        }
    }
    ctx.putImageData(id, 0, 0);
    timer(onFrame);
}

ctx.putImageData(id,...