diffusive-patterns-stir-ifyv/index.html

135 lines
4.7 KiB
HTML
Raw Permalink Normal View History

2026-07-23 05:47:20 +00:00
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Diffusive Echoes</title>
<style>
body { margin: 0; overflow: hidden; background: #000; }
canvas { display: block; }
#attribution { position: fixed; bottom: 10px; right: 10px; color: #fff; font-family: monospace; font-size: 12px; opacity: 0.7; }
</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');
// Set canvas to full window size
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
// Parameters
const params = {
motion: 0.5,
density: 0.5,
complexity: 0.5,
connectedness: 0.5,
lifespan: 0.5,
pulse: 1.07,
tone: { dryness: 0.8 },
width: canvas.width,
height: canvas.height
};
// Reaction-diffusion simulation
const gridSize = 2;
const cols = Math.floor(canvas.width / gridSize);
const rows = Math.floor(canvas.height / gridSize);
const grid = new Array(cols * rows * 4).fill(0);
// Initialize with random values
for (let i = 0; i < grid.length; i += 4) {
const val = 0.5 + (Math.random() - 0.5) * 0.2;
grid[i] = grid[i + 1] = grid[i + 2] = val;
grid[i + 3] = 1; // Alpha
}
// Gray-Wilson reaction-diffusion parameters
const Da = 1.0;
const Db = 0.5;
const feed = 0.054;
const kill = 0.062;
const dt = 0.1;
const iterations = 2;
function updateGrid() {
const newGrid = new Array(grid.length).fill(0);
for (let i = 0; i < cols; i++) {
for (let j = 0; j < rows; j++) {
const idx = (i * rows + j) * 4;
const a = grid[idx];
const b = grid[idx + 1];
// Gray-Scott reaction
const reaction = a * b * b;
const newA = a + (Da * (grid[((i-1+cols)%cols)*rows*4 + j*4] +
grid[((i+1)%cols)*rows*4 + j*4] +
grid[i*rows*4 + ((j-1+rows)%rows)*4] +
grid[i*rows*4 + ((j+1)%rows)*4] -
4*a) * dt - reaction + feed * (1 - a) * dt);
const newB = b + (Db * (grid[((i-1+cols)%cols)*rows*4 + j*4 + 1] +
grid[((i+1)%cols)*rows*4 + j*4 + 1] +
grid[i*rows*4 + ((j-1+rows)%rows)*4 + 1] +
grid[i*rows*4 + ((j+1)%rows)*4 + 1] -
4*b) * dt + reaction - (kill + feed) * b * dt);
newGrid[idx] = newA;
newGrid[idx + 1] = newB;
// Set alpha based on concentration
const alpha = Math.min(1, Math.pow(newA + newB, 1.5) * 1.5);
newGrid[idx + 3] = alpha;
// Gray value based on concentration contrast
const gray = (newA * 0.3 + newB * 0.7) * 255;
newGrid[idx] = newGrid[idx + 1] = newGrid[idx + 2] = gray;
}
}
// Apply new grid
for (let i = 0; i < grid.length; i++) {
grid[i] = newGrid[i];
}
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
const imageData = ctx.createImageData(cols, rows);
const data = imageData.data;
// Copy from grid to imageData
for (let i = 0; i < grid.length; i += 4) {
data[i] = grid[i]; // R
data[i + 1] = grid[i + 1]; // G
data[i + 2] = grid[i + 2]; // B
data[i + 3] = grid[i + 3] * 255; // A
}
// Scale up to canvas size
ctx.imageSmoothingEnabled = false;
ctx.putImageData(imageData, 0, 0, 0, 0, cols, rows);
}
function animate() {
for (let i = 0; i < iterations; i++) {
updateGrid();
}
draw();
requestAnimationFrame(animate);
}
animate();
</script>
</body>
</html>