Architecture Guide

A comprehensive, developer-friendly breakdown of the Imposter desktop application. This document explains how every core feature operates under the hood, the major technical challenges faced during development, and solutions that may help you build similar systems.

Electron 33+Node.js 20+Chromium RendererContext IsolationAssemblyAI V3Tesseract.js

Why Electron?

A regular web app can't do what Imposter does. Browsers sandbox JavaScript — they block access to OS-level APIs, enforce CORS on every HTTP request, and have no mechanism for content protection or global keyboard shortcuts.

Electron gives us two worlds: a full Node.js runtime (Main Process) for OS-level operations, and a Chromium browser (Renderer Process) for a rich UI. The cost is the ~150MB binary size, but the benefit is complete OS control with a web-tech UI — exactly what a stealth overlay application needs.

0ms
CORS Overhead
3
Renderer Windows
100%
Local Data Storage

1. The Multi-Process Model

Electron uses a multi-process architecture modeled after Chromium. Each process is isolated — a crash in one renderer doesn't take down the main process or other windows. Understanding this separation is key.

M

Main Process

src/main/ • Node.js Runtime

  • Window Management — Creating and destroying the transparent glass windows (Main Chat, Snipper overlay, Dynamic Island). Each is a separate BrowserWindow instance.
  • Global Shortcuts — Registering system-wide keyboard shortcuts via globalShortcut.register(). These fire even when Imposter is not focused.
  • Network I/O — All external HTTP and WebSocket traffic (Ollama, OpenRouter, AssemblyAI) flows through Main to bypass browser CORS.
  • OCR Engine — Runs tesseract.js in-process for pixel-to-text extraction.
  • Lifecycle — App bootstrap, graceful shutdown, and crash recovery.
R

Renderer Process

src/renderer/ • Chromium Sandbox

  • Chat Interface — Main window. Markdown rendering (GFM), syntax-highlighted code blocks, conversation history, settings panel.
  • Dynamic Island — A tiny pill-shaped overlay window for real-time transcription text. Separate renderer, separate lifecycle.
  • Snipper Window — Temporary fullscreen transparent overlay for region selection. Spawned on-demand, destroyed after crop.
  • Audio Worklets — Custom AudioWorkletProcessor for slicing raw PCM audio into 100ms buffered chunks.
  • Local Storage — Personas, resume, job description, and API keys are stored client-side.
B

The Bridge

preload.js • Context Isolation

  • The Renderer cannot import Node modules directly — contextIsolation: true enforces this boundary.
  • preload.js uses contextBridge.exposeInMainWorld() to inject a safe window.electronAPI object.
  • Each method maps to a specific ipcRenderer.invoke() or ipcRenderer.on() channel.
  • Channels are hard-coded — the UI cannot call arbitrary IPC channels. This prevents prototype pollution attacks.

Architecture Diagram

Architecture Diagram

IPC Communication Patterns

Request → Response

Mechanism: ipcRenderer.invoke(channel, data)

Used for: AI chat queries, OCR results, model list fetching.

Fire & Forget

Mechanism: ipcRenderer.send(channel, data)

Used for: Audio chunk streaming, window state changes.

Main → Renderer Push

Mechanism: win.webContents.send(channel, data)

Used for: Live transcription text, screenshot delivery, settings sync.

2. Feature Deep-Dives

A

The Stealth Mode UI System

Create a UI that floats above everything, doesn't show up in screen sharing, and hides from the taskbar.

1

Window Creation

The Main Process creates a BrowserWindow with transparent: true, frame: false, and skipTaskbar: true. This makes the window completely invisible in system UI — no title bar, no taskbar entry.

2

Z-Order Pinning

win.setAlwaysOnTop(true, 'screen-saver') pins the window at the screen-saver z-level — above almost every other OS element, including fullscreen applications.

3

Content Protection (DRM)

win.setContentProtection(true) leverages OS-level DRM to prevent screen recording tools (OBS, Teams, Zoom) from seeing the window. It renders as a black rectangle to capture APIs.

4

Glassmorphism Layer

With opacity: 0.9 and CSS backdrop-filter: blur(), the window blends into whatever is behind it as a floating glass panel.

B

Screen Snipping & OCR Pipeline

Let the user draw a box on the screen, capture the text inside it, and insert it into the prompt.

1

Global Shortcut Trigger

User presses Ctrl+Shift+S. The Main Process intercepts via globalShortcut.register().

2

Desktop Capture

Main Process uses desktopCapturer.getSources() to take a full-screen screenshot as a NativeImage buffer.

3

Region Selection

The user draws a rectangle on the frozen screenshot overlay. The Snipper captures coordinates (x, y, w, h).

4

Crop & OCR

Main Process crops the original screenshot then feeds the pixel buffer to tesseract.js which runs entirely locally.

5

Text Delivery

Extracted text is sent via IPC to the Chat Renderer and auto-appended to the prompt textarea.

C

Real-Time Voice Transcription

Capture system audio, stream it to AssemblyAI for live transcription, and display rolling text in the Dynamic Island overlay.

1

Audio Capture

Renderer uses navigator.mediaDevices.getDisplayMedia({ audio: true }) to capture speaker output directly.

2

AudioWorklet Processing

Raw audio is piped into a custom AudioWorkletProcessor that buffers 100ms of 16kHz mono PCM samples.

3

IPC Relay

The Worklet posts base64-encoded audio chunks to the Renderer, which relays them to Main Process via ipcRenderer.send('audio-chunk').

4

WebSocket to AssemblyAI

Main Process manages a persistent WSS connection to AssemblyAI's Streaming API. Audio chunks are funneled into the socket.

5

Dual-Window Broadcast

Finalized transcription JSON is broadcast to both the Chat Window and the Dynamic Island Window via webContents.send().

Dev Tip: Press F10 to grab the last finalized transcript and send it directly to the AI chat engine as a prompt — voice-to-AI in one keystroke.
D

Multi-Provider AI Orchestration

Query local models (Ollama) or cloud models (OpenRouter) seamlessly, enriched with contextual data.

1

Context Assembly

Renderer pulls Persona, System Prompt, Resume, and Job Description from LocalStorage and merges them into a hidden system message.

2

Provider Selection

The UI determines whether to hit Ollama (fully local) or OpenRouter (cloud) based on user settings.

3

CORS-Free Fetch

Main Process uses native net.fetch() to perform Node.js network calls that bypass all browser CORS policies.

4

Response Delivery

The AI response (Markdown) is pushed back to the Renderer and rendered with GFM support and syntax highlighting.

3. Window Lifecycle Management

WindowCreatedLifetimeDRMZ-Order
Chat (Main)App bootPersistentYESscreen-saver level
Dynamic IslandApp bootPersistentYESscreen-saver level
SnipperOn shortcutEphemeralNOFullscreen

4. Security Model

Context Isolation

Renderers cannot access Node.js. All OS interactions go through hard-coded IPC channels in preload.js.

Zero Cloud Storage

Personas, resumes, API keys, and history are stored in browser LocalStorage. No telemetry or analytics.

Network Minimalism

Only user-configured LLM and optional transcription connections exist. No phantom outbound traffic.

Volatile Runtime

No disk-level session persistence beyond explicit data. memory state is destroyed on app close.

5. Challenges & Solutions

Silent crashes on API failures or network timeouts
Deep, process-level crash guards: uncaughtException and unhandledRejection handlers. Every IPC call is wrapped in try/catch with a 120s AbortController.
WebSocket connections to AssemblyAI randomly dropping or hanging
Aggressive isConnecting state flag and 15s connection timeout. Teardown logic individually cleans up AudioContext, tracks, and sockets.
CORS errors when calling OpenRouter/Ollama from the UI
All API traffic is proxied through the Main Process using net.fetch(). The Renderer never makes direct HTTP calls to external services.
White screen on high load (Render Process Gone)
Listener on render-process-gone instantly destroys the corrupted Chromium process and spawns a fresh replacement window.
AssemblyAI Error 3007: Input Duration Violation
Custom AudioWorkletProcessor accumulates samples in a ring buffer and only flushes when 100ms of audio is available.

6. Contributing

Imposter is open source. Here's how to get started:

# Clone and install
git clone https://github.com/Puskar-Roy/Imposter.git
npm install && npm run dev