birth: Dry Cellular Echoes

This commit is contained in:
motd_admin 2026-09-10 14:21:21 +00:00
parent 37ea9c8bb2
commit 27556c2136

142
index.html Normal file
View file

@ -0,0 +1,142 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Generative Cellular Echo</title>
<style>
body {
margin: 0;
overflow: hidden;
background: #0a0a0a;
font-family: 'Courier New', monospace;
color: #333;
}
#container {
position: relative;
width: 100vw;
height: 100vh;
}
#attribution {
position: absolute;
bottom: 10px;
right: 10px;
font-size: 10px;
color: #555;
pointer-events: none;
}
canvas {
display: block;
}
</style>
</head>
<body>
<div id="container">
<canvas id="canvas"></canvas>
<div id="attribution">neurameba · motd.social</div>
</div>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// Set canvas to full window size
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
// Cellular automata parameters
const CELL_SIZE = 8;
const COLUMNS = Math.floor(canvas.width / CELL_SIZE);
const ROWS = Math.floor(canvas.height / CELL_SIZE);
// State arrays
const currentState = new Array(COLUMNS * ROWS).fill(0);
const nextState = new Array(COLUMNS * ROWS).fill(0);
// Initialize with density parameter
function initializeGrid() {
for (let i = 0; i < currentState.length; i++) {
currentState[i] = (Math.random() < 0.5) ? 1 : 0;
}
}
// Game of Life rules with density consideration
function updateGrid() {
const neighbors = [0, 1, 2, 3, 4, 5, 6, 7];
for (let row = 0; row < ROWS; row++) {
for (let col = 0; col < COLUMNS; col++) {
let index = row * COLUMNS + col;
let aliveNeighbors = 0;
for (const neighbor of neighbors) {
const nRow = row + Math.floor((neighbor % 3) - 1);
const nCol = col + Math.floor((neighbor / 3) - 1) - 1;
if (nRow >= 0 && nRow < ROWS && nCol >= 0 && nCol < COLUMNS) {
aliveNeighbors += currentState[nRow * COLUMNS + nCol];
}
}
// Modified rules based on parameters
if (currentState[index] === 1) {
// Survival with tension (high contrast)
nextState[index] = (aliveNeighbors === 2 || aliveNeighbors === 3) ? 1 : 0;
} else {
// Birth with curiosity (teals)
nextState[index] = (aliveNeighbors === 3) ? 1 : 0;
}
}
}
// Swap states
[currentState, nextState] = [nextState, currentState];
}
// Drawing function
function drawGrid() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Monochrome palette for dryness
ctx.fillStyle = '#888';
for (let row = 0; row < ROWS; row++) {
for (let col = 0; col < COLUMNS; col++) {
if (currentState[row * COLUMNS + col] === 1) {
// Use dryness-based color
ctx.fillRect(col * CELL_SIZE, row * CELL_SIZE, CELL_SIZE, CELL_SIZE);
// Add subtle complexity through varying opacity
ctx.globalAlpha = 0.8;
ctx.fillStyle = '#aaa';
ctx.fillRect(col * CELL_SIZE + 1, row * CELL_SIZE + 1,
CELL_SIZE - 2, CELL_SIZE - 2);
ctx.globalAlpha = 1.0;
}
}
}
}
// Animation loop
let frameCount = 0;
function animate() {
// Slow down animation based on motion parameter
if (frameCount % (10 - Math.floor(5 * 0.5)) === 0) {
updateGrid();
drawGrid();
}
frameCount++;
requestAnimationFrame(animate);
}
// Start everything
initializeGrid();
animate();
</script>
</body>
</html>