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

block/buzz

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

30 files reviewed·July 22, 2026

View on GitHub

Elevated

Design risk in this codebase.

10issues
Critical, Serious & Moderate · top 6 shown below

Top fix

Add reduced-motion guard to the slide-in overlay animation

See the fix

Verdict

Craft shows in the pixel-level chrome details, but motion and state feedback were left unfinished. A reduced-motion-blind slide animation is the single biggest risk to ship as-is.

Files Rams reviewed

desktop/src/app/routes/index.tsx

desktop/src/app/AppShellContext.tsx

desktop/src/app/AppShellOverlays.tsx

desktop/src/app/AppTopChrome.tsx

desktop/src/app/RelayConnectionOverlay.tsx

desktop/src/app/routes/ChannelRouteScreen.tsx

desktop/src/app/routes/agents.tsx

desktop/src/app/routes/channels.$channelId.posts.$postId.tsx

desktop/src/app/routes/channels.$channelId.tsx

desktop/src/app/routes/projects.$projectId.tsx

desktop/src/app/routes/pulse.tsx

desktop/src/features/huddle/components/AddAgentDialog.tsx

desktop/src/features/huddle/components/HuddleAttachment.tsx

desktop/src/features/huddle/components/HuddleIndicator.tsx

desktop/src/features/huddle/components/ParticipantList.tsx

web/src/app/routes/index.tsx

desktop/src/app/BuzzThemeSurfaces.tsx

desktop/src/app/ThemeGrainientBackground.tsx

desktop/src/app/router.tsx

desktop/src/app/routes/WorkflowsRouteScreen.tsx

desktop/src/app/routes/messages.new.tsx

desktop/src/app/routes/projects.tsx

desktop/src/app/routes/reminders.tsx

desktop/src/app/routes/root.tsx

desktop/src/app/routes/settings.tsx

desktop/src/app/routes/workflows.$workflowId.tsx

desktop/src/app/routes/workflows.tsx

desktop/src/features/forum/ui/ForumComposerCompactLayout.tsx

web/src/app/App.tsx

web/src/app/router.tsx

95/100

Motion

1 critical1 serious
MotionCritical

desktop/src/app/RelayConnectionOverlay.tsx:59

Slide-in overlay animates 20px regardless of reduced-motion setting

Both motion.div overlays ("relay-connection-overlay" and "relay-error-overlay") animate `y: -20 → 0` on enter and `y: 0 → 20` on exit with no `useReducedMotion` check or `MotionConfig reducedMotion="user"` anywhere in the file.

Why it matters

Vestibular-sensitive users get the full slide motion every time the relay disconnects or reconnects, regardless of their OS setting: this is exactly the kind of persistent, state-driven motion prefers-reduced-motion exists to suppress.

Fix

Read useReducedMotion() from the motion library and collapse the y-translate to 0 when it is true, keeping only the opacity fade.

<motion.div
  animate={{ opacity: 1, y: 0 }}
  className={cn(
    "pointer-events-none fixed z-50 w-[284px]",
    hasCommunityRail ? "left-[60px]" : "left-3",
    isHuddleDrawerOpen
      ? "bottom-[calc(var(--buzz-huddle-drawer-height,0px)+12px)]"
      : "bottom-3",
  )}
  exit={{ opacity: 0, y: 20 }}
  initial={{ opacity: 0, y: -20 }}
  key="relay-connection-overlay"
  transition={{ duration: 0.25, ease: [0.22, 1, 0.36, 1] }}
>
<motion.div
  animate={{ opacity: 1, y: 0 }}
  className={cn(
    "pointer-events-none fixed z-50 w-[284px]",
    hasCommunityRail ? "left-[60px]" : "left-3",
    isHuddleDrawerOpen
      ? "bottom-[calc(var(--buzz-huddle-drawer-height,0px)+12px)]"
      : "bottom-3",
  )}
  exit={{ opacity: 0, y: shouldReduceMotion ? 0 : 20 }}
  initial={{ opacity: 0, y: shouldReduceMotion ? 0 : -20 }}
  key="relay-connection-overlay"
  transition={{ duration: 0.25, ease: [0.22, 1, 0.36, 1] }}
>
MotionSerious

desktop/src/app/AppShellOverlays.tsx:53

Deferred dialog mount forces a null render with no reduced-motion consideration

The effect always sets `visibleBrowseDialogType` to `null` on every `browseDialogType` change, then reopens on the next frame via `openModalNextFrame`. This unmounts and remounts the dialog's open state on every browse-type switch (e.g. stream to forum), replaying its entrance transition each time.

Why it matters

Users who switch between browse types back-to-back see the dialog flash closed and re-animate open every time, and there's no `prefers-reduced-motion` branch anywhere in this file's control flow to suppress that replay for motion-sensitive users.

Fix

Only defer-remount when transitioning from closed to open, not when switching between two already-open types, and respect prefers-reduced-motion in the underlying dialog's transition.

setVisibleBrowseDialogType(null);
openModalNextFrame(() => {
  setVisibleBrowseDialogType(browseDialogType);
});
if (visibleBrowseDialogType !== null) {
  // already open, just swap the filter without a remount
  setVisibleBrowseDialogType(browseDialogType);
  return;
}
setVisibleBrowseDialogType(null);
openModalNextFrame(() => {
  setVisibleBrowseDialogType(browseDialogType);
});
96/100

UX

2 serious
UXSerious

desktop/src/app/RelayConnectionOverlay.tsx:99

Error fallback shows the failure with no way to act on it

The `relay-error-overlay` div renders `role="alert"` with an `AlertCircle` icon and `{errorMessage}` text only: no retry, dismiss, or reopen-sidebar affordance in the markup.

Why it matters

A user who sees an auth-rejection error while the sidebar is collapsed has no next step from this overlay; it sits there indefinitely with nothing to click, which is worse than an error that at least tells you what to do.

Fix

Give the error fallback a visible action (dismiss or reopen sidebar) instead of stopping at the message.

<div
  className="pointer-events-auto flex items-center gap-2 rounded-xl bg-background px-3 py-2.5 text-sm text-destructive shadow-md"
  data-testid="relay-error-overlay"
  role="alert"
>
  <AlertCircle aria-hidden="true" className="h-4 w-4 shrink-0" />
  <span className="flex-1">{errorMessage}</span>
</div>
<div
  className="pointer-events-auto flex items-center gap-2 rounded-xl bg-background px-3 py-2.5 text-sm text-destructive shadow-md"
  data-testid="relay-error-overlay"
  role="alert"
>
  <AlertCircle aria-hidden="true" className="h-4 w-4 shrink-0" />
  <span className="flex-1">{errorMessage}</span>
  <button
    aria-label="Dismiss error"
    className="pointer-events-auto shrink-0 text-destructive/70 hover:text-destructive"
    onClick={card.onDismissRelayConnectionCard}
    type="button"
  >
    ×
  </button>
</div>
UXSerious

desktop/src/app/AppTopChrome.tsx:27

Global wheel-blocking on the top chrome swallows scroll over the nav buttons themselves

`preventTopChromeWheel` calls `event.preventDefault()` unconditionally and is attached to the whole `topChromeRef` div with `capture: true`, which contains the back/forward/sidebar buttons.

Why it matters

Any wheel or trackpad gesture that crosses the back/forward buttons is discarded outright, including two-finger swipe-back gestures many users expect from a bar whose entire job is back/forward navigation.

Fix

Skip preventDefault when the wheel event originates over an interactive control so navigation gestures near the buttons keep working.

function preventTopChromeWheel(event: WheelEvent) {
  event.preventDefault();
}
function preventTopChromeWheel(event: WheelEvent) {
  if (event.target instanceof Element && event.target.closest("button")) {
    return;
  }
  event.preventDefault();
}

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

Accessibility

1 serious
AccessibilitySerious

desktop/src/app/AppTopChrome.tsx:38

Sidebar toggle swaps icons but never announces the resulting state

`TopChromeSidebarTrigger` renders `PanelLeftClose` or `PanelLeftOpen` depending on `sidebar?.open`, but the button carries a static `aria-label="Toggle Sidebar"` with no `aria-expanded`. The visual icon change is the only signal of open/closed state.

Why it matters

Screen reader users hear the same 'Toggle Sidebar, button' before and after activating it, with no way to confirm whether the sidebar is now open or closed without navigating elsewhere to check. That's a real state-value gap under WCAG 4.1.2 (name, role, value).

Fix

Expose the current state on the control itself with aria-expanded tied to the same boolean driving the icon swap.

<Button
  aria-label="Toggle Sidebar"
  className={TOP_CHROME_ICON_BUTTON_CLASS}
  data-sidebar="trigger"
  disabled={!sidebar}
  onClick={() => {
    sidebar?.toggleSidebar();
  }}
  size="icon"
  type="button"
  variant="ghost"
>
<Button
  aria-label="Toggle Sidebar"
  aria-expanded={sidebar?.open ?? false}
  className={TOP_CHROME_ICON_BUTTON_CLASS}
  data-sidebar="trigger"
  disabled={!sidebar}
  onClick={() => {
    sidebar?.toggleSidebar();
  }}
  size="icon"
  type="button"
  variant="ghost"
>
98/100

Spacing

1 serious
SpacingSerious

desktop/src/app/AppTopChrome.tsx:116

Three nav buttons sit 2px apart, compounding their already-small hit areas

The sidebar trigger (28x28px), "Go back" (24x28px), and "Go forward" (24x28px) buttons sit in a row with `gap-0.5` (2px). All three are already below the 44px comfortable-target size, and they're placed close enough that a slightly off click lands on the wrong control.

Why it matters

Tight spacing between small interactive targets increases mis-click risk for anyone with reduced motor precision, and it compounds rather than offsets the small button size chosen for traffic-light clearance.

Fix

Widen the gap between adjacent small icon buttons so a miss doesn't land on the neighboring control.

<div className={cn("flex items-center gap-0.5", navRowAlignmentClass)}>
<div className={cn("flex items-center gap-1.5", navRowAlignmentClass)}>

Typography

No issues found

Color

No issues found

Components

No issues found

Craft

No issues found

Working well

  • Splitting `pointer-events-none` on the fixed outer wrapper from `pointer-events-auto` on the inner card is the right pattern for a floating overlay: it keeps the dead space around the card from swallowing clicks meant for content underneath, while the card itself stays interactive.
  • The error fallback pairs `role="alert"` with `aria-hidden="true"` on the `AlertCircle` icon: the icon is announced as decoration while the alert role itself handles the screen-reader interruption, which is exactly how icon-plus-message error states should be built.
  • The comments above TOP_CHROME_ICON_BUTTON_CLASS and macChrome explain exactly why fixed px is used instead of rem (traffic lights don't scale with Cmd +/- zoom). That's the right way to break a system rule: name the constraint, not just override it silently.
  • Gating `ChannelManagementSheet` on both `isChannelManagementOpen && activeChannel !== null` avoids a real crash class: rendering a management sheet for a null channel. Checking the data dependency, not just the open flag, is the correct guard here.

Scored July 22, 2026 with Rams Engine v0.0.2 · Engine changelog

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 this review on every PR.