Why Cursor Needs Design Tokens
Cursor's AI is powerful at generating code, but without design tokens, it will:
- Guess color values (
bg-blue-500,#3B82F6,rgb(59, 130, 246)) - Use inconsistent spacing (
p-4,px-5,py-3) - Create arbitrary border radius values (
rounded-md,rounded-lg)
FramingUI solves this by giving Cursor a single source of truth for all design decisions.
Installation
Step 1: Install FramingUI
# Using pnpm (recommended)
pnpm add @framingui/ui @framingui/core
# Using npm
npm install @framingui/ui @framingui/core
# Using yarn
yarn add @framingui/ui @framingui/core
Step 2: Generate Design Tokens
# Interactive mode
npx framingui generate
# Or specify your brand color directly
npx framingui generate --color "#FF6B35"
This creates a .framingui/ directory with your design tokens:
.framingui/
├── tokens.css # CSS custom properties
├── tokens.json # JSON format for tooling
└── tailwind.config.js # Tailwind integration
Step 3: Import Tokens in Your App
// app/layout.tsx (Next.js App Router)
import '@framingui/ui/styles/tokens.css';
import './globals.css';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
Cursor Configuration
Create .cursorrules File
Create a .cursorrules file in your project root:
# FramingUI Design System Rules
## Component Library
Always import UI components from @framingui/ui:
- Button, Input, Card, Form, Dialog, Sheet, Tabs
- Label, Checkbox, RadioGroup, Select, Switch
- Table, Avatar, Badge, Tooltip, Popover
## Design Tokens
Use CSS custom properties for all styling:
### Colors
- Primary: var(--tekton-bg-primary)
- Secondary: var(--tekton-bg-secondary)
- Destructive: var(--tekton-bg-destructive)
- Muted: var(--tekton-bg-muted)
- Accent: var(--tekton-bg-accent)
- Card: var(--tekton-bg-card)
- Popover: var(--tekton-bg-popover)
### Spacing
- var(--tekton-spacing-1) through var(--tekton-spacing-8)
- Use these instead of Tailwind's p-1, p-2, etc.
### Border Radius
- var(--tekton-radius-sm)
- var(--tekton-radius-md)
- var(--tekton-radius-lg)
- var(--tekton-radius-xl)
### Borders
- var(--tekton-border-default)
- var(--tekton-border-input)
- var(--tekton-border-ring)
## Code Generation Rules
1. Never hardcode colors - always use var(--tekton-*)
2. Import components from @framingui/ui, not local files
3. Use semantic token names (primary, secondary) not color names (blue, red)
4. Prefer FramingUI components over raw HTML elements
5. Use Tailwind classes that reference tokens: bg-[var(--tekton-bg-primary)]
## Example Component
```tsx
import { Button, Card, CardHeader, CardTitle, CardContent } from '@framingui/ui';
export function ExampleCard() {
return (
<Card>
<CardHeader>
<CardTitle>Example</CardTitle>
</CardHeader>
<CardContent className="space-y-[var(--tekton-spacing-4)]">
<p className="text-[var(--tekton-bg-muted-foreground)]">
Card content here
</p>
<Button variant="default">Click me</Button>
</CardContent>
</Card>
);
}
### VSCode Settings (for Cursor)
Add to `.vscode/settings.json`:
```json
{
"editor.quickSuggestions": {
"strings": true
},
"css.customData": [".vscode/css-custom-data.json"]
}
Create .vscode/css-custom-data.json for token autocomplete:
{
"version": 1.1,
"properties": [
{
"name": "--tekton-bg-primary",
"description": "Primary background color"
},
{
"name": "--tekton-bg-secondary",
"description": "Secondary background color"
},
{
"name": "--tekton-spacing-4",
"description": "1rem spacing (16px)"
},
{
"name": "--tekton-radius-md",
"description": "Medium border radius"
}
]
}
Testing Cursor Integration
Test 1: Generate a Login Form
Ask Cursor:
Create a login form using FramingUI components with email and password fields
Expected output:
import { Button, Input, Label, Card, CardHeader, CardTitle, CardContent } from '@framingui/ui';
export function LoginForm() {
return (
<Card className="w-full max-w-md">
<CardHeader>
<CardTitle>Sign In</CardTitle>
</CardHeader>
<CardContent className="space-y-[var(--tekton-spacing-4)]">
<div className="space-y-[var(--tekton-spacing-2)]">
<Label htmlFor="email">Email</Label>
<Input id="email" type="email" placeholder="you@example.com" />
</div>
<div className="space-y-[var(--tekton-spacing-2)]">
<Label htmlFor="password">Password</Label>
<Input id="password" type="password" />
</div>
<Button className="w-full" variant="default">
Sign In
</Button>
</CardContent>
</Card>
);
}
✅ Verify: No hardcoded colors, uses var(--tekton-*) tokens
Test 2: Generate a Dashboard Card
Ask Cursor:
Create a stats card showing total users with an icon and value
Expected output:
import { Card, CardContent } from '@framingui/ui';
import { Users } from 'lucide-react';
export function StatsCard() {
return (
<Card>
<CardContent className="p-[var(--tekton-spacing-6)]">
<div className="flex items-center space-x-[var(--tekton-spacing-4)]">
<div className="p-[var(--tekton-spacing-3)] bg-[var(--tekton-bg-primary)]/10 rounded-[var(--tekton-radius-lg)]">
<Users className="w-6 h-6 text-[var(--tekton-bg-primary)]" />
</div>
<div>
<p className="text-sm text-[var(--tekton-bg-muted-foreground)]">Total Users</p>
<p className="text-2xl font-bold">12,345</p>
</div>
</div>
</CardContent>
</Card>
);
}
✅ Verify: Uses FramingUI Card, references design tokens
Troubleshooting
Issue: Cursor generates Tailwind classes without tokens
Solution: Update .cursorrules and explicitly ask:
Generate a button using FramingUI and var(--tekton-*) tokens
Issue: Token autocomplete not working
Solution: Restart Cursor after adding .vscode/css-custom-data.json
Issue: Components not found
Solution: Verify package installation:
pnpm list @framingui/ui
Advanced: Custom Token Extensions
You can extend FramingUI tokens for project-specific needs:
/* globals.css */
@import '@framingui/ui/styles/tokens.css';
:root {
/* Extend with custom tokens */
--my-app-header-height: 64px;
--my-app-sidebar-width: 280px;
/* Override FramingUI tokens (optional) */
--tekton-radius-xl: 16px;
}
Next Steps
- Configure Cursor: Add
.cursorrulesto your project - Test generation: Ask Cursor to create components
- Verify consistency: Check that all generated code uses tokens
- Iterate: Refine your rules based on Cursor's output
With FramingUI + Cursor, you get AI-powered UI generation with 0% hallucination on design decisions.