15 KiB
15 KiB
Atomic Design Architecture Reference
Enterprise-scale UI Kit organization using Atomic Design methodology for Pencil.
Overview
Problem: Large monolithic .pen files (5000+ lines) cause:
- ❌ Slow performance (2-3 second load times)
- ❌ Maintenance challenges (duplicate components)
- ❌ Collaboration bottlenecks (merge conflicts)
- ❌ Poor reusability
- ❌ Difficult to scale for enterprise applications
Solution: Atomic Design Hierarchy - Industry standard for enterprise UI Kits
Atomic Design Structure
project-name/
├── src/
│ ├── foundations/
│ │ └── design-tokens.pen # Design system variables
│ │
│ ├── atoms/ # Smallest building blocks
│ │ ├── buttons.pen # All button variants & states
│ │ ├── inputs.pen # Text fields, checkboxes, radio
│ │ ├── badges.pen # Badges, chips, pills, tags
│ │ ├── icons.pen # Icon library (if custom)
│ │ └── typography.pen # Headings, body text, labels
│ │
│ ├── molecules/ # Combinations of atoms
│ │ ├── form-fields.pen # Label + Input + Error
│ │ ├── search-bar.pen # Input + Icon + Button
│ │ ├── card-headers.pen # Icon + Title + Badge
│ │ └── navigation-items.pen # Icon + Text + Badge
│ │
│ ├── organisms/ # Complex UI sections
│ │ ├── cards.pen # Feature, pricing, step cards
│ │ ├── navigation.pen # Top nav, sidebar, mobile menu
│ │ ├── headers.pen # Page & section headers
│ │ ├── footers.pen # Footer variants
│ │ └── forms.pen # Complete form layouts
│ │
│ ├── templates/ # Page layouts (optional)
│ │ ├── dashboard-layout.pen
│ │ ├── landing-layout.pen
│ │ └── auth-layout.pen
│ │
│ └── pages/ # Complete pages
│ ├── desktop-home.pen
│ ├── mobile-home.pen
│ └── tablet-home.pen
│
├── build/ # Build output (gitignore)
├── scripts/
│ └── build.py # Build script
├── pencil.config.json
└── USAGE_GUIDE.md
Why Atomic Design?
Benefits
- ✅ Industry Standard - Used by Figma, Material Design, Ant Design
- ✅ Maximum Scalability - Easy to add components at any level
- ✅ Clear Hierarchy - Atoms → Molecules → Organisms → Templates → Pages
- ✅ Team Collaboration - Different designers own different atomic levels
- ✅ Reusability - Components compose naturally from smaller pieces
- ✅ Discoverability - Intuitive folder structure for finding components
- ✅ Maintainability - Small, focused files (<500 lines each)
- ✅ Version Control - Minimal merge conflicts with parallel work
Recommended For
- ✅ Enterprise applications with 50+ components
- ✅ Design systems shared across multiple products
- ✅ Teams of 3+ designers working in parallel
- ✅ Long-term maintenance (2+ years)
- ✅ Component documentation & showcases
- ✅ Cross-platform design consistency
Component Naming Convention
Atomic Design uses strict hierarchical naming:
{AtomicLevel}/{Component}/{Variant}/{State}
Atoms (Smallest Building Blocks)
Atom/Button/Primary/Default
Atom/Button/Primary/Hover
Atom/Button/Primary/Disabled
Atom/Button/Secondary/Default
Atom/Badge/Section/Default
Atom/Input/Text/Default
Atom/Input/Text/Error
Atom/Input/Text/Disabled
Molecules (Combinations of Atoms)
Molecule/FormField/Text/Default
Molecule/FormField/Text/WithError
Molecule/SearchBar/Default
Molecule/SearchBar/Focused
Molecule/CardHeader/WithIcon
Molecule/CardHeader/Plain
Organisms (Complex UI Sections)
Organism/Card/Feature/Default
Organism/Card/Pricing/Enterprise
Organism/Navigation/Desktop/Default
Organism/Navigation/Mobile/Collapsed
Organism/Navigation/Mobile/Expanded
Organism/Footer/TwoColumn/Default
Organism/Footer/FourColumn/Default
Naming Rules
- ✅ Always include atomic level (Atom/Molecule/Organism)
- ✅ Use PascalCase for all parts
- ✅ Include variant even if only one exists (use "Default")
- ✅ Add state for interactive components (Default/Hover/Active/Focus/Disabled/Loading)
- ✅ Be descriptive - Name should explain purpose without seeing component
Component States & Variants
Interactive Component States
Every interactive component should have states:
Button/Primary/
├── Default # Resting state
├── Hover # Mouse over
├── Active # Pressed/clicked
├── Focus # Keyboard focus
├── Disabled # Non-interactive
└── Loading # Processing state (with spinner)
Implementation Example
// Default state
{
"type": "frame",
"id": "BtnPrimary_Default",
"name": "Atom/Button/Primary/Default",
"reusable": true,
"fill": {
"type": "gradient",
"colors": [
{"color": "#FF5C00", "position": 0},
{"color": "#FF8A4C", "position": 1}
]
}
}
// Hover state - slightly brighter
{
"type": "frame",
"id": "BtnPrimary_Hover",
"name": "Atom/Button/Primary/Hover",
"reusable": true,
"fill": {
"type": "gradient",
"colors": [
{"color": "#FF6E1A", "position": 0},
{"color": "#FF9C66", "position": 1}
]
}
}
// Disabled state - reduced opacity
{
"type": "frame",
"id": "BtnPrimary_Disabled",
"name": "Atom/Button/Primary/Disabled",
"reusable": true,
"fill": "#6B6B70",
"opacity": 0.5
}
Responsive Variants
Organism/Navigation/
├── Desktop/
│ ├── Default # Full horizontal nav with all items
│ └── Scrolled # Sticky/collapsed on scroll
├── Tablet/
│ ├── Default # Hybrid with some collapsed items
│ └── MenuOpen # Sidebar drawer
└── Mobile/
├── Collapsed # Hamburger icon only
└── Expanded # Full-screen menu overlay
Design Tokens Foundation
design-tokens.pen Structure
{
"version": "2.6",
"children": [{
"type": "frame",
"name": "Design Tokens Reference",
"layout": "vertical",
"gap": 20,
"children": [
{
"type": "text",
"content": "Design System Tokens",
"fontSize": 32,
"fill": "$text-primary"
}
]
}],
"variables": {
// Colors - Semantic naming
"bg-page": {"type": "color", "value": "#0A0A0B"},
"bg-surface": {"type": "color", "value": "#1A1A1C"},
"bg-elevated": {"type": "color", "value": "#222225"},
"text-primary": {"type": "color", "value": "#FFFFFF"},
"text-secondary": {"type": "color", "value": "#ADADB0"},
"text-tertiary": {"type": "color", "value": "#8B8B90"},
"orange-primary": {"type": "color", "value": "#FF5C00"},
"orange-light": {"type": "color", "value": "#FF8A4C"},
"border-default": {"type": "color", "value": "#3B3B40"},
"border-subtle": {"type": "color", "value": "#27272A"},
// Typography
"font-primary": {"type": "string", "value": "Roboto"},
"text-xs": {"type": "number", "value": 11},
"text-sm": {"type": "number", "value": 13},
"text-base": {"type": "number", "value": 14},
"text-lg": {"type": "number", "value": 16},
"text-xl": {"type": "number", "value": 18},
"text-2xl": {"type": "number", "value": 24},
"text-3xl": {"type": "number", "value": 32},
// Spacing (8px grid)
"space-1": {"type": "number", "value": 4},
"space-2": {"type": "number", "value": 8},
"space-3": {"type": "number", "value": 12},
"space-4": {"type": "number", "value": 16},
"space-5": {"type": "number", "value": 20},
"space-6": {"type": "number", "value": 24},
"space-8": {"type": "number", "value": 32},
"space-10": {"type": "number", "value": 40},
// Border Radius
"radius-sm": {"type": "number", "value": 6},
"radius-md": {"type": "number", "value": 10},
"radius-lg": {"type": "number", "value": 16},
"radius-full": {"type": "number", "value": 100},
// Breakpoints
"breakpoint-mobile": {"type": "number", "value": 390},
"breakpoint-tablet": {"type": "number", "value": 768},
"breakpoint-desktop": {"type": "number", "value": 1440}
}
}
Extraction Workflow
Step 1: Audit Components
# Analyze current structure
grep '"name":' tPOS-ui-kit.pen | grep -i "button" > buttons-list.txt
grep '"name":' tPOS-ui-kit.pen | grep -i "badge" > badges-list.txt
grep '"name":' tPOS-ui-kit.pen | grep -i "card" > cards-list.txt
# Count components by category
echo "Buttons: $(grep -c button buttons-list.txt)"
echo "Badges: $(grep -c badge badges-list.txt)"
echo "Cards: $(grep -c card cards-list.txt)"
Step 2: Create Structure
mkdir -p src/foundations src/atoms src/molecules src/organisms src/pages
Step 3: Extract to Atomic Files
The pencil-design skill now includes an automated extraction tool.
# Run the extraction script
python3 scripts/extract-atomic.py
This script will:
- Read
src/components/tPOS-ui-kit.pen(or configured library) - Extract design tokens to
src/foundations/design-tokens.pen - Categorize components into
src/atoms,src/molecules,src/organisms - Generate showcase wrappers for each file
Customization:
Edit scripts/extract-atomic.py to adjust categorization logic (regex patterns) if your component names differ.
Step 4: Create Showcase Files
import json
from pathlib import Path
for atomic_dir in ['src/atoms', 'src/molecules', 'src/organisms']:
for filepath in Path(atomic_dir).glob('*.pen'):
with open(filepath, 'r') as f:
data = json.load(f)
# Wrap components in a showcase page
showcase = {
'type': 'frame',
'name': f'{filepath.stem.title()} Showcase',
'width': 1440,
'fill': '$bg-page',
'layout': 'vertical',
'gap': 80,
'padding': [80, 120],
'children': data['children']
}
data['children'] = [showcase]
with open(filepath, 'w') as f:
json.dump(data, f, indent=2)
print(f'✅ Added showcase to {filepath}')
Step 5: Validate Structure
import json
import os
from pathlib import Path
required_structure = [
'src/foundations/design-tokens.pen',
'src/atoms',
'src/molecules',
'src/organisms'
]
for path in required_structure:
if not os.path.exists(path):
print(f'❌ Missing: {path}')
else:
if path.endswith('.pen'):
with open(path, 'r') as f:
data = json.load(f)
assert 'version' in data
assert 'variables' in data
print(f'✅ Valid: {path}')
else:
files = list(Path(path).glob('*.pen'))
print(f'✅ {path}: {len(files)} files')
print('\n🎉 Atomic Design structure validated!')
Best Practices
- Foundations First - Design tokens (
design-tokens.pen) is single source of truth - Build Bottom-Up - Atoms → Molecules → Organisms → Templates → Pages
- Component States - Every interactive component needs ≥3 states (default/hover/disabled)
- Naming Consistency - Strict format:
{Level}/{Component}/{Variant}/{State} - File Organization - Each atomic level in separate folder (
src/atoms/,src/molecules/) - Token Synchronization - Copy
variablesobject fromdesign-tokens.pento all files - Showcase Pages - Each atomic file needs showcase page to demo components
- No Cross-Contamination - Atoms don't reference molecules, molecules don't reference organisms
- Reusable Flag - Set
"reusable": truefor all reusable components - Responsive Variants - Create variants for Desktop/Tablet/Mobile (not breakpoint logic in Pencil)
- Documentation - Document component props, states, usage in USAGE_GUIDE.md
- Version Control:
- Commit:
src/(all atomic files) - Gitignore:
build/(generated files) - Tag releases:
v1.0.0for breaking changes in design tokens
- Commit:
- Component Library - Update atomic files before building pages
- Validation - Validate JSON structure after extraction
- Backup Strategy - Keep
original.pen.backupbefore refactoring to Atomic Design
Usage Guide Template
# [Project] Design System - Atomic Design Structure
## Structure Overview
\`\`\`
src/
├── foundations/
│ └── design-tokens.pen # Colors, typography, spacing, breakpoints
├── atoms/ # Smallest building blocks
├── molecules/ # Simple combinations
├── organisms/ # Complex components
└── pages/ # Complete pages
\`\`\`
## Atomic Levels
### Foundations
- **File**: `design-tokens.pen`
- **Contains**: CSS variables, color palette, typography scale, spacing system
- **Usage**: Copy variables to all component files
### Atoms
- **Examples**: Buttons, inputs, badges, icons, typography
- **Characteristics**: Cannot be broken down further
- **States**: Default, Hover, Active, Disabled
### Molecules
- **Examples**: Form fields, search bars, card headers
- **Characteristics**: Combinations of 2-3 atoms
- **Usage**: Import atoms and compose
### Organisms
- **Examples**: Cards, navigation, headers, footers
- **Characteristics**: Complex sections with multiple molecules
- **Usage**: Complete, reusable UI sections
## Workflow
1. **Update Foundation**: Edit `design-tokens.pen` for colors/typography changes
2. **Build Components**: Edit atomic files with proper naming (Atom/Button/Primary/Default)
3. **Update Library**: Run `python3 scripts/build.py --library` to compile atoms
4. **Compose Up**: Molecules use atoms, organisms use molecules
5. **Test in Pages**: Reference components in page files (from compiled library)
6. **Build Monolith**: Run `python3 scripts/build.py -m` for production output
## Component Naming
\`\`\`
{Level}/{Component}/{Variant}/{State}
Examples:
- Atom/Button/Primary/Default
- Molecule/FormField/Text/WithError
- Organism/Card/Feature/Default
\`\`\`
## Best Practices
1. ✅ **Design Tokens First**: Always update foundation before components
2. ✅ **Build Up**: Atoms → Molecules → Organisms → Pages
3. ✅ **Consistent States**: All interactive components need states
4. ✅ **Reusable**: Set `"reusable": true` on all shareable components
5. ✅ **Version Control**: Commit src/ files, gitignore build/