Over the past month, I’ve been configuring my NixOS system.1 In preparation for theming (and doing it well), I wanted to be able to specify colors in the HSB2 format and have them be converted to RGB hex codes. So, I present to you, after a day or two worth of work, said function, in the hopes that it may be useful to you in some way (also, it’s neat to share random things like this):
# Converts HSB to RGB in hexadecimal form
# Note that B and V (brightness and value respectively) are the same value
# We implement the following algorithm:
# https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB_alternative
# h - A value from 0 to 360
# s - A value from 0 to 1
# v - A value from 0 to 1
hsbToHex = h: s: b:
let
# Nix lacks a built-in modulo operator, so we introduce our own.
# We used trunctuated division, the variant used by JavaScript.
# See: https://en.wikipedia.org/wiki/Modulo#Variants_of_the_definition
mod = a: b: a - b * builtins.floor (a / b);
# Get the higher or lower of two values
max = x: y:
if x < y then y
else x;
min = x: y:
if x < y then x
else y;
# Round a number to the nearest integer
round = num:
let
floored = builtins.floor num;
in
# Round up for 0.5 and above
if (num - floored < 0.5)
then floored
else builtins.ceil num
;
f = n:
let
# Explicitly use floating points, otherwise things get rounded
k = mod (n + h / 60.0) 6.0;
in
format (
b - b*s*(max 0 (min k (min (4.0-k) 1)))
)
;
# Convert an integer from 0 to 255 to a two-digit hex value
format = i:
let
ten = round (i * 255);
hex = lib.trivial.toHexString ten;
in
if builtins.stringLength hex == 1
then "0" + hex
else hex;
in
"#" + builtins.concatStringsSep "" [(f 5) (f 3) (f 1)];
I’m not sure if it’s the best way to do this in the context of using Nix (in other words, whether the code structure would be considered a “best practice”), but it works for me.
The comments come off to me as a displaying a bit more confidence about certain subjects than the confidence I have in myself as to how much I actually know/understand said subjects. For example, floating point numbers. While I’m pretty sure what I wrote is correct, it’s not an issue I run into often (I primarily do stuff3 in TypeScript) and I had to debug for a little bit in order to figure out why my colors were off.
Another would be the “we implement the following algorithm” bit. I was originally on a StackOverflow page about implementing the above function in JavaScript, but went to the Wikipedia page and implemented it myself, partly out of a desire to prove that I could do this myself. This is the first time I’ve read it.
I’d like to make the Git repository holding my NixOS configuration public, but I’ve run into issues regarding macOS-specific firmware—currently included within the repository—that I don’t want to publish.
Oh yeah, one last thing, the comments you (hopefully) see at the bottem of this page are rendered via Sukopon, a small project I had abandoned several months ago due to packaging-related issues.
Footnotes
-
It’s been really intriguing and has somehow managed to keep me enthralled for weeks. I’d also like to give credit to a really long, insightful, and interesting blog post by Skip for finally pushing me to try NixOS, which I had occasionally heard of prior to that. His NixOS configuration has also been helpful for me as I craft my own setup. ↩
-
HSB and HSV are one and the same, as mentioned in one of the comments in the code. ↩
-
I was going to write “work with,” but that comes off as overly professional.45 ↩
-
Well, I do generally act more “professional.” ↩
-
Yep, footnotes in footnotes. Footnoteception!6 …I apologize for this, I can imagine it’s quite unreadable and hard to follow. It’s either this or nested parenthesis though, and this might be the lesser of the two “evils.”7 ↩
-
I’ve seen this practice of appending the suffix “ception” to words to indicate recursion or nesting several times before8, and I don’t know what it officially means.9 ↩
-
I remember seeing a post on fedi a while back where someone jokingly said that neurodivergent folks nest parenthesis to capture ideas properly. I don’t think it’s based in fact or anything, but I’ve thought about it every time I’ve done just that. Which is a non-trivial amount, given my way of thinking and journaling. ↩
-
https://everestapi.github.io/#olympus (yep, the first link in the footnotes) ↩
-
Just looked it up (I’m a bit surprised I didn’t do this earlier), but I found a Wiktionary page that explains it. ↩