Exploring AI-Assisted UI Development: Lessons from Creating a Hacker News Clone
Published: 2024-06-20 02:30:25

Recently, I've become interested in exploring the use of AI as a collaborator in the coding process. How can it expedite development, and what are the potential benefits and drawbacks of this approach?

After watching the following video: [Building Hacker News with AI, describe a UI and AI builds it for us](https://www.youtube.com/watch?v=rCDOI8vRpz0), I decided to try implementing a similar approach, creating a Hacker News UI clone as a way to get more experience utilizing AI as an assistant. 

The video uses Rendition, an AI assistant that translates text into Figma designs. I chose to create my clone from scratch, using Chat GPT (the unpaid plan based on Chat GPT 4, June 2023 version), Next.js, React, Typescript, and Tailwind CSS.

My goal was to experiment with how different prompts, varying in detail, yield different results. I'll focus on the Hacker News header to test these prompts.

Ideally, I would like a prompt to yield an "80/20" outcome where the AI generates around 80 percent of the code, and I only need to do 20 percent of the editing to make it match the website exactly. It would likely become more time consuming to attempt to engineer a perfect prompt (which probably doesn't exist anyways) than to generate a solid foundation and intervene with a few code edits here and there.

Each prompt was input in a separate chat session with the idea that responses would be generated independently of one another, without building on prior context.

The rest will be a simple account of my experience tinkering with prompts to get Chat GPT to generate the most accurate header component for the Hacker News front page. 

---

##Prompts and Results:

Initially, I considered reviewing the docs for prompt engineering suggestions. The docs suggest detailed prompts with clear delimiters between sections to leave as little as possible for the AI to interpret. (I also asked ChatGPT directly what kind of prompt would be most effective given the technologies I planned to use, just to see if its answer matched the docs. Unsurprisingly, ChatGPT's suggestion aligned closely with the prompt format laid out in the docs.)

While this clearly sounded like the most sensible approach, I wanted to see how vague I could be with prompts and still get a solid foundation for a component. Here are a few of the prompts I tested:

---

##Prompt 1: Following the Video's Example

I decided to implement the exact same prompt used in the video to see the difference in how Chat GPT with React and Typescript differed from Rendition. I thought it would be interesting to see what the results were here given that this prompt is quite a bit different from the approach suggested in the OpenAI documentation. The prompt uses more abbreviated wording than what is suggested and is all in one paragraph:

_"The component will be in a nextjs app using typescript and tailwinds css. Here is the description:_

_hacker news top bar, a single row of (left: logo, title, navlinks) and (right: login link). bold orange background. black text. links content: Hacker News new | past | comments | ask | show | jobs | submit"_

**_Result:_**

![video prompt result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uevasgxbr105p3046f8e.png)
```TS
const TopBar: React.FC = () => {
    return (
        <div className="bg-orange-500 p-4 flex justify-between items-center">
            <div className="flex items-center space-x-4">
                <img src="/logo.png" alt="Hacker News Logo" className="h-6" />
                <span className="text-black font-bold">Hacker News</span>
                <nav className="flex space-x-4">
                    <Link href="/new" className="text-black">
                        new
                    </Link>
                    <Link href="/past" className="text-black">
                        past
                    </Link>
                    <Link href="/comments" className="text-black">
                        comments
                    </Link>
                    <Link href="/ask" className="text-black">
                        ask
                    </Link>
                    <Link href="/show" className="text-black">
                        show
                    </Link>
                    <Link href="/jobs" className="text-black">
                        jobs
                    </Link>
                    <Link href="/submit" className="text-black">
                        submit
                    </Link>
                </nav>
            </div>
            <div>
                <Link href="/login" className="text-black">
                    login
                </Link>
            </div>
        </div>
    );
};
```

This yielded decent results, but the image is broken and includes a label to its right. It did not pick up on the pipes as delimiters between the links as Rendition did in the video, but overall it is still quite accurate.

---

##Prompt 2: Testing the Waters with Vague Instructions

I tried an exceptionally vague prompt to see what it would come up with on its own with minimal input:

_"generate code for the hackernews header in nextjs, react, typescript, and tailwinds"_

**_Result:_**

![vague prompt result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f8bija75js75ajk9rbf6.png)
```TS
const Header: React.FC = () => {
    return (
        <header className="bg-orange-500 text-white p-4 flex justify-between items-center">
            <div className="flex items-center space-x-2">
                <div className="bg-white text-black font-bold p-1 rounded">
                    <span className="text-orange-500">Y</span>
                </div>
                <Link href="/" className="font-bold text-xl">
                    Hacker News
                </Link>
                <nav className="space-x-4">
                    <Link href="/new">new</Link>
                    <span>|</span>
                    <Link href="/past">past</Link>
                    <span>|</span>
                    <Link href="/comments">comments</Link>
                    <span>|</span>
                    <Link href="/ask">ask</Link>
                    <span>|</span>
                    <Link href="/show">show</Link>
                    <span>|</span>
                    <Link href="/jobs">jobs</Link>
                    <span>|</span>
                    <Link href="/submit">submit</Link>
                </nav>
            </div>
            <div className="flex items-center space-x-4">
                <input
                    type="text"
                    placeholder="Search"
                    className="p-1 rounded border border-gray-300"
                />
                <Link href="/login">login</Link>
            </div>
        </header>
    );
};
```
This was surprisingly accurate given no detail was provided aside from “hackernews” and “header”. However, it missed the text color, styling is off for the logo, and spacing between links is off. It also added a search bar. But this does show how little information Chat GPT can go off of and still get the foundations right.

---

##Prompt 3: Generating Code from a Website Link

Providing only a link to the website:

_"generate code for the header of this website: https://news.ycombinator.com/ use nextjs, react, typescript, and tailwinds css"_

**_Result:_**

![link prompt result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/joes7t7x9a54f43he4jk.png)
```TS
const Header: React.FC = () => {
    return (
        <header className="bg-[#ff6600] p-1">
            <div className="container mx-auto flex items-center space-x-2">
                <div className="flex items-center space-x-1">
                    <img
                        src="/y18.gif"
                        alt="Y Combinator logo"
                        className="w-6 h-6"
                    />
                    <Link href="/" className="text-black font-bold text-lg">
                        Hacker News
                    </Link>
                </div>
                <nav className="flex-1">
                    <ul className="flex space-x-2 text-sm">
                        <li>
                            <Link href="/newest" className="text-black">
                                new
                            </Link>
                        </li>
                        <li>|</li>
                        <li>
                            <Link href="/front" className="text-black">
                                past
                            </Link>
                        </li>
                        <li>|</li>
                        <li>
                            <Link href="/newcomments" className="text-black">
                                comments
                            </Link>
                        </li>
                        <li>|</li>
                        <li>
                            <Link href="/ask" className="text-black">
                                ask
                            </Link>
                        </li>
                        <li>|</li>
                        <li>
                            <Link href="/show" className="text-black">
                                show
                            </Link>
                        </li>
                        <li>|</li>
                        <li>
                            <Link href="/jobs" className="text-black">
                                jobs
                            </Link>
                        </li>
                        <li>|</li>
                        <li>
                            <Link href="/submit" className="text-black">
                                submit
                            </Link>
                        </li>
                    </ul>
                </nav>
                <div className="flex items-center space-x-2">
                    <input
                        type="text"
                        className="border rounded px-1 text-sm"
                        placeholder="Search"
                    />
                    <Link href="/login" className="text-black text-sm">
                        login
                    </Link>
                </div>
            </div>
        </header>
    );
};
```

Again, mostly accurate but the image is broken, the spacing is a little off, and there is a search bar, but the text styling is right this time. But still off of only a link.

---

##Prompt 4: Using a Screenshot as a Prompt

Uploading a screenshot with no further description of the component:

_"generate code for the header of this website for nextjs, react, typescript, and tailwinds css"_

![hacker news screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sootol108kwy65n7fy4i.png)

**_Result:_**

![screenshot prompt result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ci82u8fpvhsnm3nlbnnl.png)
```TS
const Header: React.FC = () => {
    return (
        <div className="bg-orange-500 py-2">
            <div className="container mx-auto flex items-center justify-between px-4">
                <div className="flex items-center space-x-1">
                    <div className="bg-white h-6 w-6 flex items-center justify-center text-black font-bold">
                        <span>Y</span>
                    </div>
                    <Link href="/" className="text-white font-bold text-lg">
                        Hacker News
                    </Link>
                    <nav className="space-x-2 ml-4">
                        <Link href="/new" className="text-white">
                            new
                        </Link>
                        <span className="text-white">|</span>
                        <Link href="/past" className="text-white">
                            past
                        </Link>
                        <span className="text-white">|</span>
                        <Link href="/comments" className="text-white">
                            comments
                        </Link>
                        <span className="text-white">|</span>
                        <Link href="/ask" className="text-white">
                            ask
                        </Link>
                        <span className="text-white">|</span>
                        <Link href="/show" className="text-white">
                            show
                        </Link>
                        <span className="text-white">|</span>
                        <Link href="/jobs" className="text-white">
                            jobs
                        </Link>
                        <span className="text-white">|</span>
                        <Link href="/submit" className="text-white">
                            submit
                        </Link>
                    </nav>
                </div>
                <div className="flex items-center space-x-4">
                    <input
                        type="text"
                        placeholder="Search"
                        className="py-1 px-2 border rounded"
                    />
                    <Link href="/login" className="text-white">
                        login
                    </Link>
                </div>
            </div>
        </div>
    );
};
```

I had the highest hopes for this one. I was hoping for an identical clone. Initially, I was disappointed with the result. The colors in the header are off, from the logo to the text color. And it still insisted on adding a search bar. However, on second thought, considering this is going off of a screenshot it is pretty impressive to have generated so much detail. 

---

##Prompt 5: Detailed Description for More Accurate Results

Based on the example provided by the docs and chat gpt, I decided to implement the following approach, which is more along the lines of that of the video but with a little more detail:

_"I need to create the header component for a Hacker News clone using Next.js, TypeScript, and Tailwind CSS. I will only be creating the UI._

_Visual Design:_
_- small ycombinator "y" logo - white border, with white "Y"_
_- title "Hacker News", bold black, on left side of header_ 
_- links: to right of title - new, past, comments, ask, show, jobs, submit_ 
_- orange background_
_- each link separated by a_ _|_
_- 'login' link, right side of header "_

**_Result:_**

![detailed prompt result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ew4ibg2z6a8zjcmno89g.png)
```TS
const Header: React.FC = () => {
    return (
        <header className="bg-gray-200 p-2 flex items-center">
            <div className="flex items-center">
                <img src="/y18.gif" alt="Y Combinator Logo" className="mr-2" />
                <span className="font-bold text-black">Hacker News</span>
            </div>
            <nav className="ml-4 flex space-x-2">
                <Link href="/">new</Link>
                <span>|</span>
                <Link href="/past">past</Link>
                <span>|</span>
                <Link href="/comments">comments</Link>
                <span>|</span>
                <Link href="/ask">ask</Link>
                <span>|</span>
                <Link href="/show">show</Link>
                <span>|</span>
                <Link href="/jobs">jobs</Link>
                <span>|</span>
                <Link href="/submit">submit</Link>
            </nav>
            <div className="ml-auto flex items-center space-x-2">
                <input
                    type="text"
                    className="border rounded p-1"
                    placeholder="Search"
                />
                <Link href="/login">login</Link>
            </div>
        </header>
    );
};
```

Pretty accurate. With more detail in the initial prompt, it likely could have ironed out the styling for the logo. Minimal tweaking in tailwinds will fix the rest. More detail is clearly the way to go.

---

##Reflection

I was surprised with how little information Chat GPT could go off of to generate a UI component of a given website. It was interesting to see the subtle variations in different prompt approaches. Clearly the best way to go is with more detail and leaving as little as possible left for the AI to have to interpret. Having clear delimiters and segments in the prompt not only makes it easier for the AI but would make it easier for other developers to read and use.

I can see that leveraging AI as a collaborator can significantly expedite the process compared to writing components by hand, while giving the developer more time to focus on the overall architecture and implementation of a project.

So after a little prompt experimentation I've got the foundations of a Hacker News header and a few code edits to make.

A few questions to consider going forward:

- Did Chat GPT's accuracy have anything to do with Hacker News being a widely used site for clone projects? 
- Would a similar quality of results be generated with a more obscure site? 
- Could another AI be used effectively to make code edits?