Skip to content

Design Systems

How I Build Design Systems

Hands-on work across Ictinus, Pounce, Lungo and ProxyDigest. I connect the needs of a product to its foundations, components and patterns, working closely with engineering.

Experience across four domains

The product comes
before the system.

I start with the people using the product, the work they need to do and the constraints of their industry. Those findings shape what the system needs to support.

OrfiumIctinus
A shared interface language for music rights, from catalog and matching to claims and earnings.
PantherPounce
A dark-first system for security teams working with dense log data, alerts and investigations.
DialecticaLungo
A multi-theme system connecting data-heavy products across internal teams and external audiences.
ProxyFoodsProxyDigest
A system for food and beverage professionals moving from spreadsheets into AI-assisted formulation.
The same building blocks, adapted.
Domain

Design systems with AI enablement

Make the system usable
by people and AI.

I turn the decisions behind the library into shared guidance. Clear examples help people apply it; explicit rules help AI follow it. Both need to understand when to use a component, how it should behave and where it fits. I document that intent alongside the implementation, so new work can be checked against the same standard.

Shared foundations

Semantic tokens and component contracts define a common language for appearance, behavior, accessibility and supported variations.

Guidance for people

Examples and practical guidance explain when to use each component, how it behaves and where it fits.

Instructions for AI

Markdown rules, structured definitions and reusable skills help AI select existing components, compose them and propose extensions.

Reviewed evolution

New work is checked in context. Design and engineering review missing capabilities before they enter the shared system.

Shared knowledge, written for people and AI.One shared design system branches into a Storybook component guide for people and a Markdown rules file for AI. The two routes sit side by side and converge below on one reviewed outcome.One shared systemAaTokens · components · patternsPeopleGuidanceStorybook / ButtonMake the next step clear.ContinueUsage · states · accessibilityAIRulescomponent.rules.mdReuse approved variants.Preserve focus states.action.primaryContinueOne reviewed outcomeShared guidance for people and AI.People use a Storybook component guide with examples and guidance. AI uses component.rules.md with instructions and token references. Both routes lead to a reviewed outcome.One shared systemAaPeopleGuidanceStorybook / ButtonMake the next step clear.ContinueUsage · states · accessibilityAIRulescomponent.rules.mdReuse approved variants.Preserve focus states.action.primaryContinueOne reviewed outcome

From requirements
to production.

Research and engineering requirements set the direction. I choose the foundation that fits, build the token logic, then scaffold and refine the components in Storybook.

Documentation develops alongside the library. I keep the Markdown guidance, custom skills and rules current so agents understand what to build and how to build it.

Engineering reviews every commit. Alpha testing and an experimental, closed beta exercise the edge cases before production. Feedback feeds the backlog and the next round of refinement.

Guidance stays current.mdSkillsRules
Start with the product and the team.

Research sets the direction. Engineering agrees the stack, repository access and a shared backlog.

Base UI / shadcnGitHub / GitLabJira / Asana

What I build:
a clear token model.

Before components, I define how decisions connect. Primitives hold raw values, semantic tokens describe their purpose, and group tokens assign those roles to a component family. This is the three-tier structure I used for Lungo.

Names describe intent. Aliases preserve the relationships. Themes define the visual language; modes adapt it to context, from light and dark to spacing across devices.

A component keeps its role and ownership as its values change. People and AI can trace each decision back to its source.

Theme
Mode
Ready for the next step.One role. Every context.

Trigger example. Studio theme, dark mode. group.trigger.color.fill.action.primary references semantic.color.fill.action.primary, which resolves to primitive color.blue.300, #85B6FF.

How I set it up:
AI with clear rules.

I translate the model into custom prompts: the hierarchy, naming rules, component ownership and required themes and modes. I use Codex and Claude to draft the initial token structure and alias mappings from those constraints.

I refine the prompts against the output, adding examples, resolving ambiguous names and correcting broken references. Each iteration makes the intended logic more explicit.

Style Dictionary turns the reviewed tokens into CSS or Tailwind foundations. I test them in React and Storybook, checking states and contrast with engineering before the changes enter the shared library.

  1. Define the model
    Primitive valueSemantic purposeGroup owner
    HierarchyRules
  2. Write the custom prompt
    custom-prompt.md
    Build from our token model.› Preserve semantic aliases.› Scope by component.› Keep mode mappings.
    CodexClaudeSkills
  3. Draft the token structure
    tokens.json
    { "action.primary": { "$value": "{primitive.color.blue.300}"} }
    JSONTokens
  4. Refine themes and modes
    Light
    Aa
    Dark
    Aa
    One role. Different values.
    AliasesOwnership
  5. Generate the code
    tokens.css
    --action-primary: var(--blue-300);
    bg-action-primary
    Style DictionaryTailwind
  6. Review with engineering
    Button / Primary
    Continue
    States · contrast · ownership
    ReactStorybookGit

Aegis · My experimental design system

A place to put
the principles to work.

I’m building Aegis as an independent case study: a working library where I can develop the foundations, write the components and test how the system holds together.

The experiment connects design decisions, React implementation and a customized Storybook. Each makes the others easier to inspect and refine.

My scope
Token architecture, component design, implementation, documentation and agent instructions.
The question
Can the same rules stay useful from a single control to a complete application?
The output
A component package, an interactive reference and working compositions, evolving together.
Aegis connects foundations, components and application patternsFoundationsColour · space · typeComponentsSave changesReadyPatterns

Every visual decision
has a traceable owner.

I use three token tiers: primitives hold values, semantics give them purpose, and groups assign those roles to component categories.

Clear ownership
A Card uses Surface tokens. The Button inside it keeps its Trigger tokens, wherever the Card places it.
Two themes
Fundamental and Fundamental Floating change the treatment of surfaces, borders and elevation.
Two modes
Light and dark are a separate choice. Spacing, control sizes and typography stay consistent across all four combinations.

Change the presentation without changing the interaction or losing someone’s work.

One height. Three token tiers.

All four theme and mode combinations resolve to the same 34px primitive.

CardSurface tokens
The child keeps
its own contract.
Button 34pxTrigger tokens
Same height in both themes, light and dark.

Show the parts.
Expose the decisions.

I made the component itself the starting point. Numbered anatomy callouts explain its parts; the token mapping shows where its visual decisions come from.

Name each part
The surface, icons, label and loading indicator are connected to the rendered Button through numbered callouts.
Trace each value
A property leads back through its group and semantic role to a primitive and the value resolved for the chosen theme and mode.
Keep it together
Usage, states, accessibility, searchable API details and examples live in the same component reference.
ButtonAnatomy
Action surface

Owns the hit area, intent, emphasis, size and focus state.

From a property to its value
Group tokenSemantic roleValue
Heighttrigger.button.height.regularsize.compact-content.xxs34px
Radiustrigger.button.radius.currentradius.l6px
Gaptrigger.button.gap.compactspace.m8px

Try a change.
See what it changes.

I made the reference a place to try the component. The playground exposes the same choices the implementation supports, so a designer or engineer can inspect a combination before using it.

Independent choices
Intent describes the action; emphasis controls its visual weight. Changing one does not silently change the other.
Real behavior
Size, icons, disabled and loading states use the component’s own rules. Loading keeps its footprint and prevents another activation.
A shared vocabulary
The visible choices map to the public props. The example and the implementation describe the same component.
Button playground
Activate the button to try it.
Intent
Emphasis
Size
State
JSX
<Button
  intent="function" emphasis="primary"
  size="md"
>
  Create project
</Button>
Try the complete playground

Explain the choice.
Make the contract searchable.

I customized the documentation around the questions people bring to a component: when to use it, how it behaves and what the code accepts.

Usage guidance
Action labels, hierarchy and keyboard behavior sit beside the working example, where the guidance can be tried.
States
Ready, disabled and loading are documented as behavior. The reference explains what changes for both the person and the interface.
API from source
Searchable properties, types and explicit defaults come from the TypeScript API. Inherited platform properties remain available in the full reference.
Button referenceGuidelines
Explore

Make the action predictable.

No save action pending.

Label
Use a verb that predicts the result. Use Link when the purpose is navigation.
Hierarchy
Reserve the strongest emphasis for the main action in a group.
Behavior
The default type is button. Set type="submit" explicitly for a form.
Keyboard
Native Enter and Space activation are retained.
Open usage in Storybook

An example should
let you follow the behavior.

I wrote examples around small, complete interactions. They make the less visible parts of the system available to inspect, including validation, asynchronous actions and where focus returns.

Action and recovery
An export offers related formats, blocks duplicate requests while pending and exposes a retryable error when the operation fails.
Connected fields
A label, helper text, error and control share their accessible relationships. The validation example updates them as the value changes.
Continuity
Clearing a field updates its value and returns focus to the input. The person can continue from the same place.
Working examples
Example

One action. Several routes.

Export CSV, open the format menu or try the unavailable-service state.

No export requested

0 requests
Composition
<SplitButton
  onAction={() => exportData("CSV")}
  actions={exportFormats}
>
  Export CSV
</SplitButton>
Run this example in Storybook

Put the components
under real pressure.

Isolated examples only take the system so far. I built a workspace application and richer component presentations to exercise the decisions together.

Connected states
The DataGrid combines search, filters, column controls, selection, bulk updates and editable record details.
Application context
Navigation, forms, tables and panels need to work with real content lengths and responsive layouts.
AI interactions
Local simulations let me explore attached context, stopping, retrying and retaining partial responses before connecting a provider.
  1. Filter
    Needs review
  2. Inspect
    PRJ-01Navigation
    review
  3. Act
    StatusReady
PRJ-01The same record, through every step.

The same contract,
available to agents.

I wrote reusable skills for creating components, tokens and layouts. Storybook presents the actual repository instructions, with the shared design contract included when they are copied.

Start from the system
Inspect existing components, preserve category ownership and carry each semantic role through all four theme and mode combinations.
Keep the boundaries
Headless interaction behavior stays separate from styling. Compositions preserve the contracts of their nested components.
Make it inspectable
Machine-readable component definitions and a token graph sit beside the human reference, giving tools another way to inspect the same system.

The instructions end in review: keyboard behavior, states, resolved values and the composition in context.

Shared design contractOwnership Modes Focus
ImplementationReview
Behavior + APIReuse the interaction boundary. Verify keyboard, states and modes.

Measure the system’s impact over time.

The figures below are outcomes from the Pounce design-system work. They are not measured gains from AI. For AI-assisted contributions, I would also track review effort, rework and recurring system gaps alongside adoption and quality.

50%+
Delivery velocity (Pounce)
30%
Fewer data-processing errors (Pounce)

The metrics I watch

Adoption

Share of UI built with the system.

Compliance

Share of values that are approved tokens, not raw hex.

Coverage

Components and patterns the system actually provides.

Accessibility

Contrast pass rate across supported modes and themes.

Contribution

Activity and number of contributors.

Outcomes

Delivery velocity, rollovers, and error reduction.

Explore the system in Storybook.

See how the token model becomes working components, documented states and reusable patterns in Aegis. Open Storybook to explore the system in context.

Aegis and the related projects are independent explorations of this approach, separate from the historical results above.