Case study 02 · Design system

FamJamdesign system

How I turned one family planner app into a set of reusable decisions: tokens, components and documentation, all built in Figma.

A laptop showing the Colours page of the FamJam design system.
Role
Sole designer
Timeline
Sep – Oct 2026
Tools
Figma variables, components, auto layout; Material Symbols
Context
Self-initiated, alongside the Google UX course
Back to work

The full story · 7 chapters · about 8 minutes

The why

A design system wasn’t part of the course. I built one to learn how good design is put together.

Constraints

Solo and new to design systems, learning with Claude as an expert tutor, alongside building the app itself.

The system, by the numbers

56

Components, in three levels

3

Variable collections: Primitives, Semantic, Member

13

Text styles across three typefaces

100+

Screen reader annotations

Chapter 1, The starting point: A home screen with nothing reusable

FamJam’s first home screen was designed screen by screen. It looked finished, but nothing underneath it was reusable.

The New Activity button selected in Figma, with its fill set to the typed-in hex FF5656 and its stroke to 23272E.
Fig. 1The New Activity button looked finished, but its colours were typed-in hex values.

What I found

  1. Colours and spacing set loosely, with many near-duplicate values

  2. One-off shadows, each set by hand

  3. Icons at mixed weights and sizes

  4. Three typefaces, but no type scale or rules for when to use each

Every change meant finding and fixing each layer by hand.

Before designing more screens, I wanted one source of truth.

Chapter 2, The approach: One section at a time

I built the design system in nine sections, from colour through to the sticker sheet and an introduction page. Most followed the same loop:

  1. Step 01

    Audit

    What did the home screen already use?

  2. Step 02

    Rules

    Turn what the audit found into tokens, styles or components.

  3. Step 03

    Document

    Record the reasoning, rules and accessibility notes on the Design System page.

Repeat for each of the nine sections

PreviewSurfaceShadowtype · blur · X · Y · opacityLinkedProposed effect style name (new)
Timeline sheetDrop · 4 · 0 · −4 · 25%Yesshadow/sheet
What's up next and Who's on top sheets (2)Drop · 4 · 0 · −4 · 25%Noshadow/sheet
Fig. 2Part of the shadow audit: the same shadow, linked in one place and typed in by hand in another.

Why go this deep

Even if I never build another system, I’ll understand how any system I join is set up, and why.

A design system wasn’t part of the Google UX course: I chose to build one alongside FamJam to push my knowledge further. It would teach me Figma properly, and more importantly, how good design is put together.

How I learned

I learned with Claude, an AI assistant, acting as a design systems expert. It explained each concept before I used it, walked me through every step and answered my questions as I went, so I understood the why as well as the how.

I made the design decisions and built most of the system myself. For some larger, repetitive jobs, Claude made the changes in Figma and I reviewed them step by step.

Close-up of the FamJam design system’s Introduction page on a laptop screen.

Chapter 3, Foundations: Every value becomes a token

Tokens come in two layers: primitives say what values exist, and semantic roles say what they’re for. Change a role and every place that uses it follows, and dark mode can be added later as a second mode.

The test for every token

Should this change together everywhere?

  • Colour

    Brand, neutral, feedback and member primitives, with roles such as text/primary.

  • Type

    Three typefaces, each with one job, and 13 text styles. Styles say what kind of text it is; colour tokens say how prominent.

  • Spacing

    An 8px grid with 4px half-steps, plus radius and border-width roles.

  • Shadows

    Raised, sheet and inset, chosen by job, plus one-offs for the logo and the New Activity button.

Close-up of FamJam’s variables in Figma: semantic spacing tokens such as screen-margin, each pointing to a primitive such as spacing/20.

8modes

Eight family colours, one switch

A Member collection holds eight colours as modes. Setting the mode on a component recolours the avatar and its card together. Red is left out, because it means destructive actions and errors.

The same event card in two Member modes, Sky (default) and Orange, above the eight member colours: Sky, Orange, Purple, Pink, Emerald, Periwinkle, Plum and Maroon.
Fig. 3Same component, different mode: only the Member mode changed.

Icons and the logo

Icons

One set, Material Symbols, with five fixed settings. Rounded matches the rounded letters of the main typeface and the pill-shaped cards, and weight 600 matches the bold headings, so icons and text feel equally strong. I chose Rounded over Outlined by comparing them side by side.

  • StyleRounded
  • Weight600
  • FillOff
  • GradeNormal
  • Optical sizeMatches the frame

Four sizes, and every tappable icon gets a 48 × 48 tap area: the area grows, not the icon.

The logo

A single component, so it’s never retyped as live text. Clear space is the height of one red “a” from the logo on every side, rounded up to the next spacing step.

The logo with clear space equal to one letter “a” on every side.
Standard
147 × 40
Minimum
100 × 27
Backgrounds
2 approved
Misuse
6 examples

Chapter 4, Components: Built bottom up, ready to hand over

The first version had 27 components, built in three levels. Something became a component when it was used three times or more, or held a decision I wanted to stay consistent. Building the prototype later grew the library to 56 (see section 6).

27 to 56

components, first version → final

Four component rules

  1. One property per decision, named by value: Size=40 State=Pressed

  2. Default, Pressed and Focus states on everything interactive.

  3. Every tappable component at least 48 × 48.

  4. Built as if handing it to a developer: names that map straight to code, and every component description and accessibility note readable in Dev Mode.

A laptop showing part of the FamJam Components page: a calendar, an empty state, a celebration message and pending inbox items.
Fig. 4The Component page

The sticker sheet

Every component as a labelled instance, so anyone can browse, copy and check them without touching the main components.

Jacob smiling beside his laptop, which shows the Base panel of the FamJam sticker sheet.
Fig. 5The Base panel, one of four on the sticker sheet.

Chapter 5, Accessibility: Fixed once, inherited everywhere

Accessibility fixed screen by screen gets lost at the next change, so I fixed it in the components instead, where every screen inherits it.

Contrast, checked in context

2.0 to 3.2

The date arrow failed in place. Two token changes took it past WCAG’s 3:1 minimum. Placeholders went from 3.7:1 to 4.8:1, passing the 4.5:1 minimum for text.

Touch areas

28 to 48

Text links were 28px tall to tap. The tap area grew to 48px; the text stayed the same size.

Screen reader notes

100+ Read as“Monday 14th September”

Annotations in one format: role, label, state, hint. Dates written as they’re spoken.

Never colour alone

Initials

Every family colour comes with an initial, so nobody relies on colour to know whose activity it is.

Five components with their touch areas outlined by dashed boxes: icon-button, date-row, text-link/back, picker-field and checkbox. Each dashed area is bigger than the element you see.
Fig. 6Touch areas from the design system: the dashed area is what you can tap.

A trade-off, documented on purpose

Testing showed the New Activity button wasn’t noticeable enough, so it became bold coral.

Its label only passes contrast because the text is large, so it’s recorded as a single, scoped exception rather than a pattern anyone could reuse.

Part of the FamJam homepage with two accessibility annotations: the inbox button’s screen reader label, and a note marking a decorative element to hide from screen readers.
Fig. 7Screen reader annotations: what each element is, and what gets read out.

Chapter 6, Putting it to work: The real test is new work

26

New screens designed for the prototype

73

Fixes found by the audit

33

Additions found by the audit

For the high-fidelity prototype I designed 26 new screens, then audited them against the system before polishing anything.

Most traced back to one cause: I’d drawn the forms, buttons and dialogs by hand. So I built those components first, and around half the list fixed itself.

  • 27 to 56

    Components, with states and 48px targets on everything interactive.

  • Instances

    Every screen rebuilt from components, with one documented exception: a timeline where an activity sits partly above the top of the screen, which the component can’t place.

  • −710px

    The gap holding the home screen together, replaced with responsive auto layout. All frames tested at 375, 393 and 430px wide.

  • 23

    Hidden prototype variables that fill in fields from the test script and stop pressed states getting stuck.

Component 56

Found in testing, fixed the same day.

In round 2, 2 of 5 participants didn’t realise the pending activity in the inbox could be tapped. It looked like a label, not a button.

The same day, I built a new component: a list row with a clear “See more details” link. It used only existing tokens, with no new colours, sizes or styles. That’s what the system was for: a problem found in testing was fixed without redesigning anything.

The moment tokens paid off

Near the end, the dark navy button felt too heavy for a playful family app.

Every primary button points at two tokens, so I compared options side by side, changed the tokens and checked contrast (8.6:1).

Every primary button updated.

The primary button tokens before and after: button/primary/fill changed from navy/950 to navy/300, and button/primary/label from cream to navy/950. The label on the new fill has 8.6:1 contrast.
Fig. 8Two token changes restyled every primary button.

Chapter 7, Reflection: What I learned, and what’s next

The biggest surprise was how much of good design comes from structure. I’d always thought it was mostly about having a creative eye, but structure is what brings the consistency that great designs share.

What I learned

Nearly every step was a new concept, from tokens and auto layout to audits and focus states. Modes, naming conventions and writing documentation a developer could pick up took me the longest.

I didn’t move on until I understood each one, often asking Claude to set me practice tests on whatever I was stuck on. Being able to ask endless questions without breaking my train of thought meant I learned far more, far faster.

Next time I’d document as I go rather than afterwards. What I’m proudest of is how much I now understand: not just how to use Figma, but why systems are set up the way they are.

Tried and dropped

  • Amber buttons

    They failed contrast at 2.1:1.

  • A live-updating New Activity card

    Binding it to variables lost its bold “Location:” label, so I kept the component as it was.

  • A Pressed state on menu items

    Tried twice and reverted, because it fought the variables behind each item.

What I’d do next

  1. Dark mode, as a second mode on the Semantic and Member collections.

  2. Test with VoiceOver, TalkBack and larger text sizes.

  3. Rebuild the Colours page from text styles and tokens.

  4. Describe every variable and publish the library.

  5. Balance the family colours, starting with maroon next to the coral.

The FamJam app on a phone in front of a laptop showing the design system’s Typography page.
Next case study: FamJam 

A family planner that isn’t a calendar.