src — screen-capture

Module: src-screen-capture Cohesion: 0.80 Members: 0

src — screen-capture

The src/screen-capture module provides a comprehensive, event-driven API for programmatically taking screenshots and recording screen activity. It offers capabilities to discover available displays and windows, capture specific regions, and manage the lifecycle of recording sessions.

Important Note: This module currently implements a mock version of the screen capture functionality. It simulates operations like taking screenshots and recording, generating mock data and paths, but does not interact with the actual operating system's screen capture APIs. A real implementation would integrate with native modules or external tools (e.g., ffmpeg, scrot).

1. Core Concepts and Types

The module defines several key types to represent capture sources, options, and results. These are exported from src/screen-capture/types.ts.

Capture Sources and Regions

Display and Window Information

Screenshot Types

Recording Types

Configuration

Events

2. CaptureManager Class

The CaptureManager class (src/screen-capture/capture-manager.ts) is the central interface for all screen capture and recording operations. It extends Node.js's EventEmitter to provide event-driven feedback on capture progress and status.

classDiagram
    EventEmitter <|-- CaptureManager
    CaptureManager "1" *-- "0..1" RecordingContext
    CaptureManager "1" *-- "N" DisplayInfo
    CaptureManager "1" *-- "N" WindowInfo
    CaptureManager "1" *-- "1" ScreenCaptureConfig

    class CaptureManager {
        +constructor(config?: Partial<ScreenCaptureConfig>)
        +getDisplays(): Promise<DisplayInfo[]>
        +getPrimaryDisplay(): Promise<DisplayInfo | undefined>
        +getWindows(): Promise<WindowInfo[]>
        +findWindows(titlePattern: string | RegExp): Promise<WindowInfo[]>
        +takeScreenshot(options?: Partial<ScreenshotOptions>): Promise<ScreenshotResult>
        +takeScreenshots(count: number, intervalMs: number, options?: Partial<ScreenshotOptions>): Promise<ScreenshotResult[]>
        +startRecording(options: RecordingOptions): Promise<void>
        +pauseRecording(): void
        +resumeRecording(): void
        +stopRecording(): Promise<RecordingResult>
        +cancelRecording(): void
        +getRecordingStatus(): RecordingStatus
        +isRecording(): boolean
        +isPaused(): boolean
        +getConfig(): ScreenCaptureConfig
        +updateConfig(config: Partial<ScreenCaptureConfig>): void
        +getStats(): object
        -initializeMockData(): void
        -resolveRegion(options): Promise<CaptureRegion>
        -generateMockImage(region, options): Buffer
        -generateFilePath(type, format): string
        -calculateRecordingDuration(): number
    }
    class RecordingContext {
        options: RecordingOptions
        state: RecordingState
        startedAt: Date
        pausedAt?: Date
        frameCount: number
        droppedFrames: number
        pausedDuration: number
        region: CaptureRegion
        interval: NodeJS.Timeout | null
    }
    class ScreenCaptureConfig {
        screenshotDefaults: Partial<ScreenshotOptions>
        recordingDefaults: Partial<RecordingOptions>
        outputDir: string
        namingPattern: string
        maxConcurrent: number
        hardwareAcceleration: boolean
    }
    class DisplayInfo {
        id: string
        name: string
        bounds: CaptureRegion
        isPrimary: boolean
        scaleFactor: number
        refreshRate?: number
    }
    class WindowInfo {
        id: string
        title: string
        processName?: string
        bounds: CaptureRegion
        isMinimized: boolean
        isVisible: boolean
        pid?: number
    }
    class CaptureRegion {
        x: number
        y: number
        width: number
        height: number
    }

2.1. Initialization and Configuration

2.2. Display and Window Discovery (Mocked)

These asynchronous methods provide information about available screens and windows. In this mock implementation, they return predefined static data initialized by initializeMockData().

2.3. Screenshot Functionality

The manager supports both single and multiple screenshot operations.

2.4. Recording Functionality

The manager provides a full lifecycle for screen recording, including start, pause, resume, and stop.

2.5. Private Helpers

The CaptureManager uses several private methods for internal logic:

2.6. Events Emitted

The CaptureManager emits the following events, which can be subscribed to using manager.on():

3. Singleton Access

For convenience and to ensure a single point of control for screen capture operations, the module provides a singleton pattern:

4. Module Entry Point (src/screen-capture/index.ts)

This file serves as the public API for the screen capture module. It re-exports all necessary types, default options, and the CaptureManager class along with its singleton access functions, making them easily importable.

5. Usage Examples

Getting the Manager and Configuration

import { getCaptureManager, DEFAULT_SCREEN_CAPTURE_CONFIG } from &#39;./screen-capture/index.js&#39;;

class="hl-cmt">// Get the singleton instance, optionally providing initial config
const manager = getCaptureManager({
  outputDir: &#39;./my-captures&#39;,
  namingPattern: &#39;capture_{type}_{timestamp}&#39;,
});

console.log(&#39;Current config:&#39;, manager.getConfig());

class="hl-cmt">// Update configuration later
manager.updateConfig({ hardwareAcceleration: false });

Discovering Displays and Windows

import { getCaptureManager } from &#39;./screen-capture/index.js&#39;;

const manager = getCaptureManager();

async function discover() {
  const displays = await manager.getDisplays();
  console.log(&#39;Displays:&#39;, displays);

  const primaryDisplay = await manager.getPrimaryDisplay();
  console.log(&#39;Primary Display:&#39;, primaryDisplay);

  const windows = await manager.getWindows();
  console.log(&#39;Visible Windows:&#39;, windows);

  class="hl-cmt">// Find windows by title pattern (case-insensitive regex)
  const terminalWindows = await manager.findWindows(/terminal/i);
  console.log(&#39;Terminal Windows:&#39;, terminalWindows);
}

discover();

Taking a Screenshot

import { getCaptureManager } from &#39;./screen-capture/index.js&#39;;

const manager = getCaptureManager();

class="hl-cmt">// Listen for events
manager.on(&#39;screenshot-complete&#39;, (result) => {
  console.log(`Screenshot saved to: ${result.path}`);
  console.log(`Image size: ${result.width}x${result.height}, ${result.size} bytes`);
});

manager.on(&#39;screenshot-error&#39;, (error) => {
  console.error(&#39;Screenshot failed:&#39;, error.message);
});

async function takeMyScreenshot() {
  try {
    const primaryDisplay = await manager.getPrimaryDisplay();
    if (!primaryDisplay) {
      console.error(&#39;No primary display found.&#39;);
      return;
    }

    class="hl-cmt">// Take a single screenshot of the primary display with a delay
    const result = await manager.takeScreenshot({
      displayId: primaryDisplay.id,
      format: &#39;jpeg&#39;,
      quality: 85,
      delayMs: 1000, class="hl-cmt">// 1 second delay
    });
    console.log(&#39;Screenshot operation complete (promise resolved).&#39;);

    class="hl-cmt">// Take multiple screenshots with an interval
    const results = await manager.takeScreenshots(3, 2000, {
      format: &#39;png&#39;,
      path: &#39;./my-captures/series.png&#39; class="hl-cmt">// Will generate series_0.png, series_1.png, etc.
    });
    console.log(`Captured ${results.length} screenshots in a series.`);

  } catch (error) {
    console.error(&#39;Error during screenshot:&#39;, error);
  }
}

takeMyScreenshot();

Recording the Screen

import { getCaptureManager } from &#39;./screen-capture/index.js&#39;;

const manager = getCaptureManager();

class="hl-cmt">// Listen for recording events
manager.on(&#39;recording-start&#39;, (options) => console.log(&#39;Recording started with options:&#39;, options));
manager.on(&#39;recording-progress&#39;, (status) => {
  console.log(`Recording state: ${status.state}, Duration: ${status.durationMs}ms, Frames: ${status.frameCount}`);
});
manager.on(&#39;recording-pause&#39;, () => console.log(&#39;Recording paused.&#39;));
manager.on(&#39;recording-resume&#39;, () => console.log(&#39;Recording resumed.&#39;));
manager.on(&#39;recording-complete&#39;, (result) => {
  console.log(`Recording complete! Saved to: ${result.path}, Duration: ${result.durationMs}ms`);
});
manager.on(&#39;recording-error&#39;, (error) => console.error(&#39;Recording error:&#39;, error.message));

async function recordMyScreen() {
  try {
    const primaryDisplay = await manager.getPrimaryDisplay();
    if (!primaryDisplay) {
      console.error(&#39;No primary display found.&#39;);
      return;
    }

    await manager.startRecording({
      path: &#39;./my-captures/my-recording.mp4&#39;,
      displayId: primaryDisplay.id,
      fps: 25,
      maxDurationMs: 10000, class="hl-cmt">// Record for 10 seconds of active time
    });

    console.log(&#39;Recording in progress...&#39;);

    class="hl-cmt">// Simulate pausing after 3 seconds
    setTimeout(() => {
      if (manager.isRecording()) {
        manager.pauseRecording();
        console.log(&#39;Recording paused for 2 seconds.&#39;);
      }
    }, 3000);

    class="hl-cmt">// Simulate resuming after 5 seconds (2 seconds after pause)
    setTimeout(() => {
      if (manager.isPaused()) {
        manager.resumeRecording();
        console.log(&#39;Recording resumed.&#39;);
      }
    }, 5000);

    class="hl-cmt">// The recording will automatically stop after maxDurationMs (10 seconds total active recording)
    class="hl-cmt">// You could also manually stop it:
    class="hl-cmt">// setTimeout(async () => {
    class="hl-cmt">//   if (manager.isRecording() || manager.isPaused()) {
    class="hl-cmt">//     const result = await manager.stopRecording();
    class="hl-cmt">//     console.log(&#39;Manually stopped recording.&#39;);
    class="hl-cmt">//   }
    class="hl-cmt">// }, 12000); // Stop after 12 seconds total elapsed time
  } catch (error) {
    console.error(&#39;Failed to start recording:&#39;, error);
  }
}

recordMyScreen();

6. Mock Implementation Details

It's crucial to understand that this module is a mock. This means:

This mock implementation is valuable for:

A real implementation would replace the mock logic in methods like initializeMockData, generateMockImage, and the setInterval loop in startRecording with calls to native OS APIs or external tools (e.g., scrot for screenshots, ffmpeg for recordings).

7. Connections to the Wider Codebase

This module is designed to be a self-contained utility for screen capture.

This module provides a robust, albeit mocked, foundation for screen capture and recording, ready for integration with native capabilities when required.