← Henry Kaufman

Aspect · 2026

Facet → WEM

Building Facet from scratch was the easy part. Landing it on top of two decades of stacked CSS — without breaking anyone's muscle memory — is the work.

Constraints

WEM is Aspect's flagship product — workforce-management software for contact centers. It's been running for over 20 years on Less, jQuery, and Knockout.js, with organically-grown CSS layered through patches, customer customizations, and pattern drift. Agents and supervisors have decades of muscle memory in its existing UI.

Facet — the design system I built for WFX (see the previous case study) — is the destination. The port has to satisfy three things at once:

  • Users with established workflows keep their muscle memory through the visual transition
  • The Facet language carries through end to end, no half-measures or “WEM-flavored” variants
  • Nothing breaks for any customer mid-shift

I started the port at the beginning of 2026. The work is solo on the design side and effectively solo on the engineering side — one developer reviews my code, but the WEM team is busy with their own roadmap and hasn't been able to contribute to the port itself.

Foundation-first, not surface-by-surface

You can port a design system into a hostile codebase three ways. Surface by surface, doing the whole screen at once. Opportunistic, where features that touch a surface get the new patterns. Or foundation-first: bring the type system, color tokens, and icon set in once, then ship components on top of the new foundation in priority order.

I picked foundation-first. The reason is mechanical. WEM has hundreds of screens. Going surface-by-surface would mean making the same type, color, and icon swap on every one — the same change repeated, every screen carrying its own regression risk. Opportunistic was slower than the time pressure allowed.

Foundation-first inverts the work. Tokens and fundamentals land once. Then components land in parallel — button, input, select, date picker, radio, checkbox, table, prioritized by surface coverage. The component work moves fast because I use the Figma MCP server to reference Facet directly, translating WEM's existing hardcoded styles against the design system in the loop instead of pattern-matching by hand.

Here's the payoff. Once color landed, half the battle for any component was already won. Spacing, padding, and border tuning was the remaining work — measurable, mechanical, doable in passes. Without consistent color tokens underneath, every component would have required individual color judgment per surface. With them, the work moves.

Same JSON, two consumers

The Figma plugin — figma-token-export — emits figma-tokens.json. Facet's Vue build consumes it directly. WEM's Less codebase needs the same values but can't read JSON.

I wrote a transform — transform-facet-token.js — that walks figma-tokens.json and emits facet-tokens.less, which compiles to facet-tokens.css. Less variable names derive algorithmically from the JSON paths, so a token added in Figma becomes a Less variable on the next build without a manual mapping table. facet-tokens.css is consumed by vars.less, which cascades into the 50+ Less files spread throughout WEM.

Single source of truth, two consumers, no parallel token sources to drift apart. When a Figma color changes, the next build threads that value into Vue, Storybook, and WEM through the same pipeline.

The trade: I own this transform too. But the alternative — two separate token sources, one per stack — would have meant manual sync at every Figma change. A small custom script is cheaper than living with drift.

Fighting WEM's CSS

WEM uses Kendo UI as its underlying component library. Most of the time you don't see it — until you try to restyle something.

Take the schedule editor toolbar. Kendo ships a base toolbar component with its own theme. WEM overrides that with toolbar-specific styles. Individual features then override those further with per-feature CSS to shape the toolbar for specific surfaces. By the time Facet tries to land on top, four layers are cascading at any element: Kendo defaults, WEM's toolbar overrides, feature-level overrides, and the Facet target.

Restyling means threading through that noise. For each Facet target — the new button, the new input, the new toolbar — I have to find every existing override, decide which are intentional design decisions worth preserving versus accidental cruft, and ship CSS that defeats them without blasting the page with !important. The discipline matters because the next feature shouldn't have to defeat me in turn.

What I cut

Anything UX. WEM users have decades of muscle memory in the existing flows. The port is a visual refresh, full stop — same buttons in the same places, same workflows, same modals, same column orders. Just the new Facet visual language underneath.

The temptation to fix UX while you're already in the code is real. I'm not taking it. UX changes are a separate scope, with their own customer-facing risk, and conflating them with a visual port would make both harder to ship and harder to roll back if something broke.

Where it is now

Targeting a Q4 2026 release. Fundamentals are merging; components are queued behind them in priority order. Enterprise product release cycles run on quarters, not sprints — which means the new visual language lands gradually across deploys, not as a single rebrand moment.

The mistake I'd undo

The work started in January 2026, but I couldn't merge anything until May. WEM was mid-release; my port had to wait until that one shipped. So I built foundations and components in branches that sat for four months. By the time the May release went out, the merge queue had accumulated, and reviewing it back-to-back was harder on the reviewer than it had to be. I broke things down as best I could — foundation PRs first, then one per component, then per-surface adjustments — but the bottleneck was real.

If I started over, I'd time the port to follow a release window, not lead one. The foundation work could have started at the merge gate instead of months ahead of it. Branched work for clarity is fine; branched work for four months is expensive on everyone else's review bandwidth.