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,...