Letting AI Build My Frontend: A Tale of Two Chatbots

TLDR; Source Available The source code (in its final form) is available here. There were too many iterations with multiple LLM's to record & commit each iteration. Unfortunately, that means you can't follow along this journey with point-in-time code. But if you are interested in skipping to the end, the repo is there and it should be functional. AI Generated Code: First Steps So for those that haven't really used any of the genai chatbots, where do you start with generating code? That part is actually pretty easy; you choose a provider/LLM and give it a simple prompt, and iterate on the prompt. Usually the chatbot will acknowledge the request, and ask clarifying questions or make suggestions. For example, this is what I used: I want to build a very basic app for entering financial transactions. I can describe the model and the very basic business rules. But before we start, I'd like help in deciding on the front end framework to use. For now I just want to build a simple single page application that I can run from my workstation/desktop; I will not be hosting it publicly at first I tried this prompt with two different LLMs: Gemini (2.5 Pro) Claude (3.5 Sonnet) And the results from each were wildly different. The mechanics of interacting with the chatbot - providing the initial prompt, and refining via continued prompts and possibly incorporating suggested feedback, were the same. But the questions and suggestions were completely different, and in the end produced highly divergent results. Observations between Gemini & Claude I will admit that since I'm still a novice, I didn't put a lot of thought into the actual models I used. I have tried to familiarize myself with the basics, and generally both Claude and Gemini received high praise for the quality of the generated code. Although I'll say most people have said Claude 3.5 Sonnet is better than 3.7, but that requires a Pro subscription so I stuck with 3.7. Initial instructions: Gemini My experience with Gemini was very interesting. The prompt I gave was very generic; I didn't give any hints about frameworks or technologies to use. Gemini responded by suggesting options including Vue.js, React, Svelte/SvelteKit, and Angular. It contrasted each selection with a list of Pros and Cons, and concluded that I should look at the Getting Started guides for each and reach my own conclusions. I responded that I just wanted to go with React: ok let's go with React for now, and use the best-in-class or default libraries where needed (such as for routing and state management). Gemini then provided instructions on how to bootstrap the application with npm and Vite to create the scaffolding of the project. Gemini concluded by asking for more information about the data model and business rules. Initial instructions: Claude I provided the exact same prompt to Claude, and it provided the exact same list of candidates as Gemini. However, there was much less detail here than with Gemini, and no compare/constrast amongst the candidates. But like Gemini, Claude did ask for more information about the data model/biz rules. Based on the quality of the first response, my instinct was to stick with Gemini. But I stuck with trying to provide the same prompts to each LLM to make sure I was comparing apples to apples. Data Model: Gemini I supplied a single sentence response to Gemini: Ok let's move on to the data model. And Gemini automatically generated javascript for a Transaction object, and provided a detailed explanation of each field. It then asked me if I liked the model, or if I wished to make any modifications. To be honest, the generated model only had a vague resemblance to what I had in my head. But to be fair, I had not provided any guidance other than in the initial prompt when I stated I wanted to enter financial transactions. The lesson to be learned here is that it does take some work to tease out what you want, and the more context you can provide, the better. So I spent some time writing up a very detailed description of the model that I use in my spreadsheet. All of the detail (context!) significantly changed the generated models. Gemini produced typescript definitions for an Account object, a Category object, and a Transaction object. It suggested improvements to how I modeled certain data in my spreadsheet, such as moving the running account total from the transaction to the Account object, and that made complete sense. In the case of a spreadsheet, it makes sense for the running account balance to be a formula based on the last transaction value, but not so much in actual code. Gemini further included statements about some assumptions it made, and asked me to confirm. It also made a suggestion that I didn't care for, as it didn't match my personal workflow. I informed Gemini of this difference and it accepted my feedback, and updated the typescript def

Apr 30, 2025 - 20:45
 0
Letting AI Build My Frontend: A Tale of Two Chatbots

TLDR; Source Available

The source code (in its final form) is available here. There were too many iterations with multiple LLM's to record & commit each iteration. Unfortunately, that means you can't follow along this journey with point-in-time code. But if you are interested in skipping to the end, the repo is there and it should be functional.

AI Generated Code: First Steps

So for those that haven't really used any of the genai chatbots, where do you start with generating code? That part is actually pretty easy; you choose a provider/LLM and give it a simple prompt, and iterate on the prompt. Usually the chatbot will acknowledge the request, and ask clarifying questions or make suggestions. For example, this is what I used:

I want to build a very basic app for entering financial transactions.
I can describe the model and the very basic business rules. 
But before we start, I'd like help in deciding on the 
front end framework to use.
For now I just want to build a simple single page 
application that I can run from my workstation/desktop; 
I will not be hosting it publicly at first

I tried this prompt with two different LLMs:

  • Gemini (2.5 Pro)
  • Claude (3.5 Sonnet)

And the results from each were wildly different. The mechanics of interacting with the chatbot - providing the initial prompt, and refining via continued prompts and possibly incorporating suggested feedback, were the same. But the questions and suggestions were completely different, and in the end produced highly divergent results.

Observations between Gemini & Claude

I will admit that since I'm still a novice, I didn't put a lot of thought into the actual models I used. I have tried to familiarize myself with the basics, and generally both Claude and Gemini received high praise for the quality of the generated code. Although I'll say most people have said Claude 3.5 Sonnet is better than 3.7, but that requires a Pro subscription so I stuck with 3.7.

Initial instructions: Gemini

My experience with Gemini was very interesting. The prompt I gave was very generic; I didn't give any hints about frameworks or technologies to use. Gemini responded by suggesting options including Vue.js, React, Svelte/SvelteKit, and Angular. It contrasted each selection with a list of Pros and Cons, and concluded that I should look at the Getting Started guides for each and reach my own conclusions. I responded that I just wanted to go with React:

ok let's go with React for now, and use the 
best-in-class or default libraries where 
needed (such as for routing and state management).

Gemini then provided instructions on how to bootstrap the application with npm and Vite to create the scaffolding of the project. Gemini concluded by asking for more information about the data model and business rules.

Initial instructions: Claude

I provided the exact same prompt to Claude, and it provided the exact same list of candidates as Gemini. However, there was much less detail here than with Gemini, and no compare/constrast amongst the candidates. But like Gemini, Claude did ask for more information about the data model/biz rules.

Based on the quality of the first response, my instinct was to stick with Gemini. But I stuck with trying to provide the same prompts to each LLM to make sure I was comparing apples to apples.

Data Model: Gemini

I supplied a single sentence response to Gemini:

Ok let's move on to the data model.

And Gemini automatically generated javascript for a Transaction object, and provided a detailed explanation of each field. It then asked me if I liked the model, or if I wished to make any modifications. To be honest, the generated model only had a vague resemblance to what I had in my head. But to be fair, I had not provided any guidance other than in the initial prompt when I stated I wanted to enter financial transactions. The lesson to be learned here is that it does take some work to tease out what you want, and the more context you can provide, the better.

So I spent some time writing up a very detailed description of the model that I use in my spreadsheet. All of the detail (context!) significantly changed the generated models. Gemini produced typescript definitions for an Account object, a Category object, and a Transaction object. It suggested improvements to how I modeled certain data in my spreadsheet, such as moving the running account total from the transaction to the Account object, and that made complete sense. In the case of a spreadsheet, it makes sense for the running account balance to be a formula based on the last transaction value, but not so much in actual code.

Gemini further included statements about some assumptions it made, and asked me to confirm. It also made a suggestion that I didn't care for, as it didn't match my personal workflow. I informed Gemini of this difference and it accepted my feedback, and updated the typescript definitions. It even asked me how I should handle the concept of refunds. You have to admit, that's an insightful question and not something I was expecting from an LLM.

Data Model: Claude

Gemini asked for some interesting clarification, so I updated my model prompt to include that clarifying context, and fed it to Claude. Claude gave me a bulleted list of components/objects (Account/Category/Transaction) with a brief description of each, and then suggested an outline for the React application. Claude then offered to create a starter React project, define a basic Reduxe store, and to generate basic UI components for entity listing and data entry. Again, in comparison to Gemini, the response was very brief and lacking in meaty detail. I asked Claude to proceed with its suggestions, and it started to generate some code. About half way through this process, I had apparently exhausted my use of Claude for a few hours, and to resume the next day. After it listed all of the generated code, it provided instructions on how to bootstrap the application and set up Tailwind CSS. Two of the steps were as follows:

npm install @reduxjs/toolkit react-redux react-router-dom tailwindcss
npx tailwindcss init

I followed the instructions, and the npx command failed with an error. I provided that error to Claude, it suggested a couple of solutions. Unfortunately, each solution it provided did not work on my workstation. I'm confident that if I had spent my own time debugging the issues, it was likely some npm dependency issue and a conflict in my environment. But for now, I'm trying to rely on the AI as much as possible, and ultimately I just removed Tailwind CSS.

After that, it was a matter of manually copying/pasting all of the generated code into the appropriate source files in the workspace. At this point, I was able to run the app and access it via the browser. It was bare bones, and since it lacked styling, it was aesthetically displeasing.

Back to Gemini

Since I couldn't get Claude to figure why npx and tailwind were not functioning in my environment, I went back to Gemini, and asked it to generate the starter project. It provided the following instructions:

# 1. Create the Vite project with the React TypeScript template
npm create vite@latest financial-tracker-app --template react-ts

# 2. Navigate into the newly created project directory
cd financial-tracker-app

# 3. Install the project dependencies
npm install

# 4. Install React Router for handling navigation
npm install react-router-dom

And then gave me step by step instructions on which files to create, including the source (mostly typescript in this case), and explained the purpose of each source file.

Unfortunatly, what it generated was too basic to be useful and lacked any of the functionality I was seeking. Basically, it was just a home page that listed dummy data for categories, accounts, and transactions. I was really surprised by this, because Claude assumed from the beginning that I wanted full CRUD functionality for each entity.

I kindly informed Gemini:

I need the ability to list, add, modify, 
and delete both accounts and categories. 
Can you generate these components/forms/pages?

Gemini dutifully performed as asked, and generated a bunch of new code. All of this had to be copy/pasted into the code editor (VS Code at this point). But it was still ugly. So I asked Gemini to style the app, using Material.

Lots of Progress, and an Error

More code was generated. More code was pasted into the IDE. Now, it was at least somewhat visually appealing:

Account Details

It still lacked the core purpose of the application, however; there was still no method of actually entering a transaction. I therefore asked it to generate a page for transaction entry. More code generation, more copy/pasting. And then a typescript error.

I've used typescript off and on over the years. I am not the biggest fan for a number of reasons, but that's another topic. The typescript compiler was complaining about something not being a valid string. It appeared to be an issue with double or even triple-escaping certain character sequences (embedded typescript string interpolation within a React TSX snippet, but the typescript string itself has embedded escaping), but I really didn't know how to resolve it. I shared the error and offending code with Gemini, along with my theory. It confirmed my suspicion and fixed the issue. After one more copy/paste, the transaction entry form was able to render.

Transaction Entry

Summary & Initial Impressions

I'll admit that I have been somewhat of a skeptic in terms of what AI can really accomplish. I am happy to say that is no longer the case. I knew AI could generate source code, but I am genuinely surprised by the insight and perceptiveness; its ability to ask meaningful questions to improve what it outputs. Furthermore, the experiencing of providing the AI a compiler error message and the broken line of code, and it actually fixing it? This is some pretty cool stuff, and I'm excited.

The workflow of working with a given chatbot in its native UI, and manually copying/pasting code from a browser tab into an IDE becomes repetitive very quickly. The chatbot UI helped me learn what I wanted in terms of interactions and their capabilities. It's time to move to an improved workflow, and my next line of investigation is to use Cursor AI.

I've also learned that context is super important. The more guidance one can provide, the better the results are going to be. AIs are surpringly good at dealing with open ended questions, but when it comes to generating code and emitting anything useful, more information is better. In fact, I am beginning to believe it might be better to be prescriptive when possible.

Conclusion: It was a good use of my time

This exercise was not one contiguous block of time; I worked on it here and there over about two and a half days. But in clock time? I had two working examples (of varying functionality and ugliness) in a matter of hours. Considering I don't have any experience with React, had I done this on my own following tutorials, it likely would have taken me several days or even a week. And I don't think I'd have had full CRUD operations for all three entities in that time.

The goal was to generate an SPA that mimicked the behavior of what I currently do via spreadsheet. The data is not persistent, and there are some rough edges, but I believe I accomplished my goal. There's still lots of room for improvement:

  • data validation
  • implementing business rules
  • adding some components
  • streamline transaction input

But will leave all of that for a future exercise.