Files
Claude-Code-Workflow/.claude/skills/software-manual/scripts/screenshot-helper.md
catlog22 7aa1cda367 feat: add issue discovery view for managing discovery sessions and findings
- Implemented main render function for the issue discovery view.
- Added data loading functions to fetch discoveries, details, findings, and progress.
- Created rendering functions for discovery list and detail sections.
- Introduced filtering and searching capabilities for findings.
- Implemented actions for exporting and dismissing findings.
- Added polling mechanism to track discovery progress.
- Included utility functions for HTML escaping and cleanup.
2025-12-28 17:21:07 +08:00

10 KiB

Screenshot Helper

Guide for capturing screenshots using Chrome MCP.

Overview

This script helps capture screenshots of web interfaces for the software manual using Chrome MCP or fallback methods.

Chrome MCP Prerequisites

Check MCP Availability

async function checkChromeMCPAvailability() {
  try {
    // Attempt to get Chrome version via MCP
    const version = await mcp__chrome__getVersion();
    return {
      available: true,
      browser: version.browser,
      version: version.version
    };
  } catch (error) {
    return {
      available: false,
      error: error.message
    };
  }
}

MCP Configuration

Expected Claude configuration for Chrome MCP:

{
  "mcpServers": {
    "chrome": {
      "command": "npx",
      "args": ["@anthropic-ai/mcp-chrome"],
      "env": {
        "CHROME_PATH": "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe"
      }
    }
  }
}

Screenshot Workflow

Step 1: Prepare Environment

async function prepareScreenshotEnvironment(workDir, config) {
  const screenshotDir = `${workDir}/screenshots`;

  // Create directory
  Bash({ command: `mkdir -p "${screenshotDir}"` });

  // Check Chrome MCP
  const chromeMCP = await checkChromeMCPAvailability();

  if (!chromeMCP.available) {
    console.log('Chrome MCP not available. Will generate manual guide.');
    return { mode: 'manual' };
  }

  // Start development server if needed
  if (config.screenshot_config?.dev_command) {
    const server = await startDevServer(config);
    return { mode: 'auto', server, screenshotDir };
  }

  return { mode: 'auto', screenshotDir };
}

Step 2: Start Development Server

async function startDevServer(config) {
  const devCommand = config.screenshot_config.dev_command;
  const devUrl = config.screenshot_config.dev_url;

  // Start server in background
  const server = Bash({
    command: devCommand,
    run_in_background: true
  });

  console.log(`Starting dev server: ${devCommand}`);

  // Wait for server to be ready
  const ready = await waitForServer(devUrl, 30000);

  if (!ready) {
    throw new Error(`Server at ${devUrl} did not start in time`);
  }

  console.log(`Dev server ready at ${devUrl}`);

  return server;
}

async function waitForServer(url, timeout = 30000) {
  const start = Date.now();

  while (Date.now() - start < timeout) {
    try {
      const response = await fetch(url, { method: 'HEAD' });
      if (response.ok) return true;
    } catch (e) {
      // Server not ready
    }
    await sleep(1000);
  }

  return false;
}

Step 3: Capture Screenshots

async function captureScreenshots(screenshots, config, workDir) {
  const results = {
    captured: [],
    failed: []
  };

  const devUrl = config.screenshot_config.dev_url;
  const screenshotDir = `${workDir}/screenshots`;

  for (const ss of screenshots) {
    try {
      // Build full URL
      const fullUrl = new URL(ss.url, devUrl).href;

      console.log(`Capturing: ${ss.id} (${fullUrl})`);

      // Configure capture options
      const options = {
        url: fullUrl,
        viewport: { width: 1280, height: 800 },
        fullPage: ss.fullPage || false
      };

      // Wait for specific element if specified
      if (ss.wait_for) {
        options.waitFor = ss.wait_for;
      }

      // Capture specific element if selector provided
      if (ss.selector) {
        options.selector = ss.selector;
      }

      // Add delay for animations
      await sleep(500);

      // Capture via Chrome MCP
      const result = await mcp__chrome__screenshot(options);

      // Save as PNG
      const filename = `${ss.id}.png`;
      Write(`${screenshotDir}/${filename}`, result.data, { encoding: 'base64' });

      results.captured.push({
        id: ss.id,
        file: filename,
        url: ss.url,
        description: ss.description,
        size: result.data.length
      });

    } catch (error) {
      console.error(`Failed to capture ${ss.id}:`, error.message);
      results.failed.push({
        id: ss.id,
        url: ss.url,
        error: error.message
      });
    }
  }

  return results;
}

Step 4: Generate Manifest

function generateScreenshotManifest(results, workDir) {
  const manifest = {
    generated: new Date().toISOString(),
    total: results.captured.length + results.failed.length,
    captured: results.captured.length,
    failed: results.failed.length,
    screenshots: results.captured,
    failures: results.failed
  };

  Write(`${workDir}/screenshots/screenshots-manifest.json`,
        JSON.stringify(manifest, null, 2));

  return manifest;
}

Step 5: Cleanup

async function cleanupScreenshotEnvironment(env) {
  if (env.server) {
    console.log('Stopping dev server...');
    KillShell({ shell_id: env.server.task_id });
  }
}

Main Runner

async function runScreenshotCapture(workDir, screenshots) {
  const config = JSON.parse(Read(`${workDir}/manual-config.json`));

  // Prepare environment
  const env = await prepareScreenshotEnvironment(workDir, config);

  if (env.mode === 'manual') {
    // Generate manual capture guide
    generateManualCaptureGuide(screenshots, workDir);
    return { success: false, mode: 'manual' };
  }

  try {
    // Capture screenshots
    const results = await captureScreenshots(screenshots, config, workDir);

    // Generate manifest
    const manifest = generateScreenshotManifest(results, workDir);

    // Generate manual guide for failed captures
    if (results.failed.length > 0) {
      generateManualCaptureGuide(results.failed, workDir);
    }

    return {
      success: true,
      captured: results.captured.length,
      failed: results.failed.length,
      manifest
    };

  } finally {
    // Cleanup
    await cleanupScreenshotEnvironment(env);
  }
}

Manual Capture Fallback

When Chrome MCP is unavailable:

function generateManualCaptureGuide(screenshots, workDir) {
  const guide = `
# Manual Screenshot Capture Guide

Chrome MCP is not available. Please capture screenshots manually.

## Prerequisites

1. Start your development server
2. Open a browser
3. Use a screenshot tool (Snipping Tool, Screenshot, etc.)

## Screenshots Required

${screenshots.map((ss, i) => `
### ${i + 1}. ${ss.id}

- **URL**: ${ss.url}
- **Description**: ${ss.description}
- **Save as**: \`screenshots/${ss.id}.png\`
${ss.selector ? `- **Capture area**: \`${ss.selector}\` element only` : '- **Type**: Full page or viewport'}
${ss.wait_for ? `- **Wait for**: \`${ss.wait_for}\` to be visible` : ''}

**Steps:**
1. Navigate to ${ss.url}
${ss.wait_for ? `2. Wait for ${ss.wait_for} to appear` : ''}
${ss.selector ? `2. Capture only the ${ss.selector} area` : '2. Capture the full viewport'}
3. Save as \`${ss.id}.png\`
`).join('\n')}

## After Capturing

1. Place all PNG files in the \`screenshots/\` directory
2. Ensure filenames match exactly (case-sensitive)
3. Run Phase 5 (HTML Assembly) to continue

## Screenshot Specifications

- **Format**: PNG
- **Width**: 1280px recommended
- **Quality**: High
- **Annotations**: None (add in post-processing if needed)
`;

  Write(`${workDir}/screenshots/MANUAL_CAPTURE.md`, guide);
}

Advanced Options

Viewport Sizes

const viewportPresets = {
  desktop: { width: 1280, height: 800 },
  tablet: { width: 768, height: 1024 },
  mobile: { width: 375, height: 667 },
  wide: { width: 1920, height: 1080 }
};

async function captureResponsive(ss, config, workDir) {
  const results = [];

  for (const [name, viewport] of Object.entries(viewportPresets)) {
    const result = await mcp__chrome__screenshot({
      url: ss.url,
      viewport
    });

    const filename = `${ss.id}-${name}.png`;
    Write(`${workDir}/screenshots/${filename}`, result.data, { encoding: 'base64' });

    results.push({ viewport: name, file: filename });
  }

  return results;
}

Before/After Comparisons

async function captureInteraction(ss, config, workDir) {
  const baseUrl = config.screenshot_config.dev_url;
  const fullUrl = new URL(ss.url, baseUrl).href;

  // Capture before state
  const before = await mcp__chrome__screenshot({
    url: fullUrl,
    viewport: { width: 1280, height: 800 }
  });
  Write(`${workDir}/screenshots/${ss.id}-before.png`, before.data, { encoding: 'base64' });

  // Perform interaction (click, type, etc.)
  if (ss.interaction) {
    await mcp__chrome__click({ selector: ss.interaction.click });
    await sleep(500);
  }

  // Capture after state
  const after = await mcp__chrome__screenshot({
    url: fullUrl,
    viewport: { width: 1280, height: 800 }
  });
  Write(`${workDir}/screenshots/${ss.id}-after.png`, after.data, { encoding: 'base64' });

  return {
    before: `${ss.id}-before.png`,
    after: `${ss.id}-after.png`
  };
}

Screenshot Annotation

function generateAnnotationGuide(screenshots, workDir) {
  const guide = `
# Screenshot Annotation Guide

For screenshots requiring callouts or highlights:

## Tools
- macOS: Preview, Skitch
- Windows: Snipping Tool, ShareX
- Cross-platform: Greenshot, Lightshot

## Annotation Guidelines

1. **Callouts**: Use numbered circles (1, 2, 3)
2. **Highlights**: Use semi-transparent rectangles
3. **Arrows**: Point from text to element
4. **Text**: Use sans-serif font, 12-14pt

## Color Scheme

- Primary: #0d6efd (blue)
- Secondary: #6c757d (gray)
- Success: #198754 (green)
- Warning: #ffc107 (yellow)
- Danger: #dc3545 (red)

## Screenshots Needing Annotation

${screenshots.filter(s => s.annotate).map(ss => `
- **${ss.id}**: ${ss.description}
  - Highlight: ${ss.annotate.highlight || 'N/A'}
  - Callouts: ${ss.annotate.callouts?.join(', ') || 'N/A'}
`).join('\n')}
`;

  Write(`${workDir}/screenshots/ANNOTATION_GUIDE.md`, guide);
}

Troubleshooting

Chrome MCP Not Found

  1. Check Claude MCP configuration
  2. Verify Chrome is installed
  3. Check CHROME_PATH environment variable

Screenshots Are Blank

  1. Increase wait time before capture
  2. Check if page requires authentication
  3. Verify URL is correct

Elements Not Visible

  1. Scroll element into view
  2. Expand collapsed sections
  3. Wait for animations to complete

Server Not Starting

  1. Check if port is already in use
  2. Verify dev command is correct
  3. Check for startup errors in logs