[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M714G4JEST2FTVCAS34N9G0F":3,"skill-same:01M714G4JEST2FTVCAS34N9G0F":77},{"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":47,"commitSha":58,"skillDirectory":59,"forksCount":14,"repositoryHtmlUrl":60,"repositoryHomepageUrl":6,"ownerHtmlUrl":61,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":62,"install":63,"resources":76},"01M714G4JEST2FTVCAS34N9G0F","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.","sapsapshen\u002Fai-memory-router","sapsapshen","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F20347959?v=4","01M6XDQEF1DP50DKF37H81J3J5","shenmian","01M6XDQEJPE41Y3DT2763X8ZJN",0,"MIT","https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router\u002Fblob\u002Fmain\u002Fskills-store\u002Fcopilot\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],"generate","hunt","social media","pages","landing","for","tree","marketing","safe","2026","product","create","documentation","product hunt","when","main","social","Media","app","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.\"\nrisk: safe\nsource: \"https:\u002F\u002Fgithub.com\u002FShpigford\u002Fskills\u002Ftree\u002Fmain\u002Fscreenshots\"\ndate_added: \"2026-02-27\"\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":40,"source":56,"date_added":57,"description":7},"https:\u002F\u002Fgithub.com\u002FShpigford\u002Fskills\u002Ftree\u002Fmain\u002Fscreenshots","2026-02-27","7a38d8e7073e61c16eda85681cb32fb68a8657a5","skills-store\u002Fcopilot\u002Fscreenshots","https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router","https:\u002F\u002Fgithub.com\u002Fsapsapshen","2026-04-14 21:12:12",{"source":8,"skillName":5,"commands":64,"prompt":74,"zipAvailable":75},[65,68,71],{"tool":66,"command":67},"npx","npx skills add sapsapshen\u002Fai-memory-router --skill screenshots",{"tool":69,"command":70},"bunx","bunx skills add sapsapshen\u002Fai-memory-router --skill screenshots",{"tool":72,"command":73},"pnpm","pnpm dlx skills add sapsapshen\u002Fai-memory-router --skill screenshots","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router\u002Fblob\u002Fmain\u002Fskills-store\u002Fcopilot\u002Fscreenshots\u002FSKILL.md",true,[],[78,100,125,135,148,165],{"skillNo":79,"name":80,"nameZh":6,"description":81,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":82,"categories":83,"keywords":87,"publishedAt":51},"01M71ATQRKG48SH06FQ697T5G9","wechat-search","Search WeChat Official Account articles using OpenClaw's web search and fetch capabilities with compliance-focused design.","https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router\u002Fblob\u002Fmain\u002Fskills-store\u002Fopenclaw\u002Fwechat-search-release\u002FSKILL.md",[84],{"categoryNo":85,"categoryName":86,"taxonomyType":29,"taxonomyTypeDesc":30},"01JBSEEDCAT000000000000037","律师与法务",[88,89,90,91,92,93,94,95,96,97,98,99],"wechat search","wechat","search","capabilities","openclaw","design","web search","compliance","web","official","fetch","with",{"skillNo":101,"name":102,"nameZh":6,"description":103,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":104,"categories":105,"keywords":106,"publishedAt":51},"01M71ATNAVGZB35PFYM2GC5N00","trend-tap","Real-time trending topics aggregator across 7 platforms (X\u002FTwitter, Reddit, Google Trends, Hacker News, Zhihu, Bilibili, Weibo). Trigger: when user says 'trend', 'trends', 'trend tap', '热点', '热搜', or asks what is trending\u002Fhot. Do NOT use web_search — this skill already fetches live data from all platforms with zero API keys.","https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router\u002Fblob\u002Fmain\u002Fskills-store\u002Fopenclaw\u002Ftrend-tap\u002FSKILL.md",[],[107,108,109,110,111,112,90,113,114,115,116,46,117,118,119,120,121,122,123,124],"trend","trend tap","tap","api keys","Bash","time","trending","hacker","aggregator","do","brew","live","data","google","install","read","across","api",{"skillNo":126,"name":127,"nameZh":6,"description":128,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":129,"categories":130,"keywords":131,"publishedAt":51},"01M71ATJ9AM5KM15AA8PS302EB","trend-radar","Real-time trending topics aggregator across 7 platforms (X\u002FTwitter, Reddit, Google Trends, Hacker News, Zhihu, Bilibili, Weibo). Trigger: when user says 'trend', 'trends', 'trend pulse', '热点', '热搜', or asks what is trending\u002Fhot. Do NOT use web_search — this skill already fetches live data from all platforms with zero API keys.","https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router\u002Fblob\u002Fmain\u002Fskills-store\u002Fopenclaw\u002Ftrend-radar\u002FSKILL.md",[],[132,133,107,117,118,119,120,111,90,122,134,123,124,46,115,114,113,121,112,110],"trend radar","radar","pulse",{"skillNo":136,"name":137,"nameZh":6,"description":138,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":139,"categories":140,"keywords":141,"publishedAt":51},"01M71ATGF095N3EJM9G8SD0BB5","tech-news-daily","每日科技新闻汇——从全球多个 RSS 源抓取最新科技新闻，翻译（英→中）、去重、排版成每日简报。当用户询问科技新闻、科技新鲜事、每日科技、技术动态、Daily Tech News 或类似表达时触发此技能。","https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router\u002Fblob\u002Fmain\u002Fskills-store\u002Fopenclaw\u002Ftech-news-daily\u002FSKILL.md",[],[142,143,144,145,146,147],"news","tech","tech news daily","daily","rss","翻译",{"skillNo":149,"name":150,"nameZh":6,"description":151,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":152,"categories":153,"keywords":157,"publishedAt":51},"01M71ATFAEAMQ17M70NQNY7SR8","summarize","Summarize URLs or files with the summarize CLI (web, PDFs, images, audio, YouTube).","https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router\u002Fblob\u002Fmain\u002Fskills-store\u002Fopenclaw\u002Fsummarize\u002FSKILL.md",[154],{"categoryNo":155,"categoryName":156,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000021","资料检索与研究",[150,96,158,159,160,99,117,161,162,163,109,164,121],"Audio","cli","youtube","images","https","files","pdfs",{"skillNo":166,"name":167,"nameZh":6,"description":168,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":169,"categories":170,"keywords":171,"publishedAt":51},"01M71ATDNS3R0M4H936PACQAWZ","sonoscli","Control Sonos speakers (discover\u002Fstatus\u002Fplay\u002Fvolume\u002Fgroup).","https:\u002F\u002Fgithub.com\u002Fsapsapshen\u002Fai-memory-router\u002Fblob\u002Fmain\u002Fskills-store\u002Fopenclaw\u002Fsonoscli\u002FSKILL.md",[],[167,172,173,174,121,175,162,176,177,178,179,180],"status","play","go","latest","github","discover","control","cmd","volume"]