Rams MCP · The full engine, now in your coding agent
weaverse on GitHub

weaverse/pilot

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

30 files reviewed·July 31, 2026

View on GitHub

Elevated

Design risk in this codebase.

9issues
Critical & Serious · top 6 shown below

Top fix

Add an accessible label to the unlabeled search trigger button

See the fix

Verdict

Three unlabeled controls and a hover-only quick-shop pattern tell the same story: visual polish outpaced interaction accessibility. Fix the accessible-name gaps first, they're small and mechanical, then tackle hover-dependency systematically before it spreads further.

Files Rams reviewed

app/routes/pages/regular-page.tsx

app/components/layout/footer/index.tsx

app/components/layout/predictive-search/index.tsx

app/components/product-card/index.tsx

app/components/product-media/index.tsx

app/components/background-image.tsx

app/components/button.tsx

app/components/cart/cart-best-sellers.tsx

app/components/cart/cart-drawer.tsx

app/components/cart/cart-line-item.tsx

app/components/cart/cart-line-qty-adjust.tsx

app/components/cart/cart-main.tsx

app/components/cart/cart-summary-actions.tsx

app/components/cart/cart-summary.tsx

app/components/heading.tsx

app/components/image.tsx

app/components/layout/country-selector/footer-country-selector.tsx

app/components/layout/country-selector/header-country-selector.tsx

app/components/layout/footer/newsletter-form.tsx

app/components/layout/footer/payment-methods.tsx

app/components/layout/footer/social-links.tsx

app/components/layout/header.tsx

app/components/layout/logo.tsx

app/components/layout/menu/desktop-menu.tsx

app/components/layout/menu/dropdown-menu.tsx

app/components/layout/menu/footer-menu.tsx

app/components/layout/menu/mobile-menu.tsx

app/components/layout/predictive-search/popular-keywords.tsx

app/components/layout/predictive-search/predictive-search-result.tsx

app/components/layout/predictive-search/search-form.tsx

92/100

Accessibility

2 critical1 serious
AccessibilityCritical

app/components/layout/predictive-search/index.tsx:29

Search trigger button announces as unlabeled to screen readers

The dialog trigger at line 30, `<button type="button"><Icon name="magnifying-glass" className="h-5 w-5" /></button>`, has no aria-label, no visible text, and no title.

Why it matters

This is the primary entry point into site search from the header, and a screen reader user gets no indication of what the control does before activating it.

Fix

Add an aria-label to icon-only trigger buttons that names the action.

<button type="button">
  <Icon name="magnifying-glass" className="h-5 w-5" />
</button>
<button type="button" aria-label="Search">
  <Icon name="magnifying-glass" className="h-5 w-5" />
</button>
AccessibilityCritical

app/components/layout/footer/index.tsx:93

Footer logo image ships with no alt text for screen readers

The footer logo `<Image>` (app/components/layout/footer/index.tsx line 93) renders `data={footerLogoData}` with no `alt` prop at all. Every other branch of this component has a text fallback (the `shopName` heading), but the image path itself carries no accessible name.

Why it matters

Screen reader users hear nothing when reaching the footer brand mark, so they lose the one visual anchor that confirms which site they're on.

Fix

Pass alt text derived from the shop name (or the image's own altText field) into the Image component.

<Image
  data={footerLogoData}
  sizes="auto"
  width={500}
  className="h-full w-full object-contain object-left"
/>
<Image
  data={footerLogoData}
  alt={footerLogoData.altText || shopName}
  sizes="auto"
  width={500}
  className="h-full w-full object-contain object-left"
/>
AccessibilitySerious

app/components/background-image.tsx:46

Decorative section background gets a descriptive alt instead of empty

When `backgroundImage` is a plain string, line 46 builds `{ url: backgroundImage, altText: "Section background" }`. This background is purely decorative (it sits behind foreground content in every section that uses it), yet it gets a non-empty, generic alt string.

Why it matters

A screen reader announces "Section background, image" on every section that uses this component across the site, adding meaningless noise the user has to sit through before reaching real content.

Fix

Decorative images get an empty alt string so assistive tech skips them, not a generic description.

? { url: backgroundImage, altText: "Section background" }
? { url: backgroundImage, altText: "" }
98/100

Components

1 serious
ComponentsSerious

app/components/layout/footer/index.tsx:92

Footer logo width set with inline style instead of a sizing token

The logo wrapper at line 92, `<div className="relative" style={{ width: footerLogoWidth }}>`, sizes the mark with an inline style while the surrounding footer layout (`footerVariants({ width: footerWidth })`) uses a proper class-based variant system.

Why it matters

Mixing an inline pixel value with a token-driven layout means the logo's size can't be constrained by the same scale that governs the rest of the footer, and future theme edits have to special-case this one element.

Fix

Route footerLogoWidth through a CVA variant or a clamped Tailwind width class instead of an inline style.

<div className="relative" style={{ width: footerLogoWidth }}>
<div className={cn("relative", logoWidthVariants({ width: footerLogoWidth }))}>

Get this score on every PR.

Rams reviews each pull request on your repo and posts inline one-click fixes — about a minute per review.

Install Rams free
98/100

Motion

1 serious
MotionSerious

app/components/layout/predictive-search/index.tsx:37

Search dialog enter/exit animations ignore reduced-motion preference

The `Dialog.Overlay` and `Dialog.Content` at lines 37-48 run `animate-[fade-in_150ms_ease-out]`, `animate-[fade-out_150ms_ease-in]`, `animate-[enter-from-top_200ms_ease-out]`, and `animate-[exit-to-top_200ms_ease-in]` unconditionally on every open/close, with no `prefers-reduced-motion` guard anywhere in the file.

Why it matters

Users with vestibular disorders who set reduced-motion at the OS level still get the full slide-and-fade treatment every time they open search, which is the exact case that preference exists to prevent.

Fix

Wrap animation utilities in a motion-safe: variant or gate them behind a reduced-motion media query.

"fixed inset-0 z-10 bg-black/50",
"data-[state=open]:animate-[fade-in_150ms_ease-out]",
"data-[state=closed]:animate-[fade-out_150ms_ease-in]",
"fixed inset-0 z-10 bg-black/50",
"motion-safe:data-[state=open]:animate-[fade-in_150ms_ease-out]",
"motion-safe:data-[state=closed]:animate-[fade-out_150ms_ease-in]",
98/100

UX

1 serious
UXSerious

app/components/product-card/index.tsx:199

Quick shop trigger only reveals on hover, locking out keyboard and touch

`QuickShopTrigger` is rendered with `showOnHover={pcardShowQuickShopOnHover}` on the product card, and nothing in this file shows a focus-within or touch fallback path for revealing it.

Why it matters

Keyboard users tabbing through the grid and touch users on mobile never trigger a `:hover` state, so the quick shop action is unreachable for both groups even though mouse users see it plainly.

Fix

Reveal the quick shop trigger on focus-within as well as hover, or always render it visibly on touch viewports.

<QuickShopTrigger
  productHandle={product.handle}
  showOnHover={pcardShowQuickShopOnHover}
  buttonType={pcardQuickShopButtonType}
  buttonText={pcardQuickShopButtonText}
  panelType={pcardQuickShopPanelType}
/>
<QuickShopTrigger
  productHandle={product.handle}
  showOnHover={pcardShowQuickShopOnHover}
  className="group-focus-within:opacity-100"
  buttonType={pcardQuickShopButtonType}
  buttonText={pcardQuickShopButtonText}
  panelType={pcardQuickShopPanelType}
/>

Typography

No issues found

Color

No issues found

Spacing

No issues found

Craft

No issues found

Working well

  • Making the BackgroundImage loading prop required and documenting the 13.6s mobile LCP measurement right next to it is a strong pattern: the performance tradeoff is stated in the code, not left for someone to rediscover later.
  • The footer's footerVariants({ width: footerWidth }) maps a theme setting straight to layout classes instead of branching inline styles, which keeps the layout logic testable and consistent across footer configurations.
  • The product card falls back to IMAGES_PLACEHOLDERS.image with a descriptive alt when a product has no image, which avoids shipping a broken or unlabeled image state to shoppers.
  • The predictive search input's Enter-key handler and the clear button both re-invoke fetchResults, so the visible input value and the result list never drift out of sync.

Scored July 31, 2026 with Rams Engine v0.0.3 · Engine changelog

This page is an automated design review of weaverse/pilot’s UI code: 30 files read against 291 versioned rules covering accessibility, color, typography, spacing, components, UX, motion, and craft. The score is out of 100; any confirmed critical issue caps it at 59.

More design scores

Score your own repo.

Free on public repos, no account. The same engine that scored this page reads your UI code and mints a score page like this one.

Public repos only. The full engine reviews the UI code and mints a public score page — we email you the link too. Already-scored repos open instantly.

Or get a design review on every pull requestInstall Rams