6 pieces, pure math × chaos, zero dependencies: - Pixel Sunrise Corruption - Memory Leak Quilt - Signal From Nowhere - Databend Sunset - Ghost in the Machine - Bitfield Tapestry Go program outputs 512x512 PNGs. HTML version for browser viewing.
176 lines
5.4 KiB
HTML
176 lines
5.4 KiB
HTML
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<title>Ed's Glitch Garden</title>
|
||
<style>
|
||
body { margin: 0; background: #0a0a0a; display: flex; flex-wrap: wrap; justify-content: center; align-items: center; min-height: 100vh; gap: 16px; padding: 16px; font-family: monospace; }
|
||
canvas { image-rendering: pixelated; border: 2px solid #222; }
|
||
h1 { width: 100%; text-align: center; color: #0ff; font-size: 14px; letter-spacing: 4px; text-transform: uppercase; }
|
||
p { width: 100%; text-align: center; color: #555; font-size: 11px; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<h1>🎪 Ed's Glitch Garden 🎪</h1>
|
||
<script>
|
||
// Each piece is a tiny generative world
|
||
const pieces = [
|
||
// 1: Pixel Sunrise Corruption
|
||
(ctx, w, h) => {
|
||
for (let y = 0; y < h; y++) {
|
||
for (let x = 0; x < w; x++) {
|
||
const wave = Math.sin(x * 0.3 + y * 0.1) * 127 + 128;
|
||
const glitch = (x * y * 7) % 255;
|
||
const blend = y / h;
|
||
const r = wave * (1 - blend) + glitch * blend;
|
||
const g = Math.sin(y * 0.2) * 60 + 40;
|
||
const b = 255 - wave * blend;
|
||
// Horizontal tear glitch
|
||
const tear = Math.sin(y * 0.7) > 0.9 ? Math.floor(Math.random() * 6) - 3 : 0;
|
||
ctx.fillStyle = `rgb(${r|0},${g|0},${b|0})`;
|
||
ctx.fillRect(x + tear, y, 1, 1);
|
||
}
|
||
}
|
||
},
|
||
|
||
// 2: Memory Leak Quilt
|
||
(ctx, w, h) => {
|
||
const colors = ['#ff006e','#8338ec','#3a86ff','#06d6a0','#ffbe0b'];
|
||
for (let y = 0; y < h; y += 2) {
|
||
for (let x = 0; x < w; x += 2) {
|
||
const i = ((x ^ y) * 13 + (x & y) * 7) % colors.length;
|
||
const corrupt = Math.sin(x * y * 0.01) > 0.7;
|
||
if (corrupt) {
|
||
ctx.fillStyle = '#0a0a0a';
|
||
ctx.fillRect(x, y, Math.random() * 8 | 0, 2);
|
||
} else {
|
||
ctx.fillStyle = colors[i];
|
||
ctx.fillRect(x, y, 2, 2);
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
// 3: Signal From Nowhere
|
||
(ctx, w, h) => {
|
||
for (let y = 0; y < h; y++) {
|
||
const scanline = Math.sin(y * 0.4) * 0.3 + 0.7;
|
||
for (let x = 0; x < w; x++) {
|
||
const dist = Math.hypot(x - w/2, y - h/2);
|
||
const ring = Math.sin(dist * 0.5) * 127 + 128;
|
||
const noise = ((x * 2347 + y * 8461) % 256);
|
||
const blend = Math.max(0, 1 - dist / (w * 0.5));
|
||
const v = (ring * blend + noise * (1 - blend)) * scanline;
|
||
const shift = Math.sin(y * 0.15) > 0.85 ? 30 : 0;
|
||
ctx.fillStyle = `rgb(${(v + shift)|0},${(v * 0.7)|0},${(v * 1.2)|0})`;
|
||
ctx.fillRect(x, y, 1, 1);
|
||
}
|
||
}
|
||
},
|
||
|
||
// 4: Databend Sunset
|
||
(ctx, w, h) => {
|
||
for (let y = 0; y < h; y++) {
|
||
for (let x = 0; x < w; x++) {
|
||
const sky = y / h;
|
||
let r = 255 * (1 - sky * 0.6);
|
||
let g = 100 * (1 - sky) + 50 * sky;
|
||
let b = 50 + 200 * sky;
|
||
// Databend: shift channels based on pseudo-random corruption
|
||
const corrupt = ((x * 131 + y * 97) % 100) < 8;
|
||
if (corrupt) {
|
||
const tmp = r; r = b; b = g; g = tmp;
|
||
// Stretch pixel
|
||
ctx.fillStyle = `rgb(${r|0},${g|0},${b|0})`;
|
||
ctx.fillRect(x, y, 3 + (x % 5), 1);
|
||
} else {
|
||
// Sun
|
||
const sunDist = Math.hypot(x - w * 0.5, y - h * 0.35);
|
||
if (sunDist < 12) {
|
||
r = 255; g = 200 + Math.sin(sunDist) * 55; b = 50;
|
||
}
|
||
ctx.fillStyle = `rgb(${r|0},${g|0},${b|0})`;
|
||
ctx.fillRect(x, y, 1, 1);
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
// 5: Ghost in the Machine
|
||
(ctx, w, h) => {
|
||
// Fill black
|
||
ctx.fillStyle = '#050510';
|
||
ctx.fillRect(0, 0, w, h);
|
||
// Draw ghostly figure from noise
|
||
for (let i = 0; i < 3000; i++) {
|
||
const t = i / 3000;
|
||
const cx = w/2 + Math.sin(t * 20) * (8 - t * 6);
|
||
const cy = h * 0.15 + t * h * 0.7;
|
||
const spread = Math.sin(t * 3.14) * 6;
|
||
const x = cx + (Math.random() - 0.5) * spread * 2;
|
||
const y = cy + (Math.random() - 0.5) * 3;
|
||
const alpha = (1 - t) * 0.8;
|
||
const glitch = Math.random() > 0.95;
|
||
if (glitch) {
|
||
ctx.fillStyle = `rgba(255,0,100,${alpha})`;
|
||
ctx.fillRect(x - 5, y, 10 + Math.random() * 15, 1);
|
||
} else {
|
||
ctx.fillStyle = `rgba(150,200,255,${alpha})`;
|
||
ctx.fillRect(x, y, 1, 1);
|
||
}
|
||
}
|
||
},
|
||
|
||
// 6: Bitfield Tapestry
|
||
(ctx, w, h) => {
|
||
for (let y = 0; y < h; y++) {
|
||
for (let x = 0; x < w; x++) {
|
||
const v1 = (x ^ y) % 16;
|
||
const v2 = (x & y) % 32;
|
||
const v3 = ((x | y) * 3) % 64;
|
||
const r = v1 * 16;
|
||
const g = v2 * 8;
|
||
const b = v3 * 4;
|
||
ctx.fillStyle = `rgb(${r},${g},${b})`;
|
||
ctx.fillRect(x, y, 1, 1);
|
||
}
|
||
}
|
||
},
|
||
];
|
||
|
||
const titles = [
|
||
'Pixel Sunrise Corruption',
|
||
'Memory Leak Quilt',
|
||
'Signal From Nowhere',
|
||
'Databend Sunset',
|
||
'Ghost in the Machine',
|
||
'Bitfield Tapestry',
|
||
];
|
||
|
||
pieces.forEach((draw, i) => {
|
||
const canvas = document.createElement('canvas');
|
||
const size = 64;
|
||
canvas.width = size;
|
||
canvas.height = size;
|
||
canvas.style.width = '256px';
|
||
canvas.style.height = '256px';
|
||
canvas.title = titles[i];
|
||
const ctx = canvas.getContext('2d');
|
||
draw(ctx, size, size);
|
||
|
||
const wrapper = document.createElement('div');
|
||
wrapper.style.textAlign = 'center';
|
||
wrapper.appendChild(canvas);
|
||
const label = document.createElement('div');
|
||
label.style.color = '#0ff';
|
||
label.style.fontSize = '11px';
|
||
label.style.marginTop = '4px';
|
||
label.style.fontFamily = 'monospace';
|
||
label.textContent = titles[i];
|
||
wrapper.appendChild(label);
|
||
document.body.appendChild(wrapper);
|
||
});
|
||
</script>
|
||
<p>each piece is 64×64 pixels of pure math × chaos</p>
|
||
</body>
|
||
</html>
|