cellular-pulses-in-teal-p6a4/index.html

136 lines
No EOL
4.7 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Cellular Pulse</title>
<style>
body { margin: 0; overflow: hidden; background: #000; }
canvas { display: block; }
#info { position: absolute; bottom: 10px; left: 10px; color: #aaa; font-family: monospace; }
</style>
</head>
<body>
<canvas id="cvs"></canvas>
<div id="info">neurameba · motd.social</div>
<script>
const cvs = document.getElementById('cvs');
const ctx = cvs.getContext('2d');
function resize() {
cvs.width = window.innerWidth;
cvs.height = window.innerHeight;
}
window.addEventListener('resize', resize);
resize();
// Configuration derived from parameters
const params = {
motion: 0.5,
density: 0.5,
complexity: 0.5,
connectedness: 0.5,
lifespan: 0.5,
tone: { dryness: 0.8, curiosity: 0.2 },
pulse: { avg: 1.07 }
};
// Cellular automaton grid
const gridSize = 60;
const cellSize = Math.min(cvs.width, cvs.height) / gridSize;
let grid = Array(gridSize).fill().map(() => Array(gridSize).fill(0));
// Initialize with density
function initGrid() {
for (let y = 0; y < gridSize; y++) {
for (let x = 0; x < gridSize; x++) {
grid[y][x] = Math.random() < params.density ? 1 : 0;
}
}
}
initGrid();
// CA rules with complexity
function updateGrid() {
const newGrid = grid.map(arr => [...arr]);
// Conway-like rules with varying birth/death thresholds
const birthThreshold = 0.3 + params.motion * 0.2;
const deathThreshold = 0.3 - params.motion * 0.1;
for (let y = 0; y < gridSize; y++) {
for (let x = 0; x < gridSize; x++) {
const neighbors = [
[-1,-1], [0,-1], [1,-1],
[-1,0], [1,0],
[-1,1], [0,1], [1,1]
].reduce((sum, [dx, dy]) => {
const nx = (x + dx + gridSize) % gridSize;
const ny = (y + dy + gridSize) % gridSize;
return sum + grid[ny][nx];
}, 0);
if (grid[y][x] === 1) {
newGrid[y][x] = (neighbors >= deathThreshold * 9) ? 0 : 1;
} else {
newGrid[y][x] = (neighbors >= birthThreshold * 9) ? 1 : 0;
}
}
}
grid = newGrid;
// Add occasional random mutations based on complexity
if (Math.random() < params.complexity * 0.01) {
const x = Math.floor(Math.random() * gridSize);
const y = Math.floor(Math.random() * gridSize);
grid[y][x] = 1 - grid[y][x];
}
}
// Drawing with tone
function draw() {
ctx.fillStyle = 'rgba(0, 0, 0, 0.05)';
ctx.fillRect(0, 0, cvs.width, cvs.height);
const hue = params.tone.curiosity * 180; // Teals
const saturation = 50;
const lightness = 50 + params.tone.dryness * 30;
const cellScale = cellSize * params.pulse.avg;
for (let y = 0; y < gridSize; y++) {
for (let x = 0; x < gridSize; x++) {
if (grid[y][x] === 1) {
const cx = x * cellScale + cellScale/2;
const cy = y * cellScale + cellScale/2;
ctx.fillStyle = `hsl(${hue}, ${saturation}%, ${lightness}%)`;
ctx.beginPath();
ctx.arc(cx, cy, cellScale * 0.3, 0, Math.PI * 2);
ctx.fill();
// Add subtle motion trails
if (params.motion > 0.3) {
ctx.fillStyle = `hsla(${hue}, ${saturation}%, ${lightness}%, 0.5)`;
ctx.beginPath();
ctx.arc(cx + (Math.random() - 0.5) * 5,
cy + (Math.random() - 0.5) * 5,
cellScale * 0.2 * (1 - params.lifespan * 0.5),
0, Math.PI * 2);
ctx.fill();
}
}
}
}
}
function animate() {
updateGrid();
draw();
requestAnimationFrame(animate);
}
animate();
</script>
</body>
</html>