A multi-design-system monorepo with theming and experimental components built on React, TypeScript, and modern web technologies.
This project is a monorepo that contains multiple design systems, shared tokens, a theme engine, and UI primitive and core components. It's designed to showcase how different design aesthetics can coexist while sharing a common underlying architecture with proper package separation.
The component library has been moved from apps/component-library/ to proper packages:
π― UI Primitive Package (@origin-art/ui-primitive)
- Button component with 5 variants (primary, secondary, outline, text, ghost)
- 3 sizes (sm, md, lg)
- Full theme integration using CSS custom properties
- Complete Storybook documentation with all variants and examples
π― UI Core Package (@origin-art/ui-core)
- ThemeSwitcher component re-exported from theme-engine
- Theme engine re-exports for convenience
- Complete Storybook documentation with examples
π― Updated Playground App
- Changed imports to use new packages instead of component-library
- Maintains all functionality with proper theme switching
β Proper Package Architecture - Components follow intended hierarchy (primitives β core β apps) β Clean Separation - UI primitives and core components are in separate packages β Better Reusability - Primitives can now be used independently β Future-Proof - Easy to add new primitives and core components β Theme Integration - All components properly use design token system β TypeScript Support - Full type safety for all components and props
- Playground app running at
http://localhost:3003/ - All packages build successfully with TypeScript support
- Theme switching working between Minimal β Rough design systems
- Button components working in all variants and sizes
graph TB
subgraph "Monorepo Root"
Root[package.json<br/>pnpm-workspace.yaml<br/>turbo.json]
end
subgraph "Token Packages"
Core[tokens-core<br/>Type definitions<br/>Token utilities]
Minimal[tokens-minimal<br/>Clean, minimal design]
Rough[tokens-rough<br/>Hand-drawn aesthetic]
end
subgraph "Theme Engine"
ThemeEngine[theme-engine<br/>ThemeProvider<br/>useTheme hook<br/>ThemeSwitcher]
end
subgraph "Component Library"
ComponentLib[component-library<br/>UI Components<br/>Storybook docs]
end
subgraph "Applications"
Playground[playground<br/>Demo app<br/>Theme showcase]
end
Core --> Minimal
Core --> Rough
Minimal --> ThemeEngine
Rough --> ThemeEngine
ThemeEngine --> ComponentLib
ComponentLib --> Playground
Root -.-> Core
Root -.-> Minimal
Root -.-> Rough
Root -.-> ThemeEngine
Root -.-> ComponentLib
Root -.-> Playground
graph LR
subgraph "packages/"
CorePkg[tokens-core]
MinimalPkg[tokens-minimal]
RoughPkg[tokens-rough]
ThemePkg[theme-engine]
end
subgraph "apps/"
ComponentPkg[component-library]
PlaygroundPkg[playground]
end
CorePkg --> MinimalPkg
CorePkg --> RoughPkg
MinimalPkg --> ThemePkg
RoughPkg --> ThemePkg
ThemePkg --> ComponentPkg
ComponentPkg --> PlaygroundPkg
graph TD
subgraph "Token Core Layer"
Types[TypeScript Interfaces<br/>SemanticTokens, ColorRole, etc.]
Factory[createSemanticTokens<br/>Token factory function]
Defaults[Default Values<br/>Fallback tokens]
end
subgraph "Design System Implementations"
MinimalTokens[Minimal Tokens<br/>Clean, modern design]
RoughTokens[Rough Tokens<br/>Hand-drawn aesthetic]
end
subgraph "Theme Resolution"
LightMode[Light Theme]
DarkMode[Dark Theme]
end
Types --> Factory
Factory --> MinimalTokens
Factory --> RoughTokens
MinimalTokens --> LightMode
MinimalTokens --> DarkMode
RoughTokens --> LightMode
RoughTokens --> DarkMode
graph LR
subgraph "Semantic Tokens"
Colors[π¨ Colors<br/>bg/page, fg/primary, accent/default]
Spacing[π Spacing<br/>xs, sm, md, lg, xl, 2xl, 3xl]
Radii[β Radii<br/>xs, sm, md, lg, xl, pill]
Typography[π€ Typography<br/>families, sizes, weights, lineHeights]
Shadows[π Shadows<br/>sm, md, lg, xl]
end
subgraph "Design Systems"
MinimalDS[Minimal Design System]
RoughDS[Rough Design System]
end
subgraph "Theme Modes"
Light[Light Mode]
Dark[Dark Mode]
end
Colors --> MinimalDS
Spacing --> MinimalDS
Radii --> MinimalDS
Typography --> MinimalDS
Shadows --> MinimalDS
Colors --> RoughDS
Spacing --> RoughDS
Radii --> RoughDS
Typography --> RoughDS
Shadows --> RoughDS
MinimalDS --> Light
MinimalDS --> Dark
RoughDS --> Light
RoughDS --> Dark
sequenceDiagram
participant App as Application
participant TP as ThemeProvider
participant TC as ThemeContext
participant DOM as Document DOM
participant Tokens as Token Packages
App->>TP: Initialize with designSystem + mode
TP->>Tokens: Load tokens based on designSystem
Tokens-->>TP: Return SemanticTokens
TP->>TP: Create ResolvedTheme object
TP->>TC: Update context value
TP->>DOM: Set CSS custom properties
loop Token Application
TP->>DOM: Set --color-* variables
TP->>DOM: Set --spacing-* variables
TP->>DOM: Set --radius-* variables
TP->>DOM: Set --font-family-* variables
TP->>DOM: Set --font-size-* variables
TP->>DOM: Set --font-weight-* variables
TP->>DOM: Set --line-height-* variables
end
App->>TP: Theme change request
TP->>Tokens: Load new tokens
TP->>DOM: Update CSS variables
TC-->>App: Notify theme change
stateDiagram-v2
[*] --> Minimal_Light
Minimal_Light --> Minimal_Dark: Toggle Mode
Minimal_Dark --> Minimal_Light: Toggle Mode
Minimal_Light --> Rough_Light: Change Design System
Minimal_Dark --> Rough_Dark: Change Design System
Rough_Light --> Rough_Dark: Toggle Mode
Rough_Dark --> Rough_Light: Toggle Mode
Rough_Light --> Minimal_Light: Change Design System
Rough_Dark --> Minimal_Dark: Change Design System
graph TD
subgraph "Component Library"
Button[Button Component]
StyledButton[Styled Components]
Stories[Storybook Stories]
Types[TypeScript Props]
end
subgraph "Theme Integration"
ThemeProvider[ThemeProvider]
useTheme[useTheme Hook]
CSSTokens[CSS Custom Properties]
end
subgraph "Token Consumption"
ColorTokens[Color Tokens<br/>accent/default, fg/primary]
SpacingTokens[Spacing Tokens<br/>xs, sm, md, lg]
TypographyTokens[Typography Tokens<br/>font-family, font-size]
RadiusTokens[Radius Tokens<br/>md, sm]
end
Button --> StyledButton
Button --> Types
Button --> Stories
StyledButton --> ThemeProvider
StyledButton --> CSSTokens
CSSTokens --> ColorTokens
CSSTokens --> SpacingTokens
CSSTokens --> TypographyTokens
CSSTokens --> RadiusTokens
flowchart TD
Start([Button Render]) --> CheckProps{Check Props}
CheckProps -->|variant='primary'| PrimaryStyle[Primary Styles]
CheckProps -->|variant='secondary'| SecondaryStyle[Secondary Styles]
CheckProps -->|variant='outline'| OutlineStyle[Outline Styles]
CheckProps -->|variant='text'| TextStyle[Text Styles]
CheckProps -->|variant='ghost'| GhostStyle[Ghost Styles]
PrimaryStyle --> SizeCheck{Check Size}
SecondaryStyle --> SizeCheck
OutlineStyle --> SizeCheck
TextStyle --> SizeCheck
GhostStyle --> SizeCheck
SizeCheck -->|size='sm'| SmallSize[Small Padding + Font]
SizeCheck -->|size='md'| MediumSize[Medium Padding + Font]
SizeCheck -->|size='lg'| LargeSize[Large Padding + Font]
SmallSize --> TokenResolution[Resolve CSS Custom Properties]
MediumSize --> TokenResolution
LargeSize --> TokenResolution
TokenResolution --> RenderButton[Render Styled Button]
RenderButton --> End([Complete])
graph TD
subgraph "Root Commands"
Build[pnpm build]
Dev[pnpm dev]
Lint[pnpm lint]
Clean[pnpm clean]
TypeCheck[pnpm type-check]
end
subgraph "Package Dependencies"
CoreBuild[tokens-core build]
MinimalBuild[tokens-minimal build]
RoughBuild[tokens-rough build]
ThemeBuild[theme-engine build]
ComponentBuild[component-library build]
PlaygroundBuild[playground build]
end
subgraph "Build Tools"
TSUP[TSUP - TypeScript bundler]
Vite[Vite - Build tool]
TSC[TypeScript Compiler]
Storybook[Storybook Build]
end
Build --> CoreBuild
Build --> MinimalBuild
Build --> RoughBuild
Build --> ThemeBuild
Build --> ComponentBuild
Build --> PlaygroundBuild
CoreBuild --> TSUP
MinimalBuild --> TSUP
RoughBuild --> TSUP
ThemeBuild --> TSUP
ComponentBuild --> Vite
ComponentBuild --> Storybook
PlaygroundBuild --> Vite
CoreBuild -.-> MinimalBuild
CoreBuild -.-> RoughBuild
MinimalBuild -.-> ThemeBuild
RoughBuild -.-> ThemeBuild
ThemeBuild -.-> ComponentBuild
ComponentBuild -.-> PlaygroundBuild
sequenceDiagram
participant Dev as Developer
participant Root as Root Package
participant Turbo as Turbo
participant Component as component-library
participant Playground as playground
participant Storybook as Storybook
Dev->>Root: pnpm dev
Root->>Turbo: Run dev pipeline
turbo->>Component: Start dev mode
turbo->>Playground: Start dev mode
turbo->>Storybook: Start Storybook
Component-->>Turbo: Dev server ready
Playground-->>Turbo: Dev server ready
Storybook-->>Turbo: Storybook ready
Turbo-->>Dev: All services running
Note over Dev,Storybook: Developer can now:
Dev->>Component: Modify components
Dev->>Playground: Test in playground
Dev->>Storybook: View component docs
- Node.js 18+
- pnpm 9+
# Clone the repository
git clone <repository-url>
cd origin-art
# Install dependencies
pnpm install# Development - starts all apps in watch mode
pnpm dev
# Build all packages
pnpm build
# Type checking
pnpm type-check
# Linting
pnpm lint
# Clean all build outputs
pnpm clean# Build specific token package
pnpm --filter @origin-art/tokens-core build
pnpm --filter @origin-art/tokens-minimal build
pnpm --filter @origin-art/tokens-rough build# Build theme engine
pnpm --filter @origin-art/theme-engine build# Development mode with Storybook
pnpm --filter @origin-art/component-library dev
# Build component library
pnpm --filter @origin-art/component-library build
# Run Storybook
pnpm --filter @origin-art/component-library storybook# Development mode
pnpm --filter @origin-art/playground dev
# Build playground
pnpm --filter @origin-art/playground buildflowchart LR
EditTokens[Edit Token Files] --> BuildCore[Build tokens-core]
BuildCore --> BuildPackages[Build token packages]
BuildPackages --> TestTheme[Test in theme engine]
TestTheme --> TestComponents[Test in components]
TestComponents --> TestPlayground[Verify in playground]
flowchart TD
CreateComponent[Create Component TSX] --> CreateProps[Define Props Interface]
CreateProps --> CreateStyled[Create Styled Component]
CreateStyled --> CreateStories[Write Storybook Stories]
CreateStories --> UpdateExports[Update index.ts exports]
UpdateExports --> TestStorybook[Test in Storybook]
TestStorybook --> TestPlayground[Test in Playground]
TestPlayground --> Build[Build Library]
flowchart TD
DefineTokens[Define Token Values] --> CreatePackage[Create tokens package]
CreatePackage --> ExportTokens[Export tokens object]
ExportTokens --> UpdateThemeEngine[Update theme engine imports]
UpdateThemeEngine --> TestSwitcher[Test theme switcher]
TestSwitcher --> TestComponents[Test with components]
TestComponents --> UpdateDocs[Update documentation]
origin-art/
βββ package.json # Root package config
βββ pnpm-workspace.yaml # PNPM workspace config
βββ turbo.json # Turbo build config
βββ tsconfig.base.json # Base TypeScript config
βββ README.md # This file
β
βββ packages/ # Shared packages
β βββ tokens-core/ # Core token types & utilities
β β βββ src/
β β β βββ index.ts # Type definitions & factory
β β βββ package.json
β β βββ tsconfig.json
β β
β βββ tokens-minimal/ # Minimal design system tokens
β β βββ src/
β β β βββ index.ts # Minimal token definitions
β β βββ package.json
β β βββ tsconfig.json
β β
β βββ tokens-rough/ # Rough design system tokens
β β βββ src/
β β β βββ index.ts # Rough token definitions
β β βββ package.json
β β βββ tsconfig.json
β β
β βββ theme-engine/ # Theme management system
β β βββ src/
β β β βββ ThemeProvider.tsx # Main theme provider
β β β βββ ThemeSwitcher.tsx # Theme switcher component
β β β βββ types.ts # TypeScript types
β β β βββ index.ts # Public exports
β β βββ package.json
β β βββ tsconfig.json
β β
β βββ ui-primitive/ # β
LOW-LEVEL UI BUILDING BLOCKS
β β βββ src/
β β β βββ Button.tsx # β
5 variants, 3 sizes, full theme integration
β β β βββ Button.stories.tsx # β
Complete Storybook docs
β β β βββ index.ts # β
Public exports
β β βββ package.json # β
Proper exports & dependencies
β β βββ tsconfig.json # β
TypeScript configuration
β β
β βββ ui-core/ # β
HIGH-LEVEL COMPOSED COMPONENTS
β βββ src/
β β βββ ThemeSwitcher.tsx # β
Re-export from theme-engine
β β βββ ThemeSwitcher.stories.tsx # β
Complete Storybook docs
β β βββ index.ts # β
Re-exports theme engine
β βββ package.json # β
Proper exports & dependencies
β βββ tsconfig.json # β
TypeScript configuration
β
βββ apps/ # Applications
β βββ experiment-2d/ # 2D Canvas components (not yet implemented)
β βββ experiment-3d/ # 3D Graphics components (Not yet implemented)
β βββ playground/ # β
Demo application
β βββ src/
β β βββ App.tsx # β
Uses new packages instead of component-library
β β βββ main.tsx # Entry point
β βββ index.html
β βββ package.json
β βββ vite.config.ts
β βββ tsconfig.json
- Minimal Design System: Clean, modern aesthetic with professional spacing and typography
- Rough Design System: Hand-drawn, organic aesthetic with playful typography and rough shadows
- Light/Dark Modes: Each design system supports both light and dark themes
- Runtime Switching: Change themes without page reload using CSS custom properties
- Persistent State: Theme choices are maintained in React context
- Styled Components: Uses styled-components for dynamic theming
- Token-Driven: All components use design tokens for consistent styling
- Storybook Documentation: Comprehensive component documentation and examples
- TypeScript Support: Full type safety for all components and props
- Turborepo: Fast, incremental builds with intelligent caching
- TypeScript: Strict type checking across all packages
- Modern Tooling: Vite for fast development and optimized builds
- Package Management: PNPM workspaces for efficient dependency management
The theme engine uses CSS custom properties (CSS variables) to dynamically apply theme values:
/* Generated by ThemeProvider */
:root {
/* Colors */
--color-bg-page: #ffffff;
--color-fg-primary: #111827;
--color-accent-default: #3b82f6;
/* Spacing */
--spacing-xs: 4px;
--spacing-sm: 8px;
--spacing-md: 16px;
/* Typography */
--font-family-body: "Inter", sans-serif;
--font-size-base: 16px;
--font-weight-medium: 500;
/* Radii */
--radius-md: 6px;
--radius-sm: 4px;
}Components access tokens through the theme context:
const StyledButton = styled.button<{ variant: string; size: string }>`
background: ${(props) => props.theme.tokens.colors["bg/surface"]};
padding: ${(props) => props.theme.tokens.spacing.md};
border-radius: ${(props) => props.theme.tokens.radii.md};
font-family: ${(props) => props.theme.tokens.typography.family.body};
`;This approach ensures:
- Runtime Theming: Components automatically adapt to theme changes
- Type Safety: TypeScript ensures correct token usage
- Performance: CSS variables are updated efficiently
- Developer Experience: Autocomplete and error checking for tokens
import {
ThemeProvider,
Button,
ThemeSwitcher,
} from "@origin-art/component-library";
function App() {
return (
<ThemeProvider initialDesignSystem="minimal" initialMode="light">
<div>
<ThemeSwitcher />
<Button variant="primary">Click me</Button>
<Button variant="secondary">Cancel</Button>
</div>
</ThemeProvider>
);
}import { useTheme } from "@origin-art/component-library";
function ThemedComponent() {
const { theme } = useTheme();
return (
<div
style={{
backgroundColor: `var(--color-bg-surface)`,
color: `var(--color-fg-primary)`,
padding: `var(--spacing-md)`,
borderRadius: `var(--radius-md)`,
}}
>
Themed content
</div>
);
}- Token First: Always start with token definitions before components
- Type Safety: Ensure all new code is fully typed
- Storybook Stories: Document all component variations
- Theme Testing: Verify components work in all themes
- Build Verification: Ensure all builds pass before committing
- New Design System: Create new tokens package and update theme engine
- New Component: Follow established patterns with stories and types
- New Token Categories: Update core types and all token packages
- Enhanced Theming: Extend ThemeProvider with new capabilities
This architecture provides a solid foundation for building scalable, themeable design systems that can adapt to different brand identities while maintaining consistent code patterns and developer experience.