You do not need to be a designer to ship an interface that looks designed. You need a small set of constraints, applied without exception. Most amateur UI isn't ugly because of bad taste, it's inconsistent, and inconsistency is what reads as cheap.
The concept
Professional-looking UI comes from constraint, not talent. Pick a small number of values for each dimension and never use anything else:
| Dimension | Amateur | Professional |
|---|---|---|
| Spacing | 13px, 17px, 22px, whatever looked right | A scale: 4, 8, 12, 16, 24, 32, 48, 64 |
| Type sizes | 9 arbitrary sizes | 5-7 steps on a ratio |
| Colours | 30 hexes | 8-12 semantic tokens |
| Corner radii | 4 different values | 2-3 |
| Shadows | Random blur values | 3 elevation levels |
| Fonts | 3-4 families | 1-2 |
The constraint is the craft. A limited palette applied consistently looks intentional; an unlimited one applied by feel looks accidental.
The four systems
1. Spacing, an 8-point scale. 4, 8, 12, 16, 24, 32, 48, 64. Every margin and padding comes from this list. It's the single highest-impact change most amateur UIs can make, because inconsistent spacing is what the eye reads as "unfinished."
Related items sit close; unrelated items sit far apart. Proximity communicates grouping more strongly than borders or boxes do, which is why heavy use of cards is often a symptom of bad spacing rather than good structure.
2. Type, a modular scale. Pick a ratio (1.25 or 1.333) and generate steps: 12, 14, 16, 20, 25, 31, 39. Body text at 16px minimum on mobile (below that iOS auto-zooms on inputs). Line height 1.5-1.7 for body. Line length 65-75 characters, longer and the eye loses its place.
Two fonts maximum, and pair on a contrast axis (serif + sans, geometric + humanist) rather than two similar sans-serifs, which reads as a mistake. A single family in multiple weights is often stronger than a timid pair.
3. Colour, semantic tokens, not raw hex. Define meaning, not appearance:
--bg --surface --border
--text --text-muted --text-inverse
--primary --primary-hover
--success --warning --danger
Then only use tokens in components. This is what makes theming, dark mode, and rebrands possible instead of a search-and-replace nightmare.
Contrast is a hard floor, not a preference: 4.5:1 for body text, 3:1 for large text and meaningful UI elements. The most common failure in AI-generated and amateur designs is muted grey text on a tinted background, it looks elegant in isolation and is unreadable in use.
4. Elevation, three levels. Flat, raised (cards), floating (modals, menus). Each with one defined shadow. Don't invent a fourth.
Dark mode is not inversion
If you support it, design it. Pure black (#000) causes smearing on OLED and harsh contrast; use a very dark neutral instead. Desaturate accent colours, a colour that pops on white will vibrate on dark. Check contrast independently in both themes; values that pass in light routinely fail in dark.
When to build a design system
Not on day one. The sequence that works:
- Build 3-4 real screens with hard-coded values
- Notice what repeats
- Extract tokens and components from what you actually built
- Refactor the screens to use them
Building a system before you know your patterns is speculative work that you'll throw away.
The AI-slop tells
Design generated without judgment has recognisable fingerprints. Avoid:
- Gradient text (
background-clip: text), decorative, never meaningful - Glassmorphism as a default rather than a purposeful choice
- Coloured left-border accents on cards and callouts
- A tiny uppercase tracked label above every section
- Identical card grids, icon, heading, two lines, repeated forever
- Emoji as interface icons, inconsistent across platforms, unstyleable
- The warm cream/beige background that every generated "editorial" design lands on
None are wrong once, deliberately. All are tells when they're the default.
📐 Best practice
Define tokens on day one, even if there are only twelve of them. Retrofitting is painful.
Use a component library and restyle it. shadcn/ui, Radix, Mantine, or the platform's native components. You get accessibility, keyboard handling, and edge cases for free, and those are the parts that take longest to get right.
Steal structure, not pixels. Study products you admire for hierarchy and density, then apply your own tokens.
Use SVG icons from one set. Lucide, Phosphor, Heroicons. One family, one stroke weight.
Test at the extremes: longest realistic string, zero items, 1,000 items, smallest screen, largest system font.
Check contrast with a tool, not your eyes. Your eyes are wrong, especially on dark backgrounds.
Reuse before you create. Every new component is maintenance forever.
💀 Common mistakes
Arbitrary spacing. The clearest amateur signal there is.
Too many fonts, too many weights.
Low-contrast "elegant" text. Fails accessibility and annoys everyone over 35.
Raw hex values in components. Kills theming permanently.
Pure black or pure white backgrounds. #000 smears on OLED; #fff is harsh. Use near-black and near-white.
Cards for everything. Cards are the lazy grouping answer. Nested cards are always wrong.
Inconsistent corner radii across components.
Designing only with perfect data. Short names, square images, three items.
Copying a whole aesthetic rather than adapting its structure.
Building a design system before you have patterns.
The professional workflow
1. TOKENS FIRST — spacing scale, type scale, 8-12 colours,
2-3 radii, 3 shadows. One file.
2. PICK A COMPONENT LIBRARY. Restyle with your tokens.
3. BUILD 3-4 REAL SCREENS with real content.
4. EXTRACT what repeats into components.
5. STATES for every component: default, hover, focus, active,
disabled, loading, error.
6. RESPONSIVE: check 375 / 768 / 1280 / 1440.
7. DARK MODE (if supported): design it, don't invert it.
8. ACCESSIBILITY: contrast both themes, focus rings, 44pt targets.
9. EXTREME-CONTENT PASS: longest string, zero items, 1000 items.
Tools, websites & costs
| Need | Tool | Cost |
|---|---|---|
| Design | Figma, Penpot | Free tiers |
| Components (web) | shadcn/ui, Radix, Mantine | Free |
| Components (mobile) | Native SDK, React Native Paper, Tamagui | Free |
| Icons | Lucide, Phosphor, Heroicons | Free |
| Fonts | Google Fonts, Fontshare | Free |
| Palettes | Coolors, Radix Colors, OKLCH picker | Free |
| Contrast | WebAIM, APCA | Free |
| Inspiration | Mobbin, Godly, Land-book | $0-15/mo |
| Reading | Refactoring UI, the single best resource for non-designers | ~$99 |
Realistic cost: $0-100. A component library plus a token file gets a non-designer 80% of the way.
Alternatives & trade-offs
Component library vs custom. Libraries give you accessibility and edge cases free, at the cost of a somewhat familiar look. Custom differentiates and costs enormous time on states, keyboard handling and ARIA. Use a library and restyle it unless visual identity is your product.
Tailwind vs CSS-in-JS vs plain CSS. Tailwind enforces a scale by default (its real benefit) and clutters markup. CSS-in-JS colocates and adds runtime cost. Plain CSS with custom properties is simplest and needs discipline. All three work; consistency matters more than the choice.
Off-the-shelf theme vs original identity. A bought theme gets you shipping fast and looks like every other product using it. Original identity is slower and can be a moat (Chapter 13). For consumer, identity matters more; for B2B tools, competence matters more.
Design in Figma vs design in code. Figma is faster to iterate and creates a translation gap. Coding directly removes the gap and is slower to explore. Solo founders often do better sketching roughly then designing in code.
Checklist
- Spacing scale defined and used exclusively
- Type scale with 5-7 steps; body ≥16px on mobile
- Line length 65-75 characters
- 8-12 semantic colour tokens; no raw hex in components
- Contrast 4.5:1 body / 3:1 large, verified with a tool, in both themes
- 2-3 radii, 3 elevation levels
- 1-2 fonts, paired on a contrast axis
- One icon set, SVG, consistent weight
- All component states designed
- Tested at 375 / 768 / 1280
- Tested with extreme content
- No AI-slop tells
📓 Case Study: constraint doing the work of talent
Project: SOLIS. Solo founder, no design background, no budget.
The whole visual system fits in one block, and that's the point:
:root{
--bg:#15100b; --bg2:#1e1710; --card:#241b12; --card2:#2e2316;
--gold:#d4a24e; --gold2:#e8c279; --bronze:#a3793a; --crimson:#9a4631;
--text:#efe3c8; --muted:#a8946f; --ok:#b7c08a;
--radius:18px;
--serif:'Cormorant Garamond',Georgia,serif;
--body:'EB Garamond',Georgia,serif;
}
Eleven colours, one radius, two fonts. Defined on day one, used everywhere.
Three deliberate choices inside it:
- Warm text, never pure white.
#efe3c8on#15100breads as candlelight;#ffffffon brown reads as an unconsidered dark theme. A small decision with a large effect. - No blue anywhere. Every competitor in the category was blue or teal. Refusing the category-standard colour is what made a screenshot recognisable.
- Two fonts, one family. Cormorant Garamond for display, EB Garamond for body, paired by contrast of weight and size rather than mixing two similar faces.
⚠️ Deviation: hand-drawn decoration was attempted before real imagery, and it looked hand-drawn.
Several screens began as programmatically generated SVG "scenes", mountains, sunbursts, decorative flourishes. The verdict:
"dont try to make the design yourself, its pretty bad using svg, lets just use an image that is darkened, to match the vibe."
The commits read like a confession: "results, darkened background images instead of SVG-drawn scenes", "time-loss screen, painting with a grey→colour wipe."
📐 The generalisable rule: if you don't have design skill, don't generate decoration, use photography or art. A darkened photograph with good typography looks premium. A hand-coded "cinematic mountain range" looks like a hand-coded mountain range. This applies equally to AI-generated SVG, CSS illustrations, and elaborate gradient scenery.
⚠️ Deviation: a colour token failed contrast and nobody noticed for weeks.
A muted token used for small captions (11-14px) measured 3.72:1 against the background, below the 4.5:1 floor for body text. It looked fine; it was tested by eye, not by tool. It was caught only during a later audit and corrected to 5.36:1.
This is the most common contrast failure there is: muted text that looks elegant and fails the standard. The fix is a tool, not an opinion.
Where the constraint paid off. When the same identity was later applied to a completely different product surface, a documentation site, the palette, type pairing and radius transferred directly. A token system built for one product became a brand system for free, which is the compounding benefit of defining tokens early.
Lessons
- Constraint is the craft. Small palettes applied without exception read as intentional.
- The spacing scale is the highest-impact fix for amateur UI.
- Semantic tokens on day one. Raw hex in components kills theming permanently.
- Check contrast with a tool, in both themes. Elegant muted grey is the most common failure.
- Never pure white or pure black.
- Don't generate decoration you can't draw. Real imagery plus good type beats hand-made SVG scenery.
- Refusing the category colour is a strategy. Fitting in is invisibility.
- Use a component library and restyle it, you're buying accessibility and edge cases.
- Extract a design system after 3-4 screens, not before.