Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
MobAI-App avatar

Desktop Recorder Skill

  • 16 repo stars
  • Updated June 27, 2026
  • MobAI-App/desktop-recorder-skill

This is a copy of desktop-recorder by MobAI-App - installs and ranking accrue to the original listing.

desktop-recorder-skill is a skill for the build phase that lets an agent drive a desktop or web app and record a reproducible screencast, exporting a clean mp4 with zoom, captions and click highlights.

About

desktop-recorder-skill is a macOS agent skill for recording polished, reproducible screencasts of desktop or web apps. The agent explores the app, writes a recording screenplay, normalizes state, does a dry run, then records and edits, adding zoom, captions, click highlights and speed-ups before exporting an mp4. Because the recording is scripted through the native deskagent CLI, you re-run it whenever the UI changes instead of re-shooting demos by hand. It is aimed at builders who need repeatable product demos, tutorial clips and release GIFs that stay in sync with the app.

  • An agent drives the app and records itself, no manual screen capture
  • Reproducible: re-run the script when your UI changes and the demo regenerates
  • Polished output - zoom, captions, click ripples and variable speed
  • Drives desktop and web apps via the native deskagent CLI
  • Exports a clean, share-ready mp4

Desktop Recorder Skill by the numbers

  • Data as of Jul 12, 2026 (Skillselion catalog sync)
npx skills add https://github.com/MobAI-App/desktop-recorder-skill --skill desktop-recorder

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
repo stars16
Last updatedJune 27, 2026
RepositoryMobAI-App/desktop-recorder-skill

What it does

An agent drives your desktop or web app and records a polished, reproducible screencast - a clean mp4 with zoom, captions and click highlights you regenerate when the UI changes.

Who is it for?

Builders who need repeatable product demos, tutorial clips or release GIFs that an agent can regenerate whenever the UI changes.

Skip if: Live webinars, real-time screen sharing, or recording on Windows or Linux - it is a scripted, macOS-only capture tool, not a streaming app.

When should I use this skill?

When you need to produce or refresh a demo video, tutorial clip or release GIF of a desktop or web app.

What you get

A scripted screencast you re-run on demand - the polished mp4 regenerates when the app changes, instead of being re-recorded.

  • a screenplay.json recording script
  • a polished mp4 screencast

By the numbers

  • MIT licensed
  • macOS 14+ / Apple Silicon
  • deskagent CLI: list, inspect, record, control

Files

SKILL.mdMarkdownGitHub ↗

Desktop Recorder

Built on deskagent (ScreenCaptureKit + AXPress + Vision OCR). The agent never improvises during the final take - exploration is unconstrained, the recording is a deterministic JSON-script replay.

Pre-recording checklist - ASK, don't pick silently

Use AskUserQuestion (or plain text) before recording. State defaults explicitly so the user can shrug and accept.

DecisionDefault if user shrugs
Background none / dark / light / color:RRGGBB / image:/pathcolor:1a1a2e (dark navy). dark/light render as cached vertical gradients; image: covers the canvas.
Layout for multi-source: auto / side-by-side / grid / stackauto
Padding between elements60
Composition canvasdisplay native (or [1400, 1000] for the typical 1.4 AR)
Supersample on capture1 (device pixels). Bump to 2 for sharper playback when the editor will scale clips up
Cursor spritemacOS system arrow with pointing-hand on click (deskagent cursor-png). Override via screenplay.highlights.cursor.{arrow,pointing,size}
Click rippleProcedural soft expanding white ring. Override color/size/duration via screenplay.highlights.ripple.*, or supply your own .mov/APNG via ripple.sprite
Zoom follow_cursorEnabled - camera tracks the synthetic cursor's eased path (shared with the sprite, no desync)
Final export resolutiondisplay native (so QuickTime plays 1:1 on this machine)
Final qualityhigh (HEVC ~200 Mbps target)
State-verification levelpreflight + fingerprint at dry-run boundary
Which apps may be drivenWhichever the user named; never silently click into others

The 6 rules

1. Explore first

Tools allowed during exploration only:

  • deskagent list --json → window picking
  • deskagent inspect --window $ID → element coords (AX + OCR)
  • deskagent assert --window $ID --label X → cheap yes/no probe
  • deskagent screenshot --window $ID → visual reference; on macOS 26/Tahoe

hangs or capture failures, use node scripts/record-screenshot.js --window $ID --out /tmp/shot.png

  • Trial deskagent control runs against the live UI

Collect: click coords (window-relative), per-step waits, demo data, popups to normalize, the recording's window size (pin BEFORE inspecting), start/end states, captions.

2. The screenplay - single source of truth

One screenplay.json describes the demo end-to-end: scenes of actions to execute, plus top-level composition / zoom / speed / captions / trim directives. deskagent control reads only scenes[].actions[]; editor scripts read the top-level directives.

{
  "schema_version": 2,
  "name": "demo1",
  "coordinate_space": "window",
  "scenes": [
    { "id": "open_settings", "windowId": 245663,
      "actions": [ { "action": "click", "x": 244.5, "y": 54.5 } ] },
    { "id": "wait_load",     "windowId": 245663,
      "actions": [ { "action": "wait", "ms": 4000 } ] }
  ],
  "composition": {
    "canvas":     [2560, 1600],
    "background": "color:0a0a10",
    "layout":     "side-by-side",          // optional; auto-computes slot rects
    "padding":    60,                      // optional gap (used by layout)
    "elements": [
      { "windowId": 245663 }               // auto rect from layout
    ]
  },
  "zoom": [
    { "scale": 2.0, "follow_cursor": true,
      "fromAction": "open_settings/0", "toAction": "wait_load/0" }
  ],
  "speed": [
    { "factor": 2.5,
      "fromAction": "wait_load/0", "toAction": "wait_load/0", "endDelayMs": 4000 }
  ],
  "captions": [
    { "text": "Open Settings",       "fromAction": "open_settings/0", "durationMs": 1500 },
    { "text": "Loading the panel…",  "fromAction": "wait_load/0",     "toAction": "wait_load/0", "endDelayMs": 3000 }
  ],
  "trim": { "beforeScene": "open_settings", "afterScene": "wait_load" }
}

composition drives scripts/stages/compose.js - required for multi-clip recordings, optional when there's a single clip. zoom, speed, and captions are top-level arrays with global fromAction / toAction refs

  • a single entry can span any range of actions across any scenes, with

timing offsets via startDelayMs/endDelayMs. Zoom camera modes: follow_cursor: true tracks the synthetic cursor across click-driven ranges; pan: [...] does cinematic sweeps over no-click ranges (the cursor is hidden during pans). Don't overlap a pan with clicks - use follow_cursor there. See `references/desktop.md` for the full shape.

coordinate_space: "window" keeps screenplays portable across window drags. Per-scene windowId routes that scene's action coords to the correct window in multi-window compositions. No conditionals, no wait_for, no observation loops - every action is deterministic. Recording start/stop is outside the screenplay; the agent owns the lifecycle.

3. Dry-run + state fingerprint

Run the full script with --background against the live UI (no recorder active). Iterate until clean.

Before the final take, prove state matches what the script expects:

1. deskagent screenshot --window $ID → visual record. If screenshot hangs or fails on macOS 26/Tahoe, use the streaming fallback: node scripts/record-screenshot.js --window $ID --out /tmp/shot.png. 2. At least two deskagent assert calls on labels that exist ONLY in the expected sub-state. (Section names usually persist across sub-states - they're too coarse.) 3. Refuse to record if any assert fails. Re-normalize in setup.

Per-step assertions inside recording are NOT supported - the recording is meant to be a deterministic replay, not a probe loop.

4. Pin window info BEFORE recording

Capture id, pid, and x,y for every window during exploration, then drive with --target-pid + --window-frame + --background during the take. No WindowServer lookups during the run, no chance of the wrong window being picked if focus shifted between dry-run and record. Multi-window: collect pid+origin per window in one pre-record list call; route each control invocation via its own flags.

Targeting flag rules are documented in references/deskagent.md. The short form: HID mode needs --target-window (activates the app); background mode needs --target-pid + --window-frame (delivers per-pid, no activation).

5. No live recovery - re-record

Final take failed? Stop, discard, fix the script, re-record. Don't patch live.

6. Don't resize source windows after exploration

Any osascript … set size of window belongs in setup BEFORE exploration, confirmed with the user. Never inside recording. Composition is done in the editor's compose stage; per-clip placement + canvas + background live in the screenplay's composition block, so a mid-take window resize would still mismatch the composition rects.

End-to-end pipeline

1. Explore  -> pin id/pid/origin per window, gather click coords.
2. Author   -> screenplay.json (scenes + actions, top-level composition/zoom/speed/captions/trim).
3. Normalize state (close tabs, log in, hide chrome, theme).
4. Dry-run  -> deskagent control screenplay.json --target-window $ID --timeline /tmp/dry.json
5. Fingerprint state with deskagent assert.
6. Record   -> deskagent record ./demo/raw --window $ID [--window $ID2 ...] --no-cursor --pid-file /tmp/rec.pid [--supersample 2] &
                  (writes per-source ProRes 4444 .mov clips + recording.manifest.json into ./demo/raw/)
7. Drive    -> deskagent control screenplay.json --target-pid $PID --window-frame "$ORIGIN" \
                  --background --no-activate --timeline timeline.json
                  (run in parallel per target window for multi-window demos)
8. Stop     -> kill -INT $(cat /tmp/rec.pid); wait
9. Export   -> node scripts/export.js ./demo/raw screenplay.json timeline.json demo.final.mp4 [format] [--quality high]
                  (one ffmpeg pass: compose -> highlights -> zoom -> captions -> speedups -> encode)
10. Copy    -> node scripts/generate_copy.js timeline.json prompt.txt copy.md

Every editing operation runs in a single ffmpeg invocation off the per-source clips - no intermediate mp4s in the hot path, no generation-loss from per-stage re-encodes. The final encoder choice (HEVC / H.264 / ProRes 422) is the only re-encode in the entire pipeline.

Outputs (one demo folder, default ./demo-out/<name>/)

screenplay.json        single source of truth (scenes + composition + directives)
timeline.json          execution evidence from `deskagent control`
raw/                   directory written by `deskagent record`:
  recording.manifest.json   per-clip paths + host-time alignment anchors
  window-<id>.mov           one ProRes 4444 .mov per source (alpha-preserving)
  display-<id>.mov
demo.final.mp4         the deliverable (single ffmpeg pass via scripts/export.js)
copy.md                upload copy

For per-stage debugging, each editing stage has a CLI that can either emit its filter fragment as JSON (used by the orchestrator) or render it standalone to a ProRes 4444 .mov to inspect just that stage's effect:

node scripts/stages/zoom.js generate <recDir> <screenplay> <timeline>
node scripts/stages/zoom.js generate <recDir> <screenplay> <timeline> --apply input.mov output.mov

References (load on demand)

  • references/deskagent.md - CLI surface, permissions, recording.manifest.json schema
  • references/desktop.md - screenplay schema (scenes + composition + captions + zoom + speed + trim), setup normalization, state-fingerprint recipe
  • references/timeline.md - timeline event schema (scene_start / action / scene_end)
  • references/editing.md - export orchestrator + per-stage modules (compose / highlights / zoom / captions / speedups); cursor track + cursor.hide/show
  • references/web-driver.md - CDP web driver (drive-web.js): drive browser page content focus-free; trajectory/pointer actions; draw on web canvases
  • remotion-template/ - optional Remotion bridge: turn a recording (manifest+timeline+screenplay) into React motion graphics. The bridge (loadRecording + <RecordingCard>/<Cursor>/<ClickRipple>/<Caption>) does the integration; you only write the creative composition. See its README.md.

Authorization rule

deskagent control mutates the user's app state (focus, tabs, open docs). --background minimizes visible impact but still mutates. Confirm before touching any app the user didn't name. Don't silently swap targets or open new tabs / windows / documents.

Quick failure map

StageCauseAction
inspect returns nothingWails/Electron WebViewrely on OCR; AX walk only sees chrome
Capture errors at startTarget window onScreen: falsebring it forward; SCK can't always frame-pump occluded windows
macOS 26/Tahoe: deskagent screenshot hangs or fails while deskagent record --window ID worksscreenshot uses a separate ScreenCaptureKit still-image path that can fail independently from streaming captureUse node scripts/record-screenshot.js --window ID --out /tmp/shot.png for visual fingerprints; keep final takes on deskagent record
macOS 26/Tahoe: deskagent list reports displays: []ScreenCaptureKit display enumeration mismatchTry deskagent record ... --display 1 directly; display recording can still work even when list output omits displays
Web/browser clip frozen, animations stalled, stale contentWindow fully occluded - WebView throttles timers/rAF/repaintskeep the window at least partially visible during the take
screenplay schema_version N not supportedscreenplay was authored for a different deskagent buildre-author to current schema (current: 2)
compose.js errors: "manifest has N clips but screenplay has no \composition\"multi-clip recording lacks compositionadd composition.canvas + composition.elements[] to screenplay
captions[i] overlaps captions[j]two caption entries cover the same time rangeshorten the first with endDelayMs/durationMs or push the second with startDelayMs
Video looks soft in QuickTimeQT renders .mov dimensions as logical points; pixel-doubles on retinarecord with --supersample 2, OR export at display-native size (default), OR open the frame as PNG in Preview
Composition stretches a windowsource pixel size doesn't fit slot AND composition.upscale is onleave upscale unset; clip will sit at native size centered in the slot (downscale-only)
TCC re-prompts every releaseAd-hoc signing - fresh identity per buildre-grant once, or build with a stable self-signed cert

Chromium-based browsers (Chrome, Edge, Brave, Arc)

For page content, prefer the CDP web driver (scripts/drive-web.js) over deskagent control - it injects input at the renderer, so it needs no focus and no foreground (drive an unfocused window while recording), targets the DOM by selector (no pixel-guessing / mis-clicks), and emits the same timeline.json so record + export are unchanged. It replaces control for browser scenes; full setup (launch flags, actions, coordinates) in `references/web-driver.md`. Use deskagent control only for the browser's own UI (omnibox, tabs, extensions, menus) - CDP can't reach those.

Fallback (no debug Chrome): deskagent control HID mode reaches only the browser chrome via --background; for page content record with --no-cursor and drive with --target-window (HID, cursor moves during the take). OCR beats AX for Chrome element discovery; URL-bar nav (cmd+l → type → return) beats chasing SPA links.

Keep the browser window at least partially visible during the take. When fully occluded, the renderer throttles timers / rAF / repaints (Page Visibility), so the clip captures stalled animations or stale content - even though SCK is still pulling frames. (Launch Chrome with the --disable-*backgrounding* / throttling flags - see web-driver.md - to keep an unfocused window compositing.)

Out of scope

Mobile (use mobile-recorder-skill); Linux/Windows; direct upload; AI voiceover / music; GUI video editor.

Related skills

How it compares

Use instead of manually recording your screen with QuickTime or Loom and re-shooting after every UI change.

FAQ

What does desktop-recorder-skill do?

It lets an agent explore your desktop or web app, script a recording, then capture and edit a polished mp4 screencast with zoom, captions and click highlights.

What platforms does it support?

macOS only, on Apple Silicon (macOS 14+). It drives native and web apps through the deskagent CLI and exports an mp4.

How is it reproducible?

The recording is scripted as a screenplay, so when your UI changes you re-run it and the demo regenerates instead of re-shooting by hand.

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.