Design Judgment in Code: Beyond AI-Generated UI — Practical Techniques for Embedding Intent into Types, Tokens, and Conditionals
Master the comprehensive techniques for embedding human design judgment into code. From TypeScript's type system for expressing UI intent, through strategic design token architecture, to semantic conditional branching and component API patterns. Learn how to inject judgment into AI-generated code and build design systems that reason like humans.
Our previous piece identified the core problem: AI-generated UI feels artificial because it lacks intentional reasoning baked into every decision. This deep dive translates that insight into systematic, implementable techniques—a complete framework for embedding human judgment into production code.
Field Notes: What the Docs Don't Tell You About Embedding AI Into Production UI
Before we dive into the philosophy, I want to share a few things I learned the painful way. Since 2014 I've shipped a portfolio of wallpaper and ambient apps (50M+ cumulative downloads, AdMob revenue as the primary income channel), and I've used Antigravity and other AI code generators to iterate on UI. The decisions below aren't theoretical — each came from a measurable hit to revenue or retention.
1. "Nice-looking UI" isn't always compatible with AdMob revenue
Ask Antigravity for "a clean home screen" and it returns something that looks polished. But in production AB tests on my wallpaper app, the AI-generated template-style layouts dropped AdMob banner viewability and pulled eCPM down by about 23%. The boundary between ad and product UI is something the model has no signal about — you have to encode that judgment in tokens and types, or revenue bleeds quietly.
Concrete tweaks I now insist on:
Always insert at least a spacing.md (16px) gap between banner ads and product chrome — never let AI compress it
Keep the safe area between status bar and banner top at spacing.lg (24px) or more. AI output tends to crunch this to 8px
Never show a banner on the very first screen after splash — App Store reviewers rejected my apps twice for this. First launch starts ad-free, period
2. WCAG 2.5.5's 44px rule earns its keep even in a wallpaper app
I used to assume "if all the user does is browse wallpapers, button size can favor aesthetics." Then I raised the "Download" button from 36px to 44px in two apps and D1 retention jumped from 41.2% to 47.8%. Users with less stable touch (my own mother is in this cohort) were mis-tapping back to the home screen far more often than I'd expected.
Locking size: 'md' at 44px isn't accessibility compliance for its own sake — it's an economic decision visible in the funnel. Every time AI-generated UI shrinks a tap target, retention pays the bill.
3. oklch shipped fine in theory; on real devices it hid a landmine
oklch is beautiful on paper. But when I rolled it out to pre-2024 Android devices running my Capacitor-based hybrid app (WebView), a non-trivial slice of devices silently ignored color: oklch(...). No Crashlytics crash — just colorless UI — followed by a steady drizzle of one-star reviews.
In production I now guard with @supports (color: oklch(0 0 0)) and ship RGB hardcoded fallbacks for unsupported devices. If you're starting an oklch-first project, add a Tailwind plugin that emits dual values at build time.
4. Make Antigravity explain "why" — review time drops 3x
When I require Antigravity's main agent to leave an inline comment for every className concatenation and conditional branch ("why this value?"), per-file review time drops from 8–10 minutes to roughly 3. Typos and type errors I fix myself; design-judgment calls I approve or reject just by reading the comments.
The prompt suffix I now reuse on every UI generation task:
For every className concatenation and conditional branch in your output,
add an inline comment on the adjacent line explaining "why this value."
ARIA attributes must be applied conditionally based on the state value,
and the reasoning for each must be recorded the same way.
Without this instruction the model emits "code that runs" but no judgment, and the cost compounds: weeks later I'd find myself archaeologically reconstructing decisions I should never have lost.
5. The 8-step checklist I actually use when changing design tokens
Token edits ripple far. Skipping steps causes color regressions in shipped apps. The pipeline I now run on every token PR:
Propose the change via the Figma Tokens plugin → designer review
Export tokens.json and review the PR diff
Update tailwind.config.ts through a generation script (no hand-edits)
Run all Storybook stories through Chromatic for visual regression
Eyeball on iOS simulators (iPhone SE / iPhone 15 Pro Max) and an Android emulator (Pixel 3a)
Verify @supports fallback on a legacy WebView device
Compare side-by-side with live AdMob test ads for viewability
Roll out via AB test, minimum 5,000 sessions before full rollout
The one time I skipped two steps to ship faster, I got 17 one-star reviews on launch day citing invisible buttons. Tokens carry judgment — the rollout procedure has to carry just as much care.
The Philosophy of Design Tokens as Brand Judgment
Design tokens are more than numeric values. They are the bridge between brand philosophy and code implementation. Every token you define is a design judgment frozen in place.
Oklab and oklch: Perceptual Color in Code
Most projects define colors in RGB or HSL. But human color perception doesn't work in RGB space. Enter oklch (Oklab cylindrical): a color space designed to match how humans actually perceive color differences.
Perceptual uniformity: A change from L=0.50 to L=0.55 looks the same anywhere on the lightness scale. In RGB, this isn't true.
Scalability: To create a lighter variant, just increase lightness and slightly reduce saturation. No guesswork.
Brand precision: oklch is based on CIELAB, the standard in print and color science. Your designer's color intuitions translate directly.
Spacing Scales Grounded in Human Cognition
Fibonacci spacing isn't arbitrary aesthetics—it's grounded in how humans perceive visual rhythm.
export const spacing = { // Fibonacci: 1, 1, 2, 3, 5, 8, 13, 21, 34 ... // This ratio appears in nature and human proportions. // The eye finds these intervals naturally pleasing. 'xs': '0.25rem', // 4px - Tight (icon spacing, text decoration) 'sm': '0.5rem', // 8px - Snug (related elements: label + icon) 'md': '1rem', // 16px - Default (component internals) 'lg': '1.5rem', // 24px - Breathing room (section boundaries) 'xl': '2.5rem', // 40px - Major separation (feature sections) 'xxl': '4rem', // 64px - Page-level margins // Touch-specific 'touch-target': '2.75rem', // 44px minimum (WCAG 2.5.5)};// Documentation: embed the "why"const RATIONALE = { xs: 'Visual tightness—elements are directly related (icon + label)', sm: 'Related elements with clear hierarchy (button + sublabel)', md: 'Standard spacing between distinct but connected ideas', lg: 'Clear visual separation for meaningful boundaries', xl: 'Major sections deserve breathing room', xxl: 'Viewport to content relationship—ensure margins frame the page',};
Typography: Readability as Judgment
Font size doesn't exist in isolation. It's always paired with line-height—and that pairing is a design judgment about readability.
export const typography = { // Tuple: [font-size, { line-height, letter-spacing }] 'xs': ['0.75rem', { lineHeight: '1.5', letterSpacing: '0.01em' }], // 12px with tight leading (1.5): compact, caption-level text 'sm': ['0.875rem', { lineHeight: '1.5' }], // 14px with snug leading: supporting text 'base': ['1rem', { lineHeight: '1.6' }], // 16px with generous leading (1.6): body text. Legibility is paramount here. // Line-height of 1.6 means line-length should be 45-75 characters for optimal reading. 'lg': ['1.125rem', { lineHeight: '1.6' }], // 18px body: for accessibility-first designs, this is more inclusive 'h3': ['1.375rem', { lineHeight: '1.5', letterSpacing: '-0.01em' }], // 22px heading: tighter line-height (1.5) because larger text // naturally has more whitespace between lines. // Negative letter-spacing pulls letters closer—visual weight increases. 'h2': ['1.75rem', { lineHeight: '1.3', letterSpacing: '-0.01em' }], // 28px heading: even tighter line-height for visual impact 'h1': ['2.25rem', { lineHeight: '1.2', letterSpacing: '-0.02em' }], // 36px hero: maximum visual impact. Line-height of 1.2 creates a cohesive block.};// Judgment documentationconst TYPOGRAPHY_RATIONALE = { 'h1-line-height': ` Headings larger than 28px benefit from tighter line-height. Large text has inherent whitespace; tightening line-height creates visual cohesion and emphasizes the heading's role. `, 'body-line-height': ` Body text needs 1.5–1.6 line-height for accessibility. Research shows this improves reading speed and comprehension, especially for users with dyslexia or low vision. `, 'negative-letter-spacing': ` Large headings get -0.01em to -0.02em letter-spacing. This pulls letters closer, creating visual weight and making the heading feel more substantial. `,};
✦
Thank you for reading this far.
Continue Reading
What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.
WHAT YOU'LL LEARN
✦Real metrics from a 50M-download wallpaper app: how token-driven UI recovered AdMob eCPM by ~23% after AI-generated layouts dropped it
✦Why a 44px tap target lifted D1 retention from 41.2% to 47.8% — and how to bake this judgment into Button size tokens
✦Prompt template that cuts Antigravity code review time from 8–10 minutes to ~3 minutes, plus an 8-step design-token rollout checklist used in production
Secure payment via Stripe · Cancel anytime
✦
Unlock This Article
Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.
The power here: every visual and behavioral choice is constrained by type. The caller cannot accidentally create an invalid combination like variant="prim" or size="super-large".
Polymorphic Components: "What HTML element is this?"
Many buttons are actually links. Historically, we'd hack around this with prop-based logic. Better approach: let the caller decide what element the component renders as.
TypeScript ensures: when as="a", only <a> props (href, target, etc.) are allowed. When as="button", only <button> props are allowed. This is type-safe polymorphism.
Semantic Conditional Branching
Conditionals are the second-most common pattern in UI code (after jsx). Making them semantic—attaching "why" to each branch—is how you document design logic.
With Chromatic (visual regression testing), every design decision is captured and tracked. Changes to color, spacing, or state handling are immediately visible.
Design Decision Log
# Design Decisions## 2026-03-27: oklch Color Space Adoption**Judgment**: Use oklch instead of HSL/RGB**Rationale**:- Perceptually uniform (L=0.5 vs L=0.55 looks the same everywhere)- Scalability (increase lightness, decrease saturation → lighter variant)- Aligns with print-industry color science (CIELAB)**Alternatives Considered**:- HSL: color rotation causes unwanted saturation/brightness shifts ✗- Tailwind defaults: lacks brand character ✗**Impact**: All color definitions, Figma tokens, theme switching---## 2026-03-27: 44px Minimum Button Height**Judgment**: All interactive elements ≥44px**Rationale**:- WCAG 2.5.5 recommendation for accessible touch targets- Includes elderly users, low-dexterity users, touch-pen environments- Reduces mis-taps by 30% empirically**Exceptions**: None. Even inline buttons get 44px min in mobile context.**Rollout**: Phased. New components first, then legacy migration.
This archive becomes invaluable when onboarding teammates or justifying design changes months later.
Recommended Reading
For deeper dives into design systems and component architecture:
"Thinking with Type" — Mastering typography as a design system
"Component Driven Development" — From design to code components
Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.