,

Port 443 · Rebuilding Design System from the Ground Up

•

min read

Role: Principal Product Designer, design system lead, Jan 2024 – Sep 2025. I planned and designed the system end to end and worked with the developers on every rollout.

Products: My Music Staff, TutorBird, AthletaDesk, plus an internal test theme.

One system for three products

I rebuilt the design system behind three SaaS products for teachers, tutors and trainers. It now has one set of foundations, components and rules, and each product differs only by its theme.

One side navigation, four product themes: Test 443, My Music Staff, TutorBird, AthletaDesk

Context

Port 443 builds scheduling and business software for music teachers (My Music Staff), tutors (TutorBird) and personal trainers (AthletaDesk). All of it runs on one codebase. When I started, there were three products and an internal test theme, one team and no shared foundation underneath them. Usage data showed a large share of mobile users on a long tail of screen sizes, so the foundation had to be flexible from the start.

Screen sizes of My Music Staff users, Oct 29 – Nov 17, 2024: a long tail of resolutions and a large mobile share

The problems sat on three levels.

Foundations

The Primary, Secondary and Accent palettes held the same ramp in most products, and the neutrals lived in two overlapping sets. Spacing had only 6 large tokens and no tokens for icon sizes or corner radius. Type styles in Figma, in the docs and in code disagreed, and Desktop and Mobile styles switched automatically, so designers lost control of responsive text.

Old color system

The rest of the foundations had the same story: three breakpoints that did not match the code, six spacing tokens, type styles that disagreed across Figma, docs and code, and icons that were Font Awesome characters.

Old foundations (breakpoints, spacing, typography, icons)

Components

Forms were stuffed into dialogs, with a new custom dialog for every form. Tables were one fixed template, so designers detached them. Status labels had 5 variants in Figma and many more in code. Icons were Font Awesome text characters. “Layouts” were copies of screens, and developers hardcoded the structure.

Old dialogs (master component)

Tables had the same problem: one fixed template with generic text cells, so changing a single column meant overriding the whole row.

Old tables (master component)

Patterns

Of 7 pattern pages, 4 were empty and 1 was junk. Only Pickers had real content.

The result was daily friction. Designers detached components, and developers hardcoded values to match what they saw.

Approach

I put the design system on the same roadmap as the product projects, sized and prioritized like any other project. The backlog had 15 estimated items, with a horizon of 6–8 months.

Tech debt first, design debt second.

The working rule was to make things consistent first, then make them right. Consistent but wrong is easier to fix than wrong in ten different ways.

Three goals guided the work:

  • One source of truth for design and code.
  • No more one-offs from designers detaching and developers hardcoding.
  • One system for four products, with differences kept in themes and terminology.
Key goals and approach

The new foundations

Color

The old palettes were named per product and repeated the same ramp, so changing a brand color meant editing every product by hand. I replaced them with a chain of tokens, a layered approach common in modern design systems, where each layer has one job:

  • A primitive names a raw value
  • An alias says what the color is for
  • A component token uses that alias for one job
New color system approach

Merging the two neutral sets into one scale took the most care: I evened out the steps and renamed them from --color-dark-25 to --color-dark-1000, so a developer can use a name directly. I also cut the brand ramp from 14 to 10 steps with names like lighter, normal and darker.

Color system fix

To move the product over, I mapped every old color to its new token, group by group (brand, neutrals, info, warning, success, danger), so the developers had one reference for the whole swap.

Color token migration map

In Figma, these tokens live in one Theme collection with a column per product, so a theme changes the values and the structure stays the same. Figma had no extended collections yet when I set this up. Today I would build each product theme as an extended collection of one base.

Theme variables: each token has a value per product (Test, MMS, TB, AD)

Typography

The new system has 23 styles in five groups (Display, Headline, Title, Body, Label) with Strong variants. Names say what a style is for. Font size is set per layout, so designers decide how text behaves on each screen. I built the migration map from the real SCSS running in production, because the old Figma library no longer matched the product.

Typography system migration

Spacing, sizing and grid

Spacing runs on a 4px scale with 14 tokens (4 to 64px). Icon sizes and corner radius became tokens as well. For the grid, I dropped the custom hardcoded one and moved to Bootstrap, which the product already included. That gave 5 breakpoints plus a fluid layout, and developers could use a known standard.

New foundations: grid, spacing and sizing

Icons

Icons moved from Font Awesome characters to SVG: Material icons as the base, plus our own custom icons drawn in 24×24 boxes and sized by tokens.

New SVG icon library, replacing Font Awesome

Making tokens readable for developers

Developers could not see Figma’s variables table, so I built a small Figma widget that renders token lists as readable tables.

Custom Figma widget that renders token tables

It has its own write-up: Creating a Figma Widget for Token Inspection.

One system, four themes

Themes change colors, fonts, logos and terminology (teachers, tutors, trainers). The components stay the same. Navigation keeps one structure and adapts its items to each product.

4 themes, one source

The marketing team had complained about the old illustrations, which were kept as four parallel sets. I set a new direction and drew one set myself in four colorways, plus neutral ones for universal cases.

New system illustrations: one set in four product colorways

Components with rules

Long forms were squeezed into small centered dialogs and scrolled inside them. Forms now live in a full-height Drawer, with a Wizard variant for long flows. Developers now take the Drawer by default.

Drawer component

Dialogs stay for short decisions, with presets for Delete, Info and Confirmation.

Dialog components

Tables and the Filter Bar

A table is now a row template plus typed cells (Header, Basic, User, Action, Status, Contacts), swapped per column. The toolbar became its own pattern: one Filter Bar across tables, calendar and attendance.

Table building blocks

I wrote it up separately:
Consolidating UX Patterns for Filtering and Content Control.

Filter bar module

The Filter Bar is built from chips, and each chip type (input, person, status, filter) is its own component.

Chip component

Figma matches code

Inputs are named after real elements (input, textarea, mat-select) in place of about 150 static frames. Status labels gained 27 named colors that existed in code but not in Figma, plus 7 semantic types with preset icons.

Status label aligned with code

Dropdowns became an item system: one set of items (basic, checkbox, person, status, sortable) that works in any panel.

Menu item components

Items sit in three panel types, Select, Menu and Chip-Menu, with their own rules for height, width and empty states.

Panel type aligned with framework

Results

The old library couldn’t scale and grow, so the new Core Library is built from the ground up: tokens first, then components, then modules assembled from them.

78components designed from scratch, with 660+ variants
17reusable modules: navigation, toolbars, calendar, etc.
390+new design tokens across 4 product themes

The new system replaced the old one across foundations, forms, tables, status labels, inputs and icons. Components now mirror what runs in the product, and developers use the Drawer and typed cells by default.

I did not measure task time or adoption, so I do not claim numbers for the speed of work.

Reflection

The hardest part was changing a live product: every step had to ship without breaking what customers already used, with a small team and a system that ran in parallel with product work.

Working with the developers from day one is what made it work. Now they take ready parts and stop hardcoding, design is faster, Figma matches the code, and new features were built on the system from the start.

If I did it again, I would measure results from the start: task time and how fast each component gets adopted. With more time and people, I would also bring AI agents into the upkeep of the system, for token sync, documentation and consistency checks.

0