Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

capture

A preview of an output or a window. Outputs use ext-image-copy-capture-v1, with wlr-screencopy as a fallback. Window capture currently requires Hyprland’s toplevel address mapping and ext capture protocols. Without the required protocols it draws nothing and warns once per target.

A rounded preview of the first screen at up to 30 frames per second:

local first_output = mantle.screens:map(function(screens)
    return screens[1] and screens[1].name or ""
end)

local preview = rect {
    width = 320,
    height = 180,
    radius = 8,
    clip = "rounded",
    background = "#000000",
    children = {
        capture { output = first_output, live = 30, fit = "contain", width = "fill", height = "fill" },
    },
}

mantle.screens lists the connected outputs by connector name.

Preview the focused window using its mantle.windows ID:

local focused_window = mantle.windows:map(function(state)
    for _, entry in ipairs(state.windows) do
        if entry.focused then return entry.id end
    end
    return ""
end)

return capture { window = focused_window, live = 15, fit = "contain", width = 320, height = 180 }

Window capture reads the toplevel itself, including when another window covers it. It does not crop an output. Pass the ID unchanged; names and titles are not identifiers.

Windows backendWindow capture
HyprlandSupported when the mapping and ext toplevel capture protocols are advertised
NiriUnsupported. Its foreign-toplevel identifiers match its window IDs, but its ext capture implementation currently handles outputs only
wlrUnsupported. Mantle assigns connection-local window IDs; the protocol provides no exact mapping to the renderer’s foreign-toplevel handles

Niri’s identifier implementation and capture handler confirm these are separate requirements. Non-Hyprland window capture remains on the roadmap.

Properties

capture takes the common properties, plus:

PropertyTypeDefaultBehaviour
outputstring|Bound""Connector name, e.g. "DP-1"; "" draws nothing. An unknown name draws nothing and warns once. Changing it starts a fresh capture
windowstring|Bound""A mantle.windows entry’s id; "" draws nothing. Currently requires Hyprland’s exact toplevel mapping and ext capture protocols. Cannot combine with a nonempty output or region. A closed window clears its preview
fit"cover"|"contain"|"stretch"|Bound"cover"As on image
liveboolean|number|Boundfalsefalse: capture on show and on each target change. true: every frame, one in flight. A number: at most that many fps, (0, 1000]. Hiding the node or unmapping its surface drops the capture; showing starts a fresh one
regionRect|Bound, [0, 8192]The whole outputPart of the output in its logical px, placed by fit as the whole frame. Every key is required and in that range; the size is non-zero
paint_cursorboolean|BoundfalseInclude the pointer in the frame

It has no intrinsic size: without width and height it draws nothing. A hidden node or unmapped surface drops its capture and starts a fresh one when it shows again. A live capture gets a new frame only when its source changes. A resized source renegotiates its buffers and keeps going. A stopped live output session keeps its last frame and restarts when its frame-rate cap allows, even without a repaint. A completed one-shot keeps its frame. Any other failed output capture retries when the output list changes. A failed or closed window capture clears or stops its preview and remains stopped until the target changes or the node hides and shows again. An unrelated output change cannot revive a closed window’s ID. A one-shot captures the current frame; use live to follow opening animations.

A region prefers wlr-screencopy, which crops at the source. Through ext-image-copy-capture-v1 the engine crops instead, and on a rotated or flipped output it cannot: it draws the whole output and logs one warning.

How do I…

TaskAnswer
Preview a monitorThe first example above
Preview a windowwindow = entry.id from mantle.windows; currently Hyprland only
Preview every monitorA list over mantle.screens, key = the screen’s name, one capture per item
Show a part of the screenregion = { x = 0, y = 0, width = 960, height = 540 }
Keep CPU lowLeave live = false for a still, or cap it: live = 10
Include the mouse pointerpaint_cursor = true
Round the cornersWrap it in a rect with radius and clip = "rounded", as above

Gotchas

TrapFix
Nothing drawsGive it a size; check output against mantle.screens names; check mantle log for a missing-protocol warning
The preview is frozenlive is false, which captures once. Set true or a frame rate
live = 0 is refusedUse false for a single frame
A region shows the whole outputThe output is rotated or flipped and only ext-image-copy-capture-v1 is offered
region = { width = 100, height = 100 } is refusedAll four keys are required
window and output are both setOnly one may be nonempty; region is output-only

See also: image, surfaces.

Source: vocabulary, content parsers, capture.