---
title: Screenshot / Snip Tool
---

# Screenshot / Snip Tool

## What it is

The Snip Tool is the image-capture half of Omniscio's built-in screen capture — trigger a snip and a region selector appears; when you finish selecting a region, Omniscio saves the PNG to the **Screenshots** library, copies it to the clipboard, and fires a shutter sound and toast per your notification settings. On **Windows** the selector is a fast **native Win32/GDI overlay** (a bundled helper, `snip-overlay.exe`); on **macOS/Linux** it is the OS-native region tool. It's the sibling of the [Screen Recorder](screen-recorder.md): both write to the same `screen_recordings` table (a snip is a row with `type='image'`), so the store, viewer, and share surfaces are shared infrastructure rather than parallel features — but each has its own type-scoped library (see below).

The Snip Tool lives in its **own sidebar entry, "Screenshots"** (`__screenshots__`, Image icon, sky-400, under the **Productivity** group), split out of the former unified "Screen Capture" panel **2026-08-03**. It is a distinct integration from **[Screen Recording](screen-recorder.md)** (`__screen_recordings__`, the video half). The two share the `screen_recordings` table and the store, but each has its **own independent on/off toggle** (split **2026-08-08**): Screenshots is gated by **`screenshotsEnabled`**, Screen Recording by `screenRecorderEnabled` — turning one off hides only that area (and, for Screenshots, unbinds the snip hotkey) and leaves the other running. Both default **off** for a new install; an existing install that had the former unified "Screen Capture" on is carried forward to `screenshotsEnabled = true` by a one-time migration, so nobody loses their Screenshots area on upgrade. A snip appears in the **Screenshots** library as a **Snip** card; clicking it opens the **snip viewer** (a zoomable lightbox with rename / share / discard / reveal). The Screenshots library shows **only** snips (no videos), with its own Recovered section.

> **Desktop app only.** Capture uses the OS native snipping experience and Electron's clipboard/file APIs — not available in a headless CLI or a mobile/web browser.

## Where to find it

### How to trigger a snip

Four entry points start a snip:

1. **Global hotkey** — default **`Ctrl/Cmd+Alt+S`**, rebindable in the **Screenshots settings** panel (the gear icon in the Screenshots header, `screenshotSnipHotkey`). The hotkey registers only while `screenshotsEnabled` is on. On macOS the default is not claimed when it conflicts with the system shortcut; a user-chosen rebind always registers. The library shows a hint naming the current binding and refreshes it live on a rebind via the `screenshot:hotkey-status-changed` push.
2. **Tray menu → Take snip** — right-click the Omniscio tray / menu-bar icon and choose **Take snip**.
3. **New snip button** — the **New snip** button in the Screenshots library header.
4. **Quick-launch** — the quick-launch palette, if configured for snip.

## How it behaves

### How region selection works (per platform)

### Windows — native GDI overlay (v5, resident helper)

Triggering a snip runs a small **native Win32/GDI helper** (`snip-overlay.exe`, bundled with Omniscio). It captures every monitor to a frozen backdrop at true physical pixels, then draws an **instant** topmost selection overlay across your whole desktop (the frozen capture, dimmed, with a live drag rectangle). You drag a rectangle and it crops exactly that region natively. Because the desktop is frozen at the moment you triggered, open menus and hover states are captured just as you saw them.

This is the AutoHotkey-style native approach, and it replaced the earlier Electron selection window (v3) — which was correct but **slow** (each snip reloaded a window carrying the full app preload, ~3–4s). Drawing the overlay natively opens it in **milliseconds**, with no Electron window in the path. It is declared Per-Monitor-V2 DPI-aware and works entirely in physical pixels, so the crop is **pixel-exact on any mixed-DPI multi-monitor arrangement** — including a rotated **portrait** monitor at a negative origin (the exact case that broke the original v1 overlay; a native window has no Chromium work-area clamp). **Esc always cancels** system-wide via a low-level keyboard hook, even if the overlay never took keyboard focus.

**Resident helper (v5).** The helper is launched **once** at startup (behind the renderer-ready gate, so it never competes with the app's own boot) and kept idle in the background; each press just **signals the already-running helper** instead of launching a new process. This matters because Windows Defender scans an unsigned executable on *every* launch (~¼ second measured) — so the earlier launch-per-press design still paid that scan on each snip, while a resident process is scanned once. The full-screen dim is also computed with a fast parallel darken (identical look). The result is a snip that opens **instantly**, matching a resident AutoHotkey tool. If the resident helper is ever unavailable or crashes, Omniscio automatically falls back to launching it per-press, so snipping never breaks; the helper also exits with the app (it can't linger as an orphan process).

**Scope:** the overlay spans **all** monitors — drag anywhere. If the capture itself fails, Omniscio shows a **clear error** — it never silently saves a full-screen image.

> **Legacy setting.** The **Capture engine** toggle (`screenRecorderSnipCaptureEngine`) is a leftover from v3 and **no longer has any effect** — the v4 native helper always self-captures. It is slated for removal.

**Cancelling** — Esc, or a click without a drag — saves nothing and is silent.

### macOS

Triggering a snip runs `screencapture -i`, the native macOS crosshair/selection mode. Drag to select a region, click a window, or use the on-screen controls; press Esc to cancel. Omniscio collects the resulting capture file from the known output location.

### Linux

Omniscio tries the best available tool in order: `gnome-screenshot -i`, `spectacle -r`, `slurp | grim -g -` — the first one found is used.

### How the result lands in the library

After a successful capture on any platform:

1. The instant a real crop exists (a non-empty PNG), a `screenshot:capture-sound` push fires and the renderer plays the shutter tone — **before** any of the save work below — so the "captured!" feedback is immediate instead of trailing the whole pipeline.
2. The PNG is written to `<userData>/screen-recordings/screenshots/<uuid>.png` (plus a sidecar `<uuid>.sidecar.json` for annotations).
3. A `screen_recordings` row is inserted with `type='image'`.
4. The PNG is copied to the system clipboard.
5. A `screenshot:captured` push fires with `{ recordId, clipboardCopied }`, and the post-capture toast appears per your notification settings (the shutter sound already played in step 1). See the native-snip contract I18 for why the sound is decoupled from this receipt.

**When Omniscio isn't focused, the toast comes to you.** You usually snip while working in another app, so if the Omniscio window isn't focused/visible the post-capture toast — with its **Annotate** and **Share** buttons — appears as a small floating window over whatever app you're in, instead of staying hidden inside Omniscio. Clicking **Annotate** brings Omniscio forward with the snip open in the editor; **Share** copies a link right there. When Omniscio _is_ focused you get the normal in-app toast. The floating toast never steals focus from your current app, auto-dismisses after a few seconds, and obeys the same capture-notification level (all / errors only / off).

**Copy-only mode** (`screenRecorderSnipCopyOnly`) puts the capture on the clipboard only — no library row is written.

**Cancelling** the selection saves nothing and fires no events.

### Settings (Screenshots settings panel)

The gear icon in the **Screenshots** header opens the **Screenshots settings** page — its own page since the **2026-08-08** split (Screen Recording has a separate page; neither shows the other's options). Snip-specific controls:

- **Snip hotkey** (`screenshotSnipHotkey`) — rebind the global trigger. Default `Ctrl/Cmd+Alt+S`. The library shows a hint if the binding couldn't register.
- **Capture notifications** (`screenRecorderSnipCaptureNotifications`) — `All` (default) shows a success toast after every snip; `Errors only` silences the routine toast but still warns on failures; `Off` suppresses all snip toasts. Applied live — no restart needed.
- **Capture sound** (`screenRecorderSnipCaptureSound`) — plays a short synthesized shutter tone the **instant a snip is captured**. Default **on**. It fires on a dedicated `screenshot:capture-sound` push the moment a real crop exists — before the PNG is saved, the row written, or the clipboard set — so it's immediate rather than trailing the save; the sound means "captured", not "saved" (a rare post-capture save/clipboard failure still plays it, then shows an error). Pressing the hotkey fires `screenshot:snip-armed` first, which warms the background-suspended audio during your selection so the tone has no wake-up lag. Independent of the notification level (plays even when toasts are `Errors only` / `Off`); never plays for a cancelled snip, a genuinely failed capture, or Snip-to-Text (OCR). Deliberately not routed through the throttled notification-sound system. See native-snip contract I18.
- **Copy-only** (`screenRecorderSnipCopyOnly`) — when on, snips go to the clipboard only; no library row is saved.
- **Snip to Text (OCR)** (`screenshotOcrEnabled`) — off by default. When on, a **Snip to Text** button appears (Windows only for now) that reads the text out of a captured region via Claude Vision. Each capture is a paid Anthropic API call, tracked in your spend under the `screenshot-ocr` source (model via `screenshotOcrModel`, default Sonnet).
- **Capture engine** (`screenRecorderSnipCaptureEngine`, **Windows only**) — **legacy / no effect in v4.** It chose the capture library for the old Electron selection window; the v4 native overlay always self-captures, so the toggle no longer does anything and is slated for removal.

**Removed settings (no longer present in Settings UI):** default snip type, toolbar visibility, loupe.

### Snip to Text (OCR)

**Snip to Text** turns a captured region into editable text using Claude Vision — the same drag-a-region selection as a normal snip, but on release the crop is sent to Anthropic's vision model and the transcribed text comes back in an editable window with a **Copy** button (modeled on the owner's AutoHotkey OCR tool). It's off by default; enable it with `screenshotOcrEnabled`. **Windows only for now** (it rides the native overlay path); the button is hidden on macOS/Linux.

Flow:

1. Click **Snip to Text** in the Snip view → the same native selection overlay opens; drag the region whose text you want.
2. On release the region is cropped and sent to Claude Vision (`screenshot-ocr-service`); a result window opens in a loading state.
3. The transcribed text appears in an **editable textarea** — fix anything, then **Copy** it. Empty region ⇒ a "No text found" state; no API key configured ⇒ an actionable "add an Anthropic API key" message; an API failure ⇒ a friendly retry toast (never a raw provider error).

**Cost:** each Snip to Text is one paid Anthropic vision call, recorded in the spend ledger under the `screenshot-ocr` source. The plain image snip and the annotation editor are unaffected — OCR is a separate, opt-in mode.

**IPC:** `screenshot:snip-to-text` (invoke; desktop-only — blocked over the mobile/web bridge) triggers the OCR snip; `screenshot:ocr-started` / `screenshot:ocr-result` (pushes) carry the loading + result states to the renderer.

### The snip viewer

Clicking a snip card opens the **snip viewer** modal — the image-shaped counterpart to the recording Review Window:

- A zoomable lightbox of the full PNG (served over the `screenshot://` custom protocol — `file://` is CSP-blocked).
- A **Name** field to rename the snip inline (writes `source_label`).
- **Link expires after** dropdown (1 day / 7 days / 30 days / Never).
- **Footer** — before sharing: **Discard · Reveal in Explorer · Share** (Ctrl+Enter shares). After sharing: **Copy link · Done** (the share link is shown and auto-copied).

Share, discard, and reveal reuse the recorder's `screen-recorder:share` / `delete-recording` / `reveal-recording` channels — the backend `share()` branches on `type === 'image'` to build an image viewer document. The minted link has the same form as a recording's: `https://shares.omniscio.com/s/<shareToken>/run`. If the snip has annotations, sharing flattens them into the published PNG first (the rebake step), so the link shows what you drew.

### Annotating a snip

Get into the editor three ways: the **Edit** action on a snip's library card, the **Annotate** button on the post-capture toast (editing is one click away right after you grab a shot), or by clicking a thumbnail in the **Snip** tab's recent-snips gallery.

- **Tools:** select · **text** · **arrow** · **box** · **highlight** (translucent marker) · **line** · **ellipse** · **numbered step** badges (auto-numbered, and stable after a delete) · **blur** (redaction). Each has an inspector for styling — color, thickness, opacity, stroke style.
- **Undo / redo** — `Ctrl/Cmd+Z` and `Ctrl/Cmd+Shift+Z` (or the toolbar buttons). A whole gesture — a drag, a slider sweep, a text edit — is ONE undo step, never one pixel or one keystroke.
- **Crop** — the crop tool draws a rectangle; **Apply crop** bakes a **new** cropped snip with the current annotations flattened in, leaving the original + its annotations untouched.

Annotations persist to the sidecar (`screenshot:save-annotations`); **Save as copy** bakes them into a new snip, **Copy image** flattens the current (even unsaved) marks to the clipboard, and publishing a link flattens them into the shared PNG — the original capture stays untouched on disk. One shared renderer (`draw-annotations.ts`) draws the live editor canvas AND the offscreen flatten, so every tool looks identical wherever the image lands. Invariants: [snip-annotation-kinds-contract.md](../../.claude/memory/contracts/snip-annotation-kinds-contract.md).

### Agent / CLI capture route

The `POST /capture/screenshot` CLI control-server route triggers a capture programmatically from an agent session and feeds the same save pipeline as a user-triggered snip (library row, clipboard copy, push event). See the CLI server docs for authentication and payload details.

### Where the data lives

- **Files:** `<userData>/screen-recordings/screenshots/<uuid>.png` + `<uuid>.sidecar.json` (the annotation overlay document).
- **DB:** `screen_recordings` table, `type='image'` rows; the video-specific columns are unused for images. Soft-delete via the same `is_deleted` flag.

## For agents

### IPC surface

Snip-specific channels live in [src/shared/ipc-channels/screenshot.ts](../../src/shared/ipc-channels/screenshot.ts); the viewer's share/discard/reveal reuse the `screen-recorder:*` channels documented on the [Screen Recorder](screen-recorder.md) page. All invoke handlers go through `wrapHandler` for the uniform `{ success } | { success, error }` envelope.

- `screenshot:start-capture` — payload `{ mode, regionRect, windowId?, displayId? }`; runs the capture pipeline (used by the agent/CLI route), returns the persisted row's UUID.
- `screenshot:show-overlay` — triggers the interactive snip (Windows native GDI overlay helper; macOS/Linux OS-native tool) — the shared action for the hotkey / tray / New snip button entry points.
- `screenshot:cancel` — no capture side effects.
- `screenshot:get-hotkey-status` — reports the current snip accelerator + whether it bound, so the library can show an "unavailable" hint.
- `screenshot:hotkey-status-changed` — push (main → renderer) fired by every (re)bind so mounted views replace their probe snapshot instead of showing a stale accelerator.
- `screenshot:save` — persists the snip's annotation overlay document (written by the unified editor's snip mode).
- `screenshot:captured` — push event `{ recordId, clipboardCopied }` fired after the row commits; drives ONLY the post-capture toast now (the shutter sound moved to `screenshot:capture-sound`). `clipboardCopied` surfaces a partial outcome (a clipboard write can fail without aborting the save).
- `screenshot:capture-sound` — push `{ emittedAt }` fired at the capture INSTANT (persist-start, before the save/DB/clipboard) so the renderer plays the shutter tone immediately instead of after the pipeline; `emittedAt` (main-side `Date.now()`) lets the renderer log the emit→play latency. (native-snip I18.)
- `screenshot:snip-armed` — push (no payload) fired when a snip is triggered, before the selection overlay, so the renderer resumes its background-suspended AudioContext ahead of the capture-sound tone. (native-snip I18.)

## Related

- [Screen Recorder](screen-recorder.md) — the video sibling in its own **Screen Recording** sidebar area; same `screen_recordings` table + store and shared share/editor surfaces, but a separate video-only library (the Screenshots and Screen Recording libraries are type-scoped, not shared).
