SYSTEM DESIGN
FRONT-END DEVELOPMENT
Shifting the paradigm from canvas to codebase
A UX-led migration of OpenText's Design System into a repo-native, agentic authoring workflow.
Suggested insights
Identify Figma source node
Select Blueprint V1 component flagged for migration.
Extract via
figma-consoleMCPPull raw node tree, bindings, and property definitions.
Author JSON contract
Capture anatomy, tokens, states, variants, and anomalies.
Lint gate one
verify_all.pyvalidates node integrity against token dictionary.ksc-usecase-card.contract.json
{
"component": "ksc-usecase-card",
"type": "component",
"version": "1.2.0",
"anatomy": {
"root": "card-container",
"elements": ["heading", "body", "cta"]
},
"boundVariables": {
"cta.background": "var(--aurora-action-primary-background)",
"cta.text": "var(--aurora-action-primary-text)",
"body.spacing": "var(--space-md)"
},
"states": ["default", "hover", "focus"],
"verified": true
}
Jira insights — migration pipeline
Avg. ticket turnover
Last 90 days
Time from ticket open to merge.
Basline
4.2 days
Current
2.1 days
Delta
50%
Weekly cycle time
Baseline
Post-Workflow
W1
W2
W3
W4
W5
W6
W7
W8
verify_all.py - lint gate two
#Card-useCase
1 issue detected
Status: Failed
Rule violated
Hardcoded value in slot bound to a semantic token in the dictionary.
background: #FF6B35;
background: var(--aurora-action-primary-background);
ksc-usecase-card.module.css : line 24
OpenText's Blueprint V1 design system had reached an inflection point. What was once a flagship Figma library serving as a centralized source of truth for the brand's atomic makeup had steadily drifted due to its inability to scale at the pace of rapid development.
Necessary maintenance protocols such as auditing for redundancies, identifying informed use cases for net new patterns, and spec documentation fell into the hands of a UX team already operating at capacity upstream, resulting in a forced culture of ad-hoc updates and a steadily growing queue of undocumented conventions.
With the organization setting its sights on a revitalized Design System as a bi-product of a wider brand restructure in 2026, my role as Lead UX Designer of AI-Enabled Systems was collaborating with Front-End engineering teams to conceptualize and implement an agentic two-stage migration workflow that automated the transition from canvas to codebase.
Learn how we reduced Jira ticket turnover windows by approximately 50% with a code-first framework that positioned Storybook as our unified source of truth for extraction and scale, increasing determinism, eliminating rogue LLM interpretation, and enabling rapid refinement and scale.
State of the system
Blueprint V1 was born inside Figma at a time when the discipline of maintaining a canonical library required the maintenance itself to live inside the file. Every component our product surfaces referenced traced back to a master node, and every net-new pattern was authored, versioned, and documented in-canvas by the UX team. Compounding the drift, the underlying V1 Front-End rested on custom CSS with no utility foundation, no shared token dictionary, and no formal nomenclature to distinguish a component (a single reusable atomic unit) from a pattern (a compositional arrangement of several components serving a specific job). Designers and engineers applied the same term to structurally different constructs across working conversations, resulting in ambiguity that made system authoring harder to reason about and harder to scale in any consistent direction.
My mandate was to lead the UX team through the transition architecturally: identifying the workflow efficiencies that would smooth the transfer of authoring conventions from Figma into the codebase, and co-designing, in collaboration with Front-End engineering, the workflows that would allow designers to operate confidently inside a repo-native environment without being asked to adopt the traditional obligations of a software engineer.
Contracts before code: the migration workflow
Conventional practice, when converting a Figma component into code, is to prompt an LLM into interpretation of the source file. Interpretation is the layer where rogue LLM behaviour, hallucinated tokens, and hardcoded values are introduced, and no volume of prompt engineering adequately resolves what is fundamentally a structural problem. The migration workflow we architected removes the interpretation step altogether by inserting a machine-checkable intermediary between Figma and the React code that references it: a JSON contract, authored into token-dictionary/contracts/, that captures a component's real anatomy, its live token bindings, its property definitions, and any known anomalies in the source file. Every downstream step is verified against the contract rather than against an LLM's evolving memory of what the component should look like.
Figma source
Legacy Blueprint V1 component identified in the existing Figma library and flagged for migration into Storybook.
Extract source (transition)
Live extraction
Figma-console MCP, running via Figma's Desktop Bridge Plugin API, pulls the raw node tree, every boundVariables binding, and every componentPropertyDefinitions entry directly from the source file. Bypasses the pre-resolved output of the official Figma MCP to preserve raw evidence for verification.
Author against extraction (transition)
JSON contract authoring
Claude Code authors a structured contract into token-dictionary/contracts/, capturing the component's anatomy, live token bindings, states, real variants, and any known anomalies in the source.
Contract complete (gate)
Lint gate one
Verify_all.py runs a paired verification, validating the generated token CSS and the contract's internal integrity against the token dictionary before a single line of React is written.
Lint pass required (gate)
Component build
Claude Code, working directly in the repo, authors the React .tsx implementation and its scoped CSS module against the contract, alongside a matching Storybook stories file.
Render in browser (transition)
Browser render check
The built component renders in a live browser session and is compared, element by element, against a Figma screenshot of the same node captured through the figma-console MCP.
Parity confirmed (gate)
Lint gate two
Verify_all.py runs a second time, re-checking the finished component against its contract and its rendered output. Any deviation returns the component to Node 5 for correction.
Clean pass (gate)
Merge to Storybook
Clean-pass component merges into the shared Storybook library through GitHub, four files intact: contract, .tsx, CSS module, and stories file.
Correction loop
The pipeline moves through eight sequential steps: live extraction, contract authoring, first lint gate, component build in React and Storybook, browser render check against a Figma screenshot, second verification pass, correction loop for any deviation, and merge into Storybook. Extraction is executed through the figma-console MCP via Figma's Desktop Bridge Plugin API, deliberately bypassing the pre-resolved output of the official Figma MCP so that raw evidence remains available for downstream verification. The first lint gate runs verify_all.py, pairing two checks: one validating the generated token CSS, and one validating the component's markup against its own contract. Only a clean pass merges.
An end-to-end example makes the shape concrete. During the migration of #ksc-usecase-card, live extraction returned every real token binding from the source file, and the JSON contract was authored against that extraction. At the component build step, the LLM's initial React implementation introduced a hardcoded hex value on the card's primary call-to-action background; a slot where the contract had explicitly bound the value to var(--aurora-action-primary-background), a semantic token from the Aurora theme extension. The first lint gate fired immediately, flagging the raw hex against the rule that no hardcoded value is permitted in any slot where a semantic token already exists in the dictionary. The contract supplied the correct binding, the correction was mechanical rather than judgement-based, and the corrected build cleared the second verification pass, matched the Figma render, and merged. The linter caught the rogue LLM interpretation at the exact junction where it would otherwise have shipped as production code.
The pipeline moves through eight sequential steps: live extraction, contract authoring, first linCross-functional collaboration with Front-End engineering was concentrated at the output layer. Together, we finalized the four-file scaffold every migrated component now ships with: a JSON contract, a .tsx React implementation, a scoped CSS module, and a Storybook stories file. The scaffold ensures each component is optimized for Storybook hosting rather than delivered as an isolated HTML and CSS artifact, giving the migration a consistent target for every step in the pipeline to be measured against.
The code-first horizon: post mirgation workflow
The migration workflow is currently the daily driver. Once every Blueprint V1 component has moved through it, a second workflow takes over. Figma is no longer the default entry point for new work; it becomes a tertiary exploration surface, reserved for highly stateful patterns whose logic is more efficiently reasoned about visually, of which the navigation mega-menu is our present example. Everything else begins in the codebase.
Content brief
Content team delivers new material for a page or surface.
Pattern research config
Research
Best-in-class interaction pattern audit via Mobbin MCP, contextual to where the content will live, appended by existing insights from live pages via Microsoft Clarity.
Prompt drafting
Claude in repo
React component drafted directly against the codebase, lands in Storybook on a feature branch.
First draft review
UX audit
Design intent reviewed against the drafted component; iterations proposed if required by stakeholders.
Formalize spec docs
JSON contract
Contract authored or updated to reflect the finalized structure, lives inside the component folder as persistent reference.
Front-End handoff
Front-End fine-tune
Implementation polished in the same branch, contract-aligned.
QA gate
QA and staging
Component validated in staging before release.
Correction loop
For the sake of transparency, the flow illustrated below is prospective rather than reported: the post-migration workflow has not yet processed a real component end-to-end. When it does, the sequence follows a predictable arc. The Content team delivers new material for a page. Mobbin, accessed via MCP, is queried for best-in-class interaction pattern precedent contextual to where the content will sit. Microsoft Clarity is consulted against the outgoing page, and its real click, scroll, and attention data informs which elements warrant prioritization, compression, or elimination entirely. A standardized template prompt is then used to ask Claude, working directly in the repo, to draft a React component reflecting the intended treatment; the component lands in Storybook on a feature branch. UX audits the result, the corresponding JSON contract is authored or updated to reflect finalized structure, with Front-End engineering fine-tuning the implementation in the same branch before the component proceeds through QA, staging, and final production.
Notably, the JSON contract's role shifts between the two workflows. In the migration workflow, it operates as a precondition to code: authored and verified before any implementation exists. Post-migration, it lives inside each component's own folder and is kept in lockstep with every subsequent edit; a persistent, structured reference that an LLM session parses before touching an existing implementation, ensuring a fresh interpretation of the underlying code cannot reintroduce the rogue interpretation risk the project set out to eliminate.
Naming as architecture
The naming problem registered as the smaller of the two crises on paper and the larger in practice. Every component and pattern in V1 was named after what currently filled it rather than the job it performed. Bento was named after a visual layout metaphor. Three Pillar Narrative was named after a count that ceased to be accurate the moment a fourth pillar was added. Use Case Gateway Card was named as though it routed somewhere, when in practice it was a static proof grid with no navigation logic embedded. Appearance-based nomenclature offers designers almost no context for when to reach for a given component, and the name itself breaks the moment its content evolves
Research findings - naming convention audit
Anatomy of three published conventions
A competitive audit of Atlassian, IBM Carbon and Nord Design systems.
Prefix
Component
Modifier
State
Prop
Atlassian Design System
PascalCase Component + appearance prop
React Import
Button
Component
CSS Classs
aui
button
primary
React Import
appearance="primary"
appearance="subtle"
appearance="link"
appearance="warning"
IBM Carbon
PascalCase Component + kind prop
React Import
Button
Component
Compound
primary
Modifier
button
Base noun
CSS Class
cds
btn
primary
Variants
kind="primary"
kind="secondary"
kind="tertiary"
kind="ghost"
kind="warning"
Nord Health
Three-prefix system
Web Component
nord
Prefix
Button
Component
Modifier Class
.n
Prefix
button
Base noun
primary
Modifier
State Class
.is
State Prefix
loading
Status
React Import
kind="primary"
kind="secondary"
kind="tertiary"
kind="ghost"
kind="warning"
State (hover, focus, disabled, active, loading) is a switch on the component, expressed through props or a dedicated state class. Component state is never encoded into the component name.
Research into three published Design Systems informed the resolution. I studied Atlassian, IBM Carbon, and Nord Health directly; examining their live Figma libraries and their published documentation rather than deferring to secondhand summaries. Atlassian's convention follows [Modifier] [Base Noun], with every meaningfully different component receiving its own dedicated name. IBM Carbon's shipped code adopts [Modifier][BaseNoun], favouring a single component with built-in options wherever variance is cosmetic rather than structural. Nord Health applies {prefix}-{name}, with modifiers applied through a separate class and states granted their own distinct prefix altogether. Convergence occurred on one absolute rule across all three systems: state, whether hover, focus, disabled, active, or loading, is a switch on the component and is never encoded into the name.
Keystone's grammar, adopted for the new system's component library, is #ksc or #ksp followed by the modifier, followed by the base noun. #ksc denotes a component; #ksp denotes a pattern. The modifier is the role or job that distinguishes a given variant from its siblings. The base noun is what the object fundamentally is, and it survives a full content swap without requiring rename. Underpinning the grammar is the three-layer token architecture that grants semantic names their real values: a Tailwind foundation of 407 variables at the base, a Themes semantic layer of 333 variables aliasing those foundation values, and per-sub-brand theme extensions (Aurora, OT Digital, and Cyber Security) that inherit the Themes collection and store only what they actually override.
Original nomenclature
Revised nomenclature
What's next?
