murmurs-of-chemical-memory-.../index.html

122 lines
No EOL
4.2 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Turings 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>