603 lines
15 KiB
Go
603 lines
15 KiB
Go
|
|
// Daily Glitch Wallpaper Generator
|
||
|
|
// Generates 6 unique glitch-inspired wallpapers at Pixel 8 resolution (1080x2400)
|
||
|
|
// Each run produces different art via randomized parameters and algorithm selection.
|
||
|
|
//
|
||
|
|
// Usage: go run daily.go [output-dir]
|
||
|
|
|
||
|
|
package main
|
||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"image"
|
||
|
|
"image/color"
|
||
|
|
"image/png"
|
||
|
|
"math"
|
||
|
|
"math/rand"
|
||
|
|
"os"
|
||
|
|
"path/filepath"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
const (
|
||
|
|
W = 1080
|
||
|
|
H = 2400
|
||
|
|
)
|
||
|
|
|
||
|
|
func main() {
|
||
|
|
rand.Seed(time.Now().UnixNano())
|
||
|
|
|
||
|
|
outDir := "daily-output"
|
||
|
|
if len(os.Args) > 1 {
|
||
|
|
outDir = os.Args[1]
|
||
|
|
}
|
||
|
|
os.MkdirAll(outDir, 0755)
|
||
|
|
|
||
|
|
// Pool of generators — pick 6 unique ones (or repeat with different params if pool < 6)
|
||
|
|
type Generator struct {
|
||
|
|
Name string
|
||
|
|
Draw func(img *image.RGBA, w, h int)
|
||
|
|
}
|
||
|
|
|
||
|
|
generators := []Generator{
|
||
|
|
{"ghost-in-the-machine", drawGhost},
|
||
|
|
{"pixel-aurora", drawAurora},
|
||
|
|
{"data-rain", drawDataRain},
|
||
|
|
{"fractal-burn", drawFractalBurn},
|
||
|
|
{"void-signal", drawVoidSignal},
|
||
|
|
{"neon-decay", drawNeonDecay},
|
||
|
|
{"static-portrait", drawStaticPortrait},
|
||
|
|
{"circuit-dream", drawCircuitDream},
|
||
|
|
{"plasma-tear", drawPlasmaTear},
|
||
|
|
{"bit-cascade", drawBitCascade},
|
||
|
|
{"deep-scan", drawDeepScan},
|
||
|
|
{"entropy-wave", drawEntropyWave},
|
||
|
|
}
|
||
|
|
|
||
|
|
// Shuffle and pick 6
|
||
|
|
rand.Shuffle(len(generators), func(i, j int) {
|
||
|
|
generators[i], generators[j] = generators[j], generators[i]
|
||
|
|
})
|
||
|
|
|
||
|
|
for i := 0; i < 6; i++ {
|
||
|
|
gen := generators[i]
|
||
|
|
img := image.NewRGBA(image.Rect(0, 0, W, H))
|
||
|
|
gen.Draw(img, W, H)
|
||
|
|
|
||
|
|
name := fmt.Sprintf("%02d-%s.png", i+1, gen.Name)
|
||
|
|
path := filepath.Join(outDir, name)
|
||
|
|
f, err := os.Create(path)
|
||
|
|
if err != nil {
|
||
|
|
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
png.Encode(f, img)
|
||
|
|
f.Close()
|
||
|
|
fmt.Printf("✓ %s\n", path)
|
||
|
|
}
|
||
|
|
fmt.Println("\n🎪 Done!")
|
||
|
|
}
|
||
|
|
|
||
|
|
func clamp(v float64) uint8 {
|
||
|
|
if v < 0 {
|
||
|
|
return 0
|
||
|
|
}
|
||
|
|
if v > 255 {
|
||
|
|
return 255
|
||
|
|
}
|
||
|
|
return uint8(v)
|
||
|
|
}
|
||
|
|
|
||
|
|
func lerpColor(a, b color.RGBA, t float64) color.RGBA {
|
||
|
|
return color.RGBA{
|
||
|
|
clamp(float64(a.R)*(1-t) + float64(b.R)*t),
|
||
|
|
clamp(float64(a.G)*(1-t) + float64(b.G)*t),
|
||
|
|
clamp(float64(a.B)*(1-t) + float64(b.B)*t),
|
||
|
|
255,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func fillBg(img *image.RGBA, w, h int, top, bot color.RGBA) {
|
||
|
|
for y := 0; y < h; y++ {
|
||
|
|
t := float64(y) / float64(h)
|
||
|
|
c := lerpColor(top, bot, t)
|
||
|
|
for x := 0; x < w; x++ {
|
||
|
|
img.SetRGBA(x, y, c)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func addScanlines(img *image.RGBA, w, h int, intensity float64) {
|
||
|
|
for y := 0; y < h; y += 2 + rand.Intn(3) {
|
||
|
|
a := intensity * (0.5 + rand.Float64()*0.5)
|
||
|
|
for x := 0; x < w; x++ {
|
||
|
|
c := img.RGBAAt(x, y)
|
||
|
|
c.R = clamp(float64(c.R) * (1 - a))
|
||
|
|
c.G = clamp(float64(c.G) * (1 - a))
|
||
|
|
c.B = clamp(float64(c.B) * (1 - a))
|
||
|
|
img.SetRGBA(x, y, c)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func addGlitchBars(img *image.RGBA, w, h int, count int) {
|
||
|
|
for i := 0; i < count; i++ {
|
||
|
|
barY := rand.Intn(h)
|
||
|
|
barH := 1 + rand.Intn(4)
|
||
|
|
shift := rand.Intn(30) - 15
|
||
|
|
tint := []color.RGBA{
|
||
|
|
{255, 0, 80, 255}, {0, 255, 200, 255}, {200, 0, 255, 255}, {255, 200, 0, 255},
|
||
|
|
}[rand.Intn(4)]
|
||
|
|
a := 0.1 + rand.Float64()*0.25
|
||
|
|
|
||
|
|
for dy := 0; dy < barH; dy++ {
|
||
|
|
yy := barY + dy
|
||
|
|
if yy >= h {
|
||
|
|
break
|
||
|
|
}
|
||
|
|
for x := 0; x < w; x++ {
|
||
|
|
sx := x + shift
|
||
|
|
if sx < 0 || sx >= w {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
c := img.RGBAAt(sx, yy)
|
||
|
|
c.R = clamp(float64(c.R)*(1-a) + float64(tint.R)*a)
|
||
|
|
c.G = clamp(float64(c.G)*(1-a) + float64(tint.G)*a)
|
||
|
|
c.B = clamp(float64(c.B)*(1-a) + float64(tint.B)*a)
|
||
|
|
img.SetRGBA(x, yy, c)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// === GENERATORS ===
|
||
|
|
|
||
|
|
func drawGhost(img *image.RGBA, w, h int) {
|
||
|
|
fillBg(img, w, h, color.RGBA{3, 3, 12, 255}, color.RGBA{10, 8, 30, 255})
|
||
|
|
cx := float64(w) / 2
|
||
|
|
startY := float64(h) * 0.12
|
||
|
|
fh := float64(h) * 0.70
|
||
|
|
n := w * 120
|
||
|
|
for i := 0; i < n; i++ {
|
||
|
|
t := float64(i) / float64(n)
|
||
|
|
sway := math.Sin(t*22+rand.Float64()*0.5) * float64(w) * (0.08 - t*0.05)
|
||
|
|
spread := math.Sin(t*math.Pi) * float64(w) * 0.12
|
||
|
|
px := int(cx + sway + (rand.Float64()-0.5)*spread*2)
|
||
|
|
py := int(startY + t*fh + (rand.Float64()-0.5)*4)
|
||
|
|
if px < 0 || px >= w || py < 0 || py >= h {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
alpha := (1 - t) * 0.85
|
||
|
|
if rand.Float64() > 0.96 {
|
||
|
|
for dx := -8; dx < 15+rand.Intn(w/12); dx++ {
|
||
|
|
sx := px + dx
|
||
|
|
if sx >= 0 && sx < w {
|
||
|
|
img.SetRGBA(sx, py, color.RGBA{clamp(255 * alpha), 0, clamp(100 * alpha), 255})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
img.SetRGBA(px, py, color.RGBA{clamp(150 * alpha), clamp(200 * alpha), clamp(255 * alpha), 255})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
addScanlines(img, w, h, 0.04)
|
||
|
|
addGlitchBars(img, w, h, 6)
|
||
|
|
}
|
||
|
|
|
||
|
|
func drawAurora(img *image.RGBA, w, h int) {
|
||
|
|
phase1 := rand.Float64() * math.Pi * 2
|
||
|
|
phase2 := rand.Float64() * math.Pi * 2
|
||
|
|
freq := 0.003 + rand.Float64()*0.004
|
||
|
|
|
||
|
|
fillBg(img, w, h, color.RGBA{2, 2, 15, 255}, color.RGBA{5, 3, 20, 255})
|
||
|
|
for y := 0; y < h; y++ {
|
||
|
|
fy := float64(y) / float64(h)
|
||
|
|
// Aurora bands in the upper portion
|
||
|
|
bandIntensity := math.Exp(-math.Pow((fy-0.3)/0.25, 2))
|
||
|
|
for x := 0; x < w; x++ {
|
||
|
|
fx := float64(x)
|
||
|
|
wave1 := math.Sin(fx*freq+phase1+fy*3) * 0.5
|
||
|
|
wave2 := math.Cos(fx*freq*1.7+phase2+fy*2) * 0.3
|
||
|
|
v := (wave1 + wave2 + 0.5) * bandIntensity
|
||
|
|
|
||
|
|
tear := 0.0
|
||
|
|
if math.Sin(fy*80+fx*0.01) > 0.97 {
|
||
|
|
tear = 0.4
|
||
|
|
}
|
||
|
|
|
||
|
|
r := clamp(v*80 + tear*200)
|
||
|
|
g := clamp(v * 255)
|
||
|
|
b := clamp(v*180 + tear*100)
|
||
|
|
|
||
|
|
c := img.RGBAAt(x, y)
|
||
|
|
c.R = clamp(float64(c.R) + float64(r))
|
||
|
|
c.G = clamp(float64(c.G) + float64(g))
|
||
|
|
c.B = clamp(float64(c.B) + float64(b))
|
||
|
|
img.SetRGBA(x, y, c)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// Stars
|
||
|
|
for i := 0; i < 400; i++ {
|
||
|
|
px, py := rand.Intn(w), rand.Intn(h/2)
|
||
|
|
b := uint8(100 + rand.Intn(155))
|
||
|
|
img.SetRGBA(px, py, color.RGBA{b, b, b, 255})
|
||
|
|
}
|
||
|
|
addGlitchBars(img, w, h, 4)
|
||
|
|
}
|
||
|
|
|
||
|
|
func drawDataRain(img *image.RGBA, w, h int) {
|
||
|
|
baseHue := rand.Float64() // randomize color each run
|
||
|
|
fillBg(img, w, h, color.RGBA{0, 0, 0, 255}, color.RGBA{5, 5, 10, 255})
|
||
|
|
cols := w / 8
|
||
|
|
for c := 0; c < cols; c++ {
|
||
|
|
x := c*8 + rand.Intn(4)
|
||
|
|
speed := 3 + rand.Intn(8)
|
||
|
|
startOff := rand.Intn(h)
|
||
|
|
length := 40 + rand.Intn(120)
|
||
|
|
for i := 0; i < length; i++ {
|
||
|
|
y := (startOff + i*speed) % h
|
||
|
|
t := float64(i) / float64(length)
|
||
|
|
brightness := (1 - t) * 0.9
|
||
|
|
|
||
|
|
// HSV-ish color from baseHue
|
||
|
|
r := clamp(math.Sin(baseHue*math.Pi*2)*100*brightness + 50*brightness)
|
||
|
|
g := clamp(math.Sin((baseHue+0.33)*math.Pi*2)*100*brightness + 200*brightness)
|
||
|
|
b := clamp(math.Sin((baseHue+0.66)*math.Pi*2)*100*brightness + 80*brightness)
|
||
|
|
|
||
|
|
for dx := 0; dx < 3; dx++ {
|
||
|
|
if x+dx < w {
|
||
|
|
img.SetRGBA(x+dx, y, color.RGBA{r, g, b, 255})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
addScanlines(img, w, h, 0.06)
|
||
|
|
addGlitchBars(img, w, h, 10)
|
||
|
|
}
|
||
|
|
|
||
|
|
func drawFractalBurn(img *image.RGBA, w, h int) {
|
||
|
|
cx := float64(w)/2 + rand.Float64()*100 - 50
|
||
|
|
cy := float64(h)/2 + rand.Float64()*200 - 100
|
||
|
|
maxIter := 80 + rand.Intn(40)
|
||
|
|
zoom := 200.0 + rand.Float64()*200
|
||
|
|
|
||
|
|
palette := []color.RGBA{
|
||
|
|
{20, 0, 40, 255}, {80, 0, 120, 255}, {200, 50, 50, 255},
|
||
|
|
{255, 150, 0, 255}, {255, 255, 100, 255}, {255, 255, 255, 255},
|
||
|
|
}
|
||
|
|
|
||
|
|
for y := 0; y < h; y++ {
|
||
|
|
for x := 0; x < w; x++ {
|
||
|
|
zr := (float64(x) - cx) / zoom
|
||
|
|
zi := (float64(y) - cy) / zoom
|
||
|
|
cr, ci := zr, zi
|
||
|
|
iter := 0
|
||
|
|
for ; iter < maxIter; iter++ {
|
||
|
|
zr2, zi2 := zr*zr, zi*zi
|
||
|
|
if zr2+zi2 > 4 {
|
||
|
|
break
|
||
|
|
}
|
||
|
|
zr, zi = zr2-zi2+cr, 2*zr*zi+ci
|
||
|
|
}
|
||
|
|
t := float64(iter) / float64(maxIter)
|
||
|
|
idx := t * float64(len(palette)-1)
|
||
|
|
i1 := int(idx)
|
||
|
|
if i1 >= len(palette)-1 {
|
||
|
|
i1 = len(palette) - 2
|
||
|
|
}
|
||
|
|
frac := idx - float64(i1)
|
||
|
|
|
||
|
|
// Burn effect — occasional pixel corruption
|
||
|
|
if (x*131+y*97+iter*3)%200 < 3 {
|
||
|
|
img.SetRGBA(x, y, color.RGBA{255, 255, 255, 255})
|
||
|
|
} else {
|
||
|
|
img.SetRGBA(x, y, lerpColor(palette[i1], palette[i1+1], frac))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
addGlitchBars(img, w, h, 8)
|
||
|
|
}
|
||
|
|
|
||
|
|
func drawVoidSignal(img *image.RGBA, w, h int) {
|
||
|
|
fillBg(img, w, h, color.RGBA{0, 0, 0, 255}, color.RGBA{0, 0, 5, 255})
|
||
|
|
ringCx := float64(w)/2 + rand.Float64()*60 - 30
|
||
|
|
ringCy := float64(h)*0.4 + rand.Float64()*100
|
||
|
|
|
||
|
|
for y := 0; y < h; y++ {
|
||
|
|
for x := 0; x < w; x++ {
|
||
|
|
dist := math.Hypot(float64(x)-ringCx, float64(y)-ringCy)
|
||
|
|
ring := math.Sin(dist*0.04) * 0.5 * math.Exp(-dist*0.001)
|
||
|
|
noise := float64((x*9871+y*6563)%256) / 256.0
|
||
|
|
|
||
|
|
v := ring*0.8 + noise*0.05
|
||
|
|
|
||
|
|
// Color: deep teal to white
|
||
|
|
r := clamp(v * 150)
|
||
|
|
g := clamp(v * 255)
|
||
|
|
b := clamp(v * 280)
|
||
|
|
img.SetRGBA(x, y, color.RGBA{r, g, b, 255})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
addScanlines(img, w, h, 0.08)
|
||
|
|
addGlitchBars(img, w, h, 12)
|
||
|
|
}
|
||
|
|
|
||
|
|
func drawNeonDecay(img *image.RGBA, w, h int) {
|
||
|
|
neonColors := []color.RGBA{
|
||
|
|
{255, 0, 110, 255}, {0, 255, 200, 255}, {130, 50, 255, 255},
|
||
|
|
{255, 200, 0, 255}, {0, 150, 255, 255},
|
||
|
|
}
|
||
|
|
pick := neonColors[rand.Intn(len(neonColors))]
|
||
|
|
pick2 := neonColors[rand.Intn(len(neonColors))]
|
||
|
|
|
||
|
|
fillBg(img, w, h, color.RGBA{8, 5, 15, 255}, color.RGBA{15, 8, 25, 255})
|
||
|
|
|
||
|
|
// Neon lines that decay
|
||
|
|
for l := 0; l < 30+rand.Intn(20); l++ {
|
||
|
|
y := rand.Intn(h)
|
||
|
|
thickness := 2 + rand.Intn(6)
|
||
|
|
c := pick
|
||
|
|
if rand.Float64() > 0.5 {
|
||
|
|
c = pick2
|
||
|
|
}
|
||
|
|
decayStart := rand.Intn(w / 2)
|
||
|
|
for x := 0; x < w; x++ {
|
||
|
|
alpha := 1.0
|
||
|
|
if x > decayStart {
|
||
|
|
decay := float64(x-decayStart) / float64(w-decayStart)
|
||
|
|
alpha = 1 - decay
|
||
|
|
// Chunk decay — blocks disappear
|
||
|
|
if ((x/8)*17+l*31)%10 < int(decay*10) {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
}
|
||
|
|
for dy := 0; dy < thickness; dy++ {
|
||
|
|
yy := y + dy
|
||
|
|
if yy < h {
|
||
|
|
img.SetRGBA(x, yy, color.RGBA{
|
||
|
|
clamp(float64(c.R) * alpha),
|
||
|
|
clamp(float64(c.G) * alpha),
|
||
|
|
clamp(float64(c.B) * alpha),
|
||
|
|
255,
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
addScanlines(img, w, h, 0.03)
|
||
|
|
}
|
||
|
|
|
||
|
|
func drawStaticPortrait(img *image.RGBA, w, h int) {
|
||
|
|
// TV static with a silhouette carved out
|
||
|
|
for y := 0; y < h; y++ {
|
||
|
|
for x := 0; x < w; x++ {
|
||
|
|
v := uint8(rand.Intn(60))
|
||
|
|
img.SetRGBA(x, y, color.RGBA{v, v, v, 255})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// Silhouette — oval head + body
|
||
|
|
headCx, headCy := float64(w)/2, float64(h)*0.28
|
||
|
|
headRx, headRy := float64(w)*0.12, float64(w)*0.15
|
||
|
|
bodyCx, bodyCy := float64(w)/2, float64(h)*0.65
|
||
|
|
bodyRx, bodyRy := float64(w)*0.22, float64(h)*0.3
|
||
|
|
|
||
|
|
for y := 0; y < h; y++ {
|
||
|
|
for x := 0; x < w; x++ {
|
||
|
|
fx, fy := float64(x), float64(y)
|
||
|
|
inHead := math.Pow((fx-headCx)/headRx, 2)+math.Pow((fy-headCy)/headRy, 2) < 1
|
||
|
|
inBody := math.Pow((fx-bodyCx)/bodyRx, 2)+math.Pow((fy-bodyCy)/bodyRy, 2) < 1
|
||
|
|
if inHead || inBody {
|
||
|
|
img.SetRGBA(x, y, color.RGBA{0, 0, 0, 255})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// Glitch the silhouette edges
|
||
|
|
addGlitchBars(img, w, h, 15)
|
||
|
|
addScanlines(img, w, h, 0.1)
|
||
|
|
}
|
||
|
|
|
||
|
|
func drawCircuitDream(img *image.RGBA, w, h int) {
|
||
|
|
accent := []color.RGBA{
|
||
|
|
{0, 255, 180, 255}, {0, 150, 255, 255}, {255, 100, 0, 255},
|
||
|
|
}[rand.Intn(3)]
|
||
|
|
|
||
|
|
fillBg(img, w, h, color.RGBA{5, 10, 15, 255}, color.RGBA{10, 15, 25, 255})
|
||
|
|
|
||
|
|
// Grid of circuit-like paths
|
||
|
|
gridSize := 20 + rand.Intn(20)
|
||
|
|
for gy := 0; gy < h/gridSize; gy++ {
|
||
|
|
for gx := 0; gx < w/gridSize; gx++ {
|
||
|
|
if rand.Float64() > 0.3 {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
x1 := gx * gridSize
|
||
|
|
y1 := gy * gridSize
|
||
|
|
// Draw horizontal or vertical trace
|
||
|
|
horizontal := rand.Float64() > 0.5
|
||
|
|
length := gridSize * (1 + rand.Intn(4))
|
||
|
|
thick := 1 + rand.Intn(2)
|
||
|
|
alpha := 0.3 + rand.Float64()*0.7
|
||
|
|
|
||
|
|
for d := 0; d < length; d++ {
|
||
|
|
for t := 0; t < thick; t++ {
|
||
|
|
var px, py int
|
||
|
|
if horizontal {
|
||
|
|
px, py = x1+d, y1+t
|
||
|
|
} else {
|
||
|
|
px, py = x1+t, y1+d
|
||
|
|
}
|
||
|
|
if px >= 0 && px < w && py >= 0 && py < h {
|
||
|
|
img.SetRGBA(px, py, color.RGBA{
|
||
|
|
clamp(float64(accent.R) * alpha),
|
||
|
|
clamp(float64(accent.G) * alpha),
|
||
|
|
clamp(float64(accent.B) * alpha),
|
||
|
|
255,
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// Node dot at start
|
||
|
|
for dx := -2; dx <= 2; dx++ {
|
||
|
|
for dy := -2; dy <= 2; dy++ {
|
||
|
|
px, py := x1+dx, y1+dy
|
||
|
|
if px >= 0 && px < w && py >= 0 && py < h {
|
||
|
|
img.SetRGBA(px, py, accent)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
addGlitchBars(img, w, h, 5)
|
||
|
|
}
|
||
|
|
|
||
|
|
func drawPlasmaTear(img *image.RGBA, w, h int) {
|
||
|
|
p1 := rand.Float64() * 10
|
||
|
|
p2 := rand.Float64() * 10
|
||
|
|
p3 := rand.Float64() * 10
|
||
|
|
|
||
|
|
for y := 0; y < h; y++ {
|
||
|
|
for x := 0; x < w; x++ {
|
||
|
|
fx := float64(x) / float64(w) * 8
|
||
|
|
fy := float64(y) / float64(h) * 8
|
||
|
|
|
||
|
|
v1 := math.Sin(fx*1.5 + p1)
|
||
|
|
v2 := math.Sin(fy*2.0 + p2)
|
||
|
|
v3 := math.Sin((fx+fy)*1.2 + p3)
|
||
|
|
v4 := math.Sin(math.Hypot(fx-4, fy-4) * 1.5)
|
||
|
|
|
||
|
|
v := (v1 + v2 + v3 + v4) / 4.0
|
||
|
|
|
||
|
|
r := clamp((v*0.5 + 0.5) * 255)
|
||
|
|
g := clamp((math.Sin(v*math.Pi)*0.5 + 0.5) * 200)
|
||
|
|
b := clamp(((1-v)*0.5 + 0.5) * 255)
|
||
|
|
|
||
|
|
// Tear: horizontal displacement
|
||
|
|
if math.Sin(float64(y)*0.05) > 0.92 {
|
||
|
|
shift := int(math.Sin(float64(y)*0.3) * 40)
|
||
|
|
nx := x + shift
|
||
|
|
if nx >= 0 && nx < w {
|
||
|
|
img.SetRGBA(nx, y, color.RGBA{r, g, b, 255})
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
img.SetRGBA(x, y, color.RGBA{r, g, b, 255})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
addScanlines(img, w, h, 0.05)
|
||
|
|
}
|
||
|
|
|
||
|
|
func drawBitCascade(img *image.RGBA, w, h int) {
|
||
|
|
shift := rand.Intn(8)
|
||
|
|
fillBg(img, w, h, color.RGBA{0, 0, 0, 255}, color.RGBA{0, 0, 10, 255})
|
||
|
|
|
||
|
|
for y := 0; y < h; y++ {
|
||
|
|
for x := 0; x < w; x++ {
|
||
|
|
bx, by := x>>2, y>>2
|
||
|
|
v1 := (bx ^ by) >> shift
|
||
|
|
v2 := (bx & by)
|
||
|
|
v3 := (bx | by) * 3
|
||
|
|
|
||
|
|
r := uint8((v1 * 13) % 256)
|
||
|
|
g := uint8((v2 * 7) % 256)
|
||
|
|
b := uint8((v3 * 5) % 256)
|
||
|
|
|
||
|
|
// Cascade: progressive corruption downward
|
||
|
|
corruptChance := float64(y) / float64(h)
|
||
|
|
if rand.Float64() < corruptChance*0.02 {
|
||
|
|
r, g, b = 255-r, 255-g, 255-b
|
||
|
|
}
|
||
|
|
|
||
|
|
img.SetRGBA(x, y, color.RGBA{r, g, b, 255})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
addGlitchBars(img, w, h, int(float64(h)*0.005))
|
||
|
|
}
|
||
|
|
|
||
|
|
func drawDeepScan(img *image.RGBA, w, h int) {
|
||
|
|
scanY := rand.Float64()
|
||
|
|
accent := []color.RGBA{
|
||
|
|
{0, 255, 100, 255}, {255, 50, 50, 255}, {50, 100, 255, 255},
|
||
|
|
}[rand.Intn(3)]
|
||
|
|
|
||
|
|
fillBg(img, w, h, color.RGBA{0, 0, 0, 255}, color.RGBA{5, 5, 8, 255})
|
||
|
|
|
||
|
|
// Horizontal bands of data
|
||
|
|
for y := 0; y < h; y++ {
|
||
|
|
fy := float64(y) / float64(h)
|
||
|
|
bandDist := math.Abs(fy - scanY)
|
||
|
|
intensity := math.Exp(-bandDist * 8)
|
||
|
|
|
||
|
|
for x := 0; x < w; x++ {
|
||
|
|
noise := float64((x*3571+y*2819)%256) / 256.0
|
||
|
|
v := intensity * (0.5 + noise*0.5)
|
||
|
|
|
||
|
|
r := clamp(float64(accent.R) * v)
|
||
|
|
g := clamp(float64(accent.G) * v)
|
||
|
|
b := clamp(float64(accent.B) * v)
|
||
|
|
|
||
|
|
// Data blocks
|
||
|
|
if intensity > 0.3 && (x/6+y/3)%4 == 0 {
|
||
|
|
r = clamp(float64(r) * 2)
|
||
|
|
g = clamp(float64(g) * 2)
|
||
|
|
b = clamp(float64(b) * 2)
|
||
|
|
}
|
||
|
|
|
||
|
|
img.SetRGBA(x, y, color.RGBA{r, g, b, 255})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
addScanlines(img, w, h, 0.06)
|
||
|
|
addGlitchBars(img, w, h, 8)
|
||
|
|
}
|
||
|
|
|
||
|
|
func drawEntropyWave(img *image.RGBA, w, h int) {
|
||
|
|
seed1 := rand.Float64() * 100
|
||
|
|
seed2 := rand.Float64() * 100
|
||
|
|
palette := []color.RGBA{
|
||
|
|
{uint8(rand.Intn(256) | 128), uint8(rand.Intn(128)), uint8(rand.Intn(256)), 255},
|
||
|
|
{uint8(rand.Intn(128)), uint8(rand.Intn(256) | 128), uint8(rand.Intn(256)), 255},
|
||
|
|
{uint8(rand.Intn(256)), uint8(rand.Intn(128)), uint8(rand.Intn(256) | 128), 255},
|
||
|
|
}
|
||
|
|
|
||
|
|
for y := 0; y < h; y++ {
|
||
|
|
for x := 0; x < w; x++ {
|
||
|
|
fx := float64(x)/float64(w)*6 + seed1
|
||
|
|
fy := float64(y)/float64(h)*6 + seed2
|
||
|
|
|
||
|
|
v := math.Sin(fx*2)*math.Cos(fy*3) +
|
||
|
|
math.Sin((fx+fy)*1.5)*0.5 +
|
||
|
|
math.Cos(fx*fy*0.3)*0.3
|
||
|
|
|
||
|
|
// Normalize -ish to 0..1
|
||
|
|
v = v*0.3 + 0.5
|
||
|
|
if v < 0 {
|
||
|
|
v = 0
|
||
|
|
}
|
||
|
|
if v > 1 {
|
||
|
|
v = 1
|
||
|
|
}
|
||
|
|
|
||
|
|
idx := v * float64(len(palette)-1)
|
||
|
|
i1 := int(idx)
|
||
|
|
if i1 >= len(palette)-1 {
|
||
|
|
i1 = len(palette) - 2
|
||
|
|
}
|
||
|
|
frac := idx - float64(i1)
|
||
|
|
|
||
|
|
c := lerpColor(palette[i1], palette[i1+1], frac)
|
||
|
|
|
||
|
|
// Entropy: increasing noise toward bottom
|
||
|
|
entropy := float64(y) / float64(h)
|
||
|
|
if rand.Float64() < entropy*0.08 {
|
||
|
|
c.R ^= uint8(rand.Intn(256))
|
||
|
|
c.G ^= uint8(rand.Intn(256))
|
||
|
|
c.B ^= uint8(rand.Intn(256))
|
||
|
|
}
|
||
|
|
|
||
|
|
img.SetRGBA(x, y, c)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
addGlitchBars(img, w, h, 6)
|
||
|
|
}
|
||
|
|
|
||
|
|
func rand_Intn(n int) uint8 {
|
||
|
|
return uint8(rand.Intn(n))
|
||
|
|
}
|