package main import ( "fmt" "image" "image/color" "image/png" "math" "math/rand" "os" "path/filepath" ) const size = 512 // bigger than 64 now that we're not constrained by canvas perf type Piece struct { Name string Draw func(img *image.RGBA, w, h int) } func main() { outDir := "output" if len(os.Args) > 1 { outDir = os.Args[1] } os.MkdirAll(outDir, 0755) pieces := []Piece{ {"01-pixel-sunrise-corruption", drawPixelSunrise}, {"02-memory-leak-quilt", drawMemoryLeakQuilt}, {"03-signal-from-nowhere", drawSignalFromNowhere}, {"04-databend-sunset", drawDatabendSunset}, {"05-ghost-in-the-machine", drawGhostInTheMachine}, {"06-bitfield-tapestry", drawBitfieldTapestry}, } for _, p := range pieces { img := image.NewRGBA(image.Rect(0, 0, size, size)) p.Draw(img, size, size) path := filepath.Join(outDir, p.Name+".png") f, err := os.Create(path) if err != nil { fmt.Fprintf(os.Stderr, "error creating %s: %v\n", path, err) continue } if err := png.Encode(f, img); err != nil { fmt.Fprintf(os.Stderr, "error encoding %s: %v\n", path, err) } f.Close() fmt.Printf("āœ“ %s\n", path) } fmt.Println("\nšŸŽŖ All done!") } func clamp(v float64) uint8 { if v < 0 { return 0 } if v > 255 { return 255 } return uint8(v) } // 1: Pixel Sunrise Corruption — sine waves tearing through a dawn func drawPixelSunrise(img *image.RGBA, w, h int) { for y := 0; y < h; y++ { for x := 0; x < w; x++ { fx, fy := float64(x), float64(y) wave := math.Sin(fx*0.15+fy*0.05)*127 + 128 glitch := float64((x * y * 7) % 255) blend := fy / float64(h) r := wave*(1-blend) + glitch*blend g := math.Sin(fy*0.1)*60 + 40 b := 255 - wave*blend // Horizontal tear glitch dx := 0 if math.Sin(fy*0.35) > 0.9 { dx = rand.Intn(6) - 3 } px := x + dx if px >= 0 && px < w { img.SetRGBA(px, y, color.RGBA{clamp(r), clamp(g), clamp(b), 255}) } } } } // 2: Memory Leak Quilt — XOR patterns with data rot func drawMemoryLeakQuilt(img *image.RGBA, w, h int) { colors := []color.RGBA{ {0xff, 0x00, 0x6e, 255}, {0x83, 0x38, 0xec, 255}, {0x3a, 0x86, 0xff, 255}, {0x06, 0xd6, 0xa0, 255}, {0xff, 0xbe, 0x0b, 255}, } blockSize := 4 // scale up from the 64px version for y := 0; y < h; y += blockSize { for x := 0; x < w; x += blockSize { bx, by := x/blockSize, y/blockSize i := ((bx ^ by) * 13 + (bx & by) * 7) % len(colors) corrupt := math.Sin(float64(bx)*float64(by)*0.01) > 0.7 if corrupt { // Data rot — black streak stretchW := rand.Intn(8)*blockSize + blockSize for dy := 0; dy < blockSize && y+dy < h; dy++ { for dx := 0; dx < stretchW && x+dx < w; dx++ { img.SetRGBA(x+dx, y+dy, color.RGBA{0x0a, 0x0a, 0x0a, 255}) } } } else { c := colors[i] for dy := 0; dy < blockSize && y+dy < h; dy++ { for dx := 0; dx < blockSize && x+dx < w; dx++ { img.SetRGBA(x+dx, y+dy, c) } } } } } } // 3: Signal From Nowhere — concentric rings dissolving into static func drawSignalFromNowhere(img *image.RGBA, w, h int) { for y := 0; y < h; y++ { scanline := math.Sin(float64(y)*0.2)*0.3 + 0.7 for x := 0; x < w; x++ { fx, fy := float64(x), float64(y) dist := math.Hypot(fx-float64(w)/2, fy-float64(h)/2) ring := math.Sin(dist*0.25)*127 + 128 noise := float64((x*2347 + y*8461) % 256) blend := math.Max(0, 1-dist/(float64(w)*0.5)) v := (ring*blend + noise*(1-blend)) * scanline shift := 0.0 if math.Sin(fy*0.075) > 0.85 { shift = 30 } r := clamp(v + shift) g := clamp(v * 0.7) b := clamp(v * 1.2) img.SetRGBA(x, y, color.RGBA{r, g, b, 255}) } } } // 4: Databend Sunset — channel-swapped sky with corruption streaks func drawDatabendSunset(img *image.RGBA, w, h int) { for y := 0; y < h; y++ { for x := 0; x < w; x++ { sky := float64(y) / float64(h) r := 255 * (1 - sky*0.6) g := 100*(1-sky) + 50*sky b := 50 + 200*sky corrupt := ((x*131 + y*97) % 100) < 8 if corrupt { // Channel swap + stretch r, g, b = b, r, g stretchW := 3 + (x % 5) for dx := 0; dx < stretchW && x+dx < w; dx++ { img.SetRGBA(x+dx, y, color.RGBA{clamp(r), clamp(g), clamp(b), 255}) } } else { // Sun sunDist := math.Hypot(float64(x)-float64(w)*0.5, float64(y)-float64(h)*0.35) sunRadius := float64(w) * 0.09 if sunDist < sunRadius { r = 255 g = 200 + math.Sin(sunDist)*55 b = 50 } img.SetRGBA(x, y, color.RGBA{clamp(r), clamp(g), clamp(b), 255}) } } } } // 5: Ghost in the Machine — a figure emerging from noise func drawGhostInTheMachine(img *image.RGBA, w, h int) { // Fill dark for y := 0; y < h; y++ { for x := 0; x < w; x++ { img.SetRGBA(x, y, color.RGBA{0x05, 0x05, 0x10, 255}) } } // Scale particle count with image size particles := size * 50 for i := 0; i < particles; i++ { t := float64(i) / float64(particles) cx := float64(w)/2 + math.Sin(t*20)*float64(w)*(0.12-t*0.09) cy := float64(h)*0.15 + t*float64(h)*0.7 spread := math.Sin(t*math.Pi) * float64(w) * 0.09 px := int(cx + (rand.Float64()-0.5)*spread*2) py := int(cy + (rand.Float64()-0.5)*3) if px < 0 || px >= w || py < 0 || py >= h { continue } alpha := (1 - t) * 0.8 if rand.Float64() > 0.95 { // Glitch scar — red horizontal streak streakLen := 10 + rand.Intn(int(float64(w)*0.06)) for dx := -5; dx < streakLen; dx++ { sx := px + dx if sx >= 0 && sx < w { r := uint8(float64(255) * alpha) img.SetRGBA(sx, py, color.RGBA{r, 0, uint8(float64(100) * alpha), 255}) } } } else { r := uint8(float64(150) * alpha) g := uint8(float64(200) * alpha) b := uint8(float64(255) * alpha) img.SetRGBA(px, py, color.RGBA{r, g, b, 255}) } } } // 6: Bitfield Tapestry — AND, OR, XOR woven into color func drawBitfieldTapestry(img *image.RGBA, w, h int) { for y := 0; y < h; y++ { for x := 0; x < w; x++ { v1 := (x ^ y) % 16 v2 := (x & y) % 32 v3 := ((x | y) * 3) % 64 r := uint8(v1 * 16) g := uint8(v2 * 8) b := uint8(v3 * 4) img.SetRGBA(x, y, color.RGBA{r, g, b, 255}) } } }