I've been working on three small browser-based projects: a collection of human benchmark tests, a set of random tools, and a few variations of the classic 2048 puzzle.
They aren't particularly complicated products. There are no large teams behind them, no elaborate infrastructure, and no revolutionary ideas.
Most of the functionality is built with vanilla JavaScript.
But working on these projects has gradually changed how I think about building things for the web.
I used to focus much more on whether a feature worked. Now I find myself paying attention to questions that are harder to answer with code alone.
Is the interaction obvious? Does the feedback make sense? Is this feature actually useful? And perhaps most importantly, why would someone choose to use something I've built when similar tools already exist?
I wanted to write down a few things I've been thinking about.
Three projects, three different kinds of simplicity
The first project is PickTests, a collection of browser-based tests for reaction time, memory, attention, and spatial thinking.
It started with a simple reaction time test.
The idea was straightforward: wait for the screen to change color, click as quickly as possible, and see the result in milliseconds.
Later, I added other challenges, including number memory, sequence memory, aim training, multiple object tracking, and Schulte tables. There are now ten tests.
The second project is WheelPage.
It began as a random spinning wheel. You enter a few options, spin, and let the wheel choose one.
Over time, I added coin flipping, dice rolling, rock paper scissors, a random number generator, and an online counter.
The third project is 2048 Cupcakes.
This one is about a familiar puzzle rather than a new idea. Matching cupcake tiles merge into new designs, following the classic 2048 rules.
The collection also includes Classic 2048, Doge 2048, Princess 2048, and Flappy 2048.
Looking at them together, there's a common theme.
All three projects are built around things people can understand almost immediately.
You see a green screen and click. You spin a wheel and get a result. You move two matching tiles together and they merge.
There's very little to explain.
And yet, making these interactions feel right takes more thought than the simple rules might suggest.
Getting something to work is only the beginning
Consider a reaction time test.
From a programming perspective, the basic logic isn't difficult. You wait for a random interval, change the screen color, record a timestamp, and calculate the difference when the user responds.
But a usable test needs to consider more than that.
What happens if someone clicks before the screen turns green? What if they click twice? What should happen after a completed round? How should the result be explained?
And there's another important detail: the time recorded by JavaScript isn't necessarily the exact time the new color becomes visible on the physical screen.
Browser rendering, display refresh rates, and input devices can all affect the measurement.
So even something as simple as showing "245 ms" carries a responsibility to explain what that number represents.
I've found similar questions in the other projects.
A random wheel needs to make the selection process understandable. A counter needs an easy way to correct a mistaken click. A 2048 game needs predictable movement and merging behavior.
One especially important rule in 2048 is that a newly merged tile should not merge again during the same move.
That's a small detail in the implementation, but getting it wrong changes the game.
These things aren't particularly exciting to talk about. They're also not the kind of features that look impressive in a product announcement.
But they're exactly the details that make a tool feel dependable.
A working interface isn't always a comfortable interface
Another lesson has been that desktop and mobile experiences need more than different layouts.
It's easy to make a page responsive using CSS.
Making the interaction comfortable is a different problem.
In an aim trainer, for example, mouse input and touchscreen input don't feel the same. A target that's easy to click with a mouse may be awkward to tap with a finger.
In a Schulte table, a 4×4 grid can be comfortable on a phone, while a 10×10 grid creates a much more difficult layout problem.
Shrinking everything until it fits the screen doesn't necessarily make it usable.
The same applies to games.
In 2048, keyboard controls should feel predictable, but touchscreen gestures also need to work naturally. Players shouldn't have to think about the input mechanism every time they move a tile.
I've become more interested in the small questions surrounding an interaction.
Does the user understand what happened after clicking?
Can they recover from a mistake?
Does the result appear at the right moment?
Is something moving because the animation helps communicate an action, or simply because animation was easy to add?
I don't think every interface needs to be minimal.
Sometimes an animation adds character. Sometimes a playful visual design makes an ordinary activity more enjoyable.
But I increasingly feel that every additional element should have a reason to exist.
More features don't automatically make a better product
This has probably been one of the harder things for me to balance.
When you're building something yourself, especially with AI-assisted coding tools available, adding another feature can feel relatively easy.
A new mode. Another setting. More statistics. Another game variation.
There's always something else you could build.
But every new feature also introduces more decisions.
Where should the control go? Does it need an explanation? How does it behave on mobile? What happens to existing saved data? Does it make the original experience harder to understand?
For PickTests, I don't want to add new tests just to make the number larger.
I'd rather improve the clarity of existing results, the touch interactions, and the small details people encounter during a test.
For WheelPage, a tool should remain useful for its original purpose. If someone only wants to flip a coin, they shouldn't have to navigate through several options first.
For 2048 Cupcakes, I think there's value in preserving the familiar mechanics rather than adding features simply to make the game appear more original.
This doesn't mean I'm against new ideas.
It means I'm trying to become more selective about which ideas deserve to become features.
A product can become more complicated without becoming more useful.
That's easy to understand in theory. It's harder to remember when you're excited about building something new.
Why I still like vanilla JavaScript
All three projects rely heavily on HTML, CSS, and vanilla JavaScript.
I'm not opposed to frameworks. They solve real problems, especially when applications become larger and more complex.
But for these particular projects, I haven't found a strong reason to introduce one just for the sake of using a modern stack.
A reaction test doesn't need a complicated architecture to change the screen and record a result.
A random number generator doesn't need a frontend framework to accept a range and display numbers.
A 2048 board can be managed with a relatively small amount of JavaScript.
Keeping the implementation simple also makes it easier to understand what's happening.
When an interaction behaves unexpectedly, I can follow the relevant event handlers and state changes without working through layers of abstractions.
That doesn't mean vanilla JavaScript automatically produces better code.
As features grow, state management and organization still matter. A collection of small scripts can become difficult to maintain if their responsibilities aren't clear.
For me, the useful principle isn't "avoid frameworks."
It's choose the amount of complexity the project actually needs.
The part of building that code doesn't solve
There's another side to these projects that I've been thinking about more recently.
Getting a website online doesn't mean people will discover it.
And building a feature doesn't give anyone a reason to return.
There are already plenty of random wheel tools, reaction time tests, and 2048 games on the internet.
Some are more established. Some have more features. Some have been around much longer.
So I keep coming back to a question:
If someone can already do this elsewhere, why should they use my version?
I don't think the answer needs to be an entirely original idea.
It might be a clearer interface, more comfortable mobile controls, better feedback, or fewer unnecessary steps.
But those differences have to matter to the person using the product.
I've also been spending more time thinking about how to introduce these projects to other people.
Writing descriptions, sharing development experiences, and finding communities where the projects might be relevant are all part of that work.
It's very different from writing code.
I can usually tell whether a button works. It's much harder to know whether a description makes someone interested enough to try a product.
And I don't want every article I write to become another product announcement.
I'd rather share something useful about the process, even if the reader never visits any of my sites.
That feels like a more sustainable way to talk about the things I'm building.
I'm still learning when to stop polishing
One thing I continue to struggle with is knowing when something is good enough.
There is almost always a detail that could be improved.
A spacing adjustment. A slightly different animation. A clearer sentence. A better mobile layout.
Sometimes those changes genuinely improve the experience.
Other times, I may simply be spending too much time trying to make something feel perfect.
I don't think there's a universal rule for when to stop.
But working on three projects has made me more aware that polishing and progressing are not always the same thing.
There are times when fixing a small interaction is the right decision.
There are also times when it's better to release a reasonable version, observe how it behaves, and move on to the next important problem.
I'm still figuring out that balance.
And I suspect it's something many solo developers deal with.
What these three projects have changed for me
I started with relatively small ideas.
A test that measures a reaction.
A wheel that makes a random choice.
A puzzle where matching tiles merge.
None of them required inventing an entirely new concept.
But they've given me many opportunities to think about the difference between implementing a feature and designing an experience.
I pay more attention to the words on a button, the feedback after a mistake, the way a result is presented, and whether someone can use a page without reading a long explanation.
I also think more carefully before adding something new.
These projects are still evolving, and there are plenty of things I want to improve.
I don't have a dramatic success story to share, or a formula for building the next popular website.
What I do have is a better understanding of the kind of products I want to make.
Small tools that are straightforward to use, pleasant to return to, and thoughtful about the details.
I'm curious how other developers approach this.
When you're working on a small side project, how do you decide whether to add another feature or spend more time improving what's already there?
Top comments (0)