# What Is @escrcpy/wscrcpy? Architecture and Purpose in Escrcpy

> Discover @escrcpy/wscrcpy, the core WebSocket Scrcpy package. Learn its architecture and purpose in powering the Escrcpy Electron app with its Vue and TypeScript implementation.

- Repository: [viarotel-org/escrcpy](https://github.com/viarotel-org/escrcpy)
- Tags: architecture
- Published: 2026-09-10

---

**@escrcpy/wscrcpy is the core WebSocket Scrcpy package that powers the Escrcpy Electron application, providing a self-contained Vue and TypeScript module implementing the full Scrcpy protocol over WebSockets with strict separation between renderer and main-process APIs.**

The `viarotel-org/escrcpy` repository uses `@escrcpy/wscrcpy` to encapsulate all Android screen mirroring and device control logic. This package exposes a clean boundary between the Electron main process (handling TCP streams via ADB) and the Vue-based renderer (displaying video and capturing input), ensuring the protocol stack remains isolated from UI concerns.

## Dual-Entry Architecture

The package enforces a strict process-separation model through two distinct entry points. According to [AGENTS.md](https://github.com/viarotel-org/escrcpy/blob/main/AGENTS.md#L11), the package root exports the **renderer-facing API** (Vue components, composables, and utilities), while `@escrcpy/wscrcpy/main` exports the **ByteBridge factory** for the main process.

This design prevents accidental cross-process imports: the renderer must never import the main entry, and the main process must never import the renderer root. The boundary ensures that low-level TCP socket handling stays in the main process while UI interactions remain in the Chromium sandbox.

## Core Components and File Structure

### The ByteBridge Service

In [`packages/wscrcpy/service/bridge/index.ts`](https://github.com/viarotel-org/escrcpy/blob/main/packages/wscrcpy/service/bridge/index.ts), the ByteBridge implements a thin **TCP ⇄ MessagePort pump** that transports raw Scrcpy streams between the Android device (accessed via ADB) and the renderer process. As noted in [AGENTS.md](https://github.com/viarotel-org/escrcpy/blob/main/AGENTS.md#L12), this service layer runs entirely in the main process and manages back-pressure handling for video and audio streams.

### Protocol Stack Implementation

The Scrcpy protocol logic—including packet parsing, channel multiplexing, and sequence handling—resides in `packages/wscrcpy/src/stack/`. This directory contains the full state machine required to decode H.264 video frames and inject input events, operating independently of Electron APIs.

### Runtime Channel Routing

[`packages/wscrcpy/src/core/runtime.ts`](https://github.com/viarotel-org/escrcpy/blob/main/packages/wscrcpy/src/core/runtime.ts) routes every incoming WebSocket channel to the correct local stack instance based on the active window. As documented in [AGENTS.md](https://github.com/viarotel-org/escrcpy/blob/main/AGENTS.md#L12), this runtime acts as a demultiplexer, ensuring that multiple concurrent device sessions do not interfere with each other.

## Practical Usage Examples

### Renderer-Side Component Integration

Import the `Wscrcpy` Vue component from the package root to render the device screen and handle user input:

```typescript
import { defineComponent } from 'vue'
import Wscrcpy from '@escrcpy/wscrcpy'

export default defineComponent({
  components: { Wscrcpy },
  template: `
    <div class="device-container">
      <Wscrcpy :device-id="deviceId" :options="scrcpyOptions" />
    </div>
  `,
  data() {
    return {
      deviceId: 'emulator-5554',
      scrcpyOptions: {
        videoCodec: 'h264',
        maxFps: 60,
        turnScreenOff: true
      }
    }
  }
})

```

### Connection Management Composable

For imperative control over sessions, use the `useWscrcpyConnection` composable exported from [`packages/wscrcpy/src/composables/useWscrcpyConnection.ts`](https://github.com/viarotel-org/escrcpy/blob/main/packages/wscrcpy/src/composables/useWscrcpyConnection.ts):

```typescript
import { useWscrcpyConnection } from '@escrcpy/wscrcpy'

const { start, stop, status, error } = useWscrcpyConnection({
  deviceId: '192.168.1.5:5555',
  audio: true,
  clipboardAutosync: false,
  displayId: 0
})

// Start the mirroring session
await start()

// Check connection state
console.log('Connection status:', status.value)

// Gracefully terminate
await stop()

```

### Main-Process Bridge Initialization

In the Electron main process, initialize the TCP bridge using the dedicated `/main` entry point:

```typescript
import { createWscrcpyByteBridge } from '@escrcpy/wscrcpy/main'
import path from 'path'

const bridge = createWscrcpyByteBridge({
  adbPath: path.join(process.resourcesPath, 'platform-tools', 'adb'),
  scrcpyPath: path.join(process.resourcesPath, 'scrcpy', 'scrcpy'),
  maxBuffer: 1024 * 1024 // 1MB buffer for video frames
})

// Register IPC handlers to communicate with renderer
bridge.registerIpcHandlers()

```

## Configuration Types and Constants

### DeviceTarget and Channel Contracts

The package defines strict TypeScript contracts for device targeting. According to [SKILL.md](https://github.com/viarotel-org/escrcpy/blob/main/.github/skills/escrcpy/SKILL.md#L42), the `DeviceTarget` type accepts `'all'`, `'primary'`, a specific serial string, or an array of serials. Additionally, the `SCRCPY_CHANNELS` constants define the official IPC channel names that must be used across the application boundary.

### Audio and Clipboard Defaults

Audio forwarding is **opt-in by default** on macOS systems due to platform limitations, as specified in [AGENTS.md](https://github.com/viarotel-org/escrcpy/blob/main/AGENTS.md#L56). The `createScrcpyOptions` helper in [`packages/wscrcpy/src/options.ts`](https://github.com/viarotel-org/escrcpy/blob/main/packages/wscrcpy/src/options.ts) builds command-line arguments respecting these defaults, allowing developers to explicitly enable audio or disable clipboard autosync through the options interface.

## Summary

- **@escrcpy/wscrcpy** encapsulates the entire Scrcpy protocol implementation as a reusable Vue/TypeScript module within the Escrcpy ecosystem.
- The package enforces **strict process separation** via two entry points: the renderer API (package root) and the main-process ByteBridge (`@escrcpy/wscrcpy/main`).
- **Service/bridge/** handles the TCP ⇄ MessagePort pump in the main process, while **src/stack/** contains the protocol decoding logic.
- **Runtime routing** in [`src/core/runtime.ts`](https://github.com/viarotel-org/escrcpy/blob/main/src/core/runtime.ts) manages multiple concurrent device sessions without cross-contamination.
- Configuration follows strict types including `DeviceTarget` and respects platform-specific defaults like macOS audio opt-in.

## Frequently Asked Questions

### What is the difference between importing from `@escrcpy/wscrcpy` versus `@escrcpy/wscrcpy/main`?

The package root (`@escrcpy/wscrcpy`) exports Vue components, composables, and renderer utilities that run inside the Chromium sandbox. The `@escrcpy/wscrcpy/main` entry exports the ByteBridge factory and low-level TCP handlers that must only execute in the Node.js-backed Electron main process. Importing the wrong entry into the wrong process will break IPC communication and likely crash the application due to missing Node APIs in the renderer or security restrictions in the main process.

### How does @escrcpy/wscrcpy handle audio forwarding from Android devices?

Audio support is implemented in the protocol stack (`src/stack/`) but is **disabled by default on macOS** as documented in [AGENTS.md](https://github.com/viarotel-org/escrcpy/blob/main/AGENTS.md#L56). Developers must explicitly set `audio: true` in the connection options. The audio stream travels through the same ByteBridge service as video, but uses separate channel multiplexing to maintain synchronization. On Linux and Windows, audio may be enabled by default depending on the Scrcpy binary version bundled with the application.

### Where is the Scrcpy protocol logic actually implemented?

The complete protocol implementation—including H.264 packet parsing, input event injection, and clipboard synchronization—lives in `packages/wscrcpy/src/stack/`. This directory operates as a standalone state machine that processes raw TCP streams from the ByteBridge service. The [`runtime.ts`](https://github.com/viarotel-org/escrcpy/blob/main/runtime.ts) file in `src/core/` then routes these decoded frames and events to the appropriate Vue component instance based on the active window ID.

### Can I use @escrcpy/wscrcpy outside of the Escrcpy Electron application?

While the package is architected for Electron’s main/renderer split, the protocol stack (`src/stack/`) and option builders ([`src/options.ts`](https://github.com/viarotel-org/escrcpy/blob/main/src/options.ts)) are framework-agnostic TypeScript modules. However, the ByteBridge service specifically relies on Electron’s IPC (`MessagePort`) and Node.js socket APIs. To use the package in a different environment (such as a plain Node.js CLI or a different UI framework), you would need to reimplement the bridge service while retaining the protocol stack and type definitions.