151 lines
No EOL
5 KiB
HTML
151 lines
No EOL
5 KiB
HTML
```html
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Organic Fractal Bloom</title>
|
|
<style>
|
|
body { margin: 0; overflow: hidden; background: #0a0a0a; }
|
|
canvas { display: block; }
|
|
#attribution { position: fixed; bottom: 10px; right: 10px; color: #555; font-family: monospace; font-size: 10px; }
|
|
</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();
|
|
|
|
// L-system parameters derived from the abstract specs
|
|
const params = {
|
|
axiom: 'X',
|
|
rules: {
|
|
'X': 'F-[[X]+X]+F[+FX]-X',
|
|
'F': 'FF'
|
|
},
|
|
angle: 25,
|
|
iterations: 4,
|
|
stepLength: 20,
|
|
stepReduction: 0.92,
|
|
randomness: 0.2,
|
|
colorBase: [220, 220, 220],
|
|
saturation: 0.1,
|
|
brightness: 0.5,
|
|
pulsationSpeed: 0.5
|
|
};
|
|
|
|
let angle = 0;
|
|
let pulsation = 0.72;
|
|
|
|
function drawLSys() {
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
ctx.save();
|
|
|
|
// Apply pulsation effect
|
|
pissation = 0.72 + Math.sin(Date.now() * 0.001 * params.pulsationSpeed) * 0.5;
|
|
ctx.translate(canvas.width / 2, canvas.height / 1.5);
|
|
|
|
// Draw recursive branches
|
|
const turns = ['F', '+', '-', '[', ']'];
|
|
let stack = [];
|
|
let hueVariation = 0;
|
|
let branchCount = 0;
|
|
|
|
function drawSegment(length, depth) {
|
|
branchCount++;
|
|
if (branchCount > 11) return; // Branch count constraint
|
|
|
|
// Color variation based on dryness
|
|
const hue = (20 + hueVariation * 10) % 360;
|
|
const saturation = params.saturation * 100;
|
|
const brightness = params.brightness * (0.5 + pulsation * 0.5);
|
|
ctx.strokeStyle = `hsl(${hue}, ${saturation}%, ${brightness}%)`;
|
|
ctx.lineWidth = Math.max(0.5, length * 0.05 * (1 + pulsation * 0.5));
|
|
|
|
// Add some organic roughness
|
|
ctx.lineCap = 'round';
|
|
ctx.lineJoin = 'round';
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(0, 0);
|
|
const x = length * Math.cos(angle);
|
|
const y = length * Math.sin(angle);
|
|
ctx.lineTo(x, y);
|
|
ctx.stroke();
|
|
|
|
// Branch recursion
|
|
if (depth > 0) {
|
|
ctx.save();
|
|
ctx.translate(x, y);
|
|
angle += Math.random() * params.randomness - params.randomness * 0.5;
|
|
drawSegment(length * params.stepReduction, depth - 1);
|
|
ctx.restore();
|
|
}
|
|
}
|
|
|
|
// Generate path with loops
|
|
let currentString = params.axiom;
|
|
for (let i = 0; i < params.iterations; i++) {
|
|
let nextString = '';
|
|
for (let c of currentString) {
|
|
if (params.rules[c]) {
|
|
nextString += params.rules[c];
|
|
} else {
|
|
nextString += c;
|
|
}
|
|
}
|
|
currentString = nextString;
|
|
}
|
|
|
|
// Draw the L-system with some randomness
|
|
ctx.save();
|
|
for (let i = 0; i < currentString.length; i++) {
|
|
const c = currentString[i];
|
|
if (c === 'F') {
|
|
drawSegment(params.stepLength, 5);
|
|
angle += Math.random() * params.randomness;
|
|
} else if (c === '+') {
|
|
angle += params.angle * (1 + Math.random() * params.randomness);
|
|
} else if (c === '-') {
|
|
angle -= params.angle * (1 + Math.random() * params.randomness);
|
|
} else if (c === '[') {
|
|
stack.push({x: ctx.lineTo(), y: ctx.lineTo(), angle: angle});
|
|
} else if (c === ']') {
|
|
const point = stack.pop();
|
|
if (point) {
|
|
ctx.lineTo(point.x, point.y);
|
|
angle = point.angle;
|
|
}
|
|
} else if (c === 'X') {
|
|
// Skip drawing X elements directly
|
|
}
|
|
|
|
// Adjust color slightly for each segment
|
|
hueVariation += 0.1;
|
|
}
|
|
ctx.restore();
|
|
|
|
ctx.restore();
|
|
}
|
|
|
|
function animate() {
|
|
angle += 0.01;
|
|
drawLSys();
|
|
requestAnimationFrame(animate);
|
|
}
|
|
|
|
animate();
|
|
</script>
|
|
</body>
|
|
</html>
|
|
``` |