weaverse/pilot
Reviewed against Rams quality heuristics: accessibility, color, typography, spacing, components, motion, UX, and craft.
30 files reviewed·July 31, 2026
Elevated
Design risk in this codebase.
More findings
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
Accessibility
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>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"
/>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: "" }Components
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 freeMotion
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]",UX
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
Color
Spacing
Craft
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.