[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6EZS4AXHXBT9KGWMK3Q1ASF":3,"skill-same:01M6EZS4AXHXBT9KGWMK3Q1ASF":85},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":31,"publishedAt":51,"linkOnly":52,"markdownContent":53,"markdownBody":54,"frontMatter":55,"refName":37,"commitSha":57,"skillDirectory":58,"forksCount":59,"repositoryHtmlUrl":60,"repositoryHomepageUrl":61,"ownerHtmlUrl":62,"ownerBlogUrl":6,"ownerDescription":63,"updatedAt":64,"install":65,"resources":78},"01M6EZS4AXHXBT9KGWMK3Q1ASF","screenshots",null,"Generate marketing screenshots of your app using Playwright. Use when the user wants to create screenshots for Product Hunt, social media, landing pages, or documentation.","ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",67,"MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fsickn33\u002Fscreenshots\u002FSKILL.md",[18,23,26],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000019","营销推广",{"categoryNo":27,"categoryName":28,"taxonomyType":29,"taxonomyTypeDesc":30},"01JBSEEDCAT000000000000035","市场营销","PROFESSION","适用职业",[5,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50],"marketing","app","pages","product hunt","social","main","hunt","use","landing","social media","Media","https","product","generate","create","documentation","playwright","github","safe","2026-11-10 10:12:30",false,"---\nname: screenshots\ndescription: \"Generate marketing screenshots of your app using Playwright. Use when the user wants to create screenshots for Product Hunt, social media, landing pages, or documentation.\"\nsource: \"https:\u002F\u002Fgithub.com\u002FShpigford\u002Fskills\u002Ftree\u002Fmain\u002Fscreenshots\"\nrisk: safe\n---\n\n# Screenshots\n\nGenerate marketing-quality screenshots of your app using Playwright directly. Screenshots are captured at true HiDPI (2x retina) resolution using `deviceScaleFactor: 2`.\n\n## When to Use This Skill\n\nUse this skill when:\n- User wants to create screenshots for Product Hunt\n- Creating screenshots for social media\n- Generating images for landing pages\n- Creating documentation screenshots\n- User requests marketing-quality app screenshots\n\n## Prerequisites\n\nPlaywright must be available. Check for it:\n```bash\nnpx playwright --version 2>\u002Fdev\u002Fnull || npm ls playwright 2>\u002Fdev\u002Fnull | grep playwright\n```\n\nIf not found, inform the user:\n> Playwright is required. Install it with: `npm install -D playwright` or `npm install -D @playwright\u002Ftest`\n\n## Step 1: Determine App URL\n\nIf `$1` is provided, use it as the app URL.\n\nIf no URL is provided:\n1. Check if a dev server is likely running by looking for `package.json` scripts\n2. Use `AskUserQuestion` to ask the user for the URL or offer to help start the dev server\n\nCommon default URLs to suggest:\n- `http:\u002F\u002Flocalhost:3000` (Next.js, Create React App, Rails)\n- `http:\u002F\u002Flocalhost:5173` (Vite)\n- `http:\u002F\u002Flocalhost:4000` (Phoenix)\n- `http:\u002F\u002Flocalhost:8080` (Vue CLI, generic)\n\n## Step 2: Gather Requirements\n\nUse `AskUserQuestion` with the following questions:\n\n**Question 1: Screenshot count**\n- Header: \"Count\"\n- Question: \"How many screenshots do you need?\"\n- Options:\n  - \"3-5\" - Quick set of key features\n  - \"5-10\" - Comprehensive feature coverage\n  - \"10+\" - Full marketing suite\n\n**Question 2: Purpose**\n- Header: \"Purpose\"\n- Question: \"What will these screenshots be used for?\"\n- Options:\n  - \"Product Hunt\" - Hero shots and feature highlights\n  - \"Social media\" - Eye-catching feature demos\n  - \"Landing page\" - Marketing sections and benefits\n  - \"Documentation\" - UI reference and tutorials\n\n**Question 3: Authentication**\n- Header: \"Auth\"\n- Question: \"Does the app require login to access the features you want to screenshot?\"\n- Options:\n  - \"No login needed\" - Public pages only\n  - \"Yes, I'll provide credentials\" - Need to log in first\n\nIf user selects \"Yes, I'll provide credentials\", ask follow-up questions:\n- \"What is the login page URL?\" (e.g., `\u002Flogin`, `\u002Fsign-in`)\n- \"What is the email\u002Fusername?\"\n- \"What is the password?\"\n\nThe script will automatically detect login form fields using Playwright's smart locators.\n\n## Step 3: Analyze Codebase for Features\n\nThoroughly explore the codebase to understand the app and identify screenshot opportunities.\n\n### 3.1: Read Documentation First\n\n**Always start by reading these files** to understand what the app does:\n\n1. **README.md** (and any README files in subdirectories) - Read the full README to understand:\n   - What the app is and what problem it solves\n   - Key features and capabilities\n   - Screenshots or feature descriptions already documented\n\n2. **CHANGELOG.md** or **HISTORY.md** - Recent features worth highlighting\n\n3. **docs\u002F** directory - Any additional documentation about features\n\n### 3.2: Analyze Routes to Find Pages\n\nRead the routing configuration to discover all available pages:\n\n| Framework | File to Read | What to Look For |\n|-----------|--------------|------------------|\n| **Next.js App Router** | `app\u002F` directory structure | Each folder with `page.tsx` is a route |\n| **Next.js Pages Router** | `pages\u002F` directory | Each file is a route |\n| **Rails** | `config\u002Froutes.rb` | Read the entire file for all routes |\n| **React Router** | Search for `createBrowserRouter` or `\u003CRoute` | Route definitions with paths |\n| **Vue Router** | `src\u002Frouter\u002Findex.js` or `router.js` | Routes array with path definitions |\n| **SvelteKit** | `src\u002Froutes\u002F` directory | Each folder with `+page.svelte` is a route |\n| **Remix** | `app\u002Froutes\u002F` directory | File-based routing |\n| **Laravel** | `routes\u002Fweb.php` | Route definitions |\n| **Django** | `urls.py` files | URL patterns |\n| **Express** | Search for `app.get`, `router.get` | Route handlers |\n\n**Important**: Actually read these files, don't just check if they exist. The route definitions tell you what pages are available for screenshots.\n\n### 3.3: Identify Key Components\n\nLook for components that represent screenshottable features:\n\n- Dashboard components\n- Feature sections with distinct UI\n- Forms and interactive inputs\n- Data visualizations (charts, graphs, tables)\n- Modals and dialogs\n- Navigation and sidebars\n- Settings panels\n- User profile sections\n\n### 3.4: Check for Marketing Assets\n\nLook for existing marketing content that hints at key features:\n- Landing page components (often in `components\u002Flanding\u002F` or `components\u002Fmarketing\u002F`)\n- Feature list components\n- Pricing tables\n- Testimonial sections\n\n### 3.5: Build Feature List\n\nCreate a comprehensive list of discovered features with:\n- Feature name (from README or component name)\n- URL path (from routes)\n- CSS selector to focus on (from component structure)\n- Required UI state (logged in, data populated, modal open, specific tab selected)\n\n## Step 4: Plan Screenshots with User\n\nPresent the discovered features to the user and ask them to confirm or modify the list.\n\nUse `AskUserQuestion`:\n- Header: \"Features\"\n- Question: \"I found these features in your codebase. Which would you like to screenshot?\"\n- Options: List 3-4 key features discovered, plus \"Let me pick specific ones\"\n\nIf user wants specific ones, ask follow-up questions to clarify exactly what to capture.\n\n## Step 5: Create Screenshots Directory\n\n```bash\nmkdir -p screenshots\n```\n\n## Step 6: Generate and Run Playwright Script\n\nCreate a Node.js script that uses Playwright with proper HiDPI settings. The script should:\n\n1. **Use `deviceScaleFactor: 2`** for true retina resolution\n2. **Set viewport to 1440x900** (produces 2880x1800 pixel images)\n3. **Handle authentication** if credentials were provided\n4. **Navigate to each page** and capture screenshots\n\n### Script Template\n\nWrite this script to a temporary file (e.g., `screenshot-script.mjs`) and execute it:\n\n```javascript\nimport { chromium } from 'playwright';\n\nconst BASE_URL = '[APP_URL]';\nconst SCREENSHOTS_DIR = '.\u002Fscreenshots';\n\n\u002F\u002F Authentication config (if needed)\nconst AUTH = {\n  needed: [true|false],\n  loginUrl: '[LOGIN_URL]',\n  email: '[EMAIL]',\n  password: '[PASSWORD]',\n};\n\n\u002F\u002F Screenshots to capture\nconst SCREENSHOTS = [\n  { name: '01-feature-name', url: '\u002Fpath', waitFor: '[optional-selector]' },\n  { name: '02-another-feature', url: '\u002Fanother-path' },\n  \u002F\u002F ... add all planned screenshots\n];\n\nasync function main() {\n  const browser = await chromium.launch();\n\n  \u002F\u002F Create context with HiDPI settings\n  const context = await browser.newContext({\n    viewport: { width: 1440, height: 900 },\n    deviceScaleFactor: 2,  \u002F\u002F This is the key for true retina screenshots\n  });\n\n  const page = await context.newPage();\n\n  \u002F\u002F Handle authentication if needed\n  if (AUTH.needed) {\n    console.log('Logging in...');\n    await page.goto(AUTH.loginUrl);\n\n    \u002F\u002F Smart login: try multiple common patterns for email\u002Fusername field\n    const emailField = page.locator([\n      'input[type=\"email\"]',\n      'input[name=\"email\"]',\n      'input[id=\"email\"]',\n      'input[placeholder*=\"email\" i]',\n      'input[name=\"username\"]',\n      'input[id=\"username\"]',\n      'input[type=\"text\"]',\n    ].join(', ')).first();\n    await emailField.fill(AUTH.email);\n\n    \u002F\u002F Smart login: try multiple common patterns for password field\n    const passwordField = page.locator([\n      'input[type=\"password\"]',\n      'input[name=\"password\"]',\n      'input[id=\"password\"]',\n    ].join(', ')).first();\n    await passwordField.fill(AUTH.password);\n\n    \u002F\u002F Smart login: try multiple common patterns for submit button\n    const submitButton = page.locator([\n      'button[type=\"submit\"]',\n      'input[type=\"submit\"]',\n      'button:has-text(\"Sign in\")',\n      'button:has-text(\"Log in\")',\n      'button:has-text(\"Login\")',\n      'button:has-text(\"Submit\")',\n    ].join(', ')).first();\n    await submitButton.click();\n\n    await page.waitForLoadState('networkidle');\n    console.log('Login complete');\n  }\n\n  \u002F\u002F Capture each screenshot\n  for (const shot of SCREENSHOTS) {\n    console.log(`Capturing: ${shot.name}`);\n    await page.goto(`${BASE_URL}${shot.url}`);\n    await page.waitForLoadState('networkidle');\n\n    \u002F\u002F Optional: wait for specific element\n    if (shot.waitFor) {\n      await page.waitForSelector(shot.waitFor);\n    }\n\n    \u002F\u002F Optional: perform actions before screenshot\n    if (shot.actions) {\n      for (const action of shot.actions) {\n        if (action.click) await page.click(action.click);\n        if (action.fill) await page.fill(action.fill.selector, action.fill.value);\n        if (action.wait) await page.waitForTimeout(action.wait);\n      }\n    }\n\n    await page.screenshot({\n      path: `${SCREENSHOTS_DIR}\u002F${shot.name}.png`,\n      fullPage: shot.fullPage || false,\n    });\n    console.log(`  Saved: ${shot.name}.png`);\n  }\n\n  await browser.close();\n  console.log('Done!');\n}\n\nmain().catch(console.error);\n```\n\n### Running the Script\n\n```bash\nnode screenshot-script.mjs\n```\n\nAfter running, clean up the temporary script:\n```bash\nrm screenshot-script.mjs\n```\n\n## Step 7: Advanced Screenshot Options\n\n### Element-Focused Screenshots\n\nTo screenshot a specific element instead of the full viewport:\n\n```javascript\nconst element = await page.locator('[CSS_SELECTOR]');\nawait element.screenshot({ path: `${SCREENSHOTS_DIR}\u002Felement.png` });\n```\n\n### Full Page Screenshots\n\nFor scrollable content, capture the entire page:\n\n```javascript\nawait page.screenshot({\n  path: `${SCREENSHOTS_DIR}\u002Ffull-page.png`,\n  fullPage: true\n});\n```\n\n### Waiting for Animations\n\nIf the page has animations, wait for them to complete:\n\n```javascript\nawait page.waitForTimeout(500); \u002F\u002F Wait 500ms for animations\n```\n\n### Clicking Elements Before Screenshot\n\nTo capture a modal, dropdown, or hover state:\n\n```javascript\nawait page.click('button.open-modal');\nawait page.waitForSelector('.modal-content');\nawait page.screenshot({ path: `${SCREENSHOTS_DIR}\u002Fmodal.png` });\n```\n\n### Dark Mode Screenshots\n\nIf the app supports dark mode:\n\n```javascript\n\u002F\u002F Set dark mode preference\nconst context = await browser.newContext({\n  viewport: { width: 1440, height: 900 },\n  deviceScaleFactor: 2,\n  colorScheme: 'dark',\n});\n```\n\n## Step 8: File Naming Convention\n\nUse descriptive, kebab-case filenames with numeric prefixes for ordering:\n\n| Feature | Filename |\n|---------|----------|\n| Dashboard overview | `01-dashboard-overview.png` |\n| Link management | `02-link-inbox.png` |\n| Edition editor | `03-edition-editor.png` |\n| Analytics | `04-analytics.png` |\n| Settings | `05-settings.png` |\n\n## Step 9: Verify and Summarize\n\nAfter capturing all screenshots, verify the results:\n\n```bash\nls -la screenshots\u002F*.png\nsips -g pixelWidth -g pixelHeight screenshots\u002F*.png 2>\u002Fdev\u002Fnull || file screenshots\u002F*.png\n```\n\nProvide a summary to the user:\n\n1. List all generated files with their paths\n2. Confirm the resolution (should be 2880x1800 for 2x retina at 1440x900 viewport)\n3. Mention total file sizes\n4. Suggest any follow-up actions\n\nExample output:\n```\nGenerated 5 marketing screenshots:\n\nscreenshots\u002F\n├── 01-dashboard-overview.png (1.2 MB, 2880x1800 @ 2x)\n├── 02-link-inbox.png (456 KB, 2880x1800 @ 2x)\n├── 03-edition-editor.png (890 KB, 2880x1800 @ 2x)\n├── 04-analytics.png (567 KB, 2880x1800 @ 2x)\n└── 05-settings.png (234 KB, 2880x1800 @ 2x)\n\nAll screenshots are true retina-quality (2x deviceScaleFactor) and ready for marketing use.\n```\n\n## Error Handling\n\n- **Playwright not found**: Suggest `npm install -D playwright`\n- **Page not loading**: Check if the dev server is running, suggest starting it\n- **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.\n- **Element not found**: Verify the CSS selector, offer to take a full page screenshot instead\n- **Screenshot failed**: Check disk space, verify write permissions to screenshots directory\n\n## Tips for Best Results\n\n1. **Clean UI state**: Use demo\u002Fseed data for realistic content\n2. **Consistent sizing**: Use the same viewport for all screenshots\n3. **Wait for content**: Use `waitForLoadState('networkidle')` to ensure all content loads\n4. **Hide dev tools**: Ensure no browser extensions or dev overlays are visible\n5. **Dark mode variants**: Consider capturing both light and dark mode if supported\n","# Screenshots\n\nGenerate marketing-quality screenshots of your app using Playwright directly. Screenshots are captured at true HiDPI (2x retina) resolution using `deviceScaleFactor: 2`.\n\n## When to Use This Skill\n\nUse this skill when:\n- User wants to create screenshots for Product Hunt\n- Creating screenshots for social media\n- Generating images for landing pages\n- Creating documentation screenshots\n- User requests marketing-quality app screenshots\n\n## Prerequisites\n\nPlaywright must be available. Check for it:\n```bash\nnpx playwright --version 2>\u002Fdev\u002Fnull || npm ls playwright 2>\u002Fdev\u002Fnull | grep playwright\n```\n\nIf not found, inform the user:\n> Playwright is required. Install it with: `npm install -D playwright` or `npm install -D @playwright\u002Ftest`\n\n## Step 1: Determine App URL\n\nIf `$1` is provided, use it as the app URL.\n\nIf no URL is provided:\n1. Check if a dev server is likely running by looking for `package.json` scripts\n2. Use `AskUserQuestion` to ask the user for the URL or offer to help start the dev server\n\nCommon default URLs to suggest:\n- `http:\u002F\u002Flocalhost:3000` (Next.js, Create React App, Rails)\n- `http:\u002F\u002Flocalhost:5173` (Vite)\n- `http:\u002F\u002Flocalhost:4000` (Phoenix)\n- `http:\u002F\u002Flocalhost:8080` (Vue CLI, generic)\n\n## Step 2: Gather Requirements\n\nUse `AskUserQuestion` with the following questions:\n\n**Question 1: Screenshot count**\n- Header: \"Count\"\n- Question: \"How many screenshots do you need?\"\n- Options:\n  - \"3-5\" - Quick set of key features\n  - \"5-10\" - Comprehensive feature coverage\n  - \"10+\" - Full marketing suite\n\n**Question 2: Purpose**\n- Header: \"Purpose\"\n- Question: \"What will these screenshots be used for?\"\n- Options:\n  - \"Product Hunt\" - Hero shots and feature highlights\n  - \"Social media\" - Eye-catching feature demos\n  - \"Landing page\" - Marketing sections and benefits\n  - \"Documentation\" - UI reference and tutorials\n\n**Question 3: Authentication**\n- Header: \"Auth\"\n- Question: \"Does the app require login to access the features you want to screenshot?\"\n- Options:\n  - \"No login needed\" - Public pages only\n  - \"Yes, I'll provide credentials\" - Need to log in first\n\nIf user selects \"Yes, I'll provide credentials\", ask follow-up questions:\n- \"What is the login page URL?\" (e.g., `\u002Flogin`, `\u002Fsign-in`)\n- \"What is the email\u002Fusername?\"\n- \"What is the password?\"\n\nThe script will automatically detect login form fields using Playwright's smart locators.\n\n## Step 3: Analyze Codebase for Features\n\nThoroughly explore the codebase to understand the app and identify screenshot opportunities.\n\n### 3.1: Read Documentation First\n\n**Always start by reading these files** to understand what the app does:\n\n1. **README.md** (and any README files in subdirectories) - Read the full README to understand:\n   - What the app is and what problem it solves\n   - Key features and capabilities\n   - Screenshots or feature descriptions already documented\n\n2. **CHANGELOG.md** or **HISTORY.md** - Recent features worth highlighting\n\n3. **docs\u002F** directory - Any additional documentation about features\n\n### 3.2: Analyze Routes to Find Pages\n\nRead the routing configuration to discover all available pages:\n\n| Framework | File to Read | What to Look For |\n|-----------|--------------|------------------|\n| **Next.js App Router** | `app\u002F` directory structure | Each folder with `page.tsx` is a route |\n| **Next.js Pages Router** | `pages\u002F` directory | Each file is a route |\n| **Rails** | `config\u002Froutes.rb` | Read the entire file for all routes |\n| **React Router** | Search for `createBrowserRouter` or `\u003CRoute` | Route definitions with paths |\n| **Vue Router** | `src\u002Frouter\u002Findex.js` or `router.js` | Routes array with path definitions |\n| **SvelteKit** | `src\u002Froutes\u002F` directory | Each folder with `+page.svelte` is a route |\n| **Remix** | `app\u002Froutes\u002F` directory | File-based routing |\n| **Laravel** | `routes\u002Fweb.php` | Route definitions |\n| **Django** | `urls.py` files | URL patterns |\n| **Express** | Search for `app.get`, `router.get` | Route handlers |\n\n**Important**: Actually read these files, don't just check if they exist. The route definitions tell you what pages are available for screenshots.\n\n### 3.3: Identify Key Components\n\nLook for components that represent screenshottable features:\n\n- Dashboard components\n- Feature sections with distinct UI\n- Forms and interactive inputs\n- Data visualizations (charts, graphs, tables)\n- Modals and dialogs\n- Navigation and sidebars\n- Settings panels\n- User profile sections\n\n### 3.4: Check for Marketing Assets\n\nLook for existing marketing content that hints at key features:\n- Landing page components (often in `components\u002Flanding\u002F` or `components\u002Fmarketing\u002F`)\n- Feature list components\n- Pricing tables\n- Testimonial sections\n\n### 3.5: Build Feature List\n\nCreate a comprehensive list of discovered features with:\n- Feature name (from README or component name)\n- URL path (from routes)\n- CSS selector to focus on (from component structure)\n- Required UI state (logged in, data populated, modal open, specific tab selected)\n\n## Step 4: Plan Screenshots with User\n\nPresent the discovered features to the user and ask them to confirm or modify the list.\n\nUse `AskUserQuestion`:\n- Header: \"Features\"\n- Question: \"I found these features in your codebase. Which would you like to screenshot?\"\n- Options: List 3-4 key features discovered, plus \"Let me pick specific ones\"\n\nIf user wants specific ones, ask follow-up questions to clarify exactly what to capture.\n\n## Step 5: Create Screenshots Directory\n\n```bash\nmkdir -p screenshots\n```\n\n## Step 6: Generate and Run Playwright Script\n\nCreate a Node.js script that uses Playwright with proper HiDPI settings. The script should:\n\n1. **Use `deviceScaleFactor: 2`** for true retina resolution\n2. **Set viewport to 1440x900** (produces 2880x1800 pixel images)\n3. **Handle authentication** if credentials were provided\n4. **Navigate to each page** and capture screenshots\n\n### Script Template\n\nWrite this script to a temporary file (e.g., `screenshot-script.mjs`) and execute it:\n\n```javascript\nimport { chromium } from 'playwright';\n\nconst BASE_URL = '[APP_URL]';\nconst SCREENSHOTS_DIR = '.\u002Fscreenshots';\n\n\u002F\u002F Authentication config (if needed)\nconst AUTH = {\n  needed: [true|false],\n  loginUrl: '[LOGIN_URL]',\n  email: '[EMAIL]',\n  password: '[PASSWORD]',\n};\n\n\u002F\u002F Screenshots to capture\nconst SCREENSHOTS = [\n  { name: '01-feature-name', url: '\u002Fpath', waitFor: '[optional-selector]' },\n  { name: '02-another-feature', url: '\u002Fanother-path' },\n  \u002F\u002F ... add all planned screenshots\n];\n\nasync function main() {\n  const browser = await chromium.launch();\n\n  \u002F\u002F Create context with HiDPI settings\n  const context = await browser.newContext({\n    viewport: { width: 1440, height: 900 },\n    deviceScaleFactor: 2,  \u002F\u002F This is the key for true retina screenshots\n  });\n\n  const page = await context.newPage();\n\n  \u002F\u002F Handle authentication if needed\n  if (AUTH.needed) {\n    console.log('Logging in...');\n    await page.goto(AUTH.loginUrl);\n\n    \u002F\u002F Smart login: try multiple common patterns for email\u002Fusername field\n    const emailField = page.locator([\n      'input[type=\"email\"]',\n      'input[name=\"email\"]',\n      'input[id=\"email\"]',\n      'input[placeholder*=\"email\" i]',\n      'input[name=\"username\"]',\n      'input[id=\"username\"]',\n      'input[type=\"text\"]',\n    ].join(', ')).first();\n    await emailField.fill(AUTH.email);\n\n    \u002F\u002F Smart login: try multiple common patterns for password field\n    const passwordField = page.locator([\n      'input[type=\"password\"]',\n      'input[name=\"password\"]',\n      'input[id=\"password\"]',\n    ].join(', ')).first();\n    await passwordField.fill(AUTH.password);\n\n    \u002F\u002F Smart login: try multiple common patterns for submit button\n    const submitButton = page.locator([\n      'button[type=\"submit\"]',\n      'input[type=\"submit\"]',\n      'button:has-text(\"Sign in\")',\n      'button:has-text(\"Log in\")',\n      'button:has-text(\"Login\")',\n      'button:has-text(\"Submit\")',\n    ].join(', ')).first();\n    await submitButton.click();\n\n    await page.waitForLoadState('networkidle');\n    console.log('Login complete');\n  }\n\n  \u002F\u002F Capture each screenshot\n  for (const shot of SCREENSHOTS) {\n    console.log(`Capturing: ${shot.name}`);\n    await page.goto(`${BASE_URL}${shot.url}`);\n    await page.waitForLoadState('networkidle');\n\n    \u002F\u002F Optional: wait for specific element\n    if (shot.waitFor) {\n      await page.waitForSelector(shot.waitFor);\n    }\n\n    \u002F\u002F Optional: perform actions before screenshot\n    if (shot.actions) {\n      for (const action of shot.actions) {\n        if (action.click) await page.click(action.click);\n        if (action.fill) await page.fill(action.fill.selector, action.fill.value);\n        if (action.wait) await page.waitForTimeout(action.wait);\n      }\n    }\n\n    await page.screenshot({\n      path: `${SCREENSHOTS_DIR}\u002F${shot.name}.png`,\n      fullPage: shot.fullPage || false,\n    });\n    console.log(`  Saved: ${shot.name}.png`);\n  }\n\n  await browser.close();\n  console.log('Done!');\n}\n\nmain().catch(console.error);\n```\n\n### Running the Script\n\n```bash\nnode screenshot-script.mjs\n```\n\nAfter running, clean up the temporary script:\n```bash\nrm screenshot-script.mjs\n```\n\n## Step 7: Advanced Screenshot Options\n\n### Element-Focused Screenshots\n\nTo screenshot a specific element instead of the full viewport:\n\n```javascript\nconst element = await page.locator('[CSS_SELECTOR]');\nawait element.screenshot({ path: `${SCREENSHOTS_DIR}\u002Felement.png` });\n```\n\n### Full Page Screenshots\n\nFor scrollable content, capture the entire page:\n\n```javascript\nawait page.screenshot({\n  path: `${SCREENSHOTS_DIR}\u002Ffull-page.png`,\n  fullPage: true\n});\n```\n\n### Waiting for Animations\n\nIf the page has animations, wait for them to complete:\n\n```javascript\nawait page.waitForTimeout(500); \u002F\u002F Wait 500ms for animations\n```\n\n### Clicking Elements Before Screenshot\n\nTo capture a modal, dropdown, or hover state:\n\n```javascript\nawait page.click('button.open-modal');\nawait page.waitForSelector('.modal-content');\nawait page.screenshot({ path: `${SCREENSHOTS_DIR}\u002Fmodal.png` });\n```\n\n### Dark Mode Screenshots\n\nIf the app supports dark mode:\n\n```javascript\n\u002F\u002F Set dark mode preference\nconst context = await browser.newContext({\n  viewport: { width: 1440, height: 900 },\n  deviceScaleFactor: 2,\n  colorScheme: 'dark',\n});\n```\n\n## Step 8: File Naming Convention\n\nUse descriptive, kebab-case filenames with numeric prefixes for ordering:\n\n| Feature | Filename |\n|---------|----------|\n| Dashboard overview | `01-dashboard-overview.png` |\n| Link management | `02-link-inbox.png` |\n| Edition editor | `03-edition-editor.png` |\n| Analytics | `04-analytics.png` |\n| Settings | `05-settings.png` |\n\n## Step 9: Verify and Summarize\n\nAfter capturing all screenshots, verify the results:\n\n```bash\nls -la screenshots\u002F*.png\nsips -g pixelWidth -g pixelHeight screenshots\u002F*.png 2>\u002Fdev\u002Fnull || file screenshots\u002F*.png\n```\n\nProvide a summary to the user:\n\n1. List all generated files with their paths\n2. Confirm the resolution (should be 2880x1800 for 2x retina at 1440x900 viewport)\n3. Mention total file sizes\n4. Suggest any follow-up actions\n\nExample output:\n```\nGenerated 5 marketing screenshots:\n\nscreenshots\u002F\n├── 01-dashboard-overview.png (1.2 MB, 2880x1800 @ 2x)\n├── 02-link-inbox.png (456 KB, 2880x1800 @ 2x)\n├── 03-edition-editor.png (890 KB, 2880x1800 @ 2x)\n├── 04-analytics.png (567 KB, 2880x1800 @ 2x)\n└── 05-settings.png (234 KB, 2880x1800 @ 2x)\n\nAll screenshots are true retina-quality (2x deviceScaleFactor) and ready for marketing use.\n```\n\n## Error Handling\n\n- **Playwright not found**: Suggest `npm install -D playwright`\n- **Page not loading**: Check if the dev server is running, suggest starting it\n- **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.\n- **Element not found**: Verify the CSS selector, offer to take a full page screenshot instead\n- **Screenshot failed**: Check disk space, verify write permissions to screenshots directory\n\n## Tips for Best Results\n\n1. **Clean UI state**: Use demo\u002Fseed data for realistic content\n2. **Consistent sizing**: Use the same viewport for all screenshots\n3. **Wait for content**: Use `waitForLoadState('networkidle')` to ensure all content loads\n4. **Hide dev tools**: Ensure no browser extensions or dev overlays are visible\n5. **Dark mode variants**: Consider capturing both light and dark mode if supported\n",{"name":5,"risk":50,"source":56,"description":7},"https:\u002F\u002Fgithub.com\u002FShpigford\u002Fskills\u002Ftree\u002Fmain\u002Fscreenshots","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002Faiskillstore\u002Fmarketplace\u002Fsickn33\u002Fscreenshots",24,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub","https:\u002F\u002Fskillshub.wtf","https:\u002F\u002Fgithub.com\u002FComeOnOliver","AI & Blockchain Engineer\r\n","2026-06-24 22:07:19",{"source":8,"skillName":5,"commands":66,"prompt":76,"zipAvailable":77},[67,70,73],{"tool":68,"command":69},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill screenshots",{"tool":71,"command":72},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill screenshots",{"tool":74,"command":75},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill screenshots","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fsickn33\u002Fscreenshots\u002FSKILL.md",true,[79],{"path":80,"resourceType":81,"resourceTypeDesc":82,"sizeBytes":83,"sourceHtmlUrl":84},"skill-report.json","REFERENCE","参考文档",10827,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fsickn33\u002Fscreenshots\u002Fskill-report.json",[86,98,108,117,123,130],{"skillNo":87,"name":88,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":89,"categories":90,"keywords":94,"publishedAt":51},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[91],{"categoryNo":92,"categoryName":93,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[95,96,97],"model","model hierarchy","model hierarchy skill",{"skillNo":99,"name":100,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":101,"categories":102,"keywords":104,"publishedAt":51},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[103],{"categoryNo":92,"categoryName":93,"taxonomyType":21,"taxonomyTypeDesc":22},[105,106,107],"MCP","zoom","zoom mcp",{"skillNo":109,"name":110,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":111,"categories":112,"keywords":113,"publishedAt":51},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[114,115,116,106],"sdk","zoom apps sdk","apps",{"skillNo":118,"name":119,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":120,"categories":121,"keywords":122,"publishedAt":51},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","windows","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[119],{"skillNo":124,"name":125,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":126,"categories":127,"keywords":129,"publishedAt":51},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[128],{"categoryNo":92,"categoryName":93,"taxonomyType":21,"taxonomyTypeDesc":22},[125],{"skillNo":131,"name":132,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":133,"categories":134,"keywords":135,"publishedAt":51},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[132]]