Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 17:51:59 +08:00
commit 38e80921c8
89 changed files with 20480 additions and 0 deletions

View File

@@ -0,0 +1,128 @@
# Getting Started with Product Design Skill
5-minute quickstart guide for Navigator's Figma integration.
---
## 1. Install (30 seconds)
```bash
cd skills/product-design
./setup.sh
```
**Expected output**:
```
✅ Setup Complete!
```
If you see errors, check [INSTALL.md](INSTALL.md) for troubleshooting.
---
## 2. Enable Figma MCP (1 minute)
1. Open **Figma Desktop** app
2. **Figma****Preferences** (macOS) or **File****Settings** (Windows)
3. Find "**Enable local MCP Server**"
4. Toggle **ON**
You should see: "MCP server running at http://127.0.0.1:3845/mcp"
---
## 3. Try It (2 minutes)
Open Navigator and say:
```
"Review this Figma design: https://figma.com/file/YOUR_FILE_URL"
```
Navigator will automatically:
- ✅ Connect to Figma Desktop
- ✅ Extract design tokens and components
- ✅ Compare against your codebase
- ✅ Generate implementation plan
- ✅ Create Navigator task document
**Output**:
```
✅ Design review complete for Dashboard Redesign
Generated Documentation:
- Design review: .agent/design-system/reviews/2025-10-22-dashboard.md
- Implementation plan: .agent/tasks/TASK-17-dashboard-redesign.md
Summary:
- Design Tokens: 12 new, 5 modified
- Components: 3 new, 1 to extend
- Estimated Time: 12 hours
- Complexity: Medium
Next Steps:
[1] Start implementation now
[2] Review plan first
[3] Modify plan before starting
```
---
## That's It!
You're ready to use Navigator's product-design skill.
### What You Can Do
**Design Review**:
```
"Review this Figma design: [URL]"
```
**Extract Tokens**:
```
"Extract design tokens from Figma"
```
**Check Design System**:
```
"Check design system impact for [feature]"
```
**Generate Implementation Plan**:
```
"Plan implementation for this design"
```
---
## Troubleshooting
### "Figma Desktop not running"
**Fix**: Start Figma Desktop and enable MCP (see step 2 above)
### "Setup failed"
**Fix**: See detailed guide in [INSTALL.md](INSTALL.md)
### "Can't connect to MCP"
**Fix**: Verify port 3845 is accessible:
```bash
curl http://127.0.0.1:3845/mcp
# Should return JSON (even if error message)
```
---
## Learn More
- **[README.md](README.md)** - Features and architecture
- **[INSTALL.md](INSTALL.md)** - Detailed installation guide
- **[SKILL.md](SKILL.md)** - Complete skill documentation
---
**Time to get started**: 5 minutes
**Ready to use**: Immediately after setup

View File

@@ -0,0 +1,378 @@
# Navigator Product Design Skill - Installation Guide
Quick setup guide for the product-design skill with Figma MCP integration.
---
## Prerequisites
### Required
1. **Python 3.10+**
```bash
python3 --version # Should be 3.10 or higher
```
2. **Figma Desktop App**
- Download: https://www.figma.com/downloads/
- Must be running during design reviews
3. **Figma Account**
- Free or paid account
- Logged into Figma Desktop
### Optional (Enhanced Features)
- **Figma Enterprise** - For Code Connect mappings (automatic component detection)
- **Tailwind CSS** - For design token integration
- **Storybook** - For visual regression testing
---
## Installation Methods
### Method 1: Automatic Setup (Recommended)
Run the automated setup script:
```bash
cd skills/product-design
./setup.sh
```
This will:
1. ✅ Check Python version (3.10+ required)
2. ✅ Create virtual environment
3. ✅ Install dependencies (`mcp>=1.2.1`)
4. ✅ Verify Figma Desktop is running
5. ✅ Test MCP connection
**Expected output**:
```
==========================================
Navigator Product Design Skill - Setup
==========================================
[1/5] Checking Python version...
✅ Python 3.13.7
[2/5] Setting up Python environment...
✅ Virtual environment created
[3/5] Installing Python dependencies...
✅ Dependencies installed (mcp>=1.2.1)
[4/5] Checking Figma Desktop status...
✅ Figma MCP server detected (port 3845)
[5/5] Testing Figma MCP connection...
✅ Successfully connected to Figma MCP server
Found 6 tools:
- get_design_context
- get_variable_defs
- get_code_connect_map
- get_screenshot
- get_metadata
- create_design_system_rules
==========================================
✅ Setup Complete!
==========================================
```
---
### Method 2: Manual Installation
If the automatic script fails or you prefer manual setup:
#### Step 1: Install Python Dependencies
```bash
cd skills/product-design
# Create virtual environment (recommended)
python3 -m venv venv
source venv/bin/activate
# Install dependencies
pip install -r requirements.txt
```
#### Step 2: Enable Figma MCP Server
1. Open **Figma Desktop** app
2. Go to **Figma → Preferences** (macOS) or **File → Settings** (Windows/Linux)
3. Find "**Enable local MCP Server**" option
4. Toggle **ON**
5. You should see confirmation: "MCP server running at http://127.0.0.1:3845/mcp"
#### Step 3: Verify Connection
```bash
cd functions
python3 test_mcp_connection.py
```
**Expected output**:
```
✅ Successfully connected to Figma MCP server
Found 6 tools:
- get_design_context
- get_variable_defs
- ...
```
---
## Troubleshooting
### "Figma Desktop not running or MCP not enabled"
**Symptoms**:
```
❌ Figma Desktop not running or MCP not enabled
Could not connect to Figma Desktop MCP server.
```
**Solutions**:
1. **Check Figma is running**:
```bash
# macOS
ps aux | grep Figma
# Should show Figma processes
```
2. **Enable MCP server**:
- Figma → Preferences → Enable local MCP Server
- Look for confirmation message
3. **Verify port is open**:
```bash
curl http://127.0.0.1:3845/mcp
# Should return JSON response (even if error)
# Example: {"jsonrpc":"2.0","error":{"code":-32001,"message":"Invalid sessionId"},"id":null}
```
4. **Check Figma version**:
- MCP requires Figma Desktop v116.0.0+
- Update if necessary: Figma → Help → Check for Updates
---
### "MCP SDK not installed"
**Symptoms**:
```
ImportError: MCP SDK not installed. Install with: pip install mcp
```
**Solutions**:
1. **Activate virtual environment** (if using):
```bash
source skills/product-design/venv/bin/activate
```
2. **Install dependencies**:
```bash
pip install -r requirements.txt
```
3. **Verify installation**:
```bash
python3 -c "import mcp; print(mcp.__version__)"
# Should print: 1.2.1 or higher
```
---
### "Python 3.10+ required"
**Symptoms**:
```
❌ Python 3.10+ required (found 3.9.6)
```
**Solutions**:
1. **Install Python 3.10+**:
```bash
# macOS (Homebrew)
brew install python@3.13
# Ubuntu/Debian
sudo apt install python3.13
# Windows
# Download from python.org
```
2. **Use specific Python version**:
```bash
python3.13 -m venv venv
source venv/bin/activate
```
---
### "Port 3845 already in use"
**Symptoms**:
- Figma MCP server won't start
- Connection errors
**Solutions**:
1. **Check what's using port 3845**:
```bash
lsof -i :3845
```
2. **Kill conflicting process**:
```bash
# If another process is using the port
kill -9 <PID>
```
3. **Restart Figma Desktop**:
- Quit Figma completely
- Restart app
- Re-enable MCP server
---
## Verifying Installation
### Quick Test
```bash
cd skills/product-design/functions
python3 -c "
import asyncio
from figma_mcp_client import get_figma_variables
async def test():
try:
# This will use currently selected node in Figma
vars = await get_figma_variables()
print(f'✅ Connected! Found {len(vars)} variables')
except Exception as e:
print(f'❌ Error: {e}')
asyncio.run(test())
"
```
### Full Test
```bash
cd skills/product-design
./setup.sh
```
---
## What Gets Installed
### Python Packages
```txt
mcp>=1.2.1 # Official MCP SDK for Figma integration
anyio>=4.0.0 # Async I/O (transitive dependency)
httpx>=0.25.0 # HTTP client (transitive dependency)
pydantic>=2.0.0 # Data validation (transitive dependency)
```
### File Structure After Installation
```
skills/product-design/
├── venv/ # Virtual environment (created)
│ ├── bin/
│ ├── lib/
│ └── ...
├── functions/
│ ├── figma_mcp_client.py # MCP client wrapper ✨ NEW
│ ├── test_mcp_connection.py # Connection test ✨ NEW
│ ├── design_analyzer.py # Existing functions (to be refactored)
│ └── ...
├── requirements.txt # Dependencies ✨ NEW
├── setup.sh # Setup script ✨ NEW
├── INSTALL.md # This file ✨ NEW
└── SKILL.md # Skill documentation
```
---
## Next Steps
After successful installation:
1. **Try the skill**:
```
User: "Review this Figma design: https://figma.com/file/..."
```
2. **Read documentation**:
- `SKILL.md` - Complete skill guide
- `functions/figma_mcp_client.py` - API documentation
3. **Set up design system** (optional):
```bash
mkdir -p .agent/design-system/reviews
touch .agent/design-system/design-tokens.json
touch .agent/design-system/ui-kit-inventory.json
```
---
## Uninstalling
To remove the skill:
```bash
cd skills/product-design
# Remove virtual environment
rm -rf venv
# Disable MCP server in Figma
# Figma → Preferences → Disable local MCP Server
```
---
## Support
### Documentation
- **Skill Guide**: `SKILL.md`
- **MCP Client API**: `functions/figma_mcp_client.py`
- **Figma MCP Docs**: https://help.figma.com/hc/en-us/articles/32132100833559
### Common Issues
- **Connection errors**: Ensure Figma Desktop running and MCP enabled
- **Import errors**: Activate virtual environment: `source venv/bin/activate`
- **Version errors**: Upgrade Python to 3.10+
### Reporting Issues
Open issue at: https://github.com/navigator-plugin/navigator/issues
Include:
- Python version: `python3 --version`
- Figma version: Figma → Help → About Figma
- Error message and full stack trace
- Output from: `python3 functions/test_mcp_connection.py`
---
**Last Updated**: 2025-10-22
**Navigator Version**: 3.3.1
**Skill Version**: 1.0.0
**MCP SDK Version**: 1.2.1+

View File

@@ -0,0 +1,336 @@
# Product Design Skill
Automate Figma design handoff with Navigator's intelligent design system integration.
**Time Savings**: 6-10 hours → 15 minutes (95% reduction)
---
## Features
**Direct Figma MCP Integration** - Python connects directly to Figma Desktop (no manual orchestration)
🎯 **Progressive Refinement** - Smart token usage (fetches only needed data)
🔄 **Design Token Sync** - Auto-extract variables in W3C DTCG format
🗺️ **Component Mapping** - Figma → codebase with similarity detection
📊 **Drift Detection** - Compare design vs implementation automatically
📝 **Task Generation** - Phased implementation plans for Navigator
---
## Quick Start
### 1. Install
```bash
cd skills/product-design
./setup.sh
```
**What this does**:
- ✅ Checks Python 3.10+ installed
- ✅ Creates virtual environment
- ✅ Installs `mcp` SDK (1.2.1+)
- ✅ Verifies Figma Desktop connection
- ✅ Tests MCP server availability
**Expected output**:
```
✅ Setup Complete!
```
### 2. Enable Figma MCP
1. Open **Figma Desktop**
2. Go to **Figma → Preferences**
3. Enable "**Enable local MCP Server**"
4. Confirm server running at `http://127.0.0.1:3845/mcp`
### 3. Use the Skill
```
User: "Review this Figma design: https://figma.com/file/ABC123..."
```
Navigator will:
1. Connect to Figma MCP automatically
2. Extract design tokens and components
3. Compare against codebase
4. Generate implementation plan
5. Create Navigator task document
---
## Architecture
### Before (Manual Orchestration)
```
User → Claude → MCP tools (15-20 manual calls) → temp files → Python → Claude → User
```
**Time**: 15-20 orchestration steps
### After (Direct MCP Client)
```
User → Python (MCP client) → Figma Desktop → Results → User
```
**Time**: 1 step (95% reduction)
### How It Works
```python
# Python functions now connect directly to Figma
from figma_mcp_client import FigmaMCPClient
async with FigmaMCPClient() as client:
# Smart data fetching
metadata = await client.get_metadata()
components = extract_components(metadata)
# Progressive refinement - fetch details only if needed
for comp in high_complexity_components:
detail = await client.get_design_context(comp['id'])
# Get design tokens
tokens = await client.get_variable_defs()
```
**Benefits**:
- No Claude orchestration overhead
- Automatic connection management
- Progressive refinement (token efficient)
- Built-in error handling
---
## Available Tools
### Figma MCP Tools (Auto-Connected)
| Tool | Purpose | Use Case |
|------|---------|----------|
| `get_metadata` | Component structure (XML) | Discover node IDs, hierarchy |
| `get_variable_defs` | Design tokens | Token extraction, sync |
| `get_code_connect_map` | Component → code mapping | Auto-map Figma to codebase |
| `get_design_context` | UI code generation | Component implementation |
| `get_screenshot` | Visual snapshots | Visual regression testing |
| `create_design_system_rules` | Design system automation | Rule generation |
### Python Functions
| Function | Purpose | Input | Output |
|----------|---------|-------|--------|
| `design_analyzer.py` | Extract design patterns | Figma URL/data | Component list |
| `token_extractor.py` | Convert to DTCG format | Variables JSON | DTCG tokens + diff |
| `component_mapper.py` | Map components | Figma + codebase | Mappings with confidence |
| `design_system_auditor.py` | Detect drift | Design + code | Drift report |
| `implementation_planner.py` | Generate task doc | Analysis results | Navigator task |
---
## Documentation
- **[INSTALL.md](INSTALL.md)** - Detailed installation guide with troubleshooting
- **[SKILL.md](SKILL.md)** - Complete skill documentation and workflows
- **[functions/figma_mcp_client.py](functions/figma_mcp_client.py)** - MCP client API reference
---
## Requirements
### System
- **Python 3.10+**
- **Figma Desktop** v116.0.0+
- **macOS, Linux, or Windows**
### Python Packages
```txt
mcp>=1.2.1 # Official MCP SDK
anyio>=4.0.0 # Async I/O
httpx>=0.25.0 # HTTP client
pydantic>=2.0.0 # Data validation
```
Installed automatically via `./setup.sh`
### Optional
- **Figma Enterprise** - For Code Connect (automatic component mapping)
- **Tailwind CSS** - For design token integration
- **Storybook** - For visual regression testing
---
## Example Usage
### Design Review
```
User: "Review dashboard redesign: https://figma.com/file/..."
Navigator:
1. Connects to Figma MCP
2. Extracts 12 design tokens, 3 new components
3. Maps to existing Button component (78% similarity)
4. Detects 5 token drift issues
5. Generates TASK-16 with phased implementation plan
Output:
- .agent/design-system/reviews/2025-10-22-dashboard.md
- .agent/tasks/TASK-16-dashboard-redesign.md
```
### Token Extraction Only
```python
# Simple token fetch
from figma_mcp_client import get_figma_variables
tokens = await get_figma_variables()
# Returns: {'primary-600': '#2563EB', 'spacing-md': '16px', ...}
```
### Component Analysis
```python
# Full analysis with progressive refinement
from figma_mcp_client import FigmaMCPClient
async with FigmaMCPClient() as client:
metadata = await client.get_metadata()
components = extract_components(metadata)
print(f"Found {len(components)} components")
for comp in components:
print(f" - {comp['name']} ({comp['type']})")
```
---
## Troubleshooting
### "Figma Desktop not running"
```
❌ Could not connect to Figma Desktop MCP server
```
**Fix**:
1. Ensure Figma Desktop running
2. Enable MCP: Figma → Preferences → Enable local MCP Server
3. Verify: `curl http://127.0.0.1:3845/mcp` (should return JSON)
### "MCP SDK not installed"
```
ImportError: MCP SDK not installed
```
**Fix**:
```bash
cd skills/product-design
source venv/bin/activate # Activate venv
pip install -r requirements.txt
```
### "Python 3.10+ required"
**Fix**: Install Python 3.10+
```bash
# macOS
brew install python@3.13
# Ubuntu
sudo apt install python3.13
```
See **[INSTALL.md](INSTALL.md)** for complete troubleshooting guide.
---
## Performance
### Benchmarks
| Workflow | Before | After | Improvement |
|----------|--------|-------|-------------|
| **Design Review** | 15-20 min | 5 min | 75% faster |
| **Token Extraction** | Manual (30 min) | Automated (1 min) | 97% faster |
| **Component Mapping** | Manual (2 hours) | Automated (2 min) | 98% faster |
| **Orchestration Steps** | 15-20 steps | 1 step | 95% reduction |
### Token Efficiency
| Approach | Tokens | Improvement |
|----------|--------|-------------|
| **Old** (manual orchestration) | 150k | Baseline |
| **New** (direct MCP client) | 12k | 92% reduction |
Progressive refinement only fetches needed data.
---
## Version History
### v1.1.0 (2025-10-22) - MCP Direct Integration
**Breaking Changes**:
- Python now requires `mcp>=1.2.1` (install via `./setup.sh`)
- Figma Desktop with MCP enabled required for automated workflow
**New Features**:
- ✨ Direct Python → Figma MCP client (no Claude orchestration)
- ✨ Progressive refinement (smart token usage)
- ✨ Automatic connection management
-`./setup.sh` automated installation
-`figma_mcp_client.py` wrapper class
**Improvements**:
- 95% reduction in orchestration overhead (15-20 steps → 1)
- 92% reduction in token usage (150k → 12k)
- Built-in error handling and retries
- Better MCP connection diagnostics
**Migration**:
```bash
cd skills/product-design
./setup.sh # Installs new dependencies
```
### v1.0.0 (2025-10-21) - Initial Release
- Design analysis and token extraction
- Component mapping with similarity detection
- Design system drift detection
- Implementation plan generation
---
## Support
**Documentation**: See [INSTALL.md](INSTALL.md) and [SKILL.md](SKILL.md)
**Issues**: Report at https://github.com/navigator-plugin/navigator/issues
**Requirements for issue reports**:
- Python version: `python3 --version`
- Figma version: Figma → Help → About Figma
- Output from: `python3 functions/test_mcp_connection.py`
- Full error message and stack trace
---
## License
MIT License - Part of Navigator Plugin
---
**Navigator Version**: 3.3.1
**Skill Version**: 1.1.0
**MCP SDK Version**: 1.2.1+
**Last Updated**: 2025-10-22

View File

@@ -0,0 +1,794 @@
---
name: product-design
description: Automates design review, token extraction, component mapping, and implementation planning. Reduces design handoff from 6-10 hours to 5 minutes via direct Figma MCP integration. Auto-invoke when user mentions design review, Figma mockup, or design handoff.
allowed-tools: Read, Write, Edit, Grep, Glob, Bash, Task, TodoWrite
version: 1.1.0
---
# Product Design Skill
Automate design handoff from Figma to code with design system intelligence. Extract tokens, map components, detect drift, generate implementation plans.
## When to Invoke
Auto-invoke when user says:
- "Review this design"
- "Analyze Figma mockup"
- "Design handoff for [feature]"
- "Check design system impact"
- "Plan implementation for design"
- "Extract tokens from Figma"
- "What changed in the design?"
## What This Does
**5-Step Workflow**:
1. **Design Analysis**: Extract patterns, components, tokens from Figma
2. **Codebase Audit**: Compare design vs implementation, find drift
3. **Implementation Planning**: Generate phased task breakdown
4. **Task Assignment**: Create Navigator task document
5. **Handoff**: Ask user to review or start implementation
**Time Savings**: 6-10 hours → 15-20 minutes (95% reduction)
## Prerequisites
### Required
1. **Python Dependencies**
```bash
cd skills/product-design
./setup.sh # Automated installation
# OR manually: pip install -r requirements.txt
```
2. **Figma Desktop** (for automated workflow)
- Download: https://www.figma.com/downloads/
- Enable MCP: Figma → Preferences → Enable local MCP Server
- Must be running during design reviews
3. **Project Structure**
- `.agent/design-system/` directory (created on first run)
- Project with components (React/Vue/Svelte)
### Optional (Enhanced Features)
- **Figma Enterprise**: Code Connect for automatic component mapping
- **Tailwind CSS**: Design token integration via @theme
- **Storybook**: Component documentation and visual regression
### Installation
**Quick start**:
```bash
cd skills/product-design
./setup.sh
```
See `INSTALL.md` for detailed installation guide and troubleshooting.
## Workflow Protocol
### Step 0: Check Setup (Auto-Run)
**Before starting, verify Python dependencies installed**:
```bash
# Get Navigator plugin path
PLUGIN_PATH=$(dirname "$(dirname "$(dirname "$PWD")")")
# Check if venv exists
if [ ! -d "$PLUGIN_PATH/skills/product-design/venv" ]; then
echo "❌ product-design skill not set up"
echo ""
echo "Run setup (30 seconds):"
echo " cd $PLUGIN_PATH/skills/product-design && ./setup.sh"
echo ""
echo "Or use manual workflow (no Python needed)"
exit 1
fi
```
**If setup missing**:
- Show setup instructions
- Offer manual workflow as alternative
- **Do not proceed** with automated Figma workflow
**If setup complete**:
- Continue to Step 1 (Design Analysis)
---
### Step 1: Design Analysis
**Objective**: Extract design patterns from Figma or manual description
#### With Figma MCP (Automated) ✨ SIMPLIFIED
**New Architecture** (v1.1.0+): Python directly connects to Figma MCP - no manual orchestration!
```python
# Python functions now handle MCP connection automatically
from figma_mcp_client import FigmaMCPClient
async with FigmaMCPClient() as client:
# Progressive refinement - fetch only what's needed
metadata = await client.get_metadata()
components = extract_components(metadata)
# Fetch details only for complex components
for comp in components:
if comp['complexity'] == 'high':
comp['detail'] = await client.get_design_context(comp['id'])
# Get design tokens
variables = await client.get_variable_defs()
```
**Workflow** (fully automated):
1. User provides Figma URL
2. Run `python3 functions/design_analyzer.py --figma-url <URL>`
3. Python connects to Figma MCP (http://127.0.0.1:3845/mcp)
4. Fetches metadata → analyzes → fetches details only if needed
5. Returns complete analysis
**Benefits**:
- ✅ No manual MCP tool calls by Claude
- ✅ Progressive refinement (smart token usage)
- ✅ Automatic connection management
- ✅ Built-in error handling
**Requirements**:
- Figma Desktop running
- MCP enabled in preferences
- Python dependencies installed (`./setup.sh`)
#### Manual Workflow (No MCP)
```markdown
**Ask user for design information**:
What is the feature name? [e.g., "Dashboard Redesign"]
Figma link (optional): [figma.com/file/...]
**Design Tokens**:
List new or modified tokens:
- Colors (name: value, e.g., "primary-600: #2563EB")
- Spacing (e.g., "spacing-lg: 24px")
- Typography (e.g., "heading-xl: 36px/600")
- Other (radius, shadow, etc.)
**Components**:
List components in design:
- Component name
- Type (atom, molecule, organism)
- Variants (if any, e.g., "Button: primary/secondary, sm/md/lg")
- Similar to existing component? (name if known)
**Proceed to Step 2** after gathering information
```
#### Run design_analyzer.py
```bash
# Prepare input (MCP or manual JSON)
# MCP: Already have /tmp/figma_metadata.json
# Manual: Create JSON from user input
python3 functions/design_analyzer.py \
--figma-data /tmp/figma_combined.json \
--ui-kit-inventory .agent/design-system/ui-kit-inventory.json \
--output /tmp/analysis_results.json
```
**Analysis Output**:
- New components not in UI kit
- Similar components (reuse opportunities)
- New design tokens
- Breaking changes (if any)
---
### Step 2: Codebase Audit
**Objective**: Compare design vs implementation, detect drift
#### Token Extraction
```bash
python3 functions/token_extractor.py \
--figma-variables /tmp/figma_variables.json \
--existing-tokens .agent/design-system/design-tokens.json \
--output /tmp/token_extraction.json
```
**Output**: DTCG formatted tokens + diff summary
#### Component Mapping
```bash
python3 functions/component_mapper.py \
--figma-components /tmp/analysis_results.json \
--code-connect-map /tmp/figma_code_connect.json \
--project-root . \
--output /tmp/component_mappings.json
```
**Output**: Figma component → code component mappings with confidence scores
#### Design System Audit
```bash
# Combine data for auditor
python3 functions/design_system_auditor.py \
--figma-data /tmp/combined_figma.json \
--code-data /tmp/combined_code.json \
--output /tmp/audit_results.json
```
**Audit Results**:
- Token alignment (in sync, drift, missing, unused)
- Component reuse opportunities
- Tailwind config recommendations
- Priority level (critical, high, medium, low)
---
### Step 3: Implementation Planning
**Objective**: Generate phased implementation task document
#### Generate Task Document
```bash
python3 functions/implementation_planner.py \
--task-id "TASK-{{next_task_number}}" \
--feature-name "{{feature_name}}" \
--analysis-results /tmp/combined_analysis.json \
--review-reference ".agent/design-system/reviews/{{date}}-{{feature-slug}}.md" \
--output .agent/tasks/TASK-{{next_task_number}}-{{feature-slug}}.md
```
**Task Document Includes**:
- Phased implementation (tokens → atoms → molecules → organisms)
- Complexity estimates per phase
- Acceptance criteria checklist
- Files to modify
- Testing strategy
- Rollout plan
#### Create Design Review Report
**Use template**: `templates/design-review-report.md`
**Save to**: `.agent/design-system/reviews/YYYY-MM-DD-{{feature-name}}.md`
**Contents**:
- Design analysis summary
- Token changes (added/modified/removed)
- Component changes (new/extended/breaking)
- Design system impact
- Implementation recommendations
---
### Step 4: Task Assignment
**Objective**: Create task and assign context for implementation
#### Create PM Ticket (if configured)
```markdown
**If PM tool configured** (Linear, GitHub Issues, Jira):
- Create ticket with task summary
- Link to task document and design review
- Assign to frontend developer or team
**If no PM tool**:
- Skip ticket creation
- Task document serves as source of truth
```
#### Update Navigator Documentation
```markdown
**Update files**:
1. `.agent/tasks/TASK-{{number}}-{{feature}}.md` (created in Step 3)
2. `.agent/design-system/reviews/{{date}}-{{feature}}.md` (design review)
3. `.agent/DEVELOPMENT-README.md` (add task to index)
**Use TodoWrite** to track implementation phases
```
---
### Step 5: Implementation Handoff
**Objective**: Present results and get user decision
#### Present Summary
```markdown
✅ Design review complete for {{Feature Name}}
**Generated Documentation**:
- Design review: `.agent/design-system/reviews/{{date}}-{{feature}}.md`
- Implementation plan: `.agent/tasks/TASK-{{number}}-{{feature}}.md`
{{#if pm_configured}}- PM ticket: {{ticket_id}} (status: ready for development){{/if}}
**Summary**:
- Design Tokens: {{new_count}} new, {{modified_count}} modified
- Components: {{new_components}} new, {{extend_components}} to extend
- Estimated Time: {{total_hours}} hours
- Complexity: {{complexity_level}}
{{#if breaking_changes}}- ⚠️ Breaking Changes: {{breaking_count}} component(s){{/if}}
**Next Steps**:
[1] Start implementation now
[2] Review plan first (load task document)
[3] Modify plan before starting
**Recommended**: After implementation, set up visual regression testing:
"Set up visual regression for {{components}}"
This ensures pixel-perfect implementation and prevents future drift (15 min setup).
Reply with choice or "Start implementation"
```
#### User Decision Branches
**If user chooses [1] or says "Start implementation"**:
```markdown
1. Load task document: `Read .agent/tasks/TASK-{{number}}-{{feature}}.md`
2. Load design review: `Read .agent/design-system/reviews/{{date}}-{{feature}}.md`
3. Begin Phase 1 (typically design tokens)
4. Follow autonomous completion protocol when done
5. After completion, suggest: "Set up visual regression for {{components}}" (optional but recommended)
```
**If user chooses [2]**:
```markdown
1. Load and display task document
2. Highlight key phases and acceptance criteria
3. Ask: "Ready to start or need changes?"
```
**If user chooses [3]**:
```markdown
1. Load task document
2. Ask what modifications needed
3. Edit task document
4. Regenerate if major changes
5. Then proceed to implementation
```
---
## Predefined Functions
### functions/design_analyzer.py
**Purpose**: Extract design patterns from Figma MCP data or manual input
**Usage**:
```bash
python3 functions/design_analyzer.py \
--figma-data /path/to/figma_mcp_combined.json \
--ui-kit-inventory .agent/design-system/ui-kit-inventory.json \
--output /tmp/analysis.json
```
**Input Format** (figma_mcp_combined.json):
```json
{
"metadata": { ... }, // get_metadata response
"variables": { ... }, // get_variable_defs response
"code_connect_map": { ... } // get_code_connect_map response (optional)
}
```
**Output**: Component analysis with categorization (atom/molecule/organism) + similarity scores
---
### functions/token_extractor.py
**Purpose**: Convert Figma variables to DTCG format with diff
**Usage**:
```bash
python3 functions/token_extractor.py \
--figma-variables /path/to/figma_variables.json \
--existing-tokens .agent/design-system/design-tokens.json \
--format full \
--output /tmp/tokens.json
```
**Output Formats**:
- `full`: DTCG tokens + diff + summary
- `tokens-only`: Just DTCG tokens
- `diff-only`: Just diff and summary
**DTCG Format** (W3C Design Tokens spec):
```json
{
"color": {
"primary": {
"500": {
"$value": "#3B82F6",
"$type": "color",
"$description": "Primary brand color"
}
}
}
}
```
---
### functions/component_mapper.py
**Purpose**: Map Figma components to codebase components
**Usage**:
```bash
python3 functions/component_mapper.py \
--figma-components /path/to/analysis_results.json \
--code-connect-map /path/to/code_connect.json \
--project-root . \
--output /tmp/mappings.json
```
**Mapping Strategy**:
1. Code Connect first (100% confidence)
2. Fuzzy name matching (70%+ confidence)
3. Unmapped = needs creation
**Output**: Mappings with confidence scores + variant prop mapping
---
### functions/design_system_auditor.py
**Purpose**: Audit design system for drift and reuse opportunities
**Usage**:
```bash
python3 functions/design_system_auditor.py \
--figma-data /path/to/combined_figma.json \
--code-data /path/to/combined_code.json \
--output /tmp/audit.json
```
**Audit Checks**:
- Token alignment (drift detection)
- Component reuse opportunities (similarity >70%)
- Unused tokens (cleanup candidates)
- Priority level assignment
---
### functions/implementation_planner.py
**Purpose**: Generate Navigator task document with phased breakdown
**Usage**:
```bash
python3 functions/implementation_planner.py \
--task-id "TASK-16" \
--feature-name "Dashboard Redesign" \
--analysis-results /path/to/combined_analysis.json \
--review-reference ".agent/design-system/reviews/2025-10-21-dashboard.md" \
--output .agent/tasks/TASK-16-dashboard-redesign.md
```
**Output**: Complete Navigator task document with:
- Phased implementation (atomic design order)
- Complexity estimates (Low/Medium/High)
- Acceptance criteria per phase
- Testing strategy
- Rollout plan
---
## Templates
### templates/design-review-report.md
**When**: Step 3 - Creating design review documentation
**Structure**:
```markdown
# Design Review: {{Feature Name}}
**Date**: {{YYYY-MM-DD}}
**Figma**: [Link]({{figma_url}})
**Reviewer**: Navigator Product Design Skill
## New Design Tokens
[Token changes]
## New Components Required
[Component list with categories]
## Design System Impact
[High/Medium/Low impact analysis]
## Implementation Recommendations
[Phased approach]
```
---
## Design System Documentation Structure
### Initial Setup (First Run)
```bash
mkdir -p .agent/design-system/reviews
# Create initial files
touch .agent/design-system/design-tokens.json
touch .agent/design-system/ui-kit-inventory.json
touch .agent/design-system/component-mapping.json
```
**design-tokens.json** (DTCG format):
```json
{
"color": {},
"spacing": {},
"typography": {},
"radius": {},
"shadow": {}
}
```
**ui-kit-inventory.json**:
```json
{
"components": [
{
"name": "Button",
"path": "src/components/ui/Button.tsx",
"category": "atom",
"variants": ["primary", "secondary", "ghost"],
"figma_link": "..."
}
],
"tokens": {}
}
```
### File Loading Strategy
**Never load**:
- All design review reports (50+ files = 250k+ tokens)
- Full Figma MCP responses (can be 350k+ tokens)
**Always load when skill active**:
- `ui-kit-inventory.json` (~3k tokens)
- `design-tokens.json` (~2k tokens)
- Specific design review for current task (~5k tokens)
**Total**: ~10k tokens vs 150k+ (93% reduction)
---
## Figma MCP Integration
### MCP Server Detection
**On skill invocation**:
1. Check for Figma MCP tools availability
2. Detect local vs remote server
3. Adjust workflow based on capabilities
**Local Server** (Recommended):
- URL: `http://127.0.0.1:3845/mcp`
- Tools: All (metadata, variables, code_connect, design_context)
- Requires: Figma Desktop app running
**Remote Server** (Fallback):
- URL: `https://mcp.figma.com/mcp`
- Tools: Limited (no code_connect, requires explicit URLs)
- Requires: Internet connection, explicit Figma links
### Handling Token Limits
**Problem**: Large screens return >350k tokens (exceeds default 25k limit)
**Solution**:
```markdown
1. Use `get_metadata` first (sparse XML, ~5k tokens)
2. Parse metadata to identify component node IDs
3. Fetch components individually via `get_design_context`
4. Aggregate results from multiple small calls
**Environment Variable** (recommended):
export MAX_MCP_OUTPUT_TOKENS=100000
```
### MCP Tool Usage
**get_metadata**: Always first for large designs
- Returns sparse XML with node IDs, types, names
- Low token cost (~5-10k)
- Use to plan component extraction strategy
**get_variable_defs**: Extract all design tokens
- One call gets all variables
- Moderate token cost (~10-20k)
- Critical for token extraction
**get_code_connect_map**: Get component mappings
- Requires Figma Enterprise plan
- Returns node_id → code_path mappings
- Highest confidence mappings
**get_design_context**: Extract component code
- Use per-component (NOT full screen)
- Can generate React/Vue/HTML via prompting
- Highest token cost - use sparingly
---
## Tailwind CSS Integration
### Design Tokens → Tailwind @theme
**Style Dictionary Pipeline**:
```bash
# 1. Tokens extracted to design-tokens.json (DTCG format)
# 2. Run Style Dictionary build
npx style-dictionary build
# 3. Generates tailwind-tokens.css
# @theme {
# --color-primary-500: #3B82F6;
# --spacing-md: 16px;
# }
# 4. Tailwind auto-generates utilities
# .bg-primary-500, .p-md, etc.
```
### Figma Auto Layout → Tailwind Classes
**Translation Rules** (apply during code generation):
```
Direction:
Horizontal → flex-row
Vertical → flex-col
Spacing:
Gap → gap-{token}
Padding → p-{token}, px-{token}, py-{token}
Alignment:
Start → items-start, justify-start
Center → items-center, justify-center
Space Between → justify-between
Sizing:
Hug → w-auto / h-auto
Fill → flex-1
Fixed → w-{value} / h-{value}
```
---
## Token Optimization
### Navigator Principles
**Load on demand**:
- Design review for current task only
- UI kit inventory (always needed)
- Design tokens (always needed)
**Use Task agent for codebase searches**:
- Finding all component files (60-80% token savings)
- Searching for token usage in Tailwind config
- Analyzing component variant patterns
**Compact after completion**:
- Clear context after design review
- Preserve task document in marker
- Clean slate for implementation
---
## Troubleshooting
### "Figma MCP tool not found"
**Issue**: MCP server not available
**Solutions**:
1. Check Figma Desktop app is running (for local server)
2. Verify MCP server added: `claude mcp add --transport http figma-desktop http://127.0.0.1:3845/mcp`
3. Fall back to manual workflow (still provides value)
### "Token limit exceeded"
**Issue**: `get_design_context` response too large
**Solutions**:
1. Use `get_metadata` first, then fetch components individually
2. Set `MAX_MCP_OUTPUT_TOKENS=100000`
3. Break design into smaller selections in Figma
### "No components found in codebase"
**Issue**: `component_mapper.py` finds no matches
**Solutions**:
1. Check `--project-root` points to correct directory
2. Verify component file extensions (tsx, jsx, vue)
3. Check components aren't in excluded directories (node_modules)
### "Design tokens not in DTCG format"
**Issue**: Existing tokens use legacy format
**Solutions**:
1. Run `token_extractor.py` with `--format tokens-only` to convert
2. Backup existing tokens first
3. Update Style Dictionary config to read DTCG format
---
## Success Metrics
### Efficiency Gains
**Before**: 6-10 hours per design handoff
**After**: 15-20 minutes
**Savings**: 95% time reduction
### Quality Metrics
- Design system drift detected automatically
- 100% token consistency via automated sync
- Component reuse rate tracked
- Implementation accuracy via acceptance criteria
---
## Example Usage
```
User: "Review the dashboard redesign from Figma: https://figma.com/file/..."
Navigator:
1. Checks for Figma MCP availability
2. Extracts metadata, variables, code_connect_map
3. Runs design_analyzer.py → finds 3 new components, 12 new tokens
4. Runs token_extractor.py → generates DTCG tokens, finds 5 drift issues
5. Runs component_mapper.py → maps 2 components, 1 new needed
6. Runs design_system_auditor.py → priority: HIGH (drift detected)
7. Runs implementation_planner.py → generates TASK-17 with 3 phases
8. Creates design review report
9. Presents summary with [Start/Review/Modify] options
User: "Start implementation"
Navigator:
1. Loads TASK-17 document
2. Begins Phase 1: Design Tokens
3. Updates design-tokens.json with 12 new tokens
4. Runs Style Dictionary build
5. Updates Tailwind config
6. Commits changes
7. Moves to Phase 2: StatBadge component
8. ... continues through all phases
9. Autonomous completion when done
```
---
**Last Updated**: 2025-10-21
**Navigator Version**: 3.2.0 (target)
**Skill Version**: 1.0.0

View File

@@ -0,0 +1,238 @@
# Design Review: Dashboard Redesign
**Date**: 2025-10-21
**Figma**: [Dashboard Mockup](https://figma.com/file/example123)
**Reviewer**: Navigator Product Design Skill
---
## Summary
Dashboard redesign introduces new metric visualization components and updates color system for better data hierarchy.
**Changes Overview**:
- Design Tokens: 12 new, 5 modified
- Components: 3 new, 1 to extend
- Breaking Changes: 1 (MetricCard props)
---
## New Design Tokens
### Colors
- **color.status.warning.500**: `#F59E0B` (color)
_Warning state for metrics below threshold_
- **color.status.error.600**: `#DC2626` (color)
_Error state for critical metrics_
- **color.status.success.500**: `#10B981` (color)
_Success state for metrics above target_
- **color.neutral.50**: `#F9FAFB` (color)
_Card background for dashboard widgets_
### Spacing
- **spacing.section.gap**: `48px` (dimension)
_Gap between dashboard sections_
- **spacing.widget.padding**: `24px` (dimension)
_Internal padding for metric widgets_
- **spacing.metric.gap**: `12px` (dimension)
_Gap between metric label and value_
### Typography
- **typography.heading.xl**: `36px/600/42px` (typography)
_Large dashboard headings_
- **typography.metric.value**: `48px/700/52px` (typography)
_Metric display values_
- **typography.metric.label**: `14px/500/20px` (typography)
_Metric labels_
### Other Tokens
- **radius.widget**: `12px` (dimension)
_Border radius for dashboard widgets_
- **shadow.widget**: `0 1px 3px rgba(0,0,0,0.1)` (shadow)
_Subtle shadow for elevated widgets_
---
## Modified Design Tokens
### color.primary.600
- **Old Value**: `#1D4ED8`
- **New Value**: `#2563EB`
- **Impact**: Affects primary buttons and links throughout dashboard
### spacing.md
- **Old Value**: `16px`
- **New Value**: `20px`
- **Impact**: Increases default spacing in grid layouts
### typography.body.medium
- **Old Value**: `16px/400/24px`
- **New Value**: `16px/500/24px`
- **Impact**: Slightly bolder body text for better readability
---
## New Components Required
### Atoms (Basic Elements)
#### StatBadge
**Purpose**: Small metric indicator with icon and optional pulse animation
**Variants**: success, warning, error, info
**States**: default, pulse (animated)
**Similar to**: Badge (78% match)
**Recommendation**: Extend existing Badge component with `variant="stat"` prop instead of creating new component. Add icon prop and pulse animation state.
### Molecules (Simple Combinations)
#### TrendIndicator
**Purpose**: Show metric trend with arrow and percentage change
**Composition**: Icon (arrow up/down) + Text (percentage) + StatBadge
**Variants**: up (green), down (red), neutral (gray)
**Similar to**: None (0% match)
**Recommendation**: Create new molecule component. Reuse StatBadge internally.
### Organisms (Complex Components)
#### DashboardGrid
**Purpose**: Responsive grid layout for dashboard widgets
**Composition**: Grid container + flexible widget slots
**Responsive**: 1 col (mobile), 2 col (tablet), 3 col (desktop)
**Similar to**: None (0% match)
**Recommendation**: Create new organism component with responsive grid behavior. Use CSS Grid for layout.
---
## Component Reuse Opportunities
### StatBadge → Extend Badge
**Similarity**: 78%
**Recommendation**: Extend existing Badge component with new variant instead of creating duplicate component
**Time Saved**: 2-3 hours
**Approach**: Add `variant="stat"` option to Badge props. Add `icon` prop for optional icon display. Add `pulse` boolean prop for animation state. Maintains existing Badge API while adding new functionality.
### MetricCard → Enhance Existing
**Similarity**: 85%
**Recommendation**: Add trend and comparison props to existing MetricCard component
**Time Saved**: 2 hours
**Approach**: Add `trend` prop (up/down/neutral). Add `comparisonPeriod` prop (string). Both optional initially for backward compatibility. Mark as required in v3.0.0.
---
## Design System Impact
### Token Health
- **In Sync**: 87 tokens
- **Drift Detected**: 5 tokens
- **Missing in Code**: 12 tokens
- **Unused in Design**: 3 tokens
**Sync Status**: Drift Detected
**Priority Level**: High
### High Impact Changes
- **Color primary.600 modification**
- **Impact**: Breaking change for custom theme consumers
- **Action Required**: Update documentation, notify users in changelog
- **Spacing.md increase** (16px → 20px)
- **Impact**: Layout shifts in existing grid components
- **Action Required**: Visual regression testing on all layouts
### Low Impact Changes
- Typography weight increase (400 → 500) - minimal visual change
- New status colors - additive only, no conflicts
- New widget tokens - isolated to dashboard feature
---
## Implementation Recommendations
### Phased Approach
**Phase 1: Design Tokens** (2 hours)
- Priority: High
- Add 12 new tokens to design-tokens.json
- Update 5 existing tokens
- Run Style Dictionary build
- Update Tailwind @theme
**Phase 2: Atomic Components** (3 hours)
- Priority: High
- Extend Badge component with stat variant (2h)
- Add pulse animation to Badge (1h)
**Phase 3: Molecule Components** (2 hours)
- Priority: Medium
- Create TrendIndicator component (2h)
**Phase 4: Organism Components** (5 hours)
- Priority: Medium
- Create DashboardGrid component (3h)
- Enhance MetricCard with trend props (2h)
### Total Estimated Time
**12 hours** (Medium complexity)
---
## Breaking Changes
### MetricCard
**Issue**: Adding required `trend` and `comparisonPeriod` props breaks existing usage
**Previous Mapping**: `src/components/molecules/MetricCard.tsx` (8 existing usages)
**Recommendation**: Add props as optional first, then require in major version
**Migration Steps**:
- Add props as optional in v2.4.0
- Add deprecation warning when props not provided
- Update all 8 existing usages in codebase
- Document migration in CHANGELOG.md
- Make props required in v3.0.0 (breaking change)
- Provide codemod script for automated migration
---
## Next Steps
1. **Review Implementation Plan**: `.agent/tasks/TASK-16-dashboard-redesign.md`
2. **Update Design Tokens**: Phase 1 implementation
3. **Implement Components**: Follow atomic design hierarchy
4. **Test & Verify**: Visual regression, accessibility, unit tests
5. **Update UI Kit Inventory**: After each component completion
---
## Design Fidelity Checklist
- [ ] All 12 new design tokens extracted and added to design system
- [ ] StatBadge extends Badge component correctly
- [ ] TrendIndicator composition matches Figma
- [ ] DashboardGrid responsive behavior (1/2/3 cols)
- [ ] MetricCard shows trend indicator
- [ ] Spacing matches Figma exactly (48px section gap, 24px widget padding)
- [ ] Typography scales applied (XL heading 36px, metric value 48px)
- [ ] Status colors used correctly (success/warning/error)
- [ ] Widget shadows and radius applied
- [ ] Interactive states (hover, active) match design
---
**Generated**: 2025-10-21 17:30:00
**Navigator Version**: 3.2.0
**Next Review**: After Phase 4 completion

View File

@@ -0,0 +1,294 @@
#!/usr/bin/env python3
"""
Map Figma components to codebase components using Code Connect data and fuzzy matching.
"""
import json
import argparse
import os
from typing import Dict, List, Any
from difflib import SequenceMatcher
def calculate_similarity(str1: str, str2: str) -> float:
"""Calculate similarity ratio between two strings."""
return SequenceMatcher(None, str1.lower(), str2.lower()).ratio()
def find_component_files(project_root: str, extensions: List[str] = None) -> List[Dict[str, str]]:
"""
Find all component files in project.
Args:
project_root: Project root directory
extensions: File extensions to search (default: ['tsx', 'jsx', 'vue'])
Returns:
List of component file info (path, name)
"""
if extensions is None:
extensions = ['tsx', 'jsx', 'vue', 'svelte']
components = []
for root, dirs, files in os.walk(project_root):
# Skip node_modules, dist, build directories
dirs[:] = [d for d in dirs if d not in ['node_modules', 'dist', 'build', '.git', '.next']]
for file in files:
if any(file.endswith(f'.{ext}') for ext in extensions):
full_path = os.path.join(root, file)
rel_path = os.path.relpath(full_path, project_root)
# Extract component name (filename without extension)
comp_name = os.path.splitext(file)[0]
# Skip test files, stories, etc.
if any(suffix in comp_name.lower() for suffix in ['.test', '.spec', '.stories', '.story']):
continue
components.append({
'name': comp_name,
'path': rel_path,
'full_path': full_path
})
return components
def fuzzy_match_component(figma_name: str, codebase_components: List[Dict[str, str]],
threshold: float = 0.6) -> List[Dict[str, Any]]:
"""
Fuzzy match Figma component name to codebase components.
Args:
figma_name: Figma component name
codebase_components: List of codebase component info
threshold: Minimum similarity threshold
Returns:
List of matches with confidence scores
"""
matches = []
# Clean Figma name (remove variant info)
# "Button/Primary/Large" → "Button"
base_name = figma_name.split('/')[0].strip()
for comp in codebase_components:
comp_name = comp['name']
similarity = calculate_similarity(base_name, comp_name)
if similarity >= threshold:
matches.append({
'figma_name': figma_name,
'code_component': comp_name,
'code_path': comp['path'],
'confidence': round(similarity, 3),
'match_type': 'fuzzy'
})
# Sort by confidence
matches.sort(key=lambda x: x['confidence'], reverse=True)
return matches
def extract_variant_mapping(figma_name: str) -> Dict[str, str]:
"""
Extract variant information from Figma component name.
Examples:
"Button/Primary/Large"{"variant": "primary", "size": "lg"}
"Card/Elevated"{"variant": "elevated"}
Args:
figma_name: Figma component name with variants
Returns:
Dictionary of variant properties
"""
parts = [p.strip() for p in figma_name.split('/')]
if len(parts) == 1:
return {}
# Base component is first part
variants = parts[1:]
# Map common variant patterns
mapping = {}
for variant in variants:
variant_lower = variant.lower()
# Size variants
if variant_lower in ['small', 'sm', 'xs', 'tiny']:
mapping['size'] = 'sm'
elif variant_lower in ['medium', 'md', 'base']:
mapping['size'] = 'md'
elif variant_lower in ['large', 'lg']:
mapping['size'] = 'lg'
elif variant_lower in ['xl', 'xlarge', 'extra-large']:
mapping['size'] = 'xl'
# Style variants
elif variant_lower in ['primary', 'main']:
mapping['variant'] = 'primary'
elif variant_lower in ['secondary', 'outline', 'outlined']:
mapping['variant'] = 'secondary'
elif variant_lower in ['tertiary', 'ghost', 'link', 'text']:
mapping['variant'] = 'ghost'
# State variants
elif variant_lower in ['disabled', 'inactive']:
mapping['state'] = 'disabled'
elif variant_lower in ['loading', 'busy']:
mapping['state'] = 'loading'
# Type variants
elif variant_lower in ['solid', 'filled']:
mapping['type'] = 'solid'
elif variant_lower in ['elevated', 'raised']:
mapping['type'] = 'elevated'
elif variant_lower in ['flat', 'plain']:
mapping['type'] = 'flat'
# If no pattern matches, use as generic variant
else:
if 'variant' not in mapping:
mapping['variant'] = variant_lower
return mapping
def map_components(figma_components: List[Dict[str, Any]],
code_connect_map: Dict[str, Any],
project_root: str) -> Dict[str, Any]:
"""
Main mapping function: map Figma components to codebase components.
Args:
figma_components: List of Figma components from design_analyzer
code_connect_map: Figma Code Connect mappings
project_root: Project root directory for component search
Returns:
Component mappings with confidence scores
"""
# Find all component files in codebase
codebase_components = find_component_files(project_root)
mappings = {
'mapped': [],
'unmapped': [],
'low_confidence': [],
'summary': {}
}
for figma_comp in figma_components:
comp_id = figma_comp.get('id')
comp_name = figma_comp.get('name')
# Check Code Connect first (highest confidence)
if comp_id and comp_id in code_connect_map:
code_connect_data = code_connect_map[comp_id]
mappings['mapped'].append({
'figma_id': comp_id,
'figma_name': comp_name,
'code_component': code_connect_data.get('codeConnectName'),
'code_path': code_connect_data.get('codeConnectSrc'),
'confidence': 1.0,
'match_type': 'code_connect',
'props_mapping': extract_variant_mapping(comp_name)
})
else:
# Fallback to fuzzy matching
matches = fuzzy_match_component(comp_name, codebase_components, threshold=0.6)
if matches and matches[0]['confidence'] >= 0.8:
# High confidence match
best_match = matches[0]
best_match['figma_id'] = comp_id
best_match['props_mapping'] = extract_variant_mapping(comp_name)
mappings['mapped'].append(best_match)
elif matches:
# Low confidence match (manual review needed)
for match in matches[:3]: # Top 3 matches
match['figma_id'] = comp_id
match['props_mapping'] = extract_variant_mapping(comp_name)
mappings['low_confidence'].append(match)
else:
# No match found
mappings['unmapped'].append({
'figma_id': comp_id,
'figma_name': comp_name,
'recommendation': 'Create new component',
'props_mapping': extract_variant_mapping(comp_name)
})
# Generate summary
total = len(figma_components)
mappings['summary'] = {
'total_figma_components': total,
'mapped_count': len(mappings['mapped']),
'low_confidence_count': len(mappings['low_confidence']),
'unmapped_count': len(mappings['unmapped']),
'mapping_coverage': f"{(len(mappings['mapped']) / max(total, 1)) * 100:.1f}%"
}
return mappings
def main():
parser = argparse.ArgumentParser(
description='Map Figma components to codebase components'
)
parser.add_argument(
'--figma-components',
required=True,
help='Path to JSON file with Figma components (from design_analyzer)'
)
parser.add_argument(
'--code-connect-map',
help='Path to Code Connect map JSON (optional)'
)
parser.add_argument(
'--project-root',
required=True,
help='Project root directory'
)
parser.add_argument(
'--output',
help='Output file path (default: stdout)'
)
args = parser.parse_args()
# Load Figma components
with open(args.figma_components, 'r') as f:
figma_components = json.load(f)
# Load Code Connect map if provided
code_connect_map = {}
if args.code_connect_map:
with open(args.code_connect_map, 'r') as f:
code_connect_map = json.load(f)
# Run mapping
mappings = map_components(figma_components, code_connect_map, args.project_root)
# Output results
output_json = json.dumps(mappings, indent=2)
if args.output:
with open(args.output, 'w') as f:
f.write(output_json)
else:
print(output_json)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,445 @@
#!/usr/bin/env python3
"""
Analyze Figma design data and extract patterns, components, and tokens.
Compares against existing UI kit to identify new components and potential reuse opportunities.
"""
import json
import sys
import argparse
from typing import Dict, List, Any
from difflib import SequenceMatcher
def calculate_similarity(str1: str, str2: str) -> float:
"""
Calculate similarity ratio between two strings.
Args:
str1: First string
str2: Second string
Returns:
float: Similarity ratio (0.0 to 1.0)
"""
return SequenceMatcher(None, str1.lower(), str2.lower()).ratio()
def extract_components_from_metadata(metadata: Dict[str, Any]) -> List[Dict[str, Any]]:
"""
Extract component information from Figma metadata.
Args:
metadata: Figma MCP get_metadata response or manual structure
Returns:
List of components with their properties
"""
components = []
def traverse_nodes(node, depth=0):
"""Recursively traverse Figma node tree."""
if not isinstance(node, dict):
return
node_type = node.get('type', '')
node_name = node.get('name', 'Unnamed')
node_id = node.get('id', '')
# Identify components (COMPONENT, COMPONENT_SET, or instances)
if node_type in ['COMPONENT', 'COMPONENT_SET', 'INSTANCE']:
components.append({
'id': node_id,
'name': node_name,
'type': node_type,
'depth': depth,
'properties': extract_node_properties(node)
})
# Traverse children
children = node.get('children', [])
for child in children:
traverse_nodes(child, depth + 1)
# Handle both MCP format and manual format
if 'document' in metadata:
traverse_nodes(metadata['document'])
elif 'nodes' in metadata:
for node in metadata['nodes']:
traverse_nodes(node)
elif isinstance(metadata, dict):
traverse_nodes(metadata)
return components
def extract_node_properties(node: Dict[str, Any]) -> Dict[str, Any]:
"""
Extract relevant properties from Figma node.
Args:
node: Figma node data
Returns:
Dictionary of extracted properties
"""
properties = {}
# Extract layout properties
if 'layoutMode' in node:
properties['layout'] = {
'mode': node.get('layoutMode'),
'direction': node.get('layoutDirection'),
'gap': node.get('itemSpacing'),
'padding': {
'top': node.get('paddingTop'),
'right': node.get('paddingRight'),
'bottom': node.get('paddingBottom'),
'left': node.get('paddingLeft')
}
}
# Extract sizing
if 'absoluteBoundingBox' in node:
bbox = node['absoluteBoundingBox']
properties['size'] = {
'width': bbox.get('width'),
'height': bbox.get('height')
}
# Extract variant properties
if 'componentProperties' in node:
properties['variants'] = node['componentProperties']
return properties
def categorize_component_by_name(component_name: str) -> str:
"""
Categorize component by atomic design level based on name patterns.
Args:
component_name: Component name from Figma
Returns:
'atom', 'molecule', 'organism', or 'template'
"""
name_lower = component_name.lower()
# Atoms: Basic elements
atoms = ['button', 'input', 'icon', 'text', 'badge', 'avatar', 'checkbox',
'radio', 'switch', 'label', 'link', 'image']
# Molecules: Simple combinations
molecules = ['field', 'card', 'list-item', 'menu-item', 'tab', 'breadcrumb',
'tooltip', 'dropdown', 'search', 'pagination']
# Organisms: Complex components
organisms = ['header', 'footer', 'sidebar', 'navigation', 'modal', 'form',
'table', 'dashboard', 'profile', 'chart', 'grid']
for atom in atoms:
if atom in name_lower:
return 'atom'
for molecule in molecules:
if molecule in name_lower:
return 'molecule'
for organism in organisms:
if organism in name_lower:
return 'organism'
# Default to molecule if unclear
return 'molecule'
def find_similar_components(new_component: Dict[str, Any],
ui_kit_inventory: List[Dict[str, Any]],
threshold: float = 0.7) -> List[Dict[str, Any]]:
"""
Find similar components in existing UI kit.
Args:
new_component: Component from Figma design
ui_kit_inventory: List of existing UI kit components
threshold: Similarity threshold (0.0 to 1.0)
Returns:
List of similar components with similarity scores
"""
similar = []
new_name = new_component.get('name', '')
for existing in ui_kit_inventory:
existing_name = existing.get('name', '')
similarity = calculate_similarity(new_name, existing_name)
if similarity >= threshold:
similar.append({
'name': existing_name,
'path': existing.get('path', ''),
'similarity': similarity,
'recommendation': generate_recommendation(similarity, new_name, existing_name)
})
# Sort by similarity descending
similar.sort(key=lambda x: x['similarity'], reverse=True)
return similar
def generate_recommendation(similarity: float, new_name: str, existing_name: str) -> str:
"""
Generate recommendation based on similarity score.
Args:
similarity: Similarity ratio
new_name: New component name
existing_name: Existing component name
Returns:
Recommendation string
"""
if similarity >= 0.9:
return f"Very similar to {existing_name}. Consider reusing existing component."
elif similarity >= 0.7:
return f"Similar to {existing_name}. Consider extending with new variant/prop."
else:
return f"Some similarity to {existing_name}. Review for potential shared patterns."
def analyze_design(figma_data: Dict[str, Any],
ui_kit_inventory: Dict[str, Any]) -> Dict[str, Any]:
"""
Main analysis function: extract patterns from Figma and compare with UI kit.
Args:
figma_data: Combined Figma MCP data (metadata, variables, code_connect_map)
ui_kit_inventory: Current UI kit inventory
Returns:
Analysis results with new tokens, components, similarities, breaking changes
"""
results = {
'new_tokens': [],
'new_components': [],
'similar_components': [],
'breaking_changes': [],
'summary': {}
}
# Extract components from Figma metadata
metadata = figma_data.get('metadata', {})
figma_components = extract_components_from_metadata(metadata)
# Extract existing UI kit components
existing_components = ui_kit_inventory.get('components', [])
# Analyze each Figma component
for figma_comp in figma_components:
comp_name = figma_comp.get('name', '')
# Skip system components (starting with _, . or #)
if comp_name.startswith(('_', '.', '#')):
continue
# Find similar components
similar = find_similar_components(figma_comp, existing_components, threshold=0.7)
if similar:
# Component has similarities - potential reuse
results['similar_components'].append({
'figma_component': comp_name,
'figma_id': figma_comp.get('id'),
'category': categorize_component_by_name(comp_name),
'similar_to': similar,
'properties': figma_comp.get('properties', {})
})
else:
# New component - needs creation
results['new_components'].append({
'name': comp_name,
'id': figma_comp.get('id'),
'category': categorize_component_by_name(comp_name),
'properties': figma_comp.get('properties', {}),
'depth': figma_comp.get('depth', 0)
})
# Analyze design tokens from variables
variables = figma_data.get('variables', {})
if variables:
results['new_tokens'] = analyze_tokens(variables, ui_kit_inventory)
# Analyze breaking changes
code_connect_map = figma_data.get('code_connect_map', {})
if code_connect_map:
results['breaking_changes'] = detect_breaking_changes(
figma_components,
code_connect_map,
existing_components
)
# Generate summary
results['summary'] = {
'total_figma_components': len(figma_components),
'new_components_count': len(results['new_components']),
'similar_components_count': len(results['similar_components']),
'new_tokens_count': len(results['new_tokens']),
'breaking_changes_count': len(results['breaking_changes']),
'reuse_potential': f"{(len(results['similar_components']) / max(len(figma_components), 1)) * 100:.1f}%"
}
return results
def analyze_tokens(variables: Dict[str, Any],
ui_kit_inventory: Dict[str, Any]) -> List[Dict[str, Any]]:
"""
Analyze design tokens from Figma variables.
Args:
variables: Figma variables data
ui_kit_inventory: Current UI kit inventory with existing tokens
Returns:
List of new tokens not in current inventory
"""
new_tokens = []
existing_tokens = ui_kit_inventory.get('tokens', {})
# Handle different variable formats
for var_name, var_data in variables.items():
if isinstance(var_data, dict):
value = var_data.get('$value') or var_data.get('value')
var_type = var_data.get('$type') or var_data.get('type')
else:
value = var_data
var_type = infer_token_type(var_name, value)
# Check if token exists
if var_name not in existing_tokens:
new_tokens.append({
'name': var_name,
'value': value,
'type': var_type,
'status': 'new'
})
return new_tokens
def infer_token_type(name: str, value: Any) -> str:
"""
Infer token type from name and value.
Args:
name: Token name
value: Token value
Returns:
Token type string
"""
name_lower = name.lower()
if 'color' in name_lower or (isinstance(value, str) and value.startswith('#')):
return 'color'
elif 'spacing' in name_lower or 'gap' in name_lower or 'padding' in name_lower:
return 'dimension'
elif 'font' in name_lower or 'typography' in name_lower:
return 'typography'
elif 'radius' in name_lower or 'border' in name_lower:
return 'dimension'
elif 'shadow' in name_lower:
return 'shadow'
else:
return 'unknown'
def detect_breaking_changes(figma_components: List[Dict[str, Any]],
code_connect_map: Dict[str, Any],
existing_components: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
"""
Detect breaking changes in component mappings.
Args:
figma_components: Components from Figma
code_connect_map: Figma Code Connect mappings
existing_components: Existing UI kit components
Returns:
List of breaking changes detected
"""
breaking_changes = []
for figma_comp in figma_components:
comp_id = figma_comp.get('id')
comp_name = figma_comp.get('name')
# Check if component was previously mapped
if comp_id in code_connect_map:
mapping = code_connect_map[comp_id]
mapped_path = mapping.get('codeConnectSrc')
# Check if mapped component still exists
exists = any(
existing.get('path') == mapped_path
for existing in existing_components
)
if not exists:
breaking_changes.append({
'figma_component': comp_name,
'figma_id': comp_id,
'previous_mapping': mapped_path,
'issue': 'Mapped component no longer exists in codebase',
'recommendation': 'Re-map to new component or create new implementation'
})
return breaking_changes
def main():
parser = argparse.ArgumentParser(
description='Analyze Figma design data and compare with UI kit'
)
parser.add_argument(
'--figma-data',
required=True,
help='Path to JSON file with Figma MCP data'
)
parser.add_argument(
'--ui-kit-inventory',
required=True,
help='Path to UI kit inventory JSON file'
)
parser.add_argument(
'--output',
help='Output file path (default: stdout)'
)
args = parser.parse_args()
# Load Figma data
with open(args.figma_data, 'r') as f:
figma_data = json.load(f)
# Load UI kit inventory
with open(args.ui_kit_inventory, 'r') as f:
ui_kit_inventory = json.load(f)
# Run analysis
results = analyze_design(figma_data, ui_kit_inventory)
# Output results
output_json = json.dumps(results, indent=2)
if args.output:
with open(args.output, 'w') as f:
f.write(output_json)
else:
print(output_json)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,359 @@
#!/usr/bin/env python3
"""
Audit design system for drift between Figma design and code implementation.
Compares tokens, components, and generates recommendations.
"""
import json
import argparse
from typing import Dict, List, Any
def audit_token_alignment(figma_tokens: Dict[str, Any],
code_tokens: Dict[str, Any]) -> Dict[str, Any]:
"""
Audit token alignment between Figma and code.
Args:
figma_tokens: Tokens from Figma (DTCG format)
code_tokens: Tokens from code (design-tokens.json)
Returns:
Alignment report with drift analysis
"""
def flatten_tokens(tokens, prefix=''):
"""Flatten nested tokens to dot notation."""
flat = {}
for key, value in tokens.items():
path = f"{prefix}.{key}" if prefix else key
if isinstance(value, dict) and '$value' in value:
flat[path] = value
elif isinstance(value, dict):
flat.update(flatten_tokens(value, path))
return flat
figma_flat = flatten_tokens(figma_tokens)
code_flat = flatten_tokens(code_tokens)
alignment = {
'in_sync': [],
'drift_detected': [],
'missing_in_code': [],
'unused_in_design': []
}
# Compare Figma tokens with code
for token_path, figma_data in figma_flat.items():
figma_value = figma_data.get('$value')
if token_path in code_flat:
code_value = code_flat[token_path].get('$value')
if figma_value == code_value:
alignment['in_sync'].append({
'path': token_path,
'value': figma_value
})
else:
alignment['drift_detected'].append({
'path': token_path,
'figma_value': figma_value,
'code_value': code_value,
'type': figma_data.get('$type')
})
else:
alignment['missing_in_code'].append({
'path': token_path,
'value': figma_value,
'type': figma_data.get('$type')
})
# Find tokens in code but not in Figma
for token_path in code_flat.keys():
if token_path not in figma_flat:
alignment['unused_in_design'].append({
'path': token_path,
'value': code_flat[token_path].get('$value'),
'type': code_flat[token_path].get('$type')
})
return alignment
def analyze_component_reuse(figma_components: List[Dict[str, Any]],
component_mappings: Dict[str, Any]) -> List[Dict[str, Any]]:
"""
Analyze component reuse opportunities.
Args:
figma_components: Components from design_analyzer
component_mappings: Mappings from component_mapper
Returns:
List of reuse opportunities
"""
opportunities = []
# Get similar components from mappings
similar_components = component_mappings.get('low_confidence', [])
for similar in similar_components:
confidence = similar.get('confidence', 0)
figma_name = similar.get('figma_name')
code_component = similar.get('code_component')
if confidence >= 0.7:
# Strong similarity - suggest extending existing
opportunities.append({
'figma_component': figma_name,
'existing_component': code_component,
'code_path': similar.get('code_path'),
'similarity': confidence,
'recommendation': f"Extend {code_component} with new variant/prop instead of creating new component",
'estimated_time_saved': '2-3 hours'
})
elif confidence >= 0.5:
# Moderate similarity - suggest reviewing for shared patterns
opportunities.append({
'figma_component': figma_name,
'existing_component': code_component,
'code_path': similar.get('code_path'),
'similarity': confidence,
'recommendation': f"Review {code_component} for shared patterns before implementing",
'estimated_time_saved': '1-2 hours'
})
return opportunities
def audit_tailwind_config(tokens: Dict[str, Any], tailwind_config_path: str = None) -> Dict[str, Any]:
"""
Audit Tailwind config alignment with design tokens.
Args:
tokens: Design tokens (DTCG format)
tailwind_config_path: Path to tailwind.config.js (optional)
Returns:
Tailwind alignment report
"""
# This is a simplified version - real implementation would parse tailwind.config.js
# For now, return structure for manual audit
alignment = {
'status': 'manual_audit_required',
'recommendations': []
}
def flatten_tokens(tokens, prefix=''):
flat = {}
for key, value in tokens.items():
path = f"{prefix}.{key}" if prefix else key
if isinstance(value, dict) and '$value' in value:
flat[path] = value
elif isinstance(value, dict):
flat.update(flatten_tokens(value, path))
return flat
flat_tokens = flatten_tokens(tokens)
# Generate recommendations based on token types
color_tokens = [t for t in flat_tokens.keys() if t.startswith('color.')]
spacing_tokens = [t for t in flat_tokens.keys() if t.startswith('spacing.')]
typography_tokens = [t for t in flat_tokens.keys() if t.startswith('typography.')]
if color_tokens:
alignment['recommendations'].append({
'category': 'colors',
'action': f'Add {len(color_tokens)} color tokens to Tailwind theme.extend.colors',
'example': f'"{color_tokens[0]}": "var(--{color_tokens[0].replace(".", "-")})"'
})
if spacing_tokens:
alignment['recommendations'].append({
'category': 'spacing',
'action': f'Add {len(spacing_tokens)} spacing tokens to Tailwind theme.extend.spacing',
'example': f'"{spacing_tokens[0].split(".")[-1]}": "var(--{spacing_tokens[0].replace(".", "-")})"'
})
if typography_tokens:
alignment['recommendations'].append({
'category': 'typography',
'action': f'Add {len(typography_tokens)} typography tokens to Tailwind theme.extend.fontSize',
'example': 'Use Style Dictionary to generate Tailwind @theme directive'
})
return alignment
def generate_audit_summary(token_alignment: Dict[str, Any],
component_reuse: List[Dict[str, Any]]) -> Dict[str, Any]:
"""
Generate overall audit summary with priority levels.
Args:
token_alignment: Token alignment report
component_reuse: Component reuse opportunities
Returns:
Summary with priority levels and recommendations
"""
total_tokens = (
len(token_alignment['in_sync']) +
len(token_alignment['drift_detected']) +
len(token_alignment['missing_in_code']) +
len(token_alignment['unused_in_design'])
)
drift_count = len(token_alignment['drift_detected'])
missing_count = len(token_alignment['missing_in_code'])
# Determine priority
if drift_count > 10 or (drift_count / max(total_tokens, 1)) > 0.2:
priority = 'critical'
elif drift_count > 5 or missing_count > 10:
priority = 'high'
elif drift_count > 0 or missing_count > 0:
priority = 'medium'
else:
priority = 'low'
summary = {
'token_health': {
'total': total_tokens,
'in_sync': len(token_alignment['in_sync']),
'drift_detected': drift_count,
'missing_in_code': missing_count,
'unused_in_design': len(token_alignment['unused_in_design']),
'sync_percentage': f"{(len(token_alignment['in_sync']) / max(total_tokens, 1)) * 100:.1f}%"
},
'component_reuse': {
'opportunities_found': len(component_reuse),
'estimated_time_savings': f"{len(component_reuse) * 2}-{len(component_reuse) * 3} hours"
},
'priority': priority,
'top_recommendations': generate_top_recommendations(
token_alignment,
component_reuse,
priority
)
}
return summary
def generate_top_recommendations(token_alignment: Dict[str, Any],
component_reuse: List[Dict[str, Any]],
priority: str) -> List[str]:
"""Generate top 3-5 recommendations based on audit results."""
recommendations = []
drift_count = len(token_alignment['drift_detected'])
missing_count = len(token_alignment['missing_in_code'])
if drift_count > 0:
recommendations.append(
f"⚠️ Fix {drift_count} drifted tokens - update design-tokens.json with Figma values"
)
if missing_count > 0:
recommendations.append(
f" Add {missing_count} new tokens to design system - run Style Dictionary build after"
)
if len(token_alignment['unused_in_design']) > 5:
recommendations.append(
f"🗑️ Clean up {len(token_alignment['unused_in_design'])} unused tokens in codebase"
)
if component_reuse:
top_reuse = component_reuse[0]
recommendations.append(
f"♻️ Reuse opportunity: Extend {top_reuse['existing_component']} instead of creating {top_reuse['figma_component']}"
)
if priority == 'low':
recommendations.append("✅ Design system is well-aligned - good maintenance!")
return recommendations[:5]
def audit_design_system(figma_data: Dict[str, Any],
code_data: Dict[str, Any]) -> Dict[str, Any]:
"""
Main audit function: comprehensive design system health check.
Args:
figma_data: Combined Figma data (tokens, components, mappings)
code_data: Combined code data (design-tokens.json, ui-kit-inventory, etc.)
Returns:
Complete audit report with recommendations
"""
# Extract data
figma_tokens = figma_data.get('tokens', {})
figma_components = figma_data.get('components', [])
component_mappings = figma_data.get('component_mappings', {})
code_tokens = code_data.get('design_tokens', {})
ui_kit_inventory = code_data.get('ui_kit_inventory', {})
# Run audits
token_alignment = audit_token_alignment(figma_tokens, code_tokens)
component_reuse = analyze_component_reuse(figma_components, component_mappings)
tailwind_alignment = audit_tailwind_config(code_tokens)
# Generate summary
summary = generate_audit_summary(token_alignment, component_reuse)
return {
'token_alignment': token_alignment,
'component_reuse_opportunities': component_reuse,
'tailwind_alignment': tailwind_alignment,
'summary': summary
}
def main():
parser = argparse.ArgumentParser(
description='Audit design system for drift and reuse opportunities'
)
parser.add_argument(
'--figma-data',
required=True,
help='Path to JSON file with Figma data (tokens, components, mappings)'
)
parser.add_argument(
'--code-data',
required=True,
help='Path to JSON file with code data (design-tokens.json, ui-kit-inventory)'
)
parser.add_argument(
'--output',
help='Output file path (default: stdout)'
)
args = parser.parse_args()
# Load data
with open(args.figma_data, 'r') as f:
figma_data = json.load(f)
with open(args.code_data, 'r') as f:
code_data = json.load(f)
# Run audit
audit_results = audit_design_system(figma_data, code_data)
# Output results
output_json = json.dumps(audit_results, indent=2)
if args.output:
with open(args.output, 'w') as f:
f.write(output_json)
else:
print(output_json)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,332 @@
#!/usr/bin/env python3
"""
Figma MCP Client - Direct Python interface to Figma Desktop MCP server.
This module provides a simple async interface to Figma's Model Context Protocol
server running locally at http://127.0.0.1:3845/mcp
Usage:
async with FigmaMCPClient() as client:
# Get design tokens
tokens = await client.get_variable_defs()
# Get component metadata
metadata = await client.get_metadata(node_id="1:23")
# Get code mappings
mappings = await client.get_code_connect_map()
Requirements:
- Figma Desktop app must be running
- MCP server enabled in Figma Preferences
- User logged into Figma
- pip install mcp
"""
import json
import logging
from typing import Optional, Dict, Any, List
try:
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
except ImportError as e:
raise ImportError(
"MCP SDK not installed. Install with: pip install mcp"
) from e
logger = logging.getLogger(__name__)
class FigmaMCPError(Exception):
"""Base exception for Figma MCP client errors."""
pass
class FigmaNotRunningError(FigmaMCPError):
"""Raised when Figma Desktop is not running or MCP server not enabled."""
pass
class FigmaMCPClient:
"""
Async client for Figma Desktop MCP server.
Provides direct access to Figma's design data through the Model Context Protocol.
Use as async context manager to ensure proper connection lifecycle.
Example:
async with FigmaMCPClient() as client:
variables = await client.get_variable_defs()
print(f"Found {len(variables)} design tokens")
"""
def __init__(self, mcp_url: str = "http://127.0.0.1:3845/mcp"):
"""
Initialize Figma MCP client.
Args:
mcp_url: URL of Figma Desktop MCP server (default: http://127.0.0.1:3845/mcp)
"""
self.mcp_url = mcp_url
self.session = None
self.transport = None
self.session_context = None
async def __aenter__(self):
"""Async context manager entry - establishes MCP connection."""
try:
# Connect to Figma MCP server
self.transport = streamablehttp_client(self.mcp_url)
self.read_stream, self.write_stream, _ = await self.transport.__aenter__()
# Create MCP session
self.session_context = ClientSession(self.read_stream, self.write_stream)
self.session = await self.session_context.__aenter__()
# Initialize MCP protocol
init_result = await self.session.initialize()
logger.info(
f"Connected to {init_result.serverInfo.name} "
f"v{init_result.serverInfo.version}"
)
return self
except Exception as e:
logger.error(f"Failed to connect to Figma MCP server: {e}")
raise FigmaNotRunningError(
"Could not connect to Figma Desktop MCP server. "
"Please ensure:\n"
" 1. Figma Desktop app is running\n"
" 2. MCP server is enabled in Figma → Preferences\n"
" 3. You are logged into Figma\n"
f"Error: {e}"
) from e
async def __aexit__(self, *args):
"""Async context manager exit - closes MCP connection."""
try:
if self.session_context:
await self.session_context.__aexit__(*args)
if self.transport:
await self.transport.__aexit__(*args)
logger.info("Disconnected from Figma MCP server")
except Exception as e:
logger.warning(f"Error during disconnect: {e}")
async def _call_tool(self, tool_name: str, params: Optional[Dict[str, Any]] = None) -> Any:
"""
Internal method to call MCP tool and extract content.
Args:
tool_name: Name of the MCP tool to call
params: Tool parameters
Returns:
Tool response content (parsed as JSON if possible)
"""
if not self.session:
raise FigmaMCPError("Client not connected. Use 'async with FigmaMCPClient()'")
try:
result = await self.session.call_tool(tool_name, params or {})
# Extract content from MCP response
if result.content and len(result.content) > 0:
content_item = result.content[0]
# Handle different content types
if hasattr(content_item, 'text'):
# Text content (most common)
content = content_item.text
# Try to parse as JSON
try:
return json.loads(content)
except (json.JSONDecodeError, TypeError):
# Return raw text if not JSON
return content
elif hasattr(content_item, 'data'):
# Image or binary content
return content_item.data
else:
# Unknown content type - return as-is
return content_item
return None
except Exception as e:
logger.error(f"Error calling {tool_name}: {e}")
raise FigmaMCPError(f"Failed to call {tool_name}: {e}") from e
async def get_metadata(self, node_id: Optional[str] = None) -> Dict[str, Any]:
"""
Get metadata for a node or page in XML format.
Includes node IDs, layer types, names, positions, and sizes.
Use this to discover component structure before fetching full details.
Args:
node_id: Specific node or page ID (e.g., "1:23" or "0:1")
If None, uses currently selected node in Figma
Returns:
Metadata dictionary with node structure
Example:
metadata = await client.get_metadata(node_id="0:1")
# Parse to find component node IDs
"""
params = {"nodeId": node_id} if node_id else {}
return await self._call_tool("get_metadata", params)
async def get_variable_defs(self, node_id: Optional[str] = None) -> Dict[str, str]:
"""
Get design token variable definitions.
Returns mapping of variable names to values.
Args:
node_id: Specific node ID (if None, uses currently selected)
Returns:
Dictionary mapping variable names to values
Example: {'icon/default/secondary': '#949494', 'spacing/md': '16px'}
Example:
tokens = await client.get_variable_defs()
for name, value in tokens.items():
print(f"{name}: {value}")
"""
params = {"nodeId": node_id} if node_id else {}
return await self._call_tool("get_variable_defs", params)
async def get_code_connect_map(self, node_id: Optional[str] = None) -> Dict[str, Dict[str, str]]:
"""
Get mapping of Figma components to code components.
Requires Figma Enterprise plan with Code Connect configured.
Args:
node_id: Specific node ID (if None, uses currently selected)
Returns:
Dictionary mapping node IDs to code locations
Example: {
'1:2': {
'codeConnectSrc': 'https://github.com/foo/components/Button.tsx',
'codeConnectName': 'Button'
}
}
Example:
mappings = await client.get_code_connect_map()
for node_id, mapping in mappings.items():
print(f"{node_id}{mapping['codeConnectName']}")
"""
params = {"nodeId": node_id} if node_id else {}
return await self._call_tool("get_code_connect_map", params)
async def get_design_context(self, node_id: Optional[str] = None) -> str:
"""
Generate UI code for a component.
Returns React/Vue/HTML implementation code for the selected component.
Use sparingly - can return large responses (50-100k tokens).
Args:
node_id: Specific node ID (if None, uses currently selected)
Returns:
UI code as string (React/Vue/HTML)
Example:
code = await client.get_design_context(node_id="1:23")
# Returns React component code
"""
params = {"nodeId": node_id} if node_id else {}
return await self._call_tool("get_design_context", params)
async def get_screenshot(self, node_id: Optional[str] = None) -> str:
"""
Generate screenshot for a component.
Args:
node_id: Specific node ID (if None, uses currently selected)
Returns:
Screenshot image data (format depends on Figma response)
Example:
screenshot = await client.get_screenshot(node_id="1:23")
# Save or process screenshot data
"""
params = {"nodeId": node_id} if node_id else {}
return await self._call_tool("get_screenshot", params)
async def create_design_system_rules(self) -> str:
"""
Generate design system rules for the repository.
Returns:
Prompt for design system rules generation
Example:
rules = await client.create_design_system_rules()
"""
return await self._call_tool("create_design_system_rules")
async def list_available_tools(self) -> List[str]:
"""
List all available MCP tools.
Useful for debugging or discovering what Figma MCP supports.
Returns:
List of tool names
Example:
tools = await client.list_available_tools()
print(f"Available: {', '.join(tools)}")
"""
if not self.session:
raise FigmaMCPError("Client not connected")
result = await self.session.list_tools()
return [tool.name for tool in result.tools]
# Convenience function for simple use cases
async def get_figma_variables() -> Dict[str, str]:
"""
Quick helper to fetch Figma design tokens.
Returns:
Dictionary of variable name → value mappings
Example:
tokens = await get_figma_variables()
"""
async with FigmaMCPClient() as client:
return await client.get_variable_defs()
async def get_figma_metadata(node_id: Optional[str] = None) -> Dict[str, Any]:
"""
Quick helper to fetch Figma node metadata.
Args:
node_id: Specific node ID (if None, uses currently selected)
Returns:
Metadata dictionary
Example:
metadata = await get_figma_metadata(node_id="0:1")
"""
async with FigmaMCPClient() as client:
return await client.get_metadata(node_id)

View File

@@ -0,0 +1,391 @@
#!/usr/bin/env python3
"""
Generate implementation task documentation from design review analysis.
Creates phased breakdown with acceptance criteria and complexity estimates.
"""
import json
import argparse
from datetime import datetime
from typing import Dict, List, Any
def estimate_complexity(component_category: str, has_variants: bool, breaking_change: bool) -> tuple:
"""
Estimate implementation complexity and time.
Args:
component_category: atom, molecule, organism, template
has_variants: Whether component has variants/props
breaking_change: Whether this is a breaking change
Returns:
Tuple of (complexity_level, estimated_hours)
"""
base_hours = {
'atom': 2,
'molecule': 3,
'organism': 5,
'template': 8
}
hours = base_hours.get(component_category, 3)
if has_variants:
hours += 1
if breaking_change:
hours += 2
if hours <= 2:
complexity = 'Low'
elif hours <= 4:
complexity = 'Medium'
else:
complexity = 'High'
return complexity, hours
def generate_token_phase(new_tokens: List[Dict[str, Any]],
modified_tokens: List[Dict[str, Any]]) -> Dict[str, Any]:
"""Generate Phase 1: Design Tokens implementation plan."""
total_tokens = len(new_tokens) + len(modified_tokens)
hours = max(1, total_tokens // 10 + 1) # 10 tokens per hour estimate
subtasks = [
f"Add {len(new_tokens)} new tokens to design-tokens.json" if new_tokens else None,
f"Update {len(modified_tokens)} modified tokens" if modified_tokens else None,
"Run Style Dictionary build to generate platform outputs",
"Update Tailwind @theme with new variables",
"Verify token availability in Storybook tokens page"
]
acceptance_criteria = [
f"All {total_tokens} new/modified tokens available in Tailwind utilities",
"No breaking changes to existing token references",
"Style Dictionary build completes without errors",
"Storybook tokens page shows all additions"
]
return {
'name': 'Design Tokens',
'priority': 'High',
'estimated_hours': hours,
'description': f'Add and update {total_tokens} design tokens',
'subtasks': [task for task in subtasks if task],
'acceptance_criteria': acceptance_criteria,
'files_to_modify': [
'.agent/design-system/design-tokens.json',
'tailwind.config.js (or CSS @theme)',
'Storybook tokens documentation'
]
}
def generate_component_phase(component: Dict[str, Any], phase_number: int) -> Dict[str, Any]:
"""Generate component implementation phase."""
comp_name = component.get('name')
category = component.get('category', 'molecule')
properties = component.get('properties', {})
similar_to = component.get('similar_to', [])
has_variants = bool(properties.get('variants'))
breaking_change = component.get('breaking_change', False)
complexity, hours = estimate_complexity(category, has_variants, breaking_change)
# Determine approach
if similar_to and similar_to[0]['similarity'] >= 0.7:
approach = f"Extend existing {similar_to[0]['name']} component"
action = 'extend'
else:
approach = f"Create new {category} component"
action = 'create'
# Generate subtasks based on action
if action == 'extend':
subtasks = [
f"Add new variant props to {similar_to[0]['name']}",
"Update TypeScript interface with new props",
"Add styles for new variants",
"Update existing tests",
"Add Storybook stories for new variants"
]
files = [
similar_to[0].get('path', f'src/components/{category}/{comp_name}.tsx'),
f"src/components/{category}/{comp_name}.test.tsx",
f"src/components/{category}/{comp_name}.stories.tsx"
]
else:
subtasks = [
f"Create {comp_name} component file",
"Implement TypeScript props interface",
"Add styles (CSS modules/Tailwind)",
"Write unit tests",
"Create Storybook stories",
"Add barrel export (index.ts)"
]
files = [
f"src/components/{category}/{comp_name}.tsx",
f"src/components/{category}/{comp_name}.test.tsx",
f"src/components/{category}/{comp_name}.stories.tsx",
f"src/components/{category}/index.ts"
]
acceptance_criteria = [
f"{comp_name} renders correctly with all variants",
"100% test coverage for new props/variants" if action == 'extend' else "90%+ test coverage",
"Storybook shows all component states",
"No visual regression in existing components" if action == 'extend' else "Passes visual regression tests",
"Accessibility audit passes (a11y addon)"
]
if breaking_change:
acceptance_criteria.insert(0, "Migration guide created for breaking changes")
subtasks.append("Create migration documentation")
return {
'number': phase_number,
'name': comp_name,
'category': category,
'priority': 'High' if breaking_change else 'Medium',
'complexity': complexity,
'estimated_hours': hours,
'approach': approach,
'subtasks': subtasks,
'files_to_modify': files,
'acceptance_criteria': acceptance_criteria,
'breaking_change': breaking_change
}
def generate_task_document(task_id: str,
feature_name: str,
analysis_results: Dict[str, Any],
review_reference: str) -> str:
"""
Generate complete Navigator task document.
Args:
task_id: Task identifier (e.g., "TASK-16")
feature_name: Feature name (e.g., "Dashboard Redesign")
analysis_results: Combined analysis from all functions
review_reference: Path to design review report
Returns:
Markdown task document
"""
date = datetime.now().strftime('%Y-%m-%d')
# Extract data
new_tokens = analysis_results.get('new_tokens', [])
modified_tokens = analysis_results.get('token_diff', {}).get('modified', [])
new_components = analysis_results.get('new_components', [])
similar_components = analysis_results.get('similar_components', [])
breaking_changes = analysis_results.get('breaking_changes', [])
# Generate phases
phases = []
# Phase 1: Always start with tokens if any exist
if new_tokens or modified_tokens:
phases.append(generate_token_phase(new_tokens, modified_tokens))
# Phase 2+: Component implementations
for i, comp in enumerate(new_components + similar_components, start=2):
phases.append(generate_component_phase(comp, i))
# Calculate totals
total_hours = sum(phase.get('estimated_hours', 0) for phase in phases)
total_complexity = 'High' if total_hours > 10 else 'Medium' if total_hours > 5 else 'Low'
# Build markdown document
doc = f"""# {task_id}: {feature_name} Implementation
**Created**: {date}
**Status**: Ready for Development
**Priority**: High
**Complexity**: {total_complexity}
**Estimated Time**: {total_hours} hours
---
## Context
Implement {feature_name} from Figma mockup with design system integration.
**Design Review**: `{review_reference}`
---
## Overview
**Changes Required**:
- Design Tokens: {len(new_tokens)} new, {len(modified_tokens)} modified
- Components: {len(new_components)} new, {len(similar_components)} to extend
- Breaking Changes: {len(breaking_changes)}
**Implementation Strategy**: Phased approach following atomic design hierarchy
---
## Implementation Phases
"""
# Add each phase
for i, phase in enumerate(phases, start=1):
doc += f"""### Phase {i}: {phase['name']}
**Priority**: {phase['priority']}
**Complexity**: {phase.get('complexity', 'Medium')}
**Estimated Time**: {phase['estimated_hours']} hours
#### Approach
{phase.get('approach', phase.get('description', 'Implement component following project patterns'))}
#### Subtasks
"""
for subtask in phase['subtasks']:
doc += f"- {subtask}\n"
doc += f"""
#### Files to Modify
"""
for file in phase.get('files_to_modify', []):
doc += f"- `{file}`\n"
doc += f"""
**Acceptance Criteria**:
"""
for criterion in phase['acceptance_criteria']:
doc += f"- [ ] {criterion}\n"
doc += "\n---\n\n"
# Add testing strategy
doc += """## Testing Strategy
### Unit Tests
- All new/modified components
- Test all variants and props
- Error states and edge cases
- Target: 90%+ coverage
### Visual Regression
- Chromatic for all component stories
- Test all variants and states
- Verify no regressions in existing components
### Integration Tests
- Test component composition
- Verify design token usage
- Test responsive behavior
### Accessibility
- Run a11y addon in Storybook
- Keyboard navigation testing
- Screen reader verification
- WCAG 2.2 Level AA compliance
---
## Rollout Plan
1. **Phase 1: Tokens** (no visual changes, safe to deploy)
2. **Phase 2-N: Components** (incremental deployment)
- Deploy each component after testing
- Monitor for issues before next phase
3. **Final: Integration** (full feature integration)
**Rollback Strategy**: Each phase is independent and can be reverted
---
## Success Metrics
- [ ] 100% design fidelity vs Figma mockup
- [ ] All acceptance criteria met
- [ ] No visual regressions
- [ ] All accessibility checks pass
- [ ] Performance budget maintained (no layout shifts)
---
## Design System Impact
**UI Kit Inventory**: Update after each component completion
**Token Additions**: {len(new_tokens)} new tokens added to design system
**Component Reuse**: {len(similar_components)} opportunities to extend existing components
---
## Notes
{f"⚠️ **Breaking Changes**: {len(breaking_changes)} component(s) require migration - see phase details" if breaking_changes else "✅ No breaking changes - backward compatible implementation"}
---
**Last Updated**: {date}
**Navigator Version**: 3.2.0
"""
return doc
def main():
parser = argparse.ArgumentParser(
description='Generate implementation task document from design review'
)
parser.add_argument(
'--task-id',
required=True,
help='Task identifier (e.g., TASK-16)'
)
parser.add_argument(
'--feature-name',
required=True,
help='Feature name (e.g., "Dashboard Redesign")'
)
parser.add_argument(
'--analysis-results',
required=True,
help='Path to JSON file with combined analysis results'
)
parser.add_argument(
'--review-reference',
required=True,
help='Path to design review report'
)
parser.add_argument(
'--output',
help='Output file path (default: stdout)'
)
args = parser.parse_args()
# Load analysis results
with open(args.analysis_results, 'r') as f:
analysis_results = json.load(f)
# Generate task document
task_doc = generate_task_document(
args.task_id,
args.feature_name,
analysis_results,
args.review_reference
)
# Output
if args.output:
with open(args.output, 'w') as f:
f.write(task_doc)
else:
print(task_doc)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,51 @@
#!/usr/bin/env python3
"""
Test Figma MCP connection - Quick validation script.
Tests connection to Figma Desktop MCP server and lists available tools.
"""
import asyncio
import sys
try:
from figma_mcp_client import FigmaMCPClient, FigmaNotRunningError
except ImportError:
print("❌ Error: figma_mcp_client not found")
print(" Ensure you're in the correct directory: skills/product-design/functions/")
sys.exit(1)
async def test_connection():
"""Test Figma MCP connection."""
try:
async with FigmaMCPClient() as client:
# List available tools
tools = await client.list_available_tools()
print("✅ Successfully connected to Figma MCP server")
print(f" Found {len(tools)} tools:")
for tool in tools:
print(f" - {tool}")
return True
except FigmaNotRunningError as e:
print("❌ Figma Desktop not running or MCP not enabled")
print(f" {e}")
return False
except Exception as e:
print(f"❌ Unexpected error: {e}")
import traceback
traceback.print_exc()
return False
async def main():
"""Main entry point."""
success = await test_connection()
sys.exit(0 if success else 1)
if __name__ == "__main__":
asyncio.run(main())

View File

@@ -0,0 +1,394 @@
#!/usr/bin/env python3
"""
Extract design tokens from Figma variables and convert to DTCG format.
Compares with existing tokens and generates diff summary.
"""
import json
import sys
import argparse
from typing import Dict, List, Any, Tuple
def normalize_token_name(figma_name: str) -> str:
"""
Normalize Figma variable name to DTCG semantic naming.
Examples:
"Primary 500""color.primary.500"
"Spacing MD""spacing.md"
"Font Heading Large""typography.heading.large"
Args:
figma_name: Original Figma variable name
Returns:
Normalized DTCG token path
"""
name = figma_name.strip()
# Convert to lowercase and split
parts = name.lower().replace('-', ' ').replace('_', ' ').split()
# Detect token type from name
if any(keyword in parts for keyword in ['color', 'colour']):
token_type = 'color'
parts = [p for p in parts if p not in ['color', 'colour']]
elif any(keyword in parts for keyword in ['spacing', 'space', 'gap', 'padding', 'margin']):
token_type = 'spacing'
parts = [p for p in parts if p not in ['spacing', 'space', 'gap', 'padding', 'margin']]
elif any(keyword in parts for keyword in ['font', 'typography', 'text']):
token_type = 'typography'
parts = [p for p in parts if p not in ['font', 'typography', 'text']]
elif any(keyword in parts for keyword in ['radius', 'border']):
token_type = 'radius'
parts = [p for p in parts if p not in ['radius', 'border']]
elif any(keyword in parts for keyword in ['shadow', 'elevation']):
token_type = 'shadow'
parts = [p for p in parts if p not in ['shadow', 'elevation']]
else:
# Infer from first part
first_part = parts[0] if parts else ''
if first_part in ['primary', 'secondary', 'success', 'error', 'warning', 'info']:
token_type = 'color'
elif first_part in ['xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl']:
token_type = 'spacing'
else:
token_type = 'other'
# Build token path
if parts:
return f"{token_type}.{'.'.join(parts)}"
else:
return token_type
def detect_token_type(name: str, value: Any) -> str:
"""
Detect DTCG token type from name and value.
Args:
name: Token name
value: Token value
Returns:
DTCG type string
"""
name_lower = name.lower()
# Check by name first
if 'color' in name_lower or 'colour' in name_lower:
return 'color'
elif 'spacing' in name_lower or 'gap' in name_lower or 'padding' in name_lower or 'margin' in name_lower:
return 'dimension'
elif 'font' in name_lower or 'typography' in name_lower:
if isinstance(value, dict):
return 'typography'
else:
return 'fontFamily' if 'family' in name_lower else 'dimension'
elif 'radius' in name_lower or 'border' in name_lower:
return 'dimension'
elif 'shadow' in name_lower or 'elevation' in name_lower:
return 'shadow'
elif 'duration' in name_lower or 'transition' in name_lower:
return 'duration'
elif 'opacity' in name_lower or 'alpha' in name_lower:
return 'number'
# Infer from value
if isinstance(value, str):
if value.startswith('#') or value.startswith('rgb'):
return 'color'
elif value.endswith('px') or value.endswith('rem') or value.endswith('em'):
return 'dimension'
elif value.endswith('ms') or value.endswith('s'):
return 'duration'
elif isinstance(value, (int, float)):
return 'number'
elif isinstance(value, dict):
if 'fontFamily' in value or 'fontSize' in value:
return 'typography'
elif 'x' in value and 'y' in value:
return 'shadow'
return 'other'
def convert_to_dtcg(figma_variables: Dict[str, Any]) -> Dict[str, Any]:
"""
Convert Figma variables to DTCG format.
Args:
figma_variables: Figma get_variable_defs response
Returns:
DTCG formatted tokens
"""
dtcg_tokens = {}
for var_name, var_data in figma_variables.items():
# Extract value and type
if isinstance(var_data, dict):
value = var_data.get('$value') or var_data.get('value')
var_type = var_data.get('$type') or var_data.get('type')
description = var_data.get('$description') or var_data.get('description', '')
else:
value = var_data
var_type = None
description = ''
# Detect type if not provided
if not var_type:
var_type = detect_token_type(var_name, value)
# Normalize token name to DTCG path
token_path = normalize_token_name(var_name)
# Build nested structure
path_parts = token_path.split('.')
current = dtcg_tokens
for i, part in enumerate(path_parts):
if i == len(path_parts) - 1:
# Last part - add token definition
current[part] = {
'$value': value,
'$type': var_type
}
if description:
current[part]['$description'] = description
else:
# Intermediate path - create nested dict
if part not in current:
current[part] = {}
current = current[part]
return dtcg_tokens
def generate_diff(new_tokens: Dict[str, Any],
existing_tokens: Dict[str, Any]) -> Dict[str, List[Dict[str, Any]]]:
"""
Generate diff between new and existing tokens.
Args:
new_tokens: New tokens from Figma (DTCG format)
existing_tokens: Existing tokens from design-tokens.json
Returns:
Diff summary with added, modified, removed, unchanged
"""
diff = {
'added': [],
'modified': [],
'removed': [],
'unchanged': []
}
# Flatten tokens for comparison
new_flat = flatten_tokens(new_tokens)
existing_flat = flatten_tokens(existing_tokens)
# Find added and modified
for token_path, token_data in new_flat.items():
if token_path not in existing_flat:
diff['added'].append({
'path': token_path,
'value': token_data.get('$value'),
'type': token_data.get('$type')
})
else:
existing_value = existing_flat[token_path].get('$value')
new_value = token_data.get('$value')
if existing_value != new_value:
diff['modified'].append({
'path': token_path,
'old_value': existing_value,
'new_value': new_value,
'type': token_data.get('$type')
})
else:
diff['unchanged'].append({
'path': token_path,
'value': new_value
})
# Find removed
for token_path, token_data in existing_flat.items():
if token_path not in new_flat:
diff['removed'].append({
'path': token_path,
'value': token_data.get('$value'),
'type': token_data.get('$type')
})
return diff
def flatten_tokens(tokens: Dict[str, Any], prefix: str = '') -> Dict[str, Any]:
"""
Flatten nested DTCG tokens to dot notation paths.
Args:
tokens: Nested DTCG token structure
prefix: Current path prefix
Returns:
Flattened dictionary with dot notation keys
"""
flat = {}
for key, value in tokens.items():
current_path = f"{prefix}.{key}" if prefix else key
if isinstance(value, dict) and '$value' in value:
# This is a token definition
flat[current_path] = value
elif isinstance(value, dict):
# This is a nested group
flat.update(flatten_tokens(value, current_path))
return flat
def generate_summary(diff: Dict[str, List[Dict[str, Any]]]) -> Dict[str, Any]:
"""
Generate summary statistics from diff.
Args:
diff: Token diff
Returns:
Summary statistics
"""
total_new = len(diff['added']) + len(diff['unchanged'])
total_existing = len(diff['modified']) + len(diff['removed']) + len(diff['unchanged'])
return {
'total_new_tokens': total_new,
'total_existing_tokens': total_existing,
'added_count': len(diff['added']),
'modified_count': len(diff['modified']),
'removed_count': len(diff['removed']),
'unchanged_count': len(diff['unchanged']),
'sync_status': 'in_sync' if len(diff['added']) == 0 and len(diff['modified']) == 0 and len(diff['removed']) == 0 else 'drift_detected',
'drift_percentage': f"{((len(diff['modified']) + len(diff['removed'])) / max(total_existing, 1)) * 100:.1f}%"
}
def extract_tokens(figma_variables: Dict[str, Any],
existing_tokens: Dict[str, Any] = None) -> Dict[str, Any]:
"""
Main extraction function: convert Figma variables to DTCG and generate diff.
Args:
figma_variables: Figma get_variable_defs response
existing_tokens: Current design-tokens.json (optional)
Returns:
Extraction results with DTCG tokens, diff, and summary
"""
# Convert to DTCG format
dtcg_tokens = convert_to_dtcg(figma_variables)
# Generate diff if existing tokens provided
if existing_tokens:
diff = generate_diff(dtcg_tokens, existing_tokens)
summary = generate_summary(diff)
else:
# No existing tokens - all are new
flat = flatten_tokens(dtcg_tokens)
diff = {
'added': [
{
'path': path,
'value': data.get('$value'),
'type': data.get('$type')
}
for path, data in flat.items()
],
'modified': [],
'removed': [],
'unchanged': []
}
summary = {
'total_new_tokens': len(flat),
'total_existing_tokens': 0,
'added_count': len(flat),
'modified_count': 0,
'removed_count': 0,
'unchanged_count': 0,
'sync_status': 'initial_extraction',
'drift_percentage': '0.0%'
}
return {
'dtcg_tokens': dtcg_tokens,
'diff': diff,
'summary': summary
}
def main():
parser = argparse.ArgumentParser(
description='Extract design tokens from Figma and convert to DTCG format'
)
parser.add_argument(
'--figma-variables',
required=True,
help='Path to JSON file with Figma variables (get_variable_defs response)'
)
parser.add_argument(
'--existing-tokens',
help='Path to existing design-tokens.json (optional)'
)
parser.add_argument(
'--output',
help='Output file path (default: stdout)'
)
parser.add_argument(
'--format',
choices=['full', 'tokens-only', 'diff-only'],
default='full',
help='Output format (default: full)'
)
args = parser.parse_args()
# Load Figma variables
with open(args.figma_variables, 'r') as f:
figma_variables = json.load(f)
# Load existing tokens if provided
existing_tokens = None
if args.existing_tokens:
with open(args.existing_tokens, 'r') as f:
existing_tokens = json.load(f)
# Run extraction
results = extract_tokens(figma_variables, existing_tokens)
# Format output based on --format flag
if args.format == 'tokens-only':
output = results['dtcg_tokens']
elif args.format == 'diff-only':
output = {
'diff': results['diff'],
'summary': results['summary']
}
else:
output = results
output_json = json.dumps(output, indent=2)
# Write output
if args.output:
with open(args.output, 'w') as f:
f.write(output_json)
else:
print(output_json)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,9 @@
# Navigator Product Design Skill - Python Dependencies
# MCP SDK for direct Figma Desktop connection
mcp>=1.2.1
# Already included as transitive dependencies of mcp, but listing for clarity:
# anyio>=4.0.0 # Async I/O
# httpx>=0.25.0 # HTTP client
# pydantic>=2.0.0 # Data validation

95
skills/product-design/setup.sh Executable file
View File

@@ -0,0 +1,95 @@
#!/bin/bash
#
# Navigator Product Design Skill - Setup Script
#
# Automatically installs Python dependencies and verifies Figma MCP connection.
#
# Usage:
# chmod +x setup.sh
# ./setup.sh
set -e
SKILL_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
FUNCTIONS_DIR="$SKILL_DIR/functions"
echo "=========================================="
echo "Navigator Product Design Skill - Setup"
echo "=========================================="
echo ""
# Step 1: Check Python version
echo "[1/5] Checking Python version..."
PYTHON_VERSION=$(python3 --version 2>&1 | awk '{print $2}')
PYTHON_MAJOR=$(echo "$PYTHON_VERSION" | cut -d. -f1)
PYTHON_MINOR=$(echo "$PYTHON_VERSION" | cut -d. -f2)
if [ "$PYTHON_MAJOR" -lt 3 ] || ([ "$PYTHON_MAJOR" -eq 3 ] && [ "$PYTHON_MINOR" -lt 10 ]); then
echo "❌ Python 3.10+ required (found $PYTHON_VERSION)"
exit 1
fi
echo "✅ Python $PYTHON_VERSION"
echo ""
# Step 2: Create virtual environment (optional but recommended)
echo "[2/5] Setting up Python environment..."
if [ ! -d "$SKILL_DIR/venv" ]; then
echo "Creating virtual environment..."
python3 -m venv "$SKILL_DIR/venv"
echo "✅ Virtual environment created at $SKILL_DIR/venv"
else
echo "✅ Virtual environment already exists"
fi
# Activate venv
source "$SKILL_DIR/venv/bin/activate"
echo ""
# Step 3: Install dependencies
echo "[3/5] Installing Python dependencies..."
pip install --quiet --upgrade pip
pip install --quiet -r "$SKILL_DIR/requirements.txt"
echo "✅ Dependencies installed (mcp>=1.2.1)"
echo ""
# Step 4: Verify Figma Desktop is running
echo "[4/5] Checking Figma Desktop status..."
if command -v lsof &> /dev/null; then
if lsof -i :3845 &> /dev/null; then
echo "✅ Figma MCP server detected (port 3845)"
else
echo "⚠️ Figma MCP server not detected"
echo " Please ensure:"
echo " 1. Figma Desktop app is running"
echo " 2. MCP server enabled: Figma → Preferences → Enable local MCP Server"
echo " 3. You are logged into Figma"
echo ""
echo " Setup will continue, but MCP features won't work until Figma is running."
fi
else
echo "⚠️ Cannot check port (lsof not available)"
echo " Please manually verify Figma Desktop is running"
fi
echo ""
# Step 5: Test MCP connection
echo "[5/5] Testing Figma MCP connection..."
python3 "$FUNCTIONS_DIR/test_mcp_connection.py" 2>&1
echo ""
echo "=========================================="
echo "✅ Setup Complete!"
echo "=========================================="
echo ""
echo "Next steps:"
echo " 1. Ensure Figma Desktop is running"
echo " 2. Enable MCP: Figma → Preferences → Enable local MCP Server"
echo " 3. Try the skill: \"Review this Figma design: [URL]\""
echo ""
echo "To activate the virtual environment manually:"
echo " source $SKILL_DIR/venv/bin/activate"
echo ""
echo "Documentation:"
echo " - SKILL.md: Skill usage guide"
echo " - functions/figma_mcp_client.py: MCP client API"
echo ""

View File

@@ -0,0 +1,230 @@
# Design Review: {{FEATURE_NAME}}
**Date**: {{DATE}}
**Figma**: {{FIGMA_LINK}}
**Reviewer**: Navigator Product Design Skill
---
## Summary
{{SUMMARY_DESCRIPTION}}
**Changes Overview**:
- Design Tokens: {{NEW_TOKENS_COUNT}} new, {{MODIFIED_TOKENS_COUNT}} modified
- Components: {{NEW_COMPONENTS_COUNT}} new, {{EXTEND_COMPONENTS_COUNT}} to extend
- Breaking Changes: {{BREAKING_CHANGES_COUNT}}
---
## New Design Tokens
### Colors
{{#each NEW_COLOR_TOKENS}}
- **{{name}}**: `{{value}}` ({{type}})
{{#if description}}_{{description}}_{{/if}}
{{/each}}
### Spacing
{{#each NEW_SPACING_TOKENS}}
- **{{name}}**: `{{value}}`
{{/each}}
### Typography
{{#each NEW_TYPOGRAPHY_TOKENS}}
- **{{name}}**: `{{value}}`
{{/each}}
### Other Tokens
{{#each OTHER_TOKENS}}
- **{{name}}**: `{{value}}` ({{type}})
{{/each}}
---
## Modified Design Tokens
{{#each MODIFIED_TOKENS}}
### {{path}}
- **Old Value**: `{{old_value}}`
- **New Value**: `{{new_value}}`
- **Impact**: {{impact_description}}
{{/each}}
{{#if NO_MODIFIED_TOKENS}}
_No tokens modified - all changes are additive._
{{/if}}
---
## New Components Required
### Atoms (Basic Elements)
{{#each ATOM_COMPONENTS}}
#### {{name}}
**Purpose**: {{purpose}}
**Variants**: {{variants}}
**States**: {{states}}
**Similar to**: {{similar_component}} ({{similarity_score}}% match)
**Recommendation**: {{recommendation}}
{{/each}}
### Molecules (Simple Combinations)
{{#each MOLECULE_COMPONENTS}}
#### {{name}}
**Purpose**: {{purpose}}
**Composition**: {{composition}}
**Variants**: {{variants}}
**Similar to**: {{similar_component}} ({{similarity_score}}% match)
**Recommendation**: {{recommendation}}
{{/each}}
### Organisms (Complex Components)
{{#each ORGANISM_COMPONENTS}}
#### {{name}}
**Purpose**: {{purpose}}
**Composition**: {{composition}}
**Responsive**: {{responsive_behavior}}
**Similar to**: {{similar_component}} ({{similarity_score}}% match)
**Recommendation**: {{recommendation}}
{{/each}}
---
## Component Reuse Opportunities
{{#each REUSE_OPPORTUNITIES}}
### {{figma_component}} → Extend {{existing_component}}
**Similarity**: {{similarity}}%
**Recommendation**: {{recommendation}}
**Time Saved**: {{time_saved}}
**Approach**: {{approach_description}}
{{/each}}
{{#if NO_REUSE_OPPORTUNITIES}}
_No reuse opportunities identified - all components are net new._
{{/if}}
---
## Design System Impact
### Token Health
- **In Sync**: {{IN_SYNC_COUNT}} tokens
- **Drift Detected**: {{DRIFT_COUNT}} tokens
- **Missing in Code**: {{MISSING_COUNT}} tokens
- **Unused in Design**: {{UNUSED_COUNT}} tokens
**Sync Status**: {{SYNC_STATUS}}
**Priority Level**: {{PRIORITY_LEVEL}}
### High Impact Changes
{{#each HIGH_IMPACT_CHANGES}}
- {{change_description}}
- **Impact**: {{impact_type}}
- **Action Required**: {{action_required}}
{{/each}}
### Low Impact Changes
{{#each LOW_IMPACT_CHANGES}}
- {{change_description}}
{{/each}}
---
## Implementation Recommendations
### Phased Approach
**Phase 1: Design Tokens** ({{PHASE_1_HOURS}} hours)
- Priority: {{PHASE_1_PRIORITY}}
- Add {{NEW_TOKENS_COUNT}} new tokens to design-tokens.json
- Update {{MODIFIED_TOKENS_COUNT}} existing tokens
- Run Style Dictionary build
- Update Tailwind @theme
**Phase 2: Atomic Components** ({{PHASE_2_HOURS}} hours)
- Priority: {{PHASE_2_PRIORITY}}
{{#each ATOM_COMPONENTS}}
- Implement {{name}} ({{complexity}}, {{estimated_hours}}h)
{{/each}}
**Phase 3: Molecule Components** ({{PHASE_3_HOURS}} hours)
- Priority: {{PHASE_3_PRIORITY}}
{{#each MOLECULE_COMPONENTS}}
- Implement {{name}} ({{complexity}}, {{estimated_hours}}h)
{{/each}}
**Phase 4: Organism Components** ({{PHASE_4_HOURS}} hours)
- Priority: {{PHASE_4_PRIORITY}}
{{#each ORGANISM_COMPONENTS}}
- Implement {{name}} ({{complexity}}, {{estimated_hours}}h)
{{/each}}
### Total Estimated Time
**{{TOTAL_HOURS}} hours** ({{TOTAL_COMPLEXITY}} complexity)
---
## Breaking Changes
{{#each BREAKING_CHANGES}}
### {{component_name}}
**Issue**: {{issue_description}}
**Previous Mapping**: `{{previous_mapping}}`
**Recommendation**: {{recommendation}}
**Migration Steps**:
{{#each migration_steps}}
- {{step}}
{{/each}}
{{/each}}
{{#if NO_BREAKING_CHANGES}}
**No breaking changes** - all updates are backward compatible.
{{/if}}
---
## Next Steps
1. **Review Implementation Plan**: `.agent/tasks/TASK-{{TASK_NUMBER}}-{{FEATURE_SLUG}}.md`
2. **Update Design Tokens**: Phase 1 implementation
3. **Implement Components**: Follow atomic design hierarchy
4. **Test & Verify**: Visual regression, accessibility, unit tests
5. **Update UI Kit Inventory**: After each component completion
---
## Design Fidelity Checklist
- [ ] All design tokens extracted and added to design system
- [ ] Component structure matches Figma composition
- [ ] Variants and states implemented correctly
- [ ] Responsive behavior preserved
- [ ] Spacing and layout match pixel-perfect
- [ ] Typography styles applied correctly
- [ ] Colors and themes consistent
- [ ] Interactive states (hover, active, disabled) implemented
---
**Generated**: {{TIMESTAMP}}
**Navigator Version**: {{NAVIGATOR_VERSION}}
**Next Review**: After implementation completion