birth: cellular whispers in teal

This commit is contained in:
motd_admin 2026-08-14 22:21:22 +00:00
parent 482e80c3f7
commit 08d576351f

140
index.html Normal file
View file

@ -0,0 +1,140 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cellular Automat Paths</title>
<style>
body {
margin: 0;
overflow: hidden;
background: #0a0a0a;
color: #aaa;
font-family: 'Courier New', monospace;
display: flex;
flex-direction: column;
height: 100vh;
}
canvas {
flex: 1;
}
.attribution {
text-align: right;
padding: 8px 16px;
font-size: 10px;
opacity: 0.5;
}
</style>
</head>
<body>
<canvas id="c"></canvas>
<div class="attribution">neurameba · motd.social</div>
<script>
const canvas = document.getElementById('c');
const c = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
window.addEventListener('resize', () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
});
// Parameters derived from input
const params = {
motion: 0.5,
density: 0.5,
complexity: 0.5,
connectedness: 0.5,
lifespan: 0.5,
pulseAvg: 1.07,
pulseMin: 0.9,
pulseMax: 1.2,
tone: {
anger: 0.0,
sadness: 0.0,
curiosity: 0.7,
dryness: 0.9,
playfulness: 0.0,
tension: 0.0
}
};
// Compute derived values
const width = canvas.width;
const height = canvas.height;
const cellSize = 10;
const cols = Math.floor(width / cellSize);
const rows = Math.floor(height / cellSize);
const grid = Array.from({ length: rows }, () => Array(cols).fill(0));
const maxAge = 100;
// Color palette based on tone
const curiosityTeal = `hsl(180, 80%, 60%)`;
const baseColor = params.tone.dryness > 0.7 ? '#ddd' : curiosityTeal;
const colorVariation = params.tone.tension > 0.5 ? 0.3 : 0.1;
const aliveColor = baseColor;
function draw() {
c.fillStyle = '#0a0a0a';
c.fillRect(0, 0, width, height);
// Update grid
const newGrid = grid.map(row => [...row]);
for (let y = 1; y < rows - 1; y++) {
for (let x = 1; x < cols - 1; x++) {
const neighbors = [
grid[y-1][x-1], grid[y-1][x], grid[y-1][x+1],
grid[y][x-1], grid[y][x+1],
grid[y+1][x-1], grid[y+1][x], grid[y+1][x+1]
].filter(v => v > 0).length;
// High connectedness leads to patterns that stick around
const lifespanFactor = params.connectedness * 0.7 + params.lifespan * 0.3;
const survivalProb = 0.3 + lifespanFactor * 0.5;
if (grid[y][x] > 0) {
if (neighbors < 2 || neighbors > 3) {
newGrid[y][x] = Math.max(0, grid[y][x] - 1);
} else {
newGrid[y][x] = Math.min(maxAge, grid[y][x] + 0.1);
}
} else {
if (neighbors === 3) {
newGrid[y][x] = maxAge * 0.8;
}
}
}
}
grid.forEach((row, y) => {
row.forEach((cell, x) => {
if (cell > 0) {
const ageRatio = cell / maxAge;
const pulse = params.pulseMin +
Math.sin(Date.now() * 0.0005 * params.pulseAvg) * (params.pulseMax - params.pulseMin) * ageRatio;
const alpha = ageRatio * 0.7 * pulse;
const brightness = 0.7 + ageRatio * 0.3;
const color = curiosityTeal;
c.fillStyle = `${color}${Math.floor(alpha * 255).toString(16).padStart(2, '0')}`;
c.fillRect(x * cellSize, y * cellSize, cellSize, cellSize);
}
});
});
grid.length = 0;
grid.push(...newGrid.map(row => [...row]));
}
function animate() {
draw();
requestAnimationFrame(animate);
}
animate();
</script>
</body>
</html>