mcpField
T
taste

taste

github.com/senlindesign设计与 UI433590 次安装16 周前更新
代码仓库

关于 taste

taste 是用于分析网站设计并提取设计规范的技能,会从 URL 生成可读说明和结构化 JSON,供后续设计工作使用。它借助 Playwright MCP 捕获页面,并记录设计取舍及其依据。

主要功能

  1. 01提取颜色、字体与间距等设计令牌
  2. 02记录设计取舍及证据
  3. 03生成 Markdown 与 JSON 文件
  4. 04支持单页或关联页面分析
  5. 05导出至指定设计工具的规则或样式

适用场景

  1. 01将网站视觉风格转为项目设计指导
  2. 02为设计系统提取样式令牌
  3. 03比较竞品网站的设计选择
  4. 04为 Cursor 或 Windsurf 等工具生成设计参考

MCP 相关

运行时需要已连接的 Playwright MCP 服务,以浏览器访问和捕获页面。技能使用其浏览器工具采集截图与 DOM 数据。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/senlindesign/taste-skill --skill taste

安装后在 Claude Code 中输入/taste确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

README.md
.gitignore
docs/
Cherry.glb
index.html
evals/
evals.json
references/
extract.js
export-formats.md
step1-measure.md
step2-pattern.md
step4-observer.md
step3-taste.md

详细介绍

Taste — 反向解析网站的设计 DNA

此技能可将 URL 转化为两个文件:

  • ./{domain}.md — 供人阅读,包含两个部分:
    • Design Map — 实用设计标记(颜色、字体比例、间距、圆角、阴影、网格)
    • Taste DNA — 3-4 条鲜明的设计取舍(触发因素 → 决策 → 原因 → 证据)
  • ./{domain}.json — 结构化数据,包含相同内容,采用机器可解析的格式,供下游工具(Cursor、Windsurf、设计系统)使用。

此流程会拒绝“简洁现代”这类泛泛描述。完成后的 taste.md 应读起来像一位资深设计师在解释:这个页面为什么做出这些特定选择,以及它拒绝了哪些看似合理的替代方案。

何时启用

每当用户想要研究网站设计,并将其整理为未来设计工作的指导时,都应触发此技能。包括以下所有情况:

  • 明确的斜杠命令:/taste <url>
  • 自然语言请求:“分析 vercel.com 的设计”“Stripe 网站为什么这么出色”“提取 linear.app 的设计标记”“给我 are.na 的设计 DNA”
  • 模仿意图:“我想让我的仪表盘有 Linear 的感觉”“按照 的风格为我制作一个落地页”“把这个网站的设计移植到我的项目中”
  • 竞品研究:“比较我们和 的视觉风格”“ 使用了哪些设计惯例”
  • 用户在任何场景下提到 URL,并询问其设计选择、字体排印、颜色、间距、设计理念或“感觉”

只要用户在视觉或设计相关话题中提到 URL,就倾向于启用此技能——Claude 往往不会充分触发技能。如有疑问,就使用它。误调用技能的代价很小;而当此技能本可提供具体且有证据支撑的分析时,却给出泛泛的设计建议,代价就很大。

不要在以下情况启用:“从网站提取数据”(使用抓取技能)、“总结 的内容”(使用 WebFetch)、“部署这个网站”(无关)。

前置条件

此技能要求安装并连接 Playwright MCP 服务(https://playwright.dev/docs/getting-started-mcp)。使用以下命令验证:

claude mcp list | grep playwright

如果看到 playwright: ... - ✓ Connected,说明已就绪。否则,请安装:

claude mcp add playwright -s user -- npx -y @playwright/mcp@latest --isolated

为什么要使用 --isolated:每次运行 /taste 都会从全新的浏览器状态开始,因此 Cookie、登录会话和先前的缓存不会泄漏到被分析的页面中。如果不使用它,当你恰好已登录 Linear 时运行 /taste https://linear.app,分析到的会是应用仪表盘,而不是公开的营销页面——页面选错,设计品味也就错了。

为什么要使用 npx @playwright/mcp@latest(不带 --browser 标志):Playwright 会下载并使用自带的 Chromium(约 100MB,只需下载一次)。这比依赖用户系统中的 Chrome 更具可移植性——它可在未安装 Chrome 的设备上运行,为不同用户提供一致的渲染效果,也绝不会在用户真实的浏览器配置文件中打开窗口。

安装后,用户必须重启 Claude Code,才能让 MCP 工具(mcp__playwright__browser_*)出现在当前会话中。如果运行此技能时 Playwright 不可用,请停止并明确告知用户:“我需要 Playwright MCP 来抓取页面。运行 claude mcp add playwright -s user -- npx -y @playwright/mcp@latest --isolated 并重启 Claude Code,然后再试一次。”

首次运行时,Playwright 可能需要约 30-60 秒,browser_navigate 才会首次返回——这是一次性下载 Chromium 所需的时间。后续运行只需几秒。如果用户想提前下载以避免等待,可以在调用此技能前运行一次 npx playwright install chromium。

工作流程

按顺序遵循以下五个阶段。每个阶段都有明确的成功标准——当前阶段未产出下一阶段所需内容之前,不要进入下一阶段。

阶段 0 — 解析 URL 并确定导出目标

步骤 1 — URL

从用户的消息中提取 URL。接受以下形式:

  • /taste https://linear.app
  • “analyze the design of vercel.com”(如果缺少 https://,则补上)
  • 提示中的任意位置出现的裸 URL

如果用户没有提供 URL,请询问。如果用户提供的是文件路径或明显不是 URL 的内容,请询问他们指的是否是托管页面。在获得有效 URL 之前,不要继续。

导航前,先解析常见的简写形式:linear.app → https://linear.app,https://www.stripe.com 可以保持原样。

步骤 2 — 提取域名用于命名文件

从 URL 中提取主机名,并去掉任何 www. 前缀。例如:

  • https://linear.app → linear.app
  • https://www.stripe.com → stripe.com
  • https://vercel.com/home → vercel.com

将其存为 {domain}。所有输出文件都将以此命名:{domain}.md、{domain}.json 以及任何导出文件。切勿使用通用名称 taste.md — 用户在同一目录中对多个网站运行此技能时,该名称会冲突。

步骤 3 — 导出目标 + 抓取范围

如果用户已在消息中同时指定导出目标和抓取范围,则完全跳过此问题。如果缺少其中任一项,请在一条消息中一次性询问:

“开始前有两个简短问题:

导出目标 — 你正在使用哪个工具?

 1  Cursor          → .cursor/rules/{domain}-taste.mdc
 2  Windsurf        → .windsurf/rules/{domain}-taste.md
 3  Claude Code     → CLAUDE.md(追加 Design Taste 部分)
 4  GitHub Copilot  → .github/copilot-instructions.md(追加)
 5  Bolt            → .bolt/prompt
 6  Antigravity     → GEMINI.md
 7  v0 by Vercel    → taste-tokens.css + instructions
 8  Figma Make      → taste-figma.css + instructions
 9  Lovable         → 输出可粘贴到 Project Knowledge 的文本
10  跳过            → 仅保留 {domain}.md + {domain}.json

抓取范围 — 仅此页面,还是浏览 2–3 个链接页面?

 1  仅此页面       → 更快,专注于你提供的页面
 2  浏览链接页面 → 我会访问 2–3 个导航页面并合并数据
```”

将答案存为 {exportTarget} 和 {crawlScope}。默认值:{exportTarget} = "skip",{crawlScope} = "single"。不要再次询问。

阶段 1 — 捕获页面数据(Playwright MCP)

按顺序执行以下步骤。如果任何步骤出错,请停止整个流程并向用户报告错误 — 不要在数据不完整的情况下悄然继续。

  1. 调整视口大小至 1440×900,确保每次运行的测量结果一致:

    mcp__playwright__browser_resize  width=1440  height=900
    
  2. 导航至该 URL:

    mcp__playwright__browser_navigate  url=<the URL>
    
  3. 稍作等待,让客户端完成水合。对于大型 SPA(figma.com、notion.so),在 domcontentloaded 后需要等待几秒钟,才能渲染实际内容。使用:

    mcp__playwright__browser_wait_for  time=3
    

    如果 3 秒后页面快照看起来仍是加载骨架屏,再等待 3 秒。如果之后仍是骨架屏,请在最终输出中注明(“页面可能未能完整渲染;部分测量值为近似值”)。

  4. 截取两张屏幕截图 — 先截取视口,再截取整页:

    4a. 视口截图(1440×900,不缩放 — 这是步骤 1 的主要视觉参考):

    mcp__playwright__browser_take_screenshot  type=jpeg  filename={domain}-viewport.jpeg
    

    4b. 有条件地截取整页截图 — 首先检查页面高度:

    mcp__playwright__browser_evaluate  function=() => document.documentElement.scrollHeight
    
    • 如果高度不超过视口高度的 6 倍(在 1440×900 分辨率下不超过 5400px):截取常规整页截图:
      mcp__playwright__browser_take_screenshot  fullPage=true  type=jpeg  filename={domain}-fullpage.jpeg
      
    • 如果高度超过视口高度的 6 倍:跳过整页截图(页面太长,会浪费 token)。改为截取两个指定位置的视口截图:
      // 页面中部(滚动 50%)
      mcp__playwright__browser_evaluate  function=() => window.scrollTo(0, document.documentElement.scrollHeight * 0.5)
      mcp__playwright__browser_take_screenshot  type=jpeg  filename={domain}-mid.jpeg
      // 页脚
      mcp__playwright__browser_evaluate  function=() => window.scrollTo(0, document.documentElement.scrollHeight)
      mcp__playwright__browser_take_screenshot  type=jpeg  filename={domain}-footer.jpeg
      // 滚回顶部
      mcp__playwright__browser_evaluate  function=() => window.scrollTo(0, 0)
      

    在步骤 1 中,将视口截图用作主要视觉参考——它展现了设计师希望用户看到的第一印象。使用整页截图或中部+页脚截图,核实页面较下方才出现的样式(页脚排版、后续版块的颜色变化等)。与 PNG 相比,JPEG 能减少 token 消耗。

  5. 运行 DOM 提取器。读取 references/extract.js,并将其完整内容作为 function 参数传入:

    mcp__playwright__browser_evaluate  function=<contents of references/extract.js>
    

    工具会返回一个 JSON 对象。将其暂存为 domData,以便在步骤 1 中使用。

6.(可选清理)浏览器会在会话剩余时间内保持打开。除非用户要求,否则无需关闭。

多页面采集(仅当 {crawlScope} 为 "multi" 时):

采集完主要页面后,提取导航链接,并访问同一网站中最多 2 个其他页面。

6a. 提取导航链接,从已加载的主要页面中获取:

(function() {
  const links = [];
  const seen = new Set([location.pathname]);
  const skip = /\/(login|logout|signup|sign-in|register|auth|account|checkout|cart|password|reset)\b/i;
  document.querySelectorAll('nav a, header a, [role="navigation"] a').forEach(a => {
    try {
      const u = new URL(a.href);
      if (u.hostname !== location.hostname) return;
      if (skip.test(u.pathname)) return;
      if (seen.has(u.pathname)) return;
      if (u.pathname === '/' && location.pathname !== '/') return;
      seen.add(u.pathname);
      links.push({ href: u.origin + u.pathname, text: (a.innerText || a.textContent).trim().slice(0, 40) });
    } catch(e) {}
  });
  return links.slice(0, 6);
})()

6b. 选择 2 个页面,从返回列表中挑选。优先选择:

  • 路径较短的页面(/product 优于 /product/features/detail)
  • 版块名称不同的页面(Product、Community、Pricing、Docs,而非同一版块下仅 slug 不同的页面)
  • 如果已采集根路径 /,则避免再次选择

6c. 对每个其他页面,执行较精简的采集流程(导航 → 等待 3s → 仅截取视口截图 → DOM 提取器)。第 2 至第 3 页无需截取整页/中部/页脚截图——视口截图足以确认设计是否一致,DOM 提取器会采集整个页面。截图命名为 {domain}-viewport-2.jpeg、{domain}-viewport-3.jpeg。将每个页面的数据保存为 pages[1]、pages[2](pages[0] 为主要 URL)。

如果链接页面加载失败或受到阻止,则静默跳过,并在第 6 阶段的报告中注明。

6d. 在阶段 2 之前合并数据。合并所有页面的颜色候选项(取并集)和排版数据(取并集)。同一值出现在 2 个或更多页面上时,即为系统信号——请标记。只在单个页面上出现的值属于局部值——仍需记录,但降低其权重。

在步骤 1–3 中,始终说明分析了多少个页面(“在 3 个页面中:……”),并区分系统样式与局部样式。多个页面达成一致,是判断设计偏好最有力的依据。

阶段 1 的成功标准:至少有一张截图,并且主要页面的 domData JSON 已填充 colors、typography、layout、effects、cards、images、spacingSamples、sectionGaps 和 grid 字段。如果其中任一字段完全为空,且截图中显示了实际内容,则说明提取器需要改进——请注明此情况并继续。

数据不完整时的处理方式:如果 domData.errors 不为空,说明提取器部分失败。在步骤 1 中,将受影响的类别标记为 ~approx (extractor section failed),并依据截图测量这些类别。在阶段 6 的报告中,将失败的部分列为注意事项。

阶段 2 — 运行 4 步分析

截图是事实依据。 在阅读任何参考文件之前:视口截图展示了人们实际看到的内容。DOM 数据提供精确数值。两者冲突时,以截图为准。DOM 中出现、但覆盖可见表面面积 <5% 的颜色属于装饰色——不要将其列为品牌色。截图中未出现的分区分隔线,无论 DOM 报告什么,都视为不存在。无法察觉的阴影(≤3% 不透明度)是 CSS 伪影,不是设计决策。

references/ 中的四个参考文件包含各步骤的完整提示词。到达每一步时再阅读对应文件(不要一次性预读全部四个文件——这些步骤是刻意按顺序设计的,前面的步骤不需要后续步骤的说明)。

每个步骤:

  1. 阅读对应的参考文件。
  2. 在你自己的回复中生成该文件要求的输出。
  3. 使用参考文件指定的标记行作为输出开头(例如,### Step 1 Output — Measurements)。
  4. 下一步会将你之前的输出作为输入——将它们保留在对话中,不要把它们概括掉。
步骤 1 — 测量
  • 阅读 references/step1-measure.md
  • 输入:domData(browser_evaluate 返回的 JSON)+ 截图
  • 产出:20 类测量数据,每个数值都要标明具体的 px / hex / 比率
步骤 2 — 模式
  • 阅读 references/step2-pattern.md
  • 输入:步骤 1 的输出
  • 产出:5-8 个系统性模式,每个都包含 Pattern / Evidence / Design Goal
步骤 3 — 品味
  • 阅读 references/step3-taste.md
  • 输入:步骤 1 + 步骤 2 的输出
  • 产出:4 条品味原则(每条都包含 Trigger / Decision / Reason / Evidence),至少包含一项克制取舍
步骤 4 — 观察者
  • 阅读 references/step4-observer.md
  • 输入:步骤 1 + 2 + 3 的输出 + 原始 URL(必须将其填入 JSON 的 source 字段)
  • 产出:一个带围栏的 json 代码块,后接 Markdown 设计地图 + 品味 DNA
阶段 3 — 写入输出文件

步骤 4 的回复包含两种格式。提取它们:

  1. JSON:找到步骤 4 输出中的第一个 json 围栏代码块。解析它(必须是有效 JSON——如果不是,说明步骤 4 失败;指出解析错误并重新运行步骤 4)。
  2. Markdown:取步骤 4 输出中 JSON 代码块结束后的全部内容。移除开头的空白字符。

然后使用你在阶段 0 中提取的 {domain},将两个文件写入当前工作目录(如需确认目录位置,可使用 pwd):

  • ./{domain}.md — Markdown 部分
  • ./{domain}.json — JSON,使用 2 个空格缩进美化输出

如果任一文件已存在,直接覆盖,无需询问。用户对同一网站重复调用此技能时,期望最新分析结果覆盖旧结果。

阶段 4 — 自我审查(反空话检查)

通过 Bash 工具运行此 grep——不要凭记忆检查:

grep -icE 'clean|modern|sleek|visually appealing|user-friendly|intuitive|seamless|\belegant\b|minimalist|polished|refined|sophisticated|delightful|stunning|\bbeautiful\b|\bpremium\b' ./{domain}.md

如果计数为 0,则文件通过检查。如果 >0,显示命中的行:

grep -inE 'clean|modern|sleek|visually appealing|user-friendly|intuitive|seamless|\belegant\b|minimalist|polished|refined|sophisticated|delightful|stunning|\bbeautiful\b|\bpremium\b' ./{domain}.md

对于每个命中:

  • 出现在引用的反衬描述中(“他们本可以选择‘简洁现代’的风格,但却……”)——没问题,计为通过。
  • 用作对此设计的正面描述——属于空话。编辑相应原则,重新保存,并重新运行 grep,直到计数为 0。

还要通过 Bash 验证:

grep -c "Design Map\|Taste DNA" ./{domain}.md

必须返回 2。如果小于 2,说明缺少某个章节——指出缺失章节并重新运行步骤 4。

验证 JSON:

python3 -m json.tool ./{domain}.json > /dev/null && echo "valid" || echo "INVALID"

如果任何检查失败,先修复并重新运行,再交付。

阶段 5 — 导出为你的构建工具

你已在阶段 0 记录了 {exportTarget}。不要再次询问。

如果 {exportTarget} 是 "skip",直接进入阶段 6。

如果 {exportTarget} 是 "all",生成所有基于文件的格式(选项 1–8)。

否则,根据 {exportTarget} 确定导出内容。接受自然语言的同义说法:"cursor"、"windsurf"、"claude" / "claude code"、"copilot"、"bolt"、"antigravity" / "gemini"、"v0"、"figma" / "figma make"、"lovable"。

阅读 references/export-formats.md,了解每个目标对应的确切文件路径、frontmatter 结构和内容规范。所有格式都基于 {domain}.json 生成,并且必须遵循相同的 Anti-Slop 规则——避免模糊的感觉描述,引用具体的 px/hex。

阶段 6 — 报告

向用户输出以下内容(替换实际的 {domain}、行数和字节数):

✓ Wrote ./{domain}.md (<line-count> lines) and ./{domain}.json (<byte-count> bytes)
[if export file(s) written]: ✓ Also wrote <path(s)>

  Sharpest principle: "<name of the strongest taste principle>"
  → <one-sentence quote of its Decision>

  Open {domain}.md to read the full Design Map + Taste DNA.

保持简洁。让文件说明一切。

错误处理

失败情况响应
未安装/未连接 Playwright MCP使用上方“先决条件”部分中的准确安装命令停止操作。不要尝试回退到 WebFetch——截图对步骤 1 至关重要。
URL 无法访问 / 404 / DNS 失败告知用户页面未能加载。不要基于错误页面提交分析。
Cloudflare / 机器人检测拦截截图会显示“verify you are human”页面。在步骤 1 中检测到此情况(大片空白,只有一个标有“Verify”的按钮)。告知用户该网站阻止自动访问;如果用户想要截图,建议他们在自己的浏览器中手动打开 URL,或尝试同一域名下的其他页面。
SPA 等待后仍在渲染等待两次,每次 3 秒后,使用当前已加载的内容继续。向报告添加一行说明:“页面可能仍在进行 hydration;部分测量值为近似值。”
用户提供的是文件路径,而非 URL询问用户是否指托管版本。不要尝试打开本地文件——此技能适用于在线页面。
用户提供的 URL 需要登录检测登录页面(含密码输入框的表单)。告知用户此技能不处理需要身份验证的页面,并建议改用公开的营销页面。
步骤 4 返回格式错误的 JSON指出具体解析错误后,重新运行一次步骤 4。如果再次失败,将原始输出保存为 ./{domain}-raw.md,并告知用户手动检查。

关于理念的说明(阅读一次,牢记,然后基本上放下)

此技能建立在一个鲜明的观点之上:设计令牌对 AI Agent 毫无用处。令牌只会说“间距是 8px”;品味则会说“间距是 8px,因为设计师选择了易读的节奏,而非数据密度;在 1× 缩放下,8px 是仍能营造明确设计感的最小单位”。正是这种原因,才能让同一个 Agent 为不同的页面生成出色设计,而不是只会照抄数字。

references/ 中的四个提示词,是基于 Gemini 的生产验证流水线的移植版本。早期版本中最大的失败模式是输出内容泛泛而谈——大段诸如“此设计采用简洁现代的美学风格,搭配直观的导航”的文字,却不包含任何有用信息。Anti-Slop 检查(禁用短语、强制要求说明克制取舍、证据要求)之所以存在,是因为每删除一条薄弱原则,都抵得上新增十条证据充分的原则。

如果不确定某条品味原则是否有价值,就问自己:“如果我从未见过这个特定网站,还能写出这条原则吗?”如果可以,那就是废话。删掉它。

评论

支持 Markdown