Blob: .impeccable.md
anvil — Design Context
Users
Solo developers first, small teams second. The person using anvil is deep in their terminal at odd hours, pushing code and watching builds. They check anvil in a browser tab alongside their editor — not on a phone, not casually. They chose anvil because they don't want another SaaS product. They want a tool they control.
Brand Personality
Blunt. Reliable. Fast.
anvil is the tool in the workshop, not the storefront. It doesn't explain itself twice. It shows you what's happening, confirms it worked, and gets out of the way. If anvil were a person, it would be the machinist who hands you exactly the right part before you finish asking.
Emotional Goals
Confidence and control. The user should trust the platform implicitly — trust that the status shown is the real status, that the action they took will do what it says, that nothing is hiding behind a loading spinner. anvil earns trust through transparency and speed, not through reassurance copy.
Aesthetic Direction
Industrial — but not cold. Think forged steel, shop floors, exposed structure. The interface should feel like it was built to work, not to impress. Raw materials with visible craftsmanship.
Reference Anchors
- jam.dev ("the knife") — Substance over decoration. Sharp typography, high contrast, no-nonsense information density. Everything on screen earns its place.
- charm.land ("the sugar high") — Personality and energy. Rejects sterile tech minimalism. Punchy copy, playful character, vibrant dark palette. Proves that developer tools can have a pulse.
Anti-References
- Generic SaaS products (Vercel marketing, Linear marketing, any "hero + 3 cards" layout)
- Existing CI/CD dashboards (GitHub Actions, CircleCI, Jenkins) — functional but lifeless
- AI-generated dark mode with purple gradients and glow effects
The Synthesis
anvil lives where jam's precision meets charm's energy, filtered through an industrial lens. The base is raw and utilitarian — exposed grid, dense information, no decorative elements. The personality comes through in motion (fast, decisive transitions), copy (blunt, occasionally sharp-witted), and the small details that show a human made this.
Accessibility — Astigmatism
The primary user has astigmatism. This is a hard constraint, not a nice-to-have.
Halation rules (bright text on dark backgrounds bleeds/glows for astigmatic eyes):
- Never pure white on pure black. Body text ceiling:
zinc-200(#e4e4e7) on lifted dark surfaces. Reservezinc-100(#f4f4f5) for headings only. Current canvas#1f1f22is good — never go darker. - Minimum font weight: 400 for body text. Light/thin weights (300 and below) blur and lose definition. Semi-bold (600) for emphasis, bold (700) only for headings.
- No hairline borders. 1px borders at low opacity disappear. Minimum effective border: 1px at 40%+ opacity, or 2px at lower opacity.
- Generous letter-spacing on small text. Sub-14px text needs tracking to stay legible.
The existing
tracking-[0.18em]on badges is correct. - Test contrast on lifted surfaces, not just bg.
zinc-400text onzinc-900card backgrounds is the real contrast check, notzinc-400onzinc-950.
Design Principles
Forged, not generated. Every element should look like it was placed with intention by a human. No template energy, no "this could be any product" layouts.
Blunt force clarity. Information hits immediately. Status, numbers, and actions are always unambiguous. Dense when the task demands it, sparse when it doesn't — never sparse just to look clean.
The tool disappears. Like a good hammer, the best interface is one you stop noticing. Confidence comes from never having to second-guess what you're looking at.
Speed you can feel. 75ms transitions. No loading states that linger. Optimistic UI. The interface should feel like it's already done before you finish clicking.
Warm industrial. Raw structure and exposed systems, but not sterile. Personality lives in the details — copy, timing, the way a status pill pulses. The workshop has good light and the radio is on.
Technical Constraints
- Dark mode only —
html.dark,color-scheme: dark - Tailwind v4 (CSS-native
@theme, no config file) - React 19 + React Router 7
- Fonts: Hanken Grotesk (body), Bricolage Grotesque (display), JetBrains Mono (code) — loaded via Google Fonts, permitted by CSP
- Icons: lucide-react
- No component library — hand-coded primitives in
src/client/components/ui/ - 75ms default transition — scoped to specific properties, never
transition-all - 60ms stagger increment — max 8 items (480ms ceiling)