Product Design Audit · Real-estate underwriting app
MAPLE was measured against how the best modern software actually looks and behaves — and against the specific tells that make an app read as generic, template, AI-generated "slop." The foundation is genuinely well-built. Three global cosmetic decisions and a handful of craft gaps are what hold it back.
MAPLE scores 11 of 22 on a premium-vs-slop rubric — the "competent but generic" band. That undersells the foundation and oversells the flaws, which is the point: the bones are premium-adjacent (a custom blue brand instead of the AI-default purple, a sophisticated hand-built hover system, tight considered corner radii, honest handling of low-confidence valuations, near-total real iconography). What caps it at "generic" is almost entirely subtractive and cheap to fix: three decorative decisions applied globally — glassmorphism on every card, purple gradient blobs on every page, and a purple pulsing glow on the AI button — plus number-alignment, keyboard-focus, and motion gaps.
Translation for a first impression: strip the purple, tighten the tables, and this jumps a full tier without a redesign. It is safe to put in front of a broker today; the fixes below are polish, not rescue.
The AI assistant reads as a thoughtful feature wearing a generic-chatbot costume. The substance is crafted and product-specific; the paint is the slop.
01 — Scorecard
A binary rubric synthesized from Nielsen Norman Group, Baymard, and the Stripe / Linear / Vercel / Raycast design-craft literature. Pass full marks · Partial right idea, uneven execution · Fail a recognized slop tell is present. Items marked ⚠ are critical — a miss there caps the whole grade regardless of total.
02 — The standard being applied
Before judging MAPLE, we pinned down the bar. "AI slop" was Macquarie Dictionary's 2025 word of the year; designers claim they spot it in about three seconds. Here is what the research says separates crafted software from the template look.
03 — The audit
Every item below is anchored to a real file and line in the codebase. Grouped by action so the build order is obvious.
A layered ::after-overlay interaction layer driven by design tokens, wired cleanly into the button and badge primitives. Genuinely sophisticated — most shadcn clones never build this. It is the app's real design signature.
Primary is a professional blue (hsl(210 85% 45%)) on every logo lockup and CTA — the deliberate choice that keeps the app off the AI-default palette. This is the single biggest thing protecting MAPLE's first impression.
When comps are missing, the app refuses to render MAO / score and shows an amber explainer instead of a misleading number. This is exactly the judgment a valuation tool must have — never fabricate precision. Do not "simplify" it away.
A real content-shaped loading skeleton (not a spinner), and the one row primitive that gets numbers right: label left, figure right-aligned in font-mono tabular-nums. This row is the template every other numeric row should copy.
Risk / tax metrics expose their exact formula and substituted numbers on hover — load-bearing information, not decoration; the strongest crafted feature in the app. The AI chat sanitizes with DOMPurify + an explicit tag allowlist, escaping before markdown conversion. Correct and secure.
Four explicit states — loading / success / error / expired — each with its own icon, color, and recovery action. Most apps ship one generic screen; this is premium-grade. The auth flows overall (validation, resend cooldown, privacy-safe reset copy) are already at a good bar.
The mesh-background blobs are literally violet (hue 260° / 280°) — the exact purple-gradient-blob signature — and they clash with the blue brand. Used on landing, login, signup, onboarding, and more.
Fix → drop mesh-background for a flat bg-background (Linear/Stripe auth pages are flat), or retune all three blob hues into the brand's blue (205–225°) at ≤0.08 opacity. Two pages already use a flat background — make that the standard.
The base Card hard-codes the glass class, so every card gets a 16px backdrop-blur. That is the glassmorphism tell applied globally — and a real performance cost with dozens of blur layers on a data-dense page.
Fix → remove glass from the base Card; make it an opt-in variant="glass" used only on overlays / sheets where a blur behind actually reads.
The assistant is a wall of from-purple-600 to-indigo-600 gradients, purple avatars, and purple hover text — while the entire rest of the app is blue. It reads as a bolted-on ChatGPT clone with its own identity rather than part of MAPLE.
Fix → recolor every gradient to bg-primary / text-primary / bg-primary/10. Same code, and the assistant suddenly reads as MAPLE's own strategist.
The fetched-comps table renders price, sqft, beds/baths, DOM, and distance as default left-aligned, non-tabular text — visibly worse than the better comps table directly below it, and this is the first table users see after generating comps.
Fix → add text-right font-mono tabular-nums to numeric cells, text-right to the headers, and render price through the shared formatCurrency.
🚗 and 📍 emoji stand in for icons in the comps panel; the Sparkles glyph is sprinkled across six screens as a generic AI signifier — both classic slop tells in a financial UI.
Fix → swap the emoji for Lucide <Car> / <MapPin> (already imported); keep Sparkles on at most one primary AI entry point and use domain icons elsewhere.
Five copies of formatCurrency, two byte-identical score-color helpers, and three hand-rolled step indicators with different sizes. On a tool whose entire value is number consistency, this is a real divergence risk.
Fix → move formatters into the existing lib/numberFormat; extract one shared <Stepper>.
"Institutional grade", "the same tools institutional shops use", "10X your underwriting speed", and a stale "launching February 2026" — hype claims plus spec numbers relabeled as "social proof."
Fix → soften to defensible language ("institutional-style comps scoring", "analyze deals in minutes"), drive the date from config, and relabel the spec tiles honestly — never dress product specs as adoption.
An infinite @keyframes ai-glow in literal rgba(147, 51, 234) — the exact violet the research calls out — pulsing forever on the floating AI button and the voice button. The textbook "AI thing must glow purple forever" tell.
Fix → delete the keyframes, the utility class, and both usages. A static shadow-md is enough.
The Comps tab renders the same comp set twice — the poorly-formatted inline table (flagged above) and, ~40 lines below, the richer panel with $/sqft, score, condition, and selection. Users scroll past two tables of the same data. Highest-value single cut: it removes redundancy and the worst-formatted table at once.
Fix → delete the inline table (and its mobile twin); keep the richer panel.
Two unused onboarding step components, an unused duplicate gauge, undefined animation-delay-150/300 classes (which is why the "staggered" pulse dots actually blink in unison), and a raw JSON tab shown to end users as a first-class view.
Fix → delete the unused files and no-op classes; move the JSON dump behind an admin flag.
New users hit a dashed-border "Video walkthrough / Coming soon" placeholder on the very first screen — a dead deliverable stub in the highest-visibility spot in the app.
Fix → remove the placeholder until a real video exists; keep the component for when a URL is supplied.
Zero prefers-reduced-motion rules anywhere, yet the app runs infinite glow, bouncing typing dots, and pulsing loops. A WCAG 2.2 (2.3.3) gap and a polish gap.
Fix → add one global @media (prefers-reduced-motion: reduce) block that neutralizes the looping animations.
The valuation confidence is computed but never shown — the "Choose ARV" card displays only a source badge. For a tool people cite to clients, decision-critical numbers should carry a Low / Med / High confidence badge and an "as of" timestamp.
Fix → badge confidence next to the anchor number; add a comp-set freshness date.
Neither comps table lets you sort by $/sqft, distance, DOM, or score — the four fields an underwriter actually sorts on — and scrolled table headers disappear.
Fix → clickable sort headers with an indicator; sticky top-0 on the header row.
Icon-only tooltip triggers are bare SVGs with no tabindex — mouse-only. Many custom buttons lack a visible focus-visible ring. And if an AI message fails to send, the user gets silence with no retry.
Fix → wrap icon triggers in a focusable <button aria-label>; add focus-visible:ring-2 ring-primary globally; add an inline error/retry row to the chat.
KPI cards show a static number and a static icon; the monthly-trend data is already fetched but unused — a sparkline or "+N this month" delta is what separates an analytics dashboard from a counter. And only one component uses tabular-nums, so big figures jitter when they update.
Fix → add an inline sparkline / delta to the KPI cards; add tabular-nums to every mono figure class.
04 — Sequenced
Ordered by impact-per-hour. The whole of P0 is subtractive — deleting or recoloring, no new design work — and moves the grade the most.
bg-background, or retune blobs to blue at low opacity.formatCurrency copies and three steppers into shared code.prefers-reduced-motion block + visible focus-visible rings.