Loading...
Loading...
Convert Figma designs to production-ready React components with Tailwind CSS using VibeFigma
npx skill4agent add aradotso/design-skills vibefigma-figma-to-reactSkill by ara.so — Design Skills collection.
# Run directly (recommended)
npx vibefigma
# Install globally
npm install -g vibefigma
# Install as dev dependency
npm install --save-dev vibefigmaexport FIGMA_TOKEN=your_figma_access_token.envFIGMA_TOKEN=your_figma_access_tokennpx vibefigma --interactive# Basic usage
npx vibefigma "https://www.figma.com/design/FILE_ID/FILE_NAME?node-id=NODE_ID"
# With explicit token
npx vibefigma "https://www.figma.com/design/FILE_ID/FILE_NAME?node-id=NODE_ID" --token YOUR_TOKEN
# Custom output paths
npx vibefigma "https://www.figma.com/design/FILE_ID/FILE_NAME?node-id=NODE_ID" \
--component ./src/components/Hero.tsx \
--assets ./public/images
# Force overwrite without confirmation
npx vibefigma "https://www.figma.com/design/FILE_ID/FILE_NAME?node-id=NODE_ID" --force# Disable Tailwind CSS (generate regular CSS)
npx vibefigma [url] --no-tailwind
# Optimize generated code
npx vibefigma [url] --optimize
# Use AI code cleaner (requires GOOGLE_GENERATIVE_AI_API_KEY)
npx vibefigma [url] --clean
# Disable responsive design
npx vibefigma [url] --no-responsive
# Don't include font imports
npx vibefigma [url] --no-fonts
# Disable absolute positioning
npx vibefigma [url] --no-absoluteOptions:
-V, --version Output version
-t, --token <token> Figma access token (overrides FIGMA_TOKEN)
-u, --url <url> Figma file/node URL
-c, --component <path> Component output path (default: ./src/components/[ComponentName].tsx)
-a, --assets <dir> Assets directory (default: ./public)
--no-tailwind Disable Tailwind CSS
--optimize Optimize components
--clean Use AI code cleaner
--no-classes Don't generate CSS classes
--no-absolute Don't use absolute positioning
--no-responsive Disable responsive design
--no-fonts Don't include fonts
--interactive Force interactive mode
-f, --force Overwrite existing files without confirmation
-h, --help Display help# Figma URL for a login form component
npx vibefigma \
"https://www.figma.com/design/4i8Tp5btFPRqtkYXplnfT6/50-Web-Sign-up-log-in-designs--Community-?node-id=26-2944" \
--component ./src/components/LoginForm.tsx \
--assets ./public/login-assets \
--force// src/components/LoginForm.tsx
import React from 'react';
export const LoginForm: React.FC = () => {
return (
<div className="flex flex-col items-center justify-center min-h-screen bg-gray-50">
<div className="w-full max-w-md p-8 space-y-6 bg-white rounded-lg shadow-md">
<h2 className="text-2xl font-bold text-center text-gray-900">
Sign In
</h2>
<form className="space-y-4">
<div>
<label htmlFor="email" className="block text-sm font-medium text-gray-700">
Email
</label>
<input
id="email"
type="email"
className="w-full px-3 py-2 mt-1 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="you@example.com"
/>
</div>
<div>
<label htmlFor="password" className="block text-sm font-medium text-gray-700">
Password
</label>
<input
id="password"
type="password"
className="w-full px-3 py-2 mt-1 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
</div>
<button
type="submit"
className="w-full px-4 py-2 text-white bg-blue-600 rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500"
>
Sign In
</button>
</form>
</div>
</div>
);
};# Create a components directory structure
mkdir -p src/components/hero
mkdir -p public/hero-assets
# Convert hero section
npx vibefigma \
"https://www.figma.com/design/YOUR_FILE_ID?node-id=HERO_NODE_ID" \
--component ./src/components/hero/Hero.tsx \
--assets ./public/hero-assets \
--optimizenpx vibefigma \
"https://www.figma.com/design/YOUR_FILE_ID?node-id=NODE_ID" \
--no-tailwind \
--component ./src/components/CustomCard.tsx# Install dependencies
bun install
# Development mode
bun run dev
# Production mode
bun run start.envGOOGLE_GENERATIVE_AI_API_KEY=your_google_ai_key_here
PORT=3000
HOST=0.0.0.0
CORS_ORIGIN=*
FIGMA_TOKEN=your_figma_token_here// POST /v1/api/vibe-figma
interface ConversionRequest {
figmaUrl: string;
token?: string; // Optional if FIGMA_TOKEN env var is set
options?: {
useTailwind?: boolean;
optimize?: boolean;
clean?: boolean;
responsive?: boolean;
includeFonts?: boolean;
};
}
interface ConversionResponse {
component: string; // Generated React component code
assets: Array<{
name: string;
url: string;
data?: string; // Base64 for embedded assets
}>;
}const response = await fetch('http://localhost:3000/v1/api/vibe-figma', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
figmaUrl: 'https://www.figma.com/design/FILE_ID?node-id=NODE_ID',
token: process.env.FIGMA_TOKEN,
options: {
useTailwind: true,
optimize: true,
responsive: true,
},
}),
});
const { component, assets } = await response.json();
// Write component to file
await fs.writeFile('./src/components/Generated.tsx', component);
// Download assets
for (const asset of assets) {
const assetData = await fetch(asset.url);
await fs.writeFile(`./public/${asset.name}`, await assetData.arrayBuffer());
}import { execSync } from 'child_process';
import path from 'path';
interface FigmaComponent {
name: string;
url: string;
outputPath: string;
}
const components: FigmaComponent[] = [
{
name: 'Header',
url: 'https://www.figma.com/design/FILE_ID?node-id=HEADER_NODE',
outputPath: './src/components/Header.tsx',
},
{
name: 'Footer',
url: 'https://www.figma.com/design/FILE_ID?node-id=FOOTER_NODE',
outputPath: './src/components/Footer.tsx',
},
];
for (const comp of components) {
console.log(`Converting ${comp.name}...`);
execSync(
`npx vibefigma "${comp.url}" --component ${comp.outputPath} --force`,
{ stdio: 'inherit' }
);
}# .github/workflows/figma-sync.yml
name: Sync Figma Designs
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * 1' # Weekly on Mondays
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Convert Figma to React
env:
FIGMA_TOKEN: ${{ secrets.FIGMA_TOKEN }}
run: |
npx vibefigma "${{ vars.FIGMA_URL }}" \
--component ./src/components/DesignSystem.tsx \
--force
- name: Create Pull Request
uses: peter-evans/create-pull-request@v5
with:
title: 'chore: sync Figma designs'
branch: figma-syncimport { execSync } from 'child_process';
import fs from 'fs/promises';
async function convertAndCustomize(figmaUrl: string, outputPath: string) {
// Generate component
execSync(
`npx vibefigma "${figmaUrl}" --component ${outputPath} --force`,
{ stdio: 'inherit' }
);
// Read generated file
let content = await fs.readFile(outputPath, 'utf-8');
// Add custom imports
content = `import { motion } from 'framer-motion';\n${content}`;
// Replace div with motion.div for animations
content = content.replace(
/<div className="/g,
'<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="'
);
content = content.replace(/<\/div>/g, '</motion.div>');
// Write back
await fs.writeFile(outputPath, content);
console.log(`✅ Generated and customized: ${outputPath}`);
}
// Usage
await convertAndCustomize(
'https://www.figma.com/design/FILE_ID?node-id=NODE_ID',
'./src/components/AnimatedHero.tsx'
);# Test token manually
curl -H "X-Figma-Token: YOUR_TOKEN" \
https://api.figma.com/v1/menode-id# Correct format
https://www.figma.com/design/FILE_ID/FILE_NAME?node-id=123-456
# You can copy this from Figma:
# Right-click frame → Copy/Paste → Copy link# Remove --no-tailwind flag
npx vibefigma [url] --component ./output.tsx
# Explicitly enable optimization
npx vibefigma [url] --component ./output.tsx --optimize# Create directory first
mkdir -p ./public/assets
# Specify absolute path
npx vibefigma [url] --assets $(pwd)/public/assetsnpx vibefigma [url] --no-absolute --responsive// tailwind.config.js
module.exports = {
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
},
},
},
};# Generate component in Next.js app directory
npx vibefigma [url] \
--component ./app/components/FigmaComponent.tsx \
--assets ./public/figma-assets# Generate for Vite project
npx vibefigma [url] \
--component ./src/components/FigmaComponent.tsx \
--assets ./public/assets// Generate component
// Then create story file
import type { Meta, StoryObj } from '@storybook/react';
import { FigmaComponent } from './FigmaComponent';
const meta: Meta<typeof FigmaComponent> = {
title: 'Design System/FigmaComponent',
component: FigmaComponent,
};
export default meta;
type Story = StoryObj<typeof FigmaComponent>;
export const Default: Story = {};--force--clean