Random Generator: Three Tabs, One Shared Core
Numbers, words, and coin-and-dice built on one tested random source instead of three separate implementations that could each drift wrong.
Three tabs — numbers, words, coin-and-dice — living in one tool rather than three separate pages, because they're all answers to the same underlying request: "I need something random and I don't have a coin, dice, or the patience to write a formula for it." Splitting them into separate tools would've meant three nearly-identical pages sharing almost no actual purpose distinction a visitor would care about.
A shared random core, three different presentations
Underneath all three tabs is the same random-number source doing the actual work — a number in a range, an index into a word list, a coin face, a die face are all fundamentally "pick a random value from a set of possibilities," just dressed up differently for each use case. Building one well-tested random core and layering three thin presentation modes over it was much less error-prone than writing three separate randomness implementations that could each develop their own subtle bias independently. If there's ever a bug in how randomness gets generated here, I only have one place to look for it, not three.
Deciding what happens on an invalid range
Someone will eventually type a min that's larger than the max, or leave one field empty, and deciding what happens then needed an actual answer rather than letting whatever the code happened to do stand as the behavior. Silently swapping the two values felt too clever — it fixes the immediate problem but does something the person didn't explicitly ask for, which can be more confusing than an honest error. I went with a clear inline message explaining the range is invalid and why, rather than either guessing at intent or letting a broken calculation through silently. A tool built around producing a single trustworthy number should never produce a wrong one quietly just to avoid showing an error message.
Range validation matters more than it seems
The number generator takes a min and max, and the boring-sounding part that actually needed care was making sure every integer in that inclusive range has genuinely equal probability of appearing, including at the exact boundaries. It's a classic, easy-to-get-wrong spot in random number generation — an off-by-one in how you scale a raw random value into a bounded range can quietly make the endpoints slightly less or more likely than everything in between, in a way that would never show up from casually clicking Generate a few times, only from a much larger sample somebody might never actually run.
Keeping a short roll history changed how the dice tab feels
The last five rolls for a given die type stay visible below the roll button, and adding that small piece of memory changed the tool from feeling like a single-use gadget into something that actually feels like rolling real dice repeatedly. Without any history, every roll exists in total isolation — you see a number, then it's gone the moment you roll again, with no way to spot a hot streak or confirm you didn't misread the last result. It's a small addition with an outsized effect on how much the tool feels like an ongoing session rather than a series of disconnected one-off actions.
Coin flips are simpler than dice and still worth doing carefully
A coin flip is the simplest possible random output — one bit, heads or tails — and even here there was a small decision worth making deliberately: the flip animation and result reveal are timed so the outcome feels like it's being determined in the moment rather than computed instantly and then artificially delayed for show. That distinction matters more than it sounds like it should for something this simple. A flip that resolves instantly with no animation reads as a lookup, not an event; one with a short flip animation before the result settles reads as something actually happening, even though the underlying random value was already generated the instant you clicked. It's a bit of theater in service of making a trivial random function feel like the physical action it's replacing.
Why the word generator needed its own honesty check
Generating random words for placeholder content or writing prompts seems like the simplest of the three tabs, and the one thing I had to actively watch for was word list bias — if the underlying list skews heavily toward common short words, "random" output stops feeling random and starts feeling repetitive after a handful of generations. I made sure the word pool is large and varied enough in length and obscurity that generating even a large batch doesn't quickly start repeating the same handful of words a disproportionate amount of the time, which is the kind of subtle quality issue that's invisible in a quick demo and obvious the moment someone actually uses the tool for real. It's the same lesson as the coin flip in a different form: the parts of a random tool that feel the most trivial to build are often the ones where a small oversight is the most likely to actually be noticed by someone paying attention.
None of these three tabs are individually impressive, and I don't think they need to be. This tool exists to answer a specific, small, recurring question — "I need something random, right now" — for three slightly different flavors of that question, and it answers all three quickly without asking anyone to think about which of the site's other tools might technically also do the job. Sometimes the right scope for a tool is exactly as wide as the actual recurring need, no wider. Three tabs, one shared source of randomness underneath, and nothing more than that was ever the actual goal here — small, correct, and genuinely finished, rather than sprawling across five tabs and only half-working on three of them, which is a trap I could very easily have talked myself into if I'd let the feature list keep growing past what the tool actually needed just because each individual addition seemed harmless on its own.