Step 1: Get Colors

First, some code eats the source image and selects colors, trying to pick “interesting” colors that occur a lot in an image. In this case, its version of interesting means saturated colors.

In the event that less than 32 colors are discovered, I shuffle those that it discovered as repeats to pad out the total color wells to 32. This is just an arbitrary choice on my part. It's how many stripes I wanted. Now, we should have a bunch of colors set aside:

  • R G B
    43,64,22
  • R G B
    75,104,54
  • R G B
    115,142,101
  • R G B
    14,27,4
  • R G B
    132,64,8
  • R G B
    191,129,58
  • R G B
    236,155,88
  • R G B
    222,173,85
  • R G B
    252,224,116
  • R G B
    139,11,12
  • R G B
    200,72,22
  • R G B
    233,103,45

An aside: a little digital color theory

On a computer, the most common way of defining colors is a mixture of three primary colors: red, green, and blue (RGB). In theory, the combinations of these three colors can reproduce just about any color. Note: this is far from true, but for our purposes, let’s run with it.

Try looking at your computer screen or television with a magnifying glass (or a droplet of water) and you’ll suddenly see little red, green, and blue lights, and you’ll see how it works.
photo of pixels

In our case, each “channel” of the color (RGB) has up to 256 shades, stored from 0-255, inclusive. So about 50% brightness red is the value 127/255*.

diagram showing rgb color examples

Each of the three channels has its own value of 0-255. All the channels on full brightness looks like white, all on zero looks like black. When the channels are near to the same value, it’s pretty much grey.

Imaginative readers will immediately grok that when the values are divergent you get richly-hued colors:
diagram showing difference in rgb saturations

Step 2: Permutation

My code takes advantage of this numerical representation of color to do variations on colors. It’s a simple algorithm: each initial color value is wiggled a bit, with some very constraints (so the change isn’t too jarring) and saved. There’s no attempt to preserve hue, brightness, or anything else. Each color has this done many times. I asked a mathematician what this is called, and he said it’s called a “random walk”.

We just have values so far, even though they started from colors — they're just numbers. Seen as text, the data looks like this:

ì›X‹ Þ­UsŽe„@¿:ég-ég-‹ +@üàtüàt+@¿:üàtKh6sŽeì›XÈH—–Q—–Qì›XÈHKh6¿:ég-„@Þ­U„@ìX á­XrŽf ‚@œ€=èi-æh.,=ûãvþàq*?À‚7úÞrKh4tgëœVÉJ——N•—OéžUÊJNe3Â~8ëd+‚=ݯU…B íœ[Œ â¬Ys‹e $ > œ}>èf-ée0Œ,<þáyüâp,>Á„9ýàpLj6vŽdê™VÇJ––P“šNçžVÊGQc3Ā;éa.ƒ@Þ¯VˆE ëœ]Š ß©\uŠb !ƒ>Œ{Açe-êg2Ž);þã{ûäm+@Ÿ†9ÿâsOh3x‹fë›UÆH““O›MéžSÇHPd0Á‚=æ_/…B Þ¯X†B ë™[ˆ Üš_x‡d "…<¹{Cåh,ìf0Œ,=ÿá{üæm,B¿ˆ8ÿãvMj3!u‰ièWÄI”‘P“šSê TÉISa.ā>è_1‚E à¬V†B ë˜]† Û«au…f $ˆ9»z@æh*ïg2Ž-;ÿázùåo)?‰8üãvKj6#t‹gêœWÇH’ŽN“Sé¡RÊKSb0NJ@éb2€D ß®U‰E ê–^ˆ Ú¬cr‡c#‹7Ÿx=æh'ïj/ />üãzøäp+?ņ8þãxNl8$tˆjêžXÄGQ–žQë£PÇJS`0ȍ@éd/€Gá°T‡Dè˜\‰ Ý«du†d$Ž9œw?ãj)òl1,Aþåxûãm.B‡6ÿà{Pm;!s‰míXÆJ‘ŽR“ Oé¢RÄJQc0ŏBçg0I à²SˆAë˜_† Ú«ewˆf–Aºz=äi*õl.Ž -Düãwýåk+@Å8ÿá|Oo9v‡lêœYÃHO‘ Më£RÁLRe1‘Båe-€H ãŽV†B é›_‡ ݬft‡d–@·{>äk-õn+Œ0Dýãzüçi)?ņ9ÿâyNr;v„iíœ[ÅGŒN”Jí£PÃNTd0Á‘Eãe+ƒKä·W†Eæ™`† Þ¯htŠe“BŽy@æl+øq+Š 3Dúà{ú

Yeah, you can't read it — it's not words, and not all values within 0-255 even map to normal letters — but you get the idea. These values can be mapped into colors, one by one, and they can be lined-up, and made into a stripe, like this:

diagram illustrationg color permutations

Step 3: Expanding the Stripes

Why 480 repetitions? Well, that goes back to 32. That was indeed arbitrary. What was NOT arbitrary was that as individual 1-pixel stripes, the twinkles don’t look very nice:

image showing flat lines of color pixels

When I first made one of these, I wanted to SEE the variation, and you can’t really see that up there. So I expanded it, it so happens 10x, and then I could see. So now those 32 1-pixel lines become 32 strips 10px wide, or 320px. And when I had some prints made, the print sizes are 2:3 ratio, which let me to 480px. And here we are:

sample twinkle image

Interesting Cumulative Effects

Through the repetition, the colors get more intense and garish. Every time. Compare the left side of a twinkle with the right. I didn’t set out for that to happen. It’s an emergent property of the way I wrote the random walk code; maybe it’s standard from a random walk. Remember that each “channel” of the color gets its own random change, so the colors can get wider and wider apart as the code loops. I like how the subtle/natural colors of a real-world photo start out on the left and get more techno as they proceed. This is just another happy accident.

twinkle image illustrating increasingly garish colors

Sometimes the colors get too artificial, but that’s just a particularity of this algorithm. I tend to like the colors in the middle, and sometimes I just want to zoom-in on one little area that has an unexpected combination of gorgeous complimentary colors in a little square of space.

zoomed-in crops of twinkle stripes

Coming soon... ?

It will be fun trying to encode my own sense of beauty into code and to find more cool algorithms. I'm also experimenting with moving “twinkles” and interactive stuff. Meanwhile, I hope that you like Twnkl.it as it is.

More “about” pages:
About (General)   ✣   Tech, Tools & Code   ✩   About Me

This isn’t even true, if you take gamma correction into account, but we aren’t doing digital imaging 101 here :-) ... jump back