How-to Blog

Origin Story

This app was made across about two months and had a handful of different epochs which had wildly different focuses, techniques, and approaches. It all started when I decided to revisit learning to code; something I’ve intermittently picked up for a few months at a time over the years. I’d typically make some progress, then get bored, then move on to a new hobby. It never quite stuck.

This time, I decided to approach it by watching a tutorial a few times, including watching it listening to it, copying it step-by-step as I watched. After the third or fourth go-around, it occurred to me that I could actually commission a bespoke tutorial by engineering a prompt for ChatGPT.

I told it something along the lines of:

ChatGPT Logo

“Hi ChatGPT, hope you’re doing very well this morning. I want to learn JavaScript, and I want you to teach me. I already have the environment set up with Virtual Studio Code. Please give me one step per response, and tell me what I should learn from that step. Only give me the next step when I respond. Go.”

…and it worked extremely well. I got few dozen steps in, to about step 50. At that point, its responses were so lengthy and intricate that it was typing out basically an entire app. Granted, it was quite clunky and unattractive, but separately from the tutorial it was pretty stunning how much functioning code it was putting together.

I decided to pivot from my tutorial altogether, and just see what this thing could do. I asked it, little by little, to create a game. Unfortunately, I didn’t document everything verbatim, but it was very incremental. First I asked for a basic HTML framework. Second I asked for a basic <canvas>, then a ‘rocket’ (which even to now is just a basic triangle). Then I incremented little by little. I went to a basic color palette generator (as a colorblind person, so maybe it’s not ideal). I slowly added behaviors, little by little.

Producing the game itself took approximately 250 prompts with AI; back and forth, iterating, refining, adding new features, etc. It’s really a remarkable technology and I can’t wait to see where it leads.

It also led me to a lower and lower level of dread over the AI hype and fear mongering. Yes a large company can replace a swathe of staff, but private individuals can too. Think; I was able to do the work of a much more qualified coder than I truly am. This can scale across a ton of areas of expertise. Certainly not to the extent of a medical doctor, but at least to the extent that little old me could get a game going in a relatively short span of time after beginning a mere tutorial.

I would advise anyone do a tutorial as I mentioned above, in any language you want to learn, just so you know the basics. There’ve been a few times where I prompted 10+ times to AI, made no progress, then decided to do something manually and resolved it in a very short time. So, it isn’t perfect, and knowing a thing or two is necessary, but it’s still pretty remarkable.


A Lot to Learn

For me, the most important thing to learn when prompting AI has been to focus on the prompt itself. I’ve made way more progress with thoughtful prompt engineering than I have with “Think longer” or any equivalent.

Because of how much of a genie in a bottle AI can be, what defines a truly good prompt really varies, and you’ll certainly learn as you go along.

What’s been most key for a good prompt is patience and a singular goal. Don’t prompt by asking, ‘give me a website with X functionality, Y functionality, Z functionality, where X interacts with Z in behaviors 1, 2, and 3 depending on user inputs [1-thru-100], or anything along those lines. What you’ll get (with current AI as of October 2025) is maybe the basic skeleton of what you asked for, but everything will be haphazardly linked and probably will outright not function in numerous different ways. These issues will then bog you down and you’ll spend the whole day unwinding the issue.

The best way to approach it is to just embrace that it’ll, depending on complexity, likely take hundreds or thousands of little tiny prompts to get where you’re going. These tiny steps are also why it’s good to know a little bit about coding; you need to know what languages are even capable of; what languages handle given responsibilities, why you might just need JavaScript for some things (like OrbitTimer’s game), or why you might need SQL, or various APIs.

This segues into one of the most important types of prompts, which is simply asking what the best way to do something will be. I’ve had a number of issues in the past where I thought I knew what the right approach would be, then got an hour (or more!) into trying to resolve an issue, all to later have AI tell me something along the lines of, ‘because you’re doing it this way and not [previously unstated other, much better and quicker way], it’s going to take much longer’.

So, knowing the capabilities, strength, and weaknesses of languages, apps, etc, is incredibly critical. I’d suggest spending a week or two doing AI prompt-driven tutorials as I noted in the article above, or at least listening to some 101’s on YouTube. That week or two will save you dozens of prompts later, dozens of dead-ends prevented, and generally improved decision-making. You don’t want to spend hours or days on an issue only to find later that there was a much quicker way of doing something.


Original Technique & Mistakes Made

When I first started OrbitTimer, my technique was just way off. I spent (to get to v1.0) probably 90-to-100 prompts getting the game to a publishable state. And, we’ll never know for sure, but likely 50 of those prompts were wasted by coming up with a prompt, entering it, then receiving incredibly buggy code. When this happens, you can easily get 5-10 prompts into the resolution phase before actually resolving it. On an unpublished app, the longest I’ve gone without resolving a bug was something like 120 prompts. It can feel like the slog-est of slogs that ever slogged. It can feel like the task is totally impossible.

So, what helps prevent getting to dozens of prompts over the same issue, is to (1) subdivide a problem as granularly as possible and (2) save each successful iteration as their own version. This is incredibly important. What can happen very easily if you don’t do that, is you can request the addition of Feature A. Then Feature A gets added. Then you request Feature B, and Feature B gets added. Then you request Feature C, and Feature C is super glitchy, then you spend some prompts untangling the glitch, but each time you prompt, you receive a resolution to the issue in Feature C, but the returned code includes the destruction of Feature A. Then, you have to chase the issue with Feature A, and maybe after some prompts Feature A is resolved, but then an issue with Feature B pops up.

The resolution to this is simple. Each time you add a feature, save that code as its own version in your development environment. For example, start with Code_v1.html, request Feature A. Feature A gets added, then save that code, copy-paste into Code_v2.html. Request Feature B, and when it’s added, iterate forward to Code_v3.html. For every published version online, I have anywhere from 5 to 30 offline versions. For example, OrbitTimer is on v1.6 publicly (as of writing), but privately and offline, I’m on v66.

Online, I have v1.0-to-1.6, and I’ve iterated in units of 0.1, which means each online version had around 10 offline versions.

In my experience, you should really only prompt multiple times per offline version if the exact request you made wasn’t met. If it starts creating other issues, you can always go back to the code in the latest un-glitchy version.

Last thing I’ll say here is that, amidst all the offline versions, you’ll likely have a large majority which aren’t necessarily publishable, likely due to simple incompleteness, but sometimes a glitch will be merely partially resolved, so sometimes they won’t be publishable due to outright dysfunction. To avoid getting lost in which offline versions are actually publishable, make sure to save publishable versions as such. If v1-to-17 aren’t publishable but v18 is, save v18 as, “Code_v18_P.html”, or “Code_v18_Publishable.html”.

That way, you can iterate sequentially, v1-to-[infinite]. Then, when you’re testing actual stages of completeness, you can see publishable (“_P”) iterations more easily, and you’ll save a lot of time sifting through what were actually complete at their given stage and what weren’t. You don’t want to be publishable at v43, then again at v57, then forget what your most recent publishable version was and have to play a guessing game of a bunch of different versions, especially if (1) the underlying issue takes multiple steps within the app to actually get to and/or (2) the app is a game and the glitch being resolved takes 15 minutes of play to actually get to and even be able to test.


Evolved Technique & Version Iteration

As stated above, you can easily get to a point in development where you’re seeing a glitch that is only accessible by getting to a stage in the app’s usage that takes 15 minutes to get to. Even if it’s only 3 minutes, if you’re prompting to resolve a glitch, you can easily stack the 2-3 minutes with 3 minutes of prompting, and get to over an hour of back-and-forth interaction. Thus, what you need to do is prompt to request a developer mode. The developer mode can function in a bunch of different ways. For OrbitTimer, there’s a store. The store has items which get quite expensive, and getting to those options via play can take 10+ minutes. If you’re trying to test the performance and functionality of the most expensive item in the store, you can easily spend inordinate development time just playing the game itself. Not that the game isn’t fun, it just is that constantly playing it for the sake of engineering certain circumstances is a giant time-sink.

For the store, I requested that currency logic was deactivated; that in the developer mode I could toggle each store item on/off by simply clicking it. It’s super simple stuff like this, where I reduced 10 minutes of play-for-testing, down to literally just 1 second, where you can turn an 8 hour day into a 45 minute day.

These techniques are invaluable and will save you tons of time. If I knew the version iterations method I outlined above, it wouldn’t have taken me 2 weeks to make the app. It likely could’ve been done in 5 days, max, and those days would’ve been infinitely less frustrating.


Online vs Offline Versions

When I was originally doing this, my first 100 prompts were almost nerve-wracking, because I knew I was always one imperfect prompt/error away from a huge setback. The reason why is simply because I didn’t have anything to fall back on, I wasn’t doing the iterate-and-save approach at all. So, I’d get dozens of prompts in, dozens of changes, features added, glitches resolved, and so forth. Because of that, I was extremely conservative.

My original posting of OrbitTimer, v1.0, was (in hindsight) probably more like a v0.1. There were issues I was afraid to address because each prompt has the chance of creating new issues, or reintroducing old ones. So, the game just was terrible. It didn’t have a store, pause/play, levels, or currency logic at all. The frame rate for side-to-side movement was bad. It had one goofy feature, which was that the fuel was contingent on a stopwatch widget (not necessary, just was an experiment), and fuel would iterate upwards for every second the stopwatch incremented, then the game would become playable. That was the only even remotely interesting aspect of it, and even then it wasn’t ‘fun’, it was just an unrelated experimental thing.

There were also a bunch of glitches; the restart button didn’t work, the game would end upon descent starting about 50% of the time, and altogether it was just a weak production.

I believe others have had similar issues, as seen in this similar article by someone named Mark Rodseth. It's a great article because it reveals that others have had similar problems, although I personally use a different approach leaning towards a high amount of prompts.

The reason I’m saying this is because locking down and iterating versions every time something you prompt for is returned allows you to be free from any threat of a bug or glitch. Each prompt doesn’t feel like a risk, or like it’ll undo previous hours of iterating. It allows you to take huge risks, and maybe even get slightly lazy. It goes from feeling like some kind of litigious nightmare to something that’s fun. It even feels productive, because you can look at your folder and see dozens of versions of something, and visualize your progress more easily.

Interestingly, the first 100 prompts had one single backend version, but the next 150 had 65. As an example, below is a screenshot of an epoch of saves:

Screenshot of RGI files as example






Troubleshooting & Console Logging

This is one of those things where actually knowing how to code will give you a huge advantage. For those who don’t know, each coding language has a way of logging targeted information in the console for the developer, in the dev environment, to be able to see what’s working and what isn’t. You also generally see console logging used in initial/101-style tutorials. The classic first-ever-code snippet, “Hello world” is generally done via the respective language’s console log syntax, but console logs have very critical real-world uses which can also save tons of prompts in AI environments.

For example, let’s say you have a glider game where you need to fly over some obstacle. You want the glider to stop/crash if it hits said obstacle. For some reason though, there’s a glitch where the glider stops midair within a second of flying through the obstacle successfully.

You should enter a prompt, requesting console log for the moment-by-moment sequence of flying near the obstacle, so you can tell where exactly the glitch is happening. You might say, “I have an issue with traversing through the obstacle. Give me a console log for speed, time, X/Y position, and any noteworthy data, for each second user approaches, goes through, and passes beyond the obstacle.” Another measure instead of time would be a range of pixels from before, during, and after the obstacle. In general, it’s critical to know the scale and terminology of what you’re using to ensure prompts are as specific as possible. If you’re altering something within a <canvas>, knowing the pixel dimensions of said canvas will be important for specifying where and when an issue occurs. Your requested logs should include that kind of data.

Then, assuming the prompt is successful, you’ll see in the console (can be found in Chrome Dev Tools [upper bar: View -> Developer -> Developer Tools -> ‘Console’ tab], the given data for each second.

Sometimes it isn’t granular enough. Sometimes you’ll see nothing in the logs, and often times asking for a finer interval, e.g; asking for a console log every 0.05 seconds, or something like that. Then, what I’ve done is literally just copy-paste all logs from Chrome Dev Tools’ UI within my prompt, and say something along the lines of:

“The glitch persists. I [can/can’t] find the issue, but here are the logs:”

Oftentimes that will expedite the resolution of the glitch(es). It’s easy to get lazy and think that each prompt needs to yield a surface-level behavior or functionality, but you’ll find that efficient prompting often includes backend, dev-only prompting. I’ve copy-pasted dozens of lines of logs and fixed persistent issues within <5 log-centric prompts.

Below is a screenshot of a hyper-basic 'app', just for example purposes. The app is simply a blank canvas wherein the user can move the blue square with the arrow keys. However, there's no logging of specific events other than the initial rendering of the page. In reality, this is straightforward, but sometimes app behaviors can be ambiguous and hard to pinpoint.

No distinct logs.

To make things easier to pinpoint, you should request logs for user inputs. The next screenshot is after a prompt requesting console logs for every arrow key input:
Basic logs.

If, in theory, there were a glitch which occurred after one kind of user input, being shown the exact input details can be helpful to pinpoint the exact moment when the glitch occurs, therefore giving key insight into what you should include in future prompts. If the right arrow key generates a glitch after 10 presses, you should cite that specifically. Instead of prompting "the glitch occurs after a handful of right arrow presses", you can say, "the glitch occurs after exactly 10 right arrow presses". This can also provide insight into where to look within your code in case you're doing changes manually.

You can even request more detailed logs, like specific events. Below's screenshot is from after requesting logs for the specific instance of 2 simultaneous button presses:
Expanded logs

Another issue in troubleshooting is the AI UI itself. In my experience, when crashing, ChatGPT doesn’t notify you. It doesn’t always readily disclose crashes. In that event, you might prompt and yield a return which is repetitive, doesn’t fix anything, and in general is just the definition of the phrase “AI slop”, or even some kind of AI hallucination. For Grok, which is what I personally use because it includes the coding environment within its UI, it discloses crashes. It’s an error message which reads something along the lines of, “Grok cannot reply right now”, so you can save time by pressing “Retry” if you want, but generally if you’re deep in a thread, it’s better to try simply reloading the page once and/or starting a new thread.

I haven’t used Gemini extensively, but you can tell it’s by a super-scale, very mature company that probably has seen its fair share of litigation. I’ve gotten very litigious responses, like when I used the phrase “bite the bullet”, it triggered a no-response sequence. Apparently it hadn’t heard that phrase (or more likely, that it was just programmed to decline all responses to doing anything with bullets), but other than that, it’s been so inconsistent that I just haven’t tried to code with it. If you don't want to troubleshoot manually or via prompts as I've noted, the good news is there are dedicated platforms for this, like Microsoft Copilot (not affiliated/sponsored!).


Embracing the Process

It’s easy to tell oneself to think granularly. It’s difficult to consistently think granularly enough that you’ll be prompting effectively.

You’ll vary in effectiveness over time, but a way to think of it is, ‘slow is fast’, or ‘granular is fast’, in the sense that asking for 0.2% of a project at a time is more likely to work sequentially than asking for 1% of a project, having it fail in a bunch of ways, then spending 15-20 prompts trying to resolve the various failures. It’s psychologically much easier too, to just constantly move forward as opposed to getting glitches to constantly untangle.

An example will be with OrbitTimer’s store. If I said, “Give me a store function with Items A/B/C/D/E at prices 1/2/3/4/5, with item A’s function being [this], Item B’s function being [that], etc…” …what would happen is that I’d get issues with the store’s UI, issues with some items, issues with the pricing logic, issues with the functionality, and testing of those things would take eons, let alone resolving everything.

You might then say, “Ok, so then prompt one store item at a time”. You could try that and you’d likely have a higher success rate, but you need to be even more granular than that. Prompts should look roughly as follows:

  1. Please add a score function as follows [Expand On Desired Methodology (EODM)]
    • There will be some intermediate prompts to refine UI integration here.
  2. Please add a score-to-currency function where [EODM]
    • Same as above
  3. Please add a store button with on-click pop-up and 5 placeholder items @ X cost each.
  4. Swap in actual store items manually or with their own prompt.
    • If you do anything manually, make sure any code you’re citing in prompts is updated to include those changes.
  5. Please add currency logic where the amount is deducted from the user’s total.
    • The rest of the steps will be contingent on actual store items and the desired behaviors, design, and relevance to your game, and each store item can be dozens of steps. For example purposes, I’ll simulate requesting Retro Thrusters I from OrbitTimer, with roughly similar details to the game itself.
  6. “For ‘Retro-Thrusters I’, if and only if purchased by the user, that item should be retained until/unless the game is reset.”
  7. “For ‘Retro-Thrusters I’, add two isosceles triangles which are 20px wide and 60px high. The midpoints of their bases should be at the lower corners of the rocket. The left triangle should be at the lower left corner of the rocket, and the right triangle should be at the lower right corner of the rocket.”
  8. “The ‘Retro-Thrusters I’, when ascending, should be very dark gray.”
  9. “The ‘Retro-Thrusters I’, when descending, should be yellow.”
  10. “The ‘Retro-Thrusters I’, when descending, should slow descent by 20%.”
It turns out 20% isn’t the most noticeable amount, so I recall asking for console logs to register the speed before and after so I could verify the change. This adds a few prompts.

That’s roughly the gist of it.

Each item will get around that number of core prompts, but realistically it’ll return errors, and you’ll want to do console logs to verify certain behaviors, so you could assume a multiple of at least 3, so at least 30 prompts to actually implement the above in totality, and 5 items would be about 150 prompts. Realistically, one feature (in my experience it’s random) will be a wildcard and end up taking a truly shocking number of prompts. In a currently-offline game, I iterated through a store like I outlined above, but one item was mysteriously very reluctant to be implemented and ended up taking 120-ish prompts. For one item. Another similar approach is to think granularly and incrementally, but all within one prompt, as seen in this article, "11 Prompt Engineering Best Practices Every Modern Dev Needs", by William Bakst. It's very interesting to comb through varying articles and see where approaches differ and where they overlap.


The Journey Ahead

As I write this, my current outlook is this: I’ve done a vintage-style arcade game (OrbitTimer), I’ve done another which hasn’t been published (title TBD), and I’ll be doing a third app which will be a little more serious but ultimately still just an exercise. For the third app, I’m going to be focusing on basic data visualization via free FRED (fed econ data) APIs, an SQL backend to learn a little about databases and SQL in general, and maybe a blog like this. Hopefully that all can be wrapped up within a couple of weeks, maybe 3 if it’s harder than I think it’ll be.

So that brings me to a review, essentially a ‘what I’d do differently, from the get-go, if I knew what I know now’.

Going forward, I’ll focus more on prep, design, and targets, then relentlessly iterate/prompt towards that goal. The percentage of overall makeup of what I have now, in OrbitTimer, that I originally planned for, is very very small. I didn’t even really have a list of bullet points. If you recall from my earlier articles, OrbitTimer originally started as more or less an accident. It originally started with me doing miscellaneous code tutorials, then branching off.

I didn’t have a plan or any seriously-defined goals, I just was spitballing ideas as they came to mind. Obviously the randomness of that paired with an unproductive iteration method; no backend versions, no locking down progress as it was made, nothing to fall back on, the maximum runway of what I thought was possible kept getting shorter and shorter. I originally wanted a DoodleJump-esque game, then by the time I published v1.0, it was really just a slow, no difficulty at all, no achievements, no levels, nonsense app. It was profoundly uninteresting and super glitchy. It was only after I did the (unpublished) glider game where I learned how to iterate in a productive way, that I came back to OrbitTimer and really let loose with everything I’d learned.

What a great pre-prompt structure also gives you, if you count progress by counting prompts, is much lower likelihood of hitting walls where you run out of ideas. If you have a very particular goal in mind, you’ll never wonder what should come next. You’ll always have the next steps pre-loaded in your mind. Because of this, you’ll be able to hit a higher total of prompts per day. You’ll never get to the end of a feature and have to take a break due to not being able to calculate what should come next. I think the evolution of tactics that’ve sped up my previous projects has been (1) focus on prompt engineering as opposed to “think longer”, (2) lock down files as successes occur, (3) introduce a ‘dev mode’ with access to all features to test and iterate more rapidly, and now (4) very very clear pre-defined goals with flow charts where needed, clear desires for functionality, and most importantly: Maximally ambitious end goals.

The idea of learning that I should have “maximally ambitious end goals” sounds like something that I should’ve already known, but it really took going through a couple of projects, and hundreds of iterations, and new methods, to realize everything is indeed possible. Because of that, i can now let loose. I think you should start with that perspective in mind.


Varieties of Production

Everyone learns lessons and as time has gone by, I’ve learned a big one. It turns out that AI is varyingly good at varying kinds of content.
With the above articles, I only had the experience of developing games. And, specifically games which needed very complex logic and sub-logic with wildly different if-then flows depending on circumstances. For example, a physics engine. If you design a game with a glider, you need pitching up to have wildly different characteristics at high speed than at low speed, and there are different downstream realities that happen in each of those contexts. This kind of variance in if-then flows is true for many things.

Counter to the above and physics engine design, I’ve done some more data-centric projects, and those’ve been incredibly easy thus far. Way less challenging. So, I’m writing this article simply to say that the difficulties vary depending on your project type.

I’d just say that the iterative approaches should still remain. You should still ask for one feature at a time. You should still save diligently as you iterate forward. You should still do all the procedural things I’ve mentioned before, and if you get lucky and AI happens to handle your project-type very well, then that’s great.


Broader Thoughts: AI’s Long Run Effect On The Economy

Over the last 10 years, there’s been a discussion in society about AI, and what has unfortunately dominated is the theory that the advent of AI in everyone’s lives will be a detrimental force, a force that’ll lead to mass unemployment. In general, I disagree, because the argument ignores what comes next. The argument basically terminates itself after layoffs, or continues down maximally gloomy avenues of varying levels of doom.

In reality, the basis for replacing people with AI is to save money, but said money doesn’t disappear. The money is reinvest-able elsewhere. Thus, the economy “after AI”, is where those savings get invested, and the R&D/CapEx of said investment is where the new jobs will exist. The fear of AI shouldn’t entail fears of being replaced by robots, it should IMO just be a matter of re-training and affordability thereof. Arguably via the improvement of LLMs, rigorous retraining itself won’t even be necessary.


An Underrated Lifehack for Morale

If you’re on this blog at all, by the time you’re at this article, you’ve probably done your fair share of prompting for a myriad of projects of all developmental stages. Today, I want to share a very basic lifehack to enhance (and counter) the slog.

The hack? Prompt nicely.

Dryly prompting like you’re talking to a computer might be tempting and might sound like the most efficient way of doing things, but frankly, getting 50, 100, or hundreds of prompts deep can often become frustrating.

So, what helps me is to start every thread with, “Hi [ChatGPT/other], hope you’re doing super well today. I was hoping to work on [XYZ], and was hoping you could help with… [continue prompt as needed]”.

It’s a super easy thing to do, and it only takes seconds. AI bots are easy to lead into certain tones, so setting the tone to the highest degree of friendliness possible is an easy way to make sure morale is maximally high, even when things get tedious. Think of it like a bright and sunny day versus a dismal foggy day, or having a room with a window versus without. Little environmental details can make huge differences in overall productivity and morale throughout any project. Hope this helps!