Website Wallpaper

2024-05-03

I spent a little time this morning making this site’s background. You can see the results - well, right here.

Creative coding at Recurse

One cool activity at the Recurse Center is a weekly “Creative Coding” meetup. Just before the session, someone picks a prompt– often a line or phrase from a poem. We get together to discuss ideas, implement them, and share them.

A couple weeks ago, the prompt was “proud-pied”, glossed as “gorgeously variegated”. I put together this page, which generates a background by simulating an interleaving of several variegated yarn strands. See more at the source.

That was a neat exploration into Javascript’s canvas, and I’m happy with how it came out. Especially with the dynamism– refreshing can give very different results.

But (as implemented) it’s relatively resource-intensive on the client, and I don’t want to require a client to run Javascript for it to look good.

Wallpaper of the mind

When I was quite young, my parents asked me what color I wanted my bedroom painted. I said I wanted it to look like blue jeans. They delivered: growing up, my walls were blue-jean blue, with thin, irregular white lines criss-crossing it.

I realized this would be pretty simple to simulate. Draw blue, add some random vertical and horizontal lines, tweak the randomness curve to make it match my memories.

Moreover, I could tweak the build process for my site to generate a new background on each deploy– giving it some dynamism over time, but not requiring anything dynamic on the user’s side.

Results

The full background:

Copy of the background image

Source code

There’s plenty to tweak- in particular, this mechanism doesn’t necessarily give me the density that I want.

That said, here’s the source code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package main

import (
	"fmt"
	"image"
	"image/color"
	"image/png"
	"math/rand"
	"os"
)

const (
	DIMENSIONS = 512
	HALF       = DIMENSIONS / 2
	QUARTER    = HALF / 2
)

var (
	white1 = color.RGBA{220, 220, 220, 255}
	white2 = color.RGBA{160, 200, 245, 255}
	white3 = color.RGBA{215, 229, 247, 255}
	blue   = color.RGBA{65, 151, 232, 255}
)

// We draw the image modulo-half-the-image.
// Rewrite each coordinate.
func mod(coord int) int {
	return coord % HALF
}

func makeImage() image.Image {
	palette := color.Palette{
		blue, white1, white2, white3,
	}

	img := image.NewPaletted(image.Rect(0, 0, DIMENSIONS, DIMENSIONS), palette)
	for y := 0; y < img.Bounds().Min.Y; y += 1 {
		for x := 0; x < img.Bounds().Min.X; x += 1 {
			img.Set(x, y, blue)
		}
	}

	// First, the columns.
	// More spaced out.
	for x := 0; x < img.Bounds().Max.X; x += 12 {
		white := palette[1:][rand.Intn(3)]

		// Intentionally biased towards thinner lines, slightly.
		width := rand.Int() % 3
		// We allow overlapping columns; they may be of different widths.
		start := rand.Intn(DIMENSIONS)
		length := rand.Intn(QUARTER)
		for i := 0; i < length; i += 1 {
			for j := 0; j < width; j++ {
				img.Set(mod(x+j), mod(i+start), white)
				img.Set(mod(x+j)+HALF, mod(i+start), white)
				img.Set(mod(x+j)+HALF, mod(i+start)+HALF, white)
				img.Set(mod(x+j), mod(i+start)+HALF, white)
			}
		}
	}

	// Rows
	for y := 0; y < img.Bounds().Max.Y; y += 6 {
		white := palette[1:][rand.Intn(3)]
		// Just single-width lines.
		// Mostly shorter lines.
		start := rand.Intn(DIMENSIONS)
		length := rand.Intn(QUARTER / 3)
		for i := 0; i < length; i += 1 {
			img.Set(mod(start+i), mod(y), white)
			img.Set(mod(start+i)+HALF, mod(y), white)
			img.Set(mod(start+i)+HALF, mod(y)+HALF, white)
			img.Set(mod(start+i), mod(y)+HALF, white)
		}
	}

	// We generated four tiles, so we only need to actually pick up one quarter.
	return img.SubImage(image.Rect(0, 0, HALF, HALF))
}

func make() error {
	return png.Encode(os.Stdout, makeImage())
}

func main() {
	if err := make(); err != nil {
		fmt.Fprintf(os.Stderr, "encountered error: %s", err)
	}
}