Screenshots
Capture the screen reproducibly — the same path the docs’ own screenshots use, on every backend including --headless with no display at all.
Take one
Section titled “Take one”scootctl screenshot --out /tmp/shot.pngscootctl screenshot --output 2 --out /tmp/second.pngscootctl screenshot --no-cursor --out /tmp/clean.png| Flag | Type | Default | Meaning |
|---|---|---|---|
--output ID |
int | 1 (first output) |
Which output to capture; every output has a framebuffer of its own, so the capture is that output’s own pixels. An id naming no output is refused rather than answered with another output’s pixels. A powered-off output is refused too, naming the recovery. |
--out FILE |
path | stdout | Where the PNG goes; without it, the PNG bytes go to stdout. |
--no-cursor |
switch | draw it in | Leave the pointer out (below). |
A screenshot taken straight after a scootbg set shows it — the set
returns once the change is on screen — the reproducible pair the docs’
own captures use.
Physical pixels, logical coordinates
Section titled “Physical pixels, logical coordinates”screenshot captures the framebuffer at full physical resolution,
while windows and outputs report logical rectangles. Convert with
physical = logical * scale, rounded down where an edge lands
mid-pixel — and per output: two screens can run at different scales,
so convert a window’s rectangle with the scale of the output the
window is on (its output), never the first output’s. (Full rule in
Rules an agent needs.)
Retry rules
Section titled “Retry rules”Captures are paced: one per connection per 16 ms frame (a second inside
the same frame is refused — and note the reply order: the refusal
arrives first, so match replies by content, not position), one in
flight per connection, four in flight across every client. On the
--tty GPU scanout tier a capture can also be refused with a retry
while the screen shows a client’s buffer directly — treat both
refusals as retryable. The full list, with what each costs and what to
do, is what the socket refuses.
The pointer in a screenshot
Section titled “The pointer in a screenshot”A screenshot shows the pointer, the same way on every backend and
renderer, unless the request says not to. On the wire that is an optional
cursor field on the request:
{"type": "screenshot"}{"type": "screenshot", "cursor": false}Omitted means drawn in (SCREENSHOT_CURSOR_DEFAULT in scoot-ipc);
false leaves it out, and scootctl screenshot --no-cursor sends that.
“The same everywhere” is the point: an agent’s script sees the pointer the
same way under --headless and --nested (whose screens have no drawn
cursor at all), on --tty’s default renderer, and on the GPU scanout tier
(whose cursor rides a hardware plane) — the pointer’s own image, hotspot and
scale, at its position on the captured output and on no other output. A
fresh session’s pointer sits at the centre of the first output, so a
default screenshot shows it there until something moves it. Leave it out
to diff two screenshots without the pointer showing up as a difference, or
to read the pixels it would cover. (Until this field existed, --headless
and --nested screenshots never showed the pointer.)
The field was added without an IPC protocol bump: a request that omits it is
the old request byte for byte, so older clients are unaffected. The flip
side: a server that predates the field silently ignores it rather than
refusing it, so on one of those cursor: false has no effect, and whether
the pointer shows depends on the backend as it used to (drawn only under
--tty, and missing where a cursor plane carries it). A client cannot tell
such a server apart: version reports the same protocol number either way.