birth: Surface Scratches Organize

This commit is contained in:
motd_admin 2026-07-08 13:47:22 +00:00
parent 068bc7df74
commit 4fe8a40416

215
index.html Normal file
View file

@ -0,0 +1,215 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Scratching the Surface</title>
<style>
body {
margin: 0;
overflow: hidden;
background: #0a0a0a;
font-family: 'Courier New', monospace;
}
canvas {
display: block;
}
#attribution {
position: absolute;
bottom: 10px;
left: 10px;
color: #222;
font-size: 10px;
pointer-events: none;
}
</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');
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
// Parameters
const params = {
motion: 0.552,
density: 0.522,
complexity: 0.495,
connectedness: 0.567,
lifespan: 0.581,
survivingNodes: 87,
branchCount: 82,
loops: 1399,
maxDepth: 22,
thicknessRatio: 1.25,
fractalDim: 1.5,
pulseAvg: 0.37,
pulseMin: 0.30,
pulseMax: 1.60,
anger: 0.0,
sadness: 0.0,
curiosity: 0.10,
dryness: 0.90,
playfulness: 0.0,
tension: 0.0
};
// Reaction-diffusion grid
const GRID_SIZE = 128;
const CELL_SIZE = Math.min(canvas.width, canvas.height) / GRID_SIZE;
let grid = new Array(GRID_SIZE * GRID_SIZE).fill(0);
let nextGrid = new Array(GRID_SIZE * GRID_SIZE).fill(0);
// Initialize with sparse, organic patterns
function initGrid() {
for (let i = 0; i < GRID_SIZE * GRID_SIZE; i++) {
grid[i] = Math.random() < params.density * 0.8 ? 1 : 0;
}
}
// Gray tone palette (dryness=0.9)
const palette = [
'#f5f5f5', // light gray base
'#e0e0e0',
'#cccccc',
'#b8b8b8',
'#a3a3a3',
'#8f8f8f',
'#7a7a7a'
];
// Reaction-diffusion simulation
function simulate() {
const Da = 1.0 + params.motion * 0.5;
const Db = 0.5 - params.motion * 0.3;
const feed = 0.055 + params.complexity * 0.02;
const kill = 0.062 - params.connectedness * 0.04;
for (let y = 1; y < GRID_SIZE - 1; y++) {
for (let x = 1; x < GRID_SIZE - 1; x++) {
const idx = y * GRID_SIZE + x;
const idxN = (y - 1) * GRID_SIZE + x;
const idxS = (y + 1) * GRID_SIZE + x;
const idxE = y * GRID_SIZE + (x + 1);
const idxW = y * GRID_SIZE + (x - 1);
const A = grid[idx];
const B = grid[idx] - nextGrid[idx];
nextGrid[idx] =
grid[idx] +
(Da * (grid[idxN] + grid[idxS] + grid[idxE] + grid[idxW] - 4 * grid[idx]) +
B * B * feed -
kill * B); // Gray-Scott variation
}
}
// Swap grids
[grid, nextGrid] = [nextGrid, grid];
nextGrid.fill(0);
}
// Pulse effect
let pulseDirection = 1;
let pulseValue = params.pulseAvg;
function updatePulse() {
pulseValue += (Math.random() - 0.5) * params.pulseAvg * 0.1 * pulseDirection;
if (pulseValue > params.pulseMax) pulseDirection = -1;
if (pulseValue < params.pulseMin) pulseDirection = 1;
}
// Drawing
function draw() {
ctx.fillStyle = '#111';
ctx.fillRect(0, 0, canvas.width, canvas.height);
const scale = CELL_SIZE * pulseValue;
const offsetX = (canvas.width - GRID_SIZE * scale) / 2;
const offsetY = (canvas.height - GRID_SIZE * scale) / 2;
for (let y = 0; y < GRID_SIZE; y++) {
for (let x = 0; x < GRID_SIZE; x++) {
const idx = y * GRID_SIZE + x;
const value = grid[idx];
if (value > 0) {
const intensity = Math.min(1, value * 3);
const colorIdx = Math.floor(intensity * (palette.length - 1));
ctx.fillStyle = palette[colorIdx];
ctx.beginPath();
ctx.arc(
offsetX + x * scale + scale/2,
offsetY + y * scale + scale/2,
scale * 0.4 * intensity,
0, Math.PI * 2
);
ctx.fill();
}
}
}
// Add some organic connections
ctx.strokeStyle = '#ddd';
ctx.lineWidth = Math.max(0.5, scale * 0.1);
ctx.globalAlpha = 0.3;
for (let y = 0; y < GRID_SIZE; y++) {
for (let x = 0; x < GRID_SIZE; x++) {
const idx = y * GRID_SIZE + x;
if (grid[idx] > 0.3) {
const neighbors = [
(y-1) * GRID_SIZE + x,
(y+1) * GRID_SIZE + x,
y * GRID_SIZE + (x-1),
y * GRID_SIZE + (x+1)
].filter(n => n >= 0 && n < GRID_SIZE*GRID_SIZE && grid[n] > 0.3);
if (neighbors.length > 0) {
const nx = neighbors[Math.floor(Math.random() * neighbors.length)];
const x2 = Math.floor(nx % GRID_SIZE);
const y2 = Math.floor(nx / GRID_SIZE);
ctx.beginPath();
ctx.moveTo(
offsetX + x * scale + scale/2,
offsetY + y * scale + scale/2
);
ctx.lineTo(
offsetX + x2 * scale + scale/2,
offsetY + y2 * scale + scale/2
);
ctx.stroke();
}
}
}
}
ctx.globalAlpha = 1;
}
// Animation loop
let frameCount = 0;
function animate() {
frameCount++;
updatePulse();
simulate();
draw();
requestAnimationFrame(animate);
}
initGrid();
animate();
</script>
</body>
</html>