@createlex/figgen 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +164 -0
- package/bin/figgen.js +156 -0
- package/companion/bridge-server.cjs +786 -0
- package/companion/createlex-auth.cjs +364 -0
- package/companion/local-llm-generator.cjs +437 -0
- package/companion/login.mjs +189 -0
- package/companion/mcp-server.mjs +1365 -0
- package/companion/package.json +17 -0
- package/companion/server.js +65 -0
- package/companion/setup.cjs +309 -0
- package/companion/xcode-writer.cjs +516 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# CreateLex Figma to SwiftUI MCP
|
|
2
|
+
|
|
3
|
+
A local MCP (Model Context Protocol) runtime that connects your Figma plugin session to Claude Code, Cursor, Windsurf, or any MCP-compatible AI tool — and writes production-ready SwiftUI directly into your Xcode project.
|
|
4
|
+
|
|
5
|
+
## Generation tiers
|
|
6
|
+
|
|
7
|
+
### Tier 1 — AI-native (zero extra API cost)
|
|
8
|
+
Your AI IDE (Claude Code, Cursor, Windsurf, etc.) calls the MCP tools itself:
|
|
9
|
+
|
|
10
|
+
1. `get_swiftui_generation_prompt` → returns a ready-to-use system prompt + user message
|
|
11
|
+
2. The AI generates SwiftUI using **its own model** (your existing subscription)
|
|
12
|
+
3. `write_generated_swiftui_to_xcode` → writes the file(s) to Xcode
|
|
13
|
+
|
|
14
|
+
No CreateLex tokens consumed. No extra API keys required.
|
|
15
|
+
|
|
16
|
+
### Tier 2 — BYOK (Bring Your Own Key)
|
|
17
|
+
Set one of these env vars in your MCP client config and `generate_swiftui` runs locally:
|
|
18
|
+
|
|
19
|
+
| Env var | Provider | Notes |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| `ANTHROPIC_API_KEY` | Claude (recommended) | Override model with `ANTHROPIC_MODEL` |
|
|
22
|
+
| `HF_API_TOKEN` | Hugging Face | Default model: `Qwen/Qwen2.5-Coder-32B-Instruct`, override with `HF_MODEL` |
|
|
23
|
+
| `OPENAI_API_KEY` | OpenAI or compatible | Override model with `OPENAI_MODEL` (default `gpt-4o`) |
|
|
24
|
+
| `OPENAI_BASE_URL` | Ollama / LM Studio | Set alongside `OPENAI_API_KEY=ollama` for fully local generation |
|
|
25
|
+
|
|
26
|
+
### Tier 3 — CreateLex hosted (subscription fallback)
|
|
27
|
+
If no BYOK keys are set, falls back to the CreateLex hosted pattern matcher. Requires an active [CreateLex subscription](https://createlex.com/figma-swiftui).
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Requirements
|
|
32
|
+
|
|
33
|
+
- Node.js 18 or later
|
|
34
|
+
- Figma desktop app with the Figma to SwiftUI plugin open
|
|
35
|
+
- A local Xcode project (optional for Tier 1 prompt-copy workflow)
|
|
36
|
+
|
|
37
|
+
## Install
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx @createlex/figma-swiftui-mcp start --project /path/to/MyApp/MyApp
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Or install globally:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm install -g @createlex/figma-swiftui-mcp
|
|
47
|
+
figma-swiftui-mcp start --project /path/to/MyApp/MyApp
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## MCP client configuration
|
|
51
|
+
|
|
52
|
+
Add to your Claude Code / Cursor / Windsurf MCP config:
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"mcpServers": {
|
|
57
|
+
"figma-swiftui": {
|
|
58
|
+
"command": "npx",
|
|
59
|
+
"args": ["@createlex/figma-swiftui-mcp", "start"],
|
|
60
|
+
"env": {
|
|
61
|
+
"FIGMA_SWIFTUI_PROJECT_PATH": "/path/to/MyApp/MyApp",
|
|
62
|
+
"ANTHROPIC_API_KEY": "sk-ant-..."
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
For Hugging Face BYOK:
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"env": {
|
|
74
|
+
"FIGMA_SWIFTUI_PROJECT_PATH": "/path/to/MyApp/MyApp",
|
|
75
|
+
"HF_API_TOKEN": "hf_...",
|
|
76
|
+
"HF_MODEL": "Qwen/Qwen2.5-Coder-32B-Instruct"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
For fully local generation with Ollama:
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"env": {
|
|
86
|
+
"FIGMA_SWIFTUI_PROJECT_PATH": "/path/to/MyApp/MyApp",
|
|
87
|
+
"OPENAI_API_KEY": "ollama",
|
|
88
|
+
"OPENAI_BASE_URL": "http://localhost:11434/v1",
|
|
89
|
+
"OPENAI_MODEL": "llama3"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## MCP tools
|
|
95
|
+
|
|
96
|
+
| Tool | Description |
|
|
97
|
+
|---|---|
|
|
98
|
+
| `get_design_context` | Get the full Figma node tree, colors, typography, and layout for a selection |
|
|
99
|
+
| `get_swiftui_generation_prompt` | Returns a ready-to-use system prompt + user message — feed to your AI model to generate SwiftUI |
|
|
100
|
+
| `generate_swiftui` | Generate SwiftUI via BYOK key or CreateLex hosted (Tier 2/3) |
|
|
101
|
+
| `write_generated_swiftui_to_xcode` | Write a generated Swift file (plus optional DesignTokens.swift and component files) to Xcode |
|
|
102
|
+
| `get_project_path` / `set_project_path` | Read or update the target Xcode source directory |
|
|
103
|
+
| `bridge_status` | Check if the Figma plugin bridge is connected |
|
|
104
|
+
|
|
105
|
+
### Multi-file output
|
|
106
|
+
|
|
107
|
+
`write_generated_swiftui_to_xcode` accepts an `additionalFiles` array for AI-generated companion files:
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"structName": "LoginScreen",
|
|
112
|
+
"code": "import SwiftUI\n...",
|
|
113
|
+
"additionalFiles": [
|
|
114
|
+
{ "name": "DesignTokens.swift", "code": "...", "dir": "shared" },
|
|
115
|
+
{ "name": "PrimaryButton.swift", "code": "...", "dir": "components" }
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Output layout inside your Xcode source folder:
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
FigmaGenerated/
|
|
124
|
+
Screens/ ← primary view files
|
|
125
|
+
Components/ ← reusable component files
|
|
126
|
+
DesignTokens.swift ← shared tokens (dir: "shared")
|
|
127
|
+
Manifest/ ← generation metadata
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## AI-native workflow (Tier 1 example)
|
|
131
|
+
|
|
132
|
+
In Claude Code or any MCP-connected AI:
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
1. Select a frame in Figma
|
|
136
|
+
2. Ask: "Generate SwiftUI for my selected Figma frame"
|
|
137
|
+
3. Claude calls get_swiftui_generation_prompt → generates code → calls write_generated_swiftui_to_xcode
|
|
138
|
+
4. File appears in Xcode immediately
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Zero CreateLex tokens consumed.
|
|
142
|
+
|
|
143
|
+
## Plugin UI
|
|
144
|
+
|
|
145
|
+
The plugin's **Smart Generate** button supports two modes via the dropdown:
|
|
146
|
+
- **Smart AI** — uses your AI IDE or BYOK key for true AI generation
|
|
147
|
+
- **Classic** — uses the hosted pattern matcher (requires subscription)
|
|
148
|
+
|
|
149
|
+
After generation, the **Copy AI Prompt** button copies a ready-to-use prompt you can paste into Claude.ai, ChatGPT, or any AI chat. Requires the MCP server to be running.
|
|
150
|
+
|
|
151
|
+
## Login (CreateLex subscription)
|
|
152
|
+
|
|
153
|
+
Only required for Tier 3 hosted generation:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
npx @createlex/figma-swiftui-mcp login
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Saves your session to `~/.createlex/auth.json`.
|
|
160
|
+
|
|
161
|
+
## Support
|
|
162
|
+
|
|
163
|
+
- Product: https://createlex.com/figma-swiftui
|
|
164
|
+
- Help & billing: https://createlex.com/contact
|
package/bin/figgen.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const { spawn } = require('node:child_process');
|
|
6
|
+
|
|
7
|
+
const CLI_NAME = 'figgen';
|
|
8
|
+
const PACKAGE_NAME = '@createlex/figgen';
|
|
9
|
+
|
|
10
|
+
function printHelp() {
|
|
11
|
+
console.log(`${CLI_NAME}
|
|
12
|
+
|
|
13
|
+
Usage:
|
|
14
|
+
npx ${PACKAGE_NAME} login
|
|
15
|
+
npx ${PACKAGE_NAME} start [--project /path/to/Xcode/source]
|
|
16
|
+
npx ${PACKAGE_NAME} setup [--force] [--dry-run]
|
|
17
|
+
|
|
18
|
+
Commands:
|
|
19
|
+
login Open the CreateLex browser login flow and save ~/.createlex/auth.json
|
|
20
|
+
start Start the local figma-swiftui MCP runtime and localhost bridge
|
|
21
|
+
setup Auto-configure MCP in Cursor, Claude, VS Code, Windsurf, and more
|
|
22
|
+
help Show this help message
|
|
23
|
+
version Show the package version
|
|
24
|
+
|
|
25
|
+
Examples:
|
|
26
|
+
npx ${PACKAGE_NAME} login
|
|
27
|
+
npx ${PACKAGE_NAME} start --project /Users/you/MyApp/MyApp
|
|
28
|
+
npx ${PACKAGE_NAME} setup
|
|
29
|
+
npm install -g ${PACKAGE_NAME}
|
|
30
|
+
${CLI_NAME} start --project /Users/you/MyApp/MyApp
|
|
31
|
+
`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function printCommandHelp(command) {
|
|
35
|
+
if (command === 'login') {
|
|
36
|
+
console.log(`${CLI_NAME} login
|
|
37
|
+
|
|
38
|
+
Usage:
|
|
39
|
+
npx ${PACKAGE_NAME} login
|
|
40
|
+
|
|
41
|
+
Description:
|
|
42
|
+
Open the CreateLex browser login flow and save ~/.createlex/auth.json
|
|
43
|
+
`);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (command === 'start') {
|
|
48
|
+
console.log(`${CLI_NAME} start
|
|
49
|
+
|
|
50
|
+
Usage:
|
|
51
|
+
npx ${PACKAGE_NAME} start [--project /path/to/Xcode/source]
|
|
52
|
+
|
|
53
|
+
Options:
|
|
54
|
+
--project <path> Set the Xcode source folder used for generated SwiftUI output
|
|
55
|
+
|
|
56
|
+
Description:
|
|
57
|
+
Start the local figma-swiftui MCP runtime and localhost bridge
|
|
58
|
+
`);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (command === 'setup') {
|
|
63
|
+
console.log(`${CLI_NAME} setup
|
|
64
|
+
|
|
65
|
+
Usage:
|
|
66
|
+
npx ${PACKAGE_NAME} setup [--force] [--dry-run]
|
|
67
|
+
|
|
68
|
+
Options:
|
|
69
|
+
--force Overwrite existing figma-swiftui config entries
|
|
70
|
+
--dry-run Show what would be configured without writing
|
|
71
|
+
|
|
72
|
+
Description:
|
|
73
|
+
Detects installed IDEs (Cursor, Claude Desktop, Claude Code, VS Code,
|
|
74
|
+
Windsurf, Antigravity) and adds the figma-swiftui MCP server entry
|
|
75
|
+
to each config file automatically.
|
|
76
|
+
`);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
printHelp();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function resolveEntry(command) {
|
|
84
|
+
if (command === 'login') {
|
|
85
|
+
return path.join(__dirname, '..', 'companion', 'login.mjs');
|
|
86
|
+
}
|
|
87
|
+
return path.join(__dirname, '..', 'companion', 'mcp-server.mjs');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function runNode(entry, args) {
|
|
91
|
+
const child = spawn(process.execPath, [entry, ...args], {
|
|
92
|
+
stdio: 'inherit',
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
child.on('exit', (code, signal) => {
|
|
96
|
+
if (signal) {
|
|
97
|
+
process.kill(process.pid, signal);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
process.exit(code ?? 0);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
child.on('error', (error) => {
|
|
104
|
+
console.error(`${CLI_NAME} failed: ${error.message}`);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const packageJson = require(path.join(__dirname, '..', 'package.json'));
|
|
110
|
+
const [command = 'help', ...args] = process.argv.slice(2);
|
|
111
|
+
const wantsHelp = args.includes('--help') || args.includes('-h');
|
|
112
|
+
|
|
113
|
+
switch (command) {
|
|
114
|
+
case 'login':
|
|
115
|
+
if (wantsHelp) {
|
|
116
|
+
printCommandHelp('login');
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
runNode(resolveEntry('login'), args);
|
|
120
|
+
break;
|
|
121
|
+
case 'start':
|
|
122
|
+
if (wantsHelp) {
|
|
123
|
+
printCommandHelp('start');
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
runNode(resolveEntry('start'), args);
|
|
127
|
+
break;
|
|
128
|
+
case 'setup':
|
|
129
|
+
if (wantsHelp) {
|
|
130
|
+
printCommandHelp('setup');
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
{
|
|
134
|
+
const { runSetup } = require(path.join(__dirname, '..', 'companion', 'setup.cjs'));
|
|
135
|
+
const flags = {
|
|
136
|
+
force: args.includes('--force'),
|
|
137
|
+
dryRun: args.includes('--dry-run'),
|
|
138
|
+
};
|
|
139
|
+
runSetup(flags);
|
|
140
|
+
}
|
|
141
|
+
break;
|
|
142
|
+
case 'help':
|
|
143
|
+
case '--help':
|
|
144
|
+
case '-h':
|
|
145
|
+
printHelp();
|
|
146
|
+
break;
|
|
147
|
+
case 'version':
|
|
148
|
+
case '--version':
|
|
149
|
+
case '-v':
|
|
150
|
+
console.log(packageJson.version);
|
|
151
|
+
break;
|
|
152
|
+
default:
|
|
153
|
+
console.error(`Unknown command: ${command}\n`);
|
|
154
|
+
printHelp();
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|