screenshots
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseScreenshots
截图
Generate marketing-quality screenshots of your app using Playwright directly. Screenshots are captured at true HiDPI (2x retina) resolution using .
deviceScaleFactor: 2直接使用Playwright生成达到营销级画质的应用截图。通过参数捕获真正的HiDPI(2倍视网膜)分辨率截图。
deviceScaleFactor: 2When 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 playwrightIf not found, inform the user:
Playwright is required. Install it with:ornpm install -D playwrightnpm install -D @playwright/test
必须已安装Playwright。可以通过以下命令检查:
bash
npx playwright --version 2>/dev/null || npm ls playwright 2>/dev/null | grep playwright如果未找到,请告知用户:
需要安装Playwright。执行以下命令安装:或npm install -D playwrightnpm install -D @playwright/test
Step 1: Determine App URL
步骤1:确定应用URL
If is provided, use it as the app URL.
$1If no URL is provided:
- Check if a dev server is likely running by looking for scripts
package.json - Use to ask the user for the URL or offer to help start the dev server
AskUserQuestion
Common default URLs to suggest:
- (Next.js, Create React App, Rails)
http://localhost:3000 - (Vite)
http://localhost:5173 - (Phoenix)
http://localhost:4000 - (Vue CLI, generic)
http://localhost:8080
如果提供了参数,则将其作为应用URL。
$1如果未提供URL:
- 检查中的脚本,判断是否可能有开发服务器在运行
package.json - 使用询问用户提供URL,或主动提出帮助启动开发服务器
AskUserQuestion
可建议的常见默认URL:
- (Next.js、Create React App、Rails)
http://localhost:3000 - (Vite)
http://localhost:5173 - (Phoenix)
http://localhost:4000 - (Vue CLI、通用型)
http://localhost:8080
Step 2: Gather Requirements
步骤2:收集需求
Use with the following questions:
AskUserQuestionQuestion 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:
-
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
-
CHANGELOG.md or HISTORY.md - Recent features worth highlighting
-
docs/ directory - Any additional documentation about features
务必先阅读以下文件,了解应用的核心功能:
-
README.md(以及子目录中的所有README文件)- 完整阅读README以了解:
- 应用的定位与解决的问题
- 核心功能与能力
- 已有的截图或功能描述
-
CHANGELOG.md 或 HISTORY.md - 值得重点展示的近期新增功能
-
docs/ 目录 - 任何关于功能的补充文档
3.2: Analyze Routes to Find Pages
3.2:分析路由以发现页面
Read the routing configuration to discover all available pages:
| Framework | File to Read | What to Look For |
|---|---|---|
| Next.js App Router | | Each folder with |
| Next.js Pages Router | | Each file is a route |
| Rails | | Read the entire file for all routes |
| React Router | Search for | Route definitions with paths |
| Vue Router | | Routes array with path definitions |
| SvelteKit | | Each folder with |
| Remix | | File-based routing |
| Laravel | | Route definitions |
| Django | | URL patterns |
| Express | Search for | 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 | | 每个包含 |
| Next.js Pages Router | | 每个文件对应一个路由 |
| Rails | | 通读整个文件获取所有路由 |
| React Router | 搜索 | 包含路径的路由定义 |
| Vue Router | | 包含路径定义的路由数组 |
| SvelteKit | | 每个包含 |
| Remix | | 基于文件的路由结构 |
| Laravel | | 路由定义 |
| Django | | URL模式 |
| Express | 搜索 | 路由处理器 |
重要提示:务必实际阅读这些文件,不要仅检查文件是否存在。路由定义会告诉你哪些页面适合截图。
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 or
components/landing/)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 screenshotsbash
mkdir -p screenshotsStep 6: Generate and Run Playwright Script
步骤6:生成并运行Playwright脚本
Create a Node.js script that uses Playwright with proper HiDPI settings. The script should:
- Use for true retina resolution
deviceScaleFactor: 2 - Set viewport to 1440x900 (produces 2880x1800 pixel images)
- Handle authentication if credentials were provided
- Navigate to each page and capture screenshots
创建一个使用Playwright的Node.js脚本,并配置正确的HiDPI参数。脚本应包含以下功能:
- 设置以实现真正的视网膜分辨率
deviceScaleFactor: 2 - 将视口设置为1440x900(生成2880x1800像素的图片)
- 处理身份验证(如果用户提供了凭据)
- 导航至每个页面并捕获截图
Script Template
脚本模板
Write this script to a temporary file (e.g., ) and execute it:
screenshot-script.mjsjavascript
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.mjsjavascript
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.mjsAfter running, clean up the temporary script:
bash
rm screenshot-script.mjsbash
node screenshot-script.mjs运行完成后,清理临时脚本:
bash
rm screenshot-script.mjsStep 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:
| Feature | Filename |
|---|---|
| Dashboard overview | |
| Link management | |
| Edition editor | |
| Analytics | |
| Settings | |
使用描述性的短横线分隔命名(kebab-case),并添加数字前缀以排序:
| 功能 | 文件名 |
|---|---|
| 仪表盘概览 | |
| 链接管理 | |
| 版本编辑器 | |
| 数据分析 | |
| 设置页面 | |
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/*.pngProvide a summary to the user:
- List all generated files with their paths
- Confirm the resolution (should be 2880x1800 for 2x retina at 1440x900 viewport)
- Mention total file sizes
- 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向用户提供总结:
- 列出所有生成的文件及其路径
- 确认分辨率(1440x900视口下的2倍视网膜截图应为2880x1800)
- 提及文件总大小
- 建议后续操作
示例输出:
已生成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
最佳实践技巧
- Clean UI state: Use demo/seed data for realistic content
- Consistent sizing: Use the same viewport for all screenshots
- Wait for content: Use to ensure all content loads
waitForLoadState('networkidle') - Hide dev tools: Ensure no browser extensions or dev overlays are visible
- Dark mode variants: Consider capturing both light and dark mode if supported
- 干净的UI状态:使用演示/种子数据以呈现真实内容
- 统一尺寸:所有截图使用相同的视口设置
- 等待内容加载:使用确保所有内容加载完成
waitForLoadState('networkidle') - 隐藏开发工具:确保没有浏览器扩展或开发覆盖层可见
- 深色模式变体:如果应用支持,考虑同时捕获浅色与深色模式截图