Hexclock and Hextime
Last updated: Jul 24, 2020
There’s a little executable in the quasi console driven “hacking” game Hacknet. If you run hexclock.exe in the game, a small widget appears and changes your HUD’s colour according to the in-game time.
So what did it take to make a web version of the hexclock? I quickly realized that most/all of the single-page “hexclock” apps that I found were variations of setting the colour value of the background using hexadecimal. I learned that there’s a difference between that and actual “hextime”, which is what I started out thinking all of this was. I made an implementation of both: a 24-hour colour-changing “hexclock” like this one, and a “hextime” colour-changing “hexclock”.
THE RESULT (Requires javascript)
In both implementations, the colour values are set the same way. Basically, I get the current time and set the colour accordingly. The first way uses the 24-hour clock: hours for red, minutes for green, and seconds for blue. For example: 12:37:21 would be #123721. This version of the clock only uses base 10 values.
//Get the time
let date = new Date();
//Get hours, minutes, and seconds individually and convert to a string
let h = date.getHours().toString();
let m = date.getMinutes().toString();
let s = date.getSeconds().toString();
//Make sure that result is always 6 digits long
if(h.length < 2)
h = '0' + h;
if(m.length < 2)
m = '0' + m;
if(s.length < 2)
s = '0' + s;
//Set background color using time
background.style.backgroundColor = "#" + h + m + s;
By far the harder part of this was figuring out how to convert to hextime. As far as I know Javascript doesn’t have a feature for fetching hextime the way that the Date() object fetches standard time. My naive solution was to just use the num.toString() method on the current time, and pass it 16 in order to convert the value to hexadecimal. But obviously this just displays the current base ten 24 hour time in hex. I needed a way to actually convert the current time of day from standard time to hex time, then set the colour value.
Another naive solution was to convert each hour/minute/second using the conversion information on this site. However, this again does not account for the structural differences in how each time frame measures a day. According to intuitor.com, hextime evaluates a day as a hexadecimal fraction. For instance, midnight is expressed as .000000, 11:59PM would be expressed as .FFFFFF, and noon would be .800000.
The application needed to mark a point along the axis of the entirety of a day. Both hextime and standard time loop at the start of a new day, so I started there and worked backwards. There are 86400 seconds in a day. Using this range information, I fetch the number of seconds since midnight, and then normalize the value using the seconds range and the hexadecimal range. The hexadecimal range can be any number of values, since a day is always measured in multiples of 16, and just depends on desired resolution (ie. .FFFF, .FFFFF, .FFFFFF). For simplicity’s sake, I take the decimal value of the top end of the hexadecimal range and convert it into hex after the calculations:
.FFFF: 65535
.FFFFF: 1048575
.FFFFFF: 16777215
The normalization equation I use is:
result = (b - a) * (x - min(x) / max(x) - min(x)) + a
where
x:
seconds since midnight
[a,b]:
range of (hexadecimal) time in a day
[min(x), max(x)]:
range of (standard) seconds in day
Put all together:
function hexClock(){
//set background color using result
background.style.backgroundColor = "#" + convert();
}
function convert(){
let normalized = normalize(
secsSinceMidnight(),
decSecondsRange,
hexSecondsRange);
//convert into hex once we have hex time value
let backColour = normalized.toString(16);
return backColour;
}
function secsSinceMidnight(){
let now = new Date();
let then = new Date(now.getFullYear(),
now.getMonth(),
now.getDate(),
0, 0, 0);
let diff = now.getTime() - then.getTime();
//trim off milliseconds
return diff / 1000;
}
function normalize(x, inRange, outRange){
//normalization equation
let normalized = (outRange.max - outRange.min) *
((x - inRange.min) / (inRange.max - inRange.min)) +
outRange.min;
//return rounded value normalized to 1 day hex time axis
return Math.round(normalized);
}
All said, I will say that hextime does not produce the most digestable colour palette.