Omniscio documentation
Browse all documentation
  1. Getting Started13
  2. Sessions & Agents115
  3. Inbox & Notifications59
  4. Projects & Tasks95
  5. Automation & Scheduling75
  6. Knowledge & Memory26
  7. AI Features60
  8. Integrations100
  9. Plugins & Marketplace33
  10. Cloud & Teams56
  11. Settings & Customization58
  12. Account & Billing28
  13. Troubleshooting84
  14. CLI & API Reference22
  15. Legal & Policies4
  16. Uncategorised22

Screen Recorder (record, edit and share your screen)

Screen Recorder is the video half of Omniscio's built-in screen capture — a built-in Loom alternative. Capture your screen with optional microphone and webcam, review the result, trim and rename it in a built-in editor, then share a public link or publish to Vimeo. This page covers the toggle, the tabbed settings, the hotkeys, the editor and the library.

What it is

The capture itself is desktop-app only — it needs Electron's desktopCapturer plus hidden BrowserWindows to run MediaRecorder and the offscreen export bake, none of which exist in a headless process or a browser. But an agent session does NOT need IPC to drive it: the CLI control server exposes /capture/* routes that ASK the running app to do the work — POST /capture/recording/start · /capture/recording/stop · /capture/recording/device-prompt (answers the "a device you chose did not open" question a take can stop at; GET /capture/state shows it as pendingDevicePrompt) · /capture/screenshot, GET /capture/state · /capture/recordings · /capture/:id, and the frame routes in Agent frame access below. Reach for those first; screen-recorder:* IPC is for main-process code, not for agents. (This note previously said no CLI route existed and none was planned — that was already wrong when several /capture/* routes had shipped, and it sent agents off to build IPC plumbing they did not need.)

An agent's start ASKS; it never starts. When the caller is a spawned agent session, POST /capture/recording/start answers 202 { queued: true } and raises an approval card naming the source, the devices and the length cap — nothing is recorded until a person clicks Approve on it. The response carries no recording id, so do not poll GET /capture/state waiting for one; the card is answered in the app's inbox. A 409 there means the ask cannot be honoured as written (nothing to record, a named source that is gone, a take already running, or a start already in flight), which is a refusal the caller can fix. Note what is NOT busy: a recorder sitting in a FAILED state refuses nothing here — the start recovers from it, so the ask is carded as usual rather than answered with a refusal the caller cannot act on. The person who approves can arm "Always allow" for this kind, and the same switch is the "Auto-approve agent recording requests" row in Settings → CLI Control; that approval applies to asks that arrive after it is armed, so requests already waiting on a card still need their own click — it never sets off the ones already queued. maxDurationMs bounds the recorded length: the clock starts at the host's first frame, so a short ask is honoured in full rather than part-spent by the warm-up. Present your own $AMC_CLI_TOKEN to this route — a bare owner-token call (a local script or cron, naming no session) still starts immediately, but the owner credential paired with an X-AMC-Source-Session-Id header is refused 400: it proves nothing about which session is calling, so the header would BE the identity.

Screen Recorder is the video-capture half of Omniscio's built-in screen capture — the built-in Loom alternative. Capture your screen (with optional microphone and webcam), review the result, trim/rename it in a built-in editor, and share a public link or upload to Vimeo. Its sibling is the Screenshot / Snip Tool — both store rows in the same screen_recordings table (a snip is a row with type='image', a recording is type='video'), so the store, editor, review, and share surfaces are shared infrastructure. The library is NOT shared UI anymore: each area shows only its own type (see below).

The feature appears as a Screen Recording entry (Camera icon, red-400) in the Omniscio sidebar under the Communication group. Sidebar-name history: it shipped as "Screen Recordings", was rescoped to the unified "Screen Capture" umbrella (v0.1.67, covering snip + record in one panel), then split apart again 2026-08-03 into two sibling entries — Screen Recording (this doc; video only) and Screenshots (the snip tool + a snips-only library). The underlying sentinel __screen_recordings__ and the screenRecorderEnabled flag are byte-stable and never change — only the displayName moved. The sibling Screenshots area is a second integration (__screenshots__) that shares the same table and store, but as of the 2026-08-08 split it has its own screenshotsEnabled toggle — each area's toggle shows/hides only that area (Screen Recording stays on screenRecorderEnabled; see Screenshots).

A recording can also be handed to an AI to review with you — mark the moments that matter while you record, then send the whole thing to one conversation that shows you a cropped screenshot every time it refers to something. That mode is documented separately in Record for Agent; everything on this page still applies to it, since it is a mode on top of this recorder rather than a second one.

All capture is local-first. A hidden host renderer streams MediaRecorder chunks to the main process, which writes them to <userData>/screen-recordings/<id>/segments/, then a one-shot ffmpeg pass transcodes (and, for multi-source, composites) the WebM chunks into a single H.264 + AAC MP4. The MP4 stays on disk until you share or discard. Sharing uploads to the Omniscio Shares Firebase project and mints a public link; nothing leaves your machine until you explicitly share.

ffmpeg is installed for you if you don't have it — and the recording is never lost to a missing tool. Omniscio ships no ffmpeg of its own. When a transcode is the thing that failed for want of one, the take is held on disk (its segments are deliberately kept) and the app provisions a copy in the background while you are told only what actually happened. It tries, in order: the machine's own package manager through the same installer the Settings → Toolchain page uses (winget Gyan.FFmpeg on Windows, Homebrew on macOS) — the rung that also puts ffmpeg on your PATH for everything else you do; then a pinned, checksum-verified static build downloaded into the app's own data folder, which needs no package manager, no administrator and no PATH edit and which the app runs by absolute path; and only when both of those are out does one inbox card appear — "A recording still needs finishing" — whose button opens Toolchain settings. The moment either automatic rung lands, every held take is re-transcoded on its own. Attempts back off (1 min → 5 min → 15 min → 1 h) so a machine that genuinely cannot install it settles into an hourly retry rather than a storm, and the card is withdrawn as soon as a copy is present.

The H.264 encoder is chosen for your machine, not assumed. The transcode probes the ffmpeg it has and takes the best rung that actually works — NVIDIA NVENC → Intel Quick Sync → AMD AMF → Media Foundation (h264_mf, Microsoft's own encoder) → a software encoder — proving each candidate with a ~1-second trial encode run through the real production argument builder rather than trusting the binary's advertised list, then caching the winner per machine so the probe is paid once. If a hardware encoder fails partway through a job (a driver reset, another app taking the GPU), the same job is retried once on the software rung rather than losing the take, and the cached choice is dropped so the next job re-probes; a software rung failing is not retried, since there is nothing left to fall back to and reporting the real error beats running the job twice. The encoder used is recorded on every transcode for support and diagnostics.

While a capture is live, the hidden host renderer is held at HIGH CPU priority and Omniscio's own main process is capped one step below it, so the recording outranks the thread that writes its frames — including while you work in the app being recorded, which is the normal case. This is the one place a renderer is allowed to outrank the app's event loop, on the reasoning that a dropped frame cannot be recovered while a late chunk write can. It is released the moment the capture ends (stop, discard, abort, or a crash), works whether or not boostAmcProcessPriority is on, and has its own kill switch AMC_DISABLE_SCREEN_RECORDER_PRIORITY=1. Disk I/O priority is deliberately NOT raised: Windows refuses a non-elevated process any I/O priority above Normal, and the app already sits there while every agent process sits below it. Governed by recorder-outranks-the-event-loop-while-recording in app-tree-priority-contract.md; read the applied state from _debugAppTreePriorityState() (recording, recordingPid, recordingClass).

Where to find it

Opt-in toggle

Screen Recording is off by default for new installs. (PRD v2 §F5 plans to flip it on once the F1–F3 harness is green on master; that flip is written and parked, not shipped.) Flip Settings → Features → Enable Screen Recording (screenRecorderEnabled) to turn it on — its own toggle since the 2026-08-08 split from the sibling Screenshots area (each has an independent switch; see Screenshots). When off: the sidebar row is hidden, every screen-recorder:* IPC call is rejected at the handler with a { success: false } envelope before the service is touched, and no recorder hotkeys register. Existing MP4s and library rows are left untouched. An in-flight recording started before you flipped the toggle off is left running — the gate fires on new start/quick-start calls, not on active captures. Settings search keywords "screen recorder", "loom", "recording", "capture", "video", "share recording" all land on this toggle. Every OTHER Screen Recording option (shortcuts, quality, webcam, click ring, countdown, watermark, extras, link expiry, Vimeo token) lives IN the tool — the gear icon in the Screen Recording header opens the Screen Recording settings page (its own page since the 2026-08-08 split; moved out of Settings 2026-07-07). That page is laid out as five tabs, so no single screen is a wall of settings:

Tab Holds
Recording quick-record shortcut · recording defaults dialog (what a zero-click take records, and how it looks) · recording quality · countdown before recording · play-a-sound-when-recording-starts · auto-title recordings
Webcam & clicks webcam shape · webcam preview size · webcam preview corner · click-ring style, colour and size
Watermark & intro watermark mode, text, image and position · intro card and its name
Sharing copy-a-share-link-when-I-stop · quick-share link expiry · default link expiry · Vimeo access token
Advanced auto-zoom to clicks · click sound · Record for Agent · the Record-for-Agent video pass · do-not-disturb while recording · export folder · take the tour

Only the open tab's settings are on screen at a time — that is what keeps the page short — and Ctrl/Cmd+Tab cycles the tabs (Ctrl/Cmd+Shift+Tab goes backwards) from anywhere inside the dialog. The Screenshots settings page is deliberately NOT tabbed: it holds only a handful of rows. Every setting id, description and default is unchanged by the tab layout — the shelf a setting sits on is the only thing that moved.

How it behaves

How to use it

Start a recording

Two entry points:

While Screen Recording is enabled, Omniscio keeps the recorder countdown and controls loaded in the background without capturing screen, microphone, or camera media. Capture cannot begin until the current control HUD has positively confirmed that its React controls mounted and painted. During an unusually slow startup or renderer recovery, Quick Record instead says that nothing was recorded; it never queues a delayed surprise start.

  • Quick Record (Fastpath) — press Ctrl/Cmd+Alt+R. It records your default preset's exact scene with no picker and no modal; with no default preset it records the built-in default (the last-used source when it's still available, else the primary monitor, + remembered webcam + remembered mic). The hotkey is acted on at once — the take is created immediately — but the first ACTUAL frame lands a few seconds later while the devices and the desktop capturer open (see When recording actually begins below), and the HUD says "Starting…" until then. See Presets & Templates + Quick Capture below. Set its defaults once in the Recording defaults dialog, reached from the Screen Recordings library header, from the gear panel's Recording tab, and automatically on first use. The dialog covers the whole take: the background (a whole screen or one window), the output size (1080p / 4K / Vertical / Square), the camera device plus its shape, size and corner, the microphone, whether to capture system sound, then recording quality, frame rate and the countdown. Quality, camera shape and countdown are the same settings the gear panel edits, so the two surfaces cannot disagree; frame rate is settable here and nowhere else. Nothing changes until you press Save defaults, and a saved preset still outranks every default. One deliberate change on upgrade: Quick Record used to ignore the camera-shape setting entirely, so a camera left on its shipped Circle default now records a circle where it previously recorded a sharp square.
  • New recording (library header button) or the picker hotkey (Ctrl/Cmd+Shift+5, rebindable; it raises the app and opens the Record tab — main pushes SCREEN_RECORDER_PICKER_OPEN_REQUESTED, the App-level listener stashes the Record view and activates the area, and an already-open view switches itself) — opens the Record tab's two-step composer. The live composed canvas preview stays visible on BOTH steps. Layout follows the composer's own measured width (SIDE_BY_SIDE_MIN_WIDTH_PX = 760): wide → the choices on the start side and the preview beside them; narrower → the preview stacks on top (~40% height) and the choices get the rest. Each step's primary action (Next / Start recording, with any start error above it) sits in a pinned footer that never scrolls away. Step 1 — What do you want to record?: one heading, then the Record my webcam card (an on/off switch; the camera picker appears inside it while on; switching it off always removes the camera, a webcam-only scene included), then the Screens & windows grid (every screen and window the OS exposes, multi-select, a refresh button), then presets & templates (loading a preset jumps to Step 2 with the restored scene). Until something recordable is picked the preview says Nothing to preview, and clicking it selects nothing. Next stays disabled until the composition is startable (same resolveCompositionStart rule as Start). Step 2 — Recording options: output size, resize mode, layout arrangement, mic/system audio, webcam shape, Record for agent; Back returns to Step 1 with the composed layout kept. The Microphone section shows a live level meter for the chosen mic so you can check it hears you before you record, and says "We're not picking up any sound from this mic" if it delivers nothing for 3 seconds (it only opens the mic while that section is on screen, a mic is picked and it is not muted). Muting the mic here starts the recording muted. The source list loads in two passes (useCaptureSourceList): names first (listSources(types, { thumbnails: false }), ~1.5 s — placeholder tiles hold the grid meanwhile), so tiles are pickable at once, then the per-window thumbnail pass (~6–9 s on a busy desktop) fills the pictures in while tiles shimmer. Each pass is bounded at ~8 seconds in main (desktopCapturer.getSources() can hang on GPU-starved/RDP/locked machines); an empty names pass shows the no-sources message with the OS permission pane and Retry, while an empty thumbnail pass keeps the names (no false permission error). Known limit: a names pass that hangs to the bound still reads as no sources.

Multi-source recording is supported. You can compose several sources (screens/windows + a webcam) into one canvas. Selecting a webcam without an explicit layout auto-generates a picture-in-picture layout (buildLoomDefaultLayout); the scene is persisted as a layout sidecar beside the WebM, and ffmpeg composites the sources into a single MP4 on stop. Quality, frame rate, countdown, and delayed-start options come from the recorder settings.

The finished file stores the frame rate you asked for, and 60 is a real rate (measured 2026-10-06, T-88). A composed screen + camera take recorded at 1080p with frame rate set to 60 came out of the bake as a true 60 fps file — ffprobe reports 60/1 for BOTH r_frame_rate and avg_frame_rate, and the frame count over the encoded span divides to exactly 60.0 (e.g. 278 frames across 4.633 s). The same held at the app's other rates: a 30 fps request stored 30/1 with 46 frames across 1.533 s, and a synthetic end-to-end case asserts the identical thing at both 30 and 60. This is the property a backdrop generated without an explicit rate= used to break — ffmpeg's color filter defaults to 25 fps, which quantised every composited take to 25.0 regardless of what was asked for (fixed in T-70; the composite's backdrop is now generated at the requested rate).

Two honest limits on that sentence. The 60 is the OUTPUT rate, not each source's own rate. The camera's own capture chunk (a per-source WebM beside the composite) declares 30000/1001 — the Insta360 Link 2 here feeds ~30 fps — and the compositor paints it onto the 60 fps canvas, so the take is 60 fps end to end while the camera area carries its device's frames. Asking for 60 never makes a 30 fps camera shoot 60.

And the recorder's window has to be visible to measure any of this. Screen capture stalls while the window is occluded or minimized, at EVERY frame rate — a 15 s take stored 1.8 s at 60 fps and 1.5 s at the app's ordinary 30, so the loss is rate-independent and a hidden window can make a perfectly healthy recorder look like it is dropping six frames in seven. With the window visible, a 30 s 1080p composed take at 60 runs clean: the file holds 23.72 s of media and 1,423 frames — 1,423 ÷ 23.72 = exactly 60.0 fps, no dropped frames inside the recorded span (r_frame_rate and avg_frame_rate both 60/1). The 6 s between the 30 s take and the 23.7 s file is the documented start latency while the devices and the desktop capturer open, not lost frames — the recorder's own counter reads 23.0 s at the 30 s mark, which is the same 7 s. On this box that take cost about 25 CPU-seconds across the whole app, measured over a window that includes the finalize and the ffmpeg bake.

The video block's shape (rounded by default)

A recorded screen or window comes in with softened corners — a camera-less recording is rounded too.

  • Shape + Roundness (Step 2): Square / Rounded / Circle plus a slider, 0–50% of the shorter side, so a corner looks identical at any resolution.
  • Preview, editor and the exported MP4 derive the corner from one shared value, so the export matches what you approved.
  • The shape rides in the scene, so a preset brings it back; Screen Recording → Video block shape / corner radius sets the standing default (both optional — older scenes still open).
  • Camera beside window — one press pairs camera and window as two equal, resizable tiles; PiP/Pack puts it back, keeping its shape.

While recording (the HUD)

Window creation and page-load completion do not count as ready. The current hidden HUD generation must prove its controls are rendered before any recording entry point may touch media; a close, failed load, or renderer crash invalidates that proof and starts bounded background recovery.

A floating recording HUD shows the elapsed timer and the live controls. It opens on the display where the Omniscio window is (not necessarily the primary monitor). Move it by its grip (the dotted handle at its left end) if it's covering something; your placement is kept for the rest of that recording (the next recording re-centers). The HUD window is pre-warmed at recording start so it appears the moment capture begins.

Layout (redesigned 2026-10-05). The full bar is three zones separated by thin dividers: status (grip, REC dot + timer — hover the timer to see what is being recorded — and the For agent chip), tools (mic with its live meter, pause/resume, the agent note + draw-a-box tools when recording for an agent, settings) and finish (one red Finish button with a share half attached, then the trash can). Finish and Pause tooltips show your bound shortcut as a key-cap when one is set.

Minimal mode. Once capture is live the bar folds down to just the grip, the REC dot + timer, the mic with its live sound meter (a red muted-mic icon when muted, so a silent take is never invisible), pause, an icon-only Finish and an expand arrow. Hover the bar — or click the arrow — and it opens into the full bar; it tucks back in about 1.5 seconds after the pointer leaves. It stays fully open while the take is still starting, while an agent note is being typed, while the trash is armed for its second click, and while an error shows. The window resizes around its centre as the bar opens and folds, so the bar never slides under the pointer and a folded bar leaves no invisible click-blocking margin. The controls:

  • Pause / resume — stops capturing but keeps the session live; the MP4 resumes into the same file.
  • Finish — finalizes. Status moves recording → transcoding → ready and the row appears in the library (the review window auto-opens on the transcode→ready edge). With auto-share-on-stop on, the share link is copied to your clipboard instantly on Finish (see Sharing below). Over the hardware warm-up — before the host reports its first frame, so nothing has been captured yet — this button reads Cancel: pressing it cancels the take rather than saving it (there is no recording to finalize), so the label is exactly what the press does. It becomes Finish on the same first-frame edge as the red dot, the chime and the tray row, together with Finish & share, which is not offered over the warm-up at all. (The two read Stop / Stop & share until 2026-10-04 — the owner renamed them; the buttons, their behaviour and their recordingHud.stop* keys are unchanged.)
  • Finish & share — Finish AND force the instant-share link + clipboard copy even when auto-share-on-stop is off.
  • Settings (gear) — foregrounds the app and opens Screen Recording settings without ending the recording.
  • Mic — mutes/unmutes the microphone. A small live level meter sits beside the mic icon: it moves as the mic picks up sound and goes flat and dimmed while muted, so you can see at a glance that your voice is being recorded.
  • Discard — drops the segments and the row (two-step confirm: the first click turns the button into Delete forever?, a second click within 3 seconds deletes; nothing is written).
  • Panic-mute — instantly mutes mic + camera without stopping.

The HUD window always fits what it shows — a warning banner, the armed Delete forever? button, the Record-for-Agent note row — so nothing is ever cut off at its edge. Every warning banner has a ✕ to dismiss it.

For a webcam recording, the small live self-view (the Loom-style floating camera pill, content-protected so it's excluded from the capture) is pre-warmed while the hardware opens, the same way the HUD is — its camera is opened during the warm-up and it is revealed on the first captured frame, so it appears live rather than as an empty pill over a camera that has not opened, and never has to start a fresh 1–3 s camera load as the take begins. Its starting size and docked corner come from Screen Capture settings.

Move and resize the self-view live — the video follows (2026-10-05). Drag the bubble to move it; drag the small round resize grip on the corner facing the middle of the screen to make it bigger or smaller (0.6×–2.2× its starting size, never more than 45% of the screen's short side, and always kept on screen — the opposite corner stays put). Every move or resize is recorded the moment you let go, on the recording's own clock (a move made while paused takes effect at resume), into webcam-position.json beside the take. When the take is finished, the webcam in the finished video sits wherever the bubble was at each moment — same relative spot, same relative size — and the editor opens with the same placements (the webcam jumps between them rather than sliding). Details that matter:

  • An untouched bubble changes nothing — no sidecar is written and the ffmpeg command is byte-for-byte what it was before this feature.
  • Moves are mapped as a delta from where the bubble started, so resizing in place never relocates the webcam; a camera-only take (the webcam is the whole picture) is never moved.
  • Moves under a second are folded into the next one and a take keeps at most 12 placements.
  • A move still in progress when you press Finish is saved before the video is made.
  • If ffmpeg ever rejects the per-segment graph, the video is re-made once with the normal corner — the take is never lost to the optional track.
  • Recording a window rather than a whole screen maps the bubble proportionally, which is close but not pixel-exact.

When something you asked for can't be captured

The microphone, your computer's sound and the camera are each optional: losing one never stops a recording. It does mean the take is missing something you asked for, and the HUD says so as soon as capture is live — the same banner the warnings channel already uses, so you see it while the recording is still running and can still act on it.

  • No microphone audio was recorded — your microphone could not be opened (disconnected, or held by another app). Screen and system audio are unaffected.

  • Your computer's sound was not recorded — the system-audio capture could not start.

  • Your chosen camera could not be opened — this recording uses "‹name›" instead — a camera IS being recorded, just not the one you picked.

  • Your mic is on but isn't picking up any sound — the microphone is open and unmuted but delivering nothing at all (a dead or wrong device, or a mic muted in Windows). It appears after the silence lasts longer than the VAD strictness setting allows (relaxed 10 s / normal 5 s / strict 2 s), and it clears itself the moment sound comes back — or when you mute on purpose. A quiet room never triggers it: a working mic always picks up some background noise, and only true digital silence counts. Muted, paused and "Starting…" time never count. (Noise-gated virtual mics such as Krisp or NVIDIA Broadcast send true silence between words, so for those it can appear during a long pause and clear on your next word.)

Each device capture gets one immediate retry first, so a microphone or camera that was only briefly busy records normally and you see no message at all. What the take actually captured is also written beside the recording as capture-report.json, next to layout.json (which records what you asked for) — so a recording made without a microphone is never mistaken for one made with it.

Review window

Click any ready recording (or stop a capture) to open the Review Window:

  • Inline <video> preview of the local MP4 (shows a "not available yet" state during transcode).
  • Name field — rename the recording inline (commits on Enter/blur; writes source_label). A recording you have not named stores source_label = '' (the column's NOT NULL default) and DISPLAYS a fallback — the AI title once Auto-titling produces one, otherwise its capture time. Never persist a placeholder string here: source_label means "a human named this", and writing a display default into it is exactly what silently disabled auto-titling for every recording ever made (auto-title's first guard is "manual title wins", which a placeholder satisfies). A display fallback belongs at the render site (cardTitle), never in the column.
  • Saved on this computer — a Show in folder button and Copy file path button.
  • Link expires after — a dropdown (1 day / 7 days / 30 days / Never) applied when you share.
  • Publish to Vimeo — appears when a Vimeo access token is set in Screen Capture settings (the gear icon); uploads the MP4 with a progress bar and surfaces the Vimeo URL with a copy button.
  • Footer — before sharing: Discard · [Publish to Vimeo] · Share (Ctrl+Enter shares). After sharing: Discard · Copy link · Done (the link is auto-copied; the same trio shows when you reopen an already-shared recording).

The editor

Open a ready recording in the built-in editor via the Edit (pencil) action on its library card (or the review window's edit/annotate link). The editor is a single in-app view (screen-recorder-editor). Recordings and snips open in the light tier (calm resting surface: stage + chip timeline + transport + the always-visible annotation tool palette); projects open in full. The Open full editor button in the transport row escalates light → full (gated by FULL_EDITOR_ENABLED in src/renderer/src/features/screen-recorder/editor/editor-mode-gate.ts), revealing the layers panel + retime/keyframe rail. (The old separate "Annotate" toggle is gone — the tools are plain toolbar controls, not a mode.)

  • Breadcrumb — Back to the library + an inline-editable name.
  • Compositor stage — a live canvas preview (CompositorStage) that composites every layer at the playhead via the pure renderCompositeFrame, the same function the export bake uses (preview/export parity). Transport row: play/pause, time, seek slider, a shuttle-rate badge, and a keyboard-shortcuts button.
  • Playback keys (stage focused): Space play/pause · J/L shuttle backward/forward at 1×/2×/4× · K pause · ←/→ frame-step (Shift = 1s) · Home/End · ? opens the shortcut sheet documenting every editor key.
  • Multi-track chip timeline — tracks are z-lanes ("layers, not lanes"); chips drag/trim with snapping (Alt bypasses snap), S splits at the playhead, split clips Merge back losslessly, Forward/Back buttons move clips across lanes, multi-select (Ctrl-click / marquee) with bulk delete, and linked groups move/trim/retime as one unit.
  • Keyframes — transform and opacity animate via per-clip keyframe lanes (diamond add/remove/drag, named easings, and a custom cubic-bezier curve editor). The compositor resolves every animatable prop through the resolve(prop, t) seam.
  • Clip effects — time-bound zoom regions (Alt-drag pans the zoom framing; mouse wheel zooms the selected source), time-bound mute ranges, retime (target-duration speed ramps), per-clip style (border / shadow / glow / corner radius), preset masks, and layout presets (one-click source arrangement).
  • Annotations — text / arrow / rect / blur are first-class clips in the z-stack, time-bound on the timeline, and baked into exports via the timeline sidecar. Pick a tool then click-and-drag on the stage to draw the shape out (rubber-band; an arrow drags tail → head); a plain click places a default-size shape at the click point.
  • Cursor & click overlay — when a recording captured cursor/click sidecars, a geometry-aware cursor glow + click rings render in preview (toggleable) and bake into exports. Event times are media-relative: they are anchored to the video's FIRST FRAME, not to the moment you pressed record. Those differ by the capture warm-up (on Windows, WGC can take a second or two after getUserMedia returns before it delivers decoded frames), so before this was anchored every ring rendered late and drifted further with each pause. One conversion owns it — see screen-recorder-contract I19.
  • Undo/redo — doc-snapshot history (Ctrl+Z / Ctrl+Shift+Z), drag-coalesced so one gesture is one undo step.
  • Export — bakes an edited MP4 via an offscreen export host with progress / complete / failed events and cancel (export, cancel-export); options cover resolution (source/1080p/720p/480p), codec (h264/vp9/av1), bitrate, and framerate.

Non-destructive edit data (trim ranges, layout, bookmarks, click events, annotations, cursor track, webcam-position track, timeline doc) persists as JSON sidecars beside the WebM, so reopening rebuilds the scene without touching the immutable source bytes.

Sharing

Share uploads to the Omniscio Shares Firebase project and mints a public link of the form https://shares.omniscio.com/s/<shareToken>/run, honoring the chosen expiry. A video share uploads the raw MP4 as its own Storage object (shares/<token>.mp4) and the viewer streams it from the Range-serving /s/<token>/video route — capped at 500 MB, and the upload deadline scales with file size plus one automatic retry on a transient network failure (a ~20 MB clip on a slow uplink shares reliably). A recording past the cap is refused before anything leaves your machine ("Video is <n> MB (cap 500 MB)") — that cap exists because the MP4 lands in the product-paid Storage bucket and is Range-streamed on every view, so an unbounded recording is a real cost/abuse vector; longer recordings are steered to the Vimeo path instead, which uploads to your own Vimeo account. A snip share inlines its PNG as a base64 data URI (10 MB cap). screen-recorder:get-share-info re-reads an already-published recording's live link + expiry so the review window can re-display and copy it without re-publishing. The legacy screen-recorder:publish channel is deprecated in favor of screen-recorder:share. screen-recorder:reveal-recording opens the rendered MP4 in the OS file manager (main owns the absolute path, so this sidesteps the project-scope gate the generic file-reveal channels enforce).

Instant share link on Stop (reserve → finalize). When auto-share-on-stop is on — or you use the HUD's Finish & share — the share link is RESERVED and copied to your clipboard the instant you finish, before the transcode + upload finish, so you can paste it right away; the recording finishes uploading in the background and attaches to that same link. At Stop, reserveInstantShare() (src/main/services/screen-recorder/screen-recorder-share-inline-ops.ts → src/main/services/screen-recorder/screen-recorder-share.ts) mirror-writes the recording's own share token to claim ownership and parks a self-refreshing "still uploading" placeholder at /s/<token>/run (buildProcessingViewerHtml in screen-recorder-viewer-html.ts — a self-refreshing placeholder, so an early open flips to the video on its own once it lands, never a 404). The post-ready finalize calls share({ reuseToken }), which pins the real upload to that SAME token (asserting the relay echoed it back). A failed finalize tears the reserved link down (no dead link); if the reserve itself can't run (offline / signed out) it falls back to today's post-upload share + toast. There is no in-app "Processing…" pill — the instant toast is the feedback, and the content-protected HUD owns the live controls. Locked by I18 in the contract.

Third-party-PII share warning. A share uploads the raw media and its transcript captions — which can contain what other people said or showed — to a public-read bucket anyone with the URL can open. Before the FIRST share on an install, a one-time ConfirmDialog discloses this (mirrors the meetings-consent pattern); acknowledging sets screenRecorderShareWarningAcknowledged and is never shown again. The acknowledgment is enforced fail-closed in the main process — shareRecording() refuses to mint/upload until it's set — so every path is covered (the renderer dialog, the CLI POST /capture/:id/share, and the default-ON auto-share-on-stop). Because auto-share-on-stop has no UI, it HOLDS the first time (keeps the local recording, pushes a "review before sharing" prompt instead of publishing) until you acknowledge once, then resumes its silent one-paste behavior. Choosing the Never expiry stays available but, once acknowledged, asks for an extra confirmation each time (the indefinite-public choice is never silent); never→null expiry is otherwise unchanged (the src/main/services/share/share-reaper.ts grace-expires old-and-unviewed never-shares separately). The interactive dialogs live in src/renderer/src/features/screen-recorder/share-warning-gate.ts; the main-side backstop + auto-share hold in src/main/services/screen-recorder/screen-recorder-share.ts / src/main/services/screen-recorder/screen-recorder-service.ts.

Viewer analytics

A shared recording's review window shows Viewer analytics — how your public link was watched. Because a recording is served at /s/<token>/run (which never hits the shell view-counter), a recording has no view events on its own; the analytics come from a lightweight watch beacon the public viewer page sends as it plays.

  • What's captured — one record per play-session: how far it got (max %), seconds watched, and — computed server-side — coarse country + a salted, pseudonymous hash of the viewer's IP + user-agent (NEVER a raw IP/UA), auto-expiring after 180 days. Same privacy posture as share view events; no viewer-facing notice (the data is hash-only). The beacon is fire-and-forget and can never affect playback.
  • The panel shows views over time · unique viewers · avg watch % · drop-off, plus a "notify me when watched" toggle (opt-in, off by default — fires an OS notification the first time each new viewer watches). To protect small audiences, the detailed charts only appear once a recording has 5+ views (below that you see just the two counts).
  • Library badge — a shared recording's card shows a live view-count badge (an eye + the number) once it has been watched.
  • Where it lives — the beacon endpoint is the serveShareWatch cloud function (POST /s/<token>/watch); the desktop mirrors sessions locally via the relay watch-read op into share_watch_sessions and aggregates with k-cohort suppression. Full invariants: screen-recording-watch-analytics-contract.md.

Recovered recordings

If Omniscio crashes mid-recording, orphan chunks may be left on disk. On next launch the recovery loader scans <userData>/screen-recordings/ for sessions in recording/paused state and surfaces them under the sidebar's Recovered row — its own destination, badged with the count, and reachable from every other section. Click to recover (transcode the existing chunks into a final MP4) or discard.

Each area only ever shows its own kind. The stored list is mixed — a crashed video and a crashed snip sit in it together — so the Recovered page and its badge both filter to the area you are in. Screenshots never lists a crashed recording, and the badge always agrees with the Library's own pointer.

Related

The panel, the library and its storage are covered on Screen Recorder (part 4).

Last verified 2026-10-04