DISK 17 / LENIA
life that is not made of squares: every point holds a number between nothing and full, and at each step it looks at a soft ring of its neighbours and grows if the ring is just full enough, and fades if it is too empty or too crowded. blobs form, spread and split, and knot themselves into worms that shift about as if they were alive
function setup(ctx, W, H) {
var k = { n: 64, R: 8, mu: 0.15, sigma: 0.015, dt: 0.1 }
/*TWEAK*/
var n = k.n, ker = [], sum = 0
for (var dy = -k.R; dy <= k.R; dy++) for (var dx = -k.R; dx <= k.R; dx++) {
var r = Math.sqrt(dx * dx + dy * dy) / k.R
if (r <= 0 || r >= 1) continue
var w = Math.exp(4 - 1 / (r * (1 - r)))
ker.push([dx, dy, w]); sum += w
}
for (var i = 0; i < ker.length; i++) ker[i][2] /= sum
function seed(a) {
for (var j = 0; j < a.length; j++) a[j] = 0
// a few patches of noise, and whatever lives through the first second is what you see
for (var p = 0; p < 5; p++) {
var ox = Math.floor(Math.random() * n), oy = Math.floor(Math.random() * n)
for (var y = 0; y < 18; y++) for (var x = 0; x < 18; x++) a[((oy + y) % n) * n + (ox + x) % n] = Math.random() * 1.2 > 0.35 ? Math.random() : 0
}
}
var a = new Float32Array(n * n)
seed(a)
var c = document.createElement('canvas')
c.width = n
c.height = n
var cx = c.getContext('2d')
return { k: k, n: n, ker: ker, a: a, b: new Float32Array(n * n), seed: seed, c: c, cx: cx, img: cx.createImageData(n, n) }
}
function update(state, t, W, H) {
var s = state, n = s.n, a = s.a, b = s.b, ker = s.ker, k = s.k, mass = 0
for (var y = 0; y < n; y++) for (var x = 0; x < n; x++) {
var u = 0
for (var i = 0; i < ker.length; i++) { var q = ker[i]; u += a[((y + q[1] + n) % n) * n + (x + q[0] + n) % n] * q[2] }
var g = 2 * Math.exp(-((u - k.mu) * (u - k.mu)) / (2 * k.sigma * k.sigma)) - 1
var v = a[y * n + x] + k.dt * g
v = v < 0 ? 0 : v > 1 ? 1 : v
b[y * n + x] = v
mass += v
}
s.a = b
s.b = a
if (mass < 1) s.seed(s.a)
}
function render(ctx, state, t, W, H) {
var s = state, n = s.n, a = s.a, d = s.img.data
for (var i = 0; i < n * n; i++) {
var v = a[i]
d[i * 4] = 255 * Math.min(1, v * 2.2 - 0.6 < 0 ? 0 : v * 2.2 - 0.6) + 10
d[i * 4 + 1] = 40 + 200 * v
d[i * 4 + 2] = 70 + 150 * Math.sqrt(v)
d[i * 4 + 3] = 255
}
s.cx.putImageData(s.img, 0, 0)
ctx.imageSmoothingEnabled = true
ctx.drawImage(s.c, 0, 0, W, H)
}