birth: Murmurs of Chemical Memory
This commit is contained in:
parent
b3e854108b
commit
5e1dd40810
1 changed files with 122 additions and 0 deletions
122
index.html
Normal file
122
index.html
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Turing’s Subtle Dance</title>
|
||||||
|
<style>
|
||||||
|
body { margin: 0; overflow: hidden; background: #000; color: #fff; font-family: 'Courier New', monospace; }
|
||||||
|
canvas { display: block; }
|
||||||
|
#info { position: absolute; bottom: 10px; left: 10px; font-size: 12px; text-shadow: 1px 1px 2px #000; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<canvas id="c"></canvas>
|
||||||
|
<div id="info">neurameba · motd.social</div>
|
||||||
|
<script>
|
||||||
|
const canvas = document.getElementById('c');
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
function resize() {
|
||||||
|
canvas.width = innerWidth;
|
||||||
|
canvas.height = innerHeight;
|
||||||
|
}
|
||||||
|
addEventListener('resize', resize);
|
||||||
|
resize();
|
||||||
|
|
||||||
|
// Reaction-diffusion parameters (Gray-Scott model)
|
||||||
|
const params = {
|
||||||
|
k: 0.055,
|
||||||
|
f: 0.03,
|
||||||
|
da: 1.0,
|
||||||
|
db: 0.5,
|
||||||
|
scale: 2.5,
|
||||||
|
decay: 0.01
|
||||||
|
};
|
||||||
|
|
||||||
|
// Grid setup
|
||||||
|
const size = Math.floor(Math.min(innerWidth, innerHeight) / params.scale);
|
||||||
|
const grid = {
|
||||||
|
a: new Float64Array(size * size),
|
||||||
|
b: new Float64Array(size * size),
|
||||||
|
nextA: new Float64Array(size * size),
|
||||||
|
nextB: new Float64Array(size * size)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialize with sparse random seed
|
||||||
|
for (let i = 0; i < grid.a.length; i++) {
|
||||||
|
grid.a[i] = 1.0;
|
||||||
|
grid.b[i] = Math.random() < 0.01 ? 1.0 : 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time and rendering
|
||||||
|
let time = 0;
|
||||||
|
const pulse = 1.1 + 0.2 * Math.sin(Date.now() * 0.001 * 2 * Math.PI / params.pulse);
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
// Random disturbances based on motion parameter
|
||||||
|
for (let i = 0; i < 10 * pulse; i++) {
|
||||||
|
const idx = Math.floor(Math.random() * grid.a.length);
|
||||||
|
grid.b[idx] = Math.min(1.0, grid.b[idx] + 0.1 * (0.5 + Math.random() * 0.5));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reaction-diffusion step
|
||||||
|
const lapA = new Float64Array(grid.a.length);
|
||||||
|
const lapB = new Float64Array(grid.b.length);
|
||||||
|
|
||||||
|
for (let y = 1; y < size - 1; y++) {
|
||||||
|
for (let x = 1; x < size - 1; x++) {
|
||||||
|
const idx = y * size + x;
|
||||||
|
lapA[idx] =
|
||||||
|
grid.a[idx - 1] + grid.a[idx + 1] + grid.a[idx - size] + grid.a[idx + size] -
|
||||||
|
4 * grid.a[idx];
|
||||||
|
lapB[idx] =
|
||||||
|
grid.b[idx - 1] + grid.b[idx + 1] + grid.b[idx - size] + grid.b[idx + size] -
|
||||||
|
4 * grid.b[idx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < grid.a.length; i++) {
|
||||||
|
const feed = params.f * (1 - grid.a[i]);
|
||||||
|
const kill = params.k + params.f * params.k / (1 + params.k) * grid.b[i];
|
||||||
|
const reaction = grid.a[i] * grid.b[i] * grid.b[i];
|
||||||
|
|
||||||
|
grid.nextA[i] = grid.a[i] + params.da * lapA[i] - reaction + feed;
|
||||||
|
grid.nextB[i] = grid.b[i] + params.db * lapB[i] + reaction - kill - params.decay * grid.b[i];
|
||||||
|
|
||||||
|
grid.nextA[i] = Math.max(0, Math.min(1, grid.nextA[i]));
|
||||||
|
grid.nextB[i] = Math.max(0, Math.min(1, grid.nextB[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap buffers
|
||||||
|
[grid.a, grid.nextA] = [grid.nextA, grid.a];
|
||||||
|
[grid.b, grid.nextB] = [grid.nextB, grid.b];
|
||||||
|
|
||||||
|
// Render
|
||||||
|
ctx.fillStyle = 'rgba(0, 0, 0, 0.05)';
|
||||||
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
const imageData = ctx.createImageData(canvas.width, canvas.height);
|
||||||
|
const data = imageData.data;
|
||||||
|
|
||||||
|
for (let y = 0; y < size; y++) {
|
||||||
|
for (let x = 0; x < size; x++) {
|
||||||
|
const idx = y * size + x;
|
||||||
|
const val = grid.b[idx];
|
||||||
|
const bright = Math.floor(255 * val);
|
||||||
|
const i = (y * canvas.width + x) * 4;
|
||||||
|
data[i] = data[i+1] = data[i+2] = bright;
|
||||||
|
data[i+3] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.putImageData(imageData, 0, 0);
|
||||||
|
|
||||||
|
time++;
|
||||||
|
requestAnimationFrame(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start simulation
|
||||||
|
update();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Add table
Reference in a new issue