Hand-coding and vibe-coding

September 9th, 2025, 10:19 PM

I've worked on two very different projects the past few months. One is a vanilla Javascript gaming engine. This project was started several years ago with the intention of making a JRPG from the ground up. The proof of concept is ready - there are win states, battle scenes, items, etc. The original code was a tightly coupled nightmare, but I wrangled it into a much more extensible state that makes it downright fun to add new features to. It is not quite ready to demo yet - the battle logic needs to be added, the UI is barebones, and the graphics have that Atari 2600 charm of being just a bunch of squares. At the same time, it's exciting to see this project move along. I have a strong feeling this could become really useful for making RPGs on the web quickly and easily!

The other is a sort of journal-timeline engine, allowing you to see a JSON of dated entries. I made it after coming across some old materials of mine and wondering what it would be like if I could see them in chronological order. It has been a big ordeal acquiring all the materials - many of these are handwritten journals I have to transcribe. Others are old forum posts. But it's all coming together, slowly.

Unlike my other projects, this one has been entirely made with AI so far. The reason for this is that all I am doing is fetching from a JSON and displaying it creatively - tedious work that I would not learn much from. I wanted to have something workable very quickly, and to see what the experience of using nothing but AI tooling would be like. The results are interesting - on the one hand, I can have a functioning prototype in a matter of seconds and iterate through new features at lightning speed. On the other hand, I find that "vibe coding" means you don't know what this is doing or why. If something is going wrong, I rely on the AI to fix it. This creates a weird sense of dependency.

Something noteworthy is that I need to be responsible for architecture decisions. You can keep asking for a change to be made over and over and it will dutifully do it for you. The result is that I currently have an intimidatingly large javascript file that technically works, and yet I get the feeling that perhaps all of this logic should not be in one big JS file. If I ask the AI for its 'opinion', it will affirm that I am beginning to reach the limits of one big JS file, especially for future features I may want to add. This is reassuring, but one must have the sense to ask "hmm, am I doing the right thing here?" It won't stop you otherwise. There are sanity checks you can have while 'vibe coding'. I find it helpful to open new chats frequently to clear the context window, and also to periodically ask, "how would you improve this?" For now one must do this manually, but perhaps in the future these suggestions will come up automatically.

An obvious downside is that I have learned absolutely nothing. On the one hand, that is why I chose this project - I did not want to go through the tedious work of getting this prototype going, I did not want to write the many scripts I would need to format a diverse set of data, and I wanted to focus on just looking and commenting on the entries as I wished. On the other hand, this concerns me about 'vibe coding' as the focus on speed means there is little focus on understanding what was generated. My experience with using AI for debugging tells me that it's fantastic until it isn't and then you're twenty levels deep in a 'fix' that seems to have done nothing but made the problem worse. In short, we are not yet freed of the burden of understanding what we made. I suppose we could use AI to explain it back to us quickly...

We thus end with two projects - one a hand-coded engine and one an entirely machine-generated timeline. The tradeoffs in terms of time are obvious. I found myself asking, at times, why not just skip all the hard stuff with the game engine and jump ahead using AI? And the answer is the same reason that I avoided using something like Phaser - because I wanted to learn, by messing around and failing myself, why things are the way they are. When AI-coding, I learned the tool, but not the system, and if I knew nothing at all about software, I would be entirely dependent on the AI to make changes and fix errors. At the same time, time is not infinite, and time spent fetching and displaying and filtering could possibly be better spent on something else. For example, when I had a strong headache that made me not want to open up the screen at all, I found the AI useful in making some progress on the timeline project. Overall, it was a matter of tradeoffs - how important was it to me to have control, to learn, versus to move quickly, to focus on the product design?

A skeptic may ask why bother hand-coding at all - is this not mere sentimentality to avoid the creeping sense of dread and obsolescence hanging over software engineers? And that is a fair retort; perhaps my attempt to understand the system is merely an attempt to cope with an unstable present. But I do continue to believe there is value in understanding the system itself, even if one incorporates AI tooling. Imagine a novice who would like to make my timeline project. That novice, using their knowledge of the world, has a certain possible set of prompts they may give the AI: "move this there, add this filter, make this feature work different." But the novice's knowledge limits them, and so long as it 'just works', there is no reason to improve it. The novice may not bother to ask "is this JS file too big? Should I split it into a smaller file, or use a framework, or some third option?" Learning about how the system works expands the possible prompts you can use, and improves your judgment about when to use which one.

Footnote: One may suggest one day in the future, the entire question of 'prompting' will be removed from people's hands, and you will only need to declaratively state the outcome, but I don't know when that day will come, and I must speak of the present day and near future.