mcpField
S
screenshots

screenshots

github.com/steveclarke营销与增长3678 次安装1 天前更新
代码仓库

关于 screenshots

screenshots 是一项使用 Playwright 为应用生成营销截图的技能,适用于产品展示、社交媒体和文档素材制作。它支持以 2 倍 HiDPI 分辨率捕获页面,并指导从应用路由中发掘截图内容。

主要功能

  1. 01使用 Playwright 捕获应用页面
  2. 02以 2 倍 HiDPI 分辨率截图
  3. 03分析路由以发现页面
  4. 04支持登录后截图
  5. 05提供截图故障排查建议

适用场景

  1. 01制作产品发布展示图
  2. 02为社交媒体准备功能截图
  3. 03生成落地页营销素材
  4. 04制作界面文档参考图

安装

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

$npx skills add https://github.com/steveclarke/dotfiles --skill screenshots

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

详细介绍

直接使用 Playwright 为应用生成营销级截图。截图将以真正的 HiDPI(2 倍视网膜屏)分辨率捕获,使用 deviceScaleFactor: 2。

前置条件

必须能使用 Playwright。检查是否已安装:

npx playwright --version 2>/dev/null || npm ls playwright 2>/dev/null | grep playwright

如果未找到,请告知用户:

必须安装 Playwright。请使用以下命令安装:npm install -D playwright 或 npm install -D @playwright/test

第 1 步:确定应用 URL

如果提供了 $1,请将其用作应用 URL。

如果未提供 URL:

  1. 查看 package.json 中的脚本,判断开发服务器是否可能正在运行
  2. 使用 AskUserQuestion 询问用户 URL,或询问是否需要协助启动开发服务器

建议的常见默认 URL:

  • http://localhost:3000(Next.js、Create React App、Rails)
  • http://localhost:5173(Vite)
  • http://localhost:4000(Phoenix)
  • http://localhost:8080(Vue CLI、通用)

第 2 步:收集需求

使用 AskUserQuestion 提出以下问题:

问题 1:截图数量

  • 标题:「数量」
  • 问题:「您需要多少张截图?」
  • 选项:
    • 「3-5」— 快速展示主要功能
    • 「5-10」— 全面展示各项功能
    • 「10+」— 完整的营销素材套件

问题 2:用途

  • 标题:「用途」
  • 问题:「这些截图将用于什么场景?」
  • 选项:
    • 「Product Hunt」— 主视觉截图和功能亮点
    • 「社交媒体」— 吸引眼球的功能演示
    • 「落地页」— 营销版块和产品优势
    • 「文档」— UI 参考和教程

问题 3:身份验证

  • 标题:「身份验证」
  • 问题:「访问您想截图的功能是否需要登录?」
  • 选项:
    • 「无需登录」— 仅限公开页面
    • 「需要,我会提供凭据」— 需要先登录

如果用户选择「需要,我会提供凭据」,请追问:

  • 「登录页面 URL 是什么?」(例如:/login、/sign-in)
  • 「电子邮件/用户名是什么?」
  • 「密码是什么?」

脚本会使用 Playwright 的智能定位器自动检测登录表单字段。

第 3 步:分析代码库,寻找功能

全面探索代码库,了解应用并找出截图机会。

3.1:先阅读文档

务必先阅读以下文件,了解应用的功能:

  1. README.md(以及子目录中的任何 README 文件)— 通读完整 README,了解:

    • 应用的用途及其解决的问题
    • 主要功能和能力
    • 已有文档中记录的截图或功能说明
  2. CHANGELOG.md 或 HISTORY.md — 值得重点展示的近期功能

  3. docs/ 目录 — 任何其他功能文档

3.2:分析路由,查找页面

阅读路由配置,找出所有可用页面:

框架要阅读的文件要查找的内容
Next.js App Routerapp/ 目录结构每个包含 page.tsx 的文件夹都是一个路由
Next.js Pages Routerpages/ 目录每个文件都是一个路由
Railsconfig/routes.rb通读整个文件,查找所有路由
React Router搜索 createBrowserRouter 或 <Route包含路径的路由定义
Vue Routersrc/router/index.js 或 router.js带有路径定义的路由数组
SvelteKitsrc/routes/ 目录每个包含 +page.svelte 的文件夹都是一个路由
Remixapp/routes/ 目录基于文件的路由
Laravelroutes/web.php路由定义
Djangourls.py 文件URL 模式
Express搜索 app.get、router.get路由处理程序

重要:请实际阅读这些文件,不要只检查它们是否存在。路由定义会告诉您哪些页面可供截图。

3.3:识别关键组件

查找代表可截图功能的组件:

  • 仪表板组件
  • 具有独特 UI 的功能板块
  • 表单和交互式输入
  • 数据可视化(图表、曲线图、表格)
  • 模态框和对话框
  • 导航和侧边栏
  • 设置面板
  • 用户资料板块
3.4:检查营销素材

查找现有营销内容,了解关键功能:

  • 落地页组件(通常位于 components/landing/ 或 components/marketing/)
  • 功能列表组件
  • 定价表格
  • 用户评价板块
3.5:构建功能列表

创建一份全面的已发现功能列表,包含:

  • 功能名称(来自 README 或组件名称)
  • URL 路径(来自路由)
  • 要聚焦的 CSS 选择器(来自组件结构)
  • 所需 UI 状态(已登录、已填充数据、模态框已打开、已选择特定选项卡)

第 4 步:与用户一起规划截图

向用户展示已发现的功能,并请他们确认或修改列表。

使用 AskUserQuestion:

  • 标题:"功能"
  • 问题:"我在你的代码库中发现了这些功能。你想截取哪些功能?"
  • 选项:列出发现的 3-4 个关键功能,以及“让我选择特定功能”

如果用户想选择特定功能,请继续提问,明确具体要截取的内容。

第 5 步:创建截图目录

mkdir -p screenshots

第 6 步:生成并运行 Playwright 脚本

创建一个使用 Playwright 并设置适当 HiDPI 参数的 Node.js 脚本。脚本应:

  1. 使用 deviceScaleFactor: 2,获得真正的 Retina 分辨率
  2. 将视口设为 1440x900(生成 2880x1800 像素的图像)
  3. 如果提供了凭据,则处理身份验证
  4. 导航至每个页面并截取屏幕截图
脚本模板

将此脚本写入临时文件(例如 screenshot-script.mjs)并执行:

import { chromium } from 'playwright';

const BASE_URL = '[APP_URL]';
const SCREENSHOTS_DIR = './screenshots';

// Authentication config (if needed)
const AUTH = {
  needed: [true|false],
  loginUrl: '[LOGIN_URL]',
  email: '[EMAIL]',
  password: '[PASSWORD]',
};

// Screenshots to capture
const SCREENSHOTS = [
  { name: '01-feature-name', url: '/path', waitFor: '[optional-selector]' },
  { name: '02-another-feature', url: '/another-path' },
  // ... add all planned screenshots
];

async function main() {
  const browser = await chromium.launch();

  // Create context with HiDPI settings
  const context = await browser.newContext({
    viewport: { width: 1440, height: 900 },
    deviceScaleFactor: 2,  // This is the key for true retina screenshots
  });

  const page = await context.newPage();

  // Handle authentication if needed
  if (AUTH.needed) {
    console.log('Logging in...');
    await page.goto(AUTH.loginUrl);

    // Smart login: try multiple common patterns for email/username field
    const emailField = page.locator([
      'input[type="email"]',
      'input[name="email"]',
      'input[id="email"]',
      'input[placeholder*="email" i]',
      'input[name="username"]',
      'input[id="username"]',
      'input[type="text"]',
    ].join(', ')).first();
    await emailField.fill(AUTH.email);

    // Smart login: try multiple common patterns for password field
    const passwordField = page.locator([
      'input[type="password"]',
      'input[name="password"]',
      'input[id="password"]',
    ].join(', ')).first();
    await passwordField.fill(AUTH.password);

    // Smart login: try multiple common patterns for submit button
    const submitButton = page.locator([
      'button[type="submit"]',
      'input[type="submit"]',
      'button:has-text("Sign in")',
      'button:has-text("Log in")',
      'button:has-text("Login")',
      'button:has-text("Submit")',
    ].join(', ')).first();
    await submitButton.click();

    await page.waitForLoadState('networkidle');
    console.log('Login complete');
  }

  // Capture each screenshot
  for (const shot of SCREENSHOTS) {
    console.log(`Capturing: ${shot.name}`);
    await page.goto(`${BASE_URL}${shot.url}`);
    await page.waitForLoadState('networkidle');

    // Optional: wait for specific element
    if (shot.waitFor) {
      await page.waitForSelector(shot.waitFor);
    }

    // Optional: perform actions before screenshot
    if (shot.actions) {
      for (const action of shot.actions) {
        if (action.click) await page.click(action.click);
        if (action.fill) await page.fill(action.fill.selector, action.fill.value);
        if (action.wait) await page.waitForTimeout(action.wait);
      }
    }

    await page.screenshot({
      path: `${SCREENSHOTS_DIR}/${shot.name}.png`,
      fullPage: shot.fullPage || false,
    });
    console.log(`  Saved: ${shot.name}.png`);
  }

  await browser.close();
  console.log('Done!');
}

main().catch(console.error);
运行脚本
node screenshot-script.mjs

运行后,清理临时脚本:

rm screenshot-script.mjs

第 7 步:高级截图选项

聚焦元素截图

若要截取特定元素,而不是整个视口:

const element = await page.locator('[CSS_SELECTOR]');
await element.screenshot({ path: `${SCREENSHOTS_DIR}/element.png` });
整页截图

对于可滚动内容,截取整个页面:

await page.screenshot({
  path: `${SCREENSHOTS_DIR}/full-page.png`,
  fullPage: true
});
等待动画结束

如果页面有动画,请等待动画结束:

await page.waitForTimeout(500); // Wait 500ms for animations
截图前点击元素

若要截取模态框、下拉菜单或悬停状态:

await page.click('button.open-modal');
await page.waitForSelector('.modal-content');
await page.screenshot({ path: `${SCREENSHOTS_DIR}/modal.png` });
深色模式截图

如果应用支持深色模式:

// Set dark mode preference
const context = await browser.newContext({
  viewport: { width: 1440, height: 900 },
  deviceScaleFactor: 2,
  colorScheme: 'dark',
});

第 8 步:文件命名规范

使用描述性 kebab-case 文件名,并添加数字前缀以便排序:

功能文件名
仪表板概览01-dashboard-overview.png
链接管理02-link-inbox.png
版本编辑器03-edition-editor.png
分析04-analytics.png
设置05-settings.png

第 9 步:验证并总结

截取所有屏幕截图后,验证结果:

ls -la screenshots/*.png
sips -g pixelWidth -g pixelHeight screenshots/*.png 2>/dev/null || file screenshots/*.png

向用户提供总结:

  1. 列出所有生成文件及其路径
  2. 确认分辨率(在 1440x900 视口下,2x Retina 分辨率应为 2880x1800)
  3. 说明文件总大小
  4. 建议后续操作

输出示例:

Generated 5 marketing screenshots:

screenshots/
├── 01-dashboard-overview.png (1.2 MB, 2880x1800 @ 2x)
├── 02-link-inbox.png (456 KB, 2880x1800 @ 2x)
├── 03-edition-editor.png (890 KB, 2880x1800 @ 2x)
├── 04-analytics.png (567 KB, 2880x1800 @ 2x)
└── 05-settings.png (234 KB, 2880x1800 @ 2x)

All screenshots are true retina-quality (2x deviceScaleFactor) and ready for marketing use.

错误处理

  • 未找到 Playwright:建议运行 npm install -D playwright
  • 页面未加载:检查开发服务器是否正在运行,并建议启动它
  • 登录失败:智能定位器会尝试常见模式,但可能无法处理不常见的登录表单。如果登录失败,请分析登录页面的 HTML,找到正确的选择器并自定义脚本。
  • 未找到元素:验证 CSS 选择器,并提出改为截取整页
  • 截图失败:检查磁盘空间,并确认对截图目录具有写入权限

获得最佳效果的提示

  1. 保持 UI 状态整洁:使用演示数据或种子数据呈现逼真的内容
  2. 保持尺寸一致:所有截图使用相同的视口
  3. 等待内容加载:使用 waitForLoadState('networkidle') 确保所有内容都已加载
  4. 隐藏开发工具:确保没有显示浏览器扩展或开发叠加层
  5. 深色模式变体:如果支持,可考虑同时截取浅色和深色模式的截图

评论

支持 Markdown