Tools
When I joined MainTouch in late December 2025, the product was live and users were paying. By most measures, the startup was succeeding. But beneath the surface, there was a structural problem brewing.
Bennett Cohen, the founder, and Nathan Lian, the lead engineer, had built the product fast. They'd used Claude and GPT heavily in early development to move quickly. The result was functional, user-facing software that solved a real problem for B2B SaaS companies trying to rank higher on Google and ChatGPT. But the codebase had evolved reactively—each feature added without reference to a central system, each component styled slightly differently, each design decision documented only in Bennett's head.
I was brought in not to redesign the product, but to systematize it. The job was specific: audit what exists, propose a structure, build it in Figma, document it, and hand it off cleanly. A 3-month, part-time engagement. I was the hired specialist, not the founder or design lead.
The friction manifested in two ways:
First, the code was incoherent. Nathan was spending roughly 25–30% of his development time making styling decisions that should have been systematic. Should a button be 10px or 12px padding? Where's the standard button gray? Does this new component need a new variant, or can it be composed from existing pieces? These weren't design questions—they were code organization questions. And they were asked repeatedly.
I did a codebase audit in week one. The findings were straightforward:
Second, handoff between design and engineering was manual and error-prone. Bennett would design in Figma, share it with Nathan, and they'd spend 20–30 minutes per component agreeing on exact values. "Is this gray actually #1F2937?" "Should the spacing be 12px or 16px?" These conversations happened in Slack, in documents, in ad-hoc video calls. The Figma file, which should have been the source of truth, wasn't trusted because it lacked specifications.
For a fast-moving startup, this was a predictable cost of speed. But it was also a predictable debt. Every new feature added complexity without reducing it. By March, the team would be shipping features through layers of ambiguity.
Bennett's initial ask was deceptively simple: "Create a design system so we can move faster."
What he really meant was: establish enough structure that new work doesn't pile on top of existing chaos. Not comprehensive. Not perfect. Just useful and maintainable.
This became the guiding constraint: build the minimum system that solves the maximum problem. Don't document 10 button variants; define the principles such that 3 variants can combine into infinite patterns. Don't create a 50-page design system manual; make Figma clear enough that the code is self-documenting.
Bennett had studied Linear's design approach—minimal options, intentional constraints, powerful through composition. That became the north star. The system would have:
This was his way of saying: "I want the system to get simpler, not more complex, as we build."
Rather than propose a vision and build it top-down, I worked bottom-up.
Week 1–2: Codebase Audit
I cataloged all 50+ existing components in a spreadsheet:
This audit was the crucial first step. It showed the team what was actually in production, not what should be. It validated Bennett's intuition that a system was needed. And it meant the system I built would reflect reality, not ideals.
Week 3: Token Layer
With the audit done, I worked backwards from the codebase. Which colors actually mattered? By analyzing production code, I found that despite 40+ hex values, there were really only 8 semantic color needs:
I organized these into a semantic hierarchy:
Then typography and spacing. I normalized everything to Tailwind's 4px base—spacing values of 8, 12, 16, 20, 24, 32px. Typography locked to 3 sizes: 12px (small), 14px (base), 16px (large).
Week 4–10: Component Layer
With tokens defined, I built the component library in Figma. Each component had:
I worked closely with Nathan, asking: "Will this work in React? Can you implement this with the tokens we defined?" This pairing meant the Figma spec was always implementable, not just beautiful.
Week 11–12: Documentation & Handoff
The system needed to be usable, not just pretty. I created:
The shift from week-one chaos to week-twelve coherence looked like this:
<ImageComparisonPair lightSrc="[placeholder]" darkSrc="[placeholder]" lightAlt="Before: Hardcoded styles scattered across component files, no consistency" darkAlt="After: Organized token layer, semantic variables, structured variants" />
Code level: Where a Button previously had:
snippet.txt
const buttonColor = "#FF6600"; // hardcoded const padding = "12px 16px"; // magic number
It became:
snippet.txt
const buttonColor = "var(--brand-primary)"; // token padding: token(spacing.md); // semantic
Figma level: Instead of 40+ color swatches with names like "gray-1," "gray-2," we had:
brand-primaryforegrounddestructiveborderOne edit to brand-primary in Figma Variables updated everywhere automatically.
Component level: Instead of documenting 50 variants, we documented patterns. Button has 3 base variants (primary, secondary, ghost). Sizes scale through a size prop. States (hover, disabled, active) are CSS. Composition handles the rest.
The result was fewer decisions per component, not more. This counterintuitively made the system more flexible.
Bennett made a strategic call: build light mode, architecture dark mode, ship light mode first.
Building both modes in parallel would add ~4 weeks. Post-launch, if the variable system was solid, dark mode would be a 1-week job of flipping tokens. The tradeoff was clear: shipping velocity now, slight debt later.
This decision unlocked faster progress and proved right. The token architecture made dark mode trivial when they decided to ship it.
I recommended using Figma's Variables feature (released mid-2024) rather than hand-crafted color swatches and typography styles.
This meant:
The tradeoff was a small learning curve for the team. Worth it.
Early iterations had 6–8 variants per component (size, color, state, disabled, loading, etc.). This felt comprehensive but was a maintenance nightmare.
Bennett's suggestion to study Linear forced a pivot: instead of variant explosion, use composition.
Before: Document "Button with icon, primary, large, disabled state" as a variant. After: Button (primary) + size prop (lg) + Icon component + disabled state (CSS) = same result through composition.
This reduced Figma maintenance by 50% while making the system more modular and developer-friendly.
A crucial decision: component prop names in React match Figma variant names exactly.
If Figma has a Button variant called variant="primary", React's Button component accepts <Button variant="primary" />.
This removed a translation layer. No ambiguity. No "wait, is this button variant called 'primary' or 'main' or 'filled'?"
I recommended starting with WCAG 2.1 AA compliance. Bennett wanted to ship faster.
We compromised: documented accessibility patterns in components, implemented the common ones (keyboard nav, color contrast ratios, ARIA labels), and deferred a full audit to post-launch.
For an early-stage startup, this was the right call. 80% accessibility shipped beats 100% accessibility that delays launch.
The most dramatic impact was on development velocity:
Nathan (Lead Engineer): "I can now grab a Figma spec and implement it without asking questions. No more 'what does this gray mean?'"
Bennett (Founder): "The system gives us a decision-making framework. New features have to work within the system or justify breaking out."
Team adoption: 100% of new code written post-launch uses the system. No one-off styles. No variance from the baseline.
Unblocked the roadmap. The founding team had deferred 3 planned features pending "design system maturity." With the system in place, those features could now be started immediately. The team estimated 3 weeks instead of 5 for each—a 2-week accelerant across the roadmap.
Made scaling possible. A clean system and clear documentation meant Bennett could now confidently hire a second designer or engineer who could ramp up in days, not weeks.
Shifted team culture. Before, the codebase felt like a prototype being held together with duct tape. After, it felt intentional—like they were building a real product. That psychological shift matters.
AI-readiness. The structured, consistent codebase became safer for AI-assisted development. When the team used Claude or GPT to generate UI code, the system acted as a guardrail. AI-generated components were more likely to fit in rather than break the consistency.
1. Start with problems, not vision. The codebase audit was crucial. Showing 40 hardcoded colors was more persuasive than proposing a design system. People believe data, not ideals.
2. Constraint as clarity. By saying "no" to dark mode, 8 typography sizes, and comprehensive variants, we forced intentionality. The system got simpler, not more complex. That's the opposite of how most design systems evolve.
3. Pairing with engineering early. Rather than design everything in Figma then hand it to Nathan, we built key components together. This meant specs were always implementable.
4. Figma Variables as infrastructure. Modern tooling (Figma Variables, CSS custom properties, Tailwind) made this possible. Without them, the system would require manual updates across 50+ components.
5. Clear handoff documentation. The system worked because it wasn't mysterious. Token reference, prop mapping, migration guide—the team could onboard and use it without constant questions.
Communicate earlier and more visibly. In retrospect, I should have shared progress weekly instead of appearing with a polished system at week 3. Visible work-in-progress keeps stakeholders engaged and surfaces feedback faster.
Involve engineering in decisions from day one. I waited until Figma was mostly built before getting Nathan's input deeply. Pairing on the first 3 components would have accelerated understanding and caught implementation constraints earlier.
Document decision rationale alongside decisions. Rather than burying choices in my head, I should have logged them in Slack or Figma as I made them. This would educate the team and prevent re-litigating the same choices.
The single most important lesson wasn't about design systems, it was about pragmatism.
I came in wanting to build the right system, complete and battle-tested. Bennett needed the system that shipped and didn't slow down development. Those aren't the same thing.
The lesson: Build for 80% of the use case with 100% intention, not 100% of the use case with 80% intention. Iterate toward completeness. Constraint beats comprehensiveness in early-stage work.
This applies beyond design systems. It's a principle for all product work in startups: ruthless focus beats ideal scope.