Skip to content

Commit b5bfd94

Browse files
Update hashart logic
1 parent aae28ed commit b5bfd94

File tree

3 files changed

+41
-32
lines changed

3 files changed

+41
-32
lines changed

config/shortcodes/hashArt.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1+
/**
2+
* @param {string} hash - A 40-character git hash from which to generate the grayscale art. Example: `7064455f12fcd0632debc20ea5cc333395c2baa5`.
3+
*/
14
const hashArt = (hash) => {
5+
// Buffer.from(hash, 'hex') will give us an array of 20 bytes; Uint8Array will interpret each byte in decimal
26
const bytes = new Uint8Array(Buffer.from(hash, 'hex'));
7+
// Markup for the artwork
38
let result = `<div class="hash-art-grid" role="img" aria-label="A four-by-four grid of grayscale tiles generated from the hash ${hash}.">`;
9+
// we want a 4x4=16-tile grid, so exclude the last four bytes
410
for (let i = 0; i < bytes.length - 4; i++) {
5-
const [r, g, b] = bytes.slice(i, i + 3);
6-
result += `<div style="background-color: rgb(${r}, ${g}, ${b})"></div>`;
11+
const gray = bytes[i];
12+
result += `<div style="background-color: rgb(${gray}, ${gray}, ${gray})"></div>`;
713
}
814
result += `</div>`;
915
return result;

src/_posts/2022-05-31-16-shades-of-gray/index.md

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ title: 16 Shades of Gray
33
description: The one where I create my first generative artwork and still refuse to use any color on my site.
44
keywords: [generative art, hash art, git hash]
55
categories: [essay, node, css, math, art]
6-
lastUpdated: 2022-06-01
76
thumbnail: ./images/hash.png
87
---
98

@@ -15,41 +14,46 @@ This is just a fancy way of saying that I'm too lazy to pick a good color palett
1514

1615
In a recent redesign of my site, I also decided to make my layout wider and bigger, but this left a noticeably big gap to the right of the hero banner on my home page. And thus began my quest to fill that space with something meaningless to stare at. It wouldn't really make sense to show a photo of myself next to my name and intro, so I had to search for more reasonable options.
1716

18-
I'm a fan of generative art, especially those that are seeded with random hashes—like Jordan Scales's [hashart](https://hash.jordanscales.com/) project, where he draws various math-based artworks using SHA-256 hashes. I also recently had an idea to [show my site's git hash in my footer](/blog/eleventy-build-info/#3-getting-the-latest-commit-hash) as part of my 11ty build. And so I wondered: Could I somehow turn this random string of symbols into a mediocre work of art? Indeed, I could!
17+
I enjoy generative art, especially works that are seeded with random hashes—like Jordan Scales's [hashart](https://hash.jordanscales.com/) project, where he draws various math-based artworks using SHA-256 hashes. I also recently had an idea to [show my site's git hash in my footer](/blog/eleventy-build-info/#3-getting-the-latest-commit-hash) as part of my 11ty build. And so I wondered: Could I somehow turn this random string of symbols into a mediocre work of art? Indeed, I could!
1918

20-
The code to do this is short—it just reads my latest Git commit hash, interprets it as an array of bytes, and maps every group of three consecutive bytes (minus the last one) to an RGB color:
19+
I decided to take my git hash and convert it to a four-by-four grid of colored tiles. Naturally, having been confronted about my phobia of color, I had no choice but to redouble my efforts and make this a *grayscale* artwork, in keeping with tradition. To introduce color when I've renounced it for so long would be regressive, a sign of weakness, and cause for rebellion.
2120

22-
```js
21+
The code to do this is short—it just reads my latest Git commit hash at build time and converts it to an array of bytes. Since one byte represents <code>2<sup>8</sup> = 256</code> values, and there are `256` values per channel in the RGB true color model, it makes sense to just interpret each byte as a color value. Grays are achieved by setting red, green, and blue to all be the same value. Note that I'm excluding the last four bytes because there are 20 bytes in a Git hash, and I'm only interested in the first 16 for the sake of symmetry.
22+
23+
```js {data-copyable="true"}
2324
const hash = childProcess.execSync(`git rev-parse HEAD`).toString().trim();
2425
const bytes = new Uint8Array(Buffer.from(hash, 'hex'));
2526
let result = `<div class="hash-art-grid">`;
2627
for (let i = 0; i < bytes.length - 4; i++) {
27-
const [r, g, b] = bytes.slice(i, i + 3);
28-
result += `<div style="background-color: rgb(${r}, ${g}, ${b})"></div>`;
28+
const gray = bytes[i];
29+
const color = `rgb(${gray}, ${gray}, ${gray})`;
30+
result += `<div style="background-color: ${color}"></div>`;
2931
}
3032
result += `</div>`;
3133
```
3234

33-
Naturally, having been confronted about my phobia of color, I had no choice but to redouble my efforts and make this a *grayscale* artwork, in keeping with tradition. To introduce color when I've renounced it for so long would be regressive, a sign of weakness, and cause for rebellion.
34-
35-
{% aside %}
36-
Also, I'm lazy.
37-
{% endaside %}
38-
39-
```css
40-
.hash-art-grid {
41-
filter: grayscale(1);
42-
}
43-
```
44-
45-
{% assign hash1 = "3b5875ce12be8bd07cf00249732c8edd7da6145f" %}
46-
Here's an example that was seeded with a hash of `{{ hash1 }}`:
47-
48-
{% hashArt hash1 %}
49-
50-
{% assign hash2 = "c302c6eabb43d3b6960279f44457168802a165db" %}
51-
And here's a fun one using `{{ hash2 }}`:
52-
53-
{% hashArt hash2 %}
54-
55-
There is just one problem: Mathematically speaking, the hash should eventually generate an embarrassing permutation of tiles. When you consider that I [make frequent and atomic commits](/blog/atomic-git-commits/), this may not end well. On the other hand, there are 256 grayscale values for each of the 16 tiles, which when you do the math comes out to—*counts fingers*—lots and lots of permutations. So it's unlikely that I'll ever run into edge cases where this algorithm produces something silly.
35+
Below are some examples of the output images this generates:
36+
37+
{%- assign hashes = "d0c50e3e6e5c215b49afe882bce5e382cb16c626,3b203fd5b0bde1a51cb39de0823e64dd27bab798,3b5875ce12be8bd07cf00249732c8edd7da6145f,0f1f9f3e7a5c6cdd8263e20b0afb18cfe64e696c,c32a1cde0eb3d3c99d9b12d6025c1de43b510ed7" | split: "," -%}
38+
39+
<div class="scroll-x" role="region">
40+
<table>
41+
<caption>Git hashes interpreted as four-by-four grayscale grids</caption>
42+
<thead>
43+
<tr>
44+
<th scope="col">Hash</th>
45+
<th scope="col">Output</th>
46+
</tr>
47+
</thead>
48+
<tbody>
49+
{% for hash in hashes %}
50+
<tr>
51+
<td><code>{{ hash }}</code></td>
52+
<td>{% hashArt hash %}</td>
53+
</tr>
54+
{% endfor %}
55+
</tbody>
56+
</table>
57+
</div>
58+
59+
Nothing super exciting, but there is one problem: Mathematically speaking, the hash should eventually generate an embarrassing permutation of tiles. When you consider that I [make frequent and atomic commits](/blog/atomic-git-commits/), this may not end well. On the other hand, there are 256 grayscale values for each of the 16 tiles, which when you do the math comes out to—*counts fingers*—lots and lots of permutations. So it's unlikely that I'll ever run into edge cases where this algorithm produces something silly. Plus, there are only so many ways to draw things in the confines of a four-by-four grid.

src/assets/styles/partials/pages/_home.scss

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
.hash-art-grid {
2828
display: grid;
2929
grid-template-columns: repeat(4, minmax(#{spacing("5")}, #{spacing("9")}));
30-
filter: grayscale(1);
3130

3231
> * {
3332
aspect-ratio: 1;

0 commit comments

Comments
 (0)