mta-mcp 2.17.0 → 3.0.0
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/agents/flutter.agent.md +23 -64
- package/agents/mta.agent.md +226 -0
- package/agents/vue3.agent.md +24 -0
- package/agents/wechat-miniprogram.agent.md +23 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -4
- package/standards/mcp-tools/sketch-mcp.md +497 -0
- package/standards/patterns/design-system-restoration.md +570 -0
- package/standards/syntax-mapping.md +256 -0
- package/standards/workflows/design-restoration.md +401 -0
- package/templates/README.md +14 -0
- package/templates/design-measurement/README.md +81 -0
- package/templates/design-measurement/component-measurement.js +52 -0
- package/templates/design-measurement/gap-measurement.js +79 -0
- package/templates/design-measurement/style-extraction.js +109 -0
- package/common/i18n.md +0 -385
- package/common/typescript-strict.md +0 -186
- package/troubleshooting/README.md +0 -368
- package/troubleshooting/USAGE_GUIDE.md +0 -289
- package/troubleshooting/flutter/clip-/351/230/264/345/275/261/350/243/201/345/211/252.md +0 -244
- package/troubleshooting/flutter/input-/345/255/227/346/256/265/347/274/272/345/244/261.md +0 -240
- package/troubleshooting/flutter/input-/350/276/271/346/241/206/351/227/256/351/242/230.md +0 -236
- package/troubleshooting/flutter/layout-/345/260/272/345/257/270/344/270/215/345/214/271/351/205/215.md +0 -214
- package/troubleshooting/flutter/shadow-/351/200/217/345/207/272/351/227/256/351/242/230.md +0 -172
- package/troubleshooting/flutter/sketch-/345/210/227/350/241/250item/345/214/272/345/237/237.md +0 -212
- package/troubleshooting/flutter/sketch-/345/233/276/346/240/207/345/260/272/345/257/270.md +0 -135
- package/troubleshooting/flutter/sketch-/345/256/214/346/225/264/346/217/220/345/217/226.md +0 -201
- package/troubleshooting/flutter/sketch-/345/261/236/346/200/247/346/234/252/344/275/277/347/224/250.md +0 -139
- package/troubleshooting/flutter/sketch-/350/203/214/346/231/257/345/261/202/351/253/230/345/272/246.md +0 -264
- package/troubleshooting/flutter/svg-/346/234/252/345/261/205/344/270/255.md +0 -120
- package/troubleshooting/flutter/svg-/351/242/234/350/211/262/345/274/202/345/270/270.md +0 -117
- package/troubleshooting/flutter/tabbar-/345/212/250/347/224/273/345/220/214/346/255/245.md +0 -107
- package/troubleshooting/flutter/withopacity-/345/274/203/347/224/250.md +0 -81
- package/troubleshooting/vue3/cascader-/350/257/257/346/233/277/346/215/242.md +0 -130
- package/troubleshooting/vue3/drawer-input-/346/240/267/345/274/217.md +0 -181
- package/troubleshooting/vue3/table-/347/274/226/350/276/221/345/217/226/346/266/210.md +0 -148
- package/troubleshooting/vue3/table-/350/276/271/346/241/206/351/227/256/351/242/230.md +0 -178
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# 跨框架样式语法映射表
|
|
2
|
+
|
|
3
|
+
> 设计稿参数到各框架代码的转换参考
|
|
4
|
+
|
|
5
|
+
## 📋 概述
|
|
6
|
+
|
|
7
|
+
本文档提供设计稿参数到不同框架(Flutter、Vue/CSS、React Native、小程序)的语法映射,用于设计稿还原时的快速查阅。
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 📐 尺寸与布局
|
|
12
|
+
|
|
13
|
+
### 宽高
|
|
14
|
+
|
|
15
|
+
| 设计稿 | Flutter | Vue/CSS | React Native | 小程序 |
|
|
16
|
+
|--------|---------|---------|--------------|--------|
|
|
17
|
+
| width: 100px | `width: 100` | `width: 100px` | `width: 100` | `width: 200rpx` |
|
|
18
|
+
| height: 50px | `height: 50` | `height: 50px` | `height: 50` | `height: 100rpx` |
|
|
19
|
+
| 100% 宽度 | `double.infinity` | `width: 100%` | `width: '100%'` | `width: 100%` |
|
|
20
|
+
|
|
21
|
+
### 内边距 (Padding)
|
|
22
|
+
|
|
23
|
+
| 设计稿 | Flutter | Vue/CSS | React Native | 小程序 |
|
|
24
|
+
|--------|---------|---------|--------------|--------|
|
|
25
|
+
| 全部 16px | `padding: EdgeInsets.all(16)` | `padding: 16px` | `padding: 16` | `padding: 32rpx` |
|
|
26
|
+
| 水平 16px | `padding: EdgeInsets.symmetric(horizontal: 16)` | `padding: 0 16px` | `paddingHorizontal: 16` | `padding: 0 32rpx` |
|
|
27
|
+
| 垂直 12px | `padding: EdgeInsets.symmetric(vertical: 12)` | `padding: 12px 0` | `paddingVertical: 12` | `padding: 24rpx 0` |
|
|
28
|
+
| 上20 右16 下12 左16 | `padding: EdgeInsets.fromLTRB(16, 20, 16, 12)` | `padding: 20px 16px 12px 16px` | `paddingTop: 20, ...` | `padding: 40rpx 32rpx 24rpx` |
|
|
29
|
+
|
|
30
|
+
### 外边距 (Margin)
|
|
31
|
+
|
|
32
|
+
| 设计稿 | Flutter | Vue/CSS | React Native | 小程序 |
|
|
33
|
+
|--------|---------|---------|--------------|--------|
|
|
34
|
+
| 底部 16px | `margin: EdgeInsets.only(bottom: 16)` | `margin-bottom: 16px` | `marginBottom: 16` | `margin-bottom: 32rpx` |
|
|
35
|
+
| 水平居中 | `Container(alignment: Alignment.center)` | `margin: 0 auto` | `alignSelf: 'center'` | `margin: 0 auto` |
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 🎨 颜色
|
|
40
|
+
|
|
41
|
+
### 纯色
|
|
42
|
+
|
|
43
|
+
| 设计稿 | Flutter | Vue/CSS | React Native |
|
|
44
|
+
|--------|---------|---------|--------------|
|
|
45
|
+
| #1C2B45 | `Color(0xFF1C2B45)` | `#1C2B45` | `'#1C2B45'` |
|
|
46
|
+
| #1C2B45 50%透明 | `Color(0x801C2B45)` | `rgba(28,43,69,0.5)` | `'rgba(28,43,69,0.5)'` |
|
|
47
|
+
|
|
48
|
+
### 透明度换算
|
|
49
|
+
|
|
50
|
+
| 透明度 | 十六进制 | 用法示例 |
|
|
51
|
+
|--------|---------|---------|
|
|
52
|
+
| 100% | FF | `0xFF1C2B45` |
|
|
53
|
+
| 90% | E6 | `0xE61C2B45` |
|
|
54
|
+
| 80% | CC | `0xCC1C2B45` |
|
|
55
|
+
| 70% | B3 | `0xB31C2B45` |
|
|
56
|
+
| 60% | 99 | `0x991C2B45` |
|
|
57
|
+
| 50% | 80 | `0x801C2B45` |
|
|
58
|
+
| 40% | 66 | `0x661C2B45` |
|
|
59
|
+
| 30% | 4D | `0x4D1C2B45` |
|
|
60
|
+
| 20% | 33 | `0x331C2B45` |
|
|
61
|
+
| 15% | 26 | `0x261C2B45` |
|
|
62
|
+
| 12% | 1F | `0x1F1C2B45` |
|
|
63
|
+
| 10% | 1A | `0x1A1C2B45` |
|
|
64
|
+
| 5% | 0D | `0x0D1C2B45` |
|
|
65
|
+
| 0% | 00 | `0x001C2B45` |
|
|
66
|
+
|
|
67
|
+
### 渐变色
|
|
68
|
+
|
|
69
|
+
**设计稿**: 从 #E01020 到 #B8101A,左上到右下
|
|
70
|
+
|
|
71
|
+
```dart
|
|
72
|
+
// Flutter
|
|
73
|
+
LinearGradient(
|
|
74
|
+
begin: Alignment.topLeft,
|
|
75
|
+
end: Alignment.bottomRight,
|
|
76
|
+
colors: [Color(0xFFE01020), Color(0xFFB8101A)],
|
|
77
|
+
)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```css
|
|
81
|
+
/* CSS */
|
|
82
|
+
background: linear-gradient(135deg, #E01020 0%, #B8101A 100%);
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
```javascript
|
|
86
|
+
// React Native (需要 react-native-linear-gradient)
|
|
87
|
+
<LinearGradient
|
|
88
|
+
colors={['#E01020', '#B8101A']}
|
|
89
|
+
start={{x: 0, y: 0}}
|
|
90
|
+
end={{x: 1, y: 1}}
|
|
91
|
+
/>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```css
|
|
95
|
+
/* 小程序 */
|
|
96
|
+
background: linear-gradient(135deg, #E01020, #B8101A);
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## 📦 圆角
|
|
102
|
+
|
|
103
|
+
| 设计稿 | Flutter | Vue/CSS | React Native |
|
|
104
|
+
|--------|---------|---------|--------------|
|
|
105
|
+
| 全部 12px | `borderRadius: BorderRadius.circular(12)` | `border-radius: 12px` | `borderRadius: 12` |
|
|
106
|
+
| 只有顶部 12px | `borderRadius: BorderRadius.vertical(top: Radius.circular(12))` | `border-radius: 12px 12px 0 0` | `borderTopLeftRadius: 12, borderTopRightRadius: 12` |
|
|
107
|
+
| 各角不同 [8,12,16,20] | `borderRadius: BorderRadius.only(topLeft: Radius.circular(8), ...)` | `border-radius: 8px 12px 16px 20px` | 逐角设置 |
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 🌑 阴影
|
|
112
|
+
|
|
113
|
+
### 单一阴影
|
|
114
|
+
|
|
115
|
+
**设计稿**: x=8, y=8, blur=20, color=#1C2B45 15%
|
|
116
|
+
|
|
117
|
+
```dart
|
|
118
|
+
// Flutter
|
|
119
|
+
BoxShadow(
|
|
120
|
+
color: Color(0x261C2B45), // 15% = 0x26
|
|
121
|
+
blurRadius: 20,
|
|
122
|
+
offset: Offset(8, 8),
|
|
123
|
+
spreadRadius: 0,
|
|
124
|
+
)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
```css
|
|
128
|
+
/* CSS */
|
|
129
|
+
box-shadow: 8px 8px 20px 0px rgba(28, 43, 69, 0.15);
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
```javascript
|
|
133
|
+
// React Native
|
|
134
|
+
shadowColor: '#1C2B45',
|
|
135
|
+
shadowOffset: { width: 8, height: 8 },
|
|
136
|
+
shadowOpacity: 0.15,
|
|
137
|
+
shadowRadius: 20,
|
|
138
|
+
elevation: 8, // Android
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 新拟态双阴影
|
|
142
|
+
|
|
143
|
+
**设计稿**: 右下深色 + 左上浅色
|
|
144
|
+
|
|
145
|
+
```dart
|
|
146
|
+
// Flutter
|
|
147
|
+
boxShadow: [
|
|
148
|
+
// 右下阴影(深色)
|
|
149
|
+
BoxShadow(
|
|
150
|
+
color: Color(0x261C2B45), // 15%
|
|
151
|
+
blurRadius: 20,
|
|
152
|
+
offset: Offset(8, 8),
|
|
153
|
+
),
|
|
154
|
+
// 左上高光(浅色)
|
|
155
|
+
BoxShadow(
|
|
156
|
+
color: Color(0xE6FFFFFF), // 90%
|
|
157
|
+
blurRadius: 20,
|
|
158
|
+
offset: Offset(-8, -8),
|
|
159
|
+
),
|
|
160
|
+
]
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
```css
|
|
164
|
+
/* CSS */
|
|
165
|
+
box-shadow:
|
|
166
|
+
8px 8px 20px rgba(28, 43, 69, 0.15),
|
|
167
|
+
-8px -8px 20px rgba(255, 255, 255, 0.9);
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## ✏️ 字体
|
|
173
|
+
|
|
174
|
+
### 基础属性
|
|
175
|
+
|
|
176
|
+
| 设计稿 | Flutter | Vue/CSS | React Native |
|
|
177
|
+
|--------|---------|---------|--------------|
|
|
178
|
+
| 字号 16px | `fontSize: 16` | `font-size: 16px` | `fontSize: 16` |
|
|
179
|
+
| 字重 SemiBold(600) | `fontWeight: FontWeight.w600` | `font-weight: 600` | `fontWeight: '600'` |
|
|
180
|
+
| 字重 Bold(700) | `fontWeight: FontWeight.bold` | `font-weight: bold` | `fontWeight: 'bold'` |
|
|
181
|
+
| 行高 24px (字号16) | `height: 1.5` (比例!) | `line-height: 24px` | `lineHeight: 24` |
|
|
182
|
+
| 字间距 0.5px | `letterSpacing: 0.5` | `letter-spacing: 0.5px` | `letterSpacing: 0.5` |
|
|
183
|
+
|
|
184
|
+
### 字重映射
|
|
185
|
+
|
|
186
|
+
| 名称 | 数值 | Flutter | CSS |
|
|
187
|
+
|------|------|---------|-----|
|
|
188
|
+
| Thin | 100 | `FontWeight.w100` | `font-weight: 100` |
|
|
189
|
+
| ExtraLight | 200 | `FontWeight.w200` | `font-weight: 200` |
|
|
190
|
+
| Light | 300 | `FontWeight.w300` | `font-weight: 300` |
|
|
191
|
+
| Regular | 400 | `FontWeight.w400` / `FontWeight.normal` | `font-weight: 400` |
|
|
192
|
+
| Medium | 500 | `FontWeight.w500` | `font-weight: 500` |
|
|
193
|
+
| SemiBold | 600 | `FontWeight.w600` | `font-weight: 600` |
|
|
194
|
+
| Bold | 700 | `FontWeight.w700` / `FontWeight.bold` | `font-weight: 700` |
|
|
195
|
+
| ExtraBold | 800 | `FontWeight.w800` | `font-weight: 800` |
|
|
196
|
+
| Black | 900 | `FontWeight.w900` | `font-weight: 900` |
|
|
197
|
+
|
|
198
|
+
### ⚠️ Flutter 行高注意
|
|
199
|
+
|
|
200
|
+
Flutter 的 `TextStyle.height` 是**比例值**,不是像素值!
|
|
201
|
+
|
|
202
|
+
```dart
|
|
203
|
+
// 设计稿:字号 16px,行高 24px
|
|
204
|
+
TextStyle(
|
|
205
|
+
fontSize: 16,
|
|
206
|
+
height: 1.5, // 24 / 16 = 1.5
|
|
207
|
+
)
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## 🔲 边框
|
|
213
|
+
|
|
214
|
+
| 设计稿 | Flutter | Vue/CSS | React Native |
|
|
215
|
+
|--------|---------|---------|--------------|
|
|
216
|
+
| 1px #E5E5E5 实线 | `border: Border.all(color: Color(0xFFE5E5E5), width: 1)` | `border: 1px solid #E5E5E5` | `borderWidth: 1, borderColor: '#E5E5E5'` |
|
|
217
|
+
| 只有底边框 | `border: Border(bottom: BorderSide(...))` | `border-bottom: 1px solid #E5E5E5` | `borderBottomWidth: 1, ...` |
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## 📱 单位换算
|
|
222
|
+
|
|
223
|
+
### 小程序 rpx
|
|
224
|
+
|
|
225
|
+
小程序设计稿通常基于 750px 宽度:
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
rpx = px * 2
|
|
229
|
+
|
|
230
|
+
设计稿 16px → 小程序 32rpx
|
|
231
|
+
设计稿 100px → 小程序 200rpx
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### React Native
|
|
235
|
+
|
|
236
|
+
React Native 使用逻辑像素(dp/pt),通常与设计稿 1:1:
|
|
237
|
+
|
|
238
|
+
```javascript
|
|
239
|
+
// 设计稿 16px
|
|
240
|
+
style={{ fontSize: 16 }}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
如需适配,使用 `PixelRatio` 或响应式方案。
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## 📚 相关规范
|
|
248
|
+
|
|
249
|
+
- [设计稿还原规范](./workflows/design-restoration.md)
|
|
250
|
+
- [Sketch MCP 最佳实践](./mcp-tools/sketch-mcp.md)
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
**维护者**: MTA工作室
|
|
255
|
+
**创建日期**: 2026-01-20
|
|
256
|
+
**适用版本**: 通用
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
# 设计稿还原规范 (Design Restoration Standard)
|
|
2
|
+
|
|
3
|
+
> 通用规范 - 适用于所有视觉化开发场景(跨平台/前端/全栈)
|
|
4
|
+
|
|
5
|
+
## 📋 概述
|
|
6
|
+
|
|
7
|
+
本规范定义了从设计工具(Sketch、Figma、Adobe XD 等)还原 UI 到代码的标准流程和注意事项,确保在不同框架(Flutter、Vue、React、小程序等)中都能准确还原设计稿。
|
|
8
|
+
|
|
9
|
+
**适用场景**:
|
|
10
|
+
- 使用 Sketch MCP、Figma MCP 等工具测量设计稿
|
|
11
|
+
- 根据设计图片手动还原 UI
|
|
12
|
+
- 跨平台/多框架项目的样式统一
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 🎯 核心原则
|
|
17
|
+
|
|
18
|
+
### 1. 测量优先级
|
|
19
|
+
|
|
20
|
+
按以下优先级获取设计参数:
|
|
21
|
+
|
|
22
|
+
1. **MCP 工具直接读取** - 最准确,但需注意 API 陷阱
|
|
23
|
+
2. **设计工具检查器** - 设计师侧边栏的属性面板
|
|
24
|
+
3. **标注插件导出** - 如 Sketch Measure、Zeplin
|
|
25
|
+
4. **肉眼估算** - 最后手段,需反复对比验证
|
|
26
|
+
|
|
27
|
+
### 2. 验证闭环
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
测量 → 编码 → 截图对比 → 微调 → 确认
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
每个元素都必须完成这个闭环。
|
|
34
|
+
|
|
35
|
+
### 3. 原子化记录
|
|
36
|
+
|
|
37
|
+
将设计参数按类别记录,便于复用和维护。
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 📐 测量要素清单
|
|
42
|
+
|
|
43
|
+
### 必须测量的参数
|
|
44
|
+
|
|
45
|
+
| 类别 | 参数 | 说明 |
|
|
46
|
+
|------|------|------|
|
|
47
|
+
| **尺寸** | width, height | 精确到像素 |
|
|
48
|
+
| **位置** | x, y, margin, padding | 相对于父容器 |
|
|
49
|
+
| **颜色** | 填充色、边框色、阴影色 | ⚠️ 注意渐变 |
|
|
50
|
+
| **圆角** | borderRadius | 四角可能不同 |
|
|
51
|
+
| **字体** | family, size, weight, height | 行高很重要 |
|
|
52
|
+
| **阴影** | color, blur, offset, spread | 多重阴影 |
|
|
53
|
+
| **边框** | color, width, style | 虚线/实线 |
|
|
54
|
+
|
|
55
|
+
### ⚠️ 常见陷阱
|
|
56
|
+
|
|
57
|
+
#### 1. 渐变色读取错误
|
|
58
|
+
|
|
59
|
+
**问题**:API 返回渐变的"代表色"而非实际渐变定义
|
|
60
|
+
|
|
61
|
+
```javascript
|
|
62
|
+
// ❌ 错误方式
|
|
63
|
+
layer.style.fills[0].color // 返回错误的单色
|
|
64
|
+
|
|
65
|
+
// ✅ 正确方式
|
|
66
|
+
if (fill.fillType === 'Gradient') {
|
|
67
|
+
fill.gradient.stops.map(s => s.color) // 获取所有色标
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
#### 2. 透明度丢失
|
|
72
|
+
|
|
73
|
+
**问题**:颜色值可能不包含透明度信息
|
|
74
|
+
|
|
75
|
+
```javascript
|
|
76
|
+
// 确保读取完整的 RGBA
|
|
77
|
+
color: "#1C2B4580" // 包含透明度
|
|
78
|
+
// 而不是
|
|
79
|
+
color: "#1C2B45" // 丢失透明度
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
#### 3. 字体权重映射
|
|
83
|
+
|
|
84
|
+
设计稿中的字重名称需要映射为数值:
|
|
85
|
+
|
|
86
|
+
| 设计稿名称 | PostScript 后缀 | 数值 | Flutter | CSS |
|
|
87
|
+
|-----------|----------------|------|---------|-----|
|
|
88
|
+
| Thin | -Thin | 100 | FontWeight.w100 | font-weight: 100 |
|
|
89
|
+
| Ultralight | -Ultralight | 200 | FontWeight.w200 | font-weight: 200 |
|
|
90
|
+
| Light | -Light | 300 | FontWeight.w300 | font-weight: 300 |
|
|
91
|
+
| Regular | -Regular | 400 | FontWeight.w400 | font-weight: 400 |
|
|
92
|
+
| Medium | -Medium | 500 | FontWeight.w500 | font-weight: 500 |
|
|
93
|
+
| SemiBold | -Semibold | 600 | FontWeight.w600 | font-weight: 600 |
|
|
94
|
+
| Bold | -Bold | 700 | FontWeight.w700 | font-weight: 700 |
|
|
95
|
+
| Heavy/ExtraBold | -Heavy | 800 | FontWeight.w800 | font-weight: 800 |
|
|
96
|
+
| Black | -Black | 900 | FontWeight.w900 | font-weight: 900 |
|
|
97
|
+
|
|
98
|
+
> ⚠️ **重要**:Sketch API 的 `fontWeight` 属性返回的数值(如 8)不可靠!必须通过 `sketchObject.font().fontName()` 获取真实的 PostScript 字体名称(如 `PingFangSC-Semibold`),然后根据后缀映射。
|
|
99
|
+
|
|
100
|
+
#### 4. 图标必须从设计稿导出
|
|
101
|
+
|
|
102
|
+
**绝对禁止**:AI 自己生成图标 SVG
|
|
103
|
+
|
|
104
|
+
**正确做法**:使用设计工具 API 导出设计稿中的图标
|
|
105
|
+
|
|
106
|
+
```javascript
|
|
107
|
+
// Sketch 导出示例
|
|
108
|
+
const buffer = sketch.export(iconLayer, {
|
|
109
|
+
formats: 'svg',
|
|
110
|
+
output: false,
|
|
111
|
+
scales: '1'
|
|
112
|
+
});
|
|
113
|
+
const svgString = buffer.toString('utf-8');
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**原因**:
|
|
117
|
+
- 设计师精心调整过图标的线条粗细、比例、细节
|
|
118
|
+
- AI 生成的图标风格可能与设计稿不一致
|
|
119
|
+
- 图标是品牌视觉的重要组成部分
|
|
120
|
+
|
|
121
|
+
#### 5. 列表间距必须逐个测量
|
|
122
|
+
|
|
123
|
+
**问题**:同一列表中的元素间距可能不完全一致
|
|
124
|
+
|
|
125
|
+
**正确做法**:测量每对相邻元素的间距,取多数值或与设计师确认
|
|
126
|
+
|
|
127
|
+
```javascript
|
|
128
|
+
// 间距计算公式
|
|
129
|
+
spacing = nextElement.y - (currentElement.y + currentElement.height)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
#### 6. 行高计算差异
|
|
133
|
+
|
|
134
|
+
不同框架对行高的处理不同:
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
设计稿行高: 24px, 字号: 16px
|
|
138
|
+
|
|
139
|
+
Flutter: height = 24 / 16 = 1.5 (比例值)
|
|
140
|
+
CSS: line-height: 24px 或 line-height: 1.5
|
|
141
|
+
小程序: line-height: 24px
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## 🎨 颜色规范
|
|
147
|
+
|
|
148
|
+
### 颜色提取完整流程
|
|
149
|
+
|
|
150
|
+
```javascript
|
|
151
|
+
function extractColor(fill) {
|
|
152
|
+
if (!fill || !fill.enabled) return null;
|
|
153
|
+
|
|
154
|
+
switch (fill.fillType) {
|
|
155
|
+
case 'Color':
|
|
156
|
+
return { type: 'solid', color: fill.color };
|
|
157
|
+
|
|
158
|
+
case 'Gradient':
|
|
159
|
+
return {
|
|
160
|
+
type: 'gradient',
|
|
161
|
+
gradientType: fill.gradient.gradientType, // Linear/Radial/Angular
|
|
162
|
+
direction: {
|
|
163
|
+
from: fill.gradient.from, // { x: 0, y: 0 }
|
|
164
|
+
to: fill.gradient.to // { x: 1, y: 1 }
|
|
165
|
+
},
|
|
166
|
+
stops: fill.gradient.stops.map(s => ({
|
|
167
|
+
position: s.position, // 0 ~ 1
|
|
168
|
+
color: s.color
|
|
169
|
+
}))
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
case 'Pattern':
|
|
173
|
+
return { type: 'pattern', image: fill.pattern?.image };
|
|
174
|
+
|
|
175
|
+
default:
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### 渐变方向映射
|
|
182
|
+
|
|
183
|
+
| 设计稿方向 | Flutter | CSS |
|
|
184
|
+
|-----------|---------|-----|
|
|
185
|
+
| 左上→右下 | Alignment.topLeft → bottomRight | to bottom right |
|
|
186
|
+
| 上→下 | Alignment.topCenter → bottomCenter | to bottom |
|
|
187
|
+
| 左→右 | Alignment.centerLeft → centerRight | to right |
|
|
188
|
+
|
|
189
|
+
### 颜色透明度表示
|
|
190
|
+
|
|
191
|
+
```dart
|
|
192
|
+
// Flutter - 使用 0x 前缀
|
|
193
|
+
Color(0x801C2B45) // 50% 透明度
|
|
194
|
+
|
|
195
|
+
// CSS - 使用 rgba 或 8位十六进制
|
|
196
|
+
rgba(28, 43, 69, 0.5)
|
|
197
|
+
#1C2B4580
|
|
198
|
+
|
|
199
|
+
// 小程序 - 同 CSS
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## 📦 框架语法映射
|
|
205
|
+
|
|
206
|
+
### 容器/盒模型
|
|
207
|
+
|
|
208
|
+
| 属性 | Flutter | Vue/CSS | React Native | 小程序 |
|
|
209
|
+
|------|---------|---------|--------------|--------|
|
|
210
|
+
| 宽度 | `width: 100` | `width: 100px` | `width: 100` | `width: 100rpx` |
|
|
211
|
+
| 高度 | `height: 100` | `height: 100px` | `height: 100` | `height: 100rpx` |
|
|
212
|
+
| 内边距 | `padding: EdgeInsets.all(16)` | `padding: 16px` | `padding: 16` | `padding: 32rpx` |
|
|
213
|
+
| 外边距 | `margin: EdgeInsets.only(top: 8)` | `margin-top: 8px` | `marginTop: 8` | `margin-top: 16rpx` |
|
|
214
|
+
| 圆角 | `borderRadius: BorderRadius.circular(12)` | `border-radius: 12px` | `borderRadius: 12` | `border-radius: 24rpx` |
|
|
215
|
+
|
|
216
|
+
### 颜色
|
|
217
|
+
|
|
218
|
+
| 场景 | Flutter | Vue/CSS | React Native |
|
|
219
|
+
|------|---------|---------|--------------|
|
|
220
|
+
| 纯色 | `Color(0xFF1C2B45)` | `#1C2B45` | `'#1C2B45'` |
|
|
221
|
+
| 透明色 | `Color(0x801C2B45)` | `rgba(28,43,69,0.5)` | `'rgba(28,43,69,0.5)'` |
|
|
222
|
+
| 渐变 | `LinearGradient(colors: [...])` | `linear-gradient(...)` | `LinearGradient` |
|
|
223
|
+
|
|
224
|
+
### 阴影
|
|
225
|
+
|
|
226
|
+
```dart
|
|
227
|
+
// Flutter
|
|
228
|
+
BoxShadow(
|
|
229
|
+
color: Color(0x261C2B45),
|
|
230
|
+
blurRadius: 20,
|
|
231
|
+
offset: Offset(8, 8),
|
|
232
|
+
spreadRadius: 0,
|
|
233
|
+
)
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
```css
|
|
237
|
+
/* CSS */
|
|
238
|
+
box-shadow: 8px 8px 20px 0px rgba(28, 43, 69, 0.15);
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
```javascript
|
|
242
|
+
// React Native
|
|
243
|
+
shadowColor: '#1C2B45',
|
|
244
|
+
shadowOffset: { width: 8, height: 8 },
|
|
245
|
+
shadowOpacity: 0.15,
|
|
246
|
+
shadowRadius: 20,
|
|
247
|
+
elevation: 8, // Android
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### 字体
|
|
251
|
+
|
|
252
|
+
| 属性 | Flutter | CSS | React Native |
|
|
253
|
+
|------|---------|-----|--------------|
|
|
254
|
+
| 字号 | `fontSize: 16` | `font-size: 16px` | `fontSize: 16` |
|
|
255
|
+
| 字重 | `fontWeight: FontWeight.w600` | `font-weight: 600` | `fontWeight: '600'` |
|
|
256
|
+
| 行高 | `height: 1.5` (比例) | `line-height: 24px` | `lineHeight: 24` |
|
|
257
|
+
| 颜色 | `color: Color(0xFF1C2B45)` | `color: #1C2B45` | `color: '#1C2B45'` |
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## 🔧 MCP 工具使用规范
|
|
262
|
+
|
|
263
|
+
### Sketch MCP
|
|
264
|
+
|
|
265
|
+
#### 正确的测量脚本模板
|
|
266
|
+
|
|
267
|
+
```javascript
|
|
268
|
+
const sketch = require('sketch');
|
|
269
|
+
const doc = sketch.getSelectedDocument();
|
|
270
|
+
const artboard = doc.selectedLayers.layers[0];
|
|
271
|
+
|
|
272
|
+
function measureLayer(layer) {
|
|
273
|
+
const result = {
|
|
274
|
+
name: layer.name,
|
|
275
|
+
type: layer.type,
|
|
276
|
+
frame: {
|
|
277
|
+
x: Math.round(layer.frame.x),
|
|
278
|
+
y: Math.round(layer.frame.y),
|
|
279
|
+
width: Math.round(layer.frame.width),
|
|
280
|
+
height: Math.round(layer.frame.height),
|
|
281
|
+
},
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
// 样式
|
|
285
|
+
if (layer.style) {
|
|
286
|
+
// 填充色 - 正确处理渐变
|
|
287
|
+
if (layer.style.fills?.length > 0) {
|
|
288
|
+
result.fills = layer.style.fills
|
|
289
|
+
.filter(f => f.enabled)
|
|
290
|
+
.map(f => extractColor(f));
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// 边框
|
|
294
|
+
if (layer.style.borders?.length > 0) {
|
|
295
|
+
result.borders = layer.style.borders
|
|
296
|
+
.filter(b => b.enabled)
|
|
297
|
+
.map(b => ({
|
|
298
|
+
color: b.color,
|
|
299
|
+
thickness: b.thickness,
|
|
300
|
+
}));
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// 阴影
|
|
304
|
+
if (layer.style.shadows?.length > 0) {
|
|
305
|
+
result.shadows = layer.style.shadows
|
|
306
|
+
.filter(s => s.enabled)
|
|
307
|
+
.map(s => ({
|
|
308
|
+
color: s.color,
|
|
309
|
+
blur: s.blur,
|
|
310
|
+
x: s.x,
|
|
311
|
+
y: s.y,
|
|
312
|
+
spread: s.spread,
|
|
313
|
+
}));
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// 圆角
|
|
317
|
+
if (layer.style.corners) {
|
|
318
|
+
result.cornerRadius = layer.style.corners.radii;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// 文字特有属性
|
|
323
|
+
if (layer.type === 'Text') {
|
|
324
|
+
result.text = {
|
|
325
|
+
content: layer.text,
|
|
326
|
+
fontSize: layer.style.fontSize,
|
|
327
|
+
fontFamily: layer.style.fontFamily,
|
|
328
|
+
fontWeight: layer.style.fontWeight,
|
|
329
|
+
textColor: layer.style.textColor,
|
|
330
|
+
alignment: layer.style.alignment,
|
|
331
|
+
lineHeight: layer.style.lineHeight,
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
return result;
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Figma MCP(预留)
|
|
340
|
+
|
|
341
|
+
```javascript
|
|
342
|
+
// Figma API 颜色读取
|
|
343
|
+
function getFigmaColor(paint) {
|
|
344
|
+
if (paint.type === 'SOLID') {
|
|
345
|
+
return {
|
|
346
|
+
type: 'solid',
|
|
347
|
+
color: rgbaToHex(paint.color, paint.opacity),
|
|
348
|
+
};
|
|
349
|
+
} else if (paint.type === 'GRADIENT_LINEAR') {
|
|
350
|
+
return {
|
|
351
|
+
type: 'gradient',
|
|
352
|
+
stops: paint.gradientStops.map(s => ({
|
|
353
|
+
position: s.position,
|
|
354
|
+
color: rgbaToHex(s.color),
|
|
355
|
+
})),
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## ✅ 还原检查清单
|
|
364
|
+
|
|
365
|
+
### 每个元素必查
|
|
366
|
+
|
|
367
|
+
- [ ] 尺寸是否精确匹配
|
|
368
|
+
- [ ] 位置/间距是否正确
|
|
369
|
+
- [ ] 颜色是否正确(特别注意渐变)
|
|
370
|
+
- [ ] 圆角是否正确
|
|
371
|
+
- [ ] 阴影效果是否还原
|
|
372
|
+
- [ ] 字体样式是否匹配
|
|
373
|
+
|
|
374
|
+
### 整体验收
|
|
375
|
+
|
|
376
|
+
- [ ] 与设计稿截图叠加对比
|
|
377
|
+
- [ ] 不同屏幕尺寸下的适配
|
|
378
|
+
- [ ] 交互状态(hover、active、disabled)
|
|
379
|
+
- [ ] 暗黑模式(如有)
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
## 📚 相关规范
|
|
384
|
+
|
|
385
|
+
- [Sketch MCP 最佳实践](./mcp-tools/sketch-mcp.md)
|
|
386
|
+
- [Figma MCP 最佳实践](./mcp-tools/figma-mcp.md)(计划中)
|
|
387
|
+
- [颜色系统规范](./color-system.md)(计划中)
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
## 🔄 版本历史
|
|
392
|
+
|
|
393
|
+
| 版本 | 日期 | 更新内容 |
|
|
394
|
+
|------|------|---------|
|
|
395
|
+
| v1.0 | 2026-01-20 | 初始版本,包含渐变色读取问题解决方案 |
|
|
396
|
+
| v1.1 | 2026-01-21 | 新增:字重映射完整表(含PostScript后缀)、图标导出强制要求、列表间距测量规范 |
|
|
397
|
+
|
|
398
|
+
---
|
|
399
|
+
|
|
400
|
+
**维护者**: MTA工作室
|
|
401
|
+
**创建日期**: 2026-01-20
|
package/templates/README.md
CHANGED
|
@@ -70,6 +70,11 @@ templates/
|
|
|
70
70
|
│ ├── api-layer/
|
|
71
71
|
│ └── themes/
|
|
72
72
|
├── react/ # React 项目模板(预留)
|
|
73
|
+
├── design-measurement/ # 设计稿测量模板 ✅ 新增
|
|
74
|
+
│ ├── README.md # 使用指南
|
|
75
|
+
│ ├── component-measurement.js # 组件测量
|
|
76
|
+
│ ├── style-extraction.js # 样式提取
|
|
77
|
+
│ └── gap-measurement.js # 间距测量
|
|
73
78
|
└── common/ # 跨框架通用模板
|
|
74
79
|
└── types/ # TypeScript 类型定义 ✅
|
|
75
80
|
```
|
|
@@ -108,6 +113,15 @@ templates/
|
|
|
108
113
|
|------|--------|------|------|
|
|
109
114
|
| `common/types` | types, 类型 | TypeScript 通用类型 | ✅ 可用 |
|
|
110
115
|
|
|
116
|
+
### 设计稿测量模板 🆕
|
|
117
|
+
|
|
118
|
+
| 模板 | 关键词 | 说明 | 状态 |
|
|
119
|
+
|------|--------|------|------|
|
|
120
|
+
| `design-measurement` | 测量, measure | 设计稿测量脚本合集 | ✅ 可用 |
|
|
121
|
+
| `component-measurement.js` | 组件, 边距 | 组件尺寸+相对边距 | ✅ 可用 |
|
|
122
|
+
| `style-extraction.js` | 样式, 渐变, 阴影 | 完整样式提取 | ✅ 可用 |
|
|
123
|
+
| `gap-measurement.js` | 间距, gap | 同级元素间距 | ✅ 可用 |
|
|
124
|
+
|
|
111
125
|
---
|
|
112
126
|
|
|
113
127
|
## 🔧 模板规范
|