fading-currents-of-obscure-.../index.html

179 lines
No EOL
5.8 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Neurameba · motion.social</title>
<style>
body { margin: 0; overflow: hidden; background: #000; }
canvas { display: block; }
#info {
position: absolute;
bottom: 10px;
right: 10px;
color: #333;
font-family: monospace;
font-size: 10px;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<div id="info">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 derived from the abstract specification
const params = {
motion: 0.310,
density: 0.841,
complexity: 0.549,
connectedness: 0.464,
lifespan: 0.473,
pulse: { avg: 0.41, min: 0.30, max: 1.25 },
tone: { dryness: 0.90, curiosity: 0.10 }
};
// Simulation grid
const gridSize = 60;
const cols = Math.floor(canvas.width / gridSize);
const rows = Math.floor(canvas.height / gridSize);
let grid = new Array(cols * rows).fill(0);
let nextGrid = new Array(cols * rows).fill(0);
// Reaction-diffusion parameters
// Simplified Gray-Scott model with dryness emphasis
const F = 0.055;
const K = 0.062;
const DA = 1.0;
const DB = 0.5;
// Initialize with patterns based on complexity
function initializeGrid() {
const centerX = Math.floor(cols / 2);
const centerY = Math.floor(rows / 2);
const radius = Math.min(centerX, centerY) * 0.4;
for (let i = 0; i < cols; i++) {
for (let j = 0; j < rows; j++) {
const index = i * rows + j;
const dx = i - centerX;
const dy = j - centerY;
const distance = Math.sqrt(dx * dx + dy * dy);
// Pattern variation based on complexity
if (distance < radius) {
grid[index] = 1;
} else {
grid[index] = (Math.random() * params.complexity < 0.05) ? 0.5 : 0;
}
}
}
}
// Update simulation with motion sensitivity
function updateGrid() {
const timeFactor = params.pulse.avg;
const motionFactor = params.motion * 2;
for (let x = 0; x < cols; x++) {
for (let y = 0; y < rows; y++) {
const i = x * rows + y;
let a = grid[i];
let b = nextGrid[i];
// Gray-Scott reaction
const laplacianA = calculateLaplacian(x, y, a);
const laplacianB = calculateLaplacian(x, y, b);
const reaction = a * b * b;
const newA = a + (DA * laplacianA - reaction + F * (1 - a)) * motionFactor;
const newB = b + (DB * laplacianB + reaction - (F + K) * b) * motionFactor;
nextGrid[i] = Math.max(0, Math.min(1, newB));
}
}
// Swap grids
[grid, nextGrid] = [nextGrid, grid];
}
// Calculate 8-way laplacian for diffusion
function calculateLaplacian(x, y, value) {
let sum = 0;
let count = 0;
for (let dx = -1; dx <= 1; dx++) {
for (let dy = -1; dy <= 1; dy++) {
if (dx === 0 && dy === 0) continue;
const nx = x + dx;
const ny = y + dy;
if (nx >= 0 && nx < cols && ny >= 0 && ny < rows) {
sum += grid[nx * rows + ny] - value;
count++;
}
}
}
return sum / count;
}
// Draw with dryness palette (near monochrome)
function drawGrid() {
ctx.fillStyle = 'rgba(20, 20, 20, 0.05)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
const scaleX = canvas.width / cols;
const scaleY = canvas.height / rows;
for (let x = 0; x < cols; x++) {
for (let y = 0; y < rows; y++) {
const index = x * rows + y;
const value = grid[index];
if (value > 0.01) {
const intensity = Math.min(1, value * 2);
const alpha = Math.pow(intensity, 2) * 0.8;
const hue = 50 + (intensity * 20);
const saturation = 10;
const lightness = 50 + (intensity * 10);
ctx.fillStyle = `hsl(${hue}, ${saturation}%, ${lightness}%)`;
ctx.globalAlpha = alpha * params.pulse.avg;
ctx.fillRect(
x * scaleX,
y * scaleY,
scaleX + 1,
scaleY + 1
);
}
}
}
ctx.globalAlpha = 1;
}
// Animation loop
function animate() {
updateGrid();
drawGrid();
requestAnimationFrame(animate);
}
// Initialize and start
initializeGrid();
animate();
</script>
</body>
</html>