Skip to main content
Glama

ps_apply_brush_stroke

Destructive

Apply a Photoshop brush stroke along a defined path using any of 16 brush-family tools, from retouching (heal, clone, dodge, burn) to painting, with control over size, hardness, opacity, and flow.

Instructions

Paint along a path with one of PS's 16 brush-family tools — supply the path EITHER as an anchor-relational placement (preferred: a path relation → the stroke traces a resolved, gate-verified curve along a traced edge / landmark / between two anchors, no pixel-guessing) OR as an explicit path list of anchor points — the retouch tools (healing_brush, clone_stamp, burn, dodge, blur, sharpen, smudge), the paint family (brush, pencil, eraser), and the specialty tools (pattern_stamp, art_history_brush, history_brush, color_replacement, background_eraser, sponge). The path parameter takes a list of anchor points with optional bezier handles, so the same tool handles straight-line strokes, freeform curves, and closed shapes — all by varying the path geometry. Reach for this when: (a) cloning out a distraction along a specific shape (clone_stamp with a source_point + a path tracing the unwanted edge); (b) healing a scratch or seam (healing_brush with source_point); (c) dodging / burning to redirect tonal balance along a contour; (d) painting a freehand line into the canvas (brush + foreground_color). Active layer must be a normal pixel layer (background auto-promotes); rasterize adjustment/shape/text/smart-object layers first. Auto-duplicates — the original is preserved and a "Brush Stroke ()" copy receives the paint. Brush dynamics: hardness, opacity, and flow are independently settable via hardness_pct / opacity_pct / flow_pct (the live tool options are mutated before stroking and restored to the user's prior state in finally). Sampled brushes (custom shape-stamp presets) silently ignore hardness/diameter mutations — vary their character via brush_preset instead.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
pathNoOrdered list of anchor points the stroke traces. **Minimum 2 anchors.** Each anchor is `{x, y}` for a sharp corner OR `{x, y, in: [hx, hy], out: [hx, hy]}` for a smooth bezier point. The `in` and `out` handles MUST be positioned **tangent** to the curve at the anchor — `in` placed in the direction of the PREVIOUS anchor in the array, `out` placed in the direction of the NEXT anchor. Handles placed RADIALLY (toward/away from the shape's center) produce loops + concave curves instead of smooth convex ones. Mix corner + smooth points freely. Coordinates are document pixels; (0, 0) is top-left. Partial handles (only `in` OR only `out`) degrade to a sharp corner. **Recipes for common natural-stroke shapes** (compute these client-side and emit the resulting `[{x, y}, ...]` array): (1) **Hand-drawn straight line A→B with sketchy feel**: sample 8-30 evenly-spaced corner anchors along the line, then perturb each interior anchor by ±2-5px on the perpendicular axis — OR pass clean anchors and use `jitter_px` to apply the perturbation server-side (preferred — cheaper, deterministic). (2) **Sine wave A→B, amplitude a, periods n**: for i in 0..N, x_i = A.x + (i/N)*(B.x - A.x), y_i = A.y + a * sin((i/N) * 2π * n). Use 20-40 anchors for a smooth wave. (3) **Parabolic arc A→B peaking height h above midline**: for i in 0..N, t = i/N, x_i = lerp(A.x, B.x, t), y_i = lerp(A.y, B.y, t) - 4*h*t*(1-t). (4) **Canonical clockwise circle of radius r around (cx, cy)** with k = r * 0.5523: TOP `{x: cx, y: cy-r, in: [cx-k, cy-r], out: [cx+k, cy-r]}`, RIGHT `{x: cx+r, y: cy, in: [cx+r, cy-k], out: [cx+r, cy+k]}`, BOTTOM `{x: cx, y: cy+r, in: [cx+k, cy+r], out: [cx-k, cy+r]}`, LEFT `{x: cx-r, y: cy, in: [cx-r, cy+k], out: [cx-r, cy-k]}` — close with `closed: true`. (5) **Many short overlapping strokes for ink-on-paper texture**: chain multiple `apply_brush_stroke` calls along the same trajectory with small position offsets and varying `brush_size`; reads more natural than one long stroke.
toolYesWhich brush-family tool to dispatch. Headline retouch options: `healing_brush` and `clone_stamp` (both REQUIRE `source_point` — set the sample location, then stroke the path); `burn` darkens; `dodge` lightens; `blur` smooths; `sharpen` enhances local contrast; `smudge` pushes pixels in the stroke direction. Paint family: `brush` (the standard paintbrush — honors `foreground_color`), `pencil` (hard-edge), `eraser`. Specialty: `pattern_stamp`, `art_history_brush`, `history_brush`, `color_replacement`, `background_eraser`, `sponge`.
closedNoWhen true, the path is closed (last anchor connects back to first) so the stroke forms a loop. Default false.
flow_pctNoOptional brush flow override (percent, 0-100). Routed through `currentToolOptions.flow` (top-level integer key). Flow controls how much paint each stroke step deposits — for paint-family tools (`brush`, `pencil`, `pattern_stamp`), low flow means the stroke needs multiple overlapping passes to reach full opacity; high flow saturates immediately. Restored to the user's original value in `finally`.
jitter_pxNoServer-side hand-drawn perturbation. When > 0, the handler shifts every INTERIOR anchor (not the first, not the last — those stay exactly where you placed them) by a deterministic pseudo-random offset in `[-jitter_px, +jitter_px]` on each axis BEFORE stroking. Bezier handles ride along with their anchor so curve tangents are preserved. Same inputs produce the same emitted shape every call. **Reach for this when** you want a clean intent (mathematically perfect line, sine wave, arc) to read as hand-drawn ink without writing the jitter math yourself. Typical values: 2-5 for subtle ink texture, 5-10 for visibly sketchy, 10-20 for cartoonish/scratchy. Default 0 (no jitter).
placementNoANCHOR-RELATIONAL stroke path (preferred over supplying pixels): a PATH relation — `along` a traced edge or a Pro face-mesh landmark curve, `offset-curve`, or `segment` between two anchors — so the stroke traces the resolved, gate-verified curve (the FULL polyline, not just endpoints: paint along the jaw / horizon / under-eye). Strokes ONLY if the gate PASSES. When set, `path` is ignored; tool/brush_size/source_point/colors/dynamics/jitter still apply. See ps_resolve_placement for the anchors + relation vocabulary.
brush_sizeYesBrush tip diameter in pixels. Typical retouch values: 12-30 for fine work, 50-100 for filling, 150+ for broad strokes. Verified scriptable via `setd Brsh.Trgt masterDiameter` in the 2026-06-09 spike.
opacity_pctNoOptional brush opacity override (percent, 0-100). Routed through `currentToolOptions.opacity` (a top-level integer key on the tool options descriptor, not nested inside the brush sub-descriptor). Applies to the WHOLE stroke uniformly — varying-opacity strokes require chaining multiple `apply_brush_stroke` calls. Restored to the user's original value in `finally`.
brush_presetNoOptional brush-preset name to select before stroking (e.g. "Soft Round", "Hard Round", or any custom preset the user has loaded). The preset's saved hardness, opacity, flow, and shape dynamics load with the slct dispatch — set the preset for a coherent character (soft vs hard, calligraphic vs round), then optionally override individual values via `hardness_pct` / `opacity_pct` / `flow_pct`. If the named preset is not installed, the tool falls back to "Soft Round" then "Hard Round" (both ship on every install) and reports which one landed via `preset_applied` in the result.
hardness_pctNoOptional brush hardness override (percent, 0-100). When set, mutates the live tool's hardness via the `currentToolOptions.brush.hardness` get-mutate-set pattern AFTER any brush_preset has loaded — so the preset's hardness is what you start from and this overrides it. **Computed brushes only**: Soft Round / Hard Round / Calligraphic / etc. accept the mutation; **sampled brushes** (custom shape-stamp presets loaded from .abr files) silently ignore it because their shape isn't parametric. The user's original tool options are restored in `finally` so this doesn't leak to their next non-LLM brush action.
source_pointNoSample point for `clone_stamp` / `healing_brush` — the pixel location PS samples from while the stroke progresses. REQUIRED for those two tools (unless `source_placement` names it instead). Ignored for all others. `layer_name` defaults to the active layer at call time when omitted.
foreground_colorNoRGB foreground color for paint-family tools (`brush`, `pencil`). The retouch family (`burn`/`dodge`/`blur`/`sharpen`/`smudge`/`clone_stamp`/`healing_brush`) ignores foreground color — setting it on those tools is harmless but pointless. The user's previous foreground color is restored after the stroke completes.
source_placementNoGrounded alternative to `source_point` for `clone_stamp` / `healing_brush`: NAME the sample location (resolves to a POINT via the grounding resolver + objective gate — e.g. an `extremum` for the cleanest/smoothest nearby skin, a `grid` intersection, or a landmark point) instead of guessing pixels. Resolves to a POINT relation (centroid / midpoint / offset / extremum / grid / landmark point); the resolved point supplies `source_point` and WINS over an explicit `source_point`. Strokes only if the source gate PASSES.
apply_to_active_layerNoIf false (default), the stroke is applied to a duplicate of the active layer named "<OpName> (<Original Name>)" — the original is preserved and the LLM can undo simply by deleting the copy. If true, the stroke bakes directly into the active layer (the historical destructive behavior).

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
toolNo
closedNo
anchorsNo
contextNo
strokedNo
placementNoPresent when the stroke path came from anchor-relational placement: the resolved curve + gate verdict.
tool_typeNo
brush_sizeNo
flow_appliedNo
path_removedNo
size_appliedNo
preset_appliedNoName of the brush preset that actually landed — equal to `brush_preset` if installed, "Soft Round" / "Hard Round" if a fallback fired, null when no preset was requested.
opacity_appliedNo
stroke_envelopeNoThe doc-pixel bbox the stroke should occupy (path bbox + brush radius) — the objective target to verify stroke occupancy against.
target_was_copyNo
clone_source_setNo
hardness_appliedNo
source_placementNoPresent when the clone/heal sample point came from a source_placement: the resolved point + gate verdict.
target_layer_nameNo
background_promotedNo
original_layer_nameNo
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description richly discloses behavioral traits: auto-duplication preserving the original, mutation of brush tools options with restoration in finally, sampled brushes ignoring hardness mutations, and the fallback chain for brush_preset. It also clarifies the destructive mode via apply_to_active_layer, adding significant context beyond the annotations' destructiveHint and idempotentHint. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely long, spanning multiple paragraphs, bullet lists, and embedded recipes. While front-loaded with the core purpose, the extensive recipe section and repeated parameter explanations make it unwieldy for an agent to parse quickly. It would benefit from trimming or moving implementation details to a separate guide.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite its length, the description leaves no gap: it covers all 16 brush tools, path construction options (path/placement), source point requirements, brush dynamics, non-destructive default, prerequisites, and parameter interactions. Given the tool's complexity (14 params, nested objects, output schema present), this description is fully complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds substantial semantic value beyond schema fields: detailed recipes for path generation (straight line, sine wave, parabola, circle), explanation of jitter_px, and the relationship between source_point/source_placement. These supplement the already-detailed schema descriptions, elevating the score above baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with an explicit verb+resource: 'Paint along a path with one of PS's 16 brush-family tools' and immediately enumerates the tool categories, making the purpose unambiguous. It also distinguishes this tool from siblings by focusing specifically on brush-stroke execution with path input, rather than other operational tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The '**Reach for this when**' section provides explicit, concrete scenarios (clone-out, healing, dodging/burning, freehand painting) and specifies prerequisites like requiring a normal pixel layer and rasterizing adjustment/shape/text/smart-object layers. It does not explicitly name alternative tools to use instead, but the context is strong and clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/editmamei/editmamei'

If you have feedback or need assistance with the MCP directory API, please join our Discord server