# Background capture (Windows)

Start a local development server with an already accepted EULA, then:

```powershell
plug --json capture doctor
plug --json capture client --player CaptureTester
plug --json capture init
plug --json capture run .plugdev/scenarios/listing.yml
plug --json capture status
plug --json capture client-stop
```

These commands require CLI 1.4.0 / MCP 0.5.0 or later; older versions may still use foreground F2 capture. Capture never accepts agreements or starts a server automatically.

Automatic capture follows the configured Prism client when selected. Otherwise it prepares/reuses an isolated Minecraft **1.21.4** client on the project's local offline development server: 800×600, 256–512 MiB Java heap, 15 FPS active, 2 FPS after 15 seconds without work, and shutdown after 90 seconds. Heap is not total process RAM. Fabric dependencies download on demand; shared assets are cached. No permanent daemon or network bridge.

## Main Prism client, animated cursors and player control

For an existing Fabric **26.1.2** instance, the optional bridge is bundled with the CLI and installed only when selected. Choose the exact instance:

```powershell
plug --json client start --instance "FO 26.1.2" --player CaptureTester
plug --json client state
plug --json client action '{"action":"command","command":"yourplugin menu"}'
plug --json client action '{"action":"cursor","theme":"plugdev-1","slot":11,"durationMs":700}'
plug --json capture shot --name menu --width 960
plug --json client detach
```

`capture client --instance "FO 26.1.2"` is equivalent. Repeated starts reuse the selected process. The main client keeps its existing mods and heap settings; the bridge caps agent rendering at 30 FPS active and 5 FPS after 15 seconds idle. Control expires after five minutes without work. Detach immediately restores normal controls and temporary HUD/pause settings; `capture client-stop` closes the controlled game. The optional bridge remains installed but inactive without a local session lease.

**PlugDev-1 Cursor** is the generated white/amber arrow. **PlugDev-2 Cursor** is an original generated dark arrow with a soft orange glow, inspired by the requested Codex-like appearance. Both are bundled and animate inside the actual Minecraft framebuffer, including real slot tooltips and click feedback. They never move the Windows pointer. Set `reducedMotion: true` for immediate movement, or `visible: false` to hide the overlay. Coordinates use GUI pixels; slot indices use the currently open container. Source contributors can rebuild the bridge with `npm run build:client-agent` using a cached Prism Java 25 / Minecraft 26.1.2 runtime.

Actions include `command`, `click` (button 0/1), `look` (yaw/pitch), `move` (keys and 1–5000 ms), preemptive `stop`, `hud` (`hidden`), and `close-screen`. Mutating player actions require the selected local development server. Protocol test players are bounded to eight distinct names and are disconnected after the scenario.

```yaml
name: menu-tour
player: CaptureTester
bots: [ListingOne, ListingTwo]
steps:
  - player: {action: command, command: yourplugin menu}
  - wait_screen: {title: Your plugin menu, timeoutMs: 10000}
  - cursor: {theme: plugdev-1, slot: 11, durationMs: 200}
  - shot: menu-diamond
  - gif:
      name: menu-tour
      seconds: 6
      steps:
        - cursor: {slot: 13, durationMs: 700}
        - player: {action: click}
        - cursor: {theme: plugdev-2, slot: 15, durationMs: 700}
  - player: {action: close-screen}
  - player: {action: look, yaw: 0, pitch: 0}
  - player: {action: move, keys: [forward], durationMs: 500}
  - shot: moved-player
```

Replace commands, menu title and slots with the real plugin contract. Allow recording time for animation, game ticks and IPC; an overrun fails explicitly and retains the source. PNGs use the native framebuffer for the selected Prism client; GIFs use verified-window recording and retain the MKV for re-export. A different explicit capture binding cannot silently control this player.

The tiny client bridge prevents launch activation and system-pointer capture. WGC records a verified HWND/PID/process creation time, never the desktop or first matching title. Use `capture client` for non-disruptive startup; `open --client` remains the interactive launcher.

For an existing client or another Minecraft version, use `capture targets`, then `capture bind --pid <pid>`. Explicit bindings take precedence. Stale/ambiguous targets fail. `capture client` explicitly selects the owned client again. Repeated starts reuse its verified identity. Already-connected usernames fail instead of disconnecting that player.

## Open a plugin GUI and report errors

Replace `yourplugin menu` with the real player command. Protocol bots alone cannot render screenshots.

```yaml
name: plugin-menu
player: CaptureTester
output: .plugdev/media
steps:
  - wait_join: 30000
  - as: yourplugin menu
  - shot: plugin-menu
  - gif:
      name: plugin-menu-demo
      seconds: 6
```

Bootstrap `as` runs the command as that connected player. Use `wait_rcon: {command: list, contains: CaptureTester, timeoutMs: 10000}` for observable readiness. Waits are capped at 120 seconds. GIF nested steps begin at the first source frame and are cancelled when footage ends; nested capture is rejected. HUD control is supported by the selected Prism bridge and restored after the scenario; other capture targets reject it before side effects.

Inspect returned images and `plug --json server logs --lines 80`; pass its byte cursor with `--since <cursor>` for incremental logs. Report plugin errors separately from expected offline-authentication warnings.

## Record once, export repeatedly

```powershell
plug --json capture start --name menu --seconds 30 --fps 15 --width 800
plug --json capture status <capture-id>
plug --json capture stop <capture-id>
plug --json capture cancel <capture-id>
plug --json capture export .plugdev/media/<capture-id>/menu.source.mkv --format mp4 --name menu-video --start 1 --seconds 4
```

Start returns a worker ID. Stop finishes and exports; cancel stops work and retains source. Status reports running/encoding/complete/cancelled/failed, frame progress and files. Ctrl+C and MCP request cancellation stop owned work. Source is capped at 30 seconds/256 MiB; one capture/encoder per project.

Shot/GIF options: `--name`, `--pid`, `--width 64..1920`, `--fps 1..30`, `--crop w:h:x:y`, `--cursor`. Windows recording cursors are separate from GUI CSS cursor styling. Multiple named scenario shots form a batch. Jobs have unique directories; exports reject collisions. FFprobe checks format, frames, dimensions, size and duration. Failed GIF export never replays actions or records again: retry from retained MKV. Partial source may remain in a `.capture-*` directory named in the error. Retention is manual; delete only on user request.

## Limits and results

Requires an unlocked interactive Windows desktop, FFmpeg with gfxcapture and FFprobe. Unfocused Minecraft has real runtime evidence. Fully covered Minecraft was also verified using window bounds/stacking order and real GUI artifacts. Minimized targets fail without restoration. Locked/disconnected desktops are unsupported and may be reported together as unavailable. Headless bots cannot render evidence. No foreground fallback. Missing source progress times out; static pixels alone do not prove a frozen simulation.

JSON is one stdout result (`ok`, `data` or `error`/`code`). Failures are nonzero; capture cancellation is 130. Preserve returned artifact paths. MCP wraps the same commands: `plugdev_capture_client` (start/status/stop), plus doctor/targets/bind/shot/gif/run/start/status/stop/cancel/export with the `plugdev_capture_` prefix.

Exports support --quality draft|balanced|high and --max-bytes 1024..52428800. A size target permits up to three attempts from the same source, reducing dimensions, FPS, and quality; returned encoding settings disclose adjustments. Unmet targets fail and preserve the source. Each export processes at most 30 seconds.
Use `capture inspect <source>` (MCP `plugdev_capture_inspect`) for full decode validation and black/static-frame diagnostics over at most 30 seconds. A static plugin GUI may correctly produce a freeze warning.
