KIT - Pillar Design System

The Pillar Transformation: From Legacy to Modern Design System

How we modernized a 2016 component library with 95 hardcoded LESS files into a token-based SCSS architecture—without breaking a single production implementation.

Role

Design Systems Lead & UX Engineer

Scope

50+ component library

Year

2024 - 2025

🎯 The Story Behind the Project

Every design system has a story. Pillar's story began in 2016 with the best intentions—build a component library to power PROS's enterprise applications. But by 2025, what started as a solution had become a problem.

The KIT Figma Migration: Design Without Implementation

In 2024, our design team embarked on an ambitious project: translating our entire design system (KIT) into Figma. Before this, KIT existed as a documentation website with prototyping artifacts scattered across Axure and Sketch, legacy tools from a different era. The transition to Figma was inevitable. Modern design tools. Better collaboration. Variables and tokens. Everything we needed for a design-to-code workflow.

We spend a significant part of 2024 painstakingly recreating KIT in Figma. Every color, every spacing value, every typography scale. Component variants. Interaction states. We built a beautiful, comprehensive design system in the tool everyone was using. And then... nothing happened 😕

The Gap: The Figma KIT was complete, but nobody was fully dedicated to implementing it in code. The design system existed in Figma, but Pillar (our actual component library) was still using 95 LESS files with hardcoded values from 2016. The design team had done their part. Now the code needed to catch up.

Taking the Initiative

Picture this: A designer in our UX team spends hours perfecting a new app in Figma, carefully adjusting every color, every spacing value using the new KIT system. They hand it off to development with confidence. Weeks later, they see the production deployment and something feels... off. The primary blue isn't quite right. The button padding doesn't match. The hover states are inconsistent.

Why? Because there was no systematic connection between what designers specified in Figma KIT and what developers implemented in Pillar. Developers were still referencing the old LESS files, making educated guesses, or worse—hardcoding values because they didn't know the token existed in Figma.

This is where I saw the opportunity. The design team had built the foundation in Figma. Someone needed to bridge the gap—to architect a code implementation that mirrored KIT's token structure and ensure the two systems stayed in sync. That someone needed to understand both design thinking and engineering architecture. That someone needed to lead.

So I took the initiative. I proposed leading the Pillar modernization project—not just as a migration from LESS to SCSS, but as a fundamental transformation that would finally connect Figma KIT to production code.

😼 Understanding the Problem

The Legacy We Inherited

Pillar was built with LESS preprocessor in 2016—a perfectly reasonable choice at the time. But nine years of patches, quick fixes, and "just hardcode it for now" moments had created a tangled web of dependencies.

95

LESS files with hardcoded color values, spacing, and typography

~60%

Figma-to-code fidelity (designers had to manually check every implementation)

50+

Components that would need manual updates for any theme change

The Real Impact

💡 The Transformation Journey

The Vision: A Token-Based Future

I didn't just want to migrate from LESS to SCSS. I wanted to fundamentally change how we think about design and development at PROS.

The vision was clear: What if designers and developers spoke the same language? What if a color in Figma had the exact same name and value in code? What if changing a theme was as simple as swapping a few variables instead of editing 50 files?

That's when I designed our three-layer token architecture; a system that bridges the gap between design intent and code implementation.

Layer 1: Foundations

Raw values stored as SCSS constants. These are context-free primitives like $blue-600: #0f6eef and $spacing-sm: 1rem. They never change.

Layer 2: Semantic Themes

Context-aware CSS custom properties. Foundations map to meaning: --color-primary: #0f6eef. Different themes redefine these values—dark mode, high contrast, brand variants.

Layer 3: Component Tokens

Components consume both layers. SCSS validates tokens at compile time (catching typos before production), while CSS variables enable instant theme switching at runtime.

Why the Hybrid Approach?

Here's where it gets interesting. I could have chosen pure CSS variables or pure SCSS. But each has limitations:

CSS variables alone: Typos become silent failures. A developer writes var(--color-primry) (typo!) and the button renders with a transparent background. The bug reaches production.

SCSS alone: You lose runtime flexibility. Want to switch themes? You need to recompile all your CSS. No dynamic theming, no respecting user preferences.

The breakthrough: Combine both. SCSS validates tokens at compile time (fail fast!), then outputs CSS variables for runtime flexibility (theme switching without recompilation). We get compile-time safety and runtime power.

SCSS Preprocessing

// ❌ BEFORE: LESS (2016)
@import (reference) '../../less/variables.less';

.pillar-button {
  background: @color-interactive-primary; // Hardcoded reference
  color: #ffffff;                         // Magic value (where did this come from?)
  padding: 8px 16px;                      // Arbitrary numbers
  font-size: 14px;                        // Not scaled responsively

  &:hover {
    background: darken(@color-interactive-primary, 10%); // Manual calculation
  }
}

Runtime Behavior

// ✅ AFTER: SCSS + Tokens (2025)
@use '../design/' as design;

$button-bg: design.$color-primary;                      // Validated token
$button-text: design.text-contrast($button-bg);         // Auto-calculated contrast (WCAG)

.pros-button {
  @include design.button-reset();                       // Reusable mixin
  background: $button-bg;
  color: $button-text;
  padding: design.$spacing-xs design.$spacing-sm;       // Semantic spacing
  border-radius: design.$radius-default;                // Consistent radius

  @include design.paragraph(1);                         // Typography mixin

  &:hover {
    background: design.resolve-hover($button-bg);       // Intelligent hover (darkens bright, lightens dark)
  }
}

Notice the difference? Every value now has meaning. The contrast is automatically calculated for accessibility. The hover state is intelligently generated based on luminance. And if you reference a token that doesn't exist? The build fails immediately 😎

CSS Custom Properties Layer

CSS variables provide runtime theming flexibility:

Theming System: Light, Dark, and Beyond

Our theming architecture separates what colors mean (semantics) from what colors are (values). This enables unlimited theme variations without touching component code.

Theme Variations

Each theme redefines the same semantic tokens with different values:

Light Theme (Default)

Primary: Blue #0f6eef
Surface: Warm whites
Text: Dark on light

Dark Theme (Default)

Primary: Light Blue #3384f2
Surface: Dark neutrals
Text: Light on dark

Future Theme Possibilities

The architecture is designed to support unlimited theme variations without modifying component logic:

Theme Type
Use Case
Implementation
High Contrast
Accessibility compliance (WCAG AAA)
Redefine color tokens with maximum contrast ratios (e.g., pure black #000 on pure white #fff)
Brand Variants
White-label products, regional customization
Swap --color-primary to client brand color, auto-generate contrast/hover states
Seasonal Themes
Marketing campaigns, special events
Temporary theme overrides applied at the application level
Reduced Motion
Accessibility for vestibular disorders
Respect prefers-reduced-motion media query, disable animations via CSS variables

How Theme Switching Works

// themes.scss - Theme definitions
$default: (
  'primary': $blue-600,           // #0f6eef
  'surface-primary': $warm-0,     // #ffffff
  'text-standard': $warm-1000,    // #3a3a3a
  // ... 22+ semantic color assignments
);

$dark: (
  'primary': $blue-500,           // #3384f2 (lighter for dark bg)
  'surface-primary': $warm-1000,  // #1a1a1a (inverted)
  'text-standard': $warm-0,       // #ffffff (inverted)
  // ... same semantic keys, different values
);

// Compiled CSS output
html > body {
  --color-primary: #0f6eef;
  --color-surface-primary: #ffffff;
  --color-text-standard: #3a3a3a;
}

html > body.dark-mode {
  --color-primary: #3384f2;
  --color-surface-primary: #1a1a1a;
  --color-text-standard: #ffffff;
}
// Theme switching in React (zero component changes)
function toggleTheme() {
  document.body.classList.toggle('dark-mode');
  // All components update instantly via CSS variables!
}

Adding New Themes: The Complete Workflow

Here's the step-by-step process to add a new theme (e.g., "High Contrast") without modifying any component code:

1. Define theme in themes.scss

$highContrast: (
  'primary': #0000ff,              // Pure blue
  'surface-primary': #ffffff,      // Pure white
  'text-standard': #000000,        // Pure black
  // ... define all 22+ semantic tokens
);

2. Generate CSS variables with existing mixin:

html > body.high-contrast {
  @include apply-theme($highContrast);
  // Automatically creates:
  // --color-primary: #0000ff
  // --color-primary-contrast: #ffffff (auto-calculated)
  // --color-primary-hover: #0000cc (auto-calculated)
}

3. Enable theme in application:

document.body.classList.add('high-contrast');

4. Result: All 50+ components update automatically because they consume var(--color-primary), not hardcoded values!

Key Principle: Components are theme-agnostic. They consume semantic tokens (--color-primary) without knowing or caring what actual color value it holds. Themes redefine the values, not the semantics.

👨🏼‍💻 How We Built It: From Solo Research to Team Leadership

Phase 1: The Foundation (January - March 2025)

I started this project alone. Not because I wanted to work in isolation, but because I needed time to think deeply about the architecture before scaling to a team. The design team had spent 2024 building KIT in Figma. Now it was my turn to build the code foundation that would finally bridge the gap.

Phase 2: Scaling to a Team (April - Q4 2025)

By April, the architecture was solid. Now I needed to scale. With the support of my manager we recruited 2 UX engineers—not frontend developers, not designers, but professionals who could bridge both worlds.

🔶 Why UX Engineers?

This project had a unique challenge: We weren't just migrating tokens. We were also improving accessibility—adding ARIA attributes, keyboard navigation, focus management. This required people who could:

Pure frontend developers might miss design nuances. Pure designers couldn't navigate complex refactoring. UX engineers were the perfect fit.​

🔶 Building a Distributed Team

The team spanned 4 countries and 4 time zones:

Finding meeting times that worked for Bulgaria (3 PM) and Houston (8 AM) required strategic planning. We settled on bi-weekly team syncs at 2 PM CET, giving everyone a reasonable window to participate.

🔶 Sprint Strategy: Quarterly Releases with Isolated Branches

Here's the constraint: We couldn't break production. Our enterprise clients depend on Pillar running smoothly 24/7. So how do you modernize a design system while maintaining stability?

The Solution: We divided 2025 into 4 quarters. Each quarter had a dedicated feature branch (e.g., feature/pillar-modernization-q2) where all token migration and accessibility work happened. This kept the development branch stable for urgent production hotfixes. Two weeks before quarter-end, we froze new features and focused solely on testing, QA validation, and release prep.

This strategy gave us:

🔶 My Role: Leading from the front

As Design Systems Lead, I wasn't just organizing the team, I was coding alongside the team:

✨ The AI Revolution: Pioneering Automated Workflows

Starting in Q3 2025, we pioneered the integration of AI tooling into our design system workflow, significantly improving team velocity and code quality. This positioned us as early adopters of AI-assisted development in the organization.

Windsurf IDE: AI as a Team Member

We integrated Windsurf IDE into our development workflow. Think of it as having an AI pair programmer who understands your entire codebase.

Contextual Assistance

AI analyzes existing patterns and suggests token replacements.

"I see you're using #0f6eef here. Should this be design.$color-primary?"

Automated PR Reviews

AI pre-reviews pull requests for common issues—token typos, missing ARIA attributes, inconsistent BEM naming—before human review.

Knowledge Assistant

Team members ask AI questions in natural language: "What's the correct token for button padding?" Instant answers, no searching docs.

Velocity Boost

~25% reduction in component migration time through intelligent refactoring suggestions and automated code transformations.

MCP Servers: Connecting the Design-to-Code Pipeline

We integrated Model Context Protocol (MCP) servers to connect AI with our tools:

The 2026 Vision: This infrastructure enables our ultimate goal: An automated Figma synchronization agent. When a designer changes a color in Figma, the agent will automatically create a Jira ticket, generate a PR with updated SCSS tokens, and route it to developers for approval. Design-to-code sync time drops from hours to minutes.

Read more in my LinkedIn article: How MCP Servers Are Changing the Game for UX/UI Designers.

📚 Storybook: The Bridge Between Design and Development

Documentation wasn't an afterthought; it was central to the entire modernization strategy. We chose Storybook as our documentation platform, transforming it from a simple component gallery into the living, breathing hub of our design system.

Why Storybook Was Essential

When we started the Pillar modernization, we faced a critical challenge: How do we ensure that 50+ migrated components, 100+ design tokens, and a new SCSS architecture would be adopted across dozens of development teams? The answer was Storybook.

Our Storybook Implementation Strategy

We didn't just use Storybook out of the box; we customized it to become the definitive source of truth for Pillar:

🔶 Interactive Component Playground

Every component has a fully interactive story where developers can:

🔶 Design Token Documentation

We created custom Storybook pages (using MDX) that showcase our entire token system:

🔶 Copy-Paste Code Snippets

Every component story includes production-ready code examples using Storybook's Docs addon:

Storybook as Development Tool: Developers don't just read Storybook—they develop in Storybook. Our workflow encourages building components in isolation using Storybook first, then integrating into applications. This "component-first" approach, enabled by Storybook, has dramatically improved code quality and reusability.

📊 Results & Impact

Quantitative Results (As of Q3 2025)

60+

Static and dynamic design tokens created

40/50

Components migrated to SCSS (80% complete)

45

New SCSS files using token architecture

88%

Figma-to-code alignment (up from 60%)

Qualitative Impact

For Designers

For Developers

For Business

⭐️ Challenges & Solutions

Challenge 1: Accessibility Improvements Without Breaking Changes

Problem: Beyond token migration, we needed to improve accessibility (WCAG compliance) for impacted components—adding ARIA attributes, keyboard navigation, and focus management, without introducing breaking changes to existing implementations.

Solution:

Why UX Engineers Were Essential: This dual challenge (modernizing tokens and improving accessibility) required team members who could both understand design intent (spacing, color, interaction patterns) and implement robust code changes (React components, SCSS architecture, Jest testing). Pure frontend developers might miss design nuances, while pure designers couldn't navigate complex component refactoring.

UX engineers bridged this gap perfectly. 😎

Challenge 2: Resistance to Change

Problem: Developers comfortable with LESS were hesitant to adopt SCSS and new architecture.

Solution:

Challenge 3: Complex Components

Problem: DataGrid and PivotTable had 1000+ lines of LESS with deep nesting.

Solution:

Challenge 4: Backwards Compatibility

Problem: Couldn't break existing production implementations during migration.

Solution:

👨🏻‍🎓 Key Learnings

This design system modernization demonstrates the intersection of design thinking, engineering rigor, and strategic leadership. By architecting a token-based system that bridges Figma and production code, I transformed a legacy library into a modern, scalable foundation that will serve PROS for years to come.

What Worked Well

What I'd Do Differently

Related Work

Building a Multi-Brand Design System for PROS Digital Retail Solutions​

In this detailed walkthrough, I’ll share the strategic approach, design process, and key features behind the creation of a robust design system tailored for PROS Digital Retail. This design system serves as the backbone for various products, including the Booking Flow IBE, Hotels applications, Stopover application, and more across the PROS Retail ecosystem.

© 2025 Rolando Fernandez. All rights reserved