<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://blog.goo-grotto.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://blog.goo-grotto.com/" rel="alternate" type="text/html" /><updated>2026-06-20T03:18:10+00:00</updated><id>https://blog.goo-grotto.com/feed.xml</id><title type="html">Goo Grotto Dev Log</title><subtitle>notes and news from planet goopiter</subtitle><author><name>gen</name></author><entry><title type="html">colour space</title><link href="https://blog.goo-grotto.com/2026/06/18/one-major-aspect-of/" rel="alternate" type="text/html" title="colour space" /><published>2026-06-18T16:00:00+00:00</published><updated>2026-06-18T16:00:00+00:00</updated><id>https://blog.goo-grotto.com/2026/06/18/one-major-aspect-of</id><content type="html" xml:base="https://blog.goo-grotto.com/2026/06/18/one-major-aspect-of/"><![CDATA[<p>One major aspect of slime squishing I want to make sure to get right is COLOUR.</p>

<p>Colour is probably the first thing a person will notice about a slime. And not only that, but it will eventually serve a mechanical purpose on the site, much like it does here on planet Goopiter. More on that will come in a future post, but for now I just want to talk about pure appearance.</p>

<p>I had a loose idea of how I wanted to approach it when I started, but I went through a lot of iterations and learned a lot about how we quantify colour along the way. I want to walk through my process, discuss the problems I encountered, and go through the solutions I experimented with until I finally landed on something that felt right.</p>

<h1 id="goals-for-slimes">goals for slimes</h1>

<p>First let’s go over my goals for slime colour:</p>

<p>1) They mix! When slimes squish together, the resulting offspring often looks pretty directly like a mix between the colours of its progenitors. I wanted to capture the feeling of blending and mixing things to produce something new in a way that felt logical and natural on the site, and ensure that slimes followed the same colour rules that we’ve been taught since kindergarten.</p>

<p>2) There should be room for chance, variance, and surprises! Sure, people should be able to target-squish their slimes to get their favourite colours… but I also didn’t want the output to be ENTIRELY predictable.</p>

<p>3) Slimes should have a good variety! If I just naively combined colours I know that without specific targeting many people would end up with greyish, average, or desaturated slimes. Slimes are mostly colourful and bright and their variety is an important part of what makes them fun and charming!</p>

<p>I needed a system and an approach that would cover all these bases. How should I represent colour? How should I reason about it? What can I build?</p>

<h1 id="rgb-not-for-me">rgb? not for me</h1>

<p>One potential representation of colour is RGB hex codes. I think most people have seen hex codes that represent colours before, but in case you haven’t, it’s a six-digit code that defines colour by how much red, green, and blue it has.</p>

<p>By increasing or decreasing the amount of RGB, the resulting colour changes. The code <span class="colour-swatch" style="background:#000000"></span><code class="language-plaintext highlighter-rouge">#000000</code> represents black (no colour at all), <span class="colour-swatch" style="background:#990000"></span><code class="language-plaintext highlighter-rouge">#990000</code> is a dark red, and <span class="colour-swatch" style="background:#FF0000"></span><code class="language-plaintext highlighter-rouge">#FF0000</code> is a bright red because we have piled more red into it. Add blue to the red and you get <span class="colour-swatch" style="background:#FF00FF"></span><code class="language-plaintext highlighter-rouge">#FF00FF</code>, magenta, which still tracks. Now add green to red instead and you get <span class="colour-swatch" style="background:#FFFF00"></span><code class="language-plaintext highlighter-rouge">#FFFF00</code>… bright yellow. Hmm…</p>

<p>Well, that’s kind of a complete nonstarter for me. RGB hex codes are made for screens, which mix colour using light. This is called additive colour mixing. But when slimes mix colour, they don’t mix like light: they mix like paint, and mix subtractively. Truthfully, I knew this from the start and working with direct RGB values was never under consideration, but I figured I’d include a mention of it for completeness.</p>

<h1 id="save-me-hsl">save me, hsl!</h1>

<p>So with that out of the way, the first system I reached for when I started to think about colour mixing was HSL, or Hue Saturation Lightness. This system was invented to solve the problems of RGB and provide that more intuitive feel I was going for, so it felt like a good fit! Instead of the 3 aspects of a colour being how bright we should make the red/green/blue lights, in HSL a colour is defined by:</p>

<ul>
  <li>
    <p>Hue. The actual colour. A hue is a value from 0 to 360 (well, really, 359 since 360 is the same as 0).</p>
  </li>
  <li>
    <p>Saturation. How intense is the colour? Saturation can range from 100% (most intense possible) to 0% (no colour at all).</p>
  </li>
  <li>
    <p>Lightness. How bright or dark is the colour? This is also a percentage value. As you go towards the extremes of this value, you end up making the colour closer to black (0%) or pure white (100%), with the in-betweens being dark or light versions of your hue.</p>
  </li>
</ul>

<p>You can actually think of HSL as a cylinder that runs the gamut of colours, and think of a colour as a point within that cylinder. Your hue is your angle from the center, your saturation is your distance from the center, and your lightness is your vertical offset within the cylinder. Here’s a picture to help.</p>

<figure>
  <img src="/assets/images/HSL_color_solid_cylinder_saturation_gray.png" alt="A 3D cylinder diagram of the HSL colour space, showing hue as the angle, saturation as the radius, and lightness as the vertical axis" style="width: 50%" />
  <figcaption>The HSL cylinder. Image by <a href="https://commons.wikimedia.org/wiki/User:SharkD">SharkD</a>, <a href="https://creativecommons.org/licenses/by-sa/3.0">CC BY-SA 3.0</a>.</figcaption>
</figure>

<p>(By the way, RGB is a cube. I don’t know what to do with this information.)</p>

<p>I thought I had it all figured out. Now that I have nice, intuitive ways to represent colours with numbers, I can think about how to add them together. The naive approach would be to average the numbers of Colour A and Colour B, but that runs into problem 3 pretty quickly: just combining colours in this way would, over time, cause most slimes to drift towards the middle-of-the-road saturation and lightness values.</p>

<h1 id="saturation-and-value-fix">saturation and value fix</h1>

<p>So my next thought was, well, why not separate those values and treat them differently? After all, hue is a circle and needs different treatment anyway, so I can split it off into its own category and zero in on Saturation and Lightness. I ended up locking Saturation and Lightness at particular levels determined by the slime’s genome, treating them as discrete values instead of continuous ones - a slime could be any combination of [dull, medium, bright] and [dark, medium, light] (with some special variants thrown in). That solved the problem pretty handily in a way I am still happy with, and all I was left with was hue.</p>

<h1 id="elegant-hue-mathematics">elegant hue mathematics</h1>

<p>My first approach gave each slime two hues in their genetics and blended them for display. Blending was simple enough, all I had to do was find the shortest arc between two points on the hue wheel and pick the midpoint. There was one edge case though: what if the two colours were exactly antipodal, 180° apart? My solution was to sidestep the problem entirely and limit the palette to a fixed set of tuned anchor values, and just never let complementary pairs exist.</p>

<p>I laid out nine anchor spokes evenly spaced around the colour wheel at 40° intervals. That 40° divided so nicely into 360°, and because there were an odd number of spokes, no two blends could ever be directly across from each other. Slimes could come in 18 possible hues, 9 derived from the anchor points themselves plus 9 blended midpoints. It felt manageable and moreover it felt kind of clever and elegant. I built a little tool so I could see all my palette at once so that I could adjust the values and really ensure everything worked nicely together, and I was very pleased with myself until I actually loaded up the page.</p>

<h1 id="green-hell">green hell</h1>

<p>IT WAS SO GREEN! Not that green is a bad colour, but take a look at just how dang green it is, and how the greens all kind of tend to look samey.</p>

<figure>
  <img src="/assets/images/colour-list-hsl.png" alt="A grid of slime colour swatches generated from the HSL anchor-spoke system, showing an overwhelming number of near-identical greens" style="width: 33%" />
  <figcaption>behold: an embarrassment of greens.</figcaption>
</figure>

<p>Of all these colours I got one yellow, I got a limp orange, but what felt like oceans of near-identical greens that my stupid human eyes struggled with distinguishing from each other. My solution was nice in terms of geometry but when faced with the reality of human vision, the evenness of my anchor colour split didn’t translate to what FELT like an even palette.</p>

<h1 id="round-peg-square-hole">round peg, square hole</h1>

<p>My first instinct was to try to fix this by moving the spokes around. Compress the green zone! Push some anchors toward yellow, sacrifice blue, redistribute the space more fairly. It helped a little. Unfortunately, it also immediately introduced new problems. Some of the blends between rearranged spokes landed in weird places, and I had to adjust again, and then again. I made a custom blend table for cross-squishing slimes. Every change I made to the layout had ripple effects.</p>

<p>No matter how I rearranged my nine points, how many spokes I added or took away, the underlying problem was the same: HSL just doesn’t carve up human vision evenly. No amount of manual topology adjustment could change that. I was alphabetizing the FTL ship’s manifest while it drifted towards a black hole (which, coincidentally, is how I ended up here to begin with).</p>

<p>I realised at some point I was fighting against the beautiful system I had built, forcing it into a shape it wasn’t intended to have. With some regret, I went in search of alternative solutions. Sometimes you have to kill your darlings.</p>

<h1 id="oklch-is-pretty-ok-lch">oklch is pretty ok (lch)</h1>

<p>I realised that if I didn’t want to spend a million years manually eyedropping a colour wheel that what I actually needed was a colour space that did the perceptual work for me. Lucky me, it turns out this exists! I wasn’t the first person to encounter this green problem, and some other folks had already balanced a new kind of colour notation system: OKLCH.</p>

<p>OKLCH is a colour space designed around how humans actually see colour. Its three axes are Lightness (L), Chroma (C - sort of like saturation), and Hue (H). Lightness and Chroma work similarly enough to Lightness and Saturation from HSL that I don’t think it’s worth going over them again, and Hue is still modelled as a 360° circle.</p>

<p>The big change is that OKLCH’s hue wheel is designed specifically to be perceptually uniform: equal angular steps correspond to equal perceived difference in colour. Every 40° of arc looks like roughly the same amount of subjective colour change.</p>

<p>You can really see the difference when they’re side-by-side like this:</p>

<figure>
  <img src="/assets/images/Colour_gradient_comparison_of_HSV_and_okLCH.png" alt="Two colour wheels side by side — HSV on the left with green dominating a large arc, okLCH on the right with colours spread much more evenly around the wheel" />
  <figcaption>HSV on the left, OKLCH on the right. Image by <a href="https://commons.wikimedia.org/wiki/User:Intervex">Intervex</a>, <a href="http://creativecommons.org/publicdomain/zero/1.0/deed.en">CC0</a>.</figcaption>
</figure>

<p>It helped that OKLCH is natively supported in modern CSS (as of 2020) and that OKLCH can be modelled as a cylinder just like HSL can. My math would all still work! Hooray!</p>

<h1 id="solved-and-improved">solved, and improved!</h1>

<p>Finding the right system to work with immediately fixed my main problem of perceptual evenness. With this fixed, I also decided to roll back my anchor hues solution to really open up the colour blending since I was confident I wouldn’t end up with mostly green slimes. Each slime now logically blends with any colour or picks a parent colour to clone, with the chance of cloning increasing depending on how far away the two parent colours are.</p>

<p>Put together, I think this covers all three of my original goals pretty nicely. Slimes mix in a way that makes intuitive sense, there’s room for variance and the occasional surprise result, and the perceptual evenness of OKLCH means the resulting colour space is varied and colourful and will hopefully remain so over the generations. And, as a bonus, it’s a system I can reason about clearly, which sets me up nicely for the mechanical layer I want to build on top of it later.</p>

<h1 id="morals">morals</h1>
<ul>
  <li>sometimes if your system is fighting you, what you need is a new system.</li>
  <li>often, you aren’t the first person to have a problem with something! don’t reinvent the colour wheel!</li>
  <li>just because something is clever doesn’t mean it’s going to be fun or good.</li>
  <li>watch out for the black hole in sector 13 of gamma chiron, it’s a doozy.</li>
</ul>]]></content><author><name>gen</name></author><summary type="html"><![CDATA[One major aspect of slime squishing I want to make sure to get right is COLOUR.]]></summary></entry><entry><title type="html">starting the goo grotto dev log</title><link href="https://blog.goo-grotto.com/2026/06/15/starting-the-dev-log/" rel="alternate" type="text/html" title="starting the goo grotto dev log" /><published>2026-06-15T16:00:00+00:00</published><updated>2026-06-15T16:00:00+00:00</updated><id>https://blog.goo-grotto.com/2026/06/15/starting-the-dev-log</id><content type="html" xml:base="https://blog.goo-grotto.com/2026/06/15/starting-the-dev-log/"><![CDATA[<p>Hi! This is the first entry in the Goo Grotto dev log, a place where I plan to document the choices I make when building the site, share news, and relay the will of the great Amalgam.</p>

<p>What’s Goo Grotto? It’s is a cozy little site on the planet Goopiter that is home to unique creatures called slimes. Slimes have flexible genetics and can combine with each other in a mysterious process known as “squishing” to create a variety of distinct offspring, passing along traits like their shape, colour, and fitness. They are independent and friendly, but they’re also kind of simple. And they are NOT edible, stop asking!</p>

<p>Goo Grotto is also a cozy little site on planet Internet being worked on solely by me, Gen, from the outer reaches of space. You can find me <a href="https://bsky.app/profile/eclectech.bsky.social">here on BlueSky</a>, <a href="https://www.tumblr.com/goo-grotto">here on Tumblr</a>, and I’ll edit this post to add other communication channels as I set them up!</p>

<p>On this blog I will share news, development updates, and write about the things I discover along the way, so check back regularly if you’re interested in following the process.  Thanks for your attention so far, and there will be more to come as everything takes shape!</p>]]></content><author><name>gen</name></author><summary type="html"><![CDATA[Hi! This is the first entry in the Goo Grotto dev log, a place where I plan to document the choices I make when building the site, share news, and relay the will of the great Amalgam.]]></summary></entry></feed>