For Brian · Read before starting Forte
Working in the Primer Component System
How the token system, the component library, and the reuse-vs-build-new decision actually work — so you can move through the Forte wireframe independently.
Everything below applies to every client build, not just Forte — this is the general playbook. The Forte-specific starting point is: duplicate the Primer Design System Figma file, then follow Section 03 to reskin it. Two new components (Resource Header + Case Study Layout) were just added and are covered in Section 05 — you'll want those for Forte's blog/resource pages.
Three layers, in order
Every value in the design system — every color, spacing amount, font size, radius — comes from one of three layers. Understanding which layer you're touching is the single most important thing to get right, because it determines whether a change is safe (isolated to one client) or dangerous (ripples across every future project built from this file).
brand/500 = #bf8b3c, space/8 = 32px. Never client-specific. Never reference these directly from a component.
color/accent/default, color/text/primary, color/bg/secondary. Components are bound to these, never to a primitive or a raw hex value.
The reason this matters for Forte specifically: reskinning a client is a semantic-layer edit, full stop. You change what color/accent/default points to — every button, link, badge, and accent-colored element across all 20+ components updates automatically, because they were all bound to that same semantic variable rather than a hardcoded color.
The semantic collection has a second mode called Wireframe — strips all brand color so a review reads as pure structure. Toggle it from the Variables panel, applied per-frame. It's fully greyscale (true neutrals, near-black CTAs) — useful for early Forte reviews before color is locked, so stakeholders react to layout instead of getting distracted by color choices that aren't final yet.
The question to ask before building anything
When a page needs something that doesn't obviously map to an existing component, don't default to building a new one — and don't default to hacking it into an existing one either. Ask one question:
Will this exact pattern repeat — across pages on this build, or across future clients?
Repeats → build a component
- Every article needs the same byline shape (just different author/date)
- A grid item that appears N times (card, feature tile, FAQ row)
- Bind every property to a variable, give it proper variant states, treat it exactly like the other 20+ components
One-off → just compose the page
- A page-level arrangement of sections that already exist
- Example: a blog listing page is just Hero + Card Grid — no new component needed
- Still bind any values to variables, but there's no reusable master to build
A carrot.io-style blog came up as a reference. The listing page (grid of post cards) is the one-off case — pure composition of Hero + Card Grid, nothing new to build. The individual article page needed a byline header with author/date/share icons — that pattern repeats on every single article, so it became a real component (Resource Header, see Section 05) rather than one-off content on a hero.
Turning the master file into Forte's file
Don't design directly in the master file — it's the reusable base every future client starts from. Work in the duplicate.
Forte's brand colors go into the semantic layer (color/accent/default, color/bg/*, color/text/*, etc.). Every component updates instantly because they're all bound to semantic, never to a primitive.
These are primitives and structural — changing them isn't a "reskin," it's a design-system change, and should be a deliberate decision, not something that happens as a side effect of chasing a brand look.
If Forte's design genuinely needs something the library doesn't have, that's a Section 02 decision — is it a new reusable component, or a one-off composition? Don't guess; note it and we'll decide together.
radius/full is the one primitive that's known to corrupt if re-derived from a Figma round-trip (it's supposed to be 9999px for pill/circle shapes but comes back as a nonsense value like 624.938rem under certain sync conditions). If you ever see a pill button or avatar suddenly become a giant misshapen blob, that's this — don't try to "fix" it by hand, flag it for James.
Finding your way around the file
One Figma page per component (Hero, Card Grid, Feature Grid, and so on) — nested pieces that only ever appear inside a parent component live on that parent's page rather than getting their own. Example: the individual Card master lives on the Card Grid page, not a separate "Card" page, because it's never used outside a Card Grid.
Variants follow a consistent naming pattern: Property=Value, Property=Value — e.g. Style=Primary, State=Hover on the Button component. If you're building a new variant, match this exact format or the component set won't recognize it correctly.
Not every component has variants. A component only gets a variant axis when the states are genuinely visual alternates (Button's Style × State, Hero's Layout). A background field that just swaps between primary/secondary/accent-subtle is not modeled as a Figma variant anywhere in this file — that one's a code-side option only. Follow that precedent rather than introducing a new pattern.
What just got added, and when to use it
Two new Figma pages, right after Video in the page list — built this week specifically because Forte's blog/case-study pages need them and they didn't exist yet:
- Resource Header — the article byline block: category tag, headline, dek, author name + avatar + date, and social share icons. Use this at the top of any long-form article page.
- Case Study Layout — the two-column article body: a key-takeaways callout, the main content column, and a sticky sidebar (auto-generated table of contents + a CTA card). Its three sub-pieces — Key Takeaway Item, Table of Contents, Sidebar CTA — live on this same page.
For an article page like the carrot.io example: stack Resource Header directly on top of Case Study Layout. That's the whole page.
Case Study Layout, Key Takeaway Item, Table of Contents, and Sidebar CTA were live in the actual Astro/Storyblok build since last month — they just never had a matching Figma component until now, so what you're looking at was built directly off the real rendered output, not guessed. Resource Header is genuinely new on both sides (Figma and code/Storyblok schema), built this week.
The rules that keep the system working
- Everything binds to a variable. No hardcoded fill, stroke, spacing, radius, or font value anywhere on a component — that's what makes reskinning a token swap instead of a manual pass through every screen.
- Match existing naming conventions before inventing new ones — variant names, layer names, page names. Check what's already there first.
- When something's ambiguous, flag it — don't silently guess. Same rule that applies to the code side applies here: a wrong guess compounds across every future client that starts from this file.
Setting paint-level opacity on a fill or stroke that's bound to a color variable didn't reliably propagate from a master component to its instances — even direct instance edits and Figma's own "reset to main component" didn't fix it. Switching to node-level opacity (the whole layer's opacity, not the paint's) resolved it immediately. If a component's color looks right on the master but wrong/flat on instances, this is the first thing to check.