Rams MCP · The full engine, now in your coding agent
onlook-dev on GitHub

onlook-dev/onlook

Reviewed against Rams quality heuristics: accessibility, color, typography, spacing, components, motion, UX, and craft.

30 files reviewed·July 9, 2026

Top fix

Fix white icon on green background to meet contrast standards

See the fix

Verdict

Solid architecture and choreography mask a pattern of one-line polish getting skipped: contrast, motion guards, live regions all left undone. The biggest risk is silent failure states, a network hiccup and a real no-subscription case look identical, quietly misrouting paying users.

Files Rams reviewed

apps/web/client/src/app/about/layout.tsx

apps/web/client/src/app/auth/redirect/page.tsx

apps/web/client/src/app/callback/github/install/page.tsx

apps/web/client/src/app/faq/layout.tsx

apps/web/client/src/app/features/ai-for-frontend/layout.tsx

apps/web/client/src/app/features/ai/layout.tsx

apps/web/client/src/app/features/ai/page.tsx

apps/web/client/src/app/features/builder/layout.tsx

apps/web/client/src/app/features/builder/page.tsx

apps/web/client/src/app/features/layout.tsx

apps/web/client/src/app/features/page.tsx

apps/web/client/src/app/features/prototype/layout.tsx

apps/web/client/src/app/layout.tsx

apps/web/client/src/app/login/page.tsx

apps/web/client/src/app/page.tsx

apps/web/client/src/app/pricing/page.tsx

apps/web/client/src/app/project/[id]/layout.tsx

apps/web/client/src/app/project/[id]/page.tsx

apps/web/client/src/app/projects/_components/select/masonry-layout.tsx

apps/web/client/src/app/projects/import/github/page.tsx

apps/web/client/src/app/projects/import/local/page.tsx

apps/web/client/src/app/projects/import/page.tsx

apps/web/client/src/app/projects/layout.tsx

apps/web/client/src/app/see-a-demo/page.tsx

apps/web/client/src/app/site-map/layout.tsx

apps/web/client/src/app/site-map/page.tsx

apps/web/client/src/app/workflows/claude-code/layout.tsx

apps/web/client/src/app/workflows/layout.tsx

apps/web/client/src/app/workflows/page.tsx

apps/web/client/src/app/workflows/vibe-coding/layout.tsx

96/100

Color

2 serious
Color·apps/web/client/src/app/layout.tsx:63Serious

Forced dark theme leaves native browser chrome light

The app forces dark theme via `forcedTheme="dark"` on `ThemeProvider`, but the `<html>` element sets no `color-scheme` value and there is no `<meta name="color-scheme">` tag.

Why it matters

Scrollbars, form control defaults, and the browser's own UI chrome render in light mode against the app's dark surfaces, producing a visible mismatch at every native control edge.

Fix

Set color-scheme to dark on the root html element to match the forced theme.

<html lang={locale} className={inter.variable} suppressHydrationWarning>
<html lang={locale} className={inter.variable} style={{ colorScheme: 'dark' }} suppressHydrationWarning>
Color·apps/web/client/src/app/callback/github/install/page.tsx:176Serious

White success icon on bg-green-500 fails non-text contrast

The success state's `CheckCircled` icon renders `text-white` inside a `bg-green-500` circle. White on green-500 (#22c55e) computes to 2.28:1.

Why it matters

WCAG 1.4.11 requires 3:1 contrast for meaningful graphical objects; at 2.28:1 the checkmark is hard to distinguish from its own background for low-vision users, undermining the one visual cue that confirms success.

Fix

Darken the status background so the fixed white icon clears the 3:1 non-text contrast minimum.

indicatorColor="bg-green-500"
indicatorColor="bg-green-600"
96/100

UX

2 serious
UX·apps/web/client/src/app/page.tsx:20Serious

Hero locked to h-screen crops content behind mobile browser chrome

The same hero wrapper sets `h-screen` (100vh) with `flex items-center justify-center`. On mobile Safari and Chrome, 100vh is calculated against the maximum viewport, not the visible area once the address bar is showing, so content can render taller than what's actually visible.

Why it matters

On first load, mobile visitors can see the hero's CTA or heading pushed below the fold or clipped by browser chrome, which is the worst place for it to happen given this is the page's entry point.

Fix

Use the dynamic viewport unit (h-dvh) so hero height tracks the actual visible viewport on mobile.

<div className="w-screen h-screen flex items-center justify-center" id="hero">
<div className="w-full h-dvh flex items-center justify-center" id="hero">
UX·apps/web/client/src/app/callback/github/install/page.tsx:175Serious

Success screen has no manual way out if window.close() is blocked

The success `StateContainer` passes no `actions`, relying solely on `setTimeout(() => window.close(), 3000)`. Browsers frequently block scripted `window.close()` on tabs not opened purely by script (e.g. after a redirect flow).

Why it matters

If the auto-close is blocked, the user is left staring at "All set!" with no button, no link, and no indication anything else needs to happen, turning a successful flow into a dead end.

Fix

Give every reachable state a designed action, including a manual fallback for auto-dismiss behavior that browsers can silently block.

{state === 'success' && (
    <StateContainer
        indicatorColor="bg-green-500"
        indicatorIcon={Icons.CheckCircled}
        iconAnimated={true}
        title="All set!"
        description="Your GitHub account is now connected"
    />
)}
{state === 'success' && (
    <StateContainer
        indicatorColor="bg-green-500"
        indicatorIcon={Icons.CheckCircled}
        iconAnimated={true}
        title="All set!"
        description="Your GitHub account is now connected"
        actions={
            <Button variant="outline" onClick={() => window.close()} className="w-full">
                Close this tab
            </Button>
        }
    />
)}

Want this on your repo?

Rams reviews your next PR automatically and posts inline fix suggestions.

Review my public repo for free
98/100

Accessibility

1 serious
Accessibility·apps/web/client/src/app/auth/redirect/page.tsx:40Serious

"Redirecting..." status has no live region for screen reader users

The heading "Redirecting..." and paragraph "Please wait while we redirect you back." render as plain `<h1>`/`<p>` with no `role="status"` or `aria-live`, while two queries and a localforage read run in the background before navigation happens.

Why it matters

If the redirect takes a couple seconds (two network queries plus storage access), screen reader users get no indication anything is happening and no confirmation when it resolves, since nothing announces the wait state.

Fix

Wrap the transitional status text in a container with role='status' so assistive tech announces the wait state as it renders.

<div className="text-center">
    <h1 className="text-2xl font-semibold mb-4">Redirecting...</h1>
    <p className="text-foreground-secondary">Please wait while we redirect you back.</p>
</div>
<div className="text-center" role="status">
    <h1 className="text-2xl font-semibold mb-4">Redirecting...</h1>
    <p className="text-foreground-secondary">Please wait while we redirect you back.</p>
</div>
98/100

Components

1 serious
Design System·apps/web/client/src/app/callback/github/install/page.tsx:149Serious

Hardcoded grays on Card override the component's own theming

`Card` is styled with `className="bg-gray-900 border-gray-800 shadow-2xl"` while the rest of the page uses semantic tokens (`text-foreground-primary`, `text-foreground-secondary`). The outer wrapper also uses `bg-gray-800` boxes and `border-gray-800`.

Why it matters

Mixing raw Tailwind gray classes with semantic foreground tokens means the Card no longer follows the design system's theme source; a future dark/light theme change updates the tokens everywhere except this page, and maintenance cost grows every time this pattern is copied.

Fix

Style Card and its surrounding chrome through the same semantic tokens already used for text, not raw Tailwind gray values.

<Card className="bg-gray-900 border-gray-800 shadow-2xl">
<Card className="bg-background-primary border-border shadow-2xl">

Typography

No issues found

Spacing

No issues found

Motion

No issues found

Craft

No issues found

Working well

  • The section order (Hero, ResponsiveMockupSection, WhatCanOnlookDoSection, ContributorSection, TestimonialsSection, FAQSection, CTASection) sequences the page correctly: product demonstration and features come before social proof, and the CTA lands only after proof has been established. That's the right shape for a conversion narrative, claim then evidence then ask.
  • The header logo bridge (Onlook logo, dots, GitHub logo) sits outside the `AnimatePresence` boundary while only `key={state}` on the inner motion.div re-animates. This is the correct pattern: persistent chrome never re-triggers its entrance animation when the card content below it swaps between loading, success, and error.
  • Keeping AuthModal, NonProjectSettingsModal, and SubscriptionModal as sibling components mounted once at the page root, rather than inlined inside individual sections, keeps page.tsx readable as pure composition and avoids duplicating modal instances across the tree.
  • Using `disableTransitionOnChange` on `ThemeProvider` is the right call: it suppresses the color transition that would otherwise animate across every element the instant the theme resolves on load, which is exactly the flash MOTION-017 warns about.

Score your own repo with Rams.

Free on public repos. Rams reviews every pull request for accessibility, color, type, spacing, components, motion, UX, and craft, and posts inline fixes.