Who is this article for?
- Founders who are used to relying on development teams, but whose current resources or budgets have forced some projects to sit in the drawer for years.
- Beginners who don’t feel confident coding the first version of their product and don’t have the budget to hire developers.
- Startups that are stuck trying to raise a round just to build a prototype or MVP.
What makes this material different?
- I’m not a programmer, and I’m writing this with readers in mind who don’t have a technical background (although a technical mindset will definitely help).
- Over the last six months, I went all the way from not writing code at all to building two full-fledged products. Naturally, my understanding of code grew a lot during that time.
- Each of these services includes 30 – 40 database tables, around 50 components, and roughly 100,000 lines of code. In other words, these are not weekend demos or toy projects.
- The first service integrates with OpenAI to “make sense” of user-generated content. It uses a vector database, embeddings, and operations built around them.
- The second service includes an internal accounting system with double-entry bookkeeping, idempotent operations, and an integrated payment system for processing online payments.
- I’m not describing some magical way to build software without touching code at all. But this material shows that it is possible to build a real product without first spending years learning programming languages.
- You will still need to look at the code, occasionally edit it manually, and keep things under control — but you will be able to do it.
Introduction
The idea of fully automated development is very popular right now: describe a product in text and get a working application. Some services can even produce a simple prototype.
But when we are building a product to test real hypotheses, the expectations are different. We want proper UI/UX, good performance, caching, scalability, and the ability for real developers to work with this code later.
From my experience, even strong models like Opus handle backend logic and database structure quite well, but they struggle much more with frontend architecture. They often generate unnecessary code, break the system into components poorly, and ignore client-side performance.
That’s why I don’t use fully automatic generators. There is no magic here: if even Opus inside my Cursor can confuse the frontend, the same thing will happen in any other product built on top of LLMs.
In this series, I use a different approach: an IDE with built-in AI agents. The AI helps write code and plan tasks, but the architecture and key decisions remain under human control.
Why did I choose Cursor?
Simply because I read that it is built on top of the popular VS Code editor. It seemed like a reasonable choice. I don’t think Antigravity would be worse; in practice, the result will be roughly the same, because the quality of the solution mostly depends on the model being used. The editor itself is just a shell that gives the model access to your project files and environment.
The story began in the summer of 2025, when I was discussing with DeepSeek an idea that had been in my head for almost 10 years: a social network of preferences, where users receive recommendations based on similarities in their personal ratings (restaurants, hotels, countries, hobbies, basically anything). And suddenly it said:
Let’s build it. We should use Next.js.
3 months later, I found myself presenting the product to the top management of a large corporation, and they were the ones who asked me to do it.
What’s funny is that, despite 20 years in IT as a founder, that had never happened to me before.
More recently, I also brought another long-postponed project to launch, one that had been sitting in a folder for years. I always assumed it would be too complex and expensive to build, and the topic itself felt risky enough that I didn’t want to invest money into it.
In this series, I’ll share the entire experience: real prompts, configurations, and pitfalls. But before we go further, we need to answer the most important question:
Should you even try this?
Short answer — yes, if you roughly understand these concepts:
- frontend
- backend
- databases
- HTML structure
- CSS styling
- JavaScript behavior
- basic React concepts
If these ideas already make sense to you, feel free to scroll down to the "Choosing a Framework" section.
If these terms sound unfamiliar, it’s better to take a moment to understand them now. What follows won’t feel like scrolling social media, but consider this: this journey saved me roughly $300,000 and a couple of years of development, hiring contractors, and building a team.
Frontend vs Backend
In simple terms, the frontend is what the user sees:
- a website in a browser
- a mobile application
- a browser extension
- any interface where users click buttons or read information
The backend is the part of the system that runs on servers somewhere on the internet.
It handles:
- data processing
- authentication
- business logic
- communication with databases
When a user clicks a button, the frontend sends a request to the backend. The backend processes the request and sends data back.
The interaction looks roughly like this:
User → Frontend → Backend → Database → Backend → Frontend → User
In practice, the frontend interacts with the backend through API routes: special URL addresses that the frontend sends requests to:
/api/articles
/api/login
/api/create-article
When the frontend calls one of these addresses, the server runs the necessary code:
- verifies the user
- queries the database
- processes the data
- and returns the result.
For example, the frontend might send a request like this:
GET /api/articles?author_id=535
The backend receives this request, retrieves the articles from the database, and returns them to the frontend.
What Is a Database?
A database stores the information used by the application. If you’ve used Excel or Google Sheets, the concept is very similar. Think of a database as a collection of tables. Each table is like a spreadsheet.
Users Table
|
id |
name |
|
|---|---|---|
|
1 |
Alice | |
|
2 |
Jack |
Articles Table
|
id |
name |
|
|---|---|---|
|
1 |
1 |
First article |
|
2 |
1 |
Another article |
|
3 |
2 |
Jack's article |
In this example, one user can create many articles.
This simple structure of related tables forms the foundation of most software systems. In your own service there might be 30–50 tables, even if right now it feels like there will only be three.
HTML: Structure of the Page
HTML defines what exists on the page.
- headings
- paragraphs
- buttons
- images
- containers
Example:
<div>
<h1>Hello</h1>
<p>This is a paragraph</p>
</div>
HTML elements form a nested structure called the DOM.
div
├── h1
└── p
Every webpage in your browser is essentially a large tree of elements.
CSS: How Things Look
If HTML defines structure, CSS defines appearance.
- colors
- fonts
- spacing
- layout
- positioning
Example:
/* CSS class that defines how the title looks */
.title {
color: blue;
font-size: 32px;
}
Applied like this:
<!-- HTML heading that uses the CSS class above -->
<h1 class="title">Hello</h1>
Combining Multiple Classes
One important concept in CSS is that elements can have multiple classes.
Example:
<!-- button with multiple classes -->
<button class="button button-primary button-large">
Submit
</button>
Each class can control different aspects of styling.
/* base button style */
.button {
border-radius: 6px;
}
/* button color style */
.button-primary {
background: blue;
color: white;
}
/* button size */
.button-large {
padding: 16px 24px;
}
This flexibility is powerful. But it can also become confusing in large applications when styles start interacting with each other.
Why Tailwind Helps
This is one reason many modern projects use Tailwind CSS. Instead of writing large CSS files, Tailwind uses predefined utility classes.
Example:
<button class="bg-blue-500 text-white px-6 py-3 rounded-lg">
Submit
</button>
<!-- bg-blue-500 = blue background -->
<!-- text-white = white text -->
<!-- px-6 = horizontal padding -->
<!-- py-3 = vertical padding -->
<!-- rounded-lg = rounded corners -->
Each class represents one small styling rule. This approach has a surprising advantage when working with AI tools like Cursor. AI tends to generate Tailwind layouts much more reliably than traditional CSS.
If you don’t explicitly instruct Cursor to use Tailwind, it may start embedding styles directly into each element.
Example:
<!-- style written directly inside the button element -->
<button style="background: blue; padding: 12px;">
This works initially.
But later it becomes painful, because changing the design requires editing every component individually. Reusable classes allow you to change the design of the entire application by modifying only a few shared styles.
JavaScript and TypeScript
HTML defines structure. CSS defines appearance. JavaScript defines behavior.
Press enter or click to view image in full size
JavaScript allows the interface to react to user actions.
Example:
// when the user clicks the button, show a message
button.addEventListener("click", () => {
alert("Hello!");
});
TypeScript is essentially JavaScript with additional type safety.
JavaScript:
// a simple function that adds two numbers
function add(a, b) {
return a + b;
}
TypeScript:
// the same function, but with explicit types
// a and b must be numbers
// the function returns a number
function add(a: number, b: number): number {
return a + b;
}
Most modern applications use TypeScript because it prevents many errors in larger systems.
Why We Will Use Next.js
In the rest of this series, we will build the example application using Next.js. Next.js is a framework built on top of React. React focuses on building user interfaces.
Next.js adds things like:
- routing
- server rendering
- API endpoints
- project structure
- build tools
You don’t need to deeply understand Next.js internals. But it helps to understand how React applications are structured.
Fortunately, the core ideas are very simple. You only need to understand three things:
- components
- props
- hooks
React Components
React applications are built from components.
A component is a reusable piece of interface.
Examples include:
- buttons
- navigation bars
- comment blocks
- modal windows
Example component:
// A simple React component.
// It renders a button.
function Button() {
return <button>Click me</button>
}
Now it can be reused anywhere.
<Button />
<Button />
<Button />
Large applications become trees of components.
Props
Props are inputs passed into components.
Example:
// A simple React component.
// It renders a button and shows the text passed in props.label.
function Button(props) {
return <button>{props.label}</button>
}
Usage:
// The same component can be reused with different labels
<Button label="Save" />
<Button label="Delete" />
<Button label="Cancel" />
Hooks
Hooks allow components to store state and react to user interactions.
Example:
// useState creates a piece of state inside the component.
// "count" stores the current value.
// "setCount" is the function used to update it.
const [count, setCount] = useState(0)
Now the component can update its internal state.
// When the button is clicked, the count increases by 1.
// The text updates automatically.
<button onClick={() => setCount(count + 1)}>
Clicked {count} times
</button>
Hooks make components interactive.
Summary:
- If you have never encountered these concepts before, I understand how this might feel.
- But you don’t need to master all of this at a professional level. You only need to understand the basic idea. If you have a technical mindset and can grasp these concepts, the journey becomes much easier.
- Instead of randomly asking AI to generate something, you will be able to guide it properly. And that makes a huge difference.
Before Moving Forward
Make sure you roughly understand:
- frontend vs backend
- databases as tables
- HTML structure
- CSS classes and styling
- JavaScript behavior
- React components, props and hooks
What’s next?
Before diving into a technical specification for your product, answer this: What stack will you use?
At first glance, this may seem like a purely technical decision. But when you build software with Cursor, the stack effectively becomes part of the instructions you give the AI. If you don’t define it in advance, the AI will start improvising, and I’d rather not even think about where that might lead.
Here I’ll describe the stack I ended up using myself. This setup worked extremely well for me and may help you avoid some of the problems I ran into at the beginning.
Choosing a Framework
If your product has a web interface (meaning users interact with it through a browser), you’ll need a framework that handles both the frontend and the backend.
For both services I built, I chose Next.js, and I never regretted that decision.
I should mention that I had never worked with Next.js before. I was familiar with things like PHP, Laravel, JavaScript, and similar technologies, but in this case I simply followed ChatGPT’s recommendation. And it worked.
The point is: even if you already know another stack, this might be a good opportunity to try something new.
If you’ve been far from development altogether, you may run into challenges with client-side caching and application state management (these are necessary if you want to fully avoid things like page reloads while a user interacts with your service). That’s where experience really helps. In the next parts, I’ll describe the main things I ended up doing.
In the end, this kind of polishing is definitely not required to bring a product to market. Once you have users and revenue, you can always hire a frontend developer to refine things further.
Where Will Your Server Run?
Once the framework is chosen, the next question is where the application will actually run. In other words: hosting.
Vercel
For my first project, I used Vercel.
This is a fairly natural choice when working with Next.js. Deployment (pushing your application to the server) happens automatically out of the box whenever you run git push.
However, over time, I ran into an unexpected issue: in some regions, the application simply isn’t accessible. Because of this, the first project remained on Vercel, but for the second one, I decided to try something different.
Fly.io
For the second project, I switched to Fly.io.
Deployment there is a bit more complex than on Vercel, but it can be automated. In the end, I actually liked Fly.io even more. It feels more flexible for scaling if the project starts to grow.
Interestingly, Fly.io doesn’t formally have a free tier, but if your monthly usage stays below $5, they don’t charge you anything at all.
Choosing a Database
There are two main approaches here:
- The first option is to run your own database on your own server. This gives you full control and can be completely free.
- The second option is to use Database as a Service.
For both of my projects, I chose the second approach because I wanted to move as fast as possible. I used Supabase.
Supabase provides a managed PostgreSQL database along with several extremely useful tools.
Why Supabase Was Convenient
- Supabase supports vector storage. This became important for one of my projects where data was stored as embeddings generated with the OpenAI
embedding-3-smallmodel. As AI becomes more integrated into software products, having native support for vector data becomes surprisingly valuable. - Supabase includes built-in authentication. Users can log in using providers like Google, GitHub, email and other providers.
- Supabase also provides file storage, which allows users to upload images and other assets without building separate infrastructure.
- Another very useful feature is support for RPC functions. In my second project I completely stopped allowing the backend to query database tables directly. Instead, everything goes through RPC functions. In practice, this significantly reduced code generation errors.
- Supabase also includes powerful security tools like Row Level Security (RLS) policies.
Supabase Drawbacks
- The first issue I encountered involved the built-in authentication system. Specifically, Google login behaves inconsistently for users accessing the application through Safari on iPhone. I only discovered this after about two months of development, and in practice it turned out to be almost impossible to fix. In my second project I ended up using only part of Supabase’s authentication system.
- The second drawback is pricing. Supabase technically offers a free tier, but in practice, you may still end up paying around $25–40 per month, even if the application is still in development and has no users. It’s not a huge amount, but it’s something to keep in mind.
Cursor + ChatGPT: Two Different Roles
For me, Cursor is the primary development environment. There are other IDE options, but Cursor worked very well in my case. Switching to something like VS Code and interacting with an AI assistant through the terminal is something I personally have no interest in trying.
The main downsides of Cursor are cost and frequent updates.
At some points, my spending reached $100 per day. Over time, I learned how to control those costs. Today, a realistic estimate is about $300 per month if you actively use powerful models.
Cursor also offers a base subscription for around $20, but relying on the cheapest model is practically impossible, and the limits for paid models are quite small.
Why ChatGPT Is Still Important
Even if you use Cursor, I strongly recommend having a ChatGPT Plus subscription.
My workflow usually looks like this:
- Cursor → writing and modifying code
- ChatGPT → discussing ideas and architecture
Inside Cursor, the model is optimized for code generation and stability. Outside Cursor, ChatGPT behaves more like a creative thinking partner.
A simple rule:
Don’t ask ChatGPT to write your production code
It doesn’t make much sense. The same model inside Cursor, or especially models like Opus, will generate code much better.
Using ChatGPT for Visual Assets
Another unexpected use of ChatGPT was image generation.
My second project represents visual environments: digital parks with monuments, paths, and decorative objects. That required a large number of graphical assets. Instead of buying assets or hiring designers for every iteration, I generated most of the visuals directly with ChatGPT.
Since image generation is included in the ChatGPT Plus subscription, this saved a surprising amount of money during development and was simply very convenient.
Design Tools
Many developers use Figma to design interfaces before writing code.
Personally, I barely used it. Cursor can generate reasonable UI layouts on its own, and I simply adjust them manually afterward.
However, if you prefer designing interfaces first, Figma can still be very useful.
Google is also experimenting with tools that convert design layouts directly into code. One example is Google Stitch, which can generate an initial implementation from interface designs.
In theory, you can:
- design the interface in Figma
- generate templates with Stitch
- then convert those templates into React components
Email and Small Infrastructure Pieces
Most applications eventually need to send emails.
For this, I used a simple service called Resend.
Later, you may also want to introduce caching using something like Redis, but in both of my projects, I postponed that step.
If the architecture is designed properly, caching can always be added later.
Do You Need Docker?
In both projects, I managed to work entirely without Docker.
Vercel builds the project automatically (as I understand it, the service was created by the same team that developed Next.js). With Fly.io, you can use Docker to build the project locally on your machine, but you can also upload the files as they are and let the build run on their servers.
At one point, something broke, and Fly.io stopped picking up the files and starting the build. The common advice online is either to change the server region in the Fly settings or switch to local builds (which is where Docker becomes useful). But I solved it differently, by using a specific flag in the Fly deployment command, so I didn’t have to do either of those things. You can also just ask Opus how to fix it with minimal effort (without changing the server or installing Docker). It will usually suggest a workable solution.
Hardware Matters More Than You Think
One unexpected lesson had nothing to do with programming.
Your hardware setup matters
Cursor works much better when you have enough screen space to see multiple panels at the same time. I initially started development on a small 13-inch tablet. Technically it worked, but it was extremely uncomfortable.
Switching to a 27-inch monitor dramatically improved the workflow.
Cursor can also be fairly resource-intensive, so having a reasonably powerful computer definitely helps.
Operating System
For context, I ran this entire experiment on Windows.
However, nothing in this stack actually depends on Windows, except for the AI’s constant attempts to generate shell commands using && (which can be fixed with a few rules I’ll describe later).
The same setup works perfectly well on macOS or Linux.
Minimal Stack Summary
If we simplify everything, my stack looks roughly like this:
- Framework: Next.js
- Database: Supabase
- Hosting: Fly.io
- IDE: Cursor
- Chat: ChatGPT
- Email: Resend
And that turned out to be more than enough to build real working products.
What Comes Next
Before writing any code, you need to clearly describe the product.
Most people using AI tools jump straight into coding. In my experience, that’s the fastest way to create a chaotic system.
If you haven’t built a product with AI yet, honestly, I envy you. I still remember the feeling I had in the summer of 2025 when I first started experimenting with it.
Now my advice may sound a bit strange:
Stop for a few days.
Take 3 - 5 days and resist the temptation to immediately install Cursor, Antigravity, or any other AI development platform.
Because the quality of your thinking at this stage will determine how painful (or how smooth) the next weeks or even months of development will be.
Every 10 minutes of thinking now can save hours of refactoring later.
Start With a Conversation
At this stage, your main goal is to clarify your idea. The easiest way to do that is to open ChatGPT and start discussing it using voice input (not the full voice conversation mode, but the speech-to-text button). Your native language works perfectly fine.
Just start talking. For example, explain:
- What your product does
- Who the users are
- What problem it solves
- What actions users will perform
The goal of this conversation is not to generate code. The goal is to gradually discover the structure of the future system.
During this discussion, you should also tell ChatGPT what technology stack you plan to use.
For example:
- Next.js
- TypeScript
- Supabase
- Tailwind
And explicitly ask ChatGPT not to generate code yet. Explain that you’ll write the code later in Cursor, but you want ChatGPT to describe how it would architect the system.
I’ve personally seen several people spend months circling around an idea without ever asking the AI this simple question.
Think About Data, Not Just Screens
One of the most important parts of this stage is designing the data model.
If you’ve never worked with databases before, imagine the system as a set of Excel spreadsheets.
Ask yourself questions like:
- Can one user create multiple objects?
- Do objects belong to categories?
- Can categories contain multiple objects?
- Are there relationships between objects?
For example:
- one user → many articles
- an article → a category… or maybe
- an article → multiple categories and tags
- an article → many comments that load on scroll
- comments → reactions
Another important question is user roles. Will everyone be equal? Or will some users have additional privileges?
- moderators
- administrators
You can add roles later, but it’s much easier to plan for them early.
Ideally, your technical description should include:
- table names (articles, comments, reactions)
- column names (username, avatar, bio)
- relationships between tables
Even if you plan to evolve the product gradually, a clear structure from the beginning can save you a huge amount of refactoring later.
In both of my projects, the database eventually ended up with about 30–40 tables. Here’s the structure from my second project:
Your project will probably end up with a similar number. But for the initial technical specification, even 10 core tables is enough.
Job Queues
The most difficult concept for beginners is usually job queues. A queue is a table that stores tasks rather than objects like users or articles. You need a queue when your system interacts with external services.
For example, imagine that after a user publishes an article, you send it to an external service for translation or analysis.
You cannot reliably perform that operation instantly during article creation, external services may fail or respond slowly.
The article itself must be created immediately (because that depends only on your application). But additional data can be added later through a background process.
For example, your articles table might look like this:
|
id |
author_id |
picture |
title_en |
text_en |
title_es |
text_es |
|---|---|---|---|---|---|---|
|
32 |
535 |
one.jpg |
Article 1 |
Hello | ||
|
33 |
535 |
two.jpg |
Article 2 |
Next part |
После создания каждой статьи, она попадает в очередь на получение перевода от внешнего сервиса:
|
id |
entity_type |
entity_id |
status |
attempts |
es_text_generated |
|---|---|---|---|---|---|
|
1 |
article_text |
32 |
processed |
1 |
Hola |
|
2 |
article_text |
33 |
pending |
0 |
Как только задание в очереди выполняется, триггер автоматически дополняет информацию о статье в основной таблице статей
|
id |
author_id |
picture |
title_en |
text_en |
title_es |
text_es |
|---|---|---|---|---|---|---|
|
32 |
535 |
one.jpg |
Article 1 |
Hello |
Hola | |
|
33 |
535 |
two.jpg |
Article 2 |
Next part |
Queues for external services in Supabase are usually handled through Edge Functions.
In Supabase there are 2 different types of functions: RPC and Edge.
Remote Procedure Call
RPC is a function that replaces direct queries to your database tables. For example, instead of your server making a direct query to retrieve (SELECT) all articles belonging to a specific user (535):
SELECT *
FROM articles
WHERE author_id = 535;
I strongly recommend asking your AI assistant to create a function like this instead:
CREATE OR REPLACE FUNCTION get_user_articles(p_author_id bigint)
RETURNS TABLE (
id bigint,
author_id bigint,
picture text,
title_en text,
text_en text,
title_es text,
text_es text
)
LANGUAGE sql
SET search_path = ''
AS $$
SELECT
id,
author_id,
picture,
title_en,
text_en,
title_es,
text_es
FROM public.articles
WHERE author_id = p_author_id
ORDER BY id DESC;
$$;
Then, inside your project code, you simply call this function like this:
SELECT * FROM get_user_articles(535);
To make sure this approach always works correctly and consistently, add explicit rules to your technical specification (we will discuss it later):
- never query the database directly from the client; always go through server API routes
- forbid direct table queries inside the API; if a new data operation is needed and no RPC exists yet, create a migration with a new RPC function
- always use
SET search_path = ''inside RPC functions and explicitly reference the schema when accessing tables
I won’t go deeper into this topic right now, but following these rules will save you a lot of headaches later.
Edge functions
An Edge function runs outside the database and is typically used to interact with external services.
They run on JavaScript or TypeScript (Deno runtime) and can call RPC functions inside your database when needed.
That’s it. This was the most complex section about the database.
You might not fully understand it yet and that’s completely fine:
- First, at this stage these are secondary details.
- Second, during your discussion you can simply ask ChatGPT to find this article, “Cursor Your Dream,” and clarify anything you don’t understand. In my experience, it instantly understands the context and can explain queues, Edge functions, and whether you even need them.
- Third, as I mentioned in Part 1, Cursor is very good at building database and backend architecture. You won’t be left alone with these problems.
Think About Components
If you already have some idea about the interface, you can describe it in terms of components.
For example:
- Article component
- User profile component
- Modal windows
- Navigation elements
An article component might have several modes:
- view mode for readers
- edit mode for authors
- moderation mode for admins
If you think about components in advance, AI tools will later generate much cleaner code.
An Important Rule for Styling
Tell ChatGPT to include an instruction in the specification that Cursor should not use inline CSS styles, but instead use proper CSS classes, for example through Tailwind.
In one of my projects I forgot to mention this.
As a result, styling logic ended up scattered across dozens of components, and cleaning it up later was painful.
A Critically Important Note About Authentication:
- If you plan to use Supabase, specify that JWT tokens should be generated by your application, not by the default Supabase authentication system.
- If you’re new to authentication systems, this may sound strange. But this small detail can prevent serious problems later, especially when users sign in through Safari on iPhone.
Sample Case Study (from my second project)
To make this more concrete, let me show you how this process actually worked for my second project, “
The First Prompt
Here’s the very first prompt that started the discussion.
For many years I’ve had the idea of building a digital memorial.
It could be a platform where one group of users creates landscape maps, another places monuments, and others leave offerings — such as flowers or comments.
I think it could be a breakthrough idea because nothing like this seems to exist.
But I’m worried about legal issues. For example, what if someone creates a monument for a living person? Or creates a monument for someone like Michael Jackson — could that cause legal problems related to using the name?
Technically I imagine it as a website with an isometric map where monuments are placed.
Ideally we should find a good engine instead of building everything from scratch.
At that stage the prompt wasn’t technical at all. It was simply a starting point for discussion.
ChatGPT Response (shortened)
The idea of a digital memorial is interesting because it’s not just another social network. Your concept is closer to a digital space of memory, where people interact through symbolic actions: visits, comments, offerings.
The legal issue you mentioned — creating a monument for a living person — does exist. In some cases it could be interpreted as defamation or reputational harm.
However, platforms usually manage this risk through product design, not through total prohibition. For example:
— complaint and takedown systems
— clear rules for user-generated content
— framing memorials assymbolic spaces, not factual claims about deathTechnically, for an isometric map on the web it’s usually best to use an existing rendering framework. For fast prototypes, good options include:
— Phaser for interactive tile-based scenes
—PixiJS for flexible web rendering and UI integrationIf you later want real 3D monuments, you could switch to Three.js, but for an MVP a 2D tile-based approach is usually much faster.
After that the discussion continued.
My Follow-Up Messages
I’m fine with pseudo-3D.
At one level, users create a map: they choose its size as a grid and fill it with grass, paths, and other elements through a visual editor.
At another level, users place monuments that may occupy different numbers of tiles, such as 1, 2, or 4.
There is also a third type of user: they don’t create maps or monuments, they simply leave offerings such as flowers.
Each map should have its own unique URL.
I also want the map owner to receive a percentage of purchases inside their map. For example, if someone buys a monument there, I might share 20% of the revenue with the map owner.
If someone leaves flowers at a monument, perhaps 20% goes to the monument owner and another 20% to the map owner.
I’m thinking of building the project using Next.js + Supabase. Which pseudo-3D engine would be best?
Okay. Now expand the technical description, gather everything into a single document, and add an introduction explaining the problem and the product.
Markdown (.md) File with the Spec
After several conversations, the technical specification was ready. The same will happen for you. Make sure to ask for the final spec to be generated in Markdown format and copy it into a text file. Or have it create an .md file right away. You will definitely need this file at later stages.
But instead of sending it straight to Cursor, ask yourself this:
Which part of the product is the most important to you, or the most representative?
This matters because your first prompt for Cursor may differ from the technical spec. We’ll get to that later.
For me, that part was the map editor mechanics. So I decided to build only that first (without authentication, a database, or a backend).
My Final Prompt to ChatGPT
Write a prompt for Cursor where the main goal is to create a map editor. For now it should work without authentication and without Supabase. Even if the map cannot be saved yet, that’s fine.
The main goal is to feel the mechanics of the map before building the entire product. Ideally this should be a component that can later be integrated into a full system. During map creation we should define slots where users will later place monuments.
ChatGPT Response
Below is the final instruction that eventually produced the working prototype in Cursor.
You are a senior frontend / game engineer.
We are building only a prototype of a map editor (isometric pseudo-3D) as an isolated component in order to explore the core interaction mechanics.
Strict Constraints
No authentication. No Supabase, database, Stripe, or any backend components. No additional product screens. The goal is only the interactive mechanics of editing the map, slots, and monument placement.
Output Format
Implement this as a self-contained React component (React + TypeScript) that can later be integrated into a Next.js application.
The component must:
*— maintain **local state
*— expose a public API (props / callbacks)Technologies
— React + TypeScript
— PixiJS + pixi-viewportCore Product Model (IMPORTANT)
When a map is created, the owner defines SLOTS — rectangular areas on the grid where other users will later be able to place monuments.
In this prototype we implement both:
— the slot editor
— monument placementAll data is stored locally.
Entities (In-Memory)
Grid — NxM tiles (grass, path)
Slot — Rectangle defined as
x, y, w, hkind: monumentidMonument occupies exactly one slot
Properties:
size(1x1 | 1x2 | 2x2)slotIdrotation(optional)idPrototype Functionality (Editor MVP)
Generate an NxM map (default: 20 × 20). Isometric projection.
Camera controls:
— pan (drag)
— zoom (3 fixed zoom levels)Tools
— Paint grass
— Paint path
— Slot tool (create / delete slot, rectangle sizes: 1×1, 1×2, 2×2)
— Place monument (monuments can only be placed on an existing slot of matching size)
— Eraser (deletes monument or slot depending on what is under the cursor)Rules
— Paths cannot be covered by slots.
— Slots cannot intersect.
— A monument can only be placed into afree slot of matching size.
— Slots and monuments must never overlap.Selection
Clicking a slot or monument selects it (highlight with a frame).
A small info panel (React div) appears on the right showing:
— type
— coordinates
— size
— idExport / Import State (JSON, In-Memory)
Button Export JSON → outputs current state into a textarea.
Button Import JSON → loads state from textarea.
UX Details
Toolbar on top or left containing:
— tool selection
— slot size selector (1×1 / 1×2 / 2×2)
— Export / Import buttonsThe cursor mode should be clearly visible (label showing current tool)
Architectural Requirements (Important for Future Scaling)
Separate model (grid / slots / monuments) from renderer (Pixi layers).
Create Pixi Application and viewport only once. Do not recreate them on every state change.
Use
useEffectwith proper cleanup:— destroy app
— remove listeners
— cancel animation framesDo not store Pixi objects in React state. Store them in refs.
Handle container resize correctly using ResizeObserver.
Attach pointer events to viewport/stage once, and remove them on unmount.
Use depth sorting for isometric rendering (for example
x + yory) so objects overlap correctly.Task
First propose a minimal file structure:
mapEditor.tsxmodel.tsisoMath.tsrender.tsThen implement a minimal working prototype (TypeScript) so I can paste the component into an empty React / Next.js project and immediately see the editor working.
At the end include a short list of “things to improve later” (maximum 8 items).
Do not add anything beyond what is specified above.
Don’t Rush to the Next Step
Your task right now is to think about your idea. Discuss it. Refine it.
In my experience, it’s also important to focus on the MVP — the minimal version of the product that is still sufficient for a user to understand what the product is and what core problem it solves.
Two successful startups in my life actually began as nothing more than demos, even simple presentations. Today, AI tools simply allow us to build real products instead of demos, and test them on real traffic much faster.
You should also think not only about the product itself, but about the path to market.
Several of my projects stalled exactly at the point where I had no good answer to basic go-to-market questions.
So before writing code, try to clarify two things:
- what the product is
- how it reaches its first users.
In the end, you should have two documents
The first one is the full technical specification in the form of a Markdown (.md) file. This document will live in the root of your project and will be continuously read and updated by the AI during development.
The second one is the first working prompt — the prompt you will send to Cursor as your very first task. And this will only be the beginning. As development progresses, you will end up writing hundreds of prompts like this.
Next
In the next article (coming soon), we’ll finally move to the technical part: installing Cursor and generating the first real working code.
And this is where everything becomes both very exciting and a little chaotic.
