npm package: @duotech/shots
Description: Automated screenshot capture tool for web applications. Optimized for AI agents.
Latest version: 1.0.4

# @duotech/shots

Automated screenshot capture tool for web applications. Optimized for AI agents.

## Features

- **Simple Configuration** - Define routes in a TypeScript config file
- **Automatic Compression** - JPEG output with configurable quality
- **Mobile Support** - Capture both desktop and mobile viewports
- **Gallery Generator** - HTML gallery for easy viewing
- **Version Management** - Track multiple capture sessions
- **Custom Authentication** - Pluggable auth handlers
- **Pattern Filtering** - Capture specific routes with `--only` and `--exclude`
- **Arbitrary URLs** - Capture any URL with `--urls`

## Installation

```bash
npm install @duotech/shots
# or
pnpm add @duotech/shots
```

Install Playwright browsers:

```bash
npx playwright install chromium
```

## Quick Start

### 1. Create Configuration

```bash
npx shots init
```

This creates `shots.config.ts`:

```typescript
import { defineConfig } from '@duotech/shots';

export default defineConfig({
  baseUrl: 'http://localhost:3000',
  routes: [
    { id: 'home', path: '/' },
    { id: 'login', path: '/login' },
    { id: 'dashboard', path: '/dashboard', auth: true },
  ],
});
```

### 2. Capture Screenshots

```bash
npx shots
```

## CLI Usage

```bash
# Capture all routes
npx shots

# Capture specific routes
npx shots --only home,login

# Exclude routes
npx shots --exclude admin,settings

# Capture arbitrary URLs
npx shots --urls /custom-page,/another-page

# Include mobile viewport
npx shots --mobile

# List captured versions
npx shots --list

# Compare versions
npx shots --compare 20231220-1234
```

### Options

| Flag | Short | Description |
|------|-------|-------------|
| `--config <path>` | `-c` | Config file path |
| `--only <ids>` | `-o` | Only capture matching routes |
| `--exclude <ids>` | `-x` | Exclude matching routes |
| `--urls <urls>` | `-u` | Capture arbitrary URLs |
| `--mobile` | `-m` | Include mobile viewport |
| `--quiet` | `-q` | Less verbose output |
| `--list` | | List available versions |
| `--compare <v>` | | Compare with previous version |
| `--help` | `-h` | Show help |

## Configuration

### Basic Config

```typescript
import { defineConfig } from '@duotech/shots';

export default defineConfig({
  baseUrl: 'http://localhost:3000',
  outputDir: './screenshots',
  routes: [
    { id: 'home', path: '/' },
    { id: 'login', path: '/login' },
  ],
});
```

### Full Config Options

```typescript
import { defineConfig } from '@duotech/shots';

export default defineConfig({
  // Required
  baseUrl: 'http://localhost:3000',
  routes: [...],

  // Optional
  outputDir: './screenshots',          // Default: './screenshots'
  locale: 'fa-IR',                     // Browser locale
  timezone: 'Asia/Tehran',             // Browser timezone

  // Placeholder values for dynamic routes
  placeholders: {
    tenant: 'demo',
    userId: '123',
  },

  // Viewport sizes
  viewports: {
    desktop: { width: 1440, height: 900 },
    mobile: { width: 390, height: 844 },
  },

  // Compression settings
  compression: {
    quality: 70,        // JPEG quality (1-100)
    maxWidth: 1440,     // Max width for desktop
    mobileMaxWidth: 390, // Max width for mobile
  },

  // Gallery configuration
  gallery: {
    title: 'My Screenshots',
    rtl: true,          // RTL support
    dark: true,         // Dark theme
    css: '',            // Custom CSS
  },

  // Custom authentication handler
  auth: async (page) => {
    await page.goto('/api/dev-login?user=test');
    return true;
  },
});
```

### Route Config

```typescript
interface RouteConfig {
  id: string;                    // Unique identifier
  path: string;                  // URL path (supports placeholders)
  description?: string;          // Human-readable description
  category?: string;             // Category for grouping
  auth?: boolean;                // Requires authentication
  action?: ActionType;           // Action before capture
  actionSelector?: string;       // CSS selector for action
  waitForSelector?: string;      // Wait for selector after action
  waitAfterLoad?: number;        // Wait time after load (ms)
  waitAfterAction?: number;      // Wait time after action (ms)
}

type ActionType =
  | 'none'
  | 'click-first-row'
  | 'click-first-card'
  | 'click-button'
  | 'open-modal';
```

### Dynamic Routes with Placeholders

```typescript
export default defineConfig({
  baseUrl: 'http://localhost:3000',
  placeholders: {
    tenant: 'acme',
    workspace: 'main',
  },
  routes: [
    { id: 'dashboard', path: '/{tenant}/{workspace}/dashboard' },
    { id: 'settings', path: '/{tenant}/settings' },
  ],
});
```

### Actions (Click, Modal, etc.)

```typescript
routes: [
  // Click first row in table
  {
    id: 'users-detail',
    path: '/admin/users',
    action: 'click-first-row',
    actionSelector: 'table tbody tr:first-child',
    waitAfterAction: 1000,
  },

  // Open modal
  {
    id: 'new-user-modal',
    path: '/admin/users',
    action: 'open-modal',
    actionSelector: 'button:has-text("Add User")',
    waitForSelector: '[role="dialog"]',
    waitAfterAction: 500,
  },
]
```

## Output Structure

```
screenshots/
├── versions.json                # Index of all versions
├── 20231220-1234-abcd/          # Version folder
│   ├── index.html               # Gallery view
│   ├── home_desktop.jpg
│   ├── login_desktop.jpg
│   ├── login_mobile.jpg
│   └── ...
```

## Programmatic API

```typescript
import { capture, defineConfig } from 'shots';

const config = defineConfig({
  baseUrl: 'http://localhost:3000',
  routes: [
    { id: 'home', path: '/' },
  ],
});

const result = await capture(config, {
  mobile: true,
  only: ['home'],
});

console.log(result);
// {
//   version: '20231220-1234-abcd',
//   successCount: 2,
//   failCount: 0,
//   totalSize: 150000,
//   outputDir: './screenshots/20231220-1234-abcd'
// }
```

## For AI Agents

This tool is optimized for AI agents to verify UI changes:

```bash
# After making UI changes, capture screenshots
npx shots --only affected-page

# View results
open screenshots/*/index.html

# Compare with previous version
npx shots --compare previous-version-id
```

### Pattern Matching

The `--only` and `--exclude` flags match against:
- Route ID: `--only home,login`
- URL path: `--only /admin/users`
- Category: `--only admin`
- Partial match: `--only user` (matches `users`, `user-settings`, etc.)

## License

MIT