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

triggerdotdev/trigger.dev

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

30 files reviewed·August 1, 2026

View on GitHub

Low

Design risk in this codebase.

7issues
Serious & Moderate · top 6 shown below

Top fix

Extract sidebar width into a single shared token, not three copies

See the fix

Verdict

Magic numbers are doing the job tokens should: 260px sidebars, arbitrary grid splits, and a stray hex color all repeat intent without sharing a source. Fix the token layer once and most of these serious issues collapse together, but the login testimonial flash is the one users will actually notice first.

Files Rams reviewed

apps/webapp/app/components/LoginPageLayout.tsx

apps/webapp/app/components/layout/AppLayout.tsx

apps/webapp/app/components/layout/MetricsLayout.tsx

apps/webapp/app/components/primitives/SettingsLayout.tsx

apps/webapp/app/components/BackgroundWrapper.tsx

apps/webapp/app/components/BulkActionFilterSummary.tsx

apps/webapp/app/components/DefinitionTooltip.tsx

apps/webapp/app/components/DevPresence.tsx

apps/webapp/app/components/ErrorDisplay.tsx

apps/webapp/app/components/FeatureBadges.tsx

apps/webapp/app/components/Feedback.tsx

apps/webapp/app/components/GitHubLoginButton.tsx

apps/webapp/app/components/GitMetadata.tsx

apps/webapp/app/components/GlobalShortcuts.tsx

apps/webapp/app/components/ListPagination.tsx

apps/webapp/app/components/LogLevelTooltipInfo.tsx

apps/webapp/app/components/LogoType.tsx

apps/webapp/app/components/MachineLabelCombo.tsx

apps/webapp/app/components/MachineTooltipInfo.tsx

apps/webapp/app/components/RuntimeIcon.tsx

apps/webapp/app/components/SetupCommands.tsx

apps/webapp/app/components/Shortcuts.tsx

apps/webapp/app/components/StaleAssetRecovery.tsx

apps/webapp/app/components/TriggerRotatingLogo.tsx

apps/webapp/app/components/UserProfilePhoto.tsx

apps/webapp/app/components/WarmStarts.tsx

apps/webapp/app/components/admin/FeatureFlagsDialog.tsx

apps/webapp/app/components/admin/FlagControls.tsx

apps/webapp/app/components/admin/backOffice/MaxProjectsSection.tsx

apps/webapp/app/components/admin/backOffice/RateLimitSection.tsx

96/100

Spacing

2 serious
Design SystemSerious

apps/webapp/app/components/LoginPageLayout.tsx:71

Right-panel row split hardcodes an arbitrary grid value with no token

The testimonial panel's outer div uses `grid-rows-[1fr_auto]`, an arbitrary Tailwind value that isn't backed by any named layout token in this file.

Why it matters

As a one-off split used only here, this is low risk today, but it means the fixed proportion between the quote block and the logo strip lives nowhere reusable, so a future split-panel layout elsewhere in the app can't share it.

Fix

Extract the repeated 1fr/auto row split into a named utility or shared class if this pattern appears in more than one layout.

<div className="hidden grid-rows-[1fr_auto] pb-6 lg:grid">
<div className="hidden grid-rows-testimonial-split pb-6 lg:grid">
SpacingSerious

apps/webapp/app/components/BackgroundWrapper.tsx:10

Sidebar width of 260px is repeated three times with no shared source

`BackgroundWrapper` repeats the literal `260px` as `w-[260px]`, `left: "260px"`, and `backgroundSize: "260px auto"` across three separate style declarations, with no shared constant tying them together.

Why it matters

Resizing the sidebar background later means finding and editing three separate literals correctly, and missing one produces a visible seam between the background images.

Fix

Extract the repeated sidebar width into a single constant and reference it everywhere it's used.

className="absolute left-0 top-0 hidden w-[260px] bg-contain bg-top-left bg-no-repeat lg:block"
        style={{
          backgroundImage: `url(${blurredDashboardBackgroundMenuTop})`,
          aspectRatio: "auto",
          height: "100vh",
          backgroundSize: "260px auto",
        }}
const SIDEBAR_WIDTH = 260;

// ...
className={`absolute left-0 top-0 hidden w-[${SIDEBAR_WIDTH}px] bg-contain bg-top-left bg-no-repeat lg:block`}
        style={{
          backgroundImage: `url(${blurredDashboardBackgroundMenuTop})`,
          aspectRatio: "auto",
          height: "100vh",
          backgroundSize: `${SIDEBAR_WIDTH}px auto`,
        }}
98/100

Accessibility

1 serious
AccessibilitySerious

apps/webapp/app/components/layout/MetricsLayout.tsx:172

Sidebar resize handle has no visible keyboard focus or keyboard resize path

`MetricsLayoutMain` renders a `ResizableHandle` (`id={`${autosaveId ?? "metrics"}-sidebar-handle`}`) as the only way to resize the main/sidebar split. Nothing in this file shows a focus ring, `tabIndex`, or keyboard arrow-key handling attached to it.

Why it matters

A keyboard-only user has no way to discover this control or resize the panel, locking a whole interaction out for anyone not using a mouse or touch.

Fix

Give the resize handle a visible focus ring and a keyboard-operable resize path (role="separator" with aria-valuenow and arrow-key handling).

<ResizableHandle id={`${autosaveId ?? "metrics"}-sidebar-handle`} />
<ResizableHandle
  id={`${autosaveId ?? "metrics"}-sidebar-handle`}
  className="focus-visible:ring-2 focus-visible:ring-blue-500"
  aria-label="Resize sidebar"
/>

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

Color

1 serious
ColorSerious

apps/webapp/app/components/BackgroundWrapper.tsx:34

Background surface hardcodes #101214 instead of the existing token

The third background layer in `BackgroundWrapper` sets `backgroundColor: "#101214"` inline, while the outer wrapper and other surfaces in this file already use the `bg-background-dimmed` token class.

Why it matters

A theme or dark-mode adjustment made to `bg-background-dimmed` elsewhere never reaches this surface, so the background silently drifts out of sync with the rest of the page.

Fix

Replace hardcoded hex values with the existing background token already used elsewhere in this component.

style={{
          left: "260px",
          backgroundImage: `url(${blurredDashboardBackgroundTable})`,
          width: "100%",
          height: "100vh",
          backgroundSize: "1200px auto",
          backgroundColor: "#101214",
        }}
className="... bg-background-dimmed"
        style={{
          left: "260px",
          backgroundImage: `url(${blurredDashboardBackgroundTable})`,
          width: "100%",
          height: "100vh",
          backgroundSize: "1200px auto",
        }}
98/100

Components

1 serious
Design SystemSerious

apps/webapp/app/components/primitives/SettingsLayout.tsx:35

Shared settings column width hardcodes an arbitrary max-width value

`SettingsContainer`, the wrapper used to center content on every settings page, sets `max-w-[37.5rem]` as an inline arbitrary Tailwind value instead of a named scale entry.

Why it matters

Every settings page in the app inherits this single number. Adjusting the settings column width later means finding and editing this one arbitrary literal correctly, with no scale entry to reach for.

Fix

Move the shared settings column width into a named Tailwind scale entry so every settings page updates from one source.

className={cn("max-w-[37.5rem] overflow-visible", className)}
className={cn("max-w-settings overflow-visible", className)}
98/100

UX

1 serious
UXSerious

apps/webapp/app/components/LoginPageLayout.tsx:47

Testimonial quote flashes from blank to populated on every login load

In LoginPageLayout, `randomQuote` starts as `useState<QuoteType | null>(null)` and only gets set inside a `useEffect` that fires after mount. The Header3 quote block renders `{randomQuote?.quote}` immediately, so on first paint the right panel shows an empty quote mark and blank paragraph before the effect swaps in a real testimonial.

Why it matters

The panel next to the login form visibly jumps from empty to populated on every page load, which reads as an unfinished page at the exact moment a new user is forming their first impression of the product.

Fix

Pick the random quote synchronously with a lazy initializer so no null state is ever rendered.

const [randomQuote, setRandomQuote] = useState<QuoteType | null>(null);
  useEffect(() => {
    const randomIndex = Math.floor(Math.random() * quotes.length);
    setRandomQuote(quotes[randomIndex]);
  }, []);
const [randomQuote] = useState<QuoteType>(
    () => quotes[Math.floor(Math.random() * quotes.length)]
  );

Typography

No issues found

Motion

No issues found

Craft

No issues found

Working well

  • The doc comment explicitly states slots bake all chrome and no className is exposed except the two documented escape hatches, which is a real guardrail against spacing drift across pages.
  • Splitting the login form and testimonial panel into a 2-column grid that collapses to single-column on mobile (grid-cols-1 lg:grid-cols-2) is a clean, minimal-CSS responsive pattern.
  • SettingsRowTitle correctly renders a <label> when htmlFor is passed and a <span> otherwise, keeping semantic form association without forcing callers to choose.
  • Using assertNever(typedKey) in the filter switch guarantees every new filter key is handled at compile time, preventing silent gaps as the filter schema grows.

Scored August 1, 2026 with Rams Engine v0.0.3 · Engine changelog
First scored July 9, 2026: 94/100. This rescore on v0.0.3: 88/100.

This page is an automated design review of triggerdotdev/trigger.dev’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; confirmed criticals cap it — one at 59, two at 49, three or more at 39.

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