A place to cache linked articles (think custom and personal wayback machine)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.md 77KB

3 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. title: Representing SHA-256 Hashes As Avatars
  2. url: https://francoisbest.com/posts/2021/hashvatars
  3. hash_url: be7ca5728939adfc50b9eef6818d6f63
  4. <p class="chakra-text css-8fkoyy">If you <a target="_blank" rel="noopener noreferrer" class="chakra-link css-y3jojq" href="https://twitter.com/fortysevenfx">follow me on Twitter</a>, you may be aware
  5. of my weird <a target="_blank" rel="noopener noreferrer" class="chakra-link css-y3jojq" href="https://twitter.com/search?q=%40fortysevenfx%20%22weekend%20project%22">weekend projects</a>.</p><p class="chakra-text css-8fkoyy">They are little challenges I give myself, usually without too many stakes
  6. involved, and with small enough a scope so that I can ship it in a day or two,
  7. while keeping spare family time.</p><p class="chakra-text css-8fkoyy">This weekend's project is to build a transaction explorer for the <a target="_blank" rel="noopener noreferrer" class="chakra-link css-y3jojq" href="https://centralized-coin.com">Centralized Coin</a>
  8. experiment. Something like a blockchain explorer, but without the crypto overhead.</p><p class="chakra-text css-8fkoyy">Each node in the system is represented by a hash. Because humans are
  9. terrible at reading and quickly identifying large numbers (other than by their
  10. first or last few digits), a visual representation is needed.</p><p class="chakra-text css-8fkoyy">There are <a target="_blank" rel="noopener noreferrer" class="chakra-link css-y3jojq" href="https://barro.github.io/2018/02/avatars-identicons-and-hash-visualization/">many solutions</a>
  11. out there: WordPress and GitHub identicons, <a target="_blank" rel="noopener noreferrer" class="chakra-link css-y3jojq" href="https://robohash.org/">robohash</a>, monsterID etc..</p><p class="chakra-text css-8fkoyy">I wanted one that still looks abstract (not as opinionated as monsters or robots),
  12. and that plays nice in a rounded avatar UI component.</p><p class="chakra-text css-8fkoyy">This is what I ended up with:<br><small class="chakra-text css-1lrujbg">Change the input below to see how the SHA-256 hash changes the render</small></p><p class="chakra-text css-8fkoyy">If you are allergic to maths and trigonometry, feel free to play with the more
  13. detailed <a class="chakra-link css-y3jojq" href="/hashvatar">interactive example here</a>. Otherwise, let's dive into
  14. how it's done.</p><h2 class="chakra-heading css-1rjvsw4" id="space-partitioning">Space Partitioning<a class="chakra-link css-jchjfc" aria-label="anchor" href="#space-partitioning">#</a></h2><p class="chakra-text css-8fkoyy">Many of the existing solutions produce square images, yet avatars are often
  15. displayed as circles. They would lose information on the corners when rounded,
  16. so instead of a cartesian (x-y) approach, we're going to use polar (angle-radius)
  17. coordinates instead.</p><p class="chakra-text css-8fkoyy">A grid in cartesian space maps to concentric circles and pie-like cuts in
  18. polar space.</p><p class="chakra-text css-8fkoyy">SHA-256 hashes have 256 bits of information that we need to represent. Dividing
  19. a circle into 256 sections would make each section too small to be visually useful,
  20. and would only leave 1 bit of "value" to represent in each section
  21. (0 or 1, black or white).</p><p class="chakra-text css-8fkoyy">Instead, we're going to divide the circle into 32 sections:</p><ul role="list" class="css-80rt2u"><li class="css-77vupy">4 concentric rings</li><li class="css-77vupy">8 pie-like cuts</li></ul><p class="chakra-text css-8fkoyy">The resulting SVG code for such a grid looks like this (in a React component):</p><pre class="language-tsx"><code class="language-tsx"><span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token function-variable function"><span class="token maybe-class-name">SHA256Avatar</span></span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
  22. <span class="token keyword">const</span> r1 <span class="token operator">=</span> <span class="token number">1</span>
  23. <span class="token keyword">const</span> r2 <span class="token operator">=</span> r1 <span class="token operator">*</span> <span class="token number">0.75</span>
  24. <span class="token keyword">const</span> r3 <span class="token operator">=</span> r1 <span class="token operator">*</span> <span class="token number">0.5</span>
  25. <span class="token keyword">const</span> r4 <span class="token operator">=</span> r1 <span class="token operator">*</span> <span class="token number">0.25</span>
  26. <span class="token keyword">return</span> <span class="token punctuation">(</span>
  27. <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>svg</span> <span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>-1 -1 2 2<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token plain-text">
  28. </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>circle</span> <span class="token attr-name">cx</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token number">0</span><span class="token punctuation">}</span></span> <span class="token attr-name">cy</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token number">0</span><span class="token punctuation">}</span></span> <span class="token attr-name">r</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>r1<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span><span class="token plain-text">
  29. </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>circle</span> <span class="token attr-name">cx</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token number">0</span><span class="token punctuation">}</span></span> <span class="token attr-name">cy</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token number">0</span><span class="token punctuation">}</span></span> <span class="token attr-name">r</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>r2<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span><span class="token plain-text">
  30. </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>circle</span> <span class="token attr-name">cx</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token number">0</span><span class="token punctuation">}</span></span> <span class="token attr-name">cy</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token number">0</span><span class="token punctuation">}</span></span> <span class="token attr-name">r</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>r3<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span><span class="token plain-text">
  31. </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>circle</span> <span class="token attr-name">cx</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token number">0</span><span class="token punctuation">}</span></span> <span class="token attr-name">cy</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token number">0</span><span class="token punctuation">}</span></span> <span class="token attr-name">r</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>r4<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span><span class="token plain-text">
  32. </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>line</span> <span class="token attr-name">x1</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token operator">-</span>r1<span class="token punctuation">}</span></span> <span class="token attr-name">x2</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>r1<span class="token punctuation">}</span></span> <span class="token attr-name">y1</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token number">0</span><span class="token punctuation">}</span></span> <span class="token attr-name">y2</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token number">0</span><span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span><span class="token plain-text">
  33. </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>line</span> <span class="token attr-name">y1</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token operator">-</span>r1<span class="token punctuation">}</span></span> <span class="token attr-name">y2</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>r1<span class="token punctuation">}</span></span> <span class="token attr-name">x1</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token number">0</span><span class="token punctuation">}</span></span> <span class="token attr-name">x2</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token number">0</span><span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span><span class="token plain-text">
  34. </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>line</span>
  35. <span class="token attr-name">x1</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token operator">-</span>r1 <span class="token operator">*</span> <span class="token known-class-name class-name">Math</span><span class="token punctuation">.</span><span class="token constant">SQRT1_2</span><span class="token punctuation">}</span></span>
  36. <span class="token attr-name">x2</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>r1 <span class="token operator">*</span> <span class="token known-class-name class-name">Math</span><span class="token punctuation">.</span><span class="token constant">SQRT1_2</span><span class="token punctuation">}</span></span>
  37. <span class="token attr-name">y1</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token operator">-</span>r1 <span class="token operator">*</span> <span class="token known-class-name class-name">Math</span><span class="token punctuation">.</span><span class="token constant">SQRT1_2</span><span class="token punctuation">}</span></span>
  38. <span class="token attr-name">y2</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>r1 <span class="token operator">*</span> <span class="token known-class-name class-name">Math</span><span class="token punctuation">.</span><span class="token constant">SQRT1_2</span><span class="token punctuation">}</span></span>
  39. <span class="token punctuation">/&gt;</span></span><span class="token plain-text">
  40. </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>line</span>
  41. <span class="token attr-name">x1</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>r1 <span class="token operator">*</span> <span class="token known-class-name class-name">Math</span><span class="token punctuation">.</span><span class="token constant">SQRT1_2</span><span class="token punctuation">}</span></span>
  42. <span class="token attr-name">x2</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token operator">-</span>r1 <span class="token operator">*</span> <span class="token known-class-name class-name">Math</span><span class="token punctuation">.</span><span class="token constant">SQRT1_2</span><span class="token punctuation">}</span></span>
  43. <span class="token attr-name">y1</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span><span class="token operator">-</span>r1 <span class="token operator">*</span> <span class="token known-class-name class-name">Math</span><span class="token punctuation">.</span><span class="token constant">SQRT1_2</span><span class="token punctuation">}</span></span>
  44. <span class="token attr-name">y2</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>r1 <span class="token operator">*</span> <span class="token known-class-name class-name">Math</span><span class="token punctuation">.</span><span class="token constant">SQRT1_2</span><span class="token punctuation">}</span></span>
  45. <span class="token punctuation">/&gt;</span></span><span class="token plain-text">
  46. </span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>svg</span><span class="token punctuation">&gt;</span></span>
  47. <span class="token punctuation">)</span>
  48. <span class="token punctuation">}</span>
  49. </code></pre><p class="chakra-text css-8fkoyy">Doing this naively, with each concentric ring's radius being 1/4th of the
  50. outermost/largest one gives us this:</p><svg xmlns="http://www.w3.org/2000/svg" role="img" viewbox="-1 -1 2 2" class="css-q1xci"><g><path d="M 0 0 L 6.123233995736766e-17 -1 A 1 1 0 0 1 0.7071067811865476 -0.7071067811865475 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.7071067811865476 -0.7071067811865475 A 1 1 0 0 1 1 0 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 1 0 A 1 1 0 0 1 0.7071067811865476 0.7071067811865475 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.7071067811865476 0.7071067811865475 A 1 1 0 0 1 6.123233995736766e-17 1 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 6.123233995736766e-17 1 A 1 1 0 0 1 -0.7071067811865475 0.7071067811865476 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.7071067811865475 0.7071067811865476 A 1 1 0 0 1 -1 1.2246467991473532e-16 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -1 1.2246467991473532e-16 A 1 1 0 0 1 -0.7071067811865477 -0.7071067811865475 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.7071067811865477 -0.7071067811865475 A 1 1 0 0 1 -1.8369701987210297e-16 -1 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -1.3777276490407724e-16 -0.75 A 0.75 0.75 0 0 1 0.5303300858899105 -0.5303300858899107 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.5303300858899105 -0.5303300858899107 A 0.75 0.75 0 0 1 0.75 -1.8369701987210297e-16 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.75 -1.8369701987210297e-16 A 0.75 0.75 0 0 1 0.5303300858899113 0.53033008588991 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.5303300858899113 0.53033008588991 A 0.75 0.75 0 0 1 2.2962127484012875e-16 0.75 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 2.2962127484012875e-16 0.75 A 0.75 0.75 0 0 1 -0.5303300858899109 0.5303300858899104 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.5303300858899109 0.5303300858899104 A 0.75 0.75 0 0 1 -0.75 2.755455298081545e-16 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.75 2.755455298081545e-16 A 0.75 0.75 0 0 1 -0.5303300858899114 -0.5303300858899099 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.5303300858899114 -0.5303300858899099 A 0.75 0.75 0 0 1 -3.214697847761802e-16 -0.75 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -2.143131898507868e-16 -0.5 A 0.5 0.5 0 0 1 0.3535533905932739 -0.3535533905932736 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.3535533905932739 -0.3535533905932736 A 0.5 0.5 0 0 1 0.5 -2.4492935982947064e-16 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.5 -2.4492935982947064e-16 A 0.5 0.5 0 0 1 0.3535533905932743 0.3535533905932733 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.3535533905932743 0.3535533905932733 A 0.5 0.5 0 0 1 2.755455298081545e-16 0.5 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 2.755455298081545e-16 0.5 A 0.5 0.5 0 0 1 -0.35355339059327384 0.3535533905932737 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.35355339059327384 0.3535533905932737 A 0.5 0.5 0 0 1 -0.5 1.1943401194869635e-15 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.5 1.1943401194869635e-15 A 0.5 0.5 0 0 1 -0.3535533905932737 -0.35355339059327384 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.3535533905932737 -0.35355339059327384 A 0.5 0.5 0 0 1 -1.2249562894656473e-15 -0.5 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -6.124781447328236e-16 -0.25 A 0.25 0.25 0 0 1 0.17677669529663723 -0.17677669529663653 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.17677669529663723 -0.17677669529663653 A 0.25 0.25 0 0 1 0.25 -1.8369701987210297e-16 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.25 -1.8369701987210297e-16 A 0.25 0.25 0 0 1 0.17677669529663748 0.17677669529663628 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.17677669529663748 0.17677669529663628 A 0.25 0.25 0 0 1 -2.450841049886177e-16 0.25 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -2.450841049886177e-16 0.25 A 0.25 0.25 0 0 1 -0.1767766952966366 0.1767766952966372 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.1767766952966366 0.1767766952966372 A 0.25 0.25 0 0 1 -0.25 1.1024916095509121e-15 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.25 1.1024916095509121e-15 A 0.25 0.25 0 0 1 -0.1767766952966369 -0.1767766952966369 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.1767766952966369 -0.1767766952966369 A 0.25 0.25 0 0 1 -6.737104846901913e-16 -0.25 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path></g></svg><p class="chakra-text css-8fkoyy">There are some issues: the innermost ring sections are tiny compared to the outermost.</p><p class="chakra-text css-8fkoyy">If we calculate the radii so that each section has an equal area, we get
  51. the following result:</p><svg xmlns="http://www.w3.org/2000/svg" role="img" viewbox="-1 -1 2 2" class="css-q1xci"><g><path d="M 0 0 L 6.123233995736766e-17 -1 A 1 1 0 0 1 0.7071067811865476 -0.7071067811865475 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.7071067811865476 -0.7071067811865475 A 1 1 0 0 1 1 0 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 1 0 A 1 1 0 0 1 0.7071067811865476 0.7071067811865475 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.7071067811865476 0.7071067811865475 A 1 1 0 0 1 6.123233995736766e-17 1 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 6.123233995736766e-17 1 A 1 1 0 0 1 -0.7071067811865475 0.7071067811865476 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.7071067811865475 0.7071067811865476 A 1 1 0 0 1 -1 1.2246467991473532e-16 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -1 1.2246467991473532e-16 A 1 1 0 0 1 -0.7071067811865477 -0.7071067811865475 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.7071067811865477 -0.7071067811865475 A 1 1 0 0 1 -1.8369701987210297e-16 -1 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -1.5908628580873602e-16 -0.8660254037844386 A 0.8660254037844386 0.8660254037844386 0 0 1 0.6123724356957944 -0.6123724356957946 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.6123724356957944 -0.6123724356957946 A 0.8660254037844386 0.8660254037844386 0 0 1 0.8660254037844386 -2.1211504774498136e-16 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.8660254037844386 -2.1211504774498136e-16 A 0.8660254037844386 0.8660254037844386 0 0 1 0.6123724356957952 0.6123724356957938 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.6123724356957952 0.6123724356957938 A 0.8660254037844386 0.8660254037844386 0 0 1 2.6514380968122674e-16 0.8660254037844386 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 2.6514380968122674e-16 0.8660254037844386 A 0.8660254037844386 0.8660254037844386 0 0 1 -0.6123724356957948 0.6123724356957941 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.6123724356957948 0.6123724356957941 A 0.8660254037844386 0.8660254037844386 0 0 1 -0.8660254037844386 3.1817257161747205e-16 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.8660254037844386 3.1817257161747205e-16 A 0.8660254037844386 0.8660254037844386 0 0 1 -0.6123724356957952 -0.6123724356957937 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.6123724356957952 -0.6123724356957937 A 0.8660254037844386 0.8660254037844386 0 0 1 -3.7120133355371736e-16 -0.8660254037844386 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -3.030846196824227e-16 -0.7071067811865476 A 0.7071067811865476 0.7071067811865476 0 0 1 0.5000000000000002 -0.49999999999999983 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.5000000000000002 -0.49999999999999983 A 0.7071067811865476 0.7071067811865476 0 0 1 0.7071067811865476 -3.4638242249419736e-16 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.7071067811865476 -3.4638242249419736e-16 A 0.7071067811865476 0.7071067811865476 0 0 1 0.5000000000000008 0.4999999999999994 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.5000000000000008 0.4999999999999994 A 0.7071067811865476 0.7071067811865476 0 0 1 3.8968022530597204e-16 0.7071067811865476 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 3.8968022530597204e-16 0.7071067811865476 A 0.7071067811865476 0.7071067811865476 0 0 1 -0.5000000000000001 0.4999999999999999 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.5000000000000001 0.4999999999999999 A 0.7071067811865476 0.7071067811865476 0 0 1 -0.7071067811865476 1.6890519950647668e-15 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.7071067811865476 1.6890519950647668e-15 A 0.7071067811865476 0.7071067811865476 0 0 1 -0.4999999999999999 -0.5000000000000001 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.4999999999999999 -0.5000000000000001 A 0.7071067811865476 0.7071067811865476 0 0 1 -1.7323497978765413e-15 -0.7071067811865476 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -1.2249562894656473e-15 -0.5 A 0.5 0.5 0 0 1 0.35355339059327445 -0.35355339059327306 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.35355339059327445 -0.35355339059327306 A 0.5 0.5 0 0 1 0.5 -3.6739403974420594e-16 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.5 -3.6739403974420594e-16 A 0.5 0.5 0 0 1 0.35355339059327495 0.35355339059327257 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.35355339059327495 0.35355339059327257 A 0.5 0.5 0 0 1 -4.901682099772354e-16 0.5 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -4.901682099772354e-16 0.5 A 0.5 0.5 0 0 1 -0.3535533905932732 0.3535533905932744 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.3535533905932732 0.3535533905932744 A 0.5 0.5 0 0 1 -0.5 2.2049832191018243e-15 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.5 2.2049832191018243e-15 A 0.5 0.5 0 0 1 -0.3535533905932738 -0.3535533905932738 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.3535533905932738 -0.3535533905932738 A 0.5 0.5 0 0 1 -1.3474209693803826e-15 -0.5 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path></g></svg><div role="alert" class="chakra-alert css-7l7mra"><div class="chakra-alert__desc css-12db8z9"><p>Equal areas are calculated by solving a system of equations.</p><ol role="list" class="css-138fnjp"><li class="css-77vupy">Each section area is 1/32nd of the area of the whole circle. Assuming the outer circle has a radius of 1, that's an area of <code>π/32</code>.</li><li class="css-77vupy">To compute the associated radius for a ring, we express the pie slice area with the outer radius R and subtract the pie slice area with the inner radius r: <code>Pi R^2 - Pi r^2</code>, then we iterate from the outside in.</li></ol><a target="_blank" rel="noopener noreferrer" class="chakra-link css-zqkdi0" href="https://www.desmos.com/calculator/cenpmgvqdy">More details</a></div></div><p class="chakra-text css-8fkoyy">Not very pleasing either. How about a mix of both ?<br><small class="chakra-text css-0">(Play with the slider to blend between equal radii and equal areas)</small></p><p class="chakra-text css-8fkoyy">I don't know about you, but <code class="chakra-code css-1uwjdr8">0.42</code> hits the ballpark both in aesthetics and
  52. <a target="_blank" rel="noopener noreferrer" class="chakra-link css-y3jojq" href="https://xkcd.com/356/">nerd-sniping satisfaction</a>, so let's go for that.</p><h2 class="chakra-heading css-1rjvsw4" id="section-mapping">Section Mapping<a class="chakra-link css-jchjfc" aria-label="anchor" href="#section-mapping">#</a></h2><p class="chakra-text css-8fkoyy">Now that we have 32 nice looking sections on our circle, we can map each section
  53. to an 8-bit value in the hash.</p><p class="chakra-text css-8fkoyy">As an example, let's take the following hash, the output of <code class="chakra-code css-1uwjdr8">sha256("Hello, world!")</code>:</p><pre><code>315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3
  54. </code></pre><p class="chakra-text css-8fkoyy">We can split it in 32 blocks of 8 bits (2 hexadecimal digits), and organise them by
  55. 4 blocks of 8 to map to the rings:</p><pre><code>12 o'clock -&gt; clockwise
  56. 31 5f 5b db 76 d0 78 c4 Outer ring
  57. 3b 8a c0 06 4e 4a 01 64 Middle-outer ring
  58. 61 2b 1f ce 77 c8 69 34 Middle-inner ring
  59. 5b fc 94 c7 58 94 ed d3 Inner ring
  60. </code></pre><svg xmlns="http://www.w3.org/2000/svg" role="img" viewbox="-1 -1 2 2" class="css-q1xci"><g><path d="M 0 0 L 6.123233995736766e-17 -1 A 1 1 0 0 1 0.7071067811865476 -0.7071067811865475 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.7071067811865476 -0.7071067811865475 A 1 1 0 0 1 1 0 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 1 0 A 1 1 0 0 1 0.7071067811865476 0.7071067811865475 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.7071067811865476 0.7071067811865475 A 1 1 0 0 1 6.123233995736766e-17 1 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 6.123233995736766e-17 1 A 1 1 0 0 1 -0.7071067811865475 0.7071067811865476 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.7071067811865475 0.7071067811865476 A 1 1 0 0 1 -1 1.2246467991473532e-16 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -1 1.2246467991473532e-16 A 1 1 0 0 1 -0.7071067811865477 -0.7071067811865475 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.7071067811865477 -0.7071067811865475 A 1 1 0 0 1 -1.8369701987210297e-16 -1 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -1.4672444368403393e-16 -0.7987306695894643 A 0.7987306695894643 0.7987306695894643 0 0 1 0.5647878728083817 -0.564787872808382 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.5647878728083817 -0.564787872808382 A 0.7987306695894643 0.7987306695894643 0 0 1 0.7987306695894643 -1.9563259157871192e-16 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.7987306695894643 -1.9563259157871192e-16 A 0.7987306695894643 0.7987306695894643 0 0 1 0.5647878728083826 0.5647878728083813 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.5647878728083826 0.5647878728083813 A 0.7987306695894643 0.7987306695894643 0 0 1 2.4454073947338993e-16 0.7987306695894643 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 2.4454073947338993e-16 0.7987306695894643 A 0.7987306695894643 0.7987306695894643 0 0 1 -0.5647878728083822 0.5647878728083816 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.5647878728083822 0.5647878728083816 A 0.7987306695894643 0.7987306695894643 0 0 1 -0.7987306695894643 2.9344888736806786e-16 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.7987306695894643 2.9344888736806786e-16 A 0.7987306695894643 0.7987306695894643 0 0 1 -0.5647878728083826 -0.5647878728083812 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.5647878728083826 -0.5647878728083812 A 0.7987306695894643 0.7987306695894643 0 0 1 -3.4235703526274585e-16 -0.7987306695894643 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -2.5159719038007387e-16 -0.5869848480983499 A 0.5869848480983499 0.5869848480983499 0 0 1 0.4150609665440989 -0.4150609665440986 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.4150609665440989 -0.4150609665440986 A 0.5869848480983499 0.5869848480983499 0 0 1 0.5869848480983499 -2.8753964614865583e-16 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.5869848480983499 -2.8753964614865583e-16 A 0.5869848480983499 0.5869848480983499 0 0 1 0.4150609665440994 0.4150609665440982 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.4150609665440994 0.4150609665440982 A 0.5869848480983499 0.5869848480983499 0 0 1 3.2348210191723783e-16 0.5869848480983499 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 3.2348210191723783e-16 0.5869848480983499 A 0.5869848480983499 0.5869848480983499 0 0 1 -0.41506096654409885 0.4150609665440987 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.41506096654409885 0.4150609665440987 A 0.5869848480983499 0.5869848480983499 0 0 1 -0.5869848480983499 1.4021191072296408e-15 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.5869848480983499 1.4021191072296408e-15 A 0.5869848480983499 0.5869848480983499 0 0 1 -0.4150609665440987 -0.41506096654409885 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.4150609665440987 -0.41506096654409885 A 0.5869848480983499 0.5869848480983499 0 0 1 -1.4380615629982227e-15 -0.5869848480983499 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -8.697189655206095e-16 -0.355 A 0.355 0.355 0 0 1 0.25102290732122484 -0.25102290732122384 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.25102290732122484 -0.25102290732122384 A 0.355 0.355 0 0 1 0.355 -2.608497682183862e-16 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.355 -2.608497682183862e-16 A 0.355 0.355 0 0 1 0.25102290732122523 0.2510229073212235 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.25102290732122523 0.2510229073212235 A 0.355 0.355 0 0 1 -3.4801942908383715e-16 0.355 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -3.4801942908383715e-16 0.355 A 0.355 0.355 0 0 1 -0.25102290732122395 0.2510229073212248 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.25102290732122395 0.2510229073212248 A 0.355 0.355 0 0 1 -0.355 1.565538085562295e-15 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.355 1.565538085562295e-15 A 0.355 0.355 0 0 1 -0.2510229073212244 -0.2510229073212244 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.2510229073212244 -0.2510229073212244 A 0.355 0.355 0 0 1 -9.566688882600716e-16 -0.355 Z" fill="none" stroke="var(--colors-accent-500)" stroke-width="0.02" stroke-linejoin="round"></path></g><g><text x="0.34417221326942626" y="-0.800905225067014" text-anchor="middle" font-size="0.1" fill="currentColor">31</text><text x="0.830905225067014" y="-0.31417221326942624" text-anchor="middle" font-size="0.1" fill="currentColor">5f</text><text x="0.830905225067014" y="0.3741722132694262" text-anchor="middle" font-size="0.1" fill="currentColor">5b</text><text x="0.34417221326942626" y="0.8609052250670141" text-anchor="middle" font-size="0.1" fill="currentColor">db</text><text x="-0.34417221326942615" y="0.8609052250670141" text-anchor="middle" font-size="0.1" fill="currentColor">76</text><text x="-0.8309052250670138" y="0.3741722132694266" text-anchor="middle" font-size="0.1" fill="currentColor">d0</text><text x="-0.8309052250670139" y="-0.31417221326942646" text-anchor="middle" font-size="0.1" fill="currentColor">78</text><text x="-0.3441722132694267" y="-0.8009052250670138" text-anchor="middle" font-size="0.1" fill="currentColor">c4</text><text x="0.26514518529517017" y="-0.6101171023375266" text-anchor="middle" font-size="0.1" fill="currentColor">3b</text><text x="0.6401171023375266" y="-0.23514518529517045" text-anchor="middle" font-size="0.1" fill="currentColor">8a</text><text x="0.6401171023375267" y="0.2951451852951701" text-anchor="middle" font-size="0.1" fill="currentColor">c0</text><text x="0.26514518529517045" y="0.6701171023375266" text-anchor="middle" font-size="0.1" fill="currentColor">06</text><text x="-0.26514518529517006" y="0.6701171023375267" text-anchor="middle" font-size="0.1" fill="currentColor">4e</text><text x="-0.6401171023375265" y="0.29514518529517053" text-anchor="middle" font-size="0.1" fill="currentColor">4a</text><text x="-0.6401171023375267" y="-0.23514518529517006" text-anchor="middle" font-size="0.1" fill="currentColor">01</text><text x="-0.26514518529517056" y="-0.6101171023375265" text-anchor="middle" font-size="0.1" fill="currentColor">64</text><text x="0.18024099745309213" y="-0.40514026054690944" text-anchor="middle" font-size="0.1" fill="currentColor">61</text><text x="0.43514026054690935" y="-0.15024099745309252" text-anchor="middle" font-size="0.1" fill="currentColor">2b</text><text x="0.43514026054690946" y="0.2102409974530921" text-anchor="middle" font-size="0.1" fill="currentColor">1f</text><text x="0.18024099745309255" y="0.4651402605469094" text-anchor="middle" font-size="0.1" fill="currentColor">ce</text><text x="-0.1802409974530913" y="0.4651402605469098" text-anchor="middle" font-size="0.1" fill="currentColor">77</text><text x="-0.43514026054690935" y="0.21024099745309258" text-anchor="middle" font-size="0.1" fill="currentColor">c8</text><text x="-0.43514026054690924" y="-0.1502409974530928" text-anchor="middle" font-size="0.1" fill="currentColor">69</text><text x="-0.1802409974530926" y="-0.4051402605469093" text-anchor="middle" font-size="0.1" fill="currentColor">34</text><text x="0.08966272820313972" y="-0.18646497446739482" text-anchor="middle" font-size="0.1" fill="currentColor">5b</text><text x="0.21646497446739454" y="-0.059662728203140405" text-anchor="middle" font-size="0.1" fill="currentColor">fc</text><text x="0.21646497446739468" y="0.11966272820314008" text-anchor="middle" font-size="0.1" fill="currentColor">94</text><text x="0.08966272820314003" y="0.2464649744673947" text-anchor="middle" font-size="0.1" fill="currentColor">c7</text><text x="-0.08966272820314046" y="0.24646497446739454" text-anchor="middle" font-size="0.1" fill="currentColor">58</text><text x="-0.21646497446739424" y="0.11966272820314121" text-anchor="middle" font-size="0.1" fill="currentColor">94</text><text x="-0.21646497446739438" y="-0.05966272820314082" text-anchor="middle" font-size="0.1" fill="currentColor">ed</text><text x="-0.08966272820314082" y="-0.18646497446739438" text-anchor="middle" font-size="0.1" fill="currentColor">d3</text></g></svg><p class="chakra-text css-8fkoyy">In order to fill each section with a different colour, we generate an SVG <code class="chakra-code css-1uwjdr8">&lt;path&gt;</code> polygon.
  61. Each section resembles a pie/pizza slice, going from the center
  62. of the circle to a given radius, and covering 1/8th of the circle.</p><div role="alert" class="chakra-alert css-xjse24"><p class="chakra-alert__desc css-12db8z9">The reason we can get away with all sections going to the center is because of our mapping order: by laying out from the outside in, the inner sections will be overlaid on top of the outer ones in z-index.</p></div><p class="chakra-text css-8fkoyy">Since SVG uses cartesian coordinates, we'll have to convert our polar logic
  63. into cartesian SVG path commands:</p><pre class="language-tsx"><code class="language-tsx{31,32,33,34,35,36}"><span class="token keyword">interface</span> <span class="token class-name">Point</span> <span class="token punctuation">{</span>
  64. x<span class="token punctuation">:</span> <span class="token builtin">number</span>
  65. y<span class="token punctuation">:</span> <span class="token builtin">number</span>
  66. <span class="token punctuation">}</span>
  67. <span class="token keyword">function</span> <span class="token function">polarPoint</span><span class="token punctuation">(</span><span class="token parameter">radius<span class="token punctuation">:</span> <span class="token builtin">number</span><span class="token punctuation">,</span> angle<span class="token punctuation">:</span> <span class="token builtin">number</span></span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token maybe-class-name">Point</span> <span class="token punctuation">{</span>
  68. <span class="token keyword">return</span> <span class="token punctuation">{</span>
  69. x<span class="token punctuation">:</span> radius <span class="token operator">*</span> <span class="token known-class-name class-name">Math</span><span class="token punctuation">.</span><span class="token method function property-access">cos</span><span class="token punctuation">(</span><span class="token number">2</span> <span class="token operator">*</span> <span class="token known-class-name class-name">Math</span><span class="token punctuation">.</span><span class="token constant">PI</span> <span class="token operator">*</span> angle <span class="token operator">-</span> <span class="token known-class-name class-name">Math</span><span class="token punctuation">.</span><span class="token constant">PI</span> <span class="token operator">/</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  70. y<span class="token punctuation">:</span> radius <span class="token operator">*</span> <span class="token known-class-name class-name">Math</span><span class="token punctuation">.</span><span class="token method function property-access">sin</span><span class="token punctuation">(</span><span class="token number">2</span> <span class="token operator">*</span> <span class="token known-class-name class-name">Math</span><span class="token punctuation">.</span><span class="token constant">PI</span> <span class="token operator">*</span> angle <span class="token operator">-</span> <span class="token known-class-name class-name">Math</span><span class="token punctuation">.</span><span class="token constant">PI</span> <span class="token operator">/</span> <span class="token number">2</span><span class="token punctuation">)</span>
  71. <span class="token punctuation">}</span>
  72. <span class="token punctuation">}</span>
  73. <span class="token keyword">function</span> <span class="token function">moveTo</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> x<span class="token punctuation">,</span> y <span class="token punctuation">}</span><span class="token punctuation">:</span> <span class="token maybe-class-name">Point</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  74. <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">M </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>x<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>y<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span>
  75. <span class="token punctuation">}</span>
  76. <span class="token keyword">function</span> <span class="token function">lineTo</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> x<span class="token punctuation">,</span> y <span class="token punctuation">}</span><span class="token punctuation">:</span> <span class="token maybe-class-name">Point</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  77. <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">L </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>x<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>y<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span>
  78. <span class="token punctuation">}</span>
  79. <span class="token keyword">function</span> <span class="token function">arcTo</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> x<span class="token punctuation">,</span> y <span class="token punctuation">}</span><span class="token punctuation">:</span> <span class="token maybe-class-name">Point</span><span class="token punctuation">,</span> radius<span class="token punctuation">:</span> <span class="token builtin">number</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  80. <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">A </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>radius<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>radius<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> 0 0 0 </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>x<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>y<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span>
  81. <span class="token punctuation">}</span>
  82. <span class="token keyword">const</span> <span class="token function-variable function"><span class="token maybe-class-name">Section</span></span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> index<span class="token punctuation">,</span> radius <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
  83. <span class="token keyword">const</span> angleA <span class="token operator">=</span> index <span class="token operator">/</span> <span class="token number">8</span>
  84. <span class="token keyword">const</span> angleB <span class="token operator">=</span> <span class="token punctuation">(</span>index <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">8</span>
  85. <p class="mdx-marker"> <span class="token keyword">const</span> path <span class="token operator">=</span> <span class="token punctuation">[</span>
  86. </p><p class="mdx-marker"> <span class="token function">moveTo</span><span class="token punctuation">(</span><span class="token punctuation">{</span> x<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> y<span class="token punctuation">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  87. </p><p class="mdx-marker"> <span class="token function">lineTo</span><span class="token punctuation">(</span><span class="token function">polarPoint</span><span class="token punctuation">(</span>radius<span class="token punctuation">,</span> angleA<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  88. </p><p class="mdx-marker"> <span class="token function">arcTo</span><span class="token punctuation">(</span><span class="token function">polarPoint</span><span class="token punctuation">(</span>radius<span class="token punctuation">,</span> angleB<span class="token punctuation">)</span><span class="token punctuation">,</span> radius<span class="token punctuation">)</span><span class="token punctuation">,</span>
  89. </p><p class="mdx-marker"> <span class="token string">'Z'</span>
  90. </p><p class="mdx-marker"> <span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token method function property-access">join</span><span class="token punctuation">(</span><span class="token string">' '</span><span class="token punctuation">)</span>
  91. </p> <span class="token keyword">return</span> <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>path</span> <span class="token attr-name">d</span><span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span><span class="token punctuation">{</span>path<span class="token punctuation">}</span></span> <span class="token punctuation">/&gt;</span></span>
  92. <span class="token punctuation">}</span>
  93. </code></pre><h2 class="chakra-heading css-1rjvsw4" id="colour-mapping">Colour Mapping<a class="chakra-link css-jchjfc" aria-label="anchor" href="#colour-mapping">#</a></h2><p class="chakra-text css-8fkoyy">Now we can turn each section's byte value into a colour.</p><p class="chakra-text css-8fkoyy">For that, we have many options. 8 bits could map directly to 256 colours like the
  94. old Windows systems, but that would require a lookup table. Instead, we can
  95. generate colours using the <a target="_blank" rel="noopener noreferrer" class="chakra-link css-y3jojq" href="https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hsl()"><code class="chakra-code css-1uwjdr8">hsl()</code></a> CSS function.</p><p class="chakra-text css-8fkoyy">Hue is the component that has the most visual impact, while Saturation and
  96. Lightness can be used to add little variants to each section.</p><p class="chakra-text css-8fkoyy">To map our 8 bit value to 3 components, we can divide the byte into:</p><ul role="list" class="css-80rt2u"><li class="css-77vupy">4 bits for the Hue (16 values)</li><li class="css-77vupy">2 bits for the Saturation (4 values)</li><li class="css-77vupy">2 bits for the Lightness (4 values)</li></ul><pre class="language-ts"><code class="language-ts"><span class="token keyword">function</span> <span class="token function">mapValueToColor</span><span class="token punctuation">(</span><span class="token parameter">value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  97. <span class="token keyword">const</span> colorH <span class="token operator">=</span> value <span class="token operator">&gt;&gt;</span> <span class="token number">4</span>
  98. <span class="token keyword">const</span> colorS <span class="token operator">=</span> <span class="token punctuation">(</span>value <span class="token operator">&gt;&gt;</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token operator">&amp;</span> <span class="token number">0x03</span>
  99. <span class="token keyword">const</span> colorL <span class="token operator">=</span> value <span class="token operator">&amp;</span> <span class="token number">0x03</span>
  100. <span class="token keyword">const</span> normalizedH <span class="token operator">=</span> colorH <span class="token operator">/</span> <span class="token number">16</span>
  101. <span class="token keyword">const</span> normalizedS <span class="token operator">=</span> colorS <span class="token operator">/</span> <span class="token number">4</span>
  102. <span class="token keyword">const</span> normalizedL <span class="token operator">=</span> colorL <span class="token operator">/</span> <span class="token number">4</span>
  103. <span class="token keyword">const</span> h <span class="token operator">=</span> <span class="token number">360</span> <span class="token operator">*</span> normalizedH
  104. <span class="token keyword">const</span> s <span class="token operator">=</span> <span class="token number">50</span> <span class="token operator">+</span> <span class="token number">50</span> <span class="token operator">*</span> normalizedS
  105. <span class="token keyword">const</span> l <span class="token operator">=</span> <span class="token number">40</span> <span class="token operator">+</span> <span class="token number">30</span> <span class="token operator">*</span> normalizedL
  106. <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">hsl(</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>h<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">, </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>s<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">%, </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>l<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">%)</span><span class="token template-punctuation string">`</span></span>
  107. <span class="token punctuation">}</span>
  108. </code></pre><p class="chakra-text css-8fkoyy">We can adjust the range for each component to get nice results:</p><svg xmlns="http://www.w3.org/2000/svg" role="img" viewbox="-1 -1 2 2" class="css-q1xci"><g><path d="M 0 0 L 6.123233995736766e-17 -1 A 1 1 0 0 1 0.7071067811865476 -0.7071067811865475 Z" fill="hsl(67.5, 50%, 47.5%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.7071067811865476 -0.7071067811865475 A 1 1 0 0 1 1 0 Z" fill="hsl(112.5, 87.5%, 62.5%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 1 0 A 1 1 0 0 1 0.7071067811865476 0.7071067811865475 Z" fill="hsl(112.5, 75%, 62.5%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.7071067811865476 0.7071067811865475 A 1 1 0 0 1 6.123233995736766e-17 1 Z" fill="hsl(292.5, 75%, 62.5%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 6.123233995736766e-17 1 A 1 1 0 0 1 -0.7071067811865475 0.7071067811865476 Z" fill="hsl(157.5, 62.5%, 55%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.7071067811865475 0.7071067811865476 A 1 1 0 0 1 -1 1.2246467991473532e-16 Z" fill="hsl(292.5, 50%, 40%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -1 1.2246467991473532e-16 A 1 1 0 0 1 -0.7071067811865477 -0.7071067811865475 Z" fill="hsl(157.5, 75%, 40%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.7071067811865477 -0.7071067811865475 A 1 1 0 0 1 -1.8369701987210297e-16 -1 Z" fill="hsl(270, 62.5%, 40%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -1.4672444368403393e-16 -0.7987306695894643 A 0.7987306695894643 0.7987306695894643 0 0 1 0.5647878728083817 -0.564787872808382 Z" fill="hsl(67.5, 75%, 62.5%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.5647878728083817 -0.564787872808382 A 0.7987306695894643 0.7987306695894643 0 0 1 0.7987306695894643 -1.9563259157871192e-16 Z" fill="hsl(180, 75%, 55%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.7987306695894643 -1.9563259157871192e-16 A 0.7987306695894643 0.7987306695894643 0 0 1 0.5647878728083826 0.5647878728083813 Z" fill="hsl(270, 50%, 40%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.5647878728083826 0.5647878728083813 A 0.7987306695894643 0.7987306695894643 0 0 1 2.4454073947338993e-16 0.7987306695894643 Z" fill="hsl(0, 62.5%, 55%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 2.4454073947338993e-16 0.7987306695894643 A 0.7987306695894643 0.7987306695894643 0 0 1 -0.5647878728083822 0.5647878728083816 Z" fill="hsl(90, 87.5%, 55%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.5647878728083822 0.5647878728083816 A 0.7987306695894643 0.7987306695894643 0 0 1 -0.7987306695894643 2.9344888736806786e-16 Z" fill="hsl(90, 75%, 55%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.7987306695894643 2.9344888736806786e-16 A 0.7987306695894643 0.7987306695894643 0 0 1 -0.5647878728083826 -0.5647878728083812 Z" fill="hsl(0, 50%, 47.5%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.5647878728083826 -0.5647878728083812 A 0.7987306695894643 0.7987306695894643 0 0 1 -3.4235703526274585e-16 -0.7987306695894643 Z" fill="hsl(135, 62.5%, 40%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -2.5159719038007387e-16 -0.5869848480983499 A 0.5869848480983499 0.5869848480983499 0 0 1 0.4150609665440989 -0.4150609665440986 Z" fill="hsl(135, 50%, 47.5%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.4150609665440989 -0.4150609665440986 A 0.5869848480983499 0.5869848480983499 0 0 1 0.5869848480983499 -2.8753964614865583e-16 Z" fill="hsl(45, 75%, 62.5%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.5869848480983499 -2.8753964614865583e-16 A 0.5869848480983499 0.5869848480983499 0 0 1 0.4150609665440994 0.4150609665440982 Z" fill="hsl(22.5, 87.5%, 62.5%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.4150609665440994 0.4150609665440982 A 0.5869848480983499 0.5869848480983499 0 0 1 3.2348210191723783e-16 0.5869848480983499 Z" fill="hsl(270, 87.5%, 55%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 3.2348210191723783e-16 0.5869848480983499 A 0.5869848480983499 0.5869848480983499 0 0 1 -0.41506096654409885 0.4150609665440987 Z" fill="hsl(157.5, 62.5%, 62.5%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.41506096654409885 0.4150609665440987 A 0.5869848480983499 0.5869848480983499 0 0 1 -0.5869848480983499 1.4021191072296408e-15 Z" fill="hsl(270, 75%, 40%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.5869848480983499 1.4021191072296408e-15 A 0.5869848480983499 0.5869848480983499 0 0 1 -0.4150609665440987 -0.41506096654409885 Z" fill="hsl(135, 75%, 47.5%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.4150609665440987 -0.41506096654409885 A 0.5869848480983499 0.5869848480983499 0 0 1 -1.4380615629982227e-15 -0.5869848480983499 Z" fill="hsl(67.5, 62.5%, 40%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -8.697189655206095e-16 -0.355 A 0.355 0.355 0 0 1 0.25102290732122484 -0.25102290732122384 Z" fill="hsl(112.5, 75%, 62.5%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.25102290732122484 -0.25102290732122384 A 0.355 0.355 0 0 1 0.355 -2.608497682183862e-16 Z" fill="hsl(337.5, 87.5%, 40%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.355 -2.608497682183862e-16 A 0.355 0.355 0 0 1 0.25102290732122523 0.2510229073212235 Z" fill="hsl(202.5, 62.5%, 40%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L 0.25102290732122523 0.2510229073212235 A 0.355 0.355 0 0 1 -3.4801942908383715e-16 0.355 Z" fill="hsl(270, 62.5%, 62.5%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -3.4801942908383715e-16 0.355 A 0.355 0.355 0 0 1 -0.25102290732122395 0.2510229073212248 Z" fill="hsl(112.5, 75%, 40%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.25102290732122395 0.2510229073212248 A 0.355 0.355 0 0 1 -0.355 1.565538085562295e-15 Z" fill="hsl(202.5, 62.5%, 40%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.355 1.565538085562295e-15 A 0.355 0.355 0 0 1 -0.2510229073212244 -0.2510229073212244 Z" fill="hsl(315, 87.5%, 47.5%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path><path d="M 0 0 L -0.2510229073212244 -0.2510229073212244 A 0.355 0.355 0 0 1 -9.566688882600716e-16 -0.355 Z" fill="hsl(292.5, 50%, 62.5%)" stroke="white" stroke-width="0.02" stroke-linejoin="round"></path></g></svg><div role="alert" class="chakra-alert css-7l7mra"><p class="chakra-alert__desc css-12db8z9">The colour mapping function could use a high-contrast version that focuses on the Luminosity channel rather than the Hue.</p></div><h3 class="chakra-heading css-106yvz" id="order-chaos--soul">Order, Chaos &amp; Soul<a class="chakra-link css-jchjfc" aria-label="anchor" href="#order-chaos--soul">#</a></h3><p class="chakra-text css-8fkoyy">Our colour encoding suffers from a flaw: two hashes can look very similar, but
  109. have a few bits of difference here and there. They can go unnoticed especially
  110. if differences occur in the LSBs of hue/saturation/lightness components.</p><p class="chakra-text css-8fkoyy">Also, the sections look random in colour, and the whole avatar lacks coherence.</p><p class="chakra-text css-8fkoyy">It would be nice if there was some pattern to a hash that makes it
  111. random enough to be distinguished yet coherent enough within itself.
  112. A balance between order and chaos.</p><p class="chakra-text css-8fkoyy">In order to fix that, we compute the <strong class="chakra-text css-35ezg3">soul</strong> of the hash, using XOR operations.</p><ol role="list" class="css-h1hn4m"><li class="css-77vupy">We XOR all the bytes of the hash together to compute the <strong class="chakra-text css-35ezg3">hash soul</strong></li><li class="css-77vupy">For each ring, we XOR the bytes that form this ring's section to compute the <strong class="chakra-text css-35ezg3">ring's soul</strong>. <em><a class="chakra-link css-y3jojq" href="/horcrux">(horcruxes?)</a></em></li></ol><pre class="language-ts"><code class="language-ts">
  113. <span class="token keyword">function</span> <span class="token function">computeSouls</span><span class="token punctuation">(</span><span class="token parameter">bytes<span class="token punctuation">:</span> <span class="token builtin">string</span><span class="token punctuation">[</span><span class="token punctuation">]</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  114. <span class="token keyword">const</span> ringLength <span class="token operator">=</span> <span class="token known-class-name class-name">Math</span><span class="token punctuation">.</span><span class="token method function property-access">round</span><span class="token punctuation">(</span>bytes<span class="token punctuation">.</span><span class="token property-access">length</span> <span class="token operator">/</span> <span class="token number">4</span><span class="token punctuation">)</span>
  115. <span class="token keyword">const</span> rings <span class="token operator">=</span> <span class="token punctuation">[</span>
  116. bytes<span class="token punctuation">.</span><span class="token method function property-access">slice</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> ringLength<span class="token punctuation">)</span><span class="token punctuation">,</span>
  117. bytes<span class="token punctuation">.</span><span class="token method function property-access">slice</span><span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">*</span> ringLength<span class="token punctuation">,</span> <span class="token number">2</span> <span class="token operator">*</span> ringLength<span class="token punctuation">)</span><span class="token punctuation">,</span>
  118. bytes<span class="token punctuation">.</span><span class="token method function property-access">slice</span><span class="token punctuation">(</span><span class="token number">2</span> <span class="token operator">*</span> ringLength<span class="token punctuation">,</span> <span class="token number">3</span> <span class="token operator">*</span> ringLength<span class="token punctuation">)</span><span class="token punctuation">,</span>
  119. bytes<span class="token punctuation">.</span><span class="token method function property-access">slice</span><span class="token punctuation">(</span><span class="token number">3</span> <span class="token operator">*</span> ringLength<span class="token punctuation">,</span> <span class="token number">4</span> <span class="token operator">*</span> ringLength<span class="token punctuation">)</span>
  120. <span class="token punctuation">]</span>
  121. <span class="token keyword">const</span> <span class="token function-variable function">xorReducer</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">xor<span class="token punctuation">:</span> <span class="token builtin">number</span><span class="token punctuation">,</span> byte<span class="token punctuation">:</span> <span class="token builtin">string</span></span><span class="token punctuation">)</span> <span class="token arrow operator">=&gt;</span> xor <span class="token operator">^</span> <span class="token function">parseInt</span><span class="token punctuation">(</span>byte<span class="token punctuation">,</span> <span class="token number">16</span><span class="token punctuation">)</span>
  122. <span class="token keyword">return</span> <span class="token punctuation">{</span>
  123. hashSoul<span class="token punctuation">:</span> <span class="token punctuation">(</span>bytes<span class="token punctuation">.</span><span class="token method function property-access">reduce</span><span class="token punctuation">(</span>xorReducer<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">0xff</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">2</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">,</span>
  124. ringSouls<span class="token punctuation">:</span> rings<span class="token punctuation">.</span><span class="token method function property-access">map</span><span class="token punctuation">(</span><span class="token parameter">ring</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">(</span>ring<span class="token punctuation">.</span><span class="token method function property-access">reduce</span><span class="token punctuation">(</span>xorReducer<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">0xff</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">2</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span>
  125. <span class="token punctuation">}</span>
  126. <span class="token punctuation">}</span>
  127. </code></pre><p class="chakra-text css-8fkoyy">These values give us additional parameters to play with in the colour calculation.</p><p class="chakra-text css-8fkoyy">Notably, we can <em>"seed"</em> the Hue with the hash soul, and introduce hue varitions
  128. per-ring with each ring soul, and with the value itself.</p><pre class="language-ts"><code class="language-ts{8,9,10}"><span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">mapValueToColor</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> value<span class="token punctuation">,</span> hashSoul<span class="token punctuation">,</span> ringSoul <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  129. <span class="token keyword">const</span> colorH <span class="token operator">=</span> value <span class="token operator">&gt;&gt;</span> <span class="token number">4</span>
  130. <span class="token keyword">const</span> colorS <span class="token operator">=</span> <span class="token punctuation">(</span>value <span class="token operator">&gt;&gt;</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token operator">&amp;</span> <span class="token number">0x03</span>
  131. <span class="token keyword">const</span> colorL <span class="token operator">=</span> value <span class="token operator">&amp;</span> <span class="token number">0x03</span>
  132. <span class="token keyword">const</span> normalizedH <span class="token operator">=</span> colorH <span class="token operator">/</span> <span class="token number">16</span>
  133. <span class="token keyword">const</span> normalizedS <span class="token operator">=</span> colorS <span class="token operator">/</span> <span class="token number">4</span>
  134. <span class="token keyword">const</span> normalizedL <span class="token operator">=</span> colorL <span class="token operator">/</span> <span class="token number">4</span>
  135. <p class="mdx-marker"> <span class="token keyword">const</span> h <span class="token operator">=</span> <span class="token number">360</span> <span class="token operator">*</span> hashSoul
  136. </p><p class="mdx-marker"> <span class="token operator">+</span> <span class="token number">120</span> <span class="token operator">*</span> ringSoul
  137. </p><p class="mdx-marker"> <span class="token operator">+</span> <span class="token number">30</span> <span class="token operator">*</span> normalizedH
  138. </p> <span class="token keyword">const</span> s <span class="token operator">=</span> <span class="token number">50</span> <span class="token operator">+</span> <span class="token number">50</span> <span class="token operator">*</span> normalizedS
  139. <span class="token keyword">const</span> l <span class="token operator">=</span> <span class="token number">40</span> <span class="token operator">+</span> <span class="token number">30</span> <span class="token operator">*</span> normalizedL
  140. <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">hsl(</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>h<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">, </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>s<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">%, </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>l<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">%)</span><span class="token template-punctuation string">`</span></span>
  141. <span class="token punctuation">}</span>
  142. </code></pre><p class="chakra-text css-8fkoyy">We can also introduce structural variations by changing each ring's starting
  143. angle based on the ring soul, to create a staggering effect:</p><div class="css-8fkoyy"><div class="css-1u4m77"><p class="chakra-text css-1fz97de">Without souls</p><p class="chakra-text css-1fz97de">With souls</p><p class="chakra-text css-1fz97de">With souls &amp; staggering</p></div></div><p class="chakra-text css-8fkoyy">Not only does this help give a bit more uniqueness to the avatar, it also helps
  144. with accessibility for colour-blind people</p><h2 class="chakra-heading css-1rjvsw4" id="a-bit-of-fun">A Bit Of Fun<a class="chakra-link css-jchjfc" aria-label="anchor" href="#a-bit-of-fun">#</a></h2><p class="chakra-text css-8fkoyy">If we change the radius and flags for the arc part of the section paths and
  145. play with each ring's starting angle, we can obtain interesting variations:</p><h2 class="chakra-heading css-1rjvsw4" id="going-further">Going Further<a class="chakra-link css-jchjfc" aria-label="anchor" href="#going-further">#</a></h2><p class="chakra-text css-8fkoyy">With a bit of tweaking in the colour mapping value, we can easily extend this
  146. technique to arbitrary hash lengths (as long as said length is divisible by 32).</p><p class="chakra-text css-8fkoyy">It so happens that when I started this project, Centralized Coin was using SHA-256,
  147. but later on switched to SHA-384, which gives 12 bits per section.</p><h2 class="chakra-heading css-1rjvsw4" id="conclusion">Conclusion<a class="chakra-link css-jchjfc" aria-label="anchor" href="#conclusion">#</a></h2><p class="chakra-text css-8fkoyy">You can see the hashvatars <em>(thanks to <a target="_blank" rel="noopener noreferrer" class="chakra-link css-y3jojq" href="https://twitter.com/wzulfikar">@wzulfikar</a> for the name)</em>
  148. in action in the
  149. <a target="_blank" rel="noopener noreferrer" class="chakra-link css-y3jojq" href="https://centralized-coin-explorer.vercel.app">Centralized Coin Explorer</a>,
  150. or play with the variants yourself <a class="chakra-link css-y3jojq" href="/hashvatar">on the playground</a>.</p><p class="chakra-text css-8fkoyy">I will publish the code as an NPM package later, in the mean time the source
  151. <a target="_blank" rel="noopener noreferrer" class="chakra-link css-y3jojq" href="https://github.com/franky47/francoisbest.com/blob/next/src/pages/posts/2021/hashvatars.mdx">code for this article</a>
  152. is on GitHub, as well as the
  153. <a target="_blank" rel="noopener noreferrer" class="chakra-link css-y3jojq" href="https://github.com/franky47/francoisbest.com/blob/next/src/components/SHA256Avatar.tsx">component itself</a>.</p><p class="chakra-text css-8fkoyy"><a target="_blank" rel="noopener noreferrer" class="chakra-link css-y3jojq" href="https://twitter.com/fortysevenfx">Follow me on Twitter</a> for updates and more weekend projects.</p>