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.
Add this skill
npx mdskills install Shpigford/screenshotsComprehensive instructions for generating marketing screenshots with intelligent framework detection and retina support
1---2name: screenshots3argument-hint: [url]4description: 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.5allowed-tools: Bash(npx *), Bash(node *), Bash(mkdir *), Bash(ls *), Bash(rm *), Bash(sips *)6context: fork7metadata:8 author: Shpigford9 version: "1.0"10---1112Generate marketing-quality screenshots of your app using Playwright directly. Screenshots are captured at true HiDPI (2x retina) resolution using `deviceScaleFactor: 2`.1314## Prerequisites1516Playwright must be available. Check for it:17```bash18npx playwright --version 2>/dev/null || npm ls playwright 2>/dev/null | grep playwright19```2021If not found, inform the user:22> Playwright is required. Install it with: `npm install -D playwright` or `npm install -D @playwright/test`2324## Step 1: Determine App URL2526If `$1` is provided, use it as the app URL.2728If no URL is provided:291. Check if a dev server is likely running by looking for `package.json` scripts302. Use `AskUserQuestion` to ask the user for the URL or offer to help start the dev server3132Common default URLs to suggest:33- `http://localhost:3000` (Next.js, Create React App, Rails)34- `http://localhost:5173` (Vite)35- `http://localhost:4000` (Phoenix)36- `http://localhost:8080` (Vue CLI, generic)3738## Step 2: Gather Requirements3940Use `AskUserQuestion` with the following questions:4142**Question 1: Screenshot count**43- Header: "Count"44- Question: "How many screenshots do you need?"45- Options:46 - "3-5" - Quick set of key features47 - "5-10" - Comprehensive feature coverage48 - "10+" - Full marketing suite4950**Question 2: Purpose**51- Header: "Purpose"52- Question: "What will these screenshots be used for?"53- Options:54 - "Product Hunt" - Hero shots and feature highlights55 - "Social media" - Eye-catching feature demos56 - "Landing page" - Marketing sections and benefits57 - "Documentation" - UI reference and tutorials5859**Question 3: Authentication**60- Header: "Auth"61- Question: "Does the app require login to access the features you want to screenshot?"62- Options:63 - "No login needed" - Public pages only64 - "Yes, I'll provide credentials" - Need to log in first6566If user selects "Yes, I'll provide credentials", ask follow-up questions:67- "What is the login page URL?" (e.g., `/login`, `/sign-in`)68- "What is the email/username?"69- "What is the password?"7071The script will automatically detect login form fields using Playwright's smart locators.7273## Step 3: Analyze Codebase for Features7475Thoroughly explore the codebase to understand the app and identify screenshot opportunities.7677### 3.1: Read Documentation First7879**Always start by reading these files** to understand what the app does:80811. **README.md** (and any README files in subdirectories) - Read the full README to understand:82 - What the app is and what problem it solves83 - Key features and capabilities84 - Screenshots or feature descriptions already documented85862. **CHANGELOG.md** or **HISTORY.md** - Recent features worth highlighting87883. **docs/** directory - Any additional documentation about features8990### 3.2: Analyze Routes to Find Pages9192Read the routing configuration to discover all available pages:9394| Framework | File to Read | What to Look For |95|-----------|--------------|------------------|96| **Next.js App Router** | `app/` directory structure | Each folder with `page.tsx` is a route |97| **Next.js Pages Router** | `pages/` directory | Each file is a route |98| **Rails** | `config/routes.rb` | Read the entire file for all routes |99| **React Router** | Search for `createBrowserRouter` or `<Route` | Route definitions with paths |100| **Vue Router** | `src/router/index.js` or `router.js` | Routes array with path definitions |101| **SvelteKit** | `src/routes/` directory | Each folder with `+page.svelte` is a route |102| **Remix** | `app/routes/` directory | File-based routing |103| **Laravel** | `routes/web.php` | Route definitions |104| **Django** | `urls.py` files | URL patterns |105| **Express** | Search for `app.get`, `router.get` | Route handlers |106107**Important**: Actually read these files, don't just check if they exist. The route definitions tell you what pages are available for screenshots.108109### 3.3: Identify Key Components110111Look for components that represent screenshottable features:112113- Dashboard components114- Feature sections with distinct UI115- Forms and interactive inputs116- Data visualizations (charts, graphs, tables)117- Modals and dialogs118- Navigation and sidebars119- Settings panels120- User profile sections121122### 3.4: Check for Marketing Assets123124Look for existing marketing content that hints at key features:125- Landing page components (often in `components/landing/` or `components/marketing/`)126- Feature list components127- Pricing tables128- Testimonial sections129130### 3.5: Build Feature List131132Create a comprehensive list of discovered features with:133- Feature name (from README or component name)134- URL path (from routes)135- CSS selector to focus on (from component structure)136- Required UI state (logged in, data populated, modal open, specific tab selected)137138## Step 4: Plan Screenshots with User139140Present the discovered features to the user and ask them to confirm or modify the list.141142Use `AskUserQuestion`:143- Header: "Features"144- Question: "I found these features in your codebase. Which would you like to screenshot?"145- Options: List 3-4 key features discovered, plus "Let me pick specific ones"146147If user wants specific ones, ask follow-up questions to clarify exactly what to capture.148149## Step 5: Create Screenshots Directory150151```bash152mkdir -p screenshots153```154155## Step 6: Generate and Run Playwright Script156157Create a Node.js script that uses Playwright with proper HiDPI settings. The script should:1581591. **Use `deviceScaleFactor: 2`** for true retina resolution1602. **Set viewport to 1440x900** (produces 2880x1800 pixel images)1613. **Handle authentication** if credentials were provided1624. **Navigate to each page** and capture screenshots163164### Script Template165166Write this script to a temporary file (e.g., `screenshot-script.mjs`) and execute it:167168```javascript169import { chromium } from 'playwright';170171const BASE_URL = '[APP_URL]';172const SCREENSHOTS_DIR = './screenshots';173174// Authentication config (if needed)175const AUTH = {176 needed: [true|false],177 loginUrl: '[LOGIN_URL]',178 email: '[EMAIL]',179 password: '[PASSWORD]',180};181182// Screenshots to capture183const SCREENSHOTS = [184 { name: '01-feature-name', url: '/path', waitFor: '[optional-selector]' },185 { name: '02-another-feature', url: '/another-path' },186 // ... add all planned screenshots187];188189async function main() {190 const browser = await chromium.launch();191192 // Create context with HiDPI settings193 const context = await browser.newContext({194 viewport: { width: 1440, height: 900 },195 deviceScaleFactor: 2, // This is the key for true retina screenshots196 });197198 const page = await context.newPage();199200 // Handle authentication if needed201 if (AUTH.needed) {202 console.log('Logging in...');203 await page.goto(AUTH.loginUrl);204205 // Smart login: try multiple common patterns for email/username field206 const emailField = page.locator([207 'input[type="email"]',208 'input[name="email"]',209 'input[id="email"]',210 'input[placeholder*="email" i]',211 'input[name="username"]',212 'input[id="username"]',213 'input[type="text"]',214 ].join(', ')).first();215 await emailField.fill(AUTH.email);216217 // Smart login: try multiple common patterns for password field218 const passwordField = page.locator([219 'input[type="password"]',220 'input[name="password"]',221 'input[id="password"]',222 ].join(', ')).first();223 await passwordField.fill(AUTH.password);224225 // Smart login: try multiple common patterns for submit button226 const submitButton = page.locator([227 'button[type="submit"]',228 'input[type="submit"]',229 'button:has-text("Sign in")',230 'button:has-text("Log in")',231 'button:has-text("Login")',232 'button:has-text("Submit")',233 ].join(', ')).first();234 await submitButton.click();235236 await page.waitForLoadState('networkidle');237 console.log('Login complete');238 }239240 // Capture each screenshot241 for (const shot of SCREENSHOTS) {242 console.log(`Capturing: ${shot.name}`);243 await page.goto(`${BASE_URL}${shot.url}`);244 await page.waitForLoadState('networkidle');245246 // Optional: wait for specific element247 if (shot.waitFor) {248 await page.waitForSelector(shot.waitFor);249 }250251 // Optional: perform actions before screenshot252 if (shot.actions) {253 for (const action of shot.actions) {254 if (action.click) await page.click(action.click);255 if (action.fill) await page.fill(action.fill.selector, action.fill.value);256 if (action.wait) await page.waitForTimeout(action.wait);257 }258 }259260 await page.screenshot({261 path: `${SCREENSHOTS_DIR}/${shot.name}.png`,262 fullPage: shot.fullPage || false,263 });264 console.log(` Saved: ${shot.name}.png`);265 }266267 await browser.close();268 console.log('Done!');269}270271main().catch(console.error);272```273274### Running the Script275276```bash277node screenshot-script.mjs278```279280After running, clean up the temporary script:281```bash282rm screenshot-script.mjs283```284285## Step 7: Advanced Screenshot Options286287### Element-Focused Screenshots288289To screenshot a specific element instead of the full viewport:290291```javascript292const element = await page.locator('[CSS_SELECTOR]');293await element.screenshot({ path: `${SCREENSHOTS_DIR}/element.png` });294```295296### Full Page Screenshots297298For scrollable content, capture the entire page:299300```javascript301await page.screenshot({302 path: `${SCREENSHOTS_DIR}/full-page.png`,303 fullPage: true304});305```306307### Waiting for Animations308309If the page has animations, wait for them to complete:310311```javascript312await page.waitForTimeout(500); // Wait 500ms for animations313```314315### Clicking Elements Before Screenshot316317To capture a modal, dropdown, or hover state:318319```javascript320await page.click('button.open-modal');321await page.waitForSelector('.modal-content');322await page.screenshot({ path: `${SCREENSHOTS_DIR}/modal.png` });323```324325### Dark Mode Screenshots326327If the app supports dark mode:328329```javascript330// Set dark mode preference331const context = await browser.newContext({332 viewport: { width: 1440, height: 900 },333 deviceScaleFactor: 2,334 colorScheme: 'dark',335});336```337338## Step 8: File Naming Convention339340Use descriptive, kebab-case filenames with numeric prefixes for ordering:341342| Feature | Filename |343|---------|----------|344| Dashboard overview | `01-dashboard-overview.png` |345| Link management | `02-link-inbox.png` |346| Edition editor | `03-edition-editor.png` |347| Analytics | `04-analytics.png` |348| Settings | `05-settings.png` |349350## Step 9: Verify and Summarize351352After capturing all screenshots, verify the results:353354```bash355ls -la screenshots/*.png356sips -g pixelWidth -g pixelHeight screenshots/*.png 2>/dev/null || file screenshots/*.png357```358359Provide a summary to the user:3603611. List all generated files with their paths3622. Confirm the resolution (should be 2880x1800 for 2x retina at 1440x900 viewport)3633. Mention total file sizes3644. Suggest any follow-up actions365366Example output:367```368Generated 5 marketing screenshots:369370screenshots/371├── 01-dashboard-overview.png (1.2 MB, 2880x1800 @ 2x)372├── 02-link-inbox.png (456 KB, 2880x1800 @ 2x)373├── 03-edition-editor.png (890 KB, 2880x1800 @ 2x)374├── 04-analytics.png (567 KB, 2880x1800 @ 2x)375└── 05-settings.png (234 KB, 2880x1800 @ 2x)376377All screenshots are true retina-quality (2x deviceScaleFactor) and ready for marketing use.378```379380## Error Handling381382- **Playwright not found**: Suggest `npm install -D playwright`383- **Page not loading**: Check if the dev server is running, suggest starting it384- **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.385- **Element not found**: Verify the CSS selector, offer to take a full page screenshot instead386- **Screenshot failed**: Check disk space, verify write permissions to screenshots directory387388## Tips for Best Results3893901. **Clean UI state**: Use demo/seed data for realistic content3912. **Consistent sizing**: Use the same viewport for all screenshots3923. **Wait for content**: Use `waitForLoadState('networkidle')` to ensure all content loads3934. **Hide dev tools**: Ensure no browser extensions or dev overlays are visible3945. **Dark mode variants**: Consider capturing both light and dark mode if supported395
Full transparency — inspect the skill content before installing.