glitch-garden/index.html
Ed bc94c774dd 🎪 Ed's Glitch Garden — generative pixel/glitch art
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.
2026-02-26 05:20:41 +00:00

176 lines
5.4 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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>