tsu-ld/tsu-ld
Reviewed against Rams quality heuristics: accessibility, color, typography, spacing, components, motion, UX, and craft.
8 files reviewed·July 25, 2026
Verdict
The card's layout and animation timing are built on shared constants and modules, which is exactly the right instinct for something meant to be retuned repeatedly. The gaps are in the details that don't get revisited often: an unguarded SMIL wipe with no reduced-motion path, stat labels that hardcode casing instead of leaning on the stylesheet, and a dead CSS class sitting next to its live twin. None of it undermines the overall composition, but it's the kind of drift that compounds the next time someone touches this file.
Files Rams reviewed
src/card/render-card.tsx
src/card/sections/background.tsx
src/card/sections/caliper-stripes.tsx
src/card/sections/sparkline.tsx
src/card/sections/stat-rows.tsx
src/card/sections/typewriter.tsx
src/svg/discrete-animate.tsx
src/svg/glyph-outline.tsx
Typography
src/card/sections/stat-rows.tsx:13
Stat labels bake uppercase into data instead of styling
rowsFor() returns labels like "UPTIME", "REPOS / CONTRIB", "CODING HOURS" as hardcoded all-caps strings, even though styleSheet() already defines a .label/.micro rule with letter-spacing meant for this exact treatment.
Why it matters
Storing casing in data instead of CSS means any future reuse of these strings (tooltips, alt text, JSON export) inherits the shouty caps, and the visual style can't be changed without touching the data layer.
Fix
Store labels in natural case and apply uppercase via a CSS text-transform rule on the existing .label class.
["UPTIME", stats.uptime],
["REPOS / CONTRIB", `${stats.repoCount} / ${stats.contributedCount}`],["Uptime", stats.uptime],
["Repos / Contrib", `${stats.repoCount} / ${stats.contributedCount}`],
// add `.label { text-transform: uppercase; }` to styleSheet() and apply the class to these <text> nodesMotion
src/card/render-card.tsx:63
Headline wipe animation has no reduced-motion fallback
The <clipPath id="headline-wipe"> in HeadlineWipe() drives a <rect> width from 0 to full via SMIL <animate attributeName="width">, running unconditionally over BOOT_HEADLINE_SECONDS with no check for prefers-reduced-motion anywhere in styleSheet() or the render path.
Why it matters
Vestibular-sensitive viewers get the full wipe motion every render with no way to opt out, which is the exact case prefers-reduced-motion exists to cover.
Fix
Gate SMIL animations behind a reduced-motion check and freeze the clip at its final width when reduced motion is requested.
<animate
attributeName="width"
values={`0;${width}`}
keyTimes="0;1"
dur={`${BOOT_HEADLINE_SECONDS}s`}
begin="0s"
fill="freeze"
calcMode="spline"
keySplines="0.22 1 0.36 1"
/>{!prefersReducedMotion && (
<animate
attributeName="width"
values={`0;${width}`}
keyTimes="0;1"
dur={`${BOOT_HEADLINE_SECONDS}s`}
begin="0s"
fill="freeze"
calcMode="spline"
keySplines="0.22 1 0.36 1"
/>
)}
{prefersReducedMotion && <rect x={PAD_LEFT - 4} y={HEADLINE_BASELINE - HEADLINE_SIZE} width={width} height={Math.round(HEADLINE_SIZE * HEADLINE_WIPE_HEIGHT_RATIO)} />}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 freeCraft
src/card/render-card.tsx:38
Duplicate .label CSS rule is dead weight next to .micro
styleSheet() defines .micro and .label with byte-for-byte identical rules (font-size: 10px, letter-spacing: 1.8px, same fill), and .label is never referenced elsewhere in render-card.tsx.
Why it matters
Two classes doing the same job with no visible distinction means the next editor can't tell which one is canonical, so future style tweaks get applied to one and silently miss the other.
Fix
Delete the unused duplicate class or merge it into the one class that's actually referenced.
.micro { font-size: 10px; letter-spacing: 1.8px; fill: ${palette.foregroundSoft}; }
.label { font-size: 10px; letter-spacing: 1.8px; fill: ${palette.foregroundSoft}; }.micro { font-size: 10px; letter-spacing: 1.8px; fill: ${palette.foregroundSoft}; }Accessibility
Color
Spacing
Components
UX
Working well
- Layout constants like PAD_LEFT, RIGHT_EDGE, and HEADLINE_BASELINE all come from a shared layout module instead of being sprinkled per-element, which keeps the SVG's coordinate system consistent and lets the whole card be retuned from one file.
- The area-fill's begin time is deliberately offset to half the line-draw duration so the fill only appears once enough of the line exists to enclose it, a physically-motivated sequencing choice rather than an arbitrary stagger.
- The background layer (grid, crosshairs, vignette, grain) sits at low opacities between 0.06 and 0.4 rather than competing colors, giving the card quiet texture without fighting the foreground stats and headline for attention.
Scored July 25, 2026 with Rams Engine v0.0.3 · Engine changelog
First scored July 22, 2026: 59/100. This rescore on v0.0.3: 94/100.
This page is an automated design review of tsu-ld/tsu-ld’s UI code: 8 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.