news 2026/11/2 9:03:09

Cursor 联动蓝湖 MCP:Vue 3 + SCSS 设计稿自动还原实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Cursor 联动蓝湖 MCP:Vue 3 + SCSS 设计稿自动还原实战

1. 这个项目到底在解决什么问题

设计师追着问“还原了吗”,大概是每个前端都经历过的日常。页面刚联调完,设计稿上标注的间距是 24px,你写的是 24px,但设计师打开一看,说“感觉不对”。你截图对比,发现字体渲染差异、行高计算方式、甚至浏览器默认样式都在悄悄捣鬼。来回拉扯几轮,时间全耗在“你截个图我看看”“你刷新一下”“是不是缓存”这种对话上。

我这次做的事情,就是把 Cursor 和蓝湖之间的链路打通,让 AI 直接读取蓝湖上的设计标注,自动生成对应的 Vue 3 + SCSS 代码,并且把还原度校验也纳入流程。核心不是“让 AI 写代码”这么简单,而是让设计稿的数值、层级、样式规则成为 AI 可理解的结构化输入,减少人工转译的误差。

这个方案适合几类人:一是中小团队的前端,没有专职的还原度校验工具,靠人眼比对;二是用 Vue 3 + SCSS 技术栈的开发者,希望把设计标注直接转成可维护的样式代码;三是对 MCP 协议感兴趣、想看看 AI 编程助手怎么跟外部设计工具联动的同学。如果你还在手动量间距、抄色值、算字号,这套流程能省掉大量重复劳动。

需要提前说明的是,蓝湖本身并没有官方开放的 MCP 服务,社区里提到的“蓝湖 MCP”更多是开发者自己搭的中间层,通过蓝湖的开放接口或者页面数据抓取,把设计稿信息转成 MCP 协议能识别的格式。我这次也是走的这个路子,下面会详细拆解。

2. 整体方案设计与技术选型

2.1 为什么选 MCP 而不是直接调 API

MCP 是 Model Context Protocol 的缩写,简单理解就是一套让 AI 助手跟外部工具对话的“插头标准”。你可以把它想象成 USB-C:以前每个设备都有自己的接口,现在统一了,AI 就能通过同一个协议去读数据库、调接口、操作浏览器。

我一开始想过直接写个脚本,从蓝湖导出标注 JSON,然后让 Cursor 读文件。但这样做有几个问题:第一,每次设计稿更新都要手动导出,容易漏;第二,Cursor 没法实时感知设计稿变化,还是得我主动触发;第三,脚本和 AI 之间的上下文传递很别扭,得把数据塞进 prompt 里,token 消耗大且容易截断。

用 MCP 的好处是,Cursor 作为 MCP 客户端,可以主动向 MCP 服务端请求数据。服务端负责跟蓝湖通信,把设计稿的图层、样式、标注转成结构化数据返回。Cursor 拿到数据后,结合当前项目里的 Vue 组件代码,直接生成或修改对应的 SCSS 和模板。整个过程是“AI 主动拉取”,而不是“我手动推送”。

2.2 技术栈组合与版本选择

这次用的技术栈如下:

组件选型版本选择理由
AI 编辑器Cursor最新稳定版对 MCP 支持成熟,Agent 模式能自动调用工具
前端框架Vue 33.4+Composition API 配合<script setup>写起来简洁
样式预处理SCSS1.70+嵌套、变量、mixin 对设计稿还原友好
设计协作蓝湖网页版团队在用,标注信息全
协议层MCP2024-11 规范社区生态活跃,Node.js SDK 好用
运行时Node.js20 LTS稳定,npm 包兼容性好

Vue 3 和 SCSS 是团队既有技术栈,没什么好纠结的。重点说下为什么用 Node.js 写 MCP 服务端:MCP 官方提供了 TypeScript SDK,用 Node.js 可以快速起一个 stdio 或 SSE 的服务,跟 Cursor 的集成成本最低。而且蓝湖的页面数据是 JSON 结构,Node.js 处理起来很顺手。

2.3 数据流转的完整链路

整个链路分四段:

  1. 蓝湖侧:设计稿发布后,蓝湖会生成一个分享链接,页面里嵌入了图层数据。我通过蓝湖的开放接口(需要团队管理员开通)或者解析页面里的window.__INITIAL_STATE__来获取原始数据。
  2. MCP 服务端:Node.js 服务监听 Cursor 发来的请求,根据传入的设计稿 ID 或页面 URL,去蓝湖拉取数据,然后做清洗和转换。
  3. Cursor 侧:Cursor 的 Agent 模式识别到需要设计稿信息时,自动调用 MCP 工具,拿到结构化的样式数据。
  4. 代码生成:Cursor 结合当前项目的组件结构,把设计稿的图层映射成 Vue 模板和 SCSS 样式,并标注出哪些数值是直接来自设计稿、哪些是推算的。

这里有个关键点:不要让 AI 直接生成整个页面。我的做法是让 Cursor 只生成或修改样式部分,模板结构由我手动控制。因为设计稿的图层命名往往很随意,“矩形 12”“编组 5”这种,AI 硬猜语义容易出错。样式数值是确定的,让 AI 干这个最稳。

3. 核心细节解析与实操要点

3.1 蓝湖数据获取的两种方式

蓝湖并没有公开的、面向个人开发者的 MCP 接口。社区里说的“蓝湖 MCP”,实际上是自己搭的桥接服务。获取数据主要有两条路:

方式一:开放接口。如果团队用的是蓝湖企业版,管理员可以在后台生成 API Token,通过https://api.lanhuapp.com/api/v1/designs/{design_id}这类接口拿到设计稿的图层树和样式信息。这种方式稳定、合规,但需要企业版权限。

方式二:页面数据解析。蓝湖的分享页面在加载时,会把设计稿数据注入到页面的全局变量里。你打开开发者工具,在 Console 里输入window.__INITIAL_STATE__或者window.__NUXT__,能看到一大坨 JSON。这里面包含了画板尺寸、图层位置、填充色、字体、间距等。我这次用的是方式二,因为团队没有企业版接口权限。

注意:页面数据解析的方式依赖于蓝湖前端实现,如果蓝湖改版,数据结构可能变化。建议把解析逻辑单独封装,方便后续维护。

解析出来的数据结构大概长这样:

{ "artboard": { "width": 375, "height": 812, "layers": [ { "id": "layer_1", "name": "标题", "type": "text", "frame": { "x": 24, "y": 60, "width": 200, "height": 28 }, "style": { "fontSize": 20, "fontWeight": 600, "color": "#1A1A1A", "lineHeight": 28 } }, { "id": "layer_2", "name": "卡片", "type": "rect", "frame": { "x": 16, "y": 100, "width": 343, "height": 120 }, "style": { "backgroundColor": "#FFFFFF", "borderRadius": 12, "boxShadow": "0 2px 8px rgba(0,0,0,0.08)" } } ] } }

3.2 MCP 服务端的搭建要点

MCP 服务端我用的是@modelcontextprotocol/sdk这个包。核心是定义一个 tool,让 Cursor 可以调用。代码结构如下:

import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; const server = new Server({ name: 'lanhu-mcp', version: '1.0.0' }, { capabilities: { tools: {} } }); server.setRequestHandler('tools/list', async () => ({ tools: [ { name: 'get_design_spec', description: '根据蓝湖设计稿链接获取图层样式数据', inputSchema: { type: 'object', properties: { url: { type: 'string', description: '蓝湖分享链接' }, layerName: { type: 'string', description: '可选,指定图层名称' } }, required: ['url'] } } ] })); server.setRequestHandler('tools/call', async (request) => { if (request.params.name === 'get_design_spec') { const { url, layerName } = request.params.arguments; const spec = await fetchLanhuSpec(url, layerName); return { content: [{ type: 'text', text: JSON.stringify(spec, null, 2) }] }; } }); const transport = new StdioServerTransport(); await server.connect(transport);

fetchLanhuSpec函数负责去蓝湖拉数据。这里有个坑:蓝湖的页面数据是异步加载的,直接用fetch拿到的 HTML 里没有完整 JSON。我的做法是用 Playwright 无头浏览器打开页面,等window.__INITIAL_STATE__就绪后再取出来。

import { chromium } from 'playwright'; async function fetchLanhuSpec(url, layerName) { const browser = await chromium.launch({ headless: true }); const page = await browser.newPage(); await page.goto(url, { waitUntil: 'networkidle' }); await page.waitForFunction(() => window.__INITIAL_STATE__ !== undefined); const state = await page.evaluate(() => window.__INITIAL_STATE__); await browser.close(); const layers = extractLayers(state); if (layerName) { return layers.filter(l => l.name.includes(layerName)); } return layers; }

提示:Playwright 需要下载浏览器内核,首次运行会慢一些。如果团队网络环境受限,可以提前把 Chromium 装好。

3.3 Cursor 侧的配置与提示词设计

Cursor 里配置 MCP 服务端,在设置里找到 MCP Servers,添加一个 stdio 类型的服务,命令指向你本地的 Node.js 脚本。配置好后,Cursor 的 Agent 模式就能看到get_design_spec这个工具。

提示词的设计很关键。我试过几种写法,最后稳定下来的是这样:

当前项目是 Vue 3 + SCSS,组件目录在 src/components。 请调用 get_design_spec 获取设计稿数据,然后: 1. 只修改 .vue 文件中的 <style lang="scss"> 部分,不要动模板结构。 2. 样式数值必须与设计稿一致,单位用 px,不要转 rem。 3. 颜色值统一用 SCSS 变量,变量定义在 src/styles/variables.scss。 4. 如果设计稿中有圆角、阴影,直接写进对应选择器。 5. 生成后列出所有与设计稿不一致的地方,并说明原因。

这样写的好处是约束了 AI 的修改范围,避免它“自作主张”改模板。同时要求它列出不一致项,方便我快速定位问题。

3.4 Vue 3 + SCSS 的样式映射规则

设计稿的图层样式到 SCSS 的映射,有几个固定规则:

  • 间距:设计稿里两个图层的frame.x差值,就是 margin 或 padding。但要注意,如果父图层有 padding,子图层的 x 是相对于父图层的,需要做减法。
  • 字体:fontSize直接对应font-size,lineHeight对应line-height。如果设计稿没标 lineHeight,按fontSize * 1.5估算,但要在注释里标明是估算值。
  • 颜色:#RRGGBB格式直接转 SCSS 变量。如果设计稿用了透明度,转成rgba()。
  • 圆角:borderRadius直接对应border-radius。如果四个角不同,分别写。
  • 阴影:boxShadow字符串直接复制,但要注意蓝湖导出的阴影格式可能是x y blur spread color,跟 CSS 一致。

我写了一个映射表放在项目里,让 Cursor 参考:

设计稿字段SCSS 属性转换规则
frame.x 差值margin-left / padding-left相对于父图层计算
frame.y 差值margin-top / padding-top同上
style.fontSizefont-size直接使用,单位 px
style.colorcolor转 SCSS 变量
style.backgroundColorbackground-color转 SCSS 变量
style.borderRadiusborder-radius直接使用
style.boxShadowbox-shadow直接复制

4. 实操过程与核心环节实现

4.1 环境准备与依赖安装

先确保本地有 Node.js 20 和 npm。然后新建一个目录,初始化项目:

mkdir lanhu-mcp && cd lanhu-mcp npm init -y npm install @modelcontextprotocol/sdk playwright npx playwright install chromium

Cursor 那边,打开设置,找到 MCP 配置,添加:

{ "mcpServers": { "lanhu": { "command": "node", "args": ["/absolute/path/to/lanhu-mcp/index.js"] } } }

保存后重启 Cursor,在 Agent 模式里输入“列出可用工具”,如果能看到get_design_spec,说明连接成功。

4.2 蓝湖数据抓取与清洗

抓取函数写好后,先手动跑一次,看看拿到的数据长什么样。我遇到的问题是,蓝湖的__INITIAL_STATE__里图层是扁平数组,但实际有父子关系。需要根据parentId重建树结构。

function buildLayerTree(flatLayers) { const map = {}; const roots = []; flatLayers.forEach(layer => { map[layer.id] = { ...layer, children: [] }; }); flatLayers.forEach(layer => { if (layer.parentId && map[layer.parentId]) { map[layer.parentId].children.push(map[layer.id]); } else { roots.push(map[layer.id]); } }); return roots; }

清洗的时候,把不需要的字段去掉,比如id、parentId、type这些对样式生成没用的,只保留name、frame、style。这样返回给 Cursor 的数据更精简,token 消耗少。

4.3 样式生成与还原度校验

Cursor 拿到数据后,会生成 SCSS。但生成完不代表就还原了。我加了一步校验:用 Playwright 打开本地开发服务器,截图,然后跟蓝湖的设计稿截图做像素对比。

具体做法是,在 MCP 服务端再加一个 tool,叫compare_screenshot,接收本地页面 URL 和蓝湖设计稿 URL,分别截图后计算差异像素比例。

async function compareScreenshots(localUrl, lanhuUrl) { const browser = await chromium.launch(); const page = await browser.newPage({ viewport: { width: 375, height: 812 } }); await page.goto(localUrl); const localShot = await page.screenshot(); await page.goto(lanhuUrl); await page.waitForTimeout(2000); const designShot = await page.screenshot(); await browser.close(); const diff = pixelDiff(localShot, designShot); return { diffRatio: diff.ratio, diffImage: diff.image }; }

pixelDiff可以用pixelmatch这个库。差异比例超过 5% 就提示需要人工检查。这个数值不是绝对的,字体渲染差异、图片加载延迟都会影响,但能筛出大部分明显问题。

4.4 实际项目中的接入记录

我在一个后台管理项目里试了这套流程。项目是 Vue 3 + Vite + SCSS,组件大概 40 多个。设计稿是一个数据看板页面,有卡片、表格、图表容器。

操作步骤:

  1. 在 Cursor 里打开项目,Agent 模式输入:“调用 get_design_spec,获取这个蓝湖链接的样式数据,然后修改 DashboardCard.vue 的样式部分。”
  2. Cursor 自动调用 MCP 工具,拿到图层数据。
  3. 它识别出卡片有borderRadius: 12、boxShadow: 0 2px 8px rgba(0,0,0,0.08)、padding: 16,然后写进 SCSS。
  4. 我手动检查了一遍,发现它把padding写成了padding: 16px 16px 16px 16px,虽然没错但冗余。我在提示词里加了“简写属性优先”,后面就改成padding: 16px了。
  5. 跑compare_screenshot,差异比例 3.2%,主要是图表区域的占位图跟设计稿的示例图不一样,样式本身没问题。

整个过程从打开设计稿到样式改完,大概 3 分钟。以前手动量、手动写,至少 15 分钟,还得反复确认。

5. 常见问题与排查技巧实录

5.1 蓝湖数据抓取失败怎么办

最常见的问题是 Playwright 打开页面后,__INITIAL_STATE__一直是 undefined。原因通常是页面需要登录,或者分享链接过期了。

排查步骤:

  1. 先用浏览器手动打开链接,确认能正常看到设计稿。
  2. 检查链接是不是需要密码,如果需要,在 Playwright 里加一步输入密码。
  3. 如果页面加载慢,把waitUntil改成domcontentloaded,然后手动waitForFunction等数据。
  4. 有些蓝湖页面用的是__NUXT__而不是__INITIAL_STATE__,两个都检查一下。

注意:不要频繁抓取同一个设计稿,蓝湖可能有频率限制。我一般加个 5 分钟缓存,同一个链接短时间内不重复请求。

5.2 Cursor 不调用 MCP 工具

有时候 Cursor 会忽略 MCP 工具,直接凭自己的理解写样式。这通常是因为提示词不够明确。

解决办法:

  • 在提示词里明确写“必须调用 get_design_spec 工具获取数据,不要凭记忆生成”。
  • 检查 MCP 服务端是否正常运行,可以在终端里手动跑一下node index.js,看有没有报错。
  • Cursor 的 Agent 模式对 MCP 支持最好,Chat 模式有时候不触发工具调用。

5.3 生成的样式跟设计稿有偏差

偏差来源主要有几个:

问题现象可能原因解决方法
间距差 1-2px设计稿图层有描边,frame 包含了描边宽度检查 style.borderWidth,从 frame 里减去
字体大小不对设计稿用了 rem 或百分比确认设计稿单位,统一转 px
颜色有差异设计稿有透明度叠加用取色器取最终色值,不要用图层填充色
圆角不生效父元素有 overflow: hidden检查父级样式,必要时调整层级
阴影被裁剪父元素 overflow: hidden同上,或者用 filter: drop-shadow 替代

我踩过最坑的一次是,设计稿里卡片的阴影是0 2px 8px rgba(0,0,0,0.08),但父容器有overflow: hidden,阴影直接被切掉了。后来把父容器的 overflow 改成 visible,问题解决。这种问题 AI 看不出来,得人工排查。

5.4 还原度校验的误报处理

compare_screenshot有时候会误报,比如:

  • 本地页面有动画,截图时刚好在中间状态。
  • 设计稿里的图片是占位图,本地是真实图片。
  • 字体渲染差异,macOS 和 Windows 不一样。

我的做法是,差异比例超过 5% 才人工介入,5% 以内先忽略。如果某个区域反复报差异,就在校验脚本里加个 mask,把那个区域排除掉。

5.5 团队协作中的权限与同步问题

如果团队多人用这套流程,要注意:

  • 蓝湖的分享链接权限,确保每个人都能访问。
  • MCP 服务端脚本放在团队共享仓库里,版本统一。
  • SCSS 变量文件要同步,不然 AI 生成的变量名可能跟别人冲突。
  • 建议加一个 pre-commit hook,提交前自动跑一次样式校验,避免把明显偏差的代码合进去。

6. 一些实操心得与后续扩展方向

这套流程跑通之后,我最大的感受是:AI 不是替代前端,而是把前端从“数值搬运”里解放出来。设计稿的数值是确定的,让 AI 去读、去写,比人眼去量、去抄靠谱得多。但 AI 不懂业务语义,不懂组件拆分,不懂交互逻辑,这些还是得人来把控。

有几个小技巧可以分享:

第一,图层命名尽量规范。如果设计稿里图层叫“标题”“卡片”“按钮”,AI 映射起来准确率高很多。如果叫“矩形 12”“编组 5”,就得靠 frame 位置去猜,容易出错。可以跟设计师约定一套命名规范,比如“模块-元素-状态”。

第二,SCSS 变量提前定义好。我把颜色、字号、间距都抽成了变量,AI 生成时直接引用变量名,而不是写死数值。这样后续改主题色,改一个变量就行,不用全局搜索替换。

第三,还原度校验不要追求 100%。像素级还原在理论上就不可能,不同浏览器、不同设备、不同字体渲染引擎,都会有差异。把目标定在“肉眼看不出来明显偏差”就行,差异比例控制在 5% 以内,重点区域人工确认。

后续我打算把图表容器的样式也纳入进来。现在图表用的是 ECharts,样式配置在 JS 里,AI 生成的 SCSS 管不到。下一步想做一个 ECharts 主题的映射,把设计稿里的图表颜色、字体、间距转成 ECharts 的 theme 配置。这样整个页面的还原度就能统一管理了。

另外,MCP 服务端现在只支持蓝湖,后面可以扩展支持 Figma。Figma 有官方 API,数据更规范,接入成本可能比蓝湖还低。如果团队同时用两个设计工具,可以做一个统一的 MCP 服务,根据链接域名自动路由到不同的数据源。

最后再提一个坑:Cursor 的 Agent 模式在调用 MCP 工具时,会把返回的数据塞进上下文。如果设计稿图层特别多,返回的 JSON 可能几千行,token 消耗很大。我的做法是在 MCP 服务端做过滤,只返回跟当前组件相关的图层。比如传入组件名“DashboardCard”,就只返回名字里包含“Card”的图层。这样上下文精简,AI 生成也更准。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/2 9:02:42

自适应模糊控制器设计:规则表到在线自整定完整方案

简介&#xff1a;这份资源面向学习模糊控制与自适应模糊控制器设计的高校学生、控制工程方向研究者及工程实践者&#xff0c;围绕模糊化、模糊规则库、模糊推理与去模糊化等核心环节&#xff0c;结合自适应机制、学习过程与实时参数调整&#xff0c;帮助读者理解如何让控制器根…

作者头像 李华
网站建设 2026/11/2 9:02:41

Windows系统bcryptprimitives.dll丢失原因与修复指南

1. 认识bcryptprimitives.dll文件bcryptprimitives.dll是Windows操作系统中一个关键的加密相关动态链接库文件&#xff0c;属于微软Windows Cryptography API: Next Generation (CNG)组件的一部分。这个文件主要负责提供基础的加密算法实现&#xff0c;包括哈希函数、对称加密和…

作者头像 李华
网站建设 2026/11/2 9:01:33

Jev类型安全中间层:统一AI模型API调用与错误处理实践

1. 从一个让人抓狂的报错说起&#xff1a;Jev到底解决什么问题第一次看到"Jev"这个词&#xff0c;大概率不是在什么技术发布会现场&#xff0c;而是在某个深夜的终端窗口里——你刚配好一个AI应用的API Key&#xff0c;满心欢喜地敲下回车&#xff0c;结果屏幕上弹出…

作者头像 李华
网站建设 2026/11/2 9:00:57

AI语音准确性验证工具:原理、实现与应用

1. 项目概述&#xff1a;AI语音准确性验证工具的核心价值在语言学习和语音技术开发领域&#xff0c;发音准确性验证工具正成为不可或缺的测试基础设施。这类工具通过声学分析、语音识别和机器学习算法&#xff0c;能够对发音的准确度、流畅度和完整性进行量化评估。不同于传统人…

作者头像 李华
网站建设 2026/11/2 8:59:44

Python学生成绩管理系统:工程化实践最小完整切片

1. 这个系统不是作业&#xff0c;而是理解Python工程落地的“最小完整切片”很多人看到“学生成绩管理系统”第一反应是&#xff1a;又一个课设&#xff1f;抄个GitHub仓库改改UI就交差&#xff1f;我带过几届某高校的Python实践课&#xff0c;也帮不少自学的朋友做过项目复盘&…

作者头像 李华
网站建设 2026/11/2 8:58:56

Go HTTP客户端下载失败的五大典型原因与解决方案

1. 这个标题背后藏着的不是“打不开”&#xff0c;而是Go语言HTTP客户端的典型行为盲区“【Go下载网页打不开】”——看到这个标题&#xff0c;我第一反应不是去查DNS或代理设置&#xff0c;而是立刻打开本地终端&#xff0c;敲下go version&#xff0c;然后翻出最近三个项目里…

作者头像 李华