pmndrs/zustand
Reviewed against Rams quality heuristics: accessibility, color, typography, spacing, components, motion, UX, and craft.
14 files reviewed·August 1, 2026
More findings
Verdict
A WebGL mascot with a fallback plan sounds resilient, but the fallback only fires after something breaks, not before. Colors are scattered as raw hex across buttons, shadows, and backdrops, so the palette will fracture as soon as either file grows.
Files Rams reviewed
examples/demo/src/components/CodePreview.jsx
examples/demo/src/components/CopyButton.jsx
examples/demo/src/components/Fireflies.jsx
examples/demo/src/components/Scene.jsx
examples/demo/src/components/Details.jsx
examples/demo/src/components/SnippetLang.jsx
examples/starter/src/index.tsx
examples/demo/src/pmndrs.css
examples/demo/src/styles.css
examples/demo/src/App.jsx
examples/demo/src/main.jsx
examples/starter/src/index.css
examples/demo/index.html
examples/starter/index.html
Components
examples/starter/src/index.tsx:44
Mascot drop-shadow color is a hardcoded hex baked into inline style
The mascot `<img>` uses `style={{ filter: 'drop-shadow(0 0 2em #582d3e)' }}` to render its glow, a second unique hex value in the same file separate from the button's `#252b37`. Neither ties back to a shared token or CSS variable.
Why it matters
Two unrelated hex values in one small file means any theme or brand-color update requires hunting through inline styles and className strings separately, and the two colors will silently drift apart over time.
Fix
Move the drop-shadow color into a CSS custom property or Tailwind class so it can be updated in one place alongside other brand colors.
style={{
filter: 'drop-shadow(0 0 2em #582d3e)',
}}className="w-36 drop-shadow-mascot"examples/demo/src/components/Scene.jsx:154
Fallback scene background is a hardcoded hex with no shared source
`FallbackScene`'s wrapper `<div>` sets `background: '#010101'` directly in an inline style object rather than through a shared variable or class, alongside the `<img src="/ogimage.jpg" alt="Zustand Bear">` it centers.
Why it matters
If the app's dark background is defined anywhere else (canvas clear color, page background), this near-black gets out of sync the next time either value changes, producing a visible seam between the fallback and the real scene.
Fix
Reference a shared background token or CSS variable for the fallback's backdrop instead of a one-off hex value.
background: '#010101',background: 'var(--color-canvas-bg)',Accessibility
examples/demo/src/components/Scene.jsx:200
WebGL scene mounts with no capability check before rendering
`Scene` renders `<Canvas><Experience /><Effects /></Canvas>` unconditionally and only swaps to `<FallbackScene />` after `onError` fires from inside the r3f root. There's no upfront check for WebGL support or a low-power/reduced-motion state before the GPU-heavy scene attempts to initialize.
Why it matters
Users on devices without WebGL, or with GPU drivers that fail silently rather than throwing, sit on a blank canvas with nothing rendered and no explanation, since the fallback path is reachable only through a thrown error.
Fix
Check for WebGL support before mounting the Canvas and render the fallback immediately when it's absent, instead of relying solely on a runtime error callback.
export default function Scene() {
const [error, setError] = useState(null)
if (error) {
return <FallbackScene />
}
return (
<Canvas onError={setError}>
<Experience />
<Effects />
</Canvas>
)
}export default function Scene() {
const [error, setError] = useState(null)
const supportsWebGL = useMemo(() => hasWebGLSupport(), [])
if (error || !supportsWebGL) {
return <FallbackScene />
}
return (
<Canvas onError={setError}>
<Experience />
<Effects />
</Canvas>
)
}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 freeColor
examples/starter/src/index.tsx:27
Counter button background is a raw hex value with no token backing
The "+1" button in `Counter` is styled with `className="bg-[#252b37] font-bold py-2 px-4 rounded"`, an arbitrary Tailwind bracket value instead of a theme color or CSS variable. There's no design-token layer in this starter, so this hex is invented on the spot and has no relationship to any other color in the app.
Why it matters
Every future button in this app has to guess or re-copy this exact hex string, so the palette drifts as soon as a second component needs a similar dark background.
Fix
Extract shared colors into a Tailwind theme token (e.g. `bg-surface`) so components reference one source instead of repeating hex literals.
<button
className="bg-[#252b37] font-bold py-2 px-4 rounded"
onClick={inc}
><button
className="bg-surface font-bold py-2 px-4 rounded"
onClick={inc}
>Typography
Spacing
Motion
UX
Craft
Working well
- `Counter` keeps all state in the zustand store (`useStore((s) => s.count)`, `useStore((s) => s.inc)`) and leaves the component purely presentational, which keeps the increment logic testable in one place instead of scattered across the UI.
- The `Canvas` helper in Scene.jsx cleanly separates r3f root creation, resize handling, and error boundary wiring into one function, keeping WebGL setup isolated from the rest of the app's layout code.
- The `+1` button renders with visible text content, so it gets an accessible name for free with no extra ARIA needed, which is the simplest correct pattern for labeling interactive controls.
Scored August 1, 2026 with Rams Engine v0.0.3 · Engine changelog
First scored May 13, 2026: 94/100. This rescore on v0.0.3: 92/100.
This page is an automated design review of pmndrs/zustand’s UI code: 14 files read against 308 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.