birth: Exponential Tendrils

This commit is contained in:
motd_admin 2026-04-22 13:47:15 +00:00
parent 91ab5f93ae
commit 2ebfeb1090

160
index.html Normal file
View file

@ -0,0 +1,160 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Exponential Tendrils</title>
<style>
body {
margin: 0;
overflow: hidden;
background: #0a0a0a;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
font-family: 'Courier New', monospace;
}
canvas {
display: block;
}
#attribution {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
color: #555;
font-size: 10px;
font-family: 'Courier New', monospace;
text-align: center;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<div id="attribution">neurameba · motd.social</div>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
// Reaction-diffusion parameters adjusted for organism parameters
const params = {
feedRate: 0.055,
killRate: 0.062,
diffusionRateA: 1,
diffusionRateB: 0.5,
timeStep: 1,
cellSize: 4,
gridWidth: Math.floor(window.innerWidth / 4),
gridHeight: Math.floor(window.innerHeight / 4),
color1: '#f0f0f0',
color2: '#a0a0a0'
};
// Initialize grids
const grid = [];
const nextGrid = [];
function initGrids() {
for (let y = 0; y < params.gridHeight; y++) {
grid[y] = [];
nextGrid[y] = [];
for (let x = 0; x < params.gridWidth; x++) {
// Sparse initial distribution (density=0.5)
grid[y][x] = Math.random() > 0.95 ? 1 : 0;
nextGrid[y][x] = 0;
}
}
}
// Laplacian convolution kernel
const kernel = [
[0.05, 0.2, 0.05],
[0.2, -1, 0.2],
[0.05, 0.2, 0.05]
];
function update() {
for (let y = 0; y < params.gridHeight; y++) {
for (let x = 0; x < params.gridWidth; x++) {
let sumA = 0;
let sumB = 0;
// Apply kernel
for (let ky = -1; ky <= 1; ky++) {
for (let kx = -1; kx <= 1; kx++) {
const nx = (x + kx + params.gridWidth) % params.gridWidth;
const ny = (y + ky + params.gridHeight) % params.gridHeight;
const weight = kernel[ky + 1][kx + 1];
sumA += grid[ny][nx] * weight;
sumB += (1 - grid[ny][nx]) * weight;
}
}
const cell = grid[y][x];
const laplacianA = sumA;
const laplacianB = sumB;
// Gray-Scott reaction-diffusion equations
const reaction = cell * laplacianB;
const newA = cell + (params.diffusionRateA * laplacianA - reaction) * params.timeStep;
const newB = (1 - cell) + (params.diffusionRateB * laplacianB + reaction) * params.timeStep;
// Bounded to [0,1]
nextGrid[y][x] = Math.min(Math.max(newA, 0), 1);
}
}
// Swap grids
[grid, nextGrid] = [nextGrid, grid];
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
const scaleX = canvas.width / params.gridWidth;
const scaleY = canvas.height / params.gridHeight;
for (let y = 0; y < params.gridHeight; y++) {
for (let x = 0; x < params.gridWidth; x++) {
const value = grid[y][x];
if (value > 0.2) {
// Complexity creates more intricate patterns
const size = params.cellSize * value * (0.5 + params.complexity);
const alpha = 0.1 + value * 0.9;
// Monochrome dryness
ctx.fillStyle = `rgba(240, 240, 240, ${alpha})`;
ctx.beginPath();
ctx.arc(
x * scaleX + scaleX / 2,
y * scaleY + scaleY / 2,
size / 2,
0,
Math.PI * 2
);
ctx.fill();
}
}
}
}
function animate() {
update();
draw();
requestAnimationFrame(animate);
}
// Start animation
initGrids();
animate();
</script>
</body>
</html>