Skip to content

Commit d9f6b75

Browse files
Rafal PrzetakowskiRafal Przetakowski
authored andcommitted
feat(figma-mcp-component-generator): add code generation tool for Figma components
Add CLI tool to generate React components, stories, and tests from Figma designs. Includes: - Figma client with REST/MCP support - DSL mapper for Figma to React component conversion - Handlebars templates for component, story, and test files - Configuration for design system mappings - Documentation and development guidelines
1 parent 2d4aca7 commit d9f6b75

17 files changed

+14661
-2868
lines changed

.github/copilot-instructions.md

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# React Starter – Development and Code Generation Guidelines
2+
3+
## **Framework and Language**
4+
5+
* All code **must** be written in **React** with **TypeScript** in **strict mode**.
6+
* Use **functional components only**; class components are not permitted.
7+
* Components must be imported **exclusively** from `@/shared/ui` and layout primitives from `@/shared/layout`.
8+
* Do not introduce any external UI library without explicit approval.
9+
10+
---
11+
12+
## **Project Structure**
13+
14+
* **Pages**: place in `src/pages`, one file per page entry point.
15+
* **Page sections and feature-specific UI**: place in `src/features/<page>/components`.
16+
* Maintain **barrel exports** (`index.ts`) in each `components` directory to facilitate cleaner imports.
17+
* Keep **cohesion**: avoid scattering related components across unrelated directories.
18+
19+
---
20+
21+
## **Figma → Code Mapping Rules**
22+
23+
When generating code from Figma designs (manually or via MCP tools), apply the following mappings:
24+
25+
* **Containers with elevation**`<Card elevation="sm|md|lg" />` based on the shadow depth in Figma.
26+
* **Buttons**`<Button variant="primary|secondary|ghost" size="sm|md|lg" />`, with `variant` and `size` inferred from Figma properties or naming.
27+
* **Form inputs**:
28+
29+
* Text input → `<TextField />`
30+
* Dropdown → `<Select />`
31+
* Checkbox → `<Checkbox />`
32+
* Toggle → `<Switch />`
33+
* **Tables**`<DataTable columns={…} data={…} />` with columns inferred from Figma table headers.
34+
* **Avatars / Icons**`<Avatar />` for user imagery, `<Icon name="…" />` for decorative or functional icons.
35+
36+
---
37+
38+
## **Layout and Spacing**
39+
40+
* Use **Flexbox** or **CSS Grid** exclusively for layout.
41+
* **Do not** use absolute positioning unless explicitly required by the design constraints.
42+
* Apply spacing **only via tokens**:
43+
44+
* Gaps: `space.1``gap-1`, `space.8``gap-8`.
45+
* Padding: `p.1``p-1`, `p.8``p-8`.
46+
* Ensure spacing matches the Figma design but is implemented through tokenised classes.
47+
48+
---
49+
50+
## **Styling and Theming**
51+
52+
* All styles **must** come from the design system tokens.
53+
* **Prohibited**:
54+
55+
* Inline styles (`style={{…}}`).
56+
* Hard-coded pixel values.
57+
* Hard-coded colours.
58+
* Use semantic tokens for typography (`text.h1`, `text.h2`, etc.) and colour (`colour.primary.600`).
59+
60+
---
61+
62+
## **Accessibility**
63+
64+
* All interactive elements **must** be focusable.
65+
* Use appropriate `aria-*` attributes where relevant (e.g., `aria-label`, `aria-expanded`).
66+
* Ensure semantic HTML tags for content (e.g., headings use `<h1>–<h6>`, body text uses `<p>`).
67+
68+
---
69+
70+
## **Testing and Storybook**
71+
72+
* Every component must have:
73+
74+
* A Storybook file (`.stories.tsx`) using **CSF3 format**.
75+
* A **Vitest snapshot test** verifying render output.
76+
* Ensure Storybook stories are comprehensive enough to cover all significant variants.
77+
78+
---
79+
80+
## **Do NOT**
81+
82+
* Do not bypass the design system by creating ad-hoc styles.
83+
* Do not hard-code dimensions, colours, or fonts.
84+
* Do not introduce new components that replicate existing design system functionality.
85+
86+
---
87+
88+
## **MCP and Figma Integration**
89+
90+
* Use MCP commands for fetching design data:
91+
92+
* `figma.listFrames(fileKey, page?)`
93+
* `figma.export_frame_json(frameId)`
94+
* `figma.get_design_tokens(fileKey)`
95+
* Run via CLI:
96+
97+
```bash
98+
pnpm figma:gen --file <fileKey> --page <PageName> --section <FrameName>
99+
```
100+
101+
---
102+
103+
## **Workflow for Generated Components**
104+
105+
1. Fetch frame data from Figma via MCP.
106+
2. Map Figma elements to the appropriate design system components per the mapping rules above.
107+
3. Generate:
108+
109+
* The component file (`.tsx`)
110+
* Corresponding Storybook story
111+
* Snapshot test
112+
4. Add component to the relevant `index.ts` barrel file.
113+
5. Open a Pull Request ensuring:
114+
115+
* `pnpm typecheck` passes (TypeScript strict mode).
116+
* `pnpm lint` passes (ESLint with repository rules).
117+
* `pnpm test` passes (Vitest).
118+
* `pnpm build:storybook` completes without errors.
119+
120+
---
121+
122+
## **Example**
123+
124+
To generate the `StatsGrid` section from the `Dashboard` page in Figma file `GhUCE2…`:
125+
126+
```bash
127+
pnpm figma:gen --file GhUCE2ZLNtDvUSVOa4w0Xg \
128+
--page Dashboard \
129+
--section StatsGrid \
130+
--feature dashboard \
131+
--name StatsGrid
132+
```
133+
134+
---
135+
136+
## **Pull Request Expectations**
137+
138+
* PR title must clearly describe the feature or component (e.g., `feat(dashboard): add StatsGrid from Figma`).
139+
* PR description should include:
140+
141+
* The Figma file key and frame name used.
142+
* Any deviations from the design and the reason.
143+
* Confirmation that tests and stories were generated and run.

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ npm run [command_name]
108108
3. [React Query abstraction](/docs/03-react-query-abstraction.md)
109109
4. [Using plop commands](/docs/04-using-plop-commands.md)
110110
5. [E2E tests](/docs/05-e2e-tests.md)
111+
6. [Generating Components from Figma](/docs/06-generating-components-from-figma.md)
111112

112113
## How to Contribute
113114

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
# **📖 Manual – Generating Components from Figma (`figma:gen`)**
2+
3+
## **1. Prerequisites**
4+
5+
Before you can run the generator, make sure you have:
6+
7+
1. **Node.js** – version 18.x or later.
8+
Check your current version:
9+
10+
```bash
11+
node -v
12+
```
13+
14+
If you don’t have it installed, download it from [nodejs.org](https://nodejs.org/en/).
15+
16+
2. **pnpm** – the package manager used in your project.
17+
Install it globally:
18+
19+
```bash
20+
npm install -g pnpm
21+
```
22+
23+
3. **A Figma account** – with access to the project or files you want to generate components from.
24+
25+
4. **Figma Personal Access Token (PAT)**
26+
27+
* In Figma: **Menu → Settings → Personal access tokens**
28+
* Click **Create a new personal access token**
29+
* Copy the token (it is active immediately after creation).
30+
31+
5. **jq** (optional, for JSON filtering in the terminal)
32+
On macOS:
33+
34+
```bash
35+
brew install jq
36+
```
37+
38+
---
39+
40+
## **2. Environment Configuration**
41+
42+
In your project root, create a `.env` file and add:
43+
44+
```env
45+
FIGMA_API_TOKEN=YOUR_FIGMA_PERSONAL_ACCESS_TOKEN
46+
```
47+
48+
> **Important:** Never commit this file to Git. Ensure `.env` is listed in `.gitignore`.
49+
50+
---
51+
52+
## **3. Finding Pages and Frames in Figma**
53+
54+
Before running `figma:gen`, you need the **fileKey** and the **frameId**.
55+
56+
* **fileKey** is the part of the Figma URL between `/design/` and the next `/`.
57+
Example:
58+
59+
```
60+
https://www.figma.com/design/GhUCE2ZLNtDvUSVOa4w0Xg/FoodBlog--Admin-dashboard
61+
```
62+
63+
Here:
64+
65+
```
66+
fileKey = GhUCE2ZLNtDvUSVOa4w0Xg
67+
```
68+
69+
### **List all pages**
70+
71+
```bash
72+
curl -sS -H "X-Figma-Token: $FIGMA_API_TOKEN" \
73+
"https://api.figma.com/v1/files/GhUCE2ZLNtDvUSVOa4w0Xg" \
74+
| jq -r '.document.children[] | select(.type=="CANVAS") | .name'
75+
```
76+
77+
### **List all frames**
78+
79+
```bash
80+
curl -sS -H "X-Figma-Token: $FIGMA_API_TOKEN" \
81+
"https://api.figma.com/v1/files/GhUCE2ZLNtDvUSVOa4w0Xg" \
82+
| jq -r '.. | objects | select(.type? == "FRAME") | "\(.id) \(.name)"'
83+
```
84+
85+
From this output, choose the exact **frameId** to use with `figma:gen`.
86+
87+
---
88+
89+
## **4. Running the Generator**
90+
91+
You can run the generator in two ways.
92+
93+
### **a) Using `--file` + `--page` + `--section`**
94+
95+
```bash
96+
pnpm figma:gen \
97+
--file GhUCE2ZLNtDvUSVOa4w0Xg \
98+
--page "GOB-98 / Admin's dashboard" \
99+
--section "StatsGrid" \
100+
--feature dashboard \
101+
--name StatsGrid
102+
```
103+
104+
### **b) Using a direct Figma link (`--url`)**
105+
106+
```bash
107+
pnpm figma:gen \
108+
--url "https://www.figma.com/design/GhUCE2ZLNtDvUSVOa4w0Xg/FoodBlog--Admin-dashboard?node-id=120-52384" \
109+
--feature dashboard \
110+
--name StatsGrid
111+
```
112+
113+
> **Tip:** If you get `Frame not found`, it means:
114+
>
115+
> * You’ve entered an incorrect `frameId` (taken from `node-id` in the Figma URL), or
116+
> * The file/page is not shared correctly. In Figma: **Share → Anyone with the link can view**.
117+
118+
---
119+
120+
## **5. Automating Frame Lookup**
121+
122+
To avoid manually finding frame IDs, you can create a helper script that:
123+
124+
* Retrieves all frames from Figma,
125+
* Filters them by part of the name,
126+
* Automatically runs `figma:gen` with the right ID.
127+
128+
Example:
129+
130+
```bash
131+
pnpm list-frames "StatsGrid"
132+
```
133+
134+
This would:
135+
136+
* List matching frames,
137+
* Pass the correct `frameId` to the generator.
138+
139+
---
140+
141+
## **6. Common Issues & Fixes**
142+
143+
| Problem | Cause | Solution |
144+
| --------------------------------------------- | ------------------------------------------------- | ---------------------------------------------------------------------------------- |
145+
| `Invalid token` | The `.env` file is missing or the token is wrong. | Ensure `FIGMA_API_TOKEN` is set correctly and loaded (`printenv FIGMA_API_TOKEN`). |
146+
| `Page not found` | The `--page` name doesn’t match exactly. | Use the exact name from the page list (see section 3). |
147+
| `Frame not found` | Wrong `frameId` or missing access. | Get the correct frame list via the curl command in section 3. |
148+
| `You must pass a string or Handlebars AST...` | The template is missing or returning a Promise. | Check the template path in `generate.ts` and ensure it resolves to a string. |
149+
150+
---
151+
152+
## **7. Example Full Workflow**
153+
154+
1. Copy the link to the required Figma design.
155+
2. Extract `fileKey` and `frameId` from the link.
156+
3. Run in the terminal:
157+
158+
```bash
159+
export FIGMA_API_TOKEN=YOUR_TOKEN
160+
pnpm figma:gen \
161+
--url "https://www.figma.com/design/GhUCE2ZLNtDvUSVOa4w0Xg/FoodBlog--Admin-dashboard?node-id=120-52384" \
162+
--feature dashboard \
163+
--name StatsGrid
164+
```
165+
4. Generated files will appear under:
166+
167+
```
168+
src/features/dashboard
169+
```
170+
171+
---
172+
173+
If you want, I can now extend this manual with a **ready-made script** so that instead of running multiple commands, you could just type:
174+
175+
```bash
176+
pnpm figma:auto "StatsGrid"
177+
```
178+
179+
and it would handle:
180+
181+
* Finding the right frame in Figma,
182+
* Pulling its ID,
183+
* Running `figma:gen` with your naming conventions.
184+
185+
Do you want me to prepare that as part of this manual? That would make the process completely one-click.

0 commit comments

Comments
 (0)