screenshots

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Screenshots

截图

Generate marketing-quality screenshots of your app using Playwright directly. Screenshots are captured at true HiDPI (2x retina) resolution using
deviceScaleFactor: 2
.
直接使用Playwright生成达到营销级画质的应用截图。通过
deviceScaleFactor: 2
参数捕获真正的HiDPI(2倍视网膜)分辨率截图。

When to Use This Skill

何时使用该技能

Use this skill when:
  • User wants to create screenshots for Product Hunt
  • Creating screenshots for social media
  • Generating images for landing pages
  • Creating documentation screenshots
  • User requests marketing-quality app screenshots
在以下场景使用本技能:
  • 用户需要为Product Hunt创建截图
  • 为社交媒体制作截图
  • 为落地页生成图片素材
  • 创建文档用截图
  • 用户要求生成营销级画质的应用截图

Prerequisites

前置条件

Playwright must be available. Check for it:
bash
npx playwright --version 2>/dev/null || npm ls playwright 2>/dev/null | grep playwright
If not found, inform the user:
Playwright is required. Install it with:
npm install -D playwright
or
npm install -D @playwright/test
必须已安装Playwright。可以通过以下命令检查:
bash
npx playwright --version 2>/dev/null || npm ls playwright 2>/dev/null | grep playwright
如果未找到,请告知用户:
需要安装Playwright。执行以下命令安装:
npm install -D playwright
npm install -D @playwright/test

Step 1: Determine App URL

步骤1:确定应用URL

If
$1
is provided, use it as the app URL.
If no URL is provided:
  1. Check if a dev server is likely running by looking for
    package.json
    scripts
  2. Use
    AskUserQuestion
    to ask the user for the URL or offer to help start the dev server
Common default URLs to suggest:
  • http://localhost:3000
    (Next.js, Create React App, Rails)
  • http://localhost:5173
    (Vite)
  • http://localhost:4000
    (Phoenix)
  • http://localhost:8080
    (Vue CLI, generic)
如果提供了
$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、通用型)

Step 2: Gather Requirements

步骤2:收集需求

Use
AskUserQuestion
with the following questions:
Question 1: Screenshot count
  • Header: "Count"
  • Question: "How many screenshots do you need?"
  • Options:
    • "3-5" - Quick set of key features
    • "5-10" - Comprehensive feature coverage
    • "10+" - Full marketing suite
Question 2: Purpose
  • Header: "Purpose"
  • Question: "What will these screenshots be used for?"
  • Options:
    • "Product Hunt" - Hero shots and feature highlights
    • "Social media" - Eye-catching feature demos
    • "Landing page" - Marketing sections and benefits
    • "Documentation" - UI reference and tutorials
Question 3: Authentication
  • Header: "Auth"
  • Question: "Does the app require login to access the features you want to screenshot?"
  • Options:
    • "No login needed" - Public pages only
    • "Yes, I'll provide credentials" - Need to log in first
If user selects "Yes, I'll provide credentials", ask follow-up questions:
  • "What is the login page URL?" (e.g.,
    /login
    ,
    /sign-in
    )
  • "What is the email/username?"
  • "What is the password?"
The script will automatically detect login form fields using Playwright's smart locators.
使用
AskUserQuestion
工具询问以下问题:
问题1:截图数量
  • 标题:"数量"
  • 问题:"你需要多少张截图?"
  • 选项:
    • "3-5张" - 快速获取核心功能截图集
    • "5-10张" - 全面覆盖功能点
    • "10张以上" - 完整营销素材包
问题2:使用场景
  • 标题:"用途"
  • 问题:"这些截图将用于什么场景?"
  • 选项:
    • "Product Hunt" - 首屏展示图与功能亮点图
    • "社交媒体" - 吸睛的功能演示图
    • "落地页" - 营销板块与优势展示图
    • "文档" - UI参考图与教程配图
问题3:身份验证
  • 标题:"认证"
  • 问题:"你要截图的功能是否需要登录才能访问?"
  • 选项:
    • "无需登录" - 仅公开页面
    • "需要,我会提供凭据" - 需先完成登录
如果用户选择"需要,我会提供凭据",继续询问以下补充问题:
  • "登录页面的URL是什么?"(例如:
    /login
    /sign-in
  • "邮箱/用户名是什么?"
  • "密码是什么?"
脚本会通过Playwright的智能定位器自动检测登录表单字段。

Step 3: Analyze Codebase for Features

步骤3:分析代码库以挖掘可截图功能

Thoroughly explore the codebase to understand the app and identify screenshot opportunities.
全面探索代码库,了解应用功能并确定适合截图的内容。

3.1: Read Documentation First

3.1:优先阅读文档

Always start by reading these files to understand what the app does:
  1. README.md (and any README files in subdirectories) - Read the full README to understand:
    • What the app is and what problem it solves
    • Key features and capabilities
    • Screenshots or feature descriptions already documented
  2. CHANGELOG.md or HISTORY.md - Recent features worth highlighting
  3. docs/ directory - Any additional documentation about features
务必先阅读以下文件,了解应用的核心功能:
  1. README.md(以及子目录中的所有README文件)- 完整阅读README以了解:
    • 应用的定位与解决的问题
    • 核心功能与能力
    • 已有的截图或功能描述
  2. CHANGELOG.mdHISTORY.md - 值得重点展示的近期新增功能
  3. docs/ 目录 - 任何关于功能的补充文档

3.2: Analyze Routes to Find Pages

3.2:分析路由以发现页面

Read the routing configuration to discover all available pages:
FrameworkFile to ReadWhat to Look For
Next.js App Router
app/
directory structure
Each folder with
page.tsx
is a route
Next.js Pages Router
pages/
directory
Each file is a route
Rails
config/routes.rb
Read the entire file for all routes
React RouterSearch for
createBrowserRouter
or
<Route
Route definitions with paths
Vue Router
src/router/index.js
or
router.js
Routes array with path definitions
SvelteKit
src/routes/
directory
Each folder with
+page.svelte
is a route
Remix
app/routes/
directory
File-based routing
Laravel
routes/web.php
Route definitions
Django
urls.py
files
URL patterns
ExpressSearch for
app.get
,
router.get
Route handlers
Important: Actually read these files, don't just check if they exist. The route definitions tell you what pages are available for screenshots.
读取路由配置文件,找出所有可用页面:
框架需读取的文件关注内容
Next.js App Router
app/
目录结构
每个包含
page.tsx
的文件夹对应一个路由
Next.js Pages Router
pages/
目录
每个文件对应一个路由
Rails
config/routes.rb
通读整个文件获取所有路由
React Router搜索
createBrowserRouter
<Route
包含路径的路由定义
Vue Router
src/router/index.js
router.js
包含路径定义的路由数组
SvelteKit
src/routes/
目录
每个包含
+page.svelte
的文件夹对应一个路由
Remix
app/routes/
目录
基于文件的路由结构
Laravel
routes/web.php
路由定义
Django
urls.py
文件
URL模式
Express搜索
app.get
router.get
路由处理器
重要提示:务必实际阅读这些文件,不要仅检查文件是否存在。路由定义会告诉你哪些页面适合截图。

3.3: Identify Key Components

3.3:识别核心组件

Look for components that represent screenshottable features:
  • Dashboard components
  • Feature sections with distinct UI
  • Forms and interactive inputs
  • Data visualizations (charts, graphs, tables)
  • Modals and dialogs
  • Navigation and sidebars
  • Settings panels
  • User profile sections
寻找代表可截图功能的组件:
  • 仪表盘组件
  • 具有独特UI的功能板块
  • 表单与交互式输入组件
  • 数据可视化(图表、图形、表格)
  • 模态框与对话框
  • 导航栏与侧边栏
  • 设置面板
  • 用户资料板块

3.4: Check for Marketing Assets

3.4:查找营销素材

Look for existing marketing content that hints at key features:
  • Landing page components (often in
    components/landing/
    or
    components/marketing/
    )
  • Feature list components
  • Pricing tables
  • Testimonial sections
寻找已有的营销内容,从中挖掘核心功能线索:
  • 落地页组件(通常位于
    components/landing/
    components/marketing/
    目录)
  • 功能列表组件
  • 定价表格
  • 客户评价板块

3.5: Build Feature List

3.5:构建功能列表

Create a comprehensive list of discovered features with:
  • Feature name (from README or component name)
  • URL path (from routes)
  • CSS selector to focus on (from component structure)
  • Required UI state (logged in, data populated, modal open, specific tab selected)
创建一份完整的可截图功能列表,包含:
  • 功能名称(来自README或组件名)
  • URL路径(来自路由)
  • 需聚焦的CSS选择器(来自组件结构)
  • 所需的UI状态(已登录、数据已填充、模态框已打开、特定标签页已选中)

Step 4: Plan Screenshots with User

步骤4:与用户确认截图方案

Present the discovered features to the user and ask them to confirm or modify the list.
Use
AskUserQuestion
:
  • Header: "Features"
  • Question: "I found these features in your codebase. Which would you like to screenshot?"
  • Options: List 3-4 key features discovered, plus "Let me pick specific ones"
If user wants specific ones, ask follow-up questions to clarify exactly what to capture.
将挖掘到的功能展示给用户,请求确认或修改列表。
使用
AskUserQuestion
工具:
  • 标题:"功能"
  • 问题:"我在代码库中发现了以下功能,你想对哪些功能进行截图?"
  • 选项:列出3-4个挖掘到的核心功能,再加上"让我选择特定功能"
如果用户选择"让我选择特定功能",继续询问以明确具体需要截图的内容。

Step 5: Create Screenshots Directory

步骤5:创建截图目录

bash
mkdir -p screenshots
bash
mkdir -p screenshots

Step 6: Generate and Run Playwright Script

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

Create a Node.js script that uses Playwright with proper HiDPI settings. The script should:
  1. Use
    deviceScaleFactor: 2
    for true retina resolution
  2. Set viewport to 1440x900 (produces 2880x1800 pixel images)
  3. Handle authentication if credentials were provided
  4. Navigate to each page and capture screenshots
创建一个使用Playwright的Node.js脚本,并配置正确的HiDPI参数。脚本应包含以下功能:
  1. 设置
    deviceScaleFactor: 2
    以实现真正的视网膜分辨率
  2. 将视口设置为1440x900(生成2880x1800像素的图片)
  3. 处理身份验证(如果用户提供了凭据)
  4. 导航至每个页面并捕获截图

Script Template

脚本模板

Write this script to a temporary file (e.g.,
screenshot-script.mjs
) and execute it:
javascript
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);
将以下脚本写入临时文件(例如
screenshot-script.mjs
)并执行:
javascript
import { chromium } from 'playwright';

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

// 认证配置(如需)
const AUTH = {
  needed: [true|false],
  loginUrl: '[LOGIN_URL]',
  email: '[EMAIL]',
  password: '[PASSWORD]',
};

// 需捕获的截图列表
const SCREENSHOTS = [
  { name: '01-feature-name', url: '/path', waitFor: '[optional-selector]' },
  { name: '02-another-feature', url: '/another-path' },
  // ... 添加所有计划截图
];

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

  // 创建带有HiDPI设置的上下文
  const context = await browser.newContext({
    viewport: { width: 1440, height: 900 },
    deviceScaleFactor: 2,  // 这是实现真正视网膜截图的关键参数
  });

  const page = await context.newPage();

  // 如需认证则处理登录流程
  if (AUTH.needed) {
    console.log('正在登录...');
    await page.goto(AUTH.loginUrl);

    // 智能登录:尝试多种常见的邮箱/用户名字段定位方式
    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);

    // 智能登录:尝试多种常见的密码字段定位方式
    const passwordField = page.locator([
      'input[type="password"]',
      'input[name="password"]',
      'input[id="password"]',
    ].join(', ')).first();
    await passwordField.fill(AUTH.password);

    // 智能登录:尝试多种常见的提交按钮定位方式
    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('登录完成');
  }

  // 捕获每张截图
  for (const shot of SCREENSHOTS) {
    console.log(`正在捕获: ${shot.name}`);
    await page.goto(`${BASE_URL}${shot.url}`);
    await page.waitForLoadState('networkidle');

    // 可选:等待特定元素加载完成
    if (shot.waitFor) {
      await page.waitForSelector(shot.waitFor);
    }

    // 可选:在截图前执行操作
    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(`  已保存: ${shot.name}.png`);
  }

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

main().catch(console.error);

Running the Script

运行脚本

bash
node screenshot-script.mjs
After running, clean up the temporary script:
bash
rm screenshot-script.mjs
bash
node screenshot-script.mjs
运行完成后,清理临时脚本:
bash
rm screenshot-script.mjs

Step 7: Advanced Screenshot Options

步骤7:高级截图选项

Element-Focused Screenshots

聚焦元素的截图

To screenshot a specific element instead of the full viewport:
javascript
const element = await page.locator('[CSS_SELECTOR]');
await element.screenshot({ path: `${SCREENSHOTS_DIR}/element.png` });
如需仅截图特定元素而非整个视口:
javascript
const element = await page.locator('[CSS_SELECTOR]');
await element.screenshot({ path: `${SCREENSHOTS_DIR}/element.png` });

Full Page Screenshots

全页面截图

For scrollable content, capture the entire page:
javascript
await page.screenshot({
  path: `${SCREENSHOTS_DIR}/full-page.png`,
  fullPage: true
});
对于可滚动内容,捕获整个页面:
javascript
await page.screenshot({
  path: `${SCREENSHOTS_DIR}/full-page.png`,
  fullPage: true
});

Waiting for Animations

等待动画完成

If the page has animations, wait for them to complete:
javascript
await page.waitForTimeout(500); // Wait 500ms for animations
如果页面包含动画,等待动画结束后再截图:
javascript
await page.waitForTimeout(500); // 等待500毫秒以确保动画完成

Clicking Elements Before Screenshot

截图前点击元素

To capture a modal, dropdown, or hover state:
javascript
await page.click('button.open-modal');
await page.waitForSelector('.modal-content');
await page.screenshot({ path: `${SCREENSHOTS_DIR}/modal.png` });
如需捕获模态框、下拉菜单或悬停状态:
javascript
await page.click('button.open-modal');
await page.waitForSelector('.modal-content');
await page.screenshot({ path: `${SCREENSHOTS_DIR}/modal.png` });

Dark Mode Screenshots

深色模式截图

If the app supports dark mode:
javascript
// Set dark mode preference
const context = await browser.newContext({
  viewport: { width: 1440, height: 900 },
  deviceScaleFactor: 2,
  colorScheme: 'dark',
});
如果应用支持深色模式:
javascript
// 设置深色模式偏好
const context = await browser.newContext({
  viewport: { width: 1440, height: 900 },
  deviceScaleFactor: 2,
  colorScheme: 'dark',
});

Step 8: File Naming Convention

步骤8:文件命名规范

Use descriptive, kebab-case filenames with numeric prefixes for ordering:
FeatureFilename
Dashboard overview
01-dashboard-overview.png
Link management
02-link-inbox.png
Edition editor
03-edition-editor.png
Analytics
04-analytics.png
Settings
05-settings.png
使用描述性的短横线分隔命名(kebab-case),并添加数字前缀以排序:
功能文件名
仪表盘概览
01-dashboard-overview.png
链接管理
02-link-inbox.png
版本编辑器
03-edition-editor.png
数据分析
04-analytics.png
设置页面
05-settings.png

Step 9: Verify and Summarize

步骤9:验证与总结

After capturing all screenshots, verify the results:
bash
ls -la screenshots/*.png
sips -g pixelWidth -g pixelHeight screenshots/*.png 2>/dev/null || file screenshots/*.png
Provide a summary to the user:
  1. List all generated files with their paths
  2. Confirm the resolution (should be 2880x1800 for 2x retina at 1440x900 viewport)
  3. Mention total file sizes
  4. Suggest any follow-up actions
Example output:
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.
捕获所有截图后,验证结果:
bash
ls -la screenshots/*.png
sips -g pixelWidth -g pixelHeight screenshots/*.png 2>/dev/null || file screenshots/*.png
向用户提供总结:
  1. 列出所有生成的文件及其路径
  2. 确认分辨率(1440x900视口下的2倍视网膜截图应为2880x1800)
  3. 提及文件总大小
  4. 建议后续操作
示例输出:
已生成5张营销级截图:

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)

所有截图均为真正的视网膜画质(2倍deviceScaleFactor),可直接用于营销场景。

Error Handling

错误处理

  • Playwright not found: Suggest
    npm install -D playwright
  • Page not loading: Check if the dev server is running, suggest starting it
  • Login failed: The smart locators try common patterns but may fail on unusual login forms. If login fails, analyze the login page HTML to find the correct selectors and customize the script.
  • Element not found: Verify the CSS selector, offer to take a full page screenshot instead
  • Screenshot failed: Check disk space, verify write permissions to screenshots directory
  • 未找到Playwright:建议执行
    npm install -D playwright
  • 页面无法加载:检查开发服务器是否运行,建议启动服务器
  • 登录失败:智能定位器会尝试常见模式,但可能无法适配特殊登录表单。如果登录失败,分析登录页面HTML以找到正确的选择器并自定义脚本。
  • 元素未找到:验证CSS选择器是否正确,或建议改为全页面截图
  • 截图失败:检查磁盘空间,确认是否有截图目录的写入权限

Tips for Best Results

最佳实践技巧

  1. Clean UI state: Use demo/seed data for realistic content
  2. Consistent sizing: Use the same viewport for all screenshots
  3. Wait for content: Use
    waitForLoadState('networkidle')
    to ensure all content loads
  4. Hide dev tools: Ensure no browser extensions or dev overlays are visible
  5. Dark mode variants: Consider capturing both light and dark mode if supported
  1. 干净的UI状态:使用演示/种子数据以呈现真实内容
  2. 统一尺寸:所有截图使用相同的视口设置
  3. 等待内容加载:使用
    waitForLoadState('networkidle')
    确保所有内容加载完成
  4. 隐藏开发工具:确保没有浏览器扩展或开发覆盖层可见
  5. 深色模式变体:如果应用支持,考虑同时捕获浅色与深色模式截图