Introducing RandoRacer.com
I've built a fun little web app so thought I'd share how I came up with it and how it's written.
Origin story
The idea came from our team's morning stand-up calls. Our scrum master at the time encouraged us to take turns in running the meeting, walking through our board, checking how everybody was getting on, the usual stuff. To pick who would run the next morning's meeting we started off with nominating but then later moved to using a random picker. We started with wheelofnames.com but then people found other random pickers online. They were mostly quite bad. I felt I could do better. This was early 2024.
Rather than just pick a name at random, which is very easy to program, I wanted it to be entertaining. So, I came up with the idea of a race. There would be a start and a finish and racers would move a random amount of distance forwards each turn. The concept is much like a board game with players taking turns and moving according to the roll of a die.
First version
The first version was just like this. I set each racer's score to 0 and the aim was to reach 100. Each turn their score would increase by a random amount, 1-6. The first to 100 would be the winner.
I used a :bike: emoji for the racer and on each turn set its right
property to the score + '%', so it moved from right to left. The racer CSS included a transition on the right
property so it moved smoothly.
Finally, I added a basic form so that the user could add their own list of names that got attributed to the racers. I added the racers' names just above the emoji. And that was it. All quite simple.
Taking it forward
Over time I added some enhancements. I stored the names in localStorage so that you would automatically get the last list you used on that device. I tweaked the scoring from 1-6 to a kind of Fibonacci sequence but weighted more towards 1, `[1, 1, 1, 2, 3, 5]. This made the sudden boost more impactful. I added some keyframes animation, making each bike appear to shake slightly throughout. I added a confetti effect when there was a winner, using the JSConfetti library via a CDN.
The final part of this phase was to add commentary. I realised that I wanted to make the whole thing somewhat accessible, so there would need to be some kind of text description of what was happening. I felt that the easiest way to achieve this would be to update something in the DOM and use aria-live so that a screen reader user would receive updates. The frequency of updates has always been an issue but using "polite" they get updated as often as possible without any one update being critical. As I was adding this I thought I'd also share it on screen to add another dimension.
I had lots of other ideas for it but it was now quite limited by the way I'd written it.
Second version
In early 2025 I decided to do a complete rewrite from the ground up, with the aim of making it more flexible and configurable.
Functions
The biggest change was to throw out the idea of moving X percent each turn and instead make it all function based. There would be a library of functions that would apply an effect to the racer. Some would be simple, like increase the score by 1%, others might be a big boost of 10%.
Probability
Rather than just apply a random function I also introduced the concept of probability against each so that more ordinary functions like increase the score by 1% could have a high chance of being applied whereas the more dramatic ones like the +10% would be improbable and rarely seen.
State
As well as changing the score I also brought in the concept of state. So, a racer's normal state would be "active" but they can also be other things, like "frozen". In this case, the function would apply a state of "frozen", which is also applied as the emoji's CSS class. The racer's appearance is changed to being completely white. Also, by wrapping the player's turn in an if (player.state === "active)
condition then they are unable to move or have any other effects applied until the state returns to "active". The function also includes a setTimeout()
which resets the state and CSS class after a delay.
Toast
The original commentary was a single div with its textContent being updated. I changed this in favour of a toast message system so that messages would appear and then fade after a delay. This means that with more happening users get longer to see each message.
The functions which control the players can also post messages and they can be styled, so we can have it show "Chris is frozen" with a pale blue background to stand out from the other plain white messages.
Your feedback
Give it a try and please let me know what you think. And feel free to suggest further twists and turns.