Skip to content

Instantly share code, notes, and snippets.

@robinhouston
Last active August 29, 2015 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robinhouston/6cfcbff910216ee3abf8 to your computer and use it in GitHub Desktop.
Save robinhouston/6cfcbff910216ee3abf8 to your computer and use it in GitHub Desktop.
Black and white and red all over

Random noise at first, but leave it running for 5–10 minutes and it will slowly become more interesting.

Notionally a numerical solution of a system of differential equations, but the “checkerboard” solution is presumably an artefact of discretisation.

Suggested by Cornus Ammonis

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Reaction-Diffusion</title>
<style>
body { margin: 0; }
#bg { width: 100%; height: 100%; }
</style>
</head>
<body>
<script>
var W = 256, H = 256, N = W*H; // Tile dimensions
var doc = document.documentElement,
canvas = document.createElement("canvas"),
cx = canvas.getContext("2d"),
tile = document.createElement("canvas"),
tcx = tile.getContext("2d");
function resizeCanvas() {
canvas.width = doc.clientWidth;
canvas.height = doc.clientHeight;
}
function init() {
tile.width = W;
tile.height = H;
window.addEventListener("resize", function() {
resizeCanvas();
drawTiles();
}, false);
resizeCanvas();
document.body.appendChild(canvas);
initReactionDiffusion();
startReactionDiffusion();
}
function drawTiles() {
renderTile();
cx.fillStyle = cx.createPattern(tile, "repeat");
cx.fillRect(0, 0, canvas.width, canvas.height);
}
var α, β, af, α1, β1, α2, β2, α3, β3, α4, β4, α_temp, β_temp;
function initReactionDiffusion() {
α = []; β = [];
for (var i=0; i<N; i++) {
α[i] = Math.random() * 100 - 50;
β[i] = Math.random() * 100 - 50;
}
α1 = []; α2 = []; α3 = []; α4 = [];
β1 = []; β2 = []; β3 = []; β4 = [];
α_temp = []; β_temp = [];
}
function frame() {
rk4(f, 0.1);
drawTiles();
af = requestAnimationFrame(frame);
}
function startReactionDiffusion() {
af = requestAnimationFrame(frame);
}
function renderTile() {
var imd = tcx.createImageData(W, H),
d = imd.data;
for (var i=0; i<N; i++) {
var v = ((α[i] + 2) * 25.5)|0;
d[4*i + 0] = v;
d[4*i + 1] = v/2;
d[4*i + 2] = v/2;
d[4*i + 3] = 0xFF;
}
tcx.putImageData(imd, 0, 0);
}
var clampMin = -10,
clampMax = 10,
D_a = 0.001,
D_b = 0.004,
abClampMin = -50,
abClampMax = 50;
function f(α_in, β_in, c, δα, δβ, δα_out, δβ_out) {
var α, β;
if (c == 0) {
α = α_in;
β = β_in;
} else {
α = α_temp;
β = β_temp;
for (var i=0; i<N; i++) {
α[i] = α_in[i] + c*δα[i];
β[i] = β_in[i] + c*δβ[i];
}
}
for (var y=0; y<H; y++) {
for (var x=0; x<W; x++) {
var i = W*y + x,
px = (x+W-1)%W, sx = (x+1)%W,
py = (y+H-1)%H, sy = (y+1)%H;
// Five-point stencil
var laplacian_a = α[W*py+x] + α[W*y+sx] + α[W*sy+x] + α[W*y+px] - 4*α[i],
laplacian_b = β[W*py+x] + β[W*y+sx] + β[W*sy+x] + β[W*y+px] - 4*β[i];
δα_out[i] = Math.max(clampMin, Math.min(clampMax, (D_a * (α[i]*α[i] - β[i]*β[i])) + laplacian_b));
δβ_out[i] = Math.max(clampMin, Math.min(clampMax, (D_b * (2*α[i]*β[i])) - laplacian_a));
}
}
}
function rk4(f, h) {
f(α, β, 0, null, null, α1, β1);
f(α, β, h/2, α1, β1, α2, β2);
f(α, β, h/2, α2, β2, α3, β3);
f(α, β, h, α3, β3, α4, β4);
for (var i=0; i<N; i++) {
α[i] = Math.max(abClampMin, Math.min(abClampMax, α[i] + (h/6) * (α1[i] + 2*α2[i] + 2*α3[i] + α4[i]) ));
β[i] = Math.max(abClampMin, Math.min(abClampMax, β[i] + (h/6) * (β1[i] + 2*β2[i] + 2*β3[i] + β4[i]) ));
}
}
init();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment