Skip to content

Commit ad3a7e5

Browse files
chore: update version to 1.0.2 and enhance documentation (#60)
1 parent 2d7a4ab commit ad3a7e5

File tree

18 files changed

+217
-234
lines changed

18 files changed

+217
-234
lines changed

README.md

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -54,18 +54,19 @@ https://github.com/user-attachments/assets/bd0c3f18-e98a-4050-bf22-46b198fadac2
5454

5555
CodeRio can be seamlessly integrated into Cursor as a Skill. Simply input a prompt like **"Create a React project and restore this design with high fidelity,"** along with your output directory, Figma URL([Design Link](https://www.figma.com/design/c0UBII8lURfxZIY8W6tSDR/Top-16-Websites-of-2024---Awwwards--Community-?node-id=30-8264&t=FB3Hohq2nsH7ZFts-4)), and Token. The Agent will guide you step-by-step through the page generation process. For Landing Pages, it achieves **high-fidelity restoration**, accurately reproducing images and styles. It also automatically encapsulates reusable components (such as cards) and strictly adheres to **frontend development best practices**.
5656

57-
5857
https://github.com/user-attachments/assets/43817e97-ffd2-40e3-9d33-78ee55b2ec2d
5958

6059
## 🚀 Quick Start
6160

6261
### Option 1: CLI (Recommended 👍🏻)
62+
6363
Best for one-click generation.
6464

6565
#### 1. Prerequisites
6666

6767
- Node.js >= 18.0.0 (< 25.0.0)
6868
- [Figma Personal Access Token](https://www.figma.com/developers/api#access-tokens)
69+
- **Figma Link**: Select a Frame or Component in Figma, right-click, and choose **Copy link to selection** ([Reference](docs/figma-link.jpg)).
6970
- LLM API Key ([Anthropic](https://console.anthropic.com/) | [OpenAI](https://platform.openai.com/) | [Google](https://aistudio.google.com/))
7071

7172
#### 2. Installation
@@ -78,35 +79,33 @@ npm install -g coderio
7879
pnpm add -g coderio
7980
```
8081

81-
> **Note for pnpm v9+ users**: If you see a warning about "Ignored build scripts", run:
82+
> **Note for pnpm v9+ users**: If you see a warning about "Ignored build scripts", run: `pnpm approve-builds` to allow native dependencies (better-sqlite3) to compile properly.
83+
>
84+
> **Note**: Validation features (e.g., `d2c --mode full`) require optional dependencies `playwright` and `sharp`. They are not bundled with coderio by default to keep installation lightweight. Please install them globally beforehand for smoother execution:
8285
>
8386
> ```bash
84-
> pnpm approve-builds
87+
> npm install -g playwright sharp
88+
> npx playwright install chromium
8589
> ```
86-
>
87-
> This allows native dependencies (better-sqlite3) to compile properly.
88-
>
89-
> **Note**: `playwright` and `sharp` are required only for validation features. They will be automatically installed when you first run a command that needs them (like `d2c --mode full`).
9090
9191
#### 3. Configuration
9292
93-
Create `~/.coderio/config.yaml`:
93+
> **Important**: Requires a **multimodal (vision)** model (Recommended: `gemini-3-pro-preview`).
9494
95-
```bash
96-
mkdir -p ~/.coderio
97-
cat > ~/.coderio/config.yaml << 'EOF'
95+
Create config file at `~/.coderio/config.yaml` (Windows: `%USERPROFILE%\.coderio\config.yaml`):
96+
97+
```yaml
9898
model:
99-
provider: openai # anthropic | openai | google
100-
model: gemini-3-pro-preview
101-
baseUrl: https://api.anthropic.com
102-
apiKey: your-api-key-here
99+
provider: openai # anthropic | openai | google
100+
model: gemini-3-pro-preview
101+
baseUrl: https://api.anthropic.com
102+
apiKey: your-api-key-here
103103
104104
figma:
105-
token: your-figma-token-here
105+
token: your-figma-token-here
106106
107107
debug:
108-
enabled: false
109-
EOF
108+
enabled: false # set 'true', if you want to save model and request information
110109
```
111110
112111
#### 4. Usage
@@ -136,10 +135,7 @@ pnpm dev
136135

137136
#### 6. View Validation Report
138137

139-
```bash
140-
# Open validation report in browser
141-
open coderio/<design-name_node-id>/process/validation/index.html
142-
```
138+
report path: coderio/<design-name_node-id>/process/validation/index.html
143139

144140
#### 📖 All Commands
145141

@@ -152,21 +148,22 @@ open coderio/<design-name_node-id>/process/validation/index.html
152148
| `images` | - | Download and process Figma assets |
153149

154150
### Option 2: Skill (Portable Embedded Workflow)
151+
155152
Best for control and precision using AI Agents.
156153

157154
**Prerequisites**:
158155
Copy the Skill file to your Cursor configuration directory:
159-
```bash
160-
mkdir -p ~/.cursor/skills/design-to-code
161-
cp docs/skills/SKILL.md ~/.cursor/skills/design-to-code/SKILL.md
162-
```
156+
157+
Copy `skills\design-to-code` folder to `~\.cursor\skills` (Windows: `%USERPROFILE%\.cursor\skills`)
163158

164159
**Using in Cursor**:
165-
1. Open Cursor Chat (`Cmd` + `L`).
160+
161+
1. Open Cursor Chat.
166162
2. Type: **"Use design-to-code skill to convert this design: [Your Figma URL]"**
167163
3. The Agent will guide you step-by-step through protocol extraction and code generation.
168164

169165
**Using in Claude Code**:
166+
170167
1. Start Claude Code.
171168
2. Type: **"Read docs/skills/SKILL.md and perform design conversion: [Your Figma URL]"**
172169

README_zh-CN.md

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -53,18 +53,19 @@ https://github.com/user-attachments/assets/bd0c3f18-e98a-4050-bf22-46b198fadac2
5353

5454
CodeRio 支持作为 Skill 集成到 Cursor 中使用。您只需在对话框中输入 **“请帮我创建一个 React 工程,高保真还原设计稿”**,并提供输出目录、设计稿链接([设计稿链接](https://www.figma.com/design/c0UBII8lURfxZIY8W6tSDR/Top-16-Websites-of-2024---Awwwards--Community-?node-id=30-8264&t=FB3Hohq2nsH7ZFts-4))及 Figma Token,Agent 即可引导您逐步完成网页生成。对于落地页(Landing Page)类页面,CodeRio 能达到 **高保真还原** 标准,精确还原图片与样式,并自动对卡片等组件进行 **复用封装**,生成的代码完全符合 **前端开发规范**
5555

56-
5756
https://github.com/user-attachments/assets/43817e97-ffd2-40e3-9d33-78ee55b2ec2d
5857

5958
## 🚀 快速开始
6059

6160
### 方式 1:命令行 CLI(推荐 👍🏻)
61+
6262
适用于一键快速生成。
6363

6464
#### 1. 前置要求
6565

6666
- Node.js >= 18.0.0 (< 25.0.0)
6767
- [Figma 个人访问令牌](https://www.figma.com/developers/api#access-tokens)
68+
- **Figma 链接**:在 Figma 中选中 Frame 或 Component,右键选择 **Copy link to selection** ([参考图片](docs/figma-link.jpg))。
6869
- LLM API 密钥([Anthropic](https://console.anthropic.com/) | [OpenAI](https://platform.openai.com/) | [Google](https://aistudio.google.com/)
6970

7071
#### 2. 安装
@@ -76,36 +77,38 @@ npm install -g coderio
7677
# 或使用 pnpm
7778
pnpm add -g coderio
7879
```
79-
> **pnpm v9+ 用户注意**:如果看到 "Ignored build scripts" 警告,请运行:
80+
81+
> **pnpm v9+ 用户注意**:如果看到 "Ignored build scripts" 警告,请运行:`pnpm approve-builds`,允许原生依赖(better-sqlite3)正确编译。
82+
>
83+
> **注意**:验证功能(如 `d2c --mode full`)依赖可选依赖 `playwright``sharp`。为了保持安装轻量,coderio 默认不内置它们。建议您提前全局安装,以确保运行更加顺畅:
84+
>
8085
> ```bash
81-
> pnpm approve-builds
86+
> npm install -g playwright sharp
87+
> npx playwright install chromium
8288
> ```
83-
> 这将允许原生依赖(better-sqlite3)正确编译。
84-
>
85-
> **注意**`playwright``sharp` 仅在验证功能中需要。当您运行需要它们的命令(如 `d2c --mode full`)时,它们将被自动安装。
8689
8790
#### 3. 配置
8891
89-
创建 `~/.coderio/config.yaml`
92+
> **重要提示**:本工具需要模型具备 **多模态(视觉)能力**(推荐 `gemini-3-pro-preview`)。
9093
91-
```bash
92-
mkdir -p ~/.coderio
93-
cat > ~/.coderio/config.yaml << 'EOF'
94+
创建配置文件 `~/.coderio/config.yaml`(Windows:`%USERPROFILE%\.coderio\config.yaml`):
95+
96+
```yaml
9497
model:
95-
provider: openai # anthropic | openai | google
96-
model: gemini-3-pro-preview
97-
baseUrl: https://api.anthropic.com
98-
apiKey: your-api-key-here
98+
provider: openai # anthropic | openai | google
99+
model: gemini-3-pro-preview
100+
baseUrl: https://api.anthropic.com
101+
apiKey: your-api-key-here
99102
100103
figma:
101-
token: your-figma-token-here
104+
token: your-figma-token-here
102105
103106
debug:
104-
enabled: false
105-
EOF
107+
enabled: false # 如果需要保留请求和模型回复,可以设置为 true
106108
```
107109
108110
#### 4. 使用
111+
109112
```bash
110113
# 将 Figma 设计转换为代码(默认模式:仅代码)
111114
coderio d2c -s 'https://www.figma.com/design/your-file-id/...'
@@ -114,7 +117,6 @@ coderio d2c -s 'https://www.figma.com/design/your-file-id/...'
114117
coderio d2c -s 'https://www.figma.com/design/your-file-id/...' -m full
115118
```
116119

117-
118120
#### 5. 运行项目
119121

120122
```bash
@@ -132,10 +134,7 @@ pnpm dev
132134

133135
#### 6. 查看验证报告
134136

135-
```bash
136-
# 在浏览器中打开验证报告
137-
open coderio/<设计文件名-页面节点编号>/process/validation/index.html
138-
```
137+
验证报告目录:`coderio/<设计文件名-页面节点编号>/process/validation/index.html`
139138

140139
#### 📖 全部命令
141140

@@ -147,27 +146,24 @@ open coderio/<设计文件名-页面节点编号>/process/validation/index.html
147146
| `validate` | `val` | 对生成的代码运行验证 |
148147
| `images` | - | 下载和处理 Figma 资源 |
149148

150-
151149
### 方式 2:Skill(便携式嵌入工作流)
150+
152151
适用于需要 AI 辅助和更精准控制的场景。
153152

154153
**前置准备**
155-
将 Skill 文件拷贝到 Cursor 配置目录:
156-
```bash
157-
mkdir -p ~/.cursor/skills/design-to-code
158-
cp docs/skills/SKILL.md ~/.cursor/skills/design-to-code/SKILL.md
159-
```
154+
`skills\design-to-code` 文件夹拷贝到 `~\.cursor\skills`(windows 为`%USERPROFILE%\.cursor\skills`) 目录下,
160155

161156
**Cursor 中使用**
162-
1. 打开 Cursor Chat (`Cmd` + `L`)。
157+
158+
1. 打开 Cursor Chat
163159
2. 输入:**"使用 design-to-code skill 帮我转换这个设计:[你的 Figma 链接]"**
164160
3. 智能体将引导你分步完成协议提取和代码生成。
165161

166162
**Claude Code 中使用**
163+
167164
1. 启动 Claude Code。
168165
2. 输入:**"阅读 docs/skills/SKILL.md 并执行设计转换任务:[你的 Figma 链接]"**
169166

170-
171167
## 💎 核心特性
172168

173169
### 1. 智能设计协议生成

docs/figma-link.jpg

858 KB
Loading

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "coderio",
3-
"version": "1.0.0",
3+
"version": "1.0.2",
44
"description": "A modern CLI development tool built with TypeScript",
55
"type": "module",
66
"bin": {

src/graph.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,36 +7,32 @@ import { runValidation } from './nodes/validation';
77
import { parseFigmaUrl } from './utils/url-parser';
88
import { workspaceManager } from './utils/workspace';
99
import { generateCode } from './nodes/code';
10-
import { initializeSqliteSaver, promptCheckpointChoice } from './utils/checkpoint';
10+
import { initializeSqliteSaver, promptCheckpointChoice, clearThreadCheckpoint } from './utils/checkpoint';
1111
import { logger } from './utils/logger';
12-
import { callModel } from './utils/call-model';
1312

1413
export async function design2code(url: string, mode?: ValidationMode): Promise<void> {
1514
const urlInfo = parseFigmaUrl(url);
1615
const threadId = urlInfo.projectName!;
1716
const workspace = workspaceManager.initWorkspace(threadId);
1817

1918
// Initialize SqliteSaver with the database path
20-
let checkpointer = initializeSqliteSaver(workspace.db);
19+
const checkpointer = initializeSqliteSaver(workspace.db);
2120
const resume = await promptCheckpointChoice(checkpointer, threadId);
2221

2322
logger.printInfoLog(`Starting design-to-code process for: ${urlInfo.projectName}`);
2423

2524
// If not resuming, delete workspace and reinitialize checkpointer
2625
if (resume !== true) {
27-
workspaceManager.deleteWorkspace(workspace);
26+
// Exclude checkpoint directory to avoid EBUSY error on Windows (SQLite lock)
27+
workspaceManager.deleteWorkspace(workspace, ['checkpoint']);
2828
logger.printInfoLog('Starting fresh...');
29-
// Reinitialize checkpointer after deleting workspace
30-
checkpointer = initializeSqliteSaver(workspace.db);
29+
30+
// Clear existing checkpoints for this thread instead of deleting the file
31+
await clearThreadCheckpoint(checkpointer, threadId);
3132
} else {
3233
logger.printInfoLog('Resuming from cache...');
3334
}
3435

35-
await callModel({
36-
question: '请介绍你自己,你是什么模型',
37-
streaming: false,
38-
});
39-
4036
// Compile graph with checkpointer (after potential reinitialization)
4137
const graph = new StateGraph(GraphStateAnnotation)
4238
.addNode(GraphNode.INITIAL, initialProject)

src/nodes/process/structure/utils.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { FigmaFrameInfo, Protocol, FrameData } from '../../../types';
22
import type { SimplifiedFigmaNode, ExtendedFrameStructNode, ParsedDataListResponse } from './types';
3+
import path from 'node:path';
34
import { toKebabCase } from '../../../utils/naming';
45
import { extractJSON } from '../../../utils/parser';
56
import { callModel } from '../../../utils/call-model';
@@ -237,12 +238,9 @@ export function postProcessStructure(structure?: Protocol | Protocol[] | null, f
237238
return;
238239
}
239240

240-
// Utility to join path segments and normalize slashes
241+
// Utility to join alias path segments (always POSIX '/')
241242
const joinSegments = (...segments: (string | undefined)[]): string =>
242-
segments
243-
.filter((segment): segment is string => Boolean(segment && segment.length))
244-
.join('/')
245-
.replace(/\/{2,}/g, '/');
243+
path.posix.join(...segments.filter((segment): segment is string => Boolean(segment && segment.length)));
246244

247245
const nodes = Array.isArray(structure) ? structure : [structure];
248246
let rootPath = '@/components';

src/nodes/validation/core/validation-loop.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ function saveIterationAndProcessedJson(
197197

198198
export async function validationLoop(params: ValidationLoopParams): Promise<ValidationLoopResult> {
199199
// Ensure dependencies are installed before starting validation loop
200-
await ensureValidationDependencies();
200+
ensureValidationDependencies();
201201

202202
const { protocol, figmaThumbnailUrl, outputDir, workspace } = params;
203203

src/tools/figma-tool/images.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,15 @@ export const createDownloadTask = async (image: ImageNode, imageDir?: string): P
325325

326326
try {
327327
const localPath = await downloadImage(image.url, filename, imageDir);
328-
const aliasPath = `@/${localPath.split('src/')?.[1] || ''}`;
328+
const normalizedImageDir = imageDir ? path.normalize(imageDir) : '';
329+
const dirParts = normalizedImageDir.split(path.sep).filter(Boolean);
330+
const srcIndex = dirParts.lastIndexOf('src');
331+
const srcDir =
332+
srcIndex >= 0 ? (normalizedImageDir.startsWith(path.sep) ? path.sep : '') + path.join(...dirParts.slice(0, srcIndex + 1)) : '';
333+
334+
const relativeFromSrc = srcDir ? path.relative(srcDir, localPath) : '';
335+
const normalizedRelative = relativeFromSrc.split(path.sep).join('/');
336+
const aliasPath = `@/${normalizedRelative}`;
329337

330338
return {
331339
id: image.id,

src/tools/figma-tool/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,14 @@ class FigmaTool {
6565

6666
const document = await fetchFigmaNode(fileId, nodeId, token);
6767
if (!document || !document?.children?.length) {
68-
return undefined;
68+
throw new Error('Failed to fetch Figma document');
6969
}
7070

7171
const images = await fetchFigmaImages(fileId, nodeId, token);
7272
const thumbnail = images?.[nodeId] || '';
73+
if (!thumbnail) {
74+
throw new Error('Failed to fetch Figma document thumbnail');
75+
}
7376
document.thumbnailUrl = thumbnail;
7477

7578
const cleanedDocument = cleanFigma(document);

0 commit comments

Comments
 (0)