Vibe coding is easy. Anyone can get ChatGPT to write a functional calculator in 20 minutes.
Vibe coding a beautiful calculator — one that looks like it belongs on Awwwards, loads instantly, feels premium in both dark and light mode, and doesn't make your users feel like they're using a 2019 Bootstrap template — that's the hard part nobody talks about.
I've been building MonuMoney.in for the past three months. It's a fintech calculator platform — 14 calculators, full blog system, SEO infrastructure — all built with Next.js 15, Tailwind CSS, and Google AI Studio. No design agency. No senior dev. Just me, working 7 to 10 PM on weeknights after my 9-5 digital marketing job.
The UI looks nothing like what AI usually generates. Here's how I forced it to stop giving me generic layouts.
The Core Problem With AI-Generated UI
When you give most devs (or AI) a blank prompt like "build me a calculator," you get this:
- White background, black text
- Input fields with default browser styling
- A blue
#submitbutton font-family: sans-serif- Absolutely zero visual hierarchy
It's functional. It's also forgettable.
The issue isn't that AI can't write beautiful code. It's that you haven't constrained it enough. AI does what you ask. If you ask for "a calculator component," you get the average of everything it's ever seen — which is, statistically, pretty mediocre.
You need prompt architecture, not just prompts.
The Design System Lock-In Prompt
Before I generate a single component, I establish a global design constraint. I give this to Claude first, which then writes production prompts for Google AI Studio:
Design constraints for all components:
- Dark mode default, light mode toggle. Colors use CSS variables via Tailwind theme extension.
- bg-page (page background), bg-card (elevated surface), text-primary (headings), text-secondary (body), text-muted (captions)
- Border: border-border-subtle (thin, low contrast — never harsh)
- Accent colors: accent-blue, accent-green, accent-orange, accent-pink — used sparingly for data visualisation only, never for decorative borders
- Font stack: font-serif (Lora) for headings only, font-sans (Inter) for UI, font-mono (JetBrains Mono) for numbers
- Spacing: use pixel-precise values [24px], [32px], [48px], [64px] — not Tailwind utility shortcuts
- Border radius: [20px] for cards, [12px] for inputs, [8px] for buttons — consistent everywhere
- No box shadows. Depth comes from border + background contrast, not shadow.
- No gradients on text. Gradients allowed only on result cards as subtle background.
This one block, prepended to every component prompt, eliminates 90% of generic AI output. The AI can't default to white backgrounds and blue buttons because those colours aren't in the system.
The Typography Prompt That Creates Cinematic Feel
Generic AI UI uses text-xl and text-2xl for everything. Premium UI uses intentional scale jumps with tight leading.
Here's the exact typography instruction I include for hero numbers (like EMI results or SIP corpus values):
Main result number: text-[40px] md:text-[48px] font-bold text-primary font-serif leading-none
Section H1: font-serif text-[32px] md:text-[48px] font-bold text-primary leading-[1.2] tracking-tight
Section H2: font-serif text-[24px] md:text-[32px] font-bold text-primary mb-[24px]
Body copy: text-[16px] leading-[1.7] text-secondary
Captions/meta: text-[13px] text-muted
Labels: text-[15px] font-medium text-primary
The leading-none on the hero number is critical. It collapses line height to the font size, making large numbers feel sculptural rather than floaty. The tracking-tight on headings prevents the loose letter-spacing that makes AI-generated headers look cheap.
The Card System That Builds Depth Without Shadows
Every AI out of the box reaches for shadow-lg. I banned shadows entirely in my design system. Here's the card pattern I enforce:
// Standard elevated card
className="bg-card border border-border-subtle rounded-[20px] p-[24px] md:p-[32px]"
// Result/highlight card (gradient instead of shadow)
className="bg-gradient-to-br from-card to-accent-green/5 border border-border-subtle rounded-[20px] p-[24px] md:p-[32px]"
// Table container
className="bg-card border border-border-subtle rounded-[20px] overflow-hidden"
// Table header row
className="bg-card-alt border-b border-border-subtle"
// (bg-card-alt is a slightly lighter/darker variant — creates depth purely through background contrast)
No shadows. The elevation hierarchy is: bg-page → bg-card → bg-card-alt. Three levels. That's enough.
The Full Prompt Architecture in Practice
Here's what a real prompt for a calculator component looks like when you apply all these constraints. This is what I feed into Google AI Studio after Claude has pre-engineered it:
Build a React client component: EmiCalculatorClient.jsx
Use "use client" directive. Import useState from React.
DESIGN SYSTEM (apply to every element, no exceptions):
- Color tokens: bg-page, bg-card, bg-card-alt, text-primary, text-secondary, text-muted, border-border-subtle, accent-blue, accent-green, accent-pink
- No hardcoded colors (#fff, #000, bg-white, bg-gray-*, text-white, text-gray-*)
- Card pattern: bg-card border border-border-subtle rounded-[20px] p-[24px] md:p-[32px]
- Result card: bg-gradient-to-br from-card to-accent-blue/5 border border-border-subtle rounded-[20px]
- No box shadows anywhere
- Spacing: always use pixel values [16px], [24px], [32px], [48px] — never arbitrary Tailwind like p-6
TYPOGRAPHY:
- Hero result number: text-[40px] md:text-[48px] font-bold text-primary font-serif leading-none
- Labels: text-[15px] font-medium text-primary
- Helper text: text-[12px] text-muted mt-[8px]
LAYOUT:
- Grid: grid-cols-1 lg:grid-cols-12 gap-[24px]
- Inputs: lg:col-span-7
- Results: lg:col-span-5 sticky top-[80px]
SLIDERS:
- className="w-full h-[6px] bg-border-subtle rounded-lg appearance-none cursor-pointer accent-accent-blue"
- Input box alongside slider: bg-page border border-border-subtle rounded-[8px] px-[12px] py-[6px]
[Then describe the actual calculator logic here]
The design constraints come first, before any business logic. AI prioritises what it sees first. Lead with design, and the logic fits around it.
The Mobile-First Card Grid Pattern
The calculator index page uses a grid of cards. Here's the exact prompt snippet I use for any card grid:
Calculator cards grid layout:
- Container: grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-[16px]
- Each card: bg-card border border-border-subtle rounded-[20px] p-[20px] hover:border-primary/30 transition-colors block (as Link wrapper)
- Icon area: w-[48px] h-[48px] rounded-[16px] bg-page border border-border-subtle flex items-center justify-center mb-[16px]
- Card title: text-[15px] font-medium text-primary leading-[1.4] mb-[8px]
- Card description: text-[13px] text-secondary leading-[1.5]
- No decorative arrows or "→" icons — the entire card is clickable
The hover:border-primary/30 instead of hover:shadow-md is intentional. It creates a subtle focus state that stays within the design system. Adding shadow on hover is a Bootstrap habit. We don't do that here.
Dark Mode That Actually Works
Most AI-generated dark modes are just dark:bg-gray-900. That's not dark mode. That's just a grey background.
My CSS variable system (in globals.css) defines two sets of variables under :root and .dark:
:root {
--color-page: #fafaf9;
--color-card: #ffffff;
--color-card-alt: #f5f5f4;
--color-primary: #1c1917;
--color-secondary: #57534e;
--color-muted: #a8a29e;
--color-border-subtle: #e7e5e4;
}
.dark {
--color-page: #0f0f0e;
--color-card: #1a1917;
--color-card-alt: #242320;
--color-primary: #fafaf9;
--color-secondary: #a8a29e;
--color-muted: #57534e;
--color-border-subtle: #2d2b28;
}
And in tailwind.config.js:
theme: {
extend: {
colors: {
page: 'var(--color-page)',
card: 'var(--color-card)',
'card-alt': 'var(--color-card-alt)',
primary: 'var(--color-primary)',
secondary: 'var(--color-secondary)',
muted: 'var(--color-muted)',
'border-subtle': 'var(--color-border-subtle)',
}
}
}
Now when I tell AI to use bg-card and text-primary, it works correctly in both modes automatically. No dark: prefixes scattered throughout the JSX. The component is mode-agnostic.
The Result
MonuMoney.in is the live, production demo of this entire framework — 14 fintech calculators, full dark/light mode, mobile responsive, built entirely through AI prompts following the architecture above.
The UI has been called "looks like a real product" by multiple people who assumed it was professionally designed. It wasn't. It was prompt engineering.
The difference between "AI-generated crud" and "AI-generated product" is constraint specificity. The more precisely you define your design system in the prompt, the less the AI has to guess — and the better the output.
Quick Reference: The Anti-Generic Checklist
Before you submit any UI prompt to AI, verify:
- [ ] All colors are design tokens, not hex values or Tailwind grey utilities
- [ ] No box shadows — depth from background contrast only
- [ ] Typography scale specified explicitly with pixel values
- [ ] Card pattern specified once, applied everywhere
- [ ] Mobile layout specified (stacked on small, grid on lg)
- [ ] Dark mode handled via CSS variables, not
dark:prefixes - [ ] No "click here" buttons — every interactive element has purposeful label
That's the whole system. Not magic. Just constraint.
Building something with this approach? Drop a comment — I'm curious what you're making.
Top comments (0)