brush-parity.md, gaps.md and ui-parity.md had 2026-10-25 revision rows
under a 2026-10-23/24 "Last updated" header; the headers now carry the
latest row. gaps.md (24 of 171), ui-parity.md and target-app-parity.md
(46 of 149) quoted stale counts of preferences that do nothing; they now
quote the scorecard's 12 of 178. target-app-parity.md still listed the
Camera Raw Calibration panel as missing, which landed on 2026-10-13
(#5128); the row now names per-camera colour for non-DNG cameras, as
gaps.md G14 does.
Found by CodeRabbit on #9386.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Tolerance defaulted to 50 and averaged alpha into the difference, so an
ordinary edit (e.g. #c03030 -> #d04848) was never painted back, and a stroke
that wrote nothing still left an empty History step. Photoshop's default is
0; the difference is now the larger of the mean colour change and the
alpha change (the Eraser keeps colour and lowers alpha), and a stroke that
writes nothing is an error instead of an empty step.
- Each tile copied a source window of tile +- halo per dab: a leftward stroke
or a curl across x = 64 read empty pixels there (seam), and a size-1000 click
copied ~5e9 floats (11.9 s). The rotated read stays inside the dab, so it now
samples the source directly; bilinear reads at pixel centres, so an
unrotated dab copies the history pixel instead of a 2x2 blend.
- The brush used its own history lookup (state 0 by default): it now takes
the History Brush's source (history.setSource, snapshots, refusal after a
canvas size change).
- TOOL-213-20 is partial (8 of 10 styles, Area scales spacing); docs follow.
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- algo/paint.rs: main locks transparency with composite_atop; keep that
for every blend mode, and Clear on a locked layer leaves the pixel.
- paint_mouse.rs: main's Some arm (loads stored tips), the PR's None arm
(a first-seen tool starts in Normal).
- retouch_ui.rs: main moved the Pattern Stamp params into
pattern_stamp_params, shared with its live preview; the PR's `mode`
goes there, so preview and commit agree.
- tool_reset.rs: main's Type keys plus the PR's Paint Bucket mode keys.
- distort_ui.rs (from #5478): main's Delete/Backspace pin branch, then
tool_keys.
- docs: both sides' history rows and status lines.
Co-authored-by: paulou-jpg <79102098+paulou-jpg@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keep the brush Mode menu's early return in canvas_buttons ahead of main's
physical right-button handling, keep both sets of control tests, and keep
both notes in docs/brush-parity.md and docs/control-protocol.md.
docs/brush-parity.md: kept main's header and added the PR's change item; the PR's change-log row added.
docs/gaps.md: kept main's header and added the PR's change item; the PR's G4 progress note and change-log row added.
crates/paint/src/brush_tests.rs: both sides added tests at the same spot; kept main's four smoothing tests and added the PR's three pose_axes tests after them.
docs/brush-parity.md: kept main's header and added the PR's change item.
docs/gaps.md: kept main's header, added the PR's change item; G4 progress notes and the change-log row kept from both sides.
docs/control-protocol.md: kept main's eyedropper line (with the document.sampleColor wording) and added the PR's Brush Pose line before it.
Photoshop gives these painting tools a Mode in the options bar; here they
always painted in Normal.
- Clone Stamp, Pattern Stamp and History Brush offer the layer modes, and
Healing its own list (Normal, Multiply, Screen, Darken, Lighten, Color,
Luminosity). The mode is kept in each tool's own brush, like its size,
and reaches the live stroke and the commit.
- Paint Bucket: paint.bucket takes "mode" (any blend mode, or "clear" to
erase the filled area). algo's bucket fill gains a FillMode for it. The
options bar's Mode has Clear after Dissolve, as the Brush's does.
- A tool's first brush now starts in Normal instead of inheriting the
previous tool's mode, so a Multiply Brush no longer makes the first
Clone Stamp stroke multiply.
- The Shift+Alt letter and Shift+Plus/Minus mode keys reach these tools,
within each tool's menu. Tools with no blend mode (the Erasers, Mixer
Brush, Dodge, Burn, Sponge) now pass the keys to the selected layers.
Not yet: Healing's Replace mode, and a Mode for Spot Healing, Color
Replacement, Blur, Sharpen and Smudge (they ignore the keys meanwhile).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Mixer Brush could not be emptied. MixerState::clean dropped only
the pickup well, paint.mixerBrush refilled the reservoir from the
foreground before every stroke unless loadAfterStroke was false, and
the app always sent the defaults. A stroke on a new layer over an image
always carried the foreground color, and the options bar had no Load
Brush or Clean Brush control.
Cleaning now empties both wells, so a clean brush lays down only the
color it picks up from the canvas. The new commands brush.mixer.load
and brush.mixer.clean load and empty the brush. paint.mixerBrush reads
loadAfterStroke and cleanAfterStroke from the brush and applies them
after the stroke. Both are on by default, and a stroke with both on
paints as before. A stroke whose color differs from the one recorded
by the last stroke, load or clean loads that color first. A load or
clean records the foreground, so choosing a new foreground loads the
reservoir.
The options bar has the Current Brush Load swatch, whose menu holds
Load Brush and Clean Brush, and two toggles for the automatic Load and
Clean. Brush Settings shows the same two options. The new strings have
rows in every catalog.
Retain both progress histories and integrate the existing Brush Settings changes with upstream. Preserve the response-curve editor, options-label scrubbing and independent preset regression tests where they overlap.
Co-authored-by: GPT-6 <noreply@openai.com>
Retain both progress histories and integrate the existing Brush Settings changes with upstream. Preserve the response-curve editor, options-label scrubbing and independent preset regression tests where they overlap.
Co-authored-by: GPT-6 <noreply@openai.com>
Retain both progress histories and integrate the existing Brush Settings changes with upstream. Preserve the response-curve editor, options-label scrubbing and independent preset regression tests where they overlap.
Co-authored-by: GPT-6 <noreply@openai.com>
Resolve the docs/brush-parity.md conflict by keeping both sides: the
upstream notes (Hue Jitter amount track, Color Replacement) and the
Brush Shift+right-click Mode picker note, in the header and the change table.
Keep X/Y flags through ABR import, presets, commands and painting; retain legacy combined inputs and expose both controls with regression coverage.
Co-authored-by: GPT-6 <noreply@openai.com>
Pass the active tool to the section renderer and disable the complete
Wetness/Mix Transfer blocks when they do not apply, preserving saved settings.
Cover all themes/tools, disabled input, active edits and real tool-cache swaps
with three regressions, including exact tools.setBrush journal routing.
Addresses the Wetness/Mix tool-applicability subsection of #3825.
Co-authored-by: GPT-6 <noreply@openai.com>
Use the shared percentage row so the jitter amount does not look like a hue selection. Cover the rendered themed track, numeric and pointer edits, neighboring settings and engine journal replay.
Addresses the Hue Jitter appearance item in #3825; other assessment items remain open.
Co-authored-by: augrclk <217665348+augrclk@users.noreply.github.com>
Co-authored-by: GPT-6 <noreply@openai.com>
Background Eraser: main now samples and matches against the pre-stroke pixels (#4552); the
shared dab effect takes the pre-stroke surface so the live preview, whose working areas are
per dab, reads the same pixels as the commit.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Keep configured minimum values across Control changes and cover disabled input, independent controls and reactivation with UI regressions.
Refs #3825 (minimum input state only).
Co-authored-by: augrclk <217665348+augrclk@users.noreply.github.com>
Co-authored-by: GPT-6 <noreply@openai.com>
#3467 traces a shaped tip's outline but scales it by the screen radius
alone, so on a rotated or flipped canvas (R, View › Flip Horizontal) the
cursor kept the document's orientation while the stroke did not.
The outline now goes on screen through the view's own axes:
ViewXform::map_vec maps a document vector (pixel aspect, rotation, flip,
zoom), and brush_cursor::tip_axes gives one tip radius along the
document's x and y. A plain view gives the same points as before.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Noise, Wet Edges, Build-up, Smoothing and Protect Texture toggle from
anywhere on their row while keeping the selected controls open. Keep
lock clicks independent and expose each switch as one accessible checkbox.
Give Smoothing a default-on enable flag so disabling it preserves the
amount and modes. Old brush JSON stays compatible; toolbar amount edits
and explicit stroke overrides enable it, and ABR imports retain disabled
smoothing values.
Cover row, checkbox, lock and keyboard gestures, old section selections,
command replay, presets, legacy JSON and 8/16/32-bit rendering.
Fixes#4283
Co-authored-by: augrclk <217665348+augrclk@users.noreply.github.com>
Co-authored-by: GPT-6 <noreply@openai.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Brush and Pencil: hold ~ to erase
Fixes#3439. Holding ~ (the backtick key) with the Brush or Pencil makes
the strokes started while it is held erase, with that tool's own brush,
as in Photoshop; releasing it paints again and the tool never changes.
The key is a Tools › Temporary binding (tools.temporary.erase), so it
can be rebound or removed in Keyboard Shortcuts.
* Brush and Pencil: Clear painting mode, used by ~
Photoshop's Clear joins the Brush's and Pencil's Mode menus, after
Dissolve: chosen there, every stroke erases with that tool's brush until
another mode is picked. Holding ~ now puts the stroke in Clear mode too,
and the Mode menu shows Clear while the key is held. History names the
tool rather than the Eraser. Agents get it as "mode": "clear" on
paint.stroke and paint.pencil.
* Keep the Smoothing doc comment on smoothing_field
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Pattern Stamp (aligned through LiveRetouch, Impressionist dab by dab) and
Background Eraser now paint during the drag; the release commits exactly the
pixels the live stroke showed (per-pixel tests at 8 and 16 bits). Spot
Healing keeps healing on release and shows a dark overlay while dragging.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Progress docs per craftrules standards/progress-docs.md: target-app parity (merges parity-estimate.md), gaps, roadmap with alpha gate, readiness by audience (full / mainstream / essentials) with Opus 5.5 hours, and UI, brush, format, hardware and localization parity docs. docs/parity.md is now docs/parity-checklist.md.
The Windows test failure (file_dialog::tests::save_dialogs_remember_where_each_document_was_last_saved) is pre-existing on main: the test hard-codes POSIX paths.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>